
Convert omap24xx_i2c driver to DM
Signed-off-by: Christophe Ricard christophe-h.ricard@st.com ---
drivers/i2c/Kconfig | 8 ++ drivers/i2c/omap24xx_i2c.c | 280 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 277 insertions(+), 11 deletions(-)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 14adda2..3498af1 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -58,6 +58,14 @@ config DM_I2C_GPIO bindings are supported. Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
+config SYS_I2C_OMAP24XX + bool "Texas Instrument OMAP I2C driver" + depends on DM_I2C + help + Enable support for the I2C interface on the Texas Instruments + OMAP1/2 family of processors. Like OMAP1510/1610/1710/5912 and OMAP242x. + For details see http://www.ti.com/omap. + config SYS_I2C_ROCKCHIP bool "Rockchip I2C driver" depends on DM_I2C diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 79a5c94..f3a4d96 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -36,13 +36,18 @@ * Copyright (c) 2014 Hannes Schmelzer oe5hpm@oevsv.at, B&R * - Added support for set_speed * + * Copyright (c) 2016 Christophe Ricard christophe.ricard@gmail.com + * - Added support for DM_I2C + * */
#include <common.h> #include <i2c.h> +#include <dm.h>
#include <asm/arch/i2c.h> #include <asm/io.h> +#include <asm/errno.h>
#include "omap24xx_i2c.h"
@@ -53,10 +58,26 @@ DECLARE_GLOBAL_DATA_PTR; /* Absolutely safe for status update at 100 kHz I2C: */ #define I2C_WAIT 200
+#ifdef CONFIG_DM_I2C +struct omap24_i2c_bus { + int bus_num; + int waitdelay; + unsigned clock_frequency; + struct i2c *i2c_base; +}; +#endif + +#ifdef CONFIG_SYS_I2C static int wait_for_bb(struct i2c_adapter *adap); static struct i2c *omap24_get_base(struct i2c_adapter *adap); static u16 wait_for_event(struct i2c_adapter *adap); static void flush_fifo(struct i2c_adapter *adap); +#else +static int wait_for_bb(struct udevice *dev); +static u16 wait_for_event(struct udevice *dev); +static void flush_fifo(struct udevice *dev); +#endif + static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed) { unsigned int sampleclk, prescaler; @@ -90,13 +111,27 @@ static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed) } return -1; } + +#ifdef CONFIG_SYS_I2C static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) +#else +static int omap24_i2c_setspeed(struct udevice *adap, unsigned int speed) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int psc, fsscll = 0, fssclh = 0; int hsscll = 0, hssclh = 0; u32 scll = 0, sclh = 0;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + if (speed >= OMAP_I2C_HIGH_SPEED) { /* High speed */ psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK; @@ -142,8 +177,14 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) } }
+#ifdef CONFIG_SYS_I2C adap->speed = speed; adap->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */ +#else + i2c_bus->clock_frequency = speed; + i2c_bus->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */ +#endif + writew(0, &i2c_base->con); writew(psc, &i2c_base->psc); writew(scll, &i2c_base->scll); @@ -154,13 +195,26 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed) return 0; }
+#ifdef CONFIG_SYS_I2C static void omap24_i2c_deblock(struct i2c_adapter *adap) +#else +static int omap24_i2c_deblock(struct udevice *adap) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int i; u16 systest; u16 orgsystest;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + /* set test mode ST_EN = 1 */ orgsystest = readw(&i2c_base->systest); systest = orgsystest; @@ -198,14 +252,31 @@ static void omap24_i2c_deblock(struct i2c_adapter *adap)
/* restore original mode */ writew(orgsystest, &i2c_base->systest); + +#ifdef CONFIG_DM_I2C + return 0; +#endif }
+#ifdef CONFIG_SYS_I2C static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) +#else +static void omap24_i2c_init(struct udevice *adap, int speed, int slaveadd) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int timeout = I2C_TIMEOUT; int deblock = 1;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + retry: if (readw(&i2c_base->con) & I2C_CON_EN) { writew(0, &i2c_base->con); @@ -253,11 +324,24 @@ retry: } }
+#ifdef CONFIG_SYS_I2C static void flush_fifo(struct i2c_adapter *adap) +#else +static void flush_fifo(struct udevice *adap) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; u16 stat;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + /* * note: if you try and read data when its not there or ready * you get a bus error @@ -277,12 +361,25 @@ static void flush_fifo(struct i2c_adapter *adap) * i2c_probe: Use write access. Allows to identify addresses that are * write-only (like the config register of dual-port EEPROMs) */ +#ifdef CONFIG_SYS_I2C static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip) +#else +static int omap24_i2c_probe(struct udevice *adap, uint chip, uint chip_flags) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; u16 status; int res = 1; /* default = fail */
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + if (chip == readw(&i2c_base->oa)) return res;
@@ -305,17 +402,26 @@ static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip) * silent exit is desired upon unconfigured bus, remove the * following 'if' section: */ - if (status == I2C_STAT_XRDY) + if (status == I2C_STAT_XRDY) { +#ifdef CONFIG_SYS_I2C printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n", adap->hwadapnr, status); - +#else + printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n", + i2c_bus->bus_num, status); +#endif + } goto pr_exit; }
/* Check for ACK (!NAK) */ if (!(status & I2C_STAT_NACK)) { res = 0; /* Device found */ +#ifdef CONFIG_SYS_I2C udelay(adap->waitdelay);/* Required by AM335X in SPL */ +#else + udelay(i2c_bus->waitdelay); +#endif /* Abort transfer (force idle state) */ writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */ udelay(1000); @@ -341,13 +447,27 @@ pr_exit: * or that do not need a register address at all (such as some clock * distributors). */ +#ifdef CONFIG_SYS_I2C static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len) +#else +static int omap24_i2c_read(struct udevice *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int i2c_error = 0; u16 status;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + if (alen < 0) { puts("I2C read: addr len < 0\n"); return 1; @@ -397,8 +517,13 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; +#ifdef CONFIG_SYS_I2C printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n", adap->hwadapnr, status); +#else + printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n", + i2c_bus->bus_num, status); +#endif goto rd_exit; } if (status == 0 || (status & I2C_STAT_NACK)) { @@ -441,8 +566,13 @@ static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, */ if (status == I2C_STAT_XRDY) { i2c_error = 2; +#ifdef CONFIG_SYS_I2C printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n", adap->hwadapnr, status); +#else + printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n", + i2c_bus->bus_num, status); +#endif goto rd_exit; } if (status == 0 || (status & I2C_STAT_NACK)) { @@ -466,15 +596,29 @@ rd_exit: }
/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */ +#ifdef CONFIG_SYS_I2C static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, int alen, uchar *buffer, int len) +#else +static int omap24_i2c_write(struct udevice *adap, uchar chip, uint addr, + int alen, uchar *buffer, int len) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int i; u16 status; int i2c_error = 0; int timeout = I2C_TIMEOUT;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + if (alen < 0) { puts("I2C write: addr len < 0\n"); return 1; @@ -519,8 +663,13 @@ static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, /* Try to identify bus that is not padconf'd for I2C */ if (status == I2C_STAT_XRDY) { i2c_error = 2; +#ifdef CONFIG_SYS_I2C printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n", adap->hwadapnr, status); +#else + printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n", + i2c_bus->bus_num, status); +#endif goto wr_exit; } if (status == 0 || (status & I2C_STAT_NACK)) { @@ -579,12 +728,25 @@ wr_exit: * Wait for the bus to be free by checking the Bus Busy (BB) * bit to become clear */ +#ifdef CONFIG_SYS_I2C static int wait_for_bb(struct i2c_adapter *adap) +#else +static int wait_for_bb(struct udevice *adap) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; int timeout = I2C_TIMEOUT; u16 stat;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/ #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) { @@ -594,7 +756,11 @@ static int wait_for_bb(struct i2c_adapter *adap) I2C_STAT_BB) && timeout--) { #endif writew(stat, &i2c_base->stat); +#ifdef CONFIG_SYS_I2C udelay(adap->waitdelay); +#else + udelay(i2c_bus->waitdelay); +#endif }
if (timeout <= 0) { @@ -610,14 +776,31 @@ static int wait_for_bb(struct i2c_adapter *adap) * Wait for the I2C controller to complete current action * and update status */ +#ifdef CONFIG_SYS_I2C static u16 wait_for_event(struct i2c_adapter *adap) +#else +static u16 wait_for_event(struct udevice *adap) +#endif { - struct i2c *i2c_base = omap24_get_base(adap); + struct i2c *i2c_base; u16 status; int timeout = I2C_TIMEOUT;
+#ifdef CONFIG_SYS_I2C + i2c_base = omap24_get_base(adap); +#else + struct omap24_i2c_bus *i2c_bus; + + i2c_bus = dev_get_priv(adap); + i2c_base = i2c_bus->i2c_base; +#endif + do { +#ifdef CONFIG_SYS_I2C udelay(adap->waitdelay); +#else + udelay(i2c_bus->waitdelay); +#endif #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) status = readw(&i2c_base->stat); #else @@ -636,8 +819,13 @@ static u16 wait_for_event(struct i2c_adapter *adap) * If status is still 0 here, probably the bus pads have * not been configured for I2C, and/or pull-ups are missing. */ +#ifdef CONFIG_SYS_I2C printf("Check if pads/pull-ups of bus %d are properly configured\n", adap->hwadapnr); +#else + printf("Check if pads/pull-ups of bus %d are properly configured\n", + i2c_bus->bus_num); +#endif writew(0xFFFF, &i2c_base->stat); status = 0; } @@ -645,6 +833,7 @@ static u16 wait_for_event(struct i2c_adapter *adap) return status; }
+#ifdef CONFIG_SYS_I2C static struct i2c *omap24_get_base(struct i2c_adapter *adap) { switch (adap->hwadapnr) { @@ -735,3 +924,72 @@ U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe, #endif #endif #endif +#endif + +#ifdef CONFIG_DM_I2C +static int omap24_i2c_xfer(struct udevice *adap, struct i2c_msg *msg, + int nmsgs) +{ + int ret; + + for (; nmsgs > 0; nmsgs--, msg++) { + if (msg->flags & I2C_M_RD) { + ret = omap24_i2c_read(adap, msg->addr, 0, 0, msg->buf, + msg->len); + } else { + ret = omap24_i2c_write(adap, msg->addr, 0, 0, msg->buf, + msg->len); + } + + if (ret) + return -EREMOTEIO; + } + + return 0; +} + +static int omap24_i2c_ofdata_to_platdata(struct udevice *adap) +{ + const void *blob = gd->fdt_blob; + struct omap24_i2c_bus *i2c_bus = dev_get_priv(adap); + int node; + + node = adap->of_offset; + + i2c_bus->clock_frequency = fdtdec_get_int(blob, node, + "clock-frequency", 100000); + i2c_bus->i2c_base = (struct i2c *)dev_get_addr(adap); + i2c_bus->waitdelay = (10000000 / i2c_bus->clock_frequency) * 2; /* wait for 20 clkperiods */ + + i2c_bus->bus_num = adap->seq; + + omap24_i2c_init(adap, i2c_bus->clock_frequency, 1); + + return 0; +} + +static const struct dm_i2c_ops omap24_i2c_ops = { + .xfer = omap24_i2c_xfer, + .probe_chip = omap24_i2c_probe, + .set_bus_speed = omap24_i2c_setspeed, + .deblock = omap24_i2c_deblock, +}; + +static const struct udevice_id omap24_i2c_ids[] = { + { .compatible = "ti,omap3-i2c" }, + { .compatible = "ti,omap4-i2c" }, + { .compatible = "ti,omap2430-i2c" }, + { .compatible = "ti,omap2420-i2c" }, + { } +}; + +U_BOOT_DRIVER(omap_i2c) = { + .name = "omap_i2c", + .id = UCLASS_I2C, + .of_match = omap24_i2c_ids, + .ofdata_to_platdata = omap24_i2c_ofdata_to_platdata, + .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), + .priv_auto_alloc_size = sizeof(struct omap24_i2c_bus), + .ops = &omap24_i2c_ops, +}; +#endif