diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 1098 |
1 files changed, 693 insertions, 405 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 142b694d1c60..d9f590f0c384 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * TI OMAP I2C master mode driver * @@ -12,20 +13,6 @@ * Juha Yrjölä <juha.yrjola@solidboot.com> * Syed Khasim <x0khasim@ti.com> * Nishant Menon <nm@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -37,13 +24,13 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/mux/consumer.h> #include <linux/of.h> -#include <linux/of_i2c.h> -#include <linux/of_device.h> #include <linux/slab.h> -#include <linux/i2c-omap.h> +#include <linux/platform_data/i2c-omap.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/consumer.h> +#include <linux/property.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -60,6 +47,9 @@ /* timeout for pm runtime autosuspend */ #define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ +/* timeout for making decision on bus free status */ +#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10)) + /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ enum { OMAP_I2C_REV_REG = 0, @@ -104,7 +94,7 @@ enum { #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ #define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */ -#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */ +#define OMAP_I2C_STAT_BF (1 << 8) /* Bus Free */ #define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ #define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */ #define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */ @@ -152,16 +142,20 @@ enum { #define OMAP_I2C_SCLH_HSSCLH 8 /* I2C System Test Register (OMAP_I2C_SYSTEST): */ -#ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */ +/* Functional mode */ +#define OMAP_I2C_SYSTEST_SCL_I_FUNC (1 << 8) /* SCL line input value */ +#define OMAP_I2C_SYSTEST_SCL_O_FUNC (1 << 7) /* SCL line output value */ +#define OMAP_I2C_SYSTEST_SDA_I_FUNC (1 << 6) /* SDA line input value */ +#define OMAP_I2C_SYSTEST_SDA_O_FUNC (1 << 5) /* SDA line output value */ +/* SDA/SCL IO mode */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */ -#endif /* OCP_SYSSTATUS bit definitions */ #define SYSS_RESETDONE_MASK (1 << 0) @@ -183,7 +177,6 @@ enum { #define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF struct omap_i2c_dev { - spinlock_t lock; /* IRQ synchronization */ struct device *dev; void __iomem *base; /* virtual */ int irq; @@ -208,6 +201,9 @@ struct omap_i2c_dev { */ u32 rev; unsigned b_hw:1; /* bad h/w fixes */ + unsigned bb_valid:1; /* true when BB-bit reflects + * the I2C bus state + */ unsigned receiver:1; /* true when we're in receiver mode */ u16 iestate; /* Saved interrupt register */ u16 pscstate; @@ -216,8 +212,7 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; - - struct pinctrl *pins; + struct mux_state *mux_state; }; static const u8 reg_map_ip_v1[] = { @@ -267,66 +262,74 @@ static const u8 reg_map_ip_v2[] = { [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, }; -static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap); + +static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, int reg, u16 val) { - __raw_writew(val, i2c_dev->base + - (i2c_dev->regs[reg] << i2c_dev->reg_shift)); + writew_relaxed(val, omap->base + + (omap->regs[reg] << omap->reg_shift)); } -static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) +static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg) { - return __raw_readw(i2c_dev->base + - (i2c_dev->regs[reg] << i2c_dev->reg_shift)); + return readw_relaxed(omap->base + + (omap->regs[reg] << omap->reg_shift)); } -static void __omap_i2c_init(struct omap_i2c_dev *dev) +static void __omap_i2c_init(struct omap_i2c_dev *omap) { - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_write_reg(omap, 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); + omap_i2c_write_reg(omap, OMAP_I2C_PSC_REG, omap->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); + omap_i2c_write_reg(omap, OMAP_I2C_SCLL_REG, omap->scllstate); + omap_i2c_write_reg(omap, OMAP_I2C_SCLH_REG, omap->sclhstate); + if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) + omap_i2c_write_reg(omap, OMAP_I2C_WE_REG, omap->westate); /* Take the I2C module out of reset: */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + + /* + * NOTE: right after setting CON_EN, STAT_BB could be 0 while the + * bus is busy. It will be changed to 1 on the next IP FCLK clock. + * udelay(1) will be enough to fix that. + */ /* * 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); + if (omap->iestate) + omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate); } -static int omap_i2c_reset(struct omap_i2c_dev *dev) +static int omap_i2c_reset(struct omap_i2c_dev *omap) { unsigned long timeout; u16 sysc; - if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { - sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG); + if (omap->rev >= OMAP_I2C_OMAP1_REV_2) { + sysc = omap_i2c_read_reg(omap, 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) & + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, + omap_i2c_read_reg(omap, OMAP_I2C_CON_REG) & ~(OMAP_I2C_CON_EN)); - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); + omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); /* For some reason we need to set the EN bit before the * reset done bit gets set. */ timeout = jiffies + OMAP_I2C_TIMEOUT; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) & + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + while (!(omap_i2c_read_reg(omap, OMAP_I2C_SYSS_REG) & SYSS_RESETDONE_MASK)) { if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting " + dev_warn(omap->dev, "timeout waiting " "for controller reset\n"); return -ETIMEDOUT; } @@ -334,37 +337,50 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) } /* SYSC register is cleared by the reset; rewrite it */ - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); + omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, sysc); + if (omap->rev > OMAP_I2C_REV_ON_3430_3530) { + /* Schedule I2C-bus monitoring on the next transfer */ + omap->bb_valid = 0; + } } + return 0; } -static int omap_i2c_init(struct omap_i2c_dev *dev) +static int omap_i2c_init(struct omap_i2c_dev *omap) { 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; + int error; - if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { + if (omap->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->westate = OMAP_I2C_WE_ALL; } - if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { + if (omap->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420 * always returns 12MHz for the functional clock, we can * do this bit unconditionally. */ - fclk = clk_get(dev->dev, "fck"); + fclk = clk_get(omap->dev, "fck"); + if (IS_ERR(fclk)) { + error = PTR_ERR(fclk); + dev_err(omap->dev, "could not get fck: %i\n", error); + + return error; + } + fclk_rate = clk_get_rate(fclk); clk_put(fclk); @@ -381,7 +397,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { + if (!(omap->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -389,14 +405,20 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * to get longer filter period for better noise suppression. * The filter is iclk (fclk for HS) period. */ - if (dev->speed > 400 || - dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) + if (omap->speed > 400 || + omap->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) internal_clk = 19200; - else if (dev->speed > 100) + else if (omap->speed > 100) internal_clk = 9600; else internal_clk = 4000; - fclk = clk_get(dev->dev, "fck"); + fclk = clk_get(omap->dev, "fck"); + if (IS_ERR(fclk)) { + error = PTR_ERR(fclk); + dev_err(omap->dev, "could not get fck: %i\n", error); + + return error; + } fclk_rate = clk_get_rate(fclk) / 1000; clk_put(fclk); @@ -405,7 +427,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = psc - 1; /* If configured for High Speed */ - if (dev->speed > 400) { + if (omap->speed > 400) { unsigned long scl; /* For first phase of HS mode */ @@ -414,20 +436,20 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - scl = fclk_rate / dev->speed; + scl = fclk_rate / omap->speed; hsscll = scl - (scl / 3) - 7; hssclh = (scl / 3) - 5; - } else if (dev->speed > 100) { + } else if (omap->speed > 100) { unsigned long scl; /* Fast mode */ - scl = internal_clk / dev->speed; + scl = internal_clk / omap->speed; fsscll = scl - (scl / 3) - 7; fssclh = (scl / 3) - 5; } else { /* Standard mode */ - fsscll = internal_clk / (dev->speed * 2) - 7; - fssclh = internal_clk / (dev->speed * 2) - 5; + fsscll = internal_clk / (omap->speed * 2) - 7; + fssclh = internal_clk / (omap->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; @@ -436,48 +458,157 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) fclk_rate /= (psc + 1) * 1000; if (psc > 2) psc = 2; - scll = fclk_rate / (dev->speed * 2) - 7 + psc; - sclh = fclk_rate / (dev->speed * 2) - 7 + psc; + scll = fclk_rate / (omap->speed * 2) - 7 + psc; + sclh = fclk_rate / (omap->speed * 2) - 7 + psc; } - dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | + omap->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_AL) | ((omap->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); - dev->pscstate = psc; - dev->scllstate = scll; - dev->sclhstate = sclh; + omap->pscstate = psc; + omap->scllstate = scll; + omap->sclhstate = sclh; - __omap_i2c_init(dev); + if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) { + /* Not implemented */ + omap->bb_valid = 1; + } + + __omap_i2c_init(omap); return 0; } /* + * Try bus recovery, but only if SDA is actually low. + */ +static int omap_i2c_recover_bus(struct omap_i2c_dev *omap) +{ + u16 systest; + + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); + if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && + (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) + return 0; /* bus seems to already be fine */ + if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC)) + return -EBUSY; /* recovery would not fix SCL */ + return i2c_recover_bus(&omap->adapter); +} + +/* * Waiting on Bus Busy */ -static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) +static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) { unsigned long timeout; timeout = jiffies + OMAP_I2C_TIMEOUT; - while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { + while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { + if (time_after(jiffies, timeout)) + return omap_i2c_recover_bus(omap); + msleep(1); + } + + return 0; +} + +/* + * Wait while BB-bit doesn't reflect the I2C bus state + * + * In a multimaster environment, after IP software reset, BB-bit value doesn't + * correspond to the current bus state. It may happen what BB-bit will be 0, + * while the bus is busy due to another I2C master activity. + * Here are BB-bit values after reset: + * SDA SCL BB NOTES + * 0 0 0 1, 2 + * 1 0 0 1, 2 + * 0 1 1 + * 1 1 0 3 + * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START) + * combinations on the bus, it set BB-bit to 1. + * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus, + * it set BB-bit to 0 and BF to 1. + * BB and BF bits correctly tracks the bus state while IP is suspended + * BB bit became valid on the next FCLK clock after CON_EN bit set + * + * NOTES: + * 1. Any transfer started when BB=0 and bus is busy wouldn't be + * completed by IP and results in controller timeout. + * 2. Any transfer started when BB=0 and SCL=0 results in IP + * starting to drive SDA low. In that case IP corrupt data + * on the bus. + * 3. Any transfer started in the middle of another master's transfer + * results in unpredictable results and data corruption + */ +static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) +{ + unsigned long bus_free_timeout = 0; + unsigned long timeout; + int bus_free = 0; + u16 stat, systest; + + if (omap->bb_valid) + return 0; + + timeout = jiffies + OMAP_I2C_TIMEOUT; + while (1) { + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); + /* + * We will see BB or BF event in a case IP had detected any + * activity on the I2C bus. Now IP correctly tracks the bus + * state. BB-bit value is valid. + */ + if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF)) + break; + + /* + * Otherwise, we must look signals on the bus to make + * the right decision. + */ + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); + if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && + (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) { + if (!bus_free) { + bus_free_timeout = jiffies + + OMAP_I2C_BUS_FREE_TIMEOUT; + bus_free = 1; + } + + /* + * SDA and SCL lines was high for 10 ms without bus + * activity detected. The bus is free. Consider + * BB-bit value is valid. + */ + if (time_after(jiffies, bus_free_timeout)) + break; + } else { + bus_free = 0; + } + if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + /* + * SDA or SCL were low for the entire timeout without + * any activity detected. Most likely, a slave is + * locking up the bus with no master driving the clock. + */ + dev_warn(omap->dev, "timeout waiting for bus ready\n"); + return omap_i2c_recover_bus(omap); } + msleep(1); } + omap->bb_valid = 1; return 0; } -static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx) { u16 buf; - if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + if (omap->flags & OMAP_I2C_FLAG_NO_FIFO) return; /* @@ -487,73 +618,84 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) * then we might use draining feature to transfer the remaining bytes. */ - dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + omap->threshold = clamp(size, (u8) 1, omap->fifo_size); - buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + buf = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); if (is_rx) { /* Clear RX Threshold */ buf &= ~(0x3f << 8); - buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + buf |= ((omap->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; } else { /* Clear TX Threshold */ buf &= ~0x3f; - buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + buf |= (omap->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; } - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, buf); - if (dev->rev < OMAP_I2C_REV_ON_3630) - dev->b_hw = 1; /* Enable hardware fixes */ + if (omap->rev < OMAP_I2C_REV_ON_3630) + omap->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->threshold) / - (1000 * dev->speed / 8); + if (omap->set_mpu_wkup_lat != NULL) + omap->latency = (1000000 * omap->threshold) / + (1000 * omap->speed / 8); +} + +static void omap_i2c_wait(struct omap_i2c_dev *omap) +{ + u16 stat; + u16 mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + int count = 0; + + do { + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); + count++; + } while (!(stat & mask) && count < 5); } /* * Low level master read/write transaction. */ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, - struct i2c_msg *msg, int stop) + struct i2c_msg *msg, int stop, bool polling) { - struct omap_i2c_dev *dev = i2c_get_adapdata(adap); - unsigned long timeout; + struct omap_i2c_dev *omap = i2c_get_adapdata(adap); + unsigned long time_left; u16 w; + int ret; - dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", + dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); - if (msg->len == 0) - return -EINVAL; - - dev->receiver = !!(msg->flags & I2C_M_RD); - omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(omap, msg->len, omap->receiver); - omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); + omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ - dev->buf = msg->buf; - dev->buf_len = msg->len; + omap->buf = msg->buf; + omap->buf_len = msg->len; - /* make sure writes to dev->buf_len are ordered */ + /* make sure writes to omap->buf_len are ordered */ barrier(); - omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); + omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len); /* Clear the FIFO Buffers */ - w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + w = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); - INIT_COMPLETION(dev->cmd_complete); - dev->cmd_err = 0; + if (!polling) + reinit_completion(&omap->cmd_complete); + omap->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; /* High speed configuration */ - if (dev->speed > 400) + if (omap->speed > 400) w |= OMAP_I2C_CON_OPMODE_HS; if (msg->flags & I2C_M_STOP) @@ -563,23 +705,27 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (!(msg->flags & I2C_M_RD)) w |= OMAP_I2C_CON_TRX; - if (!dev->b_hw && stop) + if (!omap->b_hw && stop) w |= OMAP_I2C_CON_STP; - - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + /* + * NOTE: STAT_BB bit could became 1 here if another master occupy + * the bus. IP successfully complete transfer when the bus will be + * free again (BB reset to 0). + */ + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); /* * Don't write stt and stp together on some hardware. */ - if (dev->b_hw && stop) { + if (omap->b_hw && stop) { unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; - u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + u16 con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); while (con & OMAP_I2C_CON_STT) { - con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); /* Let the user know if i2c is in a bad state */ if (time_after(jiffies, delay)) { - dev_err(dev->dev, "controller timed out " + dev_err(omap->dev, "controller timed out " "waiting for start condition to finish\n"); return -ETIMEDOUT; } @@ -588,41 +734,51 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_CON_STP; w &= ~OMAP_I2C_CON_STT; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); } /* * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - timeout = wait_for_completion_timeout(&dev->cmd_complete, - OMAP_I2C_TIMEOUT); - if (timeout == 0) { - dev_err(dev->dev, "controller timed out\n"); - omap_i2c_reset(dev); - __omap_i2c_init(dev); + if (!polling) { + time_left = wait_for_completion_timeout(&omap->cmd_complete, + OMAP_I2C_TIMEOUT); + } else { + do { + omap_i2c_wait(omap); + ret = omap_i2c_xfer_data(omap); + } while (ret == -EAGAIN); + + time_left = !ret; + } + + if (time_left == 0) { + omap_i2c_reset(omap); + __omap_i2c_init(omap); return -ETIMEDOUT; } - if (likely(!dev->cmd_err)) + if (likely(!omap->cmd_err)) return 0; /* We have an error */ - if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | - OMAP_I2C_STAT_XUDF)) { - omap_i2c_reset(dev); - __omap_i2c_init(dev); + if (omap->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { + omap_i2c_reset(omap); + __omap_i2c_init(omap); return -EIO; } - if (dev->cmd_err & OMAP_I2C_STAT_NACK) { + if (omap->cmd_err & OMAP_I2C_STAT_AL) + return -EAGAIN; + + if (omap->cmd_err & OMAP_I2C_STAT_NACK) { if (msg->flags & I2C_M_IGNORE_NAK) return 0; - if (stop) { - w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); - w |= OMAP_I2C_CON_STP; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); - } + + w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); + w |= OMAP_I2C_CON_STP; + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); return -EREMOTEIO; } return -EIO; @@ -634,25 +790,31 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * to do the work during IRQ processing. */ static int -omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num, + bool polling) { - struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + struct omap_i2c_dev *omap = i2c_get_adapdata(adap); int i; int r; - r = pm_runtime_get_sync(dev->dev); - if (IS_ERR_VALUE(r)) + r = pm_runtime_get_sync(omap->dev); + if (r < 0) + goto out; + + r = omap_i2c_wait_for_bb_valid(omap); + if (r < 0) goto out; - r = omap_i2c_wait_for_bb(dev); + r = omap_i2c_wait_for_bb(omap); if (r < 0) goto out; - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); + if (omap->set_mpu_wkup_lat != NULL) + omap->set_mpu_wkup_lat(omap->dev, omap->latency); for (i = 0; i < num; i++) { - r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); + r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)), + polling); if (r != 0) break; } @@ -660,17 +822,28 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r == 0) r = num; - omap_i2c_wait_for_bb(dev); + omap_i2c_wait_for_bb(omap); - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); + if (omap->set_mpu_wkup_lat != NULL) + omap->set_mpu_wkup_lat(omap->dev, -1); out: - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_put_autosuspend(omap->dev); return r; } +static int +omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + return omap_i2c_xfer_common(adap, msgs, num, false); +} + +static int +omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + return omap_i2c_xfer_common(adap, msgs, num, true); +} + static u32 omap_i2c_func(struct i2c_adapter *adap) { @@ -679,19 +852,19 @@ omap_i2c_func(struct i2c_adapter *adap) } static inline void -omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err) +omap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err) { - dev->cmd_err |= err; - complete(&dev->cmd_complete); + omap->cmd_err |= err; + complete(&omap->cmd_complete); } static inline void -omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat) +omap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat) { - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); + omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, stat); } -static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) +static inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat) { /* * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8) @@ -702,17 +875,17 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) */ if (stat & OMAP_I2C_STAT_RDR) { /* Step 1: If RDR is set, clear it */ - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); /* Step 2: */ - if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + if (!(omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB)) { /* Step 3: */ - if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + if (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_RDR) { - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); - dev_dbg(dev->dev, "RDR when bus is busy.\n"); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); + dev_dbg(omap->dev, "RDR when bus is busy.\n"); } } @@ -725,50 +898,50 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) static irqreturn_t omap_i2c_omap1_isr(int this_irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; u16 iv, w; - if (pm_runtime_suspended(dev->dev)) + if (pm_runtime_suspended(omap->dev)) return IRQ_NONE; - iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); + iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); switch (iv) { case 0x00: /* None */ break; case 0x01: /* Arbitration lost */ - dev_err(dev->dev, "Arbitration lost\n"); - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL); + dev_err(omap->dev, "Arbitration lost\n"); + omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL); break; case 0x02: /* No acknowledgement */ - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP); + omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP); break; case 0x03: /* Register access ready */ - omap_i2c_complete_cmd(dev, 0); + omap_i2c_complete_cmd(omap, 0); break; case 0x04: /* Receive data ready */ - if (dev->buf_len) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; + if (omap->buf_len) { + w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); + *omap->buf++ = w; + omap->buf_len--; + if (omap->buf_len) { + *omap->buf++ = w >> 8; + omap->buf_len--; } } else - dev_err(dev->dev, "RRDY IRQ while no data requested\n"); + dev_err(omap->dev, "RRDY IRQ while no data requested\n"); break; case 0x05: /* Transmit data ready */ - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; + if (omap->buf_len) { + w = *omap->buf++; + omap->buf_len--; + if (omap->buf_len) { + w |= *omap->buf++ << 8; + omap->buf_len--; } - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); } else - dev_err(dev->dev, "XRDY IRQ while no data to send\n"); + dev_err(omap->dev, "XRDY IRQ while no data to send\n"); break; default: return IRQ_NONE; @@ -785,28 +958,28 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev) +static int errata_omap3_i462(struct omap_i2c_dev *omap) { unsigned long timeout = 10000; u16 stat; do { - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); if (stat & OMAP_I2C_STAT_XUDF) break; if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); if (stat & OMAP_I2C_STAT_NACK) { - dev->cmd_err |= OMAP_I2C_STAT_NACK; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); } if (stat & OMAP_I2C_STAT_AL) { - dev_err(dev->dev, "Arbitration lost\n"); - dev->cmd_err |= OMAP_I2C_STAT_AL; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + dev_err(omap->dev, "Arbitration lost\n"); + omap->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); } return -EIO; @@ -816,137 +989,120 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) } while (--timeout); if (!timeout) { - dev_err(dev->dev, "timeout waiting on XUDF bit\n"); + dev_err(omap->dev, "timeout waiting on XUDF bit\n"); return 0; } return 0; } -static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, +static void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes, bool is_rdr) { u16 w; while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; + w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); + *omap->buf++ = w; + omap->buf_len--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - *dev->buf++ = w >> 8; - dev->buf_len--; + if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + *omap->buf++ = w >> 8; + omap->buf_len--; } } } -static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, +static int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes, bool is_xdr) { u16 w; while (num_bytes--) { - w = *dev->buf++; - dev->buf_len--; + w = *omap->buf++; + omap->buf_len--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - w |= *dev->buf++ << 8; - dev->buf_len--; + if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + w |= *omap->buf++ << 8; + omap->buf_len--; } - if (dev->errata & I2C_OMAP_ERRATA_I462) { + if (omap->errata & I2C_OMAP_ERRATA_I462) { int ret; - ret = errata_omap3_i462(dev); + ret = errata_omap3_i462(omap); if (ret < 0) return ret; } - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); } return 0; } -static irqreturn_t -omap_i2c_isr(int irq, void *dev_id) +static int omap_i2c_xfer_data(struct omap_i2c_dev *omap) { - struct omap_i2c_dev *dev = dev_id; - irqreturn_t ret = IRQ_HANDLED; - u16 mask; - u16 stat; - - spin_lock(&dev->lock); - mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - - if (stat & mask) - ret = IRQ_WAKE_THREAD; - - spin_unlock(&dev->lock); - - return ret; -} - -static irqreturn_t -omap_i2c_isr_thread(int this_irq, void *dev_id) -{ - struct omap_i2c_dev *dev = dev_id; - unsigned long flags; u16 bits; u16 stat; int err = 0, count = 0; - spin_lock_irqsave(&dev->lock, flags); do { - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); stat &= bits; /* If we're in receiver mode, ignore XDR/XRDY */ - if (dev->receiver) + if (omap->receiver) stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); else stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); if (!stat) { /* my work here is done */ - goto out; + err = -EAGAIN; + break; } - dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); + dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { - dev_warn(dev->dev, "Too much work in one IRQ\n"); + dev_warn(omap->dev, "Too much work in one IRQ\n"); break; } if (stat & OMAP_I2C_STAT_NACK) { - err |= OMAP_I2C_STAT_NACK; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - break; + omap->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); + + if (!(stat & ~OMAP_I2C_STAT_NACK)) { + err = -EAGAIN; + break; + } } if (stat & OMAP_I2C_STAT_AL) { - dev_err(dev->dev, "Arbitration lost\n"); + dev_err(omap->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); - break; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); } /* * ProDB0017052: Clear ARDY bit twice */ + if (stat & OMAP_I2C_STAT_ARDY) + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ARDY); + if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | @@ -957,26 +1113,28 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; - if (dev->fifo_size) - num_bytes = dev->buf_len; + if (omap->fifo_size) + num_bytes = omap->buf_len; - omap_i2c_receive_data(dev, num_bytes, true); - - if (dev->errata & I2C_OMAP_ERRATA_I207) - i2c_omap_errata_i207(dev, stat); + if (omap->errata & I2C_OMAP_ERRATA_I207) { + i2c_omap_errata_i207(omap, stat); + num_bytes = (omap_i2c_read_reg(omap, + OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; + } - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + omap_i2c_receive_data(omap, num_bytes, true); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); continue; } if (stat & OMAP_I2C_STAT_RRDY) { u8 num_bytes = 1; - if (dev->threshold) - num_bytes = dev->threshold; + if (omap->threshold) + num_bytes = omap->threshold; - omap_i2c_receive_data(dev, num_bytes, false); - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); + omap_i2c_receive_data(omap, num_bytes, false); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY); continue; } @@ -984,14 +1142,14 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) u8 num_bytes = 1; int ret; - if (dev->fifo_size) - num_bytes = dev->buf_len; + if (omap->fifo_size) + num_bytes = omap->buf_len; - ret = omap_i2c_transmit_data(dev, num_bytes, true); + ret = omap_i2c_transmit_data(omap, num_bytes, true); if (ret < 0) break; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XDR); continue; } @@ -999,46 +1157,73 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) u8 num_bytes = 1; int ret; - if (dev->threshold) - num_bytes = dev->threshold; + if (omap->threshold) + num_bytes = omap->threshold; - ret = omap_i2c_transmit_data(dev, num_bytes, false); + ret = omap_i2c_transmit_data(omap, num_bytes, false); if (ret < 0) break; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY); continue; } if (stat & OMAP_I2C_STAT_ROVR) { - dev_err(dev->dev, "Receive overrun\n"); + dev_err(omap->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ROVR); break; } if (stat & OMAP_I2C_STAT_XUDF) { - dev_err(dev->dev, "Transmit underflow\n"); + dev_err(omap->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XUDF); break; } } while (stat); - omap_i2c_complete_cmd(dev, err); + return err; +} -out: - spin_unlock_irqrestore(&dev->lock, flags); +static irqreturn_t +omap_i2c_isr_thread(int this_irq, void *dev_id) +{ + int ret; + struct omap_i2c_dev *omap = dev_id; + + ret = omap_i2c_xfer_data(omap); + if (ret != -EAGAIN) + omap_i2c_complete_cmd(omap, ret); return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { - .master_xfer = omap_i2c_xfer, - .functionality = omap_i2c_func, + .xfer = omap_i2c_xfer_irq, + .xfer_atomic = omap_i2c_xfer_polling, + .functionality = omap_i2c_func, +}; + +static const struct i2c_adapter_quirks omap_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, }; #ifdef CONFIG_OF +static struct omap_i2c_bus_platform_data omap2420_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_NO_FIFO | + OMAP_I2C_FLAG_SIMPLE_CLOCK | + OMAP_I2C_FLAG_16BIT_DATA_REG | + OMAP_I2C_FLAG_BUS_SHIFT_2, +}; + +static struct omap_i2c_bus_platform_data omap2430_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_BUS_SHIFT_2 | + OMAP_I2C_FLAG_FORCE_19200_INT_CLK, +}; + static struct omap_i2c_bus_platform_data omap3_pdata = { .rev = OMAP_I2C_IP_VERSION_1, .flags = OMAP_I2C_FLAG_BUS_SHIFT_2, @@ -1057,7 +1242,15 @@ static const struct of_device_id omap_i2c_of_match[] = { .compatible = "ti,omap3-i2c", .data = &omap3_pdata, }, - { }, + { + .compatible = "ti,omap2430-i2c", + .data = &omap2430_pdata, + }, + { + .compatible = "ti,omap2420-i2c", + .data = &omap2420_pdata, + }, + { } }; MODULE_DEVICE_TABLE(of, omap_i2c_of_match); #endif @@ -1072,124 +1265,176 @@ MODULE_DEVICE_TABLE(of, omap_i2c_of_match); #define OMAP_I2C_SCHEME_0 0 #define OMAP_I2C_SCHEME_1 1 +static int omap_i2c_get_scl(struct i2c_adapter *adap) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u32 reg; + + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + + return reg & OMAP_I2C_SYSTEST_SCL_I_FUNC; +} + +static int omap_i2c_get_sda(struct i2c_adapter *adap) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u32 reg; + + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + + return reg & OMAP_I2C_SYSTEST_SDA_I_FUNC; +} + +static void omap_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u32 reg; + + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + if (val) + reg |= OMAP_I2C_SYSTEST_SCL_O; + else + reg &= ~OMAP_I2C_SYSTEST_SCL_O; + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); +} + +static void omap_i2c_prepare_recovery(struct i2c_adapter *adap) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u32 reg; + + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + /* enable test mode */ + reg |= OMAP_I2C_SYSTEST_ST_EN; + /* select SDA/SCL IO mode */ + reg |= 3 << OMAP_I2C_SYSTEST_TMODE_SHIFT; + /* set SCL to high-impedance state (reset value is 0) */ + reg |= OMAP_I2C_SYSTEST_SCL_O; + /* set SDA to high-impedance state (reset value is 0) */ + reg |= OMAP_I2C_SYSTEST_SDA_O; + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); +} + +static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u32 reg; + + reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + /* restore reset values */ + reg &= ~OMAP_I2C_SYSTEST_ST_EN; + reg &= ~OMAP_I2C_SYSTEST_TMODE_MASK; + reg &= ~OMAP_I2C_SYSTEST_SCL_O; + reg &= ~OMAP_I2C_SYSTEST_SDA_O; + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg); +} + +static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = { + .get_scl = omap_i2c_get_scl, + .get_sda = omap_i2c_get_sda, + .set_scl = omap_i2c_set_scl, + .prepare_recovery = omap_i2c_prepare_recovery, + .unprepare_recovery = omap_i2c_unprepare_recovery, + .recover_bus = i2c_generic_scl_recovery, +}; + static int omap_i2c_probe(struct platform_device *pdev) { - struct omap_i2c_dev *dev; + struct omap_i2c_dev *omap; struct i2c_adapter *adap; - struct resource *mem; const struct omap_i2c_bus_platform_data *pdata = - pdev->dev.platform_data; + dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; - const struct of_device_id *match; int irq; int r; u32 rev; u16 minor, major; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); + if (irq < 0) return irq; - } - dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Menory allocation failed\n"); + omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!omap) return -ENOMEM; - } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dev->base)) - return PTR_ERR(dev->base); + omap->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(omap->base)) + return PTR_ERR(omap->base); - match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); - if (match) { - u32 freq = 100000; /* default to 100000 Hz */ + if (pdev->dev.of_node) { + u32 freq = I2C_MAX_STANDARD_MODE_FREQ; - pdata = match->data; - dev->flags = pdata->flags; + pdata = device_get_match_data(&pdev->dev); + omap->flags = pdata->flags; of_property_read_u32(node, "clock-frequency", &freq); /* convert DT freq value in Hz into kHz for speed */ - dev->speed = freq / 1000; + omap->speed = freq / 1000; } else if (pdata != NULL) { - dev->speed = pdata->clkrate; - dev->flags = pdata->flags; - dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + omap->speed = pdata->clkrate; + omap->flags = pdata->flags; + omap->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; } - 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; - } + omap->dev = &pdev->dev; + omap->irq = irq; - dev->dev = &pdev->dev; - dev->irq = irq; + platform_set_drvdata(pdev, omap); + init_completion(&omap->cmd_complete); - spin_lock_init(&dev->lock); + omap->reg_shift = (omap->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - platform_set_drvdata(pdev, dev); - init_completion(&dev->cmd_complete); + pm_runtime_enable(omap->dev); + pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(omap->dev); - dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - - pm_runtime_enable(dev->dev); - pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); - pm_runtime_use_autosuspend(dev->dev); - - r = pm_runtime_get_sync(dev->dev); - if (IS_ERR_VALUE(r)) - goto err_free_mem; + r = pm_runtime_resume_and_get(omap->dev); + if (r < 0) + goto err_disable_pm; /* * 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. + * readw_relaxed is done. */ - rev = __raw_readw(dev->base + 0x04); + rev = readw_relaxed(omap->base + 0x04); - dev->scheme = OMAP_I2C_SCHEME(rev); - switch (dev->scheme) { + omap->scheme = OMAP_I2C_SCHEME(rev); + switch (omap->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); + omap->regs = (u8 *)reg_map_ip_v1; + omap->rev = omap_i2c_read_reg(omap, OMAP_I2C_REV_REG); + minor = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); + major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); break; case OMAP_I2C_SCHEME_1: - /* FALLTHROUGH */ default: - dev->regs = (u8 *)reg_map_ip_v2; + omap->regs = (u8 *)reg_map_ip_v2; rev = (rev << 16) | - omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO); + omap_i2c_read_reg(omap, 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; + omap->rev = rev; } - dev->errata = 0; + omap->errata = 0; - if (dev->rev >= OMAP_I2C_REV_ON_2430 && - dev->rev < OMAP_I2C_REV_ON_4430_PLUS) - dev->errata |= I2C_OMAP_ERRATA_I207; + if (omap->rev >= OMAP_I2C_REV_ON_2430 && + omap->rev < OMAP_I2C_REV_ON_4430_PLUS) + omap->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) - dev->errata |= I2C_OMAP_ERRATA_I462; + if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) + omap->errata |= I2C_OMAP_ERRATA_I462; - if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { + if (!(omap->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; /* Set up the fifo size - Get total size */ - s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; - dev->fifo_size = 0x8 << s; + s = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; + omap->fifo_size = 0x8 << s; /* * Set up notification threshold as half the total available @@ -1197,143 +1442,186 @@ omap_i2c_probe(struct platform_device *pdev) * call back latencies. */ - dev->fifo_size = (dev->fifo_size / 2); + omap->fifo_size = (omap->fifo_size / 2); - if (dev->rev < OMAP_I2C_REV_ON_3630) - dev->b_hw = 1; /* Enable hardware fixes */ + if (omap->rev < OMAP_I2C_REV_ON_3630) + omap->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (omap->set_mpu_wkup_lat != NULL) + omap->latency = (1000000 * omap->fifo_size) / + (1000 * omap->speed / 8); + } + + if (of_property_present(node, "mux-states")) { + struct mux_state *mux_state; + + mux_state = devm_mux_state_get(&pdev->dev, NULL); + if (IS_ERR(mux_state)) { + r = PTR_ERR(mux_state); + dev_dbg(&pdev->dev, "failed to get I2C mux: %d\n", r); + goto err_put_pm; + } + omap->mux_state = mux_state; + r = mux_state_select(omap->mux_state); + if (r) { + dev_err(&pdev->dev, "failed to select I2C mux: %d\n", r); + goto err_put_pm; + } } /* reset ASAP, clearing any IRQs */ - omap_i2c_init(dev); + r = omap_i2c_init(omap); + if (r) + goto err_mux_state_deselect; - if (dev->rev < OMAP_I2C_OMAP1_REV_2) - r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, - IRQF_NO_SUSPEND, pdev->name, dev); + if (omap->rev < OMAP_I2C_OMAP1_REV_2) + r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr, + IRQF_NO_SUSPEND, pdev->name, omap); else - r = devm_request_threaded_irq(&pdev->dev, dev->irq, - omap_i2c_isr, omap_i2c_isr_thread, + r = devm_request_threaded_irq(&pdev->dev, omap->irq, + NULL, omap_i2c_isr_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, - pdev->name, dev); + pdev->name, omap); if (r) { - dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); + dev_err(omap->dev, "failure requesting irq %i\n", omap->irq); goto err_unuse_clocks; } - adap = &dev->adapter; - i2c_set_adapdata(adap, dev); + adap = &omap->adapter; + i2c_set_adapdata(adap, omap); adap->owner = THIS_MODULE; - adap->class = I2C_CLASS_HWMON; - strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); + adap->class = I2C_CLASS_DEPRECATED; + strscpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; + adap->quirks = &omap_i2c_quirks; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; + adap->bus_recovery_info = &omap_i2c_bus_recovery_info; /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(dev->dev, "failure adding adapter\n"); + if (r) goto err_unuse_clocks; - } - - dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, - major, minor, dev->speed); - of_i2c_register_devices(adap); + dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, + major, minor, omap->speed); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_put_autosuspend(omap->dev); return 0; err_unuse_clocks: - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - pm_runtime_put(dev->dev); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); +err_mux_state_deselect: + if (omap->mux_state) + mux_state_deselect(omap->mux_state); +err_put_pm: + pm_runtime_put_sync(omap->dev); +err_disable_pm: + pm_runtime_dont_use_autosuspend(omap->dev); pm_runtime_disable(&pdev->dev); -err_free_mem: return r; } -static int omap_i2c_remove(struct platform_device *pdev) +static void omap_i2c_remove(struct platform_device *pdev) { - struct omap_i2c_dev *dev = platform_get_drvdata(pdev); + struct omap_i2c_dev *omap = platform_get_drvdata(pdev); int ret; - i2c_del_adapter(&dev->adapter); + i2c_del_adapter(&omap->adapter); + + if (omap->mux_state) + mux_state_deselect(omap->mux_state); + ret = pm_runtime_get_sync(&pdev->dev); - if (IS_ERR_VALUE(ret)) - return ret; + if (ret < 0) + dev_err(omap->dev, "Failed to resume hardware, skip disable\n"); + else + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - pm_runtime_put(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } -#ifdef CONFIG_PM -#ifdef CONFIG_PM_RUNTIME 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); + struct omap_i2c_dev *omap = dev_get_drvdata(dev); - _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); + omap->iestate = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); - if (_dev->scheme == OMAP_I2C_SCHEME_0) - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); + if (omap->scheme == OMAP_I2C_SCHEME_0) + omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, 0); else - omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, + omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR, OMAP_I2C_IP_V2_INTERRUPTS_MASK); - if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { - omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ + if (omap->rev < OMAP_I2C_OMAP1_REV_2) { + omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); /* Read clears */ } else { - omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); + omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, omap->iestate); /* Flush posted write */ - omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG); + omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); } + pinctrl_pm_select_sleep_state(dev); + return 0; } 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); + struct omap_i2c_dev *omap = dev_get_drvdata(dev); + + pinctrl_pm_select_default_state(dev); - if (!_dev->regs) + if (!omap->regs) return 0; - __omap_i2c_init(_dev); + __omap_i2c_init(omap); return 0; } -#endif /* CONFIG_PM_RUNTIME */ -static struct dev_pm_ops omap_i2c_pm_ops = { - SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, - omap_i2c_runtime_resume, NULL) +static int omap_i2c_suspend(struct device *dev) +{ + /* + * If the controller is autosuspended, there is no way to wakeup it once + * runtime pm is disabled (in suspend_late()). + * But a device may need the controller up during suspend_noirq() or + * resume_noirq(). + * Wakeup the controller while runtime pm is enabled, so it is available + * until its suspend_noirq(), and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} + +static int omap_i2c_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct dev_pm_ops omap_i2c_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(omap_i2c_suspend, omap_i2c_resume) + RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; -#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) -#else -#define OMAP_I2C_PM_OPS NULL -#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", - .owner = THIS_MODULE, - .pm = OMAP_I2C_PM_OPS, + .pm = pm_ptr(&omap_i2c_pm_ops), .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; |
