|
@@ -43,14 +43,16 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/i2c-omap.h>
|
|
|
#include <linux/pm_runtime.h>
|
|
|
+#include <linux/pinctrl/consumer.h>
|
|
|
|
|
|
/* I2C controller revisions */
|
|
|
#define OMAP_I2C_OMAP1_REV_2 0x20
|
|
|
|
|
|
/* I2C controller revisions present on specific hardware */
|
|
|
-#define OMAP_I2C_REV_ON_2430 0x36
|
|
|
-#define OMAP_I2C_REV_ON_3430_3530 0x3C
|
|
|
-#define OMAP_I2C_REV_ON_3630_4430 0x40
|
|
|
+#define OMAP_I2C_REV_ON_2430 0x00000036
|
|
|
+#define OMAP_I2C_REV_ON_3430_3530 0x0000003C
|
|
|
+#define OMAP_I2C_REV_ON_3630 0x00000040
|
|
|
+#define OMAP_I2C_REV_ON_4430_PLUS 0x50400002
|
|
|
|
|
|
/* timeout waiting for the controller to respond */
|
|
|
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
|
@@ -190,7 +192,6 @@ struct omap_i2c_dev {
|
|
|
void (*set_mpu_wkup_lat)(struct device *dev,
|
|
|
long latency);
|
|
|
u32 speed; /* Speed of bus in kHz */
|
|
|
- u32 dtrev; /* extra revision from DT */
|
|
|
u32 flags;
|
|
|
u16 cmd_err;
|
|
|
u8 *buf;
|
|
@@ -202,17 +203,18 @@ struct omap_i2c_dev {
|
|
|
* fifo_size==0 implies no fifo
|
|
|
* if set, should be trsh+1
|
|
|
*/
|
|
|
- u8 rev;
|
|
|
+ u32 rev;
|
|
|
unsigned b_hw:1; /* bad h/w fixes */
|
|
|
unsigned receiver:1; /* true when we're in receiver mode */
|
|
|
u16 iestate; /* Saved interrupt register */
|
|
|
u16 pscstate;
|
|
|
u16 scllstate;
|
|
|
u16 sclhstate;
|
|
|
- u16 bufstate;
|
|
|
u16 syscstate;
|
|
|
u16 westate;
|
|
|
u16 errata;
|
|
|
+
|
|
|
+ struct pinctrl *pins;
|
|
|
};
|
|
|
|
|
|
static const u8 reg_map_ip_v1[] = {
|
|
@@ -275,16 +277,39 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
|
|
|
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
|
|
|
}
|
|
|
|
|
|
-static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
|
+static void __omap_i2c_init(struct omap_i2c_dev *dev)
|
|
|
+{
|
|
|
+
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
|
|
+
|
|
|
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
|
|
|
+
|
|
|
+ /* SCL low and high time values */
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
|
|
|
+ if (dev->rev >= OMAP_I2C_REV_ON_3430_3530)
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
|
|
|
+
|
|
|
+ /* Take the I2C module out of reset: */
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Don't write to this register if the IE state is 0 as it can
|
|
|
+ * cause deadlock.
|
|
|
+ */
|
|
|
+ if (dev->iestate)
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
|
|
|
+}
|
|
|
+
|
|
|
+static int omap_i2c_reset(struct omap_i2c_dev *dev)
|
|
|
{
|
|
|
- u16 psc = 0, scll = 0, sclh = 0, buf = 0;
|
|
|
- u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
|
|
|
- unsigned long fclk_rate = 12000000;
|
|
|
unsigned long timeout;
|
|
|
- unsigned long internal_clk = 0;
|
|
|
- struct clk *fclk;
|
|
|
+ u16 sysc;
|
|
|
|
|
|
if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
|
|
|
+ sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG);
|
|
|
+
|
|
|
/* Disable I2C controller before soft reset */
|
|
|
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
|
|
|
omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
|
|
@@ -306,32 +331,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
|
}
|
|
|
|
|
|
/* SYSC register is cleared by the reset; rewrite it */
|
|
|
- if (dev->rev == OMAP_I2C_REV_ON_2430) {
|
|
|
-
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
|
|
|
- SYSC_AUTOIDLE_MASK);
|
|
|
-
|
|
|
- } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
|
|
|
- dev->syscstate = SYSC_AUTOIDLE_MASK;
|
|
|
- dev->syscstate |= SYSC_ENAWAKEUP_MASK;
|
|
|
- dev->syscstate |= (SYSC_IDLEMODE_SMART <<
|
|
|
- __ffs(SYSC_SIDLEMODE_MASK));
|
|
|
- dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
|
|
|
- __ffs(SYSC_CLOCKACTIVITY_MASK));
|
|
|
-
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
|
|
|
- dev->syscstate);
|
|
|
- /*
|
|
|
- * Enabling all wakup sources to stop I2C freezing on
|
|
|
- * WFI instruction.
|
|
|
- * REVISIT: Some wkup sources might not be needed.
|
|
|
- */
|
|
|
- dev->westate = OMAP_I2C_WE_ALL;
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
|
|
|
- dev->westate);
|
|
|
- }
|
|
|
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc);
|
|
|
+
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
|
+{
|
|
|
+ u16 psc = 0, scll = 0, sclh = 0;
|
|
|
+ u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
|
|
|
+ unsigned long fclk_rate = 12000000;
|
|
|
+ unsigned long internal_clk = 0;
|
|
|
+ struct clk *fclk;
|
|
|
+
|
|
|
+ if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
|
|
|
+ /*
|
|
|
+ * Enabling all wakup sources to stop I2C freezing on
|
|
|
+ * WFI instruction.
|
|
|
+ * REVISIT: Some wkup sources might not be needed.
|
|
|
+ */
|
|
|
+ dev->westate = OMAP_I2C_WE_ALL;
|
|
|
}
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
|
|
|
|
|
|
if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
|
|
|
/*
|
|
@@ -416,28 +437,17 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
|
|
|
sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
|
|
|
}
|
|
|
|
|
|
- /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
|
|
|
-
|
|
|
- /* SCL low and high time values */
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
|
|
|
-
|
|
|
- /* Take the I2C module out of reset: */
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
|
|
-
|
|
|
- /* Enable interrupts */
|
|
|
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
|
|
|
OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
|
|
|
OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
|
|
|
(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
|
|
|
- omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
|
|
|
- if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
|
|
- dev->pscstate = psc;
|
|
|
- dev->scllstate = scll;
|
|
|
- dev->sclhstate = sclh;
|
|
|
- dev->bufstate = buf;
|
|
|
- }
|
|
|
+
|
|
|
+ dev->pscstate = psc;
|
|
|
+ dev->scllstate = scll;
|
|
|
+ dev->sclhstate = sclh;
|
|
|
+
|
|
|
+ __omap_i2c_init(dev);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -490,7 +500,7 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
|
|
|
|
|
|
omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
|
|
|
|
|
|
- if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
|
|
|
+ if (dev->rev < OMAP_I2C_REV_ON_3630)
|
|
|
dev->b_hw = 1; /* Enable hardware fixes */
|
|
|
|
|
|
/* calculate wakeup latency constraint for MPU */
|
|
@@ -586,7 +596,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|
|
OMAP_I2C_TIMEOUT);
|
|
|
if (timeout == 0) {
|
|
|
dev_err(dev->dev, "controller timed out\n");
|
|
|
- omap_i2c_init(dev);
|
|
|
+ omap_i2c_reset(dev);
|
|
|
+ __omap_i2c_init(dev);
|
|
|
return -ETIMEDOUT;
|
|
|
}
|
|
|
|
|
@@ -596,7 +607,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|
|
/* We have an error */
|
|
|
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
|
|
|
OMAP_I2C_STAT_XUDF)) {
|
|
|
- omap_i2c_init(dev);
|
|
|
+ omap_i2c_reset(dev);
|
|
|
+ __omap_i2c_init(dev);
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
@@ -642,13 +654,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (dev->set_mpu_wkup_lat != NULL)
|
|
|
- dev->set_mpu_wkup_lat(dev->dev, -1);
|
|
|
-
|
|
|
if (r == 0)
|
|
|
r = num;
|
|
|
|
|
|
omap_i2c_wait_for_bb(dev);
|
|
|
+
|
|
|
+ if (dev->set_mpu_wkup_lat != NULL)
|
|
|
+ dev->set_mpu_wkup_lat(dev->dev, -1);
|
|
|
+
|
|
|
out:
|
|
|
pm_runtime_mark_last_busy(dev->dev);
|
|
|
pm_runtime_put_autosuspend(dev->dev);
|
|
@@ -1025,9 +1038,7 @@ static const struct i2c_algorithm omap_i2c_algo = {
|
|
|
#ifdef CONFIG_OF
|
|
|
static struct omap_i2c_bus_platform_data omap3_pdata = {
|
|
|
.rev = OMAP_I2C_IP_VERSION_1,
|
|
|
- .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
|
|
|
- OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
|
|
|
- OMAP_I2C_FLAG_BUS_SHIFT_2,
|
|
|
+ .flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
|
|
|
};
|
|
|
|
|
|
static struct omap_i2c_bus_platform_data omap4_pdata = {
|
|
@@ -1048,6 +1059,16 @@ static const struct of_device_id omap_i2c_of_match[] = {
|
|
|
MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
|
|
|
#endif
|
|
|
|
|
|
+#define OMAP_I2C_SCHEME(rev) ((rev & 0xc000) >> 14)
|
|
|
+
|
|
|
+#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4)
|
|
|
+#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf)
|
|
|
+
|
|
|
+#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7)
|
|
|
+#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f)
|
|
|
+#define OMAP_I2C_SCHEME_0 0
|
|
|
+#define OMAP_I2C_SCHEME_1 1
|
|
|
+
|
|
|
static int __devinit
|
|
|
omap_i2c_probe(struct platform_device *pdev)
|
|
|
{
|
|
@@ -1060,6 +1081,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
const struct of_device_id *match;
|
|
|
int irq;
|
|
|
int r;
|
|
|
+ u32 rev;
|
|
|
+ u16 minor, major, scheme;
|
|
|
|
|
|
/* NOTE: driver uses the static register mapping */
|
|
|
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
@@ -1091,7 +1114,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
u32 freq = 100000; /* default to 100000 Hz */
|
|
|
|
|
|
pdata = match->data;
|
|
|
- dev->dtrev = pdata->rev;
|
|
|
dev->flags = pdata->flags;
|
|
|
|
|
|
of_property_read_u32(node, "clock-frequency", &freq);
|
|
@@ -1101,7 +1123,16 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
dev->speed = pdata->clkrate;
|
|
|
dev->flags = pdata->flags;
|
|
|
dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
|
|
|
- dev->dtrev = pdata->rev;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev->pins = devm_pinctrl_get_select_default(&pdev->dev);
|
|
|
+ if (IS_ERR(dev->pins)) {
|
|
|
+ if (PTR_ERR(dev->pins) == -EPROBE_DEFER)
|
|
|
+ return -EPROBE_DEFER;
|
|
|
+
|
|
|
+ dev_warn(&pdev->dev, "did not get pins for i2c error: %li\n",
|
|
|
+ PTR_ERR(dev->pins));
|
|
|
+ dev->pins = NULL;
|
|
|
}
|
|
|
|
|
|
dev->dev = &pdev->dev;
|
|
@@ -1114,11 +1145,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
|
|
|
dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
|
|
|
|
|
|
- if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
|
|
|
- dev->regs = (u8 *)reg_map_ip_v2;
|
|
|
- else
|
|
|
- dev->regs = (u8 *)reg_map_ip_v1;
|
|
|
-
|
|
|
pm_runtime_enable(dev->dev);
|
|
|
pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
|
|
|
pm_runtime_use_autosuspend(dev->dev);
|
|
@@ -1127,11 +1153,37 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
if (IS_ERR_VALUE(r))
|
|
|
goto err_free_mem;
|
|
|
|
|
|
- dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
|
|
|
+ /*
|
|
|
+ * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
|
|
|
+ * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset.
|
|
|
+ * Also since the omap_i2c_read_reg uses reg_map_ip_* a
|
|
|
+ * raw_readw is done.
|
|
|
+ */
|
|
|
+ rev = __raw_readw(dev->base + 0x04);
|
|
|
+
|
|
|
+ scheme = OMAP_I2C_SCHEME(rev);
|
|
|
+ switch (scheme) {
|
|
|
+ case OMAP_I2C_SCHEME_0:
|
|
|
+ dev->regs = (u8 *)reg_map_ip_v1;
|
|
|
+ dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG);
|
|
|
+ minor = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev);
|
|
|
+ major = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev);
|
|
|
+ break;
|
|
|
+ case OMAP_I2C_SCHEME_1:
|
|
|
+ /* FALLTHROUGH */
|
|
|
+ default:
|
|
|
+ dev->regs = (u8 *)reg_map_ip_v2;
|
|
|
+ rev = (rev << 16) |
|
|
|
+ omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO);
|
|
|
+ minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev);
|
|
|
+ major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev);
|
|
|
+ dev->rev = rev;
|
|
|
+ }
|
|
|
|
|
|
dev->errata = 0;
|
|
|
|
|
|
- if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
|
|
|
+ if (dev->rev >= OMAP_I2C_REV_ON_2430 &&
|
|
|
+ dev->rev < OMAP_I2C_REV_ON_4430_PLUS)
|
|
|
dev->errata |= I2C_OMAP_ERRATA_I207;
|
|
|
|
|
|
if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
|
|
@@ -1152,7 +1204,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
|
|
|
dev->fifo_size = (dev->fifo_size / 2);
|
|
|
|
|
|
- if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
|
|
|
+ if (dev->rev < OMAP_I2C_REV_ON_3630)
|
|
|
dev->b_hw = 1; /* Enable hardware fixes */
|
|
|
|
|
|
/* calculate wakeup latency constraint for MPU */
|
|
@@ -1195,8 +1247,8 @@ omap_i2c_probe(struct platform_device *pdev)
|
|
|
goto err_unuse_clocks;
|
|
|
}
|
|
|
|
|
|
- dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr,
|
|
|
- dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
|
|
|
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
|
|
|
+ major, minor, dev->speed);
|
|
|
|
|
|
of_i2c_register_devices(adap);
|
|
|
|
|
@@ -1239,14 +1291,13 @@ static int omap_i2c_runtime_suspend(struct device *dev)
|
|
|
{
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
|
|
- u16 iv;
|
|
|
|
|
|
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
|
|
|
|
|
|
omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
|
|
|
|
|
|
if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
|
|
|
- iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
|
|
|
+ omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
|
|
|
} else {
|
|
|
omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
|
|
|
|
|
@@ -1262,23 +1313,10 @@ static int omap_i2c_runtime_resume(struct device *dev)
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
|
|
|
|
|
|
- if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
|
|
|
- }
|
|
|
+ if (!_dev->regs)
|
|
|
+ return 0;
|
|
|
|
|
|
- /*
|
|
|
- * Don't write to this register if the IE state is 0 as it can
|
|
|
- * cause deadlock.
|
|
|
- */
|
|
|
- if (_dev->iestate)
|
|
|
- omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
|
|
|
+ __omap_i2c_init(_dev);
|
|
|
|
|
|
return 0;
|
|
|
}
|