summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/i2c/busses/i2c-axxia.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/i2c/busses/i2c-axxia.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/i2c/busses/i2c-axxia.c')
-rw-r--r--kernel/drivers/i2c/busses/i2c-axxia.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/kernel/drivers/i2c/busses/i2c-axxia.c b/kernel/drivers/i2c/busses/i2c-axxia.c
index 32d883490..c335cc785 100644
--- a/kernel/drivers/i2c/busses/i2c-axxia.c
+++ b/kernel/drivers/i2c/busses/i2c-axxia.c
@@ -42,6 +42,10 @@
#define IBML_LOW_SEXT 0x18
#define TIMER_CLOCK_DIV 0x1c
#define I2C_BUS_MONITOR 0x20
+#define BM_SDAC BIT(3)
+#define BM_SCLC BIT(2)
+#define BM_SDAS BIT(1)
+#define BM_SCLS BIT(0)
#define SOFT_RESET 0x24
#define MST_COMMAND 0x28
#define CMD_BUSY (1<<3)
@@ -394,6 +398,9 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
if (time_left == 0)
idev->msg_err = -ETIMEDOUT;
+ if (idev->msg_err == -ETIMEDOUT)
+ i2c_recover_bus(&idev->adapter);
+
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
axxia_i2c_init(idev);
@@ -437,6 +444,39 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return ret ? : i;
}
+static int axxia_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+
+ return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SCLS);
+}
+
+static void axxia_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+ u32 tmp;
+
+ /* Preserve SDA Control */
+ tmp = readl(idev->base + I2C_BUS_MONITOR) & BM_SDAC;
+ if (!val)
+ tmp |= BM_SCLC;
+ writel(tmp, idev->base + I2C_BUS_MONITOR);
+}
+
+static int axxia_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct axxia_i2c_dev *idev = i2c_get_adapdata(adap);
+
+ return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SDAS);
+}
+
+static struct i2c_bus_recovery_info axxia_i2c_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = axxia_i2c_get_scl,
+ .set_scl = axxia_i2c_set_scl,
+ .get_sda = axxia_i2c_get_sda,
+};
+
static u32 axxia_i2c_func(struct i2c_adapter *adap)
{
u32 caps = (I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
@@ -511,6 +551,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
idev->adapter.owner = THIS_MODULE;
idev->adapter.algo = &axxia_i2c_algo;
+ idev->adapter.bus_recovery_info = &axxia_i2c_recovery_info;
idev->adapter.quirks = &axxia_i2c_quirks;
idev->adapter.dev.parent = &pdev->dev;
idev->adapter.dev.of_node = pdev->dev.of_node;