diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/i2c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (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')
63 files changed, 6313 insertions, 1035 deletions
diff --git a/kernel/drivers/i2c/algos/i2c-algo-pca.c b/kernel/drivers/i2c/algos/i2c-algo-pca.c index 580dbf05c..e370804ec 100644 --- a/kernel/drivers/i2c/algos/i2c-algo-pca.c +++ b/kernel/drivers/i2c/algos/i2c-algo-pca.c @@ -521,7 +521,7 @@ static int pca_init(struct i2c_adapter *adap) pca_set_con(pca_data, I2C_PCA_CON_ENSIO); } - udelay(500); /* 500 us for oscilator to stabilise */ + udelay(500); /* 500 us for oscillator to stabilise */ return 0; } diff --git a/kernel/drivers/i2c/busses/Kconfig b/kernel/drivers/i2c/busses/Kconfig index 2255af23b..7b0aa82ea 100644 --- a/kernel/drivers/i2c/busses/Kconfig +++ b/kernel/drivers/i2c/busses/Kconfig @@ -124,6 +124,9 @@ config I2C_I801 BayTrail (SOC) Sunrise Point-H (PCH) Sunrise Point-LP (PCH) + DNV (SOC) + Broxton (SOC) + Lewisburg (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -392,6 +395,16 @@ config I2C_BCM_KONA If you do not need KONA I2C interface, say N. +config I2C_BRCMSTB + tristate "BRCM Settop I2C controller" + depends on ARCH_BRCMSTB || COMPILE_TEST + default y + help + If you say yes to this option, support will be included for the + I2C interface on the Broadcom Settop SoCs. + + If you do not need I2C interface, say N. + config I2C_BLACKFIN_TWI tristate "Blackfin TWI I2C support" depends on BLACKFIN @@ -412,14 +425,14 @@ config I2C_BLACKFIN_TWI_CLK_KHZ config I2C_CADENCE tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ + depends on ARCH_ZYNQ || ARM64 help Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. config I2C_CBUS_GPIO tristate "CBUS I2C driver" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Support for CBUS access using I2C API. Mostly relevant for Nokia Internet Tablets (770, N800 and N810). @@ -516,6 +529,13 @@ config I2C_EG20T ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. +config I2C_EMEV2 + tristate "EMMA Mobile series I2C adapter" + depends on HAVE_CLK + help + If you say yes to this option, support will be included for the + I2C interface on the Renesas Electronics EM/EV family of processors. + config I2C_EXYNOS5 tristate "Exynos5 high-speed I2C driver" depends on ARCH_EXYNOS && OF @@ -525,7 +545,7 @@ config I2C_EXYNOS5 config I2C_GPIO tristate "GPIO-based bitbanging I2C" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select I2C_ALGOBIT help This is a very simple bitbanging I2C driver utilizing the @@ -565,10 +585,10 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC + depends on ARCH_MXC || ARCH_LAYERSCAPE help Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC processors. + the Freescale i.MX/MXC or Layerscape processors. This driver can also be built as a module. If so, the module will be called i2c-imx. @@ -602,6 +622,16 @@ config I2C_KEMPLD This driver can also be built as a module. If so, the module will be called i2c-kempld. +config I2C_LPC2K + tristate "I2C bus support for NXP LPC2K/LPC178x/18xx/43xx" + depends on OF && (ARCH_LPC18XX || COMPILE_TEST) + help + This driver supports the I2C interface found several NXP + devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx. + + This driver can also be built as a module. If so, the module + will be called i2c-lpc2k. + config I2C_MESON tristate "Amlogic Meson I2C controller" depends on ARCH_MESON @@ -620,6 +650,16 @@ config I2C_MPC This driver can also be built as a module. If so, the module will be called i2c-mpc. +config I2C_MT65XX + tristate "MediaTek I2C adapter" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_DMA + help + This selects the MediaTek(R) Integrated Inter Circuit bus driver + for MT65xx and MT81xx. + If you want to use MediaTek(R) I2C interface, say Y or M here. + If unsure, say N. + config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" depends on MV64X60 || PLAT_ORION || ARCH_SUNXI @@ -865,6 +905,22 @@ config I2C_TEGRA If you say yes to this option, support will be included for the I2C controller embedded in NVIDIA Tegra SOCs +config I2C_UNIPHIER + tristate "UniPhier FIFO-less I2C controller" + depends on ARCH_UNIPHIER + help + If you say yes to this option, support will be included for + the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8, + or older UniPhier SoCs. + +config I2C_UNIPHIER_F + tristate "UniPhier FIFO-builtin I2C controller" + depends on ARCH_UNIPHIER + help + If you say yes to this option, support will be included for + the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4, + PH1-Pro5, or newer UniPhier SoCs. + config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS @@ -1110,6 +1166,15 @@ config I2C_CROS_EC_TUNNEL connected there. This will work whatever the interface used to talk to the EC (SPI, I2C or LPC). +config I2C_XGENE_SLIMPRO + tristate "APM X-Gene SoC I2C SLIMpro devices support" + depends on ARCH_XGENE && MAILBOX + help + Enable I2C bus access using the APM X-Gene SoC SLIMpro + co-processor. The I2C device access the I2C bus via the X-Gene + to SLIMpro (On chip coprocessor) mailbox mechanism. + If unsure, say N. + config SCx200_ACB tristate "Geode ACCESS.bus support" depends on X86_32 && PCI diff --git a/kernel/drivers/i2c/busses/Makefile b/kernel/drivers/i2c/busses/Makefile index cdf941da9..37f2819b4 100644 --- a/kernel/drivers/i2c/busses/Makefile +++ b/kernel/drivers/i2c/busses/Makefile @@ -48,6 +48,7 @@ i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o +obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o @@ -58,8 +59,10 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o +obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o +obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o @@ -84,6 +87,8 @@ obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o +obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o +obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_WMT) += i2c-wmt.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o @@ -105,11 +110,13 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o # Other I2C/SMBus bus drivers obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o +obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_OPAL) += i2c-opal.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o +obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/kernel/drivers/i2c/busses/i2c-at91.c b/kernel/drivers/i2c/busses/i2c-at91.c index 9bd10a9b4..10835d1f5 100644 --- a/kernel/drivers/i2c/busses/i2c-at91.c +++ b/kernel/drivers/i2c/busses/i2c-at91.c @@ -41,29 +41,38 @@ /* AT91 TWI register definitions */ #define AT91_TWI_CR 0x0000 /* Control Register */ -#define AT91_TWI_START 0x0001 /* Send a Start Condition */ -#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ -#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ -#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ -#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ -#define AT91_TWI_SWRST 0x0080 /* Software Reset */ +#define AT91_TWI_START BIT(0) /* Send a Start Condition */ +#define AT91_TWI_STOP BIT(1) /* Send a Stop Condition */ +#define AT91_TWI_MSEN BIT(2) /* Master Transfer Enable */ +#define AT91_TWI_MSDIS BIT(3) /* Master Transfer Disable */ +#define AT91_TWI_SVEN BIT(4) /* Slave Transfer Enable */ +#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */ +#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */ +#define AT91_TWI_SWRST BIT(7) /* Software Reset */ +#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */ +#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */ +#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */ +#define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */ +#define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */ +#define AT91_TWI_FIFOEN BIT(28) /* FIFO Enable */ +#define AT91_TWI_FIFODIS BIT(29) /* FIFO Disable */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ #define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ -#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */ +#define AT91_TWI_MREAD BIT(12) /* Master Read Direction */ #define AT91_TWI_IADR 0x000c /* Internal Address Register */ #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ #define AT91_TWI_SR 0x0020 /* Status Register */ -#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */ -#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */ -#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */ - -#define AT91_TWI_OVRE 0x0040 /* Overrun Error */ -#define AT91_TWI_UNRE 0x0080 /* Underrun Error */ -#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ +#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */ +#define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */ +#define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */ +#define AT91_TWI_OVRE BIT(6) /* Overrun Error */ +#define AT91_TWI_UNRE BIT(7) /* Underrun Error */ +#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ +#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */ #define AT91_TWI_INT_MASK \ (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) @@ -74,17 +83,40 @@ #define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */ +#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) +#define AT91_TWI_ACR_DIR BIT(8) + +#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */ +#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0) +#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0) +#define AT91_TWI_FMR_RXRDYM(mode) (((mode) & 0x3) << 4) +#define AT91_TWI_FMR_RXRDYM_MASK (0x3 << 4) +#define AT91_TWI_ONE_DATA 0x0 +#define AT91_TWI_TWO_DATA 0x1 +#define AT91_TWI_FOUR_DATA 0x2 + +#define AT91_TWI_FLR 0x0054 /* FIFO Level Register */ + +#define AT91_TWI_FSR 0x0060 /* FIFO Status Register */ +#define AT91_TWI_FIER 0x0064 /* FIFO Interrupt Enable Register */ +#define AT91_TWI_FIDR 0x0068 /* FIFO Interrupt Disable Register */ +#define AT91_TWI_FIMR 0x006c /* FIFO Interrupt Mask Register */ + +#define AT91_TWI_VER 0x00fc /* Version Register */ + struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_alt_cmd; struct at_dma_slave dma_slave; }; struct at91_twi_dma { struct dma_chan *chan_rx; struct dma_chan *chan_tx; - struct scatterlist sg; + struct scatterlist sg[2]; struct dma_async_tx_descriptor *data_desc; enum dma_data_direction direction; bool buf_mapped; @@ -107,6 +139,7 @@ struct at91_twi_dev { struct at91_twi_pdata *pdata; bool use_dma; bool recv_len_abort; + u32 fifo_size; struct at91_twi_dma dma; }; @@ -140,6 +173,9 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev) { at91_disable_twi_interrupts(dev); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); + /* FIFO should be enabled immediately after the software reset */ + if (dev->fifo_size) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); @@ -186,7 +222,7 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) dma->xfer_in_progress = false; } if (dma->buf_mapped) { - dma_unmap_single(dev->dev, sg_dma_address(&dma->sg), + dma_unmap_single(dev->dev, sg_dma_address(&dma->sg[0]), dev->buf_len, dma->direction); dma->buf_mapped = false; } @@ -196,14 +232,16 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) static void at91_twi_write_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + if (!dev->buf_len) return; - at91_twi_write(dev, AT91_TWI_THR, *dev->buf); + /* 8bit write works with and without FIFO */ + writeb_relaxed(*dev->buf, dev->base + AT91_TWI_THR); /* send stop when last byte has been written */ if (--dev->buf_len == 0) - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + if (!dev->pdata->has_alt_cmd) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); @@ -214,7 +252,7 @@ static void at91_twi_write_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_TO_DEVICE); /* @@ -225,7 +263,8 @@ static void at91_twi_write_data_dma_callback(void *data) * we just have to enable TXCOMP one. */ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + if (!dev->pdata->has_alt_cmd) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } static void at91_twi_write_data_dma(struct at91_twi_dev *dev) @@ -234,8 +273,9 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *txdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_tx = dma->chan_tx; + unsigned int sg_len = 1; - if (dev->buf_len <= 0) + if (!dev->buf_len) return; dma->direction = DMA_TO_DEVICE; @@ -249,10 +289,43 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) } dma->buf_mapped = true; at91_twi_irq_restore(dev); - sg_dma_len(&dma->sg) = dev->buf_len; - sg_dma_address(&dma->sg) = dma_addr; - txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV, + if (dev->fifo_size) { + size_t part1_len, part2_len; + struct scatterlist *sg; + unsigned fifo_mr; + + sg_len = 0; + + part1_len = dev->buf_len & ~0x3; + if (part1_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part1_len; + sg_dma_address(sg) = dma_addr; + } + + part2_len = dev->buf_len & 0x3; + if (part2_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part2_len; + sg_dma_address(sg) = dma_addr + part1_len; + } + + /* + * DMA controller is triggered when at least 4 data can be + * written into the TX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_TXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } else { + sg_dma_len(&dma->sg[0]) = dev->buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + } + + txdesc = dmaengine_prep_slave_sg(chan_tx, dma->sg, sg_len, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -274,10 +347,17 @@ error: static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + /* + * If we are in this case, it means there is garbage data in RHR, so + * delete them. + */ + if (!dev->buf_len) { + at91_twi_read(dev, AT91_TWI_RHR); return; + } - *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; + /* 8bit read works with and without FIFO */ + *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR); --dev->buf_len; /* return if aborting, we only needed to read RHR to clear RXRDY*/ @@ -301,7 +381,7 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) } /* send stop if second but last byte has been read */ - if (dev->buf_len == 1) + if (!dev->pdata->has_alt_cmd && dev->buf_len == 1) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); @@ -312,14 +392,18 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) static void at91_twi_read_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + unsigned ier = AT91_TWI_TXCOMP; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_FROM_DEVICE); - /* The last two bytes have to be read without using dma */ - dev->buf += dev->buf_len - 2; - dev->buf_len = 2; - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY | AT91_TWI_TXCOMP); + if (!dev->pdata->has_alt_cmd) { + /* The last two bytes have to be read without using dma */ + dev->buf += dev->buf_len - 2; + dev->buf_len = 2; + ier |= AT91_TWI_RXRDY; + } + at91_twi_write(dev, AT91_TWI_IER, ier); } static void at91_twi_read_data_dma(struct at91_twi_dev *dev) @@ -328,23 +412,38 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *rxdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_rx = dma->chan_rx; + size_t buf_len; + buf_len = (dev->pdata->has_alt_cmd) ? dev->buf_len : dev->buf_len - 2; dma->direction = DMA_FROM_DEVICE; /* Keep in mind that we won't use dma to read the last two bytes */ at91_twi_irq_save(dev); - dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2, - DMA_FROM_DEVICE); + dma_addr = dma_map_single(dev->dev, dev->buf, buf_len, DMA_FROM_DEVICE); if (dma_mapping_error(dev->dev, dma_addr)) { dev_err(dev->dev, "dma map failed\n"); return; } dma->buf_mapped = true; at91_twi_irq_restore(dev); - dma->sg.dma_address = dma_addr; - sg_dma_len(&dma->sg) = dev->buf_len - 2; - rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, + if (dev->fifo_size && IS_ALIGNED(buf_len, 4)) { + unsigned fifo_mr; + + /* + * DMA controller is triggered when at least 4 data can be + * read from the RX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_RXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } + + sg_dma_len(&dma->sg[0]) = buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + + rxdesc = dmaengine_prep_slave_sg(chan_rx, dma->sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -372,19 +471,73 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) if (!irqstatus) return IRQ_NONE; - else if (irqstatus & AT91_TWI_RXRDY) + /* + * In reception, the behavior of the twi device (before sama5d2) is + * weird. There is some magic about RXRDY flag! When a data has been + * almost received, the reception of a new one is anticipated if there + * is no stop command to send. That is the reason why ask for sending + * the stop command not on the last data but on the second last one. + * + * Unfortunately, we could still have the RXRDY flag set even if the + * transfer is done and we have read the last data. It might happen + * when the i2c slave device sends too quickly data after receiving the + * ack from the master. The data has been almost received before having + * the order to send stop. In this case, sending the stop command could + * cause a RXRDY interrupt with a TXCOMP one. It is better to manage + * the RXRDY interrupt first in order to not keep garbage data in the + * Receive Holding Register for the next transfer. + */ + if (irqstatus & AT91_TWI_RXRDY) at91_twi_read_next_byte(dev); - else if (irqstatus & AT91_TWI_TXRDY) - at91_twi_write_next_byte(dev); - - /* catch error flags */ - dev->transfer_status |= status; + /* + * When a NACK condition is detected, the I2C controller sets the NACK, + * TXCOMP and TXRDY bits all together in the Status Register (SR). + * + * 1 - Handling NACK errors with CPU write transfer. + * + * In such case, we should not write the next byte into the Transmit + * Holding Register (THR) otherwise the I2C controller would start a new + * transfer and the I2C slave is likely to reply by another NACK. + * + * 2 - Handling NACK errors with DMA write transfer. + * + * By setting the TXRDY bit in the SR, the I2C controller also triggers + * the DMA controller to write the next data into the THR. Then the + * result depends on the hardware version of the I2C controller. + * + * 2a - Without support of the Alternative Command mode. + * + * This is the worst case: the DMA controller is triggered to write the + * next data into the THR, hence starting a new transfer: the I2C slave + * is likely to reply by another NACK. + * Concurrently, this interrupt handler is likely to be called to manage + * the first NACK before the I2C controller detects the second NACK and + * sets once again the NACK bit into the SR. + * When handling the first NACK, this interrupt handler disables the I2C + * controller interruptions, especially the NACK interrupt. + * Hence, the NACK bit is pending into the SR. This is why we should + * read the SR to clear all pending interrupts at the beginning of + * at91_do_twi_transfer() before actually starting a new transfer. + * + * 2b - With support of the Alternative Command mode. + * + * When a NACK condition is detected, the I2C controller also locks the + * THR (and sets the LOCK bit in the SR): even though the DMA controller + * is triggered by the TXRDY bit to write the next data into the THR, + * this data actually won't go on the I2C bus hence a second NACK is not + * generated. + */ if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); + } else if (irqstatus & AT91_TWI_TXRDY) { + at91_twi_write_next_byte(dev); } + /* catch error flags */ + dev->transfer_status |= status; + return IRQ_HANDLED; } @@ -393,6 +546,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) int ret; unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; + bool has_alt_cmd = dev->pdata->has_alt_cmd; /* * WARNING: the TXCOMP bit in the Status Register is NOT a clear on @@ -402,6 +556,21 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * empty and STOP condition has been sent. * Consequently, we should enable NACK interrupt rather than TXCOMP to * detect transmission failure. + * Indeed let's take the case of an i2c write command using DMA. + * Whenever the slave doesn't acknowledge a byte, the LOCK, NACK and + * TXCOMP bits are set together into the Status Register. + * LOCK is a clear on write bit, which is set to prevent the DMA + * controller from sending new data on the i2c bus after a NACK + * condition has happened. Once locked, this i2c peripheral stops + * triggering the DMA controller for new data but it is more than + * likely that a new DMA transaction is already in progress, writing + * into the Transmit Holding Register. Since the peripheral is locked, + * these new data won't be sent to the i2c bus but they will remain + * into the Transmit Holding Register, so TXCOMP bit is cleared. + * Then when the interrupt handler is called, the Status Register is + * read: the TXCOMP bit is clear but NACK bit is still set. The driver + * manage the error properly, without waiting for timeout. + * This case can be reproduced easyly when writing into an at24 eeprom. * * Besides, the TXCOMP bit is already set before the i2c transaction * has been started. For read transactions, this bit is cleared when @@ -417,9 +586,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * condition since we don't know whether the TXCOMP interrupt is enabled * before or after the DMA has started to write into THR. So the TXCOMP * interrupt is enabled later by at91_twi_write_data_dma_callback(). - * Immediately after in that DMA callback, we still need to send the - * STOP condition manually writing the corresponding bit into the - * Control Register. + * Immediately after in that DMA callback, if the alternative command + * mode is not used, we still need to send the STOP condition manually + * writing the corresponding bit into the Control Register. */ dev_dbg(dev->dev, "transfer: %s %d bytes.\n", @@ -428,26 +597,41 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; + /* Clear pending interrupts, such as NACK. */ + at91_twi_read(dev, AT91_TWI_SR); + + if (dev->fifo_size) { + unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + + /* Reset FIFO mode register */ + fifo_mr &= ~(AT91_TWI_FMR_TXRDYM_MASK | + AT91_TWI_FMR_RXRDYM_MASK); + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_ONE_DATA); + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_ONE_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + + /* Flush FIFOs */ + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_RHRCLR); + } + if (!dev->buf_len) { at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; - if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { - dev_err(dev->dev, "RXRDY still set!"); - at91_twi_read(dev, AT91_TWI_RHR); - } - /* if only one byte is to be read, immediately stop transfer */ - if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) + if (!has_alt_cmd && dev->buf_len <= 1 && + !(dev->msg->flags & I2C_M_RECV_LEN)) start_flags |= AT91_TWI_STOP; at91_twi_write(dev, AT91_TWI_CR, start_flags); /* - * When using dma, the last byte has to be read manually in - * order to not send the stop command too late and then - * to receive extra data. In practice, there are some issues - * if you use the dma to read n-1 bytes because of latency. + * When using dma without alternative command mode, the last + * byte has to be read manually in order to not send the stop + * command too late and then to receive extra data. + * In practice, there are some issues if you use the dma to + * read n-1 bytes because of latency. * Reading n-2 bytes with dma and the two last ones manually * seems to be the best solution. */ @@ -476,6 +660,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) time_left = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); if (time_left == 0) { + dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR); dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; @@ -496,6 +681,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO; goto error; } + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { + dev_err(dev->dev, "tx locked\n"); + ret = -EIO; + goto error; + } if (dev->recv_len_abort) { dev_err(dev->dev, "invalid smbus block length recvd\n"); ret = -EPROTO; @@ -507,7 +698,15 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) return 0; error: + /* first stop DMA transfer if still in progress */ at91_twi_dma_cleanup(dev); + /* then flush THR/FIFO and unlock TX if locked */ + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { + dev_dbg(dev->dev, "unlock tx\n"); + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_LOCKCLR); + } return ret; } @@ -517,6 +716,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) int ret; unsigned int_addr_flag = 0; struct i2c_msg *m_start = msg; + bool is_read, use_alt_cmd = false; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); @@ -539,8 +739,23 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) at91_twi_write(dev, AT91_TWI_IADR, internal_address); } - at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag - | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + is_read = (m_start->flags & I2C_M_RD); + if (dev->pdata->has_alt_cmd) { + if (m_start->len > 0) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN); + at91_twi_write(dev, AT91_TWI_ACR, + AT91_TWI_ACR_DATAL(m_start->len) | + ((is_read) ? AT91_TWI_ACR_DIR : 0)); + use_alt_cmd = true; + } else { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS); + } + } + + at91_twi_write(dev, AT91_TWI_MMR, + (m_start->addr << 16) | + int_addr_flag | + ((!use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); dev->buf_len = m_start->len; dev->buf = m_start->buf; @@ -581,30 +796,35 @@ static struct at91_twi_pdata at91rm9200_config = { .clk_max_div = 5, .clk_offset = 3, .has_unre_flag = true, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9261_config = { .clk_max_div = 5, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9260_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g20_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g10_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -633,6 +853,14 @@ static struct at91_twi_pdata at91sam9x5_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, +}; + +static struct at91_twi_pdata sama5d2_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = true, + .has_alt_cmd = true, }; static const struct of_device_id atmel_twi_dt_ids[] = { @@ -655,6 +883,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = { .compatible = "atmel,at91sam9x5-i2c", .data = &at91sam9x5_config, }, { + .compatible = "atmel,sama5d2-i2c", + .data = &sama5d2_config, + }, { /* sentinel */ } }; @@ -666,13 +897,32 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) int ret = 0; struct dma_slave_config slave_config; struct at91_twi_dma *dma = &dev->dma; + enum dma_slave_buswidth addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + /* + * The actual width of the access will be chosen in + * dmaengine_prep_slave_sg(): + * for each buffer in the scatter-gather list, if its size is aligned + * to addr_width then addr_width accesses will be performed to transfer + * the buffer. On the other hand, if the buffer size is not aligned to + * addr_width then the buffer is transferred using single byte accesses. + * Please refer to the Atmel eXtended DMA controller driver. + * When FIFOs are used, the TXRDYM threshold can always be set to + * trigger the XDMAC when at least 4 data can be written into the TX + * FIFO, even if single byte accesses are performed. + * However the RXRDYM threshold must be set to fit the access width, + * deduced from buffer length, so the XDMAC is triggered properly to + * read data from the RX FIFO. + */ + if (dev->fifo_size) + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; memset(&slave_config, 0, sizeof(slave_config)); slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; - slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = addr_width; slave_config.src_maxburst = 1; slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR; - slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr_width = addr_width; slave_config.dst_maxburst = 1; slave_config.device_fc = false; @@ -704,7 +954,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) goto error; } - sg_init_table(&dma->sg, 1); + sg_init_table(dma->sg, 2); dma->buf_mapped = false; dma->xfer_in_progress = false; dev->use_dma = true; @@ -790,6 +1040,11 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &dev->fifo_size)) { + dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size); + } + rc = of_property_read_u32(dev->dev->of_node, "clock-frequency", &bus_clk_rate); if (rc) @@ -826,7 +1081,8 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } - dev_info(dev->dev, "AT91 i2c bus driver.\n"); + dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n", + at91_twi_read(dev, AT91_TWI_VER)); return 0; } diff --git a/kernel/drivers/i2c/busses/i2c-au1550.c b/kernel/drivers/i2c/busses/i2c-au1550.c index a6aae84e5..5bcb1f0bb 100644 --- a/kernel/drivers/i2c/busses/i2c-au1550.c +++ b/kernel/drivers/i2c/busses/i2c-au1550.c @@ -48,7 +48,6 @@ struct i2c_au1550_data { void __iomem *psc_base; int xfer_timeout; struct i2c_adapter adap; - struct resource *ioarea; }; static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v) @@ -284,10 +283,10 @@ static void i2c_au1550_setup(struct i2c_au1550_data *priv) /* Set the protocol timer values. See Table 71 in the * Au1550 Data Book for standard timing values. */ - WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \ - PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \ - PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \ - PSC_SMBTMR_SET_CH(15)); + WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(20) | \ + PSC_SMBTMR_SET_PU(20) | PSC_SMBTMR_SET_SH(20) | \ + PSC_SMBTMR_SET_SU(20) | PSC_SMBTMR_SET_CL(20) | \ + PSC_SMBTMR_SET_CH(20)); cfg |= PSC_SMBCFG_DE_ENABLE; WR(priv, PSC_SMBCFG, cfg); @@ -315,30 +314,16 @@ i2c_au1550_probe(struct platform_device *pdev) struct resource *r; int ret; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - ret = -ENODEV; - goto out; - } + priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data), + GFP_KERNEL); + if (!priv) + return -ENOMEM; - priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out; - } - - priv->ioarea = request_mem_region(r->start, resource_size(r), - pdev->name); - if (!priv->ioarea) { - ret = -EBUSY; - goto out_mem; - } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->psc_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->psc_base)) + return PTR_ERR(priv->psc_base); - priv->psc_base = ioremap(r->start, resource_size(r)); - if (!priv->psc_base) { - ret = -EIO; - goto out_map; - } priv->xfer_timeout = 200; priv->adap.nr = pdev->id; @@ -351,20 +336,13 @@ i2c_au1550_probe(struct platform_device *pdev) i2c_au1550_setup(priv); ret = i2c_add_numbered_adapter(&priv->adap); - if (ret == 0) { - platform_set_drvdata(pdev, priv); - return 0; + if (ret) { + i2c_au1550_disable(priv); + return ret; } - i2c_au1550_disable(priv); - iounmap(priv->psc_base); -out_map: - release_resource(priv->ioarea); - kfree(priv->ioarea); -out_mem: - kfree(priv); -out: - return ret; + platform_set_drvdata(pdev, priv); + return 0; } static int i2c_au1550_remove(struct platform_device *pdev) @@ -373,10 +351,6 @@ static int i2c_au1550_remove(struct platform_device *pdev) i2c_del_adapter(&priv->adap); i2c_au1550_disable(priv); - iounmap(priv->psc_base); - release_resource(priv->ioarea); - kfree(priv->ioarea); - kfree(priv); return 0; } 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; diff --git a/kernel/drivers/i2c/busses/i2c-bcm-iproc.c b/kernel/drivers/i2c/busses/i2c-bcm-iproc.c index f9f2c2082..0419f5284 100644 --- a/kernel/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/kernel/drivers/i2c/busses/i2c-bcm-iproc.c @@ -91,6 +91,7 @@ struct bcm_iproc_i2c_dev { void __iomem *base; struct i2c_adapter adapter; + unsigned int bus_speed; struct completion done; int xfer_is_done; @@ -309,6 +310,7 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) bus_speed = 400000; } + iproc_i2c->bus_speed = bus_speed; val = readl(iproc_i2c->base + TIM_CFG_OFFSET); val &= ~(1 << TIM_CFG_MODE_400_SHIFT); val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT; @@ -439,6 +441,60 @@ static int bcm_iproc_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int bcm_iproc_i2c_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev); + + /* make sure there's no pending interrupt when we go into suspend */ + writel(0, iproc_i2c->base + IE_OFFSET); + readl(iproc_i2c->base + IE_OFFSET); + synchronize_irq(iproc_i2c->irq); + + /* now disable the controller */ + bcm_iproc_i2c_enable_disable(iproc_i2c, false); + + return 0; +} + +static int bcm_iproc_i2c_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev); + int ret; + u32 val; + + /* + * Power domain could have been shut off completely in system deep + * sleep, so re-initialize the block here + */ + ret = bcm_iproc_i2c_init(iproc_i2c); + if (ret) + return ret; + + /* configure to the desired bus speed */ + val = readl(iproc_i2c->base + TIM_CFG_OFFSET); + val &= ~(1 << TIM_CFG_MODE_400_SHIFT); + val |= (iproc_i2c->bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT; + writel(val, iproc_i2c->base + TIM_CFG_OFFSET); + + bcm_iproc_i2c_enable_disable(iproc_i2c, true); + + return 0; +} + +static const struct dev_pm_ops bcm_iproc_i2c_pm_ops = { + .suspend_late = &bcm_iproc_i2c_suspend, + .resume_early = &bcm_iproc_i2c_resume +}; + +#define BCM_IPROC_I2C_PM_OPS (&bcm_iproc_i2c_pm_ops) +#else +#define BCM_IPROC_I2C_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static const struct of_device_id bcm_iproc_i2c_of_match[] = { { .compatible = "brcm,iproc-i2c" }, { /* sentinel */ } @@ -449,6 +505,7 @@ static struct platform_driver bcm_iproc_i2c_driver = { .driver = { .name = "bcm-iproc-i2c", .of_match_table = bcm_iproc_i2c_of_match, + .pm = BCM_IPROC_I2C_PM_OPS, }, .probe = bcm_iproc_i2c_probe, .remove = bcm_iproc_i2c_remove, diff --git a/kernel/drivers/i2c/busses/i2c-bcm2835.c b/kernel/drivers/i2c/busses/i2c-bcm2835.c index c9336a320..3032b89ac 100644 --- a/kernel/drivers/i2c/busses/i2c-bcm2835.c +++ b/kernel/drivers/i2c/busses/i2c-bcm2835.c @@ -50,6 +50,11 @@ #define BCM2835_I2C_S_CLKT BIT(9) #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ +#define BCM2835_I2C_BITMSK_S 0x03FF + +#define BCM2835_I2C_CDIV_MIN 0x0002 +#define BCM2835_I2C_CDIV_MAX 0xFFFE + #define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000)) struct bcm2835_i2c_dev { @@ -111,6 +116,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) u32 val, err; val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + val &= BCM2835_I2C_BITMSK_S; bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val); err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); @@ -258,6 +264,11 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) */ if (divider & 1) divider++; + if ((divider < BCM2835_I2C_CDIV_MIN) || + (divider > BCM2835_I2C_CDIV_MAX)) { + dev_err(&pdev->dev, "Invalid clock-frequency\n"); + return -ENODEV; + } bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); diff --git a/kernel/drivers/i2c/busses/i2c-bfin-twi.c b/kernel/drivers/i2c/busses/i2c-bfin-twi.c index af162b4c7..025686d41 100644 --- a/kernel/drivers/i2c/busses/i2c-bfin-twi.c +++ b/kernel/drivers/i2c/busses/i2c-bfin-twi.c @@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iface); - dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, " + dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, " "regs_base@%p\n", iface->regs_base); return 0; @@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init); module_exit(i2c_bfin_twi_exit); MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); -MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver"); +MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:i2c-bfin-twi"); diff --git a/kernel/drivers/i2c/busses/i2c-brcmstb.c b/kernel/drivers/i2c/busses/i2c-brcmstb.c new file mode 100644 index 000000000..81115abf3 --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-brcmstb.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/version.h> + +#define N_DATA_REGS 8 +#define N_DATA_BYTES (N_DATA_REGS * 4) + +/* BSC count register field definitions */ +#define BSC_CNT_REG1_MASK 0x0000003f +#define BSC_CNT_REG1_SHIFT 0 +#define BSC_CNT_REG2_MASK 0x00000fc0 +#define BSC_CNT_REG2_SHIFT 6 + +/* BSC CTL register field definitions */ +#define BSC_CTL_REG_DTF_MASK 0x00000003 +#define BSC_CTL_REG_SCL_SEL_MASK 0x00000030 +#define BSC_CTL_REG_SCL_SEL_SHIFT 4 +#define BSC_CTL_REG_INT_EN_MASK 0x00000040 +#define BSC_CTL_REG_INT_EN_SHIFT 6 +#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080 + +/* BSC_IIC_ENABLE r/w enable and interrupt field defintions */ +#define BSC_IIC_EN_RESTART_MASK 0x00000040 +#define BSC_IIC_EN_NOSTART_MASK 0x00000020 +#define BSC_IIC_EN_NOSTOP_MASK 0x00000010 +#define BSC_IIC_EN_NOACK_MASK 0x00000004 +#define BSC_IIC_EN_INTRP_MASK 0x00000002 +#define BSC_IIC_EN_ENABLE_MASK 0x00000001 + +/* BSC_CTLHI control register field definitions */ +#define BSC_CTLHI_REG_INPUT_SWITCHING_LEVEL_MASK 0x00000080 +#define BSC_CTLHI_REG_DATAREG_SIZE_MASK 0x00000040 +#define BSC_CTLHI_REG_IGNORE_ACK_MASK 0x00000002 +#define BSC_CTLHI_REG_WAIT_DIS_MASK 0x00000001 + +#define I2C_TIMEOUT 100 /* msecs */ + +/* Condition mask used for non combined transfer */ +#define COND_RESTART BSC_IIC_EN_RESTART_MASK +#define COND_NOSTART BSC_IIC_EN_NOSTART_MASK +#define COND_NOSTOP BSC_IIC_EN_NOSTOP_MASK +#define COND_START_STOP (COND_RESTART | COND_NOSTART | COND_NOSTOP) + +/* BSC data transfer direction */ +#define DTF_WR_MASK 0x00000000 +#define DTF_RD_MASK 0x00000001 +/* BSC data transfer direction combined format */ +#define DTF_RD_WR_MASK 0x00000002 +#define DTF_WR_RD_MASK 0x00000003 + +#define INT_ENABLE true +#define INT_DISABLE false + +/* BSC block register map structure to cache fields to be written */ +struct bsc_regs { + u32 chip_address; /* slave address */ + u32 data_in[N_DATA_REGS]; /* tx data buffer*/ + u32 cnt_reg; /* rx/tx data length */ + u32 ctl_reg; /* control register */ + u32 iic_enable; /* xfer enable and status */ + u32 data_out[N_DATA_REGS]; /* rx data buffer */ + u32 ctlhi_reg; /* more control fields */ + u32 scl_param; /* reserved */ +}; + +struct bsc_clk_param { + u32 hz; + u32 scl_mask; + u32 div_mask; +}; + +enum bsc_xfer_cmd { + CMD_WR, + CMD_RD, + CMD_WR_NOACK, + CMD_RD_NOACK, +}; + +static char const *cmd_string[] = { + [CMD_WR] = "WR", + [CMD_RD] = "RD", + [CMD_WR_NOACK] = "WR NOACK", + [CMD_RD_NOACK] = "RD NOACK", +}; + +enum bus_speeds { + SPD_375K, + SPD_390K, + SPD_187K, + SPD_200K, + SPD_93K, + SPD_97K, + SPD_46K, + SPD_50K +}; + +static const struct bsc_clk_param bsc_clk[] = { + [SPD_375K] = { + .hz = 375000, + .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0 + }, + [SPD_390K] = { + .hz = 390000, + .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0 + }, + [SPD_187K] = { + .hz = 187500, + .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0 + }, + [SPD_200K] = { + .hz = 200000, + .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = 0 + }, + [SPD_93K] = { + .hz = 93750, + .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK + }, + [SPD_97K] = { + .hz = 97500, + .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK + }, + [SPD_46K] = { + .hz = 46875, + .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK + }, + [SPD_50K] = { + .hz = 50000, + .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, + .div_mask = BSC_CTL_REG_DIV_CLK_MASK + } +}; + +struct brcmstb_i2c_dev { + struct device *device; + void __iomem *base; + void __iomem *irq_base; + int irq; + struct bsc_regs *bsc_regmap; + struct i2c_adapter adapter; + struct completion done; + bool is_suspended; + u32 clk_freq_hz; +}; + +/* register accessors for both be and le cpu arch */ +#ifdef CONFIG_CPU_BIG_ENDIAN +#define __bsc_readl(_reg) ioread32be(_reg) +#define __bsc_writel(_val, _reg) iowrite32be(_val, _reg) +#else +#define __bsc_readl(_reg) ioread32(_reg) +#define __bsc_writel(_val, _reg) iowrite32(_val, _reg) +#endif + +#define bsc_readl(_dev, _reg) \ + __bsc_readl(_dev->base + offsetof(struct bsc_regs, _reg)) + +#define bsc_writel(_dev, _val, _reg) \ + __bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg)) + +static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev, + bool int_en) +{ + + if (int_en) + /* Enable BSC CTL interrupt line */ + dev->bsc_regmap->ctl_reg |= BSC_CTL_REG_INT_EN_MASK; + else + /* Disable BSC CTL interrupt line */ + dev->bsc_regmap->ctl_reg &= ~BSC_CTL_REG_INT_EN_MASK; + + barrier(); + bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg); +} + +static irqreturn_t brcmstb_i2c_isr(int irq, void *devid) +{ + struct brcmstb_i2c_dev *dev = devid; + u32 status_bsc_ctl = bsc_readl(dev, ctl_reg); + u32 status_iic_intrp = bsc_readl(dev, iic_enable); + + dev_dbg(dev->device, "isr CTL_REG %x IIC_EN %x\n", + status_bsc_ctl, status_iic_intrp); + + if (!(status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK)) + return IRQ_NONE; + + brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); + complete_all(&dev->done); + + dev_dbg(dev->device, "isr handled"); + return IRQ_HANDLED; +} + +/* Wait for device to be ready */ +static int brcmstb_i2c_wait_if_busy(struct brcmstb_i2c_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT); + + while ((bsc_readl(dev, iic_enable) & BSC_IIC_EN_INTRP_MASK)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cpu_relax(); + } + return 0; +} + +/* i2c xfer completion function, handles both irq and polling mode */ +static int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev) +{ + int ret = 0; + unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT); + + if (dev->irq >= 0) { + if (!wait_for_completion_timeout(&dev->done, timeout)) + ret = -ETIMEDOUT; + } else { + /* we are in polling mode */ + u32 bsc_intrp; + unsigned long time_left = jiffies + timeout; + + do { + bsc_intrp = bsc_readl(dev, iic_enable) & + BSC_IIC_EN_INTRP_MASK; + if (time_after(jiffies, time_left)) { + ret = -ETIMEDOUT; + break; + } + cpu_relax(); + } while (!bsc_intrp); + } + + if (dev->irq < 0 || ret == -ETIMEDOUT) + brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); + + return ret; +} + +/* Set xfer START/STOP conditions for subsequent transfer */ +static void brcmstb_set_i2c_start_stop(struct brcmstb_i2c_dev *dev, + u32 cond_flag) +{ + u32 regval = dev->bsc_regmap->iic_enable; + + dev->bsc_regmap->iic_enable = (regval & ~COND_START_STOP) | cond_flag; +} + +/* Send I2C request check completion */ +static int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev, + enum bsc_xfer_cmd cmd) +{ + int rc = 0; + struct bsc_regs *pi2creg = dev->bsc_regmap; + + /* Make sure the hardware is ready */ + rc = brcmstb_i2c_wait_if_busy(dev); + if (rc < 0) + return rc; + + /* only if we are in interrupt mode */ + if (dev->irq >= 0) + reinit_completion(&dev->done); + + /* enable BSC CTL interrupt line */ + brcmstb_i2c_enable_disable_irq(dev, INT_ENABLE); + + /* initiate transfer by setting iic_enable */ + pi2creg->iic_enable |= BSC_IIC_EN_ENABLE_MASK; + bsc_writel(dev, pi2creg->iic_enable, iic_enable); + + /* Wait for transaction to finish or timeout */ + rc = brcmstb_i2c_wait_for_completion(dev); + if (rc) { + dev_dbg(dev->device, "intr timeout for cmd %s\n", + cmd_string[cmd]); + goto cmd_out; + } + + if ((CMD_RD || CMD_WR) && + bsc_readl(dev, iic_enable) & BSC_IIC_EN_NOACK_MASK) { + rc = -EREMOTEIO; + dev_dbg(dev->device, "controller received NOACK intr for %s\n", + cmd_string[cmd]); + } + +cmd_out: + bsc_writel(dev, 0, cnt_reg); + bsc_writel(dev, 0, iic_enable); + + return rc; +} + +/* Actual data transfer through the BSC master */ +static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, + u8 *buf, unsigned int len, + struct i2c_msg *pmsg) +{ + int cnt, byte, rc; + enum bsc_xfer_cmd cmd; + u32 ctl_reg; + struct bsc_regs *pi2creg = dev->bsc_regmap; + int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; + + /* see if the transaction needs to check NACK conditions */ + if (no_ack || len <= N_DATA_BYTES) { + cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK + : CMD_WR_NOACK; + pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; + } else { + cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD : CMD_WR; + pi2creg->ctlhi_reg &= ~BSC_CTLHI_REG_IGNORE_ACK_MASK; + } + bsc_writel(dev, pi2creg->ctlhi_reg, ctlhi_reg); + + /* set data transfer direction */ + ctl_reg = pi2creg->ctl_reg & ~BSC_CTL_REG_DTF_MASK; + if (cmd == CMD_WR || cmd == CMD_WR_NOACK) + pi2creg->ctl_reg = ctl_reg | DTF_WR_MASK; + else + pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK; + + /* set the read/write length */ + bsc_writel(dev, BSC_CNT_REG1_MASK & (len << BSC_CNT_REG1_SHIFT), + cnt_reg); + + /* Write data into data_in register */ + if (cmd == CMD_WR || cmd == CMD_WR_NOACK) { + for (cnt = 0; cnt < len; cnt += 4) { + u32 word = 0; + + for (byte = 0; byte < 4; byte++) { + word >>= 8; + if ((cnt + byte) < len) + word |= buf[cnt + byte] << 24; + } + bsc_writel(dev, word, data_in[cnt >> 2]); + } + } + + /* Initiate xfer, the function will return on completion */ + rc = brcmstb_send_i2c_cmd(dev, cmd); + + if (rc != 0) { + dev_dbg(dev->device, "%s failure", cmd_string[cmd]); + return rc; + } + + if (cmd == CMD_RD || cmd == CMD_RD_NOACK) { + for (cnt = 0; cnt < len; cnt += 4) { + u32 data = bsc_readl(dev, data_out[cnt >> 2]); + + for (byte = 0; byte < 4 && + (byte + cnt) < len; byte++) { + buf[cnt + byte] = data & 0xff; + data >>= 8; + } + } + } + + return 0; +} + +/* Write a single byte of data to the i2c bus */ +static int brcmstb_i2c_write_data_byte(struct brcmstb_i2c_dev *dev, + u8 *buf, unsigned int nak_expected) +{ + enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK; + + bsc_writel(dev, 1, cnt_reg); + bsc_writel(dev, *buf, data_in); + + return brcmstb_send_i2c_cmd(dev, cmd); +} + +/* Send i2c address */ +static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev, + struct i2c_msg *msg) +{ + unsigned char addr; + + if (msg->flags & I2C_M_TEN) { + /* First byte is 11110XX0 where XX is upper 2 bits */ + addr = 0xF0 | ((msg->addr & 0x300) >> 7); + bsc_writel(dev, addr, chip_address); + + /* Second byte is the remaining 8 bits */ + addr = msg->addr & 0xFF; + if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) + return -EREMOTEIO; + + if (msg->flags & I2C_M_RD) { + /* For read, send restart without stop condition */ + brcmstb_set_i2c_start_stop(dev, COND_RESTART + | COND_NOSTOP); + /* Then re-send the first byte with the read bit set */ + addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01; + if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) + return -EREMOTEIO; + + } + } else { + addr = msg->addr << 1; + if (msg->flags & I2C_M_RD) + addr |= 1; + + bsc_writel(dev, addr, chip_address); + } + + return 0; +} + +/* Master transfer function */ +static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, + struct i2c_msg msgs[], int num) +{ + struct brcmstb_i2c_dev *dev = i2c_get_adapdata(adapter); + struct i2c_msg *pmsg; + int rc = 0; + int i; + int bytes_to_xfer; + u8 *tmp_buf; + int len = 0; + + if (dev->is_suspended) + return -EBUSY; + + /* Loop through all messages */ + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + len = pmsg->len; + tmp_buf = pmsg->buf; + + dev_dbg(dev->device, + "msg# %d/%d flg %x buf %x len %d\n", i, + num - 1, pmsg->flags, + pmsg->buf ? pmsg->buf[0] : '0', pmsg->len); + + if (i < (num - 1) && (msgs[i + 1].flags & I2C_M_NOSTART)) + brcmstb_set_i2c_start_stop(dev, ~(COND_START_STOP)); + else + brcmstb_set_i2c_start_stop(dev, + COND_RESTART | COND_NOSTOP); + + /* Send slave address */ + if (!(pmsg->flags & I2C_M_NOSTART)) { + rc = brcmstb_i2c_do_addr(dev, pmsg); + if (rc < 0) { + dev_dbg(dev->device, + "NACK for addr %2.2x msg#%d rc = %d\n", + pmsg->addr, i, rc); + goto out; + } + } + + /* Perform data transfer */ + while (len) { + bytes_to_xfer = min(len, N_DATA_BYTES); + + if (len <= N_DATA_BYTES && i == (num - 1)) + brcmstb_set_i2c_start_stop(dev, + ~(COND_START_STOP)); + + rc = brcmstb_i2c_xfer_bsc_data(dev, tmp_buf, + bytes_to_xfer, pmsg); + if (rc < 0) + goto out; + + len -= bytes_to_xfer; + tmp_buf += bytes_to_xfer; + } + } + + rc = num; +out: + return rc; + +} + +static u32 brcmstb_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR + | I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING; +} + +static const struct i2c_algorithm brcmstb_i2c_algo = { + .master_xfer = brcmstb_i2c_xfer, + .functionality = brcmstb_i2c_functionality, +}; + +static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev) +{ + int i = 0, num_speeds = ARRAY_SIZE(bsc_clk); + u32 clk_freq_hz = dev->clk_freq_hz; + + for (i = 0; i < num_speeds; i++) { + if (bsc_clk[i].hz == clk_freq_hz) { + dev->bsc_regmap->ctl_reg &= ~(BSC_CTL_REG_SCL_SEL_MASK + | BSC_CTL_REG_DIV_CLK_MASK); + dev->bsc_regmap->ctl_reg |= (bsc_clk[i].scl_mask | + bsc_clk[i].div_mask); + bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg); + break; + } + } + + /* in case we did not get find a valid speed */ + if (i == num_speeds) { + i = (bsc_readl(dev, ctl_reg) & BSC_CTL_REG_SCL_SEL_MASK) >> + BSC_CTL_REG_SCL_SEL_SHIFT; + dev_warn(dev->device, "leaving current clock-frequency @ %dHz\n", + bsc_clk[i].hz); + } +} + +static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev) +{ + /* 4 byte data register */ + dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK; + bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg); + /* set bus speed */ + brcmstb_i2c_set_bus_speed(dev); +} + +static int brcmstb_i2c_probe(struct platform_device *pdev) +{ + int rc = 0; + struct brcmstb_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *iomem; + const char *int_name; + + /* Allocate memory for private data structure */ + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL); + if (!dev->bsc_regmap) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + dev->device = &pdev->dev; + init_completion(&dev->done); + + /* Map hardware registers */ + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(dev->device, iomem); + if (IS_ERR(dev->base)) { + rc = -ENOMEM; + goto probe_errorout; + } + + rc = of_property_read_string(dev->device->of_node, "interrupt-names", + &int_name); + if (rc < 0) + int_name = NULL; + + /* Get the interrupt number */ + dev->irq = platform_get_irq(pdev, 0); + + /* disable the bsc interrupt line */ + brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); + + /* register the ISR handler */ + rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr, + IRQF_SHARED, + int_name ? int_name : pdev->name, + dev); + + if (rc) { + dev_dbg(dev->device, "falling back to polling mode"); + dev->irq = -1; + } + + if (of_property_read_u32(dev->device->of_node, + "clock-frequency", &dev->clk_freq_hz)) { + dev_warn(dev->device, "setting clock-frequency@%dHz\n", + bsc_clk[0].hz); + dev->clk_freq_hz = bsc_clk[0].hz; + } + + brcmstb_i2c_set_bsc_reg_defaults(dev); + + /* Add the i2c adapter */ + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + strlcpy(adap->name, "Broadcom STB : ", sizeof(adap->name)); + if (int_name) + strlcat(adap->name, int_name, sizeof(adap->name)); + adap->algo = &brcmstb_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + rc = i2c_add_adapter(adap); + if (rc) { + dev_err(dev->device, "failed to add adapter\n"); + goto probe_errorout; + } + + dev_info(dev->device, "%s@%dhz registered in %s mode\n", + int_name ? int_name : " ", dev->clk_freq_hz, + (dev->irq >= 0) ? "interrupt" : "polling"); + + return 0; + +probe_errorout: + return rc; +} + +static int brcmstb_i2c_remove(struct platform_device *pdev) +{ + struct brcmstb_i2c_dev *dev = platform_get_drvdata(pdev); + + i2c_del_adapter(&dev->adapter); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int brcmstb_i2c_suspend(struct device *dev) +{ + struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); + + i2c_lock_adapter(&i2c_dev->adapter); + i2c_dev->is_suspended = true; + i2c_unlock_adapter(&i2c_dev->adapter); + + return 0; +} + +static int brcmstb_i2c_resume(struct device *dev) +{ + struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); + + i2c_lock_adapter(&i2c_dev->adapter); + brcmstb_i2c_set_bsc_reg_defaults(i2c_dev); + i2c_dev->is_suspended = false; + i2c_unlock_adapter(&i2c_dev->adapter); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, + brcmstb_i2c_resume); + +static const struct of_device_id brcmstb_i2c_of_match[] = { + {.compatible = "brcm,brcmstb-i2c"}, + {}, +}; +MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match); + +static struct platform_driver brcmstb_i2c_driver = { + .driver = { + .name = "brcmstb-i2c", + .of_match_table = brcmstb_i2c_of_match, + .pm = &brcmstb_i2c_pm, + }, + .probe = brcmstb_i2c_probe, + .remove = brcmstb_i2c_remove, +}; +module_platform_driver(brcmstb_i2c_driver); + +MODULE_AUTHOR("Kamal Dasu <kdasu@broadcom.com>"); +MODULE_DESCRIPTION("Broadcom Settop I2C Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/i2c/busses/i2c-cadence.c b/kernel/drivers/i2c/busses/i2c-cadence.c index 2ee78e099..84deed657 100644 --- a/kernel/drivers/i2c/busses/i2c-cadence.c +++ b/kernel/drivers/i2c/busses/i2c-cadence.c @@ -17,6 +17,7 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> /* Register offsets for the I2C device. */ #define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */ @@ -113,6 +114,8 @@ #define CDNS_I2C_TIMEOUT_MAX 0xFF +#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) + #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) @@ -135,6 +138,7 @@ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit * @clk: Pointer to struct clk * @clk_rate_change_nb: Notifier block for clock rate changes + * @quirks: flag for broken hold bit usage in r1p10 */ struct cdns_i2c { void __iomem *membase; @@ -154,6 +158,11 @@ struct cdns_i2c { unsigned int bus_hold_flag; struct clk *clk; struct notifier_block clk_rate_change_nb; + u32 quirks; +}; + +struct cdns_platform_data { + u32 quirks; }; #define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \ @@ -172,6 +181,12 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET); } +static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround) +{ + return (hold_wrkaround && + (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)); +} + /** * cdns_i2c_isr - Interrupt handler for the I2C device * @irq: irq number for the I2C device @@ -186,6 +201,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) { unsigned int isr_status, avail_bytes, updatetx; unsigned int bytes_to_send; + bool hold_quirk; struct cdns_i2c *id = ptr; /* Signal completion only after everything is updated */ int done_flag = 0; @@ -208,6 +224,8 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) if (id->recv_count > id->curr_recv_count) updatetx = 1; + hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx; + /* When receiving, handle data interrupt and completion interrupt */ if (id->p_recv_buf && ((isr_status & CDNS_I2C_IXR_COMP) || @@ -229,8 +247,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) id->recv_count--; id->curr_recv_count--; - if (updatetx && - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) + if (cdns_is_holdquirk(id, hold_quirk)) break; } @@ -241,8 +258,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) * maintain transfer size non-zero while performing a large * receive operation. */ - if (updatetx && - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) { + if (cdns_is_holdquirk(id, hold_quirk)) { /* wait while fifo is full */ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH)) @@ -264,6 +280,22 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) CDNS_I2C_XFER_SIZE_OFFSET); id->curr_recv_count = id->recv_count; } + } else if (id->recv_count && !hold_quirk && + !id->curr_recv_count) { + + /* Set the slave address in address register*/ + cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, + CDNS_I2C_ADDR_OFFSET); + + if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { + cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; + } else { + cdns_i2c_writereg(id->recv_count, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; + } } /* Clear hold (if not repeated start) and signal completion */ @@ -535,11 +567,13 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int ret, count; u32 reg; struct cdns_i2c *id = adap->algo_data; + bool hold_quirk; /* Check if the bus is free */ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) return -EAGAIN; + hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); /* * Set the flag to one when multiple messages are to be * processed with a repeated start. @@ -552,7 +586,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, * followed by any other message, an error is returned * indicating that this sequence is not supported. */ - for (count = 0; count < num - 1; count++) { + for (count = 0; (count < num - 1 && hold_quirk); count++) { if (msgs[count].flags & I2C_M_RD) { dev_warn(adap->dev.parent, "Can't do repeated start after a receive message\n"); @@ -815,6 +849,17 @@ static int __maybe_unused cdns_i2c_resume(struct device *_dev) static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend, cdns_i2c_resume); +static const struct cdns_platform_data r1p10_i2c_def = { + .quirks = CDNS_I2C_BROKEN_HOLD_BIT, +}; + +static const struct of_device_id cdns_i2c_of_match[] = { + { .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def }, + { .compatible = "cdns,i2c-r1p14",}, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, cdns_i2c_of_match); + /** * cdns_i2c_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -830,6 +875,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) struct resource *r_mem; struct cdns_i2c *id; int ret; + const struct of_device_id *match; id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); if (!id) @@ -837,6 +883,12 @@ static int cdns_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, id); + match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node); + if (match && match->data) { + const struct cdns_platform_data *data = match->data; + id->quirks = data->quirks; + } + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); id->membase = devm_ioremap_resource(&pdev->dev, r_mem); if (IS_ERR(id->membase)) @@ -844,6 +896,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) id->irq = platform_get_irq(pdev, 0); + id->adap.owner = THIS_MODULE; id->adap.dev.of_node = pdev->dev.of_node; id->adap.algo = &cdns_i2c_algo; id->adap.timeout = CDNS_I2C_TIMEOUT; @@ -935,12 +988,6 @@ static int cdns_i2c_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id cdns_i2c_of_match[] = { - { .compatible = "cdns,i2c-r1p10", }, - { /* end of table */ } -}; -MODULE_DEVICE_TABLE(of, cdns_i2c_of_match); - static struct platform_driver cdns_i2c_drv = { .driver = { .name = DRIVER_NAME, diff --git a/kernel/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/kernel/drivers/i2c/busses/i2c-cros-ec-tunnel.c index fa8dedd8c..a0d95ff68 100644 --- a/kernel/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/kernel/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -182,8 +182,9 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], const u16 bus_num = bus->remote_bus; int request_len; int response_len; + int alloc_size; int result; - struct cros_ec_command msg = { }; + struct cros_ec_command *msg; request_len = ec_i2c_count_message(i2c_msgs, num); if (request_len < 0) { @@ -198,25 +199,39 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], return response_len; } - result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num); - if (result) - return result; + alloc_size = max(request_len, response_len); + msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL); + if (!msg) + return -ENOMEM; - msg.version = 0; - msg.command = EC_CMD_I2C_PASSTHRU; - msg.outsize = request_len; - msg.insize = response_len; + result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num); + if (result) { + dev_err(dev, "Error constructing EC i2c message %d\n", result); + goto exit; + } - result = cros_ec_cmd_xfer(bus->ec, &msg); - if (result < 0) - return result; + msg->version = 0; + msg->command = EC_CMD_I2C_PASSTHRU; + msg->outsize = request_len; + msg->insize = response_len; - result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num); - if (result < 0) - return result; + result = cros_ec_cmd_xfer(bus->ec, msg); + if (result < 0) { + dev_err(dev, "Error transferring EC i2c message %d\n", result); + goto exit; + } + + result = ec_i2c_parse_response(msg->data, i2c_msgs, &num); + if (result < 0) { + dev_err(dev, "Error parsing EC i2c message %d\n", result); + goto exit; + } /* Indicate success by saying how many messages were sent */ - return num; + result = num; +exit: + kfree(msg); + return result; } static u32 ec_i2c_functionality(struct i2c_adapter *adap) diff --git a/kernel/drivers/i2c/busses/i2c-davinci.c b/kernel/drivers/i2c/busses/i2c-davinci.c index 4788a32af..a8bdcb529 100644 --- a/kernel/drivers/i2c/busses/i2c-davinci.c +++ b/kernel/drivers/i2c/busses/i2c-davinci.c @@ -41,8 +41,8 @@ #define DAVINCI_I2C_TIMEOUT (1*HZ) #define DAVINCI_I2C_MAX_TRIES 2 -#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \ - DAVINCI_I2C_IMR_SCD | \ +#define DAVINCI_I2C_OWN_ADDRESS 0x08 +#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_SCD | \ DAVINCI_I2C_IMR_ARDY | \ DAVINCI_I2C_IMR_NACK | \ DAVINCI_I2C_IMR_AL) @@ -181,6 +181,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) u32 clkh; u32 clkl; u32 input_clock = clk_get_rate(dev->clk); + struct device_node *of_node = dev->dev->of_node; /* NOTE: I2C Clock divider programming info * As per I2C specs the following formulas provide prescaler @@ -196,17 +197,51 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) * where if PSC == 0, d = 7, * if PSC == 1, d = 6 * if PSC > 1 , d = 5 + * + * Note: + * d is always 6 on Keystone I2C controller */ - /* get minimum of 7 MHz clock, but max of 12 MHz */ - psc = (input_clock / 7000000) - 1; + /* + * Both Davinci and current Keystone User Guides recommend a value + * between 7MHz and 12MHz. In reality 7MHz module clock doesn't + * always produce enough margin between SDA and SCL transitions. + * Measurements show that the higher the module clock is, the + * bigger is the margin, providing more reliable communication. + * So we better target for 12MHz. + */ + psc = (input_clock / 12000000) - 1; if ((input_clock / (psc + 1)) > 12000000) psc++; /* better to run under spec than over */ d = (psc >= 2) ? 5 : 7 - psc; - clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - (d << 1); - clkh = clk >> 1; - clkl = clk - clkh; + if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c")) + d = 6; + + clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)); + /* Avoid driving the bus too fast because of rounding errors above */ + if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000) + clk++; + /* + * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at + * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH + * to LOW ratio as 1 to 2 is more safe. + */ + if (pdata->bus_freq > 100) + clkl = (clk << 1) / 3; + else + clkl = (clk >> 1); + /* + * It's not always possible to have 1 to 2 ratio when d=7, so fall back + * to minimal possible clkh in this case. + */ + if (clk >= clkl + d) { + clkh = clk - clkl - d; + clkl -= d; + } else { + clkh = 0; + clkl = clk - (d << 1); + } davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc); davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh); @@ -233,7 +268,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) /* Respond at reserved "SMBus Host" slave address" (and zero); * we seem to have no option to not respond... */ - davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08); + davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, DAVINCI_I2C_OWN_ADDRESS); dev_dbg(dev->dev, "PSC = %d\n", davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG)); @@ -350,29 +385,25 @@ static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = { /* * Waiting for bus not busy */ -static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev, - char allow_sleep) +static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev) { - unsigned long timeout; - static u16 to_cnt; - - timeout = jiffies + dev->adapter.timeout; - while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) - & DAVINCI_I2C_STR_BB) { - if (to_cnt <= DAVINCI_I2C_MAX_TRIES) { - if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, - "timeout waiting for bus ready\n"); - to_cnt++; - return -ETIMEDOUT; - } else { - to_cnt = 0; - i2c_recover_bus(&dev->adapter); - } - } - if (allow_sleep) - schedule_timeout(1); - } + unsigned long timeout = jiffies + dev->adapter.timeout; + + do { + if (!(davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) & DAVINCI_I2C_STR_BB)) + return 0; + schedule_timeout_uninterruptible(1); + } while (time_before_eq(jiffies, timeout)); + + dev_warn(dev->dev, "timeout waiting for bus ready\n"); + i2c_recover_bus(&dev->adapter); + + /* + * if bus is still "busy" here, it's most probably a HW problem like + * short-circuit + */ + if (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG) & DAVINCI_I2C_STR_BB) + return -EIO; return 0; } @@ -390,6 +421,11 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) u16 w; unsigned long time_left; + if (msg->addr == DAVINCI_I2C_OWN_ADDRESS) { + dev_warn(dev->dev, "transfer to own address aborted\n"); + return -EADDRNOTAVAIL; + } + /* Introduce a delay, required for some boards (e.g Davinci EVM) */ if (pdata->bus_delay) udelay(pdata->bus_delay); @@ -505,7 +541,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); - ret = i2c_davinci_wait_bus_not_busy(dev, 1); + ret = i2c_davinci_wait_bus_not_busy(dev); if (ret < 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); return ret; @@ -704,6 +740,7 @@ static struct i2c_algorithm i2c_davinci_algo = { static const struct of_device_id davinci_i2c_of_match[] = { {.compatible = "ti,davinci-i2c", }, + {.compatible = "ti,keystone-i2c", }, {}, }; MODULE_DEVICE_TABLE(of, davinci_i2c_of_match); diff --git a/kernel/drivers/i2c/busses/i2c-designware-core.c b/kernel/drivers/i2c/busses/i2c-designware-core.c index 6f19a3377..de7fbbb37 100644 --- a/kernel/drivers/i2c/busses/i2c-designware-core.c +++ b/kernel/drivers/i2c/busses/i2c-designware-core.c @@ -165,7 +165,7 @@ static char *abort_sources[] = { "lost arbitration", }; -u32 dw_readl(struct dw_i2c_dev *dev, int offset) +static u32 dw_readl(struct dw_i2c_dev *dev, int offset) { u32 value; @@ -181,7 +181,7 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset) return value; } -void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) +static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) { if (dev->accessor_flags & ACCESS_SWAP) b = swab32(b); @@ -438,7 +438,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) __i2c_dw_enable(dev, true); /* Clear and enable interrupts */ - i2c_dw_clear_int(dev); + dw_readl(dev, DW_IC_CLR_INTR); dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); } @@ -618,7 +618,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) /* * Prepare controller for a transaction and call i2c_dw_xfer_msg */ -int +static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); @@ -702,14 +702,17 @@ done_nolock: return ret; } -EXPORT_SYMBOL_GPL(i2c_dw_xfer); -u32 i2c_dw_func(struct i2c_adapter *adap) +static u32 i2c_dw_func(struct i2c_adapter *adap) { struct dw_i2c_dev *dev = i2c_get_adapdata(adap); return dev->functionality; } -EXPORT_SYMBOL_GPL(i2c_dw_func); + +static struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { @@ -770,15 +773,14 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) * Interrupt service routine. This gets called whenever an I2C interrupt * occurs. */ -irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; u32 stat, enabled; enabled = dw_readl(dev, DW_IC_ENABLE); stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); - dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__, - dev->adapter.name, enabled, stat); + dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat); if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) return IRQ_NONE; @@ -811,23 +813,15 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) tx_aborted: if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) complete(&dev->cmd_complete); + else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { + /* workaround to trigger pending interrupt */ + stat = dw_readl(dev, DW_IC_INTR_MASK); + i2c_dw_disable_int(dev); + dw_writel(dev, stat, DW_IC_INTR_MASK); + } return IRQ_HANDLED; } -EXPORT_SYMBOL_GPL(i2c_dw_isr); - -void i2c_dw_enable(struct dw_i2c_dev *dev) -{ - /* Enable the adapter */ - __i2c_dw_enable(dev, true); -} -EXPORT_SYMBOL_GPL(i2c_dw_enable); - -u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) -{ - return dw_readl(dev, DW_IC_ENABLE); -} -EXPORT_SYMBOL_GPL(i2c_dw_is_enabled); void i2c_dw_disable(struct dw_i2c_dev *dev) { @@ -840,12 +834,6 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) } EXPORT_SYMBOL_GPL(i2c_dw_disable); -void i2c_dw_clear_int(struct dw_i2c_dev *dev) -{ - dw_readl(dev, DW_IC_CLR_INTR); -} -EXPORT_SYMBOL_GPL(i2c_dw_clear_int); - void i2c_dw_disable_int(struct dw_i2c_dev *dev) { dw_writel(dev, 0, DW_IC_INTR_MASK); @@ -858,5 +846,40 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) } EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param); +int i2c_dw_probe(struct dw_i2c_dev *dev) +{ + struct i2c_adapter *adap = &dev->adapter; + int r; + + init_completion(&dev->cmd_complete); + mutex_init(&dev->lock); + + r = i2c_dw_init(dev); + if (r) + return r; + + snprintf(adap->name, sizeof(adap->name), + "Synopsys DesignWare I2C adapter"); + adap->algo = &i2c_dw_algo; + adap->dev.parent = dev->dev; + i2c_set_adapdata(adap, dev); + + i2c_dw_disable_int(dev); + r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED, + dev_name(dev->dev), dev); + if (r) { + dev_err(dev->dev, "failure requesting irq %i: %d\n", + dev->irq, r); + return r; + } + + r = i2c_add_numbered_adapter(adap); + if (r) + dev_err(dev->dev, "failure adding adapter: %d\n", r); + + return r; +} +EXPORT_SYMBOL_GPL(i2c_dw_probe); + MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/i2c/busses/i2c-designware-core.h b/kernel/drivers/i2c/busses/i2c-designware-core.h index 9630222ab..9ffb63a60 100644 --- a/kernel/drivers/i2c/busses/i2c-designware-core.h +++ b/kernel/drivers/i2c/busses/i2c-designware-core.h @@ -111,20 +111,13 @@ struct dw_i2c_dev { #define ACCESS_SWAP 0x00000001 #define ACCESS_16BIT 0x00000002 +#define ACCESS_INTR_MASK 0x00000004 -extern u32 dw_readl(struct dw_i2c_dev *dev, int offset); -extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); extern int i2c_dw_init(struct dw_i2c_dev *dev); -extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - int num); -extern u32 i2c_dw_func(struct i2c_adapter *adap); -extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id); -extern void i2c_dw_enable(struct dw_i2c_dev *dev); -extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev); extern void i2c_dw_disable(struct dw_i2c_dev *dev); -extern void i2c_dw_clear_int(struct dw_i2c_dev *dev); extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); +extern int i2c_dw_probe(struct dw_i2c_dev *dev); #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev); diff --git a/kernel/drivers/i2c/busses/i2c-designware-pcidrv.c b/kernel/drivers/i2c/busses/i2c-designware-pcidrv.c index 6643d2dc0..1543d35d2 100644 --- a/kernel/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/kernel/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/pm_runtime.h> +#include <linux/acpi.h> #include "i2c-designware-core.h" #define DRIVER_NAME "i2c-designware-pci" @@ -158,11 +159,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, }; -static struct i2c_algorithm i2c_dw_algo = { - .master_xfer = i2c_dw_xfer, - .functionality = i2c_dw_func, -}; - #ifdef CONFIG_PM static int i2c_dw_pci_suspend(struct device *dev) { @@ -222,13 +218,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, if (!dev) return -ENOMEM; - init_completion(&dev->cmd_complete); - mutex_init(&dev->lock); dev->clk = NULL; dev->controller = controller; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->base = pcim_iomap_table(pdev)[0]; dev->dev = &pdev->dev; + dev->irq = pdev->irq; dev->functionality = controller->functionality | DW_DEFAULT_FUNCTIONALITY; @@ -246,34 +241,16 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->tx_fifo_depth = controller->tx_fifo_depth; dev->rx_fifo_depth = controller->rx_fifo_depth; - r = i2c_dw_init(dev); - if (r) - return r; adap = &dev->adapter; - i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; adap->class = 0; - adap->algo = &i2c_dw_algo; - adap->dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->nr = controller->bus_num; - snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci"); - - r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED, - adap->name, dev); - if (r) { - dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); - return r; - } - - i2c_dw_disable_int(dev); - i2c_dw_clear_int(dev); - r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(&pdev->dev, "failure adding adapter\n"); + r = i2c_dw_probe(dev); + if (r) return r; - } pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); pm_runtime_use_autosuspend(&pdev->dev); diff --git a/kernel/drivers/i2c/busses/i2c-designware-platdrv.c b/kernel/drivers/i2c/busses/i2c-designware-platdrv.c index 0a80e4aab..6b00061c3 100644 --- a/kernel/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/kernel/drivers/i2c/busses/i2c-designware-platdrv.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/dmi.h> #include <linux/i2c.h> #include <linux/clk.h> #include <linux/clk-provider.h> @@ -41,16 +42,28 @@ #include <linux/platform_data/i2c-designware.h> #include "i2c-designware-core.h" -static struct i2c_algorithm i2c_dw_algo = { - .master_xfer = i2c_dw_xfer, - .functionality = i2c_dw_func, -}; static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) { return clk_get_rate(dev->clk)/1000; } #ifdef CONFIG_ACPI +/* + * The HCNT/LCNT information coming from ACPI should be the most accurate + * for given platform. However, some systems get it wrong. On such systems + * we get better results by calculating those based on the input clock. + */ +static const struct dmi_system_id dw_i2c_no_acpi_params[] = { + { + .ident = "Dell Inspiron 7348", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7348"), + }, + }, + { } +}; + static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], u16 *hcnt, u16 *lcnt, u32 *sda_hold) { @@ -58,6 +71,9 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], acpi_handle handle = ACPI_HANDLE(&pdev->dev); union acpi_object *obj; + if (dmi_check_system(dw_i2c_no_acpi_params)) + return; + if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf))) return; @@ -91,29 +107,13 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &dev->sda_hold_time); - /* - * Provide a way for Designware I2C host controllers that are not - * based on Intel LPSS to specify their input clock frequency via - * id->driver_data. - */ id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (id && id->driver_data) - clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL, - CLK_IS_ROOT, id->driver_data); + dev->accessor_flags |= (u32)id->driver_data; return 0; } -static void dw_i2c_acpi_unconfigure(struct platform_device *pdev) -{ - struct dw_i2c_dev *dev = platform_get_drvdata(pdev); - const struct acpi_device_id *id; - - id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); - if (id && id->driver_data) - clk_unregister(dev->clk); -} - static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C2", 0 }, { "INT33C3", 0 }, @@ -121,7 +121,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT3433", 0 }, { "80860F41", 0 }, { "808622C1", 0 }, - { "AMD0010", 133 * 1000 * 1000 }, + { "AMD0010", ACCESS_INTR_MASK }, { } }; MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); @@ -130,10 +130,9 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) { return -ENODEV; } -static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { } #endif -static int dw_i2c_probe(struct platform_device *pdev) +static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_dev *dev; struct i2c_adapter *adap; @@ -155,8 +154,6 @@ static int dw_i2c_probe(struct platform_device *pdev) if (IS_ERR(dev->base)) return PTR_ERR(dev->base); - init_completion(&dev->cmd_complete); - mutex_init(&dev->lock); dev->dev = &pdev->dev; dev->irq = irq; platform_set_drvdata(pdev, dev); @@ -231,34 +228,13 @@ static int dw_i2c_probe(struct platform_device *pdev) dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; dev->adapter.nr = pdev->id; } - r = i2c_dw_init(dev); - if (r) - return r; - - i2c_dw_disable_int(dev); - r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED, - pdev->name, dev); - if (r) { - dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); - return r; - } adap = &dev->adapter; - i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; - strlcpy(adap->name, "Synopsys DesignWare I2C adapter", - sizeof(adap->name)); - adap->algo = &i2c_dw_algo; - adap->dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(&pdev->dev, "failure adding adapter\n"); - return r; - } - if (dev->pm_runtime_disabled) { pm_runtime_forbid(&pdev->dev); } else { @@ -268,10 +244,14 @@ static int dw_i2c_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); } - return 0; + r = i2c_dw_probe(dev); + if (r && !dev->pm_runtime_disabled) + pm_runtime_disable(&pdev->dev); + + return r; } -static int dw_i2c_remove(struct platform_device *pdev) +static int dw_i2c_plat_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); @@ -281,11 +261,10 @@ static int dw_i2c_remove(struct platform_device *pdev) i2c_dw_disable(dev); - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - if (has_acpi_companion(&pdev->dev)) - dw_i2c_acpi_unconfigure(pdev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + if (!dev->pm_runtime_disabled) + pm_runtime_disable(&pdev->dev); return 0; } @@ -298,8 +277,24 @@ static const struct of_device_id dw_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #endif +#ifdef CONFIG_PM_SLEEP +static int dw_i2c_plat_prepare(struct device *dev) +{ + return pm_runtime_suspended(dev); +} + +static void dw_i2c_plat_complete(struct device *dev) +{ + if (dev->power.direct_complete) + pm_request_resume(dev); +} +#else +#define dw_i2c_plat_prepare NULL +#define dw_i2c_plat_complete NULL +#endif + #ifdef CONFIG_PM -static int dw_i2c_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); @@ -310,7 +305,7 @@ static int dw_i2c_suspend(struct device *dev) return 0; } -static int dw_i2c_resume(struct device *dev) +static int dw_i2c_plat_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); @@ -322,22 +317,30 @@ static int dw_i2c_resume(struct device *dev) return 0; } -#endif -static UNIVERSAL_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, - dw_i2c_resume, NULL); +static const struct dev_pm_ops dw_i2c_dev_pm_ops = { + .prepare = dw_i2c_plat_prepare, + .complete = dw_i2c_plat_complete, + SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL) +}; + +#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) +#else +#define DW_I2C_DEV_PMOPS NULL +#endif /* work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_designware"); static struct platform_driver dw_i2c_driver = { - .probe = dw_i2c_probe, - .remove = dw_i2c_remove, + .probe = dw_i2c_plat_probe, + .remove = dw_i2c_plat_remove, .driver = { .name = "i2c_designware", .of_match_table = of_match_ptr(dw_i2c_of_match), .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), - .pm = &dw_i2c_dev_pm_ops, + .pm = DW_I2C_DEV_PMOPS, }, }; diff --git a/kernel/drivers/i2c/busses/i2c-emev2.c b/kernel/drivers/i2c/busses/i2c-emev2.c new file mode 100644 index 000000000..192ef6b50 --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-emev2.c @@ -0,0 +1,332 @@ +/* + * I2C driver for the Renesas EMEV2 SoC + * + * Copyright (C) 2015 Wolfram Sang <wsa@sang-engineering.com> + * Copyright 2013 Codethink Ltd. + * Copyright 2010-2015 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/sched.h> + +/* I2C Registers */ +#define I2C_OFS_IICACT0 0x00 /* start */ +#define I2C_OFS_IIC0 0x04 /* shift */ +#define I2C_OFS_IICC0 0x08 /* control */ +#define I2C_OFS_SVA0 0x0c /* slave address */ +#define I2C_OFS_IICCL0 0x10 /* clock select */ +#define I2C_OFS_IICX0 0x14 /* extension */ +#define I2C_OFS_IICS0 0x18 /* status */ +#define I2C_OFS_IICSE0 0x1c /* status For emulation */ +#define I2C_OFS_IICF0 0x20 /* IIC flag */ + +/* I2C IICACT0 Masks */ +#define I2C_BIT_IICE0 0x0001 + +/* I2C IICC0 Masks */ +#define I2C_BIT_LREL0 0x0040 +#define I2C_BIT_WREL0 0x0020 +#define I2C_BIT_SPIE0 0x0010 +#define I2C_BIT_WTIM0 0x0008 +#define I2C_BIT_ACKE0 0x0004 +#define I2C_BIT_STT0 0x0002 +#define I2C_BIT_SPT0 0x0001 + +/* I2C IICCL0 Masks */ +#define I2C_BIT_SMC0 0x0008 +#define I2C_BIT_DFC0 0x0004 + +/* I2C IICSE0 Masks */ +#define I2C_BIT_MSTS0 0x0080 +#define I2C_BIT_ALD0 0x0040 +#define I2C_BIT_EXC0 0x0020 +#define I2C_BIT_COI0 0x0010 +#define I2C_BIT_TRC0 0x0008 +#define I2C_BIT_ACKD0 0x0004 +#define I2C_BIT_STD0 0x0002 +#define I2C_BIT_SPD0 0x0001 + +/* I2C IICF0 Masks */ +#define I2C_BIT_STCF 0x0080 +#define I2C_BIT_IICBSY 0x0040 +#define I2C_BIT_STCEN 0x0002 +#define I2C_BIT_IICRSV 0x0001 + +struct em_i2c_device { + void __iomem *base; + struct i2c_adapter adap; + struct completion msg_done; + struct clk *sclk; +}; + +static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg) +{ + writeb((readb(priv->base + reg) & ~clear) | set, priv->base + reg); +} + +static int em_i2c_wait_for_event(struct em_i2c_device *priv) +{ + unsigned long time_left; + int status; + + reinit_completion(&priv->msg_done); + + time_left = wait_for_completion_timeout(&priv->msg_done, priv->adap.timeout); + + if (!time_left) + return -ETIMEDOUT; + + status = readb(priv->base + I2C_OFS_IICSE0); + return status & I2C_BIT_ALD0 ? -EAGAIN : status; +} + +static void em_i2c_stop(struct em_i2c_device *priv) +{ + /* Send Stop condition */ + em_clear_set_bit(priv, 0, I2C_BIT_SPT0 | I2C_BIT_SPIE0, I2C_OFS_IICC0); + + /* Wait for stop condition */ + em_i2c_wait_for_event(priv); +} + +static void em_i2c_reset(struct i2c_adapter *adap) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int retr; + + /* If I2C active */ + if (readb(priv->base + I2C_OFS_IICACT0) & I2C_BIT_IICE0) { + /* Disable I2C operation */ + writeb(0, priv->base + I2C_OFS_IICACT0); + + retr = 1000; + while (readb(priv->base + I2C_OFS_IICACT0) == 1 && retr) + retr--; + WARN_ON(retr == 0); + } + + /* Transfer mode set */ + writeb(I2C_BIT_DFC0, priv->base + I2C_OFS_IICCL0); + + /* Can Issue start without detecting a stop, Reservation disabled. */ + writeb(I2C_BIT_STCEN | I2C_BIT_IICRSV, priv->base + I2C_OFS_IICF0); + + /* I2C enable, 9 bit interrupt mode */ + writeb(I2C_BIT_WTIM0, priv->base + I2C_OFS_IICC0); + + /* Enable I2C operation */ + writeb(I2C_BIT_IICE0, priv->base + I2C_OFS_IICACT0); + + retr = 1000; + while (readb(priv->base + I2C_OFS_IICACT0) == 0 && retr) + retr--; + WARN_ON(retr == 0); +} + +static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int stop) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int count, status, read = !!(msg->flags & I2C_M_RD); + + /* Send start condition */ + em_clear_set_bit(priv, 0, I2C_BIT_ACKE0 | I2C_BIT_WTIM0, I2C_OFS_IICC0); + em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0); + + /* Send slave address and R/W type */ + writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0); + + /* Wait for transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + + /* Received NACK (result of setting slave address and R/W) */ + if (!(status & I2C_BIT_ACKD0)) { + em_i2c_stop(priv); + goto out; + } + + /* Extra setup for read transactions */ + if (read) { + /* 8 bit interrupt mode */ + em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0); + em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0); + + /* Wait for transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + } + + /* Send / receive data */ + for (count = 0; count < msg->len; count++) { + if (read) { /* Read transaction */ + msg->buf[count] = readb(priv->base + I2C_OFS_IIC0); + em_clear_set_bit(priv, 0, I2C_BIT_WREL0, I2C_OFS_IICC0); + + } else { /* Write transaction */ + /* Received NACK */ + if (!(status & I2C_BIT_ACKD0)) { + em_i2c_stop(priv); + goto out; + } + + /* Write data */ + writeb(msg->buf[count], priv->base + I2C_OFS_IIC0); + } + + /* Wait for R/W transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + } + + if (stop) + em_i2c_stop(priv); + + return count; + +out_reset: + em_i2c_reset(adap); +out: + return status < 0 ? status : -ENXIO; +} + +static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int ret, i; + + if (readb(priv->base + I2C_OFS_IICF0) & I2C_BIT_IICBSY) + return -EAGAIN; + + for (i = 0; i < num; i++) { + ret = __em_i2c_xfer(adap, &msgs[i], (i == (num - 1))); + if (ret < 0) + return ret; + } + + /* I2C transfer completed */ + return num; +} + +static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id) +{ + struct em_i2c_device *priv = dev_id; + + complete(&priv->msg_done); + return IRQ_HANDLED; +} + +static u32 em_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm em_i2c_algo = { + .master_xfer = em_i2c_xfer, + .functionality = em_i2c_func, +}; + +static int em_i2c_probe(struct platform_device *pdev) +{ + struct em_i2c_device *priv; + struct resource *r; + int irq, ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + strlcpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name)); + + priv->sclk = devm_clk_get(&pdev->dev, "sclk"); + if (IS_ERR(priv->sclk)) + return PTR_ERR(priv->sclk); + + clk_prepare_enable(priv->sclk); + + priv->adap.timeout = msecs_to_jiffies(100); + priv->adap.retries = 5; + priv->adap.dev.parent = &pdev->dev; + priv->adap.algo = &em_i2c_algo; + priv->adap.owner = THIS_MODULE; + priv->adap.dev.of_node = pdev->dev.of_node; + + init_completion(&priv->msg_done); + + platform_set_drvdata(pdev, priv); + i2c_set_adapdata(&priv->adap, priv); + + em_i2c_reset(&priv->adap); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, em_i2c_irq_handler, 0, + "em_i2c", priv); + if (ret) + goto err_clk; + + ret = i2c_add_adapter(&priv->adap); + + if (ret) + goto err_clk; + + dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, irq); + + return 0; + +err_clk: + clk_disable_unprepare(priv->sclk); + return ret; +} + +static int em_i2c_remove(struct platform_device *dev) +{ + struct em_i2c_device *priv = platform_get_drvdata(dev); + + i2c_del_adapter(&priv->adap); + clk_disable_unprepare(priv->sclk); + + return 0; +} + +static const struct of_device_id em_i2c_ids[] = { + { .compatible = "renesas,iic-emev2", }, + { } +}; + +static struct platform_driver em_i2c_driver = { + .probe = em_i2c_probe, + .remove = em_i2c_remove, + .driver = { + .name = "em-i2c", + .of_match_table = em_i2c_ids, + } +}; +module_platform_driver(em_i2c_driver); + +MODULE_DESCRIPTION("EMEV2 I2C bus driver"); +MODULE_AUTHOR("Ian Molton and Wolfram Sang <wsa@sang-engineering.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, em_i2c_ids); diff --git a/kernel/drivers/i2c/busses/i2c-i801.c b/kernel/drivers/i2c/busses/i2c-i801.c index 5ecbb3fdc..27fa0cb09 100644 --- a/kernel/drivers/i2c/busses/i2c-i801.c +++ b/kernel/drivers/i2c/busses/i2c-i801.c @@ -60,6 +60,10 @@ * BayTrail (SOC) 0x0f12 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes + * DNV (SOC) 0x19df 32 hard yes yes yes + * Broxton (SOC) 0x5ad4 32 hard yes yes yes + * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes + * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -88,12 +92,13 @@ #include <linux/slab.h> #include <linux/wait.h> #include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/platform_data/itco_wdt.h> #if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ defined CONFIG_DMI #include <linux/gpio.h> #include <linux/i2c-mux-gpio.h> -#include <linux/platform_device.h> #endif /* I801 SMBus address offsets */ @@ -113,6 +118,16 @@ #define SMBPCICTL 0x004 #define SMBPCISTS 0x006 #define SMBHSTCFG 0x040 +#define TCOBASE 0x050 +#define TCOCTL 0x054 + +#define ACPIBASE 0x040 +#define ACPIBASE_SMI_OFF 0x030 +#define ACPICTRL 0x044 +#define ACPICTRL_EN 0x080 + +#define SBREG_BAR 0x10 +#define SBREG_SMBCTRL 0xc6000c /* Host status bits for SMBPCISTS */ #define SMBPCISTS_INTS 0x08 @@ -125,6 +140,9 @@ #define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_I2C_EN 4 +/* TCO configuration bits for TCOCTL */ +#define TCOCTL_EN 0x0100 + /* Auxiliary control register bits, ICH4+ only */ #define SMBAUXCTL_CRC 1 #define SMBAUXCTL_E32B 2 @@ -188,6 +206,10 @@ #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 +#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df +#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 +#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 struct i801_mux_config { char *gpio_chip; @@ -221,6 +243,7 @@ struct i801_priv { const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; #endif + struct platform_device *tco_pdev; }; #define FEATURE_SMBUS_PEC (1 << 0) @@ -230,6 +253,7 @@ struct i801_priv { #define FEATURE_IRQ (1 << 4) /* Not really a feature, but it's convenient to handle it as such */ #define FEATURE_IDF (1 << 15) +#define FEATURE_TCO (1 << 16) static const char *i801_feature_names[] = { "SMBus PEC", @@ -847,6 +871,10 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, { 0, } }; @@ -1132,6 +1160,95 @@ static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) } #endif +static const struct itco_wdt_platform_data tco_platform_data = { + .name = "Intel PCH", + .version = 4, +}; + +static DEFINE_SPINLOCK(p2sb_spinlock); + +static void i801_add_tco(struct i801_priv *priv) +{ + struct pci_dev *pci_dev = priv->pci_dev; + struct resource tco_res[3], *res; + struct platform_device *pdev; + unsigned int devfn; + u32 tco_base, tco_ctl; + u32 base_addr, ctrl_val; + u64 base64_addr; + + if (!(priv->features & FEATURE_TCO)) + return; + + pci_read_config_dword(pci_dev, TCOBASE, &tco_base); + pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl); + if (!(tco_ctl & TCOCTL_EN)) + return; + + memset(tco_res, 0, sizeof(tco_res)); + + res = &tco_res[ICH_RES_IO_TCO]; + res->start = tco_base & ~1; + res->end = res->start + 32 - 1; + res->flags = IORESOURCE_IO; + + /* + * Power Management registers. + */ + devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2); + pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr); + + res = &tco_res[ICH_RES_IO_SMI]; + res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF; + res->end = res->start + 3; + res->flags = IORESOURCE_IO; + + /* + * Enable the ACPI I/O space. + */ + pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val); + ctrl_val |= ACPICTRL_EN; + pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val); + + /* + * We must access the NO_REBOOT bit over the Primary to Sideband + * bridge (P2SB). The BIOS prevents the P2SB device from being + * enumerated by the PCI subsystem, so we need to unhide/hide it + * to lookup the P2SB BAR. + */ + spin_lock(&p2sb_spinlock); + + devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); + + /* Unhide the P2SB device */ + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); + base64_addr = base_addr & 0xfffffff0; + + pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); + base64_addr |= (u64)base_addr << 32; + + /* Hide the P2SB device */ + pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x1); + spin_unlock(&p2sb_spinlock); + + res = &tco_res[ICH_RES_MEM_OFF]; + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + res->end = res->start + 3; + res->flags = IORESOURCE_MEM; + + pdev = platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, + tco_res, 3, &tco_platform_data, + sizeof(tco_platform_data)); + if (IS_ERR(pdev)) { + dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); + return; + } + + priv->tco_pdev = pdev; +} + static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { unsigned char temp; @@ -1146,9 +1263,24 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->adapter.owner = THIS_MODULE; priv->adapter.class = i801_get_adapter_class(priv); priv->adapter.algo = &smbus_algorithm; + priv->adapter.dev.parent = &dev->dev; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); + priv->adapter.retries = 3; priv->pci_dev = dev; switch (dev->device) { + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: + case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: + case PCI_DEVICE_ID_INTEL_DNV_SMBUS: + priv->features |= FEATURE_I2C_BLOCK_READ; + priv->features |= FEATURE_IRQ; + priv->features |= FEATURE_SMBUS_PEC; + priv->features |= FEATURE_BLOCK_BUFFER; + priv->features |= FEATURE_TCO; + break; + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: @@ -1265,11 +1397,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) dev_info(&dev->dev, "SMBus using %s\n", priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); - /* set up the sysfs linkage to our parent device */ - priv->adapter.dev.parent = &dev->dev; - - /* Retry up to 3 times on lost arbitration */ - priv->adapter.retries = 3; + i801_add_tco(priv); snprintf(priv->adapter.name, sizeof(priv->adapter.name), "SMBus I801 adapter at %04lx", priv->smba); @@ -1296,6 +1424,8 @@ static void i801_remove(struct pci_dev *dev) i2c_del_adapter(&priv->adapter); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + platform_device_unregister(priv->tco_pdev); + /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) diff --git a/kernel/drivers/i2c/busses/i2c-ibm_iic.c b/kernel/drivers/i2c/busses/i2c-ibm_iic.c index 722f839cf..ab4923015 100644 --- a/kernel/drivers/i2c/busses/i2c-ibm_iic.c +++ b/kernel/drivers/i2c/busses/i2c-ibm_iic.c @@ -798,6 +798,7 @@ static const struct of_device_id ibm_iic_match[] = { { .compatible = "ibm,iic", }, {} }; +MODULE_DEVICE_TABLE(of, ibm_iic_match); static struct platform_driver ibm_iic_driver = { .driver = { diff --git a/kernel/drivers/i2c/busses/i2c-img-scb.c b/kernel/drivers/i2c/busses/i2c-img-scb.c index 00ffd6613..3795fe130 100644 --- a/kernel/drivers/i2c/busses/i2c-img-scb.c +++ b/kernel/drivers/i2c/busses/i2c-img-scb.c @@ -278,8 +278,6 @@ #define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) #define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) -#define REL_SOC_IP_SCB_2_2_1 0x00020201 - enum img_i2c_mode { MODE_INACTIVE, MODE_RAW, @@ -536,6 +534,7 @@ static void img_i2c_read_fifo(struct img_i2c *i2c) u32 fifo_status; u8 data; + img_i2c_wr_rd_fence(i2c); fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG); if (fifo_status & FIFO_READ_EMPTY) break; @@ -544,7 +543,6 @@ static void img_i2c_read_fifo(struct img_i2c *i2c) *i2c->msg.buf = data; img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff); - img_i2c_wr_rd_fence(i2c); i2c->msg.len--; i2c->msg.buf++; } @@ -556,12 +554,12 @@ static void img_i2c_write_fifo(struct img_i2c *i2c) while (i2c->msg.len) { u32 fifo_status; + img_i2c_wr_rd_fence(i2c); fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG); if (fifo_status & FIFO_WRITE_FULL) break; img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf); - img_i2c_wr_rd_fence(i2c); i2c->msg.len--; i2c->msg.buf++; } @@ -859,7 +857,7 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c, } /* Enable transaction halt on start bit */ - if (!i2c->last_msg && i2c->line_status & LINESTAT_START_BIT_DET) { + if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) { img_i2c_transaction_halt(i2c, true); /* we're no longer interested in the slave event */ i2c->int_enable &= ~INT_SLAVE_EVENT; @@ -1062,6 +1060,15 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, i2c->last_msg = (i == num - 1); reinit_completion(&i2c->msg_complete); + /* + * Clear line status and all interrupts before starting a + * transfer, as we may have unserviced interrupts from + * previous transfers that might be handled in the context + * of the new transfer. + */ + img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0); + img_i2c_writel(i2c, SCB_CLEAR_REG, ~0); + if (atomic) img_i2c_atomic_start(i2c); else if (msg->flags & I2C_M_RD) @@ -1120,13 +1127,8 @@ static int img_i2c_init(struct img_i2c *i2c) return -EINVAL; } - if (rev == REL_SOC_IP_SCB_2_2_1) { - i2c->need_wr_rd_fence = true; - dev_info(i2c->adap.dev.parent, "fence quirk enabled"); - } - - bitrate_khz = i2c->bitrate / 1000; - clk_khz = clk_get_rate(i2c->scb_clk) / 1000; + /* Fencing enabled by default. */ + i2c->need_wr_rd_fence = true; /* Determine what mode we're in from the bitrate */ timing = timings[0]; @@ -1136,6 +1138,17 @@ static int img_i2c_init(struct img_i2c *i2c) break; } } + if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) { + dev_warn(i2c->adap.dev.parent, + "requested bitrate (%u) is higher than the max bitrate supported (%u)\n", + i2c->bitrate, + timings[ARRAY_SIZE(timings) - 1].max_bitrate); + timing = timings[ARRAY_SIZE(timings) - 1]; + i2c->bitrate = timing.max_bitrate; + } + + bitrate_khz = i2c->bitrate / 1000; + clk_khz = clk_get_rate(i2c->scb_clk) / 1000; /* Find the prescale that would give us that inc (approx delay = 0) */ prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz); @@ -1182,32 +1195,32 @@ static int img_i2c_init(struct img_i2c *i2c) ((bitrate_khz * clk_period) / 2)) int_bitrate++; - /* Setup TCKH value */ - tckh = timing.tckh / clk_period; - if (timing.tckh % clk_period) - tckh++; + /* + * Setup clock duty cycle, start with 50% and adjust TCKH and TCKL + * values from there if they don't meet minimum timing requirements + */ + tckh = int_bitrate / 2; + tckl = int_bitrate - tckh; - if (tckh > 0) - data = tckh - 1; - else - data = 0; + /* Adjust TCKH and TCKL values */ + data = DIV_ROUND_UP(timing.tckl, clk_period); - img_i2c_writel(i2c, SCB_TIME_TCKH_REG, data); + if (tckl < data) { + tckl = data; + tckh = int_bitrate - tckl; + } - /* Setup TCKL value */ - tckl = int_bitrate - tckh; + if (tckh > 0) + --tckh; if (tckl > 0) - data = tckl - 1; - else - data = 0; + --tckl; - img_i2c_writel(i2c, SCB_TIME_TCKL_REG, data); + img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh); + img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl); /* Setup TSDH value */ - tsdh = timing.tsdh / clk_period; - if (timing.tsdh % clk_period) - tsdh++; + tsdh = DIV_ROUND_UP(timing.tsdh, clk_period); if (tsdh > 1) data = tsdh - 1; diff --git a/kernel/drivers/i2c/busses/i2c-imx.c b/kernel/drivers/i2c/busses/i2c-imx.c index a53a7dd66..d4d853680 100644 --- a/kernel/drivers/i2c/busses/i2c-imx.c +++ b/kernel/drivers/i2c/busses/i2c-imx.c @@ -49,6 +49,8 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_dma.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_data/i2c-imx.h> #include <linux/platform_device.h> #include <linux/sched.h> @@ -207,6 +209,11 @@ struct imx_i2c_struct { unsigned int cur_clk; unsigned int bitrate; const struct imx_i2c_hwdata *hwdata; + struct i2c_bus_recovery_info rinfo; + + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_pins_default; + struct pinctrl_state *pinctrl_pins_gpio; struct imx_i2c_dma *dma; }; @@ -241,7 +248,7 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = { }; -static struct platform_device_id imx_i2c_devtype[] = { +static const struct platform_device_id imx_i2c_devtype[] = { { .name = "imx1-i2c", .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata, @@ -461,7 +468,7 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) { if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) { dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__); - return -EIO; /* No ACK */ + return -ENXIO; /* No ACK */ } dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__); @@ -896,6 +903,13 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, /* Start I2C transfer */ result = i2c_imx_start(i2c_imx); + if (result) { + if (i2c_imx->adapter.bus_recovery_info) { + i2c_recover_bus(&i2c_imx->adapter); + result = i2c_imx_start(i2c_imx); + } + } + if (result) goto fail0; @@ -956,6 +970,55 @@ fail0: return (result < 0) ? result : num; } +static void i2c_imx_prepare_recovery(struct i2c_adapter *adap) +{ + struct imx_i2c_struct *i2c_imx; + + i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); + + pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio); +} + +static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) +{ + struct imx_i2c_struct *i2c_imx; + + i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); + + pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); +} + +static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, + struct platform_device *pdev) +{ + struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo; + + i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl, + PINCTRL_STATE_DEFAULT); + i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, + "gpio"); + rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node, + "sda-gpios", 0, NULL); + rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node, + "scl-gpios", 0, NULL); + + if (!gpio_is_valid(rinfo->sda_gpio) || + !gpio_is_valid(rinfo->scl_gpio) || + IS_ERR(i2c_imx->pinctrl_pins_default) || + IS_ERR(i2c_imx->pinctrl_pins_gpio)) { + dev_dbg(&pdev->dev, "recovery information incomplete\n"); + return; + } + + dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", + rinfo->sda_gpio, rinfo->scl_gpio); + + rinfo->prepare_recovery = i2c_imx_prepare_recovery; + rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; + rinfo->recover_bus = i2c_generic_gpio_recovery; + i2c_imx->adapter.bus_recovery_info = rinfo; +} + static u32 i2c_imx_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL @@ -1023,6 +1086,13 @@ static int i2c_imx_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't enable I2C clock\n"); return ret; } + + i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(i2c_imx->pinctrl)) { + ret = PTR_ERR(i2c_imx->pinctrl); + goto clk_disable; + } + /* Request IRQ */ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, pdev->name, i2c_imx); @@ -1049,6 +1119,8 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); + i2c_imx_init_recovery_info(i2c_imx, pdev); + /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) { diff --git a/kernel/drivers/i2c/busses/i2c-ismt.c b/kernel/drivers/i2c/busses/i2c-ismt.c index f994712d0..7ba795b24 100644 --- a/kernel/drivers/i2c/busses/i2c-ismt.c +++ b/kernel/drivers/i2c/busses/i2c-ismt.c @@ -67,7 +67,7 @@ #include <linux/acpi.h> #include <linux/interrupt.h> -#include <asm-generic/io-64-nonatomic-lo-hi.h> +#include <linux/io-64-nonatomic-lo-hi.h> /* PCI Address Constants */ #define SMBBAR 0 @@ -165,14 +165,13 @@ struct ismt_desc { struct ismt_priv { struct i2c_adapter adapter; - void *smba; /* PCI BAR */ + void __iomem *smba; /* PCI BAR */ struct pci_dev *pci_dev; struct ismt_desc *hw; /* descriptor virt base addr */ dma_addr_t io_rng_dma; /* descriptor HW base addr */ u8 head; /* ring buffer head pointer */ struct completion cmp; /* interrupt completion */ u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */ - bool using_msi; /* type of interrupt flag */ }; /** @@ -398,7 +397,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); /* Initialize common control bits */ - if (likely(priv->using_msi)) + if (likely(pci_dev_msi_enabled(priv->pci_dev))) desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; else desc->control = ISMT_DESC_FAIR; @@ -789,11 +788,8 @@ static int ismt_int_init(struct ismt_priv *priv) /* Try using MSI interrupts */ err = pci_enable_msi(priv->pci_dev); - if (err) { - dev_warn(&priv->pci_dev->dev, - "Unable to use MSI interrupts, falling back to legacy\n"); + if (err) goto intx; - } err = devm_request_irq(&priv->pci_dev->dev, priv->pci_dev->irq, @@ -806,11 +802,13 @@ static int ismt_int_init(struct ismt_priv *priv) goto intx; } - priv->using_msi = true; - goto done; + return 0; /* Try using legacy interrupts */ intx: + dev_warn(&priv->pci_dev->dev, + "Unable to use MSI interrupts, falling back to legacy\n"); + err = devm_request_irq(&priv->pci_dev->dev, priv->pci_dev->irq, ismt_do_interrupt, @@ -819,12 +817,9 @@ intx: priv); if (err) { dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); - return -ENODEV; + return err; } - priv->using_msi = false; - -done: return 0; } @@ -847,17 +842,13 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; pci_set_drvdata(pdev, priv); + i2c_set_adapdata(&priv->adapter, priv); priv->adapter.owner = THIS_MODULE; - priv->adapter.class = I2C_CLASS_HWMON; - priv->adapter.algo = &smbus_algorithm; - - /* set up the sysfs linkage to our parent device */ priv->adapter.dev.parent = &pdev->dev; - - /* number of retries on lost arbitration */ + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); priv->adapter.retries = ISMT_MAX_RETRIES; priv->pci_dev = pdev; @@ -904,8 +895,7 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) priv->smba = pcim_iomap(pdev, SMBBAR, len); if (!priv->smba) { dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); - err = -ENODEV; - goto fail; + return -ENODEV; } if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || @@ -915,32 +905,26 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) DMA_BIT_MASK(32)) != 0)) { dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", pdev); - err = -ENODEV; - goto fail; + return -ENODEV; } } err = ismt_dev_init(priv); if (err) - goto fail; + return err; ismt_hw_init(priv); err = ismt_int_init(priv); if (err) - goto fail; + return err; err = i2c_add_adapter(&priv->adapter); if (err) { dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n"); - err = -ENODEV; - goto fail; + return -ENODEV; } return 0; - -fail: - pci_release_region(pdev, SMBBAR); - return err; } /** @@ -952,47 +936,13 @@ static void ismt_remove(struct pci_dev *pdev) struct ismt_priv *priv = pci_get_drvdata(pdev); i2c_del_adapter(&priv->adapter); - pci_release_region(pdev, SMBBAR); } -/** - * ismt_suspend() - place the device in suspend - * @pdev: PCI-Express device - * @mesg: PM message - */ -#ifdef CONFIG_PM -static int ismt_suspend(struct pci_dev *pdev, pm_message_t mesg) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, mesg)); - return 0; -} - -/** - * ismt_resume() - PCI resume code - * @pdev: PCI-Express device - */ -static int ismt_resume(struct pci_dev *pdev) -{ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - return pci_enable_device(pdev); -} - -#else - -#define ismt_suspend NULL -#define ismt_resume NULL - -#endif - static struct pci_driver ismt_driver = { .name = "ismt_smbus", .id_table = ismt_ids, .probe = ismt_probe, .remove = ismt_remove, - .suspend = ismt_suspend, - .resume = ismt_resume, }; module_pci_driver(ismt_driver); diff --git a/kernel/drivers/i2c/busses/i2c-jz4780.c b/kernel/drivers/i2c/busses/i2c-jz4780.c index 19b2d689a..f325663c2 100644 --- a/kernel/drivers/i2c/busses/i2c-jz4780.c +++ b/kernel/drivers/i2c/busses/i2c-jz4780.c @@ -764,12 +764,15 @@ static int jz4780_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) return PTR_ERR(i2c->clk); - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return ret; - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &clk_freq)) { + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &clk_freq); + if (ret) { dev_err(&pdev->dev, "clock-frequency not specified in DT"); - return clk_freq; + goto err; } i2c->speed = clk_freq / 1000; @@ -790,10 +793,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev) i2c->irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, dev_name(&pdev->dev), i2c); - if (ret) { - ret = -ENODEV; + if (ret) goto err; - } ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { diff --git a/kernel/drivers/i2c/busses/i2c-lpc2k.c b/kernel/drivers/i2c/busses/i2c-lpc2k.c new file mode 100644 index 000000000..8560a13bf --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-lpc2k.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2011 NXP Semiconductors + * + * Code portions referenced from the i2x-pxa and i2c-pnx drivers + * + * Make SMBus byte and word transactions work on LPC178x/7x + * Copyright (c) 2012 + * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com + * Anton Protopopov, Emcraft Systems, antonp@emcraft.com + * + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.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. + * + */ + +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/time.h> + +/* LPC24xx register offsets and bits */ +#define LPC24XX_I2CONSET 0x00 +#define LPC24XX_I2STAT 0x04 +#define LPC24XX_I2DAT 0x08 +#define LPC24XX_I2ADDR 0x0c +#define LPC24XX_I2SCLH 0x10 +#define LPC24XX_I2SCLL 0x14 +#define LPC24XX_I2CONCLR 0x18 + +#define LPC24XX_AA BIT(2) +#define LPC24XX_SI BIT(3) +#define LPC24XX_STO BIT(4) +#define LPC24XX_STA BIT(5) +#define LPC24XX_I2EN BIT(6) + +#define LPC24XX_STO_AA (LPC24XX_STO | LPC24XX_AA) +#define LPC24XX_CLEAR_ALL (LPC24XX_AA | LPC24XX_SI | LPC24XX_STO | \ + LPC24XX_STA | LPC24XX_I2EN) + +/* I2C SCL clock has different duty cycle depending on mode */ +#define I2C_STD_MODE_DUTY 46 +#define I2C_FAST_MODE_DUTY 36 +#define I2C_FAST_MODE_PLUS_DUTY 38 + +/* + * 26 possible I2C status codes, but codes applicable only + * to master are listed here and used in this driver + */ +enum { + M_BUS_ERROR = 0x00, + M_START = 0x08, + M_REPSTART = 0x10, + MX_ADDR_W_ACK = 0x18, + MX_ADDR_W_NACK = 0x20, + MX_DATA_W_ACK = 0x28, + MX_DATA_W_NACK = 0x30, + M_DATA_ARB_LOST = 0x38, + MR_ADDR_R_ACK = 0x40, + MR_ADDR_R_NACK = 0x48, + MR_DATA_R_ACK = 0x50, + MR_DATA_R_NACK = 0x58, + M_I2C_IDLE = 0xf8, +}; + +struct lpc2k_i2c { + void __iomem *base; + struct clk *clk; + int irq; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int msg_idx; + int msg_status; + int is_last; +}; + +static void i2c_lpc2k_reset(struct lpc2k_i2c *i2c) +{ + /* Will force clear all statuses */ + writel(LPC24XX_CLEAR_ALL, i2c->base + LPC24XX_I2CONCLR); + writel(0, i2c->base + LPC24XX_I2ADDR); + writel(LPC24XX_I2EN, i2c->base + LPC24XX_I2CONSET); +} + +static int i2c_lpc2k_clear_arb(struct lpc2k_i2c *i2c) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + /* + * If the transfer needs to abort for some reason, we'll try to + * force a stop condition to clear any pending bus conditions + */ + writel(LPC24XX_STO, i2c->base + LPC24XX_I2CONSET); + + /* Wait for status change */ + while (readl(i2c->base + LPC24XX_I2STAT) != M_I2C_IDLE) { + if (time_after(jiffies, timeout)) { + /* Bus was not idle, try to reset adapter */ + i2c_lpc2k_reset(i2c); + return -EBUSY; + } + + cpu_relax(); + } + + return 0; +} + +static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) +{ + unsigned char data; + u32 status; + + /* + * I2C in the LPC2xxx series is basically a state machine. + * Just run through the steps based on the current status. + */ + status = readl(i2c->base + LPC24XX_I2STAT); + + switch (status) { + case M_START: + case M_REPSTART: + /* Start bit was just sent out, send out addr and dir */ + data = i2c->msg->addr << 1; + if (i2c->msg->flags & I2C_M_RD) + data |= 1; + + writel(data, i2c->base + LPC24XX_I2DAT); + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + break; + + case MX_ADDR_W_ACK: + case MX_DATA_W_ACK: + /* + * Address or data was sent out with an ACK. If there is more + * data to send, send it now + */ + if (i2c->msg_idx < i2c->msg->len) { + writel(i2c->msg->buf[i2c->msg_idx], + i2c->base + LPC24XX_I2DAT); + } else if (i2c->is_last) { + /* Last message, send stop */ + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } else { + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } + + i2c->msg_idx++; + break; + + case MR_ADDR_R_ACK: + /* Receive first byte from slave */ + if (i2c->msg->len == 1) { + /* Last byte, return NACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); + } else { + /* Not last byte, return ACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + break; + + case MR_DATA_R_NACK: + /* + * The I2C shows NACK status on reads, so we need to accept + * the NACK as an ACK here. This should be ok, as the real + * BACK would of been caught on the address write. + */ + case MR_DATA_R_ACK: + /* Data was received */ + if (i2c->msg_idx < i2c->msg->len) { + i2c->msg->buf[i2c->msg_idx] = + readl(i2c->base + LPC24XX_I2DAT); + } + + /* If transfer is done, send STOP */ + if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) { + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_status = 0; + } + + /* Message is done */ + if (i2c->msg_idx >= i2c->msg->len - 1) { + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } + + /* + * One pre-last data input, send NACK to tell the slave that + * this is going to be the last data byte to be transferred. + */ + if (i2c->msg_idx >= i2c->msg->len - 2) { + /* One byte left to receive - NACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); + } else { + /* More than one byte left to receive - ACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_idx++; + break; + + case MX_ADDR_W_NACK: + case MX_DATA_W_NACK: + case MR_ADDR_R_NACK: + /* NACK processing is done */ + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + i2c->msg_status = -ENXIO; + disable_irq_nosync(i2c->irq); + break; + + case M_DATA_ARB_LOST: + /* Arbitration lost */ + i2c->msg_status = -EAGAIN; + + /* Release the I2C bus */ + writel(LPC24XX_STA | LPC24XX_STO, i2c->base + LPC24XX_I2CONCLR); + disable_irq_nosync(i2c->irq); + break; + + default: + /* Unexpected statuses */ + i2c->msg_status = -EIO; + disable_irq_nosync(i2c->irq); + break; + } + + /* Exit on failure or all bytes transferred */ + if (i2c->msg_status != -EBUSY) + wake_up(&i2c->wait); + + /* + * If `msg_status` is zero, then `lpc2k_process_msg()` + * is responsible for clearing the SI flag. + */ + if (i2c->msg_status != 0) + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); +} + +static int lpc2k_process_msg(struct lpc2k_i2c *i2c, int msgidx) +{ + /* A new transfer is kicked off by initiating a start condition */ + if (!msgidx) { + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); + } else { + /* + * A multi-message I2C transfer continues where the + * previous I2C transfer left off and uses the + * current condition of the I2C adapter. + */ + if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) { + WARN_ON(i2c->msg->len == 0); + + if (!(i2c->msg->flags & I2C_M_RD)) { + /* Start transmit of data */ + writel(i2c->msg->buf[0], + i2c->base + LPC24XX_I2DAT); + i2c->msg_idx++; + } + } else { + /* Start or repeated start */ + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + } + + enable_irq(i2c->irq); + + /* Wait for transfer completion */ + if (wait_event_timeout(i2c->wait, i2c->msg_status != -EBUSY, + msecs_to_jiffies(1000)) == 0) { + disable_irq_nosync(i2c->irq); + + return -ETIMEDOUT; + } + + return i2c->msg_status; +} + +static int i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int msg_num) +{ + struct lpc2k_i2c *i2c = i2c_get_adapdata(adap); + int ret, i; + u32 stat; + + /* Check for bus idle condition */ + stat = readl(i2c->base + LPC24XX_I2STAT); + if (stat != M_I2C_IDLE) { + /* Something is holding the bus, try to clear it */ + return i2c_lpc2k_clear_arb(i2c); + } + + /* Process a single message at a time */ + for (i = 0; i < msg_num; i++) { + /* Save message pointer and current message data index */ + i2c->msg = &msgs[i]; + i2c->msg_idx = 0; + i2c->msg_status = -EBUSY; + i2c->is_last = (i == (msg_num - 1)); + + ret = lpc2k_process_msg(i2c, i); + if (ret) + return ret; + } + + return msg_num; +} + +static irqreturn_t i2c_lpc2k_handler(int irq, void *dev_id) +{ + struct lpc2k_i2c *i2c = dev_id; + + if (readl(i2c->base + LPC24XX_I2CONSET) & LPC24XX_SI) { + i2c_lpc2k_pump_msg(i2c); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static u32 i2c_lpc2k_functionality(struct i2c_adapter *adap) +{ + /* Only emulated SMBus for now */ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm i2c_lpc2k_algorithm = { + .master_xfer = i2c_lpc2k_xfer, + .functionality = i2c_lpc2k_functionality, +}; + +static int i2c_lpc2k_probe(struct platform_device *pdev) +{ + struct lpc2k_i2c *i2c; + struct resource *res; + u32 bus_clk_rate; + u32 scl_high; + u32 clkrate; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) { + dev_err(&pdev->dev, "can't get interrupt resource\n"); + return i2c->irq; + } + + init_waitqueue_head(&i2c->wait); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "error getting clock\n"); + return PTR_ERR(i2c->clk); + } + + ret = clk_prepare_enable(i2c->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable clock.\n"); + return ret; + } + + ret = devm_request_irq(&pdev->dev, i2c->irq, i2c_lpc2k_handler, 0, + dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "can't request interrupt.\n"); + goto fail_clk; + } + + disable_irq_nosync(i2c->irq); + + /* Place controller is a known state */ + i2c_lpc2k_reset(i2c); + + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &bus_clk_rate); + if (ret) + bus_clk_rate = 100000; /* 100 kHz default clock rate */ + + clkrate = clk_get_rate(i2c->clk); + if (clkrate == 0) { + dev_err(&pdev->dev, "can't get I2C base clock\n"); + ret = -EINVAL; + goto fail_clk; + } + + /* Setup I2C dividers to generate clock with proper duty cycle */ + clkrate = clkrate / bus_clk_rate; + if (bus_clk_rate <= 100000) + scl_high = (clkrate * I2C_STD_MODE_DUTY) / 100; + else if (bus_clk_rate <= 400000) + scl_high = (clkrate * I2C_FAST_MODE_DUTY) / 100; + else + scl_high = (clkrate * I2C_FAST_MODE_PLUS_DUTY) / 100; + + writel(scl_high, i2c->base + LPC24XX_I2SCLH); + writel(clkrate - scl_high, i2c->base + LPC24XX_I2SCLL); + + platform_set_drvdata(pdev, i2c); + + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.owner = THIS_MODULE; + strlcpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name)); + i2c->adap.algo = &i2c_lpc2k_algorithm; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add adapter!\n"); + goto fail_clk; + } + + dev_info(&pdev->dev, "LPC2K I2C adapter\n"); + + return 0; + +fail_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int i2c_lpc2k_remove(struct platform_device *dev) +{ + struct lpc2k_i2c *i2c = platform_get_drvdata(dev); + + i2c_del_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM +static int i2c_lpc2k_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc2k_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable(i2c->clk); + + return 0; +} + +static int i2c_lpc2k_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc2k_i2c *i2c = platform_get_drvdata(pdev); + + clk_enable(i2c->clk); + i2c_lpc2k_reset(i2c); + + return 0; +} + +static const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = { + .suspend_noirq = i2c_lpc2k_suspend, + .resume_noirq = i2c_lpc2k_resume, +}; + +#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops) +#else +#define I2C_LPC2K_DEV_PM_OPS NULL +#endif + +static const struct of_device_id lpc2k_i2c_match[] = { + { .compatible = "nxp,lpc1788-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc2k_i2c_match); + +static struct platform_driver i2c_lpc2k_driver = { + .probe = i2c_lpc2k_probe, + .remove = i2c_lpc2k_remove, + .driver = { + .name = "lpc2k-i2c", + .pm = I2C_LPC2K_DEV_PM_OPS, + .of_match_table = lpc2k_i2c_match, + }, +}; +module_platform_driver(i2c_lpc2k_driver); + +MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); +MODULE_DESCRIPTION("I2C driver for LPC2xxx devices"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lpc2k-i2c"); diff --git a/kernel/drivers/i2c/busses/i2c-meson.c b/kernel/drivers/i2c/busses/i2c-meson.c index 5e176adca..71d3929ad 100644 --- a/kernel/drivers/i2c/busses/i2c-meson.c +++ b/kernel/drivers/i2c/busses/i2c-meson.c @@ -475,6 +475,7 @@ static const struct of_device_id meson_i2c_match[] = { { .compatible = "amlogic,meson6-i2c" }, { }, }; +MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { .probe = meson_i2c_probe, diff --git a/kernel/drivers/i2c/busses/i2c-mt65xx.c b/kernel/drivers/i2c/busses/i2c-mt65xx.c new file mode 100644 index 000000000..9b8671691 --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-mt65xx.c @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Xudong Chen <xudong.chen@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <linux/sched.h> +#include <linux/slab.h> + +#define I2C_RS_TRANSFER (1 << 4) +#define I2C_HS_NACKERR (1 << 2) +#define I2C_ACKERR (1 << 1) +#define I2C_TRANSAC_COMP (1 << 0) +#define I2C_TRANSAC_START (1 << 0) +#define I2C_RS_MUL_CNFG (1 << 15) +#define I2C_RS_MUL_TRIG (1 << 14) +#define I2C_DCM_DISABLE 0x0000 +#define I2C_IO_CONFIG_OPEN_DRAIN 0x0003 +#define I2C_IO_CONFIG_PUSH_PULL 0x0000 +#define I2C_SOFT_RST 0x0001 +#define I2C_FIFO_ADDR_CLR 0x0001 +#define I2C_DELAY_LEN 0x0002 +#define I2C_ST_START_CON 0x8001 +#define I2C_FS_START_CON 0x1800 +#define I2C_TIME_CLR_VALUE 0x0000 +#define I2C_TIME_DEFAULT_VALUE 0x0003 +#define I2C_FS_TIME_INIT_VALUE 0x1303 +#define I2C_WRRD_TRANAC_VALUE 0x0002 +#define I2C_RD_TRANAC_VALUE 0x0001 + +#define I2C_DMA_CON_TX 0x0000 +#define I2C_DMA_CON_RX 0x0001 +#define I2C_DMA_START_EN 0x0001 +#define I2C_DMA_INT_FLAG_NONE 0x0000 +#define I2C_DMA_CLR_FLAG 0x0000 +#define I2C_DMA_HARD_RST 0x0002 + +#define I2C_DEFAULT_SPEED 100000 /* hz */ +#define MAX_FS_MODE_SPEED 400000 +#define MAX_HS_MODE_SPEED 3400000 +#define MAX_SAMPLE_CNT_DIV 8 +#define MAX_STEP_CNT_DIV 64 +#define MAX_HS_STEP_CNT_DIV 8 + +#define I2C_CONTROL_RS (0x1 << 1) +#define I2C_CONTROL_DMA_EN (0x1 << 2) +#define I2C_CONTROL_CLK_EXT_EN (0x1 << 3) +#define I2C_CONTROL_DIR_CHANGE (0x1 << 4) +#define I2C_CONTROL_ACKERR_DET_EN (0x1 << 5) +#define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6) +#define I2C_CONTROL_WRAPPER (0x1 << 0) + +#define I2C_DRV_NAME "i2c-mt65xx" + +enum DMA_REGS_OFFSET { + OFFSET_INT_FLAG = 0x0, + OFFSET_INT_EN = 0x04, + OFFSET_EN = 0x08, + OFFSET_RST = 0x0c, + OFFSET_CON = 0x18, + OFFSET_TX_MEM_ADDR = 0x1c, + OFFSET_RX_MEM_ADDR = 0x20, + OFFSET_TX_LEN = 0x24, + OFFSET_RX_LEN = 0x28, +}; + +enum i2c_trans_st_rs { + I2C_TRANS_STOP = 0, + I2C_TRANS_REPEATED_START, +}; + +enum mtk_trans_op { + I2C_MASTER_WR = 1, + I2C_MASTER_RD, + I2C_MASTER_WRRD, +}; + +enum I2C_REGS_OFFSET { + OFFSET_DATA_PORT = 0x0, + OFFSET_SLAVE_ADDR = 0x04, + OFFSET_INTR_MASK = 0x08, + OFFSET_INTR_STAT = 0x0c, + OFFSET_CONTROL = 0x10, + OFFSET_TRANSFER_LEN = 0x14, + OFFSET_TRANSAC_LEN = 0x18, + OFFSET_DELAY_LEN = 0x1c, + OFFSET_TIMING = 0x20, + OFFSET_START = 0x24, + OFFSET_EXT_CONF = 0x28, + OFFSET_FIFO_STAT = 0x30, + OFFSET_FIFO_THRESH = 0x34, + OFFSET_FIFO_ADDR_CLR = 0x38, + OFFSET_IO_CONFIG = 0x40, + OFFSET_RSV_DEBUG = 0x44, + OFFSET_HS = 0x48, + OFFSET_SOFTRESET = 0x50, + OFFSET_DCM_EN = 0x54, + OFFSET_PATH_DIR = 0x60, + OFFSET_DEBUGSTAT = 0x64, + OFFSET_DEBUGCTRL = 0x68, + OFFSET_TRANSFER_LEN_AUX = 0x6c, +}; + +struct mtk_i2c_compatible { + const struct i2c_adapter_quirks *quirks; + unsigned char pmic_i2c: 1; + unsigned char dcm: 1; + unsigned char auto_restart: 1; +}; + +struct mtk_i2c { + struct i2c_adapter adap; /* i2c host adapter */ + struct device *dev; + struct completion msg_complete; + + /* set in i2c probe */ + void __iomem *base; /* i2c base addr */ + void __iomem *pdmabase; /* dma base address*/ + struct clk *clk_main; /* main clock for i2c bus */ + struct clk *clk_dma; /* DMA clock for i2c via DMA */ + struct clk *clk_pmic; /* PMIC clock for i2c from PMIC */ + bool have_pmic; /* can use i2c pins from PMIC */ + bool use_push_pull; /* IO config push-pull mode */ + + u16 irq_stat; /* interrupt status */ + unsigned int speed_hz; /* The speed in transfer */ + enum mtk_trans_op op; + u16 timing_reg; + u16 high_speed_reg; + const struct mtk_i2c_compatible *dev_comp; +}; + +static const struct i2c_adapter_quirks mt6577_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_num_msgs = 1, + .max_write_len = 255, + .max_read_len = 255, + .max_comb_1st_msg_len = 255, + .max_comb_2nd_msg_len = 31, +}; + +static const struct i2c_adapter_quirks mt8173_i2c_quirks = { + .max_num_msgs = 65535, + .max_write_len = 65535, + .max_read_len = 65535, + .max_comb_1st_msg_len = 65535, + .max_comb_2nd_msg_len = 65535, +}; + +static const struct mtk_i2c_compatible mt6577_compat = { + .quirks = &mt6577_i2c_quirks, + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 0, +}; + +static const struct mtk_i2c_compatible mt6589_compat = { + .quirks = &mt6577_i2c_quirks, + .pmic_i2c = 1, + .dcm = 0, + .auto_restart = 0, +}; + +static const struct mtk_i2c_compatible mt8173_compat = { + .quirks = &mt8173_i2c_quirks, + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 1, +}; + +static const struct of_device_id mtk_i2c_of_match[] = { + { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, + { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, + { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat }, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_i2c_of_match); + +static int mtk_i2c_clock_enable(struct mtk_i2c *i2c) +{ + int ret; + + ret = clk_prepare_enable(i2c->clk_dma); + if (ret) + return ret; + + ret = clk_prepare_enable(i2c->clk_main); + if (ret) + goto err_main; + + if (i2c->have_pmic) { + ret = clk_prepare_enable(i2c->clk_pmic); + if (ret) + goto err_pmic; + } + return 0; + +err_pmic: + clk_disable_unprepare(i2c->clk_main); +err_main: + clk_disable_unprepare(i2c->clk_dma); + + return ret; +} + +static void mtk_i2c_clock_disable(struct mtk_i2c *i2c) +{ + if (i2c->have_pmic) + clk_disable_unprepare(i2c->clk_pmic); + + clk_disable_unprepare(i2c->clk_main); + clk_disable_unprepare(i2c->clk_dma); +} + +static void mtk_i2c_init_hw(struct mtk_i2c *i2c) +{ + u16 control_reg; + + writew(I2C_SOFT_RST, i2c->base + OFFSET_SOFTRESET); + + /* Set ioconfig */ + if (i2c->use_push_pull) + writew(I2C_IO_CONFIG_PUSH_PULL, i2c->base + OFFSET_IO_CONFIG); + else + writew(I2C_IO_CONFIG_OPEN_DRAIN, i2c->base + OFFSET_IO_CONFIG); + + if (i2c->dev_comp->dcm) + writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN); + + writew(i2c->timing_reg, i2c->base + OFFSET_TIMING); + writew(i2c->high_speed_reg, i2c->base + OFFSET_HS); + + /* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */ + if (i2c->have_pmic) + writew(I2C_CONTROL_WRAPPER, i2c->base + OFFSET_PATH_DIR); + + control_reg = I2C_CONTROL_ACKERR_DET_EN | + I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN; + writew(control_reg, i2c->base + OFFSET_CONTROL); + writew(I2C_DELAY_LEN, i2c->base + OFFSET_DELAY_LEN); + + writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST); + udelay(50); + writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST); +} + +/* + * Calculate i2c port speed + * + * Hardware design: + * i2c_bus_freq = parent_clk / (clock_div * 2 * sample_cnt * step_cnt) + * clock_div: fixed in hardware, but may be various in different SoCs + * + * The calculation want to pick the highest bus frequency that is still + * less than or equal to i2c->speed_hz. The calculation try to get + * sample_cnt and step_cn + */ +static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk, + unsigned int clock_div) +{ + unsigned int clk_src; + unsigned int step_cnt; + unsigned int sample_cnt; + unsigned int max_step_cnt; + unsigned int target_speed; + unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV; + unsigned int base_step_cnt; + unsigned int opt_div; + unsigned int best_mul; + unsigned int cnt_mul; + + clk_src = parent_clk / clock_div; + target_speed = i2c->speed_hz; + + if (target_speed > MAX_HS_MODE_SPEED) + target_speed = MAX_HS_MODE_SPEED; + + if (target_speed > MAX_FS_MODE_SPEED) + max_step_cnt = MAX_HS_STEP_CNT_DIV; + else + max_step_cnt = MAX_STEP_CNT_DIV; + + base_step_cnt = max_step_cnt; + /* Find the best combination */ + opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed); + best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt; + + /* Search for the best pair (sample_cnt, step_cnt) with + * 0 < sample_cnt < MAX_SAMPLE_CNT_DIV + * 0 < step_cnt < max_step_cnt + * sample_cnt * step_cnt >= opt_div + * optimizing for sample_cnt * step_cnt being minimal + */ + for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) { + step_cnt = DIV_ROUND_UP(opt_div, sample_cnt); + cnt_mul = step_cnt * sample_cnt; + if (step_cnt > max_step_cnt) + continue; + + if (cnt_mul < best_mul) { + best_mul = cnt_mul; + base_sample_cnt = sample_cnt; + base_step_cnt = step_cnt; + if (best_mul == opt_div) + break; + } + } + + sample_cnt = base_sample_cnt; + step_cnt = base_step_cnt; + + if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) { + /* In this case, hardware can't support such + * low i2c_bus_freq + */ + dev_dbg(i2c->dev, "Unsupported speed (%uhz)\n", target_speed); + return -EINVAL; + } + + step_cnt--; + sample_cnt--; + + if (target_speed > MAX_FS_MODE_SPEED) { + /* Set the high speed mode register */ + i2c->timing_reg = I2C_FS_TIME_INIT_VALUE; + i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE | + (sample_cnt << 12) | (step_cnt << 8); + } else { + i2c->timing_reg = (sample_cnt << 8) | (step_cnt << 0); + /* Disable the high speed transaction */ + i2c->high_speed_reg = I2C_TIME_CLR_VALUE; + } + + return 0; +} + +static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, + int num, int left_num) +{ + u16 addr_reg; + u16 start_reg; + u16 control_reg; + u16 restart_flag = 0; + dma_addr_t rpaddr = 0; + dma_addr_t wpaddr = 0; + int ret; + + i2c->irq_stat = 0; + + if (i2c->dev_comp->auto_restart) + restart_flag = I2C_RS_TRANSFER; + + reinit_completion(&i2c->msg_complete); + + control_reg = readw(i2c->base + OFFSET_CONTROL) & + ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS); + if ((i2c->speed_hz > 400000) || (left_num >= 1)) + control_reg |= I2C_CONTROL_RS; + + if (i2c->op == I2C_MASTER_WRRD) + control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS; + + writew(control_reg, i2c->base + OFFSET_CONTROL); + + /* set start condition */ + if (i2c->speed_hz <= 100000) + writew(I2C_ST_START_CON, i2c->base + OFFSET_EXT_CONF); + else + writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF); + + addr_reg = msgs->addr << 1; + if (i2c->op == I2C_MASTER_RD) + addr_reg |= 0x1; + + writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR); + + /* Clear interrupt status */ + writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR | + I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_STAT); + writew(I2C_FIFO_ADDR_CLR, i2c->base + OFFSET_FIFO_ADDR_CLR); + + /* Enable interrupt */ + writew(restart_flag | I2C_HS_NACKERR | I2C_ACKERR | + I2C_TRANSAC_COMP, i2c->base + OFFSET_INTR_MASK); + + /* Set transfer and transaction len */ + if (i2c->op == I2C_MASTER_WRRD) { + writew(msgs->len | ((msgs + 1)->len) << 8, + i2c->base + OFFSET_TRANSFER_LEN); + writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN); + } else { + writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN); + writew(num, i2c->base + OFFSET_TRANSAC_LEN); + } + + /* Prepare buffer data to start transfer */ + if (i2c->op == I2C_MASTER_RD) { + writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); + writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON); + rpaddr = dma_map_single(i2c->dev, msgs->buf, + msgs->len, DMA_FROM_DEVICE); + if (dma_mapping_error(i2c->dev, rpaddr)) + return -ENOMEM; + writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR); + writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN); + } else if (i2c->op == I2C_MASTER_WR) { + writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); + writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON); + wpaddr = dma_map_single(i2c->dev, msgs->buf, + msgs->len, DMA_TO_DEVICE); + if (dma_mapping_error(i2c->dev, wpaddr)) + return -ENOMEM; + writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR); + writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN); + } else { + writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG); + writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON); + wpaddr = dma_map_single(i2c->dev, msgs->buf, + msgs->len, DMA_TO_DEVICE); + if (dma_mapping_error(i2c->dev, wpaddr)) + return -ENOMEM; + rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf, + (msgs + 1)->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(i2c->dev, rpaddr)) { + dma_unmap_single(i2c->dev, wpaddr, + msgs->len, DMA_TO_DEVICE); + return -ENOMEM; + } + writel((u32)wpaddr, i2c->pdmabase + OFFSET_TX_MEM_ADDR); + writel((u32)rpaddr, i2c->pdmabase + OFFSET_RX_MEM_ADDR); + writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN); + writel((msgs + 1)->len, i2c->pdmabase + OFFSET_RX_LEN); + } + + writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN); + + if (!i2c->dev_comp->auto_restart) { + start_reg = I2C_TRANSAC_START; + } else { + start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG; + if (left_num >= 1) + start_reg |= I2C_RS_MUL_CNFG; + } + writew(start_reg, i2c->base + OFFSET_START); + + ret = wait_for_completion_timeout(&i2c->msg_complete, + i2c->adap.timeout); + + /* Clear interrupt mask */ + writew(~(restart_flag | I2C_HS_NACKERR | I2C_ACKERR | + I2C_TRANSAC_COMP), i2c->base + OFFSET_INTR_MASK); + + if (i2c->op == I2C_MASTER_WR) { + dma_unmap_single(i2c->dev, wpaddr, + msgs->len, DMA_TO_DEVICE); + } else if (i2c->op == I2C_MASTER_RD) { + dma_unmap_single(i2c->dev, rpaddr, + msgs->len, DMA_FROM_DEVICE); + } else { + dma_unmap_single(i2c->dev, wpaddr, msgs->len, + DMA_TO_DEVICE); + dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len, + DMA_FROM_DEVICE); + } + + if (ret == 0) { + dev_dbg(i2c->dev, "addr: %x, transfer timeout\n", msgs->addr); + mtk_i2c_init_hw(i2c); + return -ETIMEDOUT; + } + + completion_done(&i2c->msg_complete); + + if (i2c->irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) { + dev_dbg(i2c->dev, "addr: %x, transfer ACK error\n", msgs->addr); + mtk_i2c_init_hw(i2c); + return -ENXIO; + } + + return 0; +} + +static int mtk_i2c_transfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + int ret; + int left_num = num; + struct mtk_i2c *i2c = i2c_get_adapdata(adap); + + ret = mtk_i2c_clock_enable(i2c); + if (ret) + return ret; + + while (left_num--) { + if (!msgs->buf) { + dev_dbg(i2c->dev, "data buffer is NULL.\n"); + ret = -EINVAL; + goto err_exit; + } + + if (msgs->flags & I2C_M_RD) + i2c->op = I2C_MASTER_RD; + else + i2c->op = I2C_MASTER_WR; + + if (!i2c->dev_comp->auto_restart) { + if (num > 1) { + /* combined two messages into one transaction */ + i2c->op = I2C_MASTER_WRRD; + left_num--; + } + } + + /* always use DMA mode. */ + ret = mtk_i2c_do_transfer(i2c, msgs, num, left_num); + if (ret < 0) + goto err_exit; + + msgs++; + } + /* the return value is number of executed messages */ + ret = num; + +err_exit: + mtk_i2c_clock_disable(i2c); + return ret; +} + +static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id) +{ + struct mtk_i2c *i2c = dev_id; + u16 restart_flag = 0; + u16 intr_stat; + + if (i2c->dev_comp->auto_restart) + restart_flag = I2C_RS_TRANSFER; + + intr_stat = readw(i2c->base + OFFSET_INTR_STAT); + writew(intr_stat, i2c->base + OFFSET_INTR_STAT); + + /* + * when occurs ack error, i2c controller generate two interrupts + * first is the ack error interrupt, then the complete interrupt + * i2c->irq_stat need keep the two interrupt value. + */ + i2c->irq_stat |= intr_stat; + if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag)) + complete(&i2c->msg_complete); + + return IRQ_HANDLED; +} + +static u32 mtk_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm mtk_i2c_algorithm = { + .master_xfer = mtk_i2c_transfer, + .functionality = mtk_i2c_functionality, +}; + +static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c, + unsigned int *clk_src_div) +{ + int ret; + + ret = of_property_read_u32(np, "clock-frequency", &i2c->speed_hz); + if (ret < 0) + i2c->speed_hz = I2C_DEFAULT_SPEED; + + ret = of_property_read_u32(np, "clock-div", clk_src_div); + if (ret < 0) + return ret; + + if (*clk_src_div == 0) + return -EINVAL; + + i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic"); + i2c->use_push_pull = + of_property_read_bool(np, "mediatek,use-push-pull"); + + return 0; +} + +static int mtk_i2c_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id; + int ret = 0; + struct mtk_i2c *i2c; + struct clk *clk; + unsigned int clk_src_div; + struct resource *res; + int irq; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c, &clk_src_div); + if (ret) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->pdmabase)) + return PTR_ERR(i2c->pdmabase); + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq; + + init_completion(&i2c->msg_complete); + + of_id = of_match_node(mtk_i2c_of_match, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + + i2c->dev_comp = of_id->data; + i2c->adap.dev.of_node = pdev->dev.of_node; + i2c->dev = &pdev->dev; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &mtk_i2c_algorithm; + i2c->adap.quirks = i2c->dev_comp->quirks; + i2c->adap.timeout = 2 * HZ; + i2c->adap.retries = 1; + + if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c) + return -EINVAL; + + i2c->clk_main = devm_clk_get(&pdev->dev, "main"); + if (IS_ERR(i2c->clk_main)) { + dev_err(&pdev->dev, "cannot get main clock\n"); + return PTR_ERR(i2c->clk_main); + } + + i2c->clk_dma = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(i2c->clk_dma)) { + dev_err(&pdev->dev, "cannot get dma clock\n"); + return PTR_ERR(i2c->clk_dma); + } + + clk = i2c->clk_main; + if (i2c->have_pmic) { + i2c->clk_pmic = devm_clk_get(&pdev->dev, "pmic"); + if (IS_ERR(i2c->clk_pmic)) { + dev_err(&pdev->dev, "cannot get pmic clock\n"); + return PTR_ERR(i2c->clk_pmic); + } + clk = i2c->clk_pmic; + } + + strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name)); + + ret = mtk_i2c_set_speed(i2c, clk_get_rate(clk), clk_src_div); + if (ret) { + dev_err(&pdev->dev, "Failed to set the speed.\n"); + return -EINVAL; + } + + ret = mtk_i2c_clock_enable(i2c); + if (ret) { + dev_err(&pdev->dev, "clock enable failed!\n"); + return ret; + } + mtk_i2c_init_hw(i2c); + mtk_i2c_clock_disable(i2c); + + ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq, + IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c); + if (ret < 0) { + dev_err(&pdev->dev, + "Request I2C IRQ %d fail\n", irq); + return ret; + } + + i2c_set_adapdata(&i2c->adap, i2c); + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + dev_err(&pdev->dev, "Failed to add i2c bus to i2c core\n"); + return ret; + } + + platform_set_drvdata(pdev, i2c); + + return 0; +} + +static int mtk_i2c_remove(struct platform_device *pdev) +{ + struct mtk_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mtk_i2c_resume(struct device *dev) +{ + struct mtk_i2c *i2c = dev_get_drvdata(dev); + + mtk_i2c_init_hw(i2c); + + return 0; +} +#endif + +static const struct dev_pm_ops mtk_i2c_pm = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume) +}; + +static struct platform_driver mtk_i2c_driver = { + .probe = mtk_i2c_probe, + .remove = mtk_i2c_remove, + .driver = { + .name = I2C_DRV_NAME, + .pm = &mtk_i2c_pm, + .of_match_table = of_match_ptr(mtk_i2c_of_match), + }, +}; + +module_platform_driver(mtk_i2c_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MediaTek I2C Bus Driver"); +MODULE_AUTHOR("Xudong Chen <xudong.chen@mediatek.com>"); diff --git a/kernel/drivers/i2c/busses/i2c-mv64xxx.c b/kernel/drivers/i2c/busses/i2c-mv64xxx.c index 30059c1df..43207f52e 100644 --- a/kernel/drivers/i2c/busses/i2c-mv64xxx.c +++ b/kernel/drivers/i2c/busses/i2c-mv64xxx.c @@ -146,6 +146,8 @@ struct mv64xxx_i2c_data { bool errata_delay; struct reset_control *rstc; bool irq_clear_inverted; + /* Clk div is 2 to the power n, not 2 to the power n + 1 */ + bool clk_n_base_0; }; static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { @@ -669,8 +671,6 @@ mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data) struct i2c_msg *msgs = drv_data->msgs; int num = drv_data->num_msgs; - return false; - if (!drv_data->offload_enabled) return false; @@ -759,25 +759,29 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); #ifdef CONFIG_OF #ifdef CONFIG_HAVE_CLK static int -mv64xxx_calc_freq(const int tclk, const int n, const int m) +mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data, + const int tclk, const int n, const int m) { - return tclk / (10 * (m + 1) * (2 << n)); + if (drv_data->clk_n_base_0) + return tclk / (10 * (m + 1) * (1 << n)); + else + return tclk / (10 * (m + 1) * (2 << n)); } static bool -mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, - u32 *best_m) +mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data, + const u32 req_freq, const u32 tclk) { int freq, delta, best_delta = INT_MAX; int m, n; for (n = 0; n <= 7; n++) for (m = 0; m <= 15; m++) { - freq = mv64xxx_calc_freq(tclk, n, m); + freq = mv64xxx_calc_freq(drv_data, tclk, n, m); delta = req_freq - freq; if (delta >= 0 && delta < best_delta) { - *best_m = m; - *best_n = n; + drv_data->freq_m = m; + drv_data->freq_n = n; best_delta = delta; } if (best_delta == 0) @@ -815,8 +819,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, if (of_property_read_u32(np, "clock-frequency", &bus_freq)) bus_freq = 100000; /* 100kHz by default */ - if (!mv64xxx_find_baud_factors(bus_freq, tclk, - &drv_data->freq_n, &drv_data->freq_m)) { + if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") || + of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) + drv_data->clk_n_base_0 = true; + + if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) { rc = -EINVAL; goto out; } diff --git a/kernel/drivers/i2c/busses/i2c-mxs.c b/kernel/drivers/i2c/busses/i2c-mxs.c index 3e84f6c09..033846cdf 100644 --- a/kernel/drivers/i2c/busses/i2c-mxs.c +++ b/kernel/drivers/i2c/busses/i2c-mxs.c @@ -784,7 +784,7 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) return 0; } -static struct platform_device_id mxs_i2c_devtype[] = { +static const struct platform_device_id mxs_i2c_devtype[] = { { .name = "imx23-i2c", .driver_data = MXS_I2C_V1, diff --git a/kernel/drivers/i2c/busses/i2c-ocores.c b/kernel/drivers/i2c/busses/i2c-ocores.c index abf5db7e4..11b7b8731 100644 --- a/kernel/drivers/i2c/busses/i2c-ocores.c +++ b/kernel/drivers/i2c/busses/i2c-ocores.c @@ -92,6 +92,16 @@ static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) iowrite32(value, i2c->base + (reg << i2c->reg_shift)); } +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) { return ioread8(i2c->base + (reg << i2c->reg_shift)); @@ -107,6 +117,16 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) return ioread32(i2c->base + (reg << i2c->reg_shift)); } +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { i2c->setreg(i2c, reg, value); @@ -428,6 +448,9 @@ static int ocores_i2c_probe(struct platform_device *pdev) i2c->reg_io_width = 1; /* Set to default value */ if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + switch (i2c->reg_io_width) { case 1: i2c->setreg = oc_setreg_8; @@ -435,13 +458,13 @@ static int ocores_i2c_probe(struct platform_device *pdev) break; case 2: - i2c->setreg = oc_setreg_16; - i2c->getreg = oc_getreg_16; + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; break; case 4: - i2c->setreg = oc_setreg_32; - i2c->getreg = oc_getreg_32; + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; break; default: diff --git a/kernel/drivers/i2c/busses/i2c-octeon.c b/kernel/drivers/i2c/busses/i2c-octeon.c index 6e75e016b..32914ab42 100644 --- a/kernel/drivers/i2c/busses/i2c-octeon.c +++ b/kernel/drivers/i2c/busses/i2c-octeon.c @@ -200,7 +200,7 @@ static int octeon_i2c_test_iflg(struct octeon_i2c *i2c) */ static int octeon_i2c_wait(struct octeon_i2c *i2c) { - int result; + long result; octeon_i2c_int_enable(i2c); @@ -210,10 +210,7 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) octeon_i2c_int_disable(i2c); - if (result < 0) { - dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__); - return result; - } else if (result == 0) { + if (result == 0) { dev_dbg(i2c->dev, "%s: timeout\n", __func__); return -ETIMEDOUT; } diff --git a/kernel/drivers/i2c/busses/i2c-omap.c b/kernel/drivers/i2c/busses/i2c-omap.c index 2f9de5ecb..46b89dd42 100644 --- a/kernel/drivers/i2c/busses/i2c-omap.c +++ b/kernel/drivers/i2c/busses/i2c-omap.c @@ -38,6 +38,7 @@ #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 @@ -269,35 +270,35 @@ 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 inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, int reg, u16 val) { - writew_relaxed(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 readw_relaxed(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 @@ -309,32 +310,32 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) * 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; } @@ -342,18 +343,18 @@ 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 (dev->rev > OMAP_I2C_REV_ON_3430_3530) { + if (omap->rev > OMAP_I2C_REV_ON_3430_3530) { /* Schedule I2C-bus monitoring on the next transfer */ - dev->bb_valid = 0; + 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; @@ -361,23 +362,23 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long internal_clk = 0; struct clk *fclk; - 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"); fclk_rate = clk_get_rate(fclk); clk_put(fclk); @@ -394,7 +395,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 @@ -402,14 +403,14 @@ 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"); fclk_rate = clk_get_rate(fclk) / 1000; clk_put(fclk); @@ -418,7 +419,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 */ @@ -427,20 +428,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; @@ -449,25 +450,25 @@ 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; - if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) { + if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) { /* Not implemented */ - dev->bb_valid = 1; + omap->bb_valid = 1; } - __omap_i2c_init(dev); + __omap_i2c_init(omap); return 0; } @@ -475,16 +476,14 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* * 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) { - if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; - } + while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { + if (time_after(jiffies, timeout)) + return i2c_recover_bus(&omap->adapter); msleep(1); } @@ -519,19 +518,19 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) * 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 *dev) +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 (dev->bb_valid) + if (omap->bb_valid) return 0; timeout = jiffies + OMAP_I2C_TIMEOUT; while (1) { - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + 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 @@ -544,7 +543,7 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev) * Otherwise, we must look signals on the bus to make * the right decision. */ - systest = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + 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) { @@ -565,22 +564,22 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev) } if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting for bus ready\n"); + dev_warn(omap->dev, "timeout waiting for bus ready\n"); return -ETIMEDOUT; } msleep(1); } - dev->bb_valid = 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; /* @@ -590,29 +589,29 @@ 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); } /* @@ -621,42 +620,42 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { - struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + struct omap_i2c_dev *omap = i2c_get_adapdata(adap); unsigned long timeout; u16 w; - 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); - reinit_completion(&dev->cmd_complete); - dev->cmd_err = 0; + 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) @@ -666,27 +665,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; /* * 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(dev, OMAP_I2C_CON_REG, w); + 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; } @@ -695,42 +694,42 @@ 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, + timeout = wait_for_completion_timeout(&omap->cmd_complete, OMAP_I2C_TIMEOUT); if (timeout == 0) { - dev_err(dev->dev, "controller timed out\n"); - omap_i2c_reset(dev); - __omap_i2c_init(dev); + dev_err(omap->dev, "controller timed out\n"); + 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_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_AL) + if (omap->cmd_err & OMAP_I2C_STAT_AL) return -EAGAIN; - if (dev->cmd_err & OMAP_I2C_STAT_NACK) { + if (omap->cmd_err & OMAP_I2C_STAT_NACK) { if (msg->flags & I2C_M_IGNORE_NAK) return 0; - w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); w |= OMAP_I2C_CON_STP; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); return -EREMOTEIO; } return -EIO; @@ -744,24 +743,24 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, static int omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { - 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); + r = pm_runtime_get_sync(omap->dev); if (r < 0) goto out; - r = omap_i2c_wait_for_bb_valid(dev); + 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))); @@ -772,14 +771,14 @@ 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_mark_last_busy(omap->dev); + pm_runtime_put_autosuspend(omap->dev); return r; } @@ -791,19 +790,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) @@ -814,17 +813,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"); } } @@ -837,50 +836,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; @@ -897,28 +896,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; @@ -928,61 +927,61 @@ 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; @@ -991,13 +990,13 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, static irqreturn_t omap_i2c_isr(int irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; irqreturn_t ret = IRQ_HANDLED; u16 mask; u16 stat; - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); + mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); if (stat & mask) ret = IRQ_WAKE_THREAD; @@ -1008,20 +1007,20 @@ omap_i2c_isr(int irq, void *dev_id) static irqreturn_t omap_i2c_isr_thread(int this_irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; unsigned long flags; u16 bits; u16 stat; int err = 0, count = 0; - spin_lock_irqsave(&dev->lock, flags); + spin_lock_irqsave(&omap->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); @@ -1031,32 +1030,32 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) goto out; } - 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); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); } 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); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); } /* * ProDB0017052: Clear ARDY bit twice */ if (stat & OMAP_I2C_STAT_ARDY) - omap_i2c_ack_stat(dev, 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 | @@ -1067,28 +1066,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; - if (dev->errata & I2C_OMAP_ERRATA_I207) { - i2c_omap_errata_i207(dev, stat); - num_bytes = (omap_i2c_read_reg(dev, + 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_receive_data(dev, num_bytes, true); - 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; } @@ -1096,14 +1095,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; } @@ -1111,36 +1110,36 @@ 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); + omap_i2c_complete_cmd(omap, err); out: - spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock_irqrestore(&omap->lock, flags); return IRQ_HANDLED; } @@ -1206,10 +1205,83 @@ 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 = @@ -1227,46 +1299,46 @@ omap_i2c_probe(struct platform_device *pdev) return irq; } - dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) + 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_ioremap_resource(&pdev->dev, mem); + 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 */ pdata = match->data; - dev->flags = pdata->flags; + 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->dev = &pdev->dev; - dev->irq = irq; + omap->dev = &pdev->dev; + omap->irq = irq; - spin_lock_init(&dev->lock); + spin_lock_init(&omap->lock); - platform_set_drvdata(pdev, dev); - init_completion(&dev->cmd_complete); + platform_set_drvdata(pdev, omap); + init_completion(&omap->cmd_complete); - dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; + omap->reg_shift = (omap->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); + pm_runtime_enable(omap->dev); + pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(omap->dev); - r = pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(omap->dev); if (r < 0) goto err_free_mem; @@ -1276,42 +1348,42 @@ omap_i2c_probe(struct platform_device *pdev) * Also since the omap_i2c_read_reg uses reg_map_ip_* a * readw_relaxed is done. */ - rev = readw_relaxed(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 @@ -1319,62 +1391,63 @@ 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); } /* reset ASAP, clearing any IRQs */ - omap_i2c_init(dev); + omap_i2c_init(omap); - 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, + r = devm_request_threaded_irq(&pdev->dev, omap->irq, omap_i2c_isr, 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_DEPRECATED; strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; 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"); + dev_err(omap->dev, "failure adding adapter\n"); goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, - major, minor, dev->speed); + 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_mark_last_busy(omap->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); + pm_runtime_put(omap->dev); pm_runtime_disable(&pdev->dev); err_free_mem: @@ -1383,16 +1456,16 @@ err_free_mem: static int 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); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) return ret; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - pm_runtime_put(&pdev->dev); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } @@ -1400,38 +1473,40 @@ static int omap_i2c_remove(struct platform_device *pdev) #ifdef CONFIG_PM 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; } diff --git a/kernel/drivers/i2c/busses/i2c-parport.c b/kernel/drivers/i2c/busses/i2c-parport.c index a1fac5aa9..a8e54df4a 100644 --- a/kernel/drivers/i2c/busses/i2c-parport.c +++ b/kernel/drivers/i2c/busses/i2c-parport.c @@ -20,6 +20,8 @@ GNU General Public License for more details. * ------------------------------------------------------------------------ */ +#define pr_fmt(fmt) "i2c-parport: " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -46,6 +48,9 @@ struct i2c_par { static LIST_HEAD(adapter_list); static DEFINE_MUTEX(adapter_list_lock); +#define MAX_DEVICE 4 +static int parport[MAX_DEVICE] = {0, -1, -1, -1}; + /* ----- Low-level parallel port access ----------------------------------- */ @@ -163,19 +168,34 @@ static void i2c_parport_irq(void *data) static void i2c_parport_attach(struct parport *port) { struct i2c_par *adapter; + int i; + struct pardev_cb i2c_parport_cb; + + for (i = 0; i < MAX_DEVICE; i++) { + if (parport[i] == -1) + continue; + if (port->number == parport[i]) + break; + } + if (i == MAX_DEVICE) { + pr_debug("Not using parport%d.\n", port->number); + return; + } adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL); - if (adapter == NULL) { - printk(KERN_ERR "i2c-parport: Failed to kzalloc\n"); + if (!adapter) return; - } + memset(&i2c_parport_cb, 0, sizeof(i2c_parport_cb)); + i2c_parport_cb.flags = PARPORT_FLAG_EXCL; + i2c_parport_cb.irq_func = i2c_parport_irq; + i2c_parport_cb.private = adapter; - pr_debug("i2c-parport: attaching to %s\n", port->name); + pr_debug("attaching to %s\n", port->name); parport_disable_irq(port); - adapter->pdev = parport_register_device(port, "i2c-parport", - NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter); + adapter->pdev = parport_register_dev_model(port, "i2c-parport", + &i2c_parport_cb, i); if (!adapter->pdev) { - printk(KERN_ERR "i2c-parport: Unable to register with parport\n"); + pr_err("Unable to register with parport\n"); goto err_free; } @@ -195,7 +215,8 @@ static void i2c_parport_attach(struct parport *port) adapter->adapter.dev.parent = port->physport->dev; if (parport_claim_or_block(adapter->pdev) < 0) { - printk(KERN_ERR "i2c-parport: Could not claim parallel port\n"); + dev_err(&adapter->pdev->dev, + "Could not claim parallel port\n"); goto err_unregister; } @@ -210,7 +231,7 @@ static void i2c_parport_attach(struct parport *port) } if (i2c_bit_add_bus(&adapter->adapter) < 0) { - printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); + dev_err(&adapter->pdev->dev, "Unable to register with I2C\n"); goto err_unregister; } @@ -222,8 +243,8 @@ static void i2c_parport_attach(struct parport *port) if (adapter->ara) parport_enable_irq(port); else - printk(KERN_WARNING "i2c-parport: Failed to register " - "ARA client\n"); + dev_warn(&adapter->pdev->dev, + "Failed to register ARA client\n"); } /* Add the new adapter to the list */ @@ -267,9 +288,10 @@ static void i2c_parport_detach(struct parport *port) } static struct parport_driver i2c_parport_driver = { - .name = "i2c-parport", - .attach = i2c_parport_attach, - .detach = i2c_parport_detach, + .name = "i2c-parport", + .match_port = i2c_parport_attach, + .detach = i2c_parport_detach, + .devmodel = true, }; /* ----- Module loading, unloading and information ------------------------ */ @@ -277,12 +299,12 @@ static struct parport_driver i2c_parport_driver = { static int __init i2c_parport_init(void) { if (type < 0) { - printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + pr_warn("adapter type unspecified\n"); return -ENODEV; } if (type >= ARRAY_SIZE(adapter_parm)) { - printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); + pr_warn("invalid type (%d)\n", type); return -ENODEV; } @@ -298,5 +320,12 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("I2C bus over parallel port"); MODULE_LICENSE("GPL"); +module_param_array(parport, int, NULL, 0); +MODULE_PARM_DESC(parport, + "List of parallel ports to bind to, by index.\n" + " Atmost " __stringify(MAX_DEVICE) " devices are supported.\n" + " Default is one device connected to parport0.\n" +); + module_init(i2c_parport_init); module_exit(i2c_parport_exit); diff --git a/kernel/drivers/i2c/busses/i2c-parport.h b/kernel/drivers/i2c/busses/i2c-parport.h index 4e1294536..84a6616b0 100644 --- a/kernel/drivers/i2c/busses/i2c-parport.h +++ b/kernel/drivers/i2c/busses/i2c-parport.h @@ -89,6 +89,13 @@ static const struct adapter_parm adapter_parm[] = { .getsda = { 0x80, PORT_STAT, 1 }, .init = { 0x04, PORT_DATA, 1 }, }, + /* type 8: VCT-jig */ + { + .setsda = { 0x04, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x40, PORT_STAT, 0 }, + .getscl = { 0x80, PORT_STAT, 1 }, + }, }; static int type = -1; @@ -103,4 +110,5 @@ MODULE_PARM_DESC(type, " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" " 6 = Barco LPT->DVI (K5800236) adapter\n" " 7 = One For All JP1 parallel port adapter\n" + " 8 = VCT-jig\n" ); diff --git a/kernel/drivers/i2c/busses/i2c-piix4.c b/kernel/drivers/i2c/busses/i2c-piix4.c index 67cbec679..630bce68b 100644 --- a/kernel/drivers/i2c/busses/i2c-piix4.c +++ b/kernel/drivers/i2c/busses/i2c-piix4.c @@ -245,7 +245,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS && PIIX4_dev->revision >= 0x41) || (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD && - PIIX4_dev->device == 0x790b && + PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS && PIIX4_dev->revision >= 0x49)) smb_en = 0x00; else @@ -545,7 +545,7 @@ static const struct pci_device_id piix4_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, diff --git a/kernel/drivers/i2c/busses/i2c-pnx.c b/kernel/drivers/i2c/busses/i2c-pnx.c index e814a36d9..7ea67aa46 100644 --- a/kernel/drivers/i2c/busses/i2c-pnx.c +++ b/kernel/drivers/i2c/busses/i2c-pnx.c @@ -496,7 +496,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_msg *pmsg; int rc = 0, completed = 0, i; struct i2c_pnx_algo_data *alg_data = adap->algo_data; - u32 stat = ioread32(I2C_REG_STS(alg_data)); + u32 stat; dev_dbg(&alg_data->adapter.dev, "%s(): entering: %d messages, stat = %04x.\n", @@ -600,7 +600,7 @@ static int i2c_pnx_controller_suspend(struct device *dev) { struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); - clk_disable(alg_data->clk); + clk_disable_unprepare(alg_data->clk); return 0; } @@ -609,7 +609,7 @@ static int i2c_pnx_controller_resume(struct device *dev) { struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); - return clk_enable(alg_data->clk); + return clk_prepare_enable(alg_data->clk); } static SIMPLE_DEV_PM_OPS(i2c_pnx_pm, @@ -659,9 +659,8 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk); - init_timer(&alg_data->mif.timer); - alg_data->mif.timer.function = i2c_pnx_timeout; - alg_data->mif.timer.data = (unsigned long)alg_data; + setup_timer(&alg_data->mif.timer, i2c_pnx_timeout, + (unsigned long)alg_data); snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name); @@ -672,7 +671,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->ioaddr)) return PTR_ERR(alg_data->ioaddr); - ret = clk_enable(alg_data->clk); + ret = clk_prepare_enable(alg_data->clk); if (ret) return ret; @@ -726,7 +725,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) return 0; out_clock: - clk_disable(alg_data->clk); + clk_disable_unprepare(alg_data->clk); return ret; } @@ -735,7 +734,7 @@ static int i2c_pnx_remove(struct platform_device *pdev) struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); i2c_del_adapter(&alg_data->adapter); - clk_disable(alg_data->clk); + clk_disable_unprepare(alg_data->clk); return 0; } diff --git a/kernel/drivers/i2c/busses/i2c-pxa.c b/kernel/drivers/i2c/busses/i2c-pxa.c index d9c0d6a17..0d351954d 100644 --- a/kernel/drivers/i2c/busses/i2c-pxa.c +++ b/kernel/drivers/i2c/busses/i2c-pxa.c @@ -46,12 +46,15 @@ struct pxa_reg_layout { u32 icr; u32 isr; u32 isar; + u32 ilcr; + u32 iwcr; }; enum pxa_i2c_types { REGS_PXA2XX, REGS_PXA3XX, REGS_CE4100, + REGS_PXA910, }; /* @@ -79,12 +82,22 @@ static struct pxa_reg_layout pxa_reg_layout[] = { .isr = 0x04, /* no isar register */ }, + [REGS_PXA910] = { + .ibmr = 0x00, + .idbr = 0x08, + .icr = 0x10, + .isr = 0x18, + .isar = 0x20, + .ilcr = 0x28, + .iwcr = 0x30, + }, }; static const struct platform_device_id i2c_pxa_id_table[] = { { "pxa2xx-i2c", REGS_PXA2XX }, { "pxa3xx-pwri2c", REGS_PXA3XX }, { "ce4100-i2c", REGS_CE4100 }, + { "pxa910-i2c", REGS_PXA910 }, { }, }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); @@ -124,6 +137,23 @@ MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); #define ISR_SAD (1 << 9) /* slave address detected */ #define ISR_BED (1 << 10) /* bus error no ACK/NAK */ +/* bit field shift & mask */ +#define ILCR_SLV_SHIFT 0 +#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT) +#define ILCR_FLV_SHIFT 9 +#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT) +#define ILCR_HLVL_SHIFT 18 +#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT) +#define ILCR_HLVH_SHIFT 27 +#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT) + +#define IWCR_CNT_SHIFT 0 +#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT) +#define IWCR_HS_CNT1_SHIFT 5 +#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT) +#define IWCR_HS_CNT2_SHIFT 10 +#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT) + struct pxa_i2c { spinlock_t lock; wait_queue_head_t wait; @@ -132,6 +162,7 @@ struct pxa_i2c { unsigned int msg_idx; unsigned int msg_ptr; unsigned int slave_addr; + unsigned int req_slave_addr; struct i2c_adapter adap; struct clk *clk; @@ -149,6 +180,8 @@ struct pxa_i2c { void __iomem *reg_icr; void __iomem *reg_isr; void __iomem *reg_isar; + void __iomem *reg_ilcr; + void __iomem *reg_iwcr; unsigned long iobase; unsigned long iosize; @@ -167,6 +200,8 @@ struct pxa_i2c { #define _ICR(i2c) ((i2c)->reg_icr) #define _ISR(i2c) ((i2c)->reg_isr) #define _ISAR(i2c) ((i2c)->reg_isar) +#define _ILCR(i2c) ((i2c)->reg_ilcr) +#define _IWCR(i2c) ((i2c)->reg_iwcr) /* * I2C Slave mode address @@ -253,15 +288,20 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) { unsigned int i; - printk(KERN_ERR "i2c: error: %s\n", why); - printk(KERN_ERR "i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", + struct device *dev = &i2c->adap.dev; + + dev_err(dev, "slave_0x%x error: %s\n", + i2c->req_slave_addr >> 1, why); + dev_err(dev, "msg_num: %d msg_idx: %d msg_ptr: %d\n", i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); - printk(KERN_ERR "i2c: ICR: %08x ISR: %08x\n", - readl(_ICR(i2c)), readl(_ISR(i2c))); - printk(KERN_DEBUG "i2c: log: "); + dev_err(dev, "IBMR: %08x IDBR: %08x ICR: %08x ISR: %08x\n", + readl(_IBMR(i2c)), readl(_IDBR(i2c)), readl(_ICR(i2c)), + readl(_ISR(i2c))); + dev_dbg(dev, "log: "); for (i = 0; i < i2c->irqlogidx; i++) - printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); - printk("\n"); + pr_debug("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); + + pr_debug("\n"); } #else /* ifdef DEBUG */ @@ -459,7 +499,7 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) writel(I2C_ISR_INIT, _ISR(i2c)); writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); - if (i2c->reg_isar) + if (i2c->reg_isar && IS_ENABLED(CONFIG_I2C_PXA_SLAVE)) writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ @@ -638,6 +678,7 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) * Step 1: target slave address into IDBR */ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); + i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); /* * Step 2: initiate the write. @@ -745,8 +786,10 @@ static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, ret = i2c->msg_idx; out: - if (timeout == 0) + if (timeout == 0) { i2c_pxa_scream_blue_murder(i2c, "timeout"); + ret = I2C_RETRY; + } return ret; } @@ -949,6 +992,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) * Write the next address. */ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); + i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); /* * And trigger a repeated start, and send the byte. @@ -1092,7 +1136,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { static const struct of_device_id i2c_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, - { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX }, + { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 }, {} }; MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); @@ -1114,7 +1158,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, i2c->use_pio = 1; if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) i2c->fast_mode = 1; - *i2c_types = (u32)(of_id->data); + + *i2c_types = (enum pxa_i2c_types)(of_id->data); + return 0; } @@ -1146,10 +1192,19 @@ static int i2c_pxa_probe(struct platform_device *dev) struct resource *res = NULL; int ret, irq; - i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); - if (!i2c) { - ret = -ENOMEM; - goto emalloc; + i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(i2c->reg_base)) + return PTR_ERR(i2c->reg_base); + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no irq resource: %d\n", irq); + return irq; } /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ @@ -1159,19 +1214,7 @@ static int i2c_pxa_probe(struct platform_device *dev) if (ret > 0) ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type); if (ret < 0) - goto eclk; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - irq = platform_get_irq(dev, 0); - if (res == NULL || irq < 0) { - ret = -ENODEV; - goto eclk; - } - - if (!request_mem_region(res->start, resource_size(res), res->name)) { - ret = -ENOMEM; - goto eclk; - } + return ret; i2c->adap.owner = THIS_MODULE; i2c->adap.retries = 5; @@ -1181,16 +1224,10 @@ static int i2c_pxa_probe(struct platform_device *dev) strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); - i2c->clk = clk_get(&dev->dev, NULL); + i2c->clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(i2c->clk)) { - ret = PTR_ERR(i2c->clk); - goto eclk; - } - - i2c->reg_base = ioremap(res->start, resource_size(res)); - if (!i2c->reg_base) { - ret = -EIO; - goto eremap; + dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); + return PTR_ERR(i2c->clk); } i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; @@ -1200,6 +1237,11 @@ static int i2c_pxa_probe(struct platform_device *dev) if (i2c_type != REGS_CE4100) i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; + if (i2c_type == REGS_PXA910) { + i2c->reg_ilcr = i2c->reg_base + pxa_reg_layout[i2c_type].ilcr; + i2c->reg_iwcr = i2c->reg_base + pxa_reg_layout[i2c_type].iwcr; + } + i2c->iobase = res->start; i2c->iosize = resource_size(res); @@ -1232,10 +1274,13 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { i2c->adap.algo = &i2c_pxa_algorithm; - ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED, - dev_name(&dev->dev), i2c); - if (ret) + ret = devm_request_irq(&dev->dev, irq, i2c_pxa_handler, + IRQF_SHARED | IRQF_NO_SUSPEND, + dev_name(&dev->dev), i2c); + if (ret) { + dev_err(&dev->dev, "failed to request irq: %d\n", ret); goto ereqirq; + } } i2c_pxa_reset(i2c); @@ -1248,33 +1293,22 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { - printk(KERN_INFO "I2C: Failed to add bus\n"); - goto eadapt; + dev_err(&dev->dev, "failed to add bus: %d\n", ret); + goto ereqirq; } platform_set_drvdata(dev, i2c); #ifdef CONFIG_I2C_PXA_SLAVE - printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n", - dev_name(&i2c->adap.dev), i2c->slave_addr); + dev_info(&i2c->adap.dev, " PXA I2C adapter, slave address %d\n", + i2c->slave_addr); #else - printk(KERN_INFO "I2C: %s: PXA I2C adapter\n", - dev_name(&i2c->adap.dev)); + dev_info(&i2c->adap.dev, " PXA I2C adapter\n"); #endif return 0; -eadapt: - if (!i2c->use_pio) - free_irq(irq, i2c); ereqirq: clk_disable_unprepare(i2c->clk); - iounmap(i2c->reg_base); -eremap: - clk_put(i2c->clk); -eclk: - kfree(i2c); -emalloc: - release_mem_region(res->start, resource_size(res)); return ret; } @@ -1283,15 +1317,8 @@ static int i2c_pxa_remove(struct platform_device *dev) struct pxa_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); - if (!i2c->use_pio) - free_irq(i2c->irq, i2c); clk_disable_unprepare(i2c->clk); - clk_put(i2c->clk); - - iounmap(i2c->reg_base); - release_mem_region(i2c->iobase, i2c->iosize); - kfree(i2c); return 0; } diff --git a/kernel/drivers/i2c/busses/i2c-rcar.c b/kernel/drivers/i2c/busses/i2c-rcar.c index 5a84bea5b..599c0d7bd 100644 --- a/kernel/drivers/i2c/busses/i2c-rcar.c +++ b/kernel/drivers/i2c/busses/i2c-rcar.c @@ -27,7 +27,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/i2c.h> -#include <linux/i2c/i2c-rcar.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_device.h> @@ -103,6 +102,7 @@ enum rcar_i2c_type { I2C_RCAR_GEN1, I2C_RCAR_GEN2, + I2C_RCAR_GEN3, }; struct rcar_i2c_priv { @@ -178,6 +178,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, cdf_width = 2; break; case I2C_RCAR_GEN2: + case I2C_RCAR_GEN3: cdf_width = 3; break; default: @@ -490,7 +491,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); struct device *dev = rcar_i2c_priv_to_dev(priv); unsigned long flags; - int i, ret, timeout; + int i, ret; + long timeout; pm_runtime_get_sync(dev); @@ -532,7 +534,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, timeout = wait_event_timeout(priv->wait, rcar_i2c_flags_has(priv, ID_DONE), - 5 * HZ); + adap->timeout); if (!timeout) { ret = -ETIMEDOUT; break; @@ -574,7 +576,7 @@ static int rcar_reg_slave(struct i2c_client *slave) if (slave->flags & I2C_CLIENT_TEN) return -EAFNOSUPPORT; - pm_runtime_forbid(rcar_i2c_priv_to_dev(priv)); + pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv)); priv->slave = slave; rcar_i2c_write(priv, ICSAR, slave->addr); @@ -596,7 +598,7 @@ static int rcar_unreg_slave(struct i2c_client *slave) priv->slave = NULL; - pm_runtime_allow(rcar_i2c_priv_to_dev(priv)); + pm_runtime_put(rcar_i2c_priv_to_dev(priv)); return 0; } @@ -604,7 +606,8 @@ static int rcar_unreg_slave(struct i2c_client *slave) static u32 rcar_i2c_func(struct i2c_adapter *adap) { /* This HW can't do SMBUS_QUICK and NOSTART */ - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + return I2C_FUNC_I2C | I2C_FUNC_SLAVE | + (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); } static const struct i2c_algorithm rcar_i2c_algo = { @@ -623,13 +626,13 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); static int rcar_i2c_probe(struct platform_device *pdev) { - struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev); struct rcar_i2c_priv *priv; struct i2c_adapter *adap; struct resource *res; @@ -648,15 +651,9 @@ static int rcar_i2c_probe(struct platform_device *pdev) } bus_speed = 100000; /* default 100 kHz */ - ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed); - if (ret < 0 && pdata && pdata->bus_speed) - bus_speed = pdata->bus_speed; + of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed); - if (pdev->dev.of_node) - priv->devtype = (long)of_match_device(rcar_i2c_dt_ids, - dev)->data; - else - priv->devtype = platform_get_device_id(pdev)->driver_data; + priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data; ret = rcar_i2c_clock_calculate(priv, bus_speed, dev); if (ret < 0) @@ -688,15 +685,16 @@ static int rcar_i2c_probe(struct platform_device *pdev) return ret; } + pm_runtime_enable(dev); + platform_set_drvdata(pdev, priv); + ret = i2c_add_numbered_adapter(adap); if (ret < 0) { dev_err(dev, "reg adap failed: %d\n", ret); + pm_runtime_disable(dev); return ret; } - pm_runtime_enable(dev); - platform_set_drvdata(pdev, priv); - dev_info(dev, "probed\n"); return 0; @@ -713,14 +711,6 @@ static int rcar_i2c_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id rcar_i2c_id_table[] = { - { "i2c-rcar", I2C_RCAR_GEN1 }, - { "i2c-rcar_gen1", I2C_RCAR_GEN1 }, - { "i2c-rcar_gen2", I2C_RCAR_GEN2 }, - {}, -}; -MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table); - static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", @@ -728,7 +718,6 @@ static struct platform_driver rcar_i2c_driver = { }, .probe = rcar_i2c_probe, .remove = rcar_i2c_remove, - .id_table = rcar_i2c_id_table, }; module_platform_driver(rcar_i2c_driver); diff --git a/kernel/drivers/i2c/busses/i2c-rk3x.c b/kernel/drivers/i2c/busses/i2c-rk3x.c index 019d5426f..9096d17be 100644 --- a/kernel/drivers/i2c/busses/i2c-rk3x.c +++ b/kernel/drivers/i2c/busses/i2c-rk3x.c @@ -72,7 +72,7 @@ enum { #define REG_INT_ALL 0x7f /* Constants */ -#define WAIT_TIMEOUT 200 /* ms */ +#define WAIT_TIMEOUT 1000 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ enum rk3x_i2c_state { @@ -858,6 +858,7 @@ static const struct of_device_id rk3x_i2c_match[] = { { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, {}, }; +MODULE_DEVICE_TABLE(of, rk3x_i2c_match); static int rk3x_i2c_probe(struct platform_device *pdev) { @@ -907,7 +908,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) &i2c->scl_fall_ns)) i2c->scl_fall_ns = 300; if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns", - &i2c->scl_fall_ns)) + &i2c->sda_fall_ns)) i2c->sda_fall_ns = i2c->scl_fall_ns; strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); diff --git a/kernel/drivers/i2c/busses/i2c-s3c2410.c b/kernel/drivers/i2c/busses/i2c-s3c2410.c index 297e9c9ac..5df819610 100644 --- a/kernel/drivers/i2c/busses/i2c-s3c2410.c +++ b/kernel/drivers/i2c/busses/i2c-s3c2410.c @@ -132,7 +132,7 @@ struct s3c24xx_i2c { unsigned int sys_i2c_cfg; }; -static struct platform_device_id s3c24xx_driver_ids[] = { +static const struct platform_device_id s3c24xx_driver_ids[] = { { .name = "s3c2410-i2c", .driver_data = 0, @@ -1243,17 +1243,19 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->adap.nr = i2c->pdata->bus_num; i2c->adap.dev.of_node = pdev->dev.of_node; + platform_set_drvdata(pdev, i2c); + + pm_runtime_enable(&pdev->dev); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + pm_runtime_disable(&pdev->dev); s3c24xx_i2c_deregister_cpufreq(i2c); clk_unprepare(i2c->clk); return ret; } - platform_set_drvdata(pdev, i2c); - - pm_runtime_enable(&pdev->dev); pm_runtime_enable(&i2c->adap.dev); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); diff --git a/kernel/drivers/i2c/busses/i2c-sh_mobile.c b/kernel/drivers/i2c/busses/i2c-sh_mobile.c index 007818b3e..7d2bd3ec2 100644 --- a/kernel/drivers/i2c/busses/i2c-sh_mobile.c +++ b/kernel/drivers/i2c/busses/i2c-sh_mobile.c @@ -150,6 +150,7 @@ struct sh_mobile_i2c_data { struct sh_mobile_dt_config { int clks_per_count; + void (*setup)(struct sh_mobile_i2c_data *pd); }; #define IIC_FLAG_HAS_ICIC67 (1 << 0) @@ -164,6 +165,7 @@ struct sh_mobile_dt_config { #define ICIC 0x0c #define ICCL 0x10 #define ICCH 0x14 +#define ICSTART 0x70 /* Register bits */ #define ICCR_ICE 0x80 @@ -190,6 +192,8 @@ struct sh_mobile_dt_config { #define ICIC_WAITE 0x02 #define ICIC_DTEE 0x01 +#define ICSTART_ICSTART 0x10 + static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data) { if (offs == ICIC) @@ -726,7 +730,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter); struct i2c_msg *msg; int err = 0; - int i, k; + int i; + long timeout; activate_ch(pd); @@ -745,10 +750,10 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, i2c_op(pd, OP_START, 0); /* The interrupt handler takes care of the rest... */ - k = wait_event_timeout(pd->wait, + timeout = wait_event_timeout(pd->wait, pd->sr & (ICSR_TACK | SW_DONE), - 5 * HZ); - if (!k) { + adapter->timeout); + if (!timeout) { dev_err(pd->dev, "Transfer request timed out\n"); if (pd->dma_direction != DMA_NONE) sh_mobile_i2c_cleanup_dma(pd); @@ -782,6 +787,33 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; +/* + * r8a7740 chip has lasting errata on I2C I/O pad reset. + * this is work-around for it. + */ +static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) +{ + iic_set_clr(pd, ICCR, ICCR_ICE, 0); + iic_rd(pd, ICCR); /* dummy read */ + + iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0); + iic_rd(pd, ICSTART); /* dummy read */ + + udelay(10); + + iic_wr(pd, ICCR, ICCR_SCP); + iic_wr(pd, ICSTART, 0); + + udelay(10); + + iic_wr(pd, ICCR, ICCR_TRS); + udelay(10); + iic_wr(pd, ICCR, 0); + udelay(10); + iic_wr(pd, ICCR, ICCR_TRS); + udelay(10); +} + static const struct sh_mobile_dt_config default_dt_config = { .clks_per_count = 1, }; @@ -790,14 +822,21 @@ static const struct sh_mobile_dt_config fast_clock_dt_config = { .clks_per_count = 2, }; +static const struct sh_mobile_dt_config r8a7740_dt_config = { + .clks_per_count = 1, + .setup = sh_mobile_i2c_r8a7740_workaround, +}; + static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config }, {}, }; @@ -885,6 +924,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) config = match->data; pd->clks_per_count = config->clks_per_count; + + if (config->setup) + config->setup(pd); } } else { if (pdata && pdata->bus_speed) diff --git a/kernel/drivers/i2c/busses/i2c-sirf.c b/kernel/drivers/i2c/busses/i2c-sirf.c index 1092d4eee..13e51ef6a 100644 --- a/kernel/drivers/i2c/busses/i2c-sirf.c +++ b/kernel/drivers/i2c/busses/i2c-sirf.c @@ -358,11 +358,29 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) if (err < 0) bitrate = SIRFSOC_I2C_DEFAULT_SPEED; - if (bitrate < 100000) - regval = - (2 * ctrl_speed) / (bitrate * 11); - else + /* + * Due to some hardware design issues, we need to tune the formula. + * Since i2c is open drain interface that allows the slave to + * stall the transaction by holding the SCL line at '0', the RTL + * implementation is waiting for SCL feedback from the pin after + * setting it to High-Z ('1'). This wait adds to the high-time + * interval counter few cycles of the input synchronization + * (depending on the SCL_FILTER_REG field), and also the time it + * takes for the board pull-up resistor to rise the SCL line. + * For slow SCL settings these additions are negligible, + * but they start to affect the speed when clock is set to faster + * frequencies. + * Through the actual tests, use the different user_div value(which + * in the divider formular 'Fio / (Fi2c * user_div)') to adapt + * the different ranges of i2c bus clock frequency, to make the SCL + * more accurate. + */ + if (bitrate <= 30000) regval = ctrl_speed / (bitrate * 5); + else if (bitrate > 30000 && bitrate <= 280000) + regval = (2 * ctrl_speed) / (bitrate * 11); + else + regval = ctrl_speed / (bitrate * 6); writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL); if (regval > 0xFF) diff --git a/kernel/drivers/i2c/busses/i2c-st.c b/kernel/drivers/i2c/busses/i2c-st.c index ea72dca32..25020ec77 100644 --- a/kernel/drivers/i2c/busses/i2c-st.c +++ b/kernel/drivers/i2c/busses/i2c-st.c @@ -822,7 +822,7 @@ static int st_i2c_probe(struct platform_device *pdev) adap = &i2c_dev->adap; i2c_set_adapdata(adap, i2c_dev); - snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%pa)", &res->start); + snprintf(adap->name, sizeof(adap->name), "ST I2C(%pa)", &res->start); adap->owner = THIS_MODULE; adap->timeout = 2 * HZ; adap->retries = 0; diff --git a/kernel/drivers/i2c/busses/i2c-stu300.c b/kernel/drivers/i2c/busses/i2c-stu300.c index 4885da9e9..460c13483 100644 --- a/kernel/drivers/i2c/busses/i2c-stu300.c +++ b/kernel/drivers/i2c/busses/i2c-stu300.c @@ -977,6 +977,7 @@ static const struct of_device_id stu300_dt_match[] = { { .compatible = "st,ddci2c" }, {}, }; +MODULE_DEVICE_TABLE(of, stu300_dt_match); static struct platform_driver stu300_i2c_driver = { .driver = { diff --git a/kernel/drivers/i2c/busses/i2c-tegra.c b/kernel/drivers/i2c/busses/i2c-tegra.c index 1bcd75ea0..a0522fcc4 100644 --- a/kernel/drivers/i2c/busses/i2c-tegra.c +++ b/kernel/drivers/i2c/busses/i2c-tegra.c @@ -100,6 +100,12 @@ #define I2C_HEADER_CONTINUE_XFER (1<<15) #define I2C_HEADER_MASTER_ADDR_SHIFT 12 #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 + +#define I2C_CONFIG_LOAD 0x08C +#define I2C_MSTR_CONFIG_LOAD (1 << 0) +#define I2C_SLV_CONFIG_LOAD (1 << 1) +#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) + /* * msg_end_type: The bus control which need to be send at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer. @@ -121,6 +127,8 @@ enum msg_end_type { * @has_single_clk_source: The i2c controller has single clock source. Tegra30 * and earlier Socs has two clock sources i.e. div-clk and * fast-clk. + * @has_config_load_reg: Has the config load register to load the new + * configuration. * @clk_divisor_hs_mode: Clock divisor in HS mode. * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is * applicable if there is no fast clock source i.e. single clock @@ -131,8 +139,10 @@ struct tegra_i2c_hw_feature { bool has_continue_xfer_support; bool has_per_pkt_xfer_complete_irq; bool has_single_clk_source; + bool has_config_load_reg; int clk_divisor_hs_mode; int clk_divisor_std_fast_mode; + u16 clk_divisor_fast_plus_mode; }; /** @@ -172,6 +182,7 @@ struct tegra_i2c_dev { size_t msg_buf_remaining; int msg_read; u32 bus_clk_rate; + u16 clk_divisor_non_hs_mode; bool is_suspended; }; @@ -410,6 +421,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) u32 val; int err = 0; u32 clk_divisor; + unsigned long timeout = jiffies + HZ; err = tegra_i2c_clock_enable(i2c_dev); if (err < 0) { @@ -431,7 +443,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) /* Make sure clock divisor programmed correctly */ clk_divisor = i2c_dev->hw->clk_divisor_hs_mode; - clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode << + clk_divisor |= i2c_dev->clk_divisor_non_hs_mode << I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT; i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR); @@ -451,6 +463,18 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (tegra_i2c_flush_fifos(i2c_dev)) err = -ETIMEDOUT; + if (i2c_dev->hw->has_config_load_reg) { + i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); + while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c_dev->dev, + "timeout waiting for config load\n"); + return -ETIMEDOUT; + } + msleep(1); + } + } + tegra_i2c_clock_disable(i2c_dev); if (i2c_dev->irq_disabled) { @@ -656,8 +680,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], static u32 tegra_i2c_func(struct i2c_adapter *adap) { struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - u32 ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING; + u32 ret = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; if (i2c_dev->hw->has_continue_xfer_support) ret |= I2C_FUNC_NOSTART; @@ -669,12 +693,20 @@ static const struct i2c_algorithm tegra_i2c_algo = { .functionality = tegra_i2c_func, }; +/* payload size is only 12 bit */ +static struct i2c_adapter_quirks tegra_i2c_quirks = { + .max_read_len = 4096, + .max_write_len = 4096, +}; + static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_continue_xfer_support = false, .has_per_pkt_xfer_complete_irq = false, .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .clk_divisor_fast_plus_mode = 0, + .has_config_load_reg = false, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -683,6 +715,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .clk_divisor_fast_plus_mode = 0, + .has_config_load_reg = false, }; static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -691,10 +725,23 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_single_clk_source = true, .clk_divisor_hs_mode = 1, .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, + .has_config_load_reg = false, +}; + +static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .has_single_clk_source = true, + .clk_divisor_hs_mode = 1, + .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, + .has_config_load_reg = true, }; /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, @@ -739,6 +786,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->base = base; i2c_dev->div_clk = div_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; + i2c_dev->adapter.quirks = &tegra_i2c_quirks; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; @@ -786,7 +834,14 @@ static int tegra_i2c_probe(struct platform_device *pdev) } } - clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1); + i2c_dev->clk_divisor_non_hs_mode = + i2c_dev->hw->clk_divisor_std_fast_mode; + if (i2c_dev->hw->clk_divisor_fast_plus_mode && + (i2c_dev->bus_clk_rate == 1000000)) + i2c_dev->clk_divisor_non_hs_mode = + i2c_dev->hw->clk_divisor_fast_plus_mode; + + clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1); ret = clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * clk_multiplier); if (ret) { @@ -818,7 +873,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->adapter.class = I2C_CLASS_DEPRECATED; strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter", sizeof(i2c_dev->adapter.name)); - i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; i2c_dev->adapter.dev.of_node = pdev->dev.of_node; diff --git a/kernel/drivers/i2c/busses/i2c-uniphier-f.c b/kernel/drivers/i2c/busses/i2c-uniphier-f.c new file mode 100644 index 000000000..e8d03bcfe --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-uniphier-f.c @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.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. + */ + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define UNIPHIER_FI2C_CR 0x00 /* control register */ +#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */ +#define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */ +#define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */ +#define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */ +#define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */ +#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */ +#define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */ +#define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */ +#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */ +#define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */ +#define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */ +#define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */ +#define UNIPHIER_FI2C_DSUT 0x1c /* data setup time control */ +#define UNIPHIER_FI2C_INT 0x20 /* interrupt status */ +#define UNIPHIER_FI2C_IE 0x24 /* interrupt enable */ +#define UNIPHIER_FI2C_IC 0x28 /* interrupt clear */ +#define UNIPHIER_FI2C_INT_TE BIT(9) /* TX FIFO empty */ +#define UNIPHIER_FI2C_INT_RF BIT(8) /* RX FIFO full */ +#define UNIPHIER_FI2C_INT_TC BIT(7) /* send complete (STOP) */ +#define UNIPHIER_FI2C_INT_RC BIT(6) /* receive complete (STOP) */ +#define UNIPHIER_FI2C_INT_TB BIT(5) /* sent specified bytes */ +#define UNIPHIER_FI2C_INT_RB BIT(4) /* received specified bytes */ +#define UNIPHIER_FI2C_INT_NA BIT(2) /* no ACK */ +#define UNIPHIER_FI2C_INT_AL BIT(1) /* arbitration lost */ +#define UNIPHIER_FI2C_SR 0x2c /* status register */ +#define UNIPHIER_FI2C_SR_DB BIT(12) /* device busy */ +#define UNIPHIER_FI2C_SR_STS BIT(11) /* stop condition detected */ +#define UNIPHIER_FI2C_SR_BB BIT(8) /* bus busy */ +#define UNIPHIER_FI2C_SR_RFF BIT(3) /* RX FIFO full */ +#define UNIPHIER_FI2C_SR_RNE BIT(2) /* RX FIFO not empty */ +#define UNIPHIER_FI2C_SR_TNF BIT(1) /* TX FIFO not full */ +#define UNIPHIER_FI2C_SR_TFE BIT(0) /* TX FIFO empty */ +#define UNIPHIER_FI2C_RST 0x34 /* reset control */ +#define UNIPHIER_FI2C_RST_TBRST BIT(2) /* clear TX FIFO */ +#define UNIPHIER_FI2C_RST_RBRST BIT(1) /* clear RX FIFO */ +#define UNIPHIER_FI2C_RST_RST BIT(0) /* forcible bus reset */ +#define UNIPHIER_FI2C_BM 0x38 /* bus monitor */ +#define UNIPHIER_FI2C_BM_SDAO BIT(3) /* output for SDA line */ +#define UNIPHIER_FI2C_BM_SDAS BIT(2) /* readback of SDA line */ +#define UNIPHIER_FI2C_BM_SCLO BIT(1) /* output for SCL line */ +#define UNIPHIER_FI2C_BM_SCLS BIT(0) /* readback of SCL line */ +#define UNIPHIER_FI2C_NOISE 0x3c /* noise filter control */ +#define UNIPHIER_FI2C_TBC 0x40 /* TX byte count setting */ +#define UNIPHIER_FI2C_RBC 0x44 /* RX byte count setting */ +#define UNIPHIER_FI2C_TBCM 0x48 /* TX byte count monitor */ +#define UNIPHIER_FI2C_RBCM 0x4c /* RX byte count monitor */ +#define UNIPHIER_FI2C_BRST 0x50 /* bus reset */ +#define UNIPHIER_FI2C_BRST_FOEN BIT(1) /* normal operation */ +#define UNIPHIER_FI2C_BRST_RSCL BIT(0) /* release SCL */ + +#define UNIPHIER_FI2C_INT_FAULTS \ + (UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL) +#define UNIPHIER_FI2C_INT_STOP \ + (UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC) + +#define UNIPHIER_FI2C_RD BIT(0) +#define UNIPHIER_FI2C_STOP BIT(1) +#define UNIPHIER_FI2C_MANUAL_NACK BIT(2) +#define UNIPHIER_FI2C_BYTE_WISE BIT(3) +#define UNIPHIER_FI2C_DEFER_STOP_COMP BIT(4) + +#define UNIPHIER_FI2C_DEFAULT_SPEED 100000 +#define UNIPHIER_FI2C_MAX_SPEED 400000 +#define UNIPHIER_FI2C_FIFO_SIZE 8 + +struct uniphier_fi2c_priv { + struct completion comp; + struct i2c_adapter adap; + void __iomem *membase; + struct clk *clk; + unsigned int len; + u8 *buf; + u32 enabled_irqs; + int error; + unsigned int flags; + unsigned int busy_cnt; +}; + +static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, + bool first) +{ + int fifo_space = UNIPHIER_FI2C_FIFO_SIZE; + + /* + * TX-FIFO stores slave address in it for the first access. + * Decrement the counter. + */ + if (first) + fifo_space--; + + while (priv->len) { + if (fifo_space-- <= 0) + break; + + dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf); + writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX); + priv->len--; + } +} + +static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv) +{ + int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ? + 1 : UNIPHIER_FI2C_FIFO_SIZE; + + while (priv->len) { + if (fifo_left-- <= 0) + break; + + *priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX); + dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]); + priv->len--; + } +} + +static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv) +{ + writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE); +} + +static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv) +{ + writel(-1, priv->membase + UNIPHIER_FI2C_IC); +} + +static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv) +{ + dev_dbg(&priv->adap.dev, "stop condition\n"); + + priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP; + uniphier_fi2c_set_irqs(priv); + writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO, + priv->membase + UNIPHIER_FI2C_CR); +} + +static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) +{ + struct uniphier_fi2c_priv *priv = dev_id; + u32 irq_status; + + irq_status = readl(priv->membase + UNIPHIER_FI2C_INT); + + dev_dbg(&priv->adap.dev, + "interrupt: enabled_irqs=%04x, irq_status=%04x\n", + priv->enabled_irqs, irq_status); + + if (irq_status & UNIPHIER_FI2C_INT_STOP) + goto complete; + + if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) { + dev_dbg(&priv->adap.dev, "arbitration lost\n"); + priv->error = -EAGAIN; + goto complete; + } + + if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) { + dev_dbg(&priv->adap.dev, "could not get ACK\n"); + priv->error = -ENXIO; + if (priv->flags & UNIPHIER_FI2C_RD) { + /* + * work around a hardware bug: + * The receive-completed interrupt is never set even if + * STOP condition is detected after the address phase + * of read transaction fails to get ACK. + * To avoid time-out error, we issue STOP here, + * but do not wait for its completion. + * It should be checked after exiting this handler. + */ + uniphier_fi2c_stop(priv); + priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP; + goto complete; + } + goto stop; + } + + if (irq_status & UNIPHIER_FI2C_INT_TE) { + if (!priv->len) + goto data_done; + + uniphier_fi2c_fill_txfifo(priv, false); + goto handled; + } + + if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) { + uniphier_fi2c_drain_rxfifo(priv); + if (!priv->len) + goto data_done; + + if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) { + if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE && + !(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) { + dev_dbg(&priv->adap.dev, + "enable read byte count IRQ\n"); + priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB; + uniphier_fi2c_set_irqs(priv); + priv->flags |= UNIPHIER_FI2C_BYTE_WISE; + } + if (priv->len <= 1) { + dev_dbg(&priv->adap.dev, "set NACK\n"); + writel(UNIPHIER_FI2C_CR_MST | + UNIPHIER_FI2C_CR_NACK, + priv->membase + UNIPHIER_FI2C_CR); + } + } + + goto handled; + } + + return IRQ_NONE; + +data_done: + if (priv->flags & UNIPHIER_FI2C_STOP) { +stop: + uniphier_fi2c_stop(priv); + } else { +complete: + priv->enabled_irqs = 0; + uniphier_fi2c_set_irqs(priv); + complete(&priv->comp); + } + +handled: + uniphier_fi2c_clear_irqs(priv); + + return IRQ_HANDLED; +} + +static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr) +{ + priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE; + /* do not use TX byte counter */ + writel(0, priv->membase + UNIPHIER_FI2C_TBC); + /* set slave address */ + writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1, + priv->membase + UNIPHIER_FI2C_DTTX); + /* first chunk of data */ + uniphier_fi2c_fill_txfifo(priv, true); +} + +static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr) +{ + priv->flags |= UNIPHIER_FI2C_RD; + + if (likely(priv->len < 256)) { + /* + * If possible, use RX byte counter. + * It can automatically handle NACK for the last byte. + */ + writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC); + priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF | + UNIPHIER_FI2C_INT_RB; + } else { + /* + * The byte counter can not count over 256. In this case, + * do not use it at all. Drain data when FIFO gets full, + * but treat the last portion as a special case. + */ + writel(0, priv->membase + UNIPHIER_FI2C_RBC); + priv->flags |= UNIPHIER_FI2C_MANUAL_NACK; + priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF; + } + + /* set slave address with RD bit */ + writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1, + priv->membase + UNIPHIER_FI2C_DTTX); +} + +static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv) +{ + writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST); +} + +static void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv) +{ + writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL, + priv->membase + UNIPHIER_FI2C_BRST); +} + +static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) +{ + uniphier_fi2c_reset(priv); + i2c_recover_bus(&priv->adap); +} + +static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, + struct i2c_msg *msg, bool stop) +{ + struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); + bool is_read = msg->flags & I2C_M_RD; + unsigned long time_left; + + dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", + is_read ? "receive" : "transmit", msg->addr, msg->len, stop); + + priv->len = msg->len; + priv->buf = msg->buf; + priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS; + priv->error = 0; + priv->flags = 0; + + if (stop) + priv->flags |= UNIPHIER_FI2C_STOP; + + reinit_completion(&priv->comp); + uniphier_fi2c_clear_irqs(priv); + writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST, + priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */ + + if (is_read) + uniphier_fi2c_rx_init(priv, msg->addr); + else + uniphier_fi2c_tx_init(priv, msg->addr); + + uniphier_fi2c_set_irqs(priv); + + dev_dbg(&adap->dev, "start condition\n"); + writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA, + priv->membase + UNIPHIER_FI2C_CR); + + time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); + if (!time_left) { + dev_err(&adap->dev, "transaction timeout.\n"); + uniphier_fi2c_recover(priv); + return -ETIMEDOUT; + } + dev_dbg(&adap->dev, "complete\n"); + + if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) { + u32 status = readl(priv->membase + UNIPHIER_FI2C_SR); + + if (!(status & UNIPHIER_FI2C_SR_STS) || + status & UNIPHIER_FI2C_SR_BB) { + dev_err(&adap->dev, + "stop condition was not completed.\n"); + uniphier_fi2c_recover(priv); + return -EBUSY; + } + } + + return priv->error; +} + +static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap) +{ + struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); + + if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) { + if (priv->busy_cnt++ > 3) { + /* + * If bus busy continues too long, it is probably + * in a wrong state. Try bus recovery. + */ + uniphier_fi2c_recover(priv); + priv->busy_cnt = 0; + } + + return -EAGAIN; + } + + priv->busy_cnt = 0; + return 0; +} + +static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct i2c_msg *msg, *emsg = msgs + num; + int ret; + + ret = uniphier_fi2c_check_bus_busy(adap); + if (ret) + return ret; + + for (msg = msgs; msg < emsg; msg++) { + /* If next message is read, skip the stop condition */ + bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD); + /* but, force it if I2C_M_STOP is set */ + if (msg->flags & I2C_M_STOP) + stop = true; + + ret = uniphier_fi2c_master_xfer_one(adap, msg, stop); + if (ret) + return ret; + } + + return num; +} + +static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm uniphier_fi2c_algo = { + .master_xfer = uniphier_fi2c_master_xfer, + .functionality = uniphier_fi2c_functionality, +}; + +static int uniphier_fi2c_get_scl(struct i2c_adapter *adap) +{ + struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); + + return !!(readl(priv->membase + UNIPHIER_FI2C_BM) & + UNIPHIER_FI2C_BM_SCLS); +} + +static void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); + + writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0, + priv->membase + UNIPHIER_FI2C_BRST); +} + +static int uniphier_fi2c_get_sda(struct i2c_adapter *adap) +{ + struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); + + return !!(readl(priv->membase + UNIPHIER_FI2C_BM) & + UNIPHIER_FI2C_BM_SDAS); +} + +static void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap) +{ + uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap)); +} + +static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .get_scl = uniphier_fi2c_get_scl, + .set_scl = uniphier_fi2c_set_scl, + .get_sda = uniphier_fi2c_get_sda, + .unprepare_recovery = uniphier_fi2c_unprepare_recovery, +}; + +static int uniphier_fi2c_clk_init(struct device *dev, + struct uniphier_fi2c_priv *priv) +{ + struct device_node *np = dev->of_node; + unsigned long clk_rate; + u32 bus_speed, clk_count; + int ret; + + if (of_property_read_u32(np, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED; + + if (bus_speed > UNIPHIER_FI2C_MAX_SPEED) + bus_speed = UNIPHIER_FI2C_MAX_SPEED; + + /* Get input clk rate through clk driver */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(priv->clk); + + uniphier_fi2c_reset(priv); + + clk_count = clk_rate / bus_speed; + + writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC); + writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL); + writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT); + writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT); + + uniphier_fi2c_prepare_operation(priv); + + return 0; +} + +static int uniphier_fi2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_fi2c_priv *priv; + struct resource *regs; + int irq; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->membase = devm_ioremap_resource(dev, regs); + if (IS_ERR(priv->membase)) + return PTR_ERR(priv->membase); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number"); + return irq; + } + + init_completion(&priv->comp); + priv->adap.owner = THIS_MODULE; + priv->adap.algo = &uniphier_fi2c_algo; + priv->adap.dev.parent = dev; + priv->adap.dev.of_node = dev->of_node; + strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name)); + priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info; + i2c_set_adapdata(&priv->adap, priv); + platform_set_drvdata(pdev, priv); + + ret = uniphier_fi2c_clk_init(dev, priv); + if (ret) + return ret; + + ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, + pdev->name, priv); + if (ret) { + dev_err(dev, "failed to request irq %d\n", irq); + goto err; + } + + ret = i2c_add_adapter(&priv->adap); + if (ret) { + dev_err(dev, "failed to add I2C adapter\n"); + goto err; + } + +err: + if (ret) + clk_disable_unprepare(priv->clk); + + return ret; +} + +static int uniphier_fi2c_remove(struct platform_device *pdev) +{ + struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev); + + i2c_del_adapter(&priv->adap); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id uniphier_fi2c_match[] = { + { .compatible = "socionext,uniphier-fi2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_fi2c_match); + +static struct platform_driver uniphier_fi2c_drv = { + .probe = uniphier_fi2c_probe, + .remove = uniphier_fi2c_remove, + .driver = { + .name = "uniphier-fi2c", + .of_match_table = uniphier_fi2c_match, + }, +}; +module_platform_driver(uniphier_fi2c_drv); + +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); +MODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/i2c/busses/i2c-uniphier.c b/kernel/drivers/i2c/busses/i2c-uniphier.c new file mode 100644 index 000000000..e3c3861c3 --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-uniphier.c @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.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. + */ + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define UNIPHIER_I2C_DTRM 0x00 /* TX register */ +#define UNIPHIER_I2C_DTRM_IRQEN BIT(11) /* enable interrupt */ +#define UNIPHIER_I2C_DTRM_STA BIT(10) /* start condition */ +#define UNIPHIER_I2C_DTRM_STO BIT(9) /* stop condition */ +#define UNIPHIER_I2C_DTRM_NACK BIT(8) /* do not return ACK */ +#define UNIPHIER_I2C_DTRM_RD BIT(0) /* read transaction */ +#define UNIPHIER_I2C_DREC 0x04 /* RX register */ +#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = master, 0 = slave */ +#define UNIPHIER_I2C_DREC_TX BIT(13) /* 1 = transmit, 0 = receive */ +#define UNIPHIER_I2C_DREC_STS BIT(12) /* stop condition detected */ +#define UNIPHIER_I2C_DREC_LRB BIT(11) /* no ACK */ +#define UNIPHIER_I2C_DREC_LAB BIT(9) /* arbitration lost */ +#define UNIPHIER_I2C_DREC_BBN BIT(8) /* bus not busy */ +#define UNIPHIER_I2C_MYAD 0x08 /* slave address */ +#define UNIPHIER_I2C_CLK 0x0c /* clock frequency control */ +#define UNIPHIER_I2C_BRST 0x10 /* bus reset */ +#define UNIPHIER_I2C_BRST_FOEN BIT(1) /* normal operation */ +#define UNIPHIER_I2C_BRST_RSCL BIT(0) /* release SCL */ +#define UNIPHIER_I2C_HOLD 0x14 /* hold time control */ +#define UNIPHIER_I2C_BSTS 0x18 /* bus status monitor */ +#define UNIPHIER_I2C_BSTS_SDA BIT(1) /* readback of SDA line */ +#define UNIPHIER_I2C_BSTS_SCL BIT(0) /* readback of SCL line */ +#define UNIPHIER_I2C_NOISE 0x1c /* noise filter control */ +#define UNIPHIER_I2C_SETUP 0x20 /* setup time control */ + +#define UNIPHIER_I2C_DEFAULT_SPEED 100000 +#define UNIPHIER_I2C_MAX_SPEED 400000 + +struct uniphier_i2c_priv { + struct completion comp; + struct i2c_adapter adap; + void __iomem *membase; + struct clk *clk; + unsigned int busy_cnt; +}; + +static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id) +{ + struct uniphier_i2c_priv *priv = dev_id; + + /* + * This hardware uses edge triggered interrupt. Do not touch the + * hardware registers in this handler to make sure to catch the next + * interrupt edge. Just send a complete signal and return. + */ + complete(&priv->comp); + + return IRQ_HANDLED; +} + +static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata, + u32 *rxdatap) +{ + struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); + unsigned long time_left; + u32 rxdata; + + reinit_completion(&priv->comp); + + txdata |= UNIPHIER_I2C_DTRM_IRQEN; + dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata); + writel(txdata, priv->membase + UNIPHIER_I2C_DTRM); + + time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); + if (unlikely(!time_left)) { + dev_err(&adap->dev, "transaction timeout\n"); + return -ETIMEDOUT; + } + + rxdata = readl(priv->membase + UNIPHIER_I2C_DREC); + dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata); + + if (rxdatap) + *rxdatap = rxdata; + + return 0; +} + +static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata) +{ + u32 rxdata; + int ret; + + ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata); + if (ret) + return ret; + + if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) { + dev_dbg(&adap->dev, "arbitration lost\n"); + return -EAGAIN; + } + if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) { + dev_dbg(&adap->dev, "could not get ACK\n"); + return -ENXIO; + } + + return 0; +} + +static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len, + const u8 *buf) +{ + int ret; + + dev_dbg(&adap->dev, "start condition\n"); + ret = uniphier_i2c_send_byte(adap, addr << 1 | + UNIPHIER_I2C_DTRM_STA | + UNIPHIER_I2C_DTRM_NACK); + if (ret) + return ret; + + while (len--) { + ret = uniphier_i2c_send_byte(adap, + UNIPHIER_I2C_DTRM_NACK | *buf++); + if (ret) + return ret; + } + + return 0; +} + +static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len, + u8 *buf) +{ + int ret; + + dev_dbg(&adap->dev, "start condition\n"); + ret = uniphier_i2c_send_byte(adap, addr << 1 | + UNIPHIER_I2C_DTRM_STA | + UNIPHIER_I2C_DTRM_NACK | + UNIPHIER_I2C_DTRM_RD); + if (ret) + return ret; + + while (len--) { + u32 rxdata; + + ret = uniphier_i2c_xfer_byte(adap, + len ? 0 : UNIPHIER_I2C_DTRM_NACK, + &rxdata); + if (ret) + return ret; + *buf++ = rxdata; + } + + return 0; +} + +static int uniphier_i2c_stop(struct i2c_adapter *adap) +{ + dev_dbg(&adap->dev, "stop condition\n"); + return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO | + UNIPHIER_I2C_DTRM_NACK); +} + +static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap, + struct i2c_msg *msg, bool stop) +{ + bool is_read = msg->flags & I2C_M_RD; + bool recovery = false; + int ret; + + dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", + is_read ? "receive" : "transmit", msg->addr, msg->len, stop); + + if (is_read) + ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf); + else + ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf); + + if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */ + return ret; + + if (ret == -ETIMEDOUT) { + /* This error is fatal. Needs recovery. */ + stop = false; + recovery = true; + } + + if (stop) { + int ret2 = uniphier_i2c_stop(adap); + + if (ret2) { + /* Failed to issue STOP. The bus needs recovery. */ + recovery = true; + ret = ret ?: ret2; + } + } + + if (recovery) + i2c_recover_bus(adap); + + return ret; +} + +static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap) +{ + struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); + + if (!(readl(priv->membase + UNIPHIER_I2C_DREC) & + UNIPHIER_I2C_DREC_BBN)) { + if (priv->busy_cnt++ > 3) { + /* + * If bus busy continues too long, it is probably + * in a wrong state. Try bus recovery. + */ + i2c_recover_bus(adap); + priv->busy_cnt = 0; + } + + return -EAGAIN; + } + + priv->busy_cnt = 0; + return 0; +} + +static int uniphier_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct i2c_msg *msg, *emsg = msgs + num; + int ret; + + ret = uniphier_i2c_check_bus_busy(adap); + if (ret) + return ret; + + for (msg = msgs; msg < emsg; msg++) { + /* If next message is read, skip the stop condition */ + bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD); + /* but, force it if I2C_M_STOP is set */ + if (msg->flags & I2C_M_STOP) + stop = true; + + ret = uniphier_i2c_master_xfer_one(adap, msg, stop); + if (ret) + return ret; + } + + return num; +} + +static u32 uniphier_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm uniphier_i2c_algo = { + .master_xfer = uniphier_i2c_master_xfer, + .functionality = uniphier_i2c_functionality, +}; + +static void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on) +{ + u32 val = UNIPHIER_I2C_BRST_RSCL; + + val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN; + writel(val, priv->membase + UNIPHIER_I2C_BRST); +} + +static int uniphier_i2c_get_scl(struct i2c_adapter *adap) +{ + struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); + + return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) & + UNIPHIER_I2C_BSTS_SCL); +} + +static void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); + + writel(val ? UNIPHIER_I2C_BRST_RSCL : 0, + priv->membase + UNIPHIER_I2C_BRST); +} + +static int uniphier_i2c_get_sda(struct i2c_adapter *adap) +{ + struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap); + + return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) & + UNIPHIER_I2C_BSTS_SDA); +} + +static void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap) +{ + uniphier_i2c_reset(i2c_get_adapdata(adap), false); +} + +static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = { + .recover_bus = i2c_generic_scl_recovery, + .get_scl = uniphier_i2c_get_scl, + .set_scl = uniphier_i2c_set_scl, + .get_sda = uniphier_i2c_get_sda, + .unprepare_recovery = uniphier_i2c_unprepare_recovery, +}; + +static int uniphier_i2c_clk_init(struct device *dev, + struct uniphier_i2c_priv *priv) +{ + struct device_node *np = dev->of_node; + unsigned long clk_rate; + u32 bus_speed; + int ret; + + if (of_property_read_u32(np, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_I2C_DEFAULT_SPEED; + + if (bus_speed > UNIPHIER_I2C_MAX_SPEED) + bus_speed = UNIPHIER_I2C_MAX_SPEED; + + /* Get input clk rate through clk driver */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(priv->clk); + + uniphier_i2c_reset(priv, true); + + writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed), + priv->membase + UNIPHIER_I2C_CLK); + + uniphier_i2c_reset(priv, false); + + return 0; +} + +static int uniphier_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_i2c_priv *priv; + struct resource *regs; + int irq; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->membase = devm_ioremap_resource(dev, regs); + if (IS_ERR(priv->membase)) + return PTR_ERR(priv->membase); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number"); + return irq; + } + + init_completion(&priv->comp); + priv->adap.owner = THIS_MODULE; + priv->adap.algo = &uniphier_i2c_algo; + priv->adap.dev.parent = dev; + priv->adap.dev.of_node = dev->of_node; + strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name)); + priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info; + i2c_set_adapdata(&priv->adap, priv); + platform_set_drvdata(pdev, priv); + + ret = uniphier_i2c_clk_init(dev, priv); + if (ret) + return ret; + + ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, + priv); + if (ret) { + dev_err(dev, "failed to request irq %d\n", irq); + goto err; + } + + ret = i2c_add_adapter(&priv->adap); + if (ret) { + dev_err(dev, "failed to add I2C adapter\n"); + goto err; + } + +err: + if (ret) + clk_disable_unprepare(priv->clk); + + return ret; +} + +static int uniphier_i2c_remove(struct platform_device *pdev) +{ + struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev); + + i2c_del_adapter(&priv->adap); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id uniphier_i2c_match[] = { + { .compatible = "socionext,uniphier-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_i2c_match); + +static struct platform_driver uniphier_i2c_drv = { + .probe = uniphier_i2c_probe, + .remove = uniphier_i2c_remove, + .driver = { + .name = "uniphier-i2c", + .of_match_table = uniphier_i2c_match, + }, +}; +module_platform_driver(uniphier_i2c_drv); + +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); +MODULE_DESCRIPTION("UniPhier I2C bus driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/i2c/busses/i2c-viperboard.c b/kernel/drivers/i2c/busses/i2c-viperboard.c index 47e88adf2..543456a0a 100644 --- a/kernel/drivers/i2c/busses/i2c-viperboard.c +++ b/kernel/drivers/i2c/busses/i2c-viperboard.c @@ -391,11 +391,11 @@ static int vprbrd_i2c_probe(struct platform_device *pdev) VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1, VPRBRD_USB_TIMEOUT_MS); - if (ret != 1) { - dev_err(&pdev->dev, - "failure setting i2c_bus_freq to %d\n", i2c_bus_freq); - return -EIO; - } + if (ret != 1) { + dev_err(&pdev->dev, "failure setting i2c_bus_freq to %d\n", + i2c_bus_freq); + return -EIO; + } } else { dev_err(&pdev->dev, "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq); diff --git a/kernel/drivers/i2c/busses/i2c-xgene-slimpro.c b/kernel/drivers/i2c/busses/i2c-xgene-slimpro.c new file mode 100644 index 000000000..4233f5695 --- /dev/null +++ b/kernel/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -0,0 +1,470 @@ +/* + * X-Gene SLIMpro I2C Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Feng Kan <fkan@apm.com> + * Author: Hieu Le <hnle@apm.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, see <http://www.gnu.org/licenses/>. + * + * This driver provides support for X-Gene SLIMpro I2C device access + * using the APM X-Gene SLIMpro mailbox driver. + * + */ +#include <linux/acpi.h> +#include <linux/dma-mapping.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/version.h> + +#define MAILBOX_OP_TIMEOUT 1000 /* Operation time out in ms */ +#define MAILBOX_I2C_INDEX 0 +#define SLIMPRO_IIC_BUS 1 /* Use I2C bus 1 only */ + +#define SMBUS_CMD_LEN 1 +#define BYTE_DATA 1 +#define WORD_DATA 2 +#define BLOCK_DATA 3 + +#define SLIMPRO_IIC_I2C_PROTOCOL 0 +#define SLIMPRO_IIC_SMB_PROTOCOL 1 + +#define SLIMPRO_IIC_READ 0 +#define SLIMPRO_IIC_WRITE 1 + +#define IIC_SMB_WITHOUT_DATA_LEN 0 +#define IIC_SMB_WITH_DATA_LEN 1 + +#define SLIMPRO_DEBUG_MSG 0 +#define SLIMPRO_MSG_TYPE_SHIFT 28 +#define SLIMPRO_DBG_SUBTYPE_I2C1READ 4 +#define SLIMPRO_DBGMSG_TYPE_SHIFT 24 +#define SLIMPRO_DBGMSG_TYPE_MASK 0x0F000000U +#define SLIMPRO_IIC_DEV_SHIFT 23 +#define SLIMPRO_IIC_DEV_MASK 0x00800000U +#define SLIMPRO_IIC_DEVID_SHIFT 13 +#define SLIMPRO_IIC_DEVID_MASK 0x007FE000U +#define SLIMPRO_IIC_RW_SHIFT 12 +#define SLIMPRO_IIC_RW_MASK 0x00001000U +#define SLIMPRO_IIC_PROTO_SHIFT 11 +#define SLIMPRO_IIC_PROTO_MASK 0x00000800U +#define SLIMPRO_IIC_ADDRLEN_SHIFT 8 +#define SLIMPRO_IIC_ADDRLEN_MASK 0x00000700U +#define SLIMPRO_IIC_DATALEN_SHIFT 0 +#define SLIMPRO_IIC_DATALEN_MASK 0x000000FFU + +/* + * SLIMpro I2C message encode + * + * dev - Controller number (0-based) + * chip - I2C chip address + * op - SLIMPRO_IIC_READ or SLIMPRO_IIC_WRITE + * proto - SLIMPRO_IIC_SMB_PROTOCOL or SLIMPRO_IIC_I2C_PROTOCOL + * addrlen - Length of the address field + * datalen - Length of the data field + */ +#define SLIMPRO_IIC_ENCODE_MSG(dev, chip, op, proto, addrlen, datalen) \ + ((SLIMPRO_DEBUG_MSG << SLIMPRO_MSG_TYPE_SHIFT) | \ + ((SLIMPRO_DBG_SUBTYPE_I2C1READ << SLIMPRO_DBGMSG_TYPE_SHIFT) & \ + SLIMPRO_DBGMSG_TYPE_MASK) | \ + ((dev << SLIMPRO_IIC_DEV_SHIFT) & SLIMPRO_IIC_DEV_MASK) | \ + ((chip << SLIMPRO_IIC_DEVID_SHIFT) & SLIMPRO_IIC_DEVID_MASK) | \ + ((op << SLIMPRO_IIC_RW_SHIFT) & SLIMPRO_IIC_RW_MASK) | \ + ((proto << SLIMPRO_IIC_PROTO_SHIFT) & SLIMPRO_IIC_PROTO_MASK) | \ + ((addrlen << SLIMPRO_IIC_ADDRLEN_SHIFT) & SLIMPRO_IIC_ADDRLEN_MASK) | \ + ((datalen << SLIMPRO_IIC_DATALEN_SHIFT) & SLIMPRO_IIC_DATALEN_MASK)) + +/* + * Encode for upper address for block data + */ +#define SLIMPRO_IIC_ENCODE_FLAG_BUFADDR 0x80000000 +#define SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(a) ((u32) (((a) << 30) \ + & 0x40000000)) +#define SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(a) ((u32) (((a) >> 12) \ + & 0x3FF00000)) +#define SLIMPRO_IIC_ENCODE_ADDR(a) ((a) & 0x000FFFFF) + +struct slimpro_i2c_dev { + struct i2c_adapter adapter; + struct device *dev; + struct mbox_chan *mbox_chan; + struct mbox_client mbox_client; + struct completion rd_complete; + u8 dma_buffer[I2C_SMBUS_BLOCK_MAX]; + u32 *resp_msg; +}; + +#define to_slimpro_i2c_dev(cl) \ + container_of(cl, struct slimpro_i2c_dev, mbox_client) + +static void slimpro_i2c_rx_cb(struct mbox_client *cl, void *mssg) +{ + struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl); + + /* + * Response message format: + * mssg[0] is the return code of the operation + * mssg[1] is the first data word + * mssg[2] is NOT used + */ + if (ctx->resp_msg) + *ctx->resp_msg = ((u32 *)mssg)[1]; + + if (ctx->mbox_client.tx_block) + complete(&ctx->rd_complete); +} + +static int start_i2c_msg_xfer(struct slimpro_i2c_dev *ctx) +{ + if (ctx->mbox_client.tx_block) { + if (!wait_for_completion_timeout(&ctx->rd_complete, + msecs_to_jiffies(MAILBOX_OP_TIMEOUT))) + return -ETIMEDOUT; + } + + /* Check of invalid data or no device */ + if (*ctx->resp_msg == 0xffffffff) + return -ENODEV; + + return 0; +} + +static int slimpro_i2c_rd(struct slimpro_i2c_dev *ctx, u32 chip, + u32 addr, u32 addrlen, u32 protocol, + u32 readlen, u32 *data) +{ + u32 msg[3]; + int rc; + + msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, + SLIMPRO_IIC_READ, protocol, addrlen, readlen); + msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr); + msg[2] = 0; + ctx->resp_msg = data; + rc = mbox_send_message(ctx->mbox_chan, &msg); + if (rc < 0) + goto err; + + rc = start_i2c_msg_xfer(ctx); +err: + ctx->resp_msg = NULL; + return rc; +} + +static int slimpro_i2c_wr(struct slimpro_i2c_dev *ctx, u32 chip, + u32 addr, u32 addrlen, u32 protocol, u32 writelen, + u32 data) +{ + u32 msg[3]; + int rc; + + msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, + SLIMPRO_IIC_WRITE, protocol, addrlen, writelen); + msg[1] = SLIMPRO_IIC_ENCODE_ADDR(addr); + msg[2] = data; + ctx->resp_msg = msg; + + rc = mbox_send_message(ctx->mbox_chan, &msg); + if (rc < 0) + goto err; + + rc = start_i2c_msg_xfer(ctx); +err: + ctx->resp_msg = NULL; + return rc; +} + +static int slimpro_i2c_blkrd(struct slimpro_i2c_dev *ctx, u32 chip, u32 addr, + u32 addrlen, u32 protocol, u32 readlen, + u32 with_data_len, void *data) +{ + dma_addr_t paddr; + u32 msg[3]; + int rc; + + paddr = dma_map_single(ctx->dev, ctx->dma_buffer, readlen, DMA_FROM_DEVICE); + if (dma_mapping_error(ctx->dev, paddr)) { + dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", + ctx->dma_buffer); + rc = -ENOMEM; + goto err; + } + + msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_READ, + protocol, addrlen, readlen); + msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR | + SLIMPRO_IIC_ENCODE_FLAG_WITH_DATA_LEN(with_data_len) | + SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) | + SLIMPRO_IIC_ENCODE_ADDR(addr); + msg[2] = (u32)paddr; + ctx->resp_msg = msg; + + rc = mbox_send_message(ctx->mbox_chan, &msg); + if (rc < 0) + goto err_unmap; + + rc = start_i2c_msg_xfer(ctx); + + /* Copy to destination */ + memcpy(data, ctx->dma_buffer, readlen); + +err_unmap: + dma_unmap_single(ctx->dev, paddr, readlen, DMA_FROM_DEVICE); +err: + ctx->resp_msg = NULL; + return rc; +} + +static int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip, + u32 addr, u32 addrlen, u32 protocol, u32 writelen, + void *data) +{ + dma_addr_t paddr; + u32 msg[3]; + int rc; + + memcpy(ctx->dma_buffer, data, writelen); + paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen, + DMA_TO_DEVICE); + if (dma_mapping_error(ctx->dev, paddr)) { + dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", + ctx->dma_buffer); + rc = -ENOMEM; + goto err; + } + + msg[0] = SLIMPRO_IIC_ENCODE_MSG(SLIMPRO_IIC_BUS, chip, SLIMPRO_IIC_WRITE, + protocol, addrlen, writelen); + msg[1] = SLIMPRO_IIC_ENCODE_FLAG_BUFADDR | + SLIMPRO_IIC_ENCODE_UPPER_BUFADDR(paddr) | + SLIMPRO_IIC_ENCODE_ADDR(addr); + msg[2] = (u32)paddr; + ctx->resp_msg = msg; + + if (ctx->mbox_client.tx_block) + reinit_completion(&ctx->rd_complete); + + rc = mbox_send_message(ctx->mbox_chan, &msg); + if (rc < 0) + goto err_unmap; + + rc = start_i2c_msg_xfer(ctx); + +err_unmap: + dma_unmap_single(ctx->dev, paddr, writelen, DMA_TO_DEVICE); +err: + ctx->resp_msg = NULL; + return rc; +} + +static int xgene_slimpro_i2c_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, + union i2c_smbus_data *data) +{ + struct slimpro_i2c_dev *ctx = i2c_get_adapdata(adap); + int ret = -EOPNOTSUPP; + u32 val; + + switch (size) { + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_READ) { + ret = slimpro_i2c_rd(ctx, addr, 0, 0, + SLIMPRO_IIC_SMB_PROTOCOL, + BYTE_DATA, &val); + data->byte = val; + } else { + ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + 0, 0); + } + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + BYTE_DATA, &val); + data->byte = val; + } else { + val = data->byte; + ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + BYTE_DATA, val); + } + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = slimpro_i2c_rd(ctx, addr, command, SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + WORD_DATA, &val); + data->word = val; + } else { + val = data->word; + ret = slimpro_i2c_wr(ctx, addr, command, SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + WORD_DATA, val); + } + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = slimpro_i2c_blkrd(ctx, addr, command, + SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + I2C_SMBUS_BLOCK_MAX + 1, + IIC_SMB_WITH_DATA_LEN, + &data->block[0]); + + } else { + ret = slimpro_i2c_blkwr(ctx, addr, command, + SMBUS_CMD_LEN, + SLIMPRO_IIC_SMB_PROTOCOL, + data->block[0] + 1, + &data->block[0]); + } + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = slimpro_i2c_blkrd(ctx, addr, + command, + SMBUS_CMD_LEN, + SLIMPRO_IIC_I2C_PROTOCOL, + I2C_SMBUS_BLOCK_MAX, + IIC_SMB_WITHOUT_DATA_LEN, + &data->block[1]); + } else { + ret = slimpro_i2c_blkwr(ctx, addr, command, + SMBUS_CMD_LEN, + SLIMPRO_IIC_I2C_PROTOCOL, + data->block[0], + &data->block[1]); + } + break; + default: + break; + } + return ret; +} + +/* +* Return list of supported functionality. +*/ +static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static struct i2c_algorithm xgene_slimpro_i2c_algorithm = { + .smbus_xfer = xgene_slimpro_i2c_xfer, + .functionality = xgene_slimpro_i2c_func, +}; + +static int xgene_slimpro_i2c_probe(struct platform_device *pdev) +{ + struct slimpro_i2c_dev *ctx; + struct i2c_adapter *adapter; + struct mbox_client *cl; + int rc; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = &pdev->dev; + platform_set_drvdata(pdev, ctx); + cl = &ctx->mbox_client; + + /* Request mailbox channel */ + cl->dev = &pdev->dev; + cl->rx_callback = slimpro_i2c_rx_cb; + cl->tx_block = true; + init_completion(&ctx->rd_complete); + cl->tx_tout = MAILBOX_OP_TIMEOUT; + cl->knows_txdone = false; + ctx->mbox_chan = mbox_request_channel(cl, MAILBOX_I2C_INDEX); + if (IS_ERR(ctx->mbox_chan)) { + dev_err(&pdev->dev, "i2c mailbox channel request failed\n"); + return PTR_ERR(ctx->mbox_chan); + } + + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) + dev_warn(&pdev->dev, "Unable to set dma mask\n"); + + /* Setup I2C adapter */ + adapter = &ctx->adapter; + snprintf(adapter->name, sizeof(adapter->name), "MAILBOX I2C"); + adapter->algo = &xgene_slimpro_i2c_algorithm; + adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = &pdev->dev; + i2c_set_adapdata(adapter, ctx); + rc = i2c_add_adapter(adapter); + if (rc) { + dev_err(&pdev->dev, "Adapter registeration failed\n"); + mbox_free_channel(ctx->mbox_chan); + return rc; + } + + dev_info(&pdev->dev, "Mailbox I2C Adapter registered\n"); + return 0; +} + +static int xgene_slimpro_i2c_remove(struct platform_device *pdev) +{ + struct slimpro_i2c_dev *ctx = platform_get_drvdata(pdev); + + i2c_del_adapter(&ctx->adapter); + + mbox_free_channel(ctx->mbox_chan); + + return 0; +} + +static const struct of_device_id xgene_slimpro_i2c_dt_ids[] = { + {.compatible = "apm,xgene-slimpro-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = { + {"APMC0D40", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); +#endif + +static struct platform_driver xgene_slimpro_i2c_driver = { + .probe = xgene_slimpro_i2c_probe, + .remove = xgene_slimpro_i2c_remove, + .driver = { + .name = "xgene-slimpro-i2c", + .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids), + .acpi_match_table = ACPI_PTR(xgene_slimpro_i2c_acpi_ids) + }, +}; + +module_platform_driver(xgene_slimpro_i2c_driver); + +MODULE_DESCRIPTION("APM X-Gene SLIMpro I2C driver"); +MODULE_AUTHOR("Feng Kan <fkan@apm.com>"); +MODULE_AUTHOR("Hieu Le <hnle@apm.com>"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/i2c/busses/i2c-xiic.c b/kernel/drivers/i2c/busses/i2c-xiic.c index e8400042b..0b20449e4 100644 --- a/kernel/drivers/i2c/busses/i2c-xiic.c +++ b/kernel/drivers/i2c/busses/i2c-xiic.c @@ -63,6 +63,7 @@ enum xiic_endian { * @state: See STATE_ * @rx_msg: Current RX message * @rx_pos: Position within current RX message + * @endianness: big/little-endian byte order */ struct xiic_i2c { void __iomem *base; @@ -282,7 +283,7 @@ static void xiic_reinit(struct xiic_i2c *i2c) /* Enable interrupts */ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); - xiic_irq_clr_en(i2c, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK); + xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK); } static void xiic_deinit(struct xiic_i2c *i2c) @@ -357,8 +358,9 @@ static void xiic_wakeup(struct xiic_i2c *i2c, int code) wake_up(&i2c->wait); } -static void xiic_process(struct xiic_i2c *i2c) +static irqreturn_t xiic_process(int irq, void *dev_id) { + struct xiic_i2c *i2c = dev_id; u32 pend, isr, ier; u32 clr = 0; @@ -367,6 +369,7 @@ static void xiic_process(struct xiic_i2c *i2c) * To find which interrupts are pending; AND interrupts pending with * interrupts masked. */ + spin_lock(&i2c->lock); isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); pend = isr & ier; @@ -377,11 +380,6 @@ static void xiic_process(struct xiic_i2c *i2c) __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), i2c->tx_msg, i2c->nmsgs); - /* Do not processes a devices interrupts if the device has no - * interrupts pending - */ - if (!pend) - return; /* Service requesting interrupt */ if ((pend & XIIC_INTR_ARB_LOST_MASK) || @@ -401,13 +399,15 @@ static void xiic_process(struct xiic_i2c *i2c) */ xiic_reinit(i2c); + if (i2c->rx_msg) + xiic_wakeup(i2c, STATE_ERROR); if (i2c->tx_msg) xiic_wakeup(i2c, STATE_ERROR); - - } else if (pend & XIIC_INTR_RX_FULL_MASK) { + } + if (pend & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ - clr = XIIC_INTR_RX_FULL_MASK; + clr |= XIIC_INTR_RX_FULL_MASK; if (!i2c->rx_msg) { dev_dbg(i2c->adap.dev.parent, "%s unexpexted RX IRQ\n", __func__); @@ -440,9 +440,10 @@ static void xiic_process(struct xiic_i2c *i2c) __xiic_start_xfer(i2c); } } - } else if (pend & XIIC_INTR_BNB_MASK) { + } + if (pend & XIIC_INTR_BNB_MASK) { /* IIC bus has transitioned to not busy */ - clr = XIIC_INTR_BNB_MASK; + clr |= XIIC_INTR_BNB_MASK; /* The bus is not busy, disable BusNotBusy interrupt */ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK); @@ -455,12 +456,12 @@ static void xiic_process(struct xiic_i2c *i2c) xiic_wakeup(i2c, STATE_DONE); else xiic_wakeup(i2c, STATE_ERROR); - - } else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { + } + if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty */ - clr = pend & - (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); + clr |= (pend & + (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)); if (!i2c->tx_msg) { dev_dbg(i2c->adap.dev.parent, @@ -491,16 +492,13 @@ static void xiic_process(struct xiic_i2c *i2c) * make sure to disable tx half */ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); - } else { - /* got IRQ which is not acked */ - dev_err(i2c->adap.dev.parent, "%s Got unexpected IRQ\n", - __func__); - clr = pend; } out: dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr); + spin_unlock(&i2c->lock); + return IRQ_HANDLED; } static int xiic_bus_busy(struct xiic_i2c *i2c) @@ -524,7 +522,7 @@ static int xiic_busy(struct xiic_i2c *i2c) */ err = xiic_bus_busy(i2c); while (err && tries--) { - mdelay(1); + msleep(1); err = xiic_bus_busy(i2c); } @@ -601,19 +599,21 @@ static void xiic_start_send(struct xiic_i2c *i2c) static irqreturn_t xiic_isr(int irq, void *dev_id) { struct xiic_i2c *i2c = dev_id; - - spin_lock(&i2c->lock); - /* disable interrupts globally */ - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0); + u32 pend, isr, ier; + irqreturn_t ret = IRQ_NONE; + /* Do not processes a devices interrupts if the device has no + * interrupts pending + */ dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__); - xiic_process(i2c); - - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); - spin_unlock(&i2c->lock); + isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); + ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); + pend = isr & ier; + if (pend) + ret = IRQ_WAKE_THREAD; - return IRQ_HANDLED; + return ret; } static void __xiic_start_xfer(struct xiic_i2c *i2c) @@ -662,16 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) static void xiic_start_xfer(struct xiic_i2c *i2c) { - unsigned long flags; - - spin_lock_irqsave(&i2c->lock, flags); + spin_lock(&i2c->lock); xiic_reinit(i2c); - /* disable interrupts globally */ - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0); - spin_unlock_irqrestore(&i2c->lock, flags); - __xiic_start_xfer(i2c); - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); + spin_unlock(&i2c->lock); } static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) @@ -754,7 +748,10 @@ static int xiic_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, irq, xiic_isr, 0, pdev->name, i2c); + ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, + xiic_process, IRQF_ONESHOT, + pdev->name, i2c); + if (ret < 0) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); return ret; diff --git a/kernel/drivers/i2c/i2c-core.c b/kernel/drivers/i2c/i2c-core.c index 987c12443..ba8eb087f 100644 --- a/kernel/drivers/i2c/i2c-core.c +++ b/kernel/drivers/i2c/i2c-core.c @@ -27,6 +27,7 @@ I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com> */ +#include <dt-bindings/i2c/i2c.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> @@ -47,6 +48,7 @@ #include <linux/rwsem.h> #include <linux/pm_runtime.h> #include <linux/pm_domain.h> +#include <linux/pm_wakeirq.h> #include <linux/acpi.h> #include <linux/jump_label.h> #include <asm/uaccess.h> @@ -57,6 +59,9 @@ #define CREATE_TRACE_POINTS #include <trace/events/i2c.h> +#define I2C_ADDR_OFFSET_TEN_BIT 0xa000 +#define I2C_ADDR_OFFSET_SLAVE 0x1000 + /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter calls are serialized */ @@ -94,27 +99,40 @@ struct gsb_buffer { }; } __packed; -static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) +struct acpi_i2c_lookup { + struct i2c_board_info *info; + acpi_handle adapter_handle; + acpi_handle device_handle; +}; + +static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) { - struct i2c_board_info *info = data; + struct acpi_i2c_lookup *lookup = data; + struct i2c_board_info *info = lookup->info; + struct acpi_resource_i2c_serialbus *sb; + acpi_handle adapter_handle; + acpi_status status; - if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { - struct acpi_resource_i2c_serialbus *sb; + if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return 1; - sb = &ares->data.i2c_serial_bus; - if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { - info->addr = sb->slave_address; - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - info->flags |= I2C_CLIENT_TEN; - } - } else if (info->irq < 0) { - struct resource r; + sb = &ares->data.i2c_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) + return 1; - if (acpi_dev_resource_interrupt(ares, 0, &r)) - info->irq = r.start; + /* + * Extract the ResourceSource and make sure that the handle matches + * with the I2C adapter handle. + */ + status = acpi_get_handle(lookup->device_handle, + sb->resource_source.string_ptr, + &adapter_handle); + if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) { + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; } - /* Tell the ACPI core to skip this resource */ return 1; } @@ -123,6 +141,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, { struct i2c_adapter *adapter = data; struct list_head resource_list; + struct acpi_i2c_lookup lookup; + struct resource_entry *entry; struct i2c_board_info info; struct acpi_device *adev; int ret; @@ -134,16 +154,38 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, memset(&info, 0, sizeof(info)); info.fwnode = acpi_fwnode_handle(adev); - info.irq = -1; + memset(&lookup, 0, sizeof(lookup)); + lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); + lookup.device_handle = handle; + lookup.info = &info; + + /* + * Look up for I2cSerialBus resource with ResourceSource that + * matches with this adapter. + */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_add_resource, &info); + acpi_i2c_find_address, &lookup); acpi_dev_free_resource_list(&resource_list); if (ret < 0 || !info.addr) return AE_OK; + /* Then fill IRQ number if any */ + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (ret < 0) + return AE_OK; + + resource_list_for_each_entry(entry, &resource_list) { + if (resource_type(entry->res) == IORESOURCE_IRQ) { + info.irq = entry->res->start; + break; + } + } + + acpi_dev_free_resource_list(&resource_list); + adev->power.flags.ignore_parent = true; strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); if (!i2c_new_device(adapter, &info)) { @@ -156,6 +198,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, return AE_OK; } +#define ACPI_I2C_MAX_SCAN_DEPTH 32 + /** * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter @@ -166,17 +210,13 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, */ static void acpi_i2c_register_devices(struct i2c_adapter *adap) { - acpi_handle handle; acpi_status status; - if (!adap->dev.parent) + if (!has_acpi_companion(&adap->dev)) return; - handle = ACPI_HANDLE(adap->dev.parent); - if (!handle) - return; - - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_I2C_MAX_SCAN_DEPTH, acpi_i2c_add_device, NULL, adap, NULL); if (ACPI_FAILURE(status)) @@ -258,7 +298,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, struct acpi_connection_info *info = &data->info; struct acpi_resource_i2c_serialbus *sb; struct i2c_adapter *adapter = data->adapter; - struct i2c_client client; + struct i2c_client *client; struct acpi_resource *ares; u32 accessor_type = function >> 16; u8 action = function & ACPI_IO_MASK; @@ -269,6 +309,12 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, if (ACPI_FAILURE(ret)) return ret; + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) { + ret = AE_NO_MEMORY; + goto err; + } + if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { ret = AE_BAD_PARAMETER; goto err; @@ -280,75 +326,73 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, goto err; } - memset(&client, 0, sizeof(client)); - client.adapter = adapter; - client.addr = sb->slave_address; - client.flags = 0; + client->adapter = adapter; + client->addr = sb->slave_address; if (sb->access_mode == ACPI_I2C_10BIT_MODE) - client.flags |= I2C_CLIENT_TEN; + client->flags |= I2C_CLIENT_TEN; switch (accessor_type) { case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: if (action == ACPI_READ) { - status = i2c_smbus_read_byte(&client); + status = i2c_smbus_read_byte(client); if (status >= 0) { gsb->bdata = status; status = 0; } } else { - status = i2c_smbus_write_byte(&client, gsb->bdata); + status = i2c_smbus_write_byte(client, gsb->bdata); } break; case ACPI_GSB_ACCESS_ATTRIB_BYTE: if (action == ACPI_READ) { - status = i2c_smbus_read_byte_data(&client, command); + status = i2c_smbus_read_byte_data(client, command); if (status >= 0) { gsb->bdata = status; status = 0; } } else { - status = i2c_smbus_write_byte_data(&client, command, + status = i2c_smbus_write_byte_data(client, command, gsb->bdata); } break; case ACPI_GSB_ACCESS_ATTRIB_WORD: if (action == ACPI_READ) { - status = i2c_smbus_read_word_data(&client, command); + status = i2c_smbus_read_word_data(client, command); if (status >= 0) { gsb->wdata = status; status = 0; } } else { - status = i2c_smbus_write_word_data(&client, command, + status = i2c_smbus_write_word_data(client, command, gsb->wdata); } break; case ACPI_GSB_ACCESS_ATTRIB_BLOCK: if (action == ACPI_READ) { - status = i2c_smbus_read_block_data(&client, command, + status = i2c_smbus_read_block_data(client, command, gsb->data); if (status >= 0) { gsb->len = status; status = 0; } } else { - status = i2c_smbus_write_block_data(&client, command, + status = i2c_smbus_write_block_data(client, command, gsb->len, gsb->data); } break; case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: if (action == ACPI_READ) { - status = acpi_gsb_i2c_read_bytes(&client, command, + status = acpi_gsb_i2c_read_bytes(client, command, gsb->data, info->access_length); if (status > 0) status = 0; } else { - status = acpi_gsb_i2c_write_bytes(&client, command, + status = acpi_gsb_i2c_write_bytes(client, command, gsb->data, info->access_length); } break; @@ -362,6 +406,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, gsb->status = status; err: + kfree(client); ACPI_FREE(ares); return ret; } @@ -563,6 +608,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) if (bri->prepare_recovery) bri->prepare_recovery(adap); + bri->set_scl(adap, val); + ndelay(RECOVERY_NDELAY); + /* * By this time SCL is high, as we need to give 9 falling-rising edges */ @@ -593,7 +641,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) int i2c_generic_scl_recovery(struct i2c_adapter *adap) { - adap->bus_recovery_info->set_scl(adap, 1); return i2c_generic_recovery(adap); } EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); @@ -632,9 +679,16 @@ static int i2c_device_probe(struct device *dev) if (!client) return 0; - if (!client->irq && dev->of_node) { - int irq = of_irq_get(dev->of_node, 0); + if (!client->irq) { + int irq = -ENOENT; + if (dev->of_node) { + irq = of_irq_get_byname(dev->of_node, "irq"); + if (irq == -EINVAL || irq == -ENODATA) + irq = of_irq_get(dev->of_node, 0); + } else if (ACPI_COMPANION(dev)) { + irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); + } if (irq == -EPROBE_DEFER) return irq; if (irq < 0) @@ -647,23 +701,49 @@ static int i2c_device_probe(struct device *dev) if (!driver->probe || !driver->id_table) return -ENODEV; - if (!device_can_wakeup(&client->dev)) - device_init_wakeup(&client->dev, - client->flags & I2C_CLIENT_WAKE); + if (client->flags & I2C_CLIENT_WAKE) { + int wakeirq = -ENOENT; + + if (dev->of_node) { + wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); + if (wakeirq == -EPROBE_DEFER) + return wakeirq; + } + + device_init_wakeup(&client->dev, true); + + if (wakeirq > 0 && wakeirq != client->irq) + status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); + else if (client->irq > 0) + status = dev_pm_set_wake_irq(dev, client->irq); + else + status = 0; + + if (status) + dev_warn(&client->dev, "failed to set up wakeup irq"); + } + dev_dbg(dev, "probe\n"); status = of_clk_set_defaults(dev->of_node, false); if (status < 0) - return status; + goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true); - if (status != -EPROBE_DEFER) { - status = driver->probe(client, i2c_match_id(driver->id_table, - client)); - if (status) - dev_pm_domain_detach(&client->dev, true); - } + if (status == -EPROBE_DEFER) + goto err_clear_wakeup_irq; + + status = driver->probe(client, i2c_match_id(driver->id_table, client)); + if (status) + goto err_detach_pm_domain; + return 0; + +err_detach_pm_domain: + dev_pm_domain_detach(&client->dev, true); +err_clear_wakeup_irq: + dev_pm_clear_wake_irq(&client->dev); + device_init_wakeup(&client->dev, false); return status; } @@ -683,6 +763,10 @@ static int i2c_device_remove(struct device *dev) } dev_pm_domain_detach(&client->dev, true); + + dev_pm_clear_wake_irq(&client->dev); + device_init_wakeup(&client->dev, false); + return status; } @@ -767,17 +851,32 @@ struct i2c_client *i2c_verify_client(struct device *dev) EXPORT_SYMBOL(i2c_verify_client); +/* Return a unique address which takes the flags of the client into account */ +static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) +{ + unsigned short addr = client->addr; + + /* For some client flags, add an arbitrary offset to avoid collisions */ + if (client->flags & I2C_CLIENT_TEN) + addr |= I2C_ADDR_OFFSET_TEN_BIT; + + if (client->flags & I2C_CLIENT_SLAVE) + addr |= I2C_ADDR_OFFSET_SLAVE; + + return addr; +} + /* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */ -static int i2c_check_client_addr_validity(const struct i2c_client *client) +static int i2c_check_addr_validity(unsigned addr, unsigned short flags) { - if (client->flags & I2C_CLIENT_TEN) { + if (flags & I2C_CLIENT_TEN) { /* 10-bit address, all values are valid */ - if (client->addr > 0x3ff) + if (addr > 0x3ff) return -EINVAL; } else { /* 7-bit address, reject the general call address */ - if (client->addr == 0x00 || client->addr > 0x7f) + if (addr == 0x00 || addr > 0x7f) return -EINVAL; } return 0; @@ -787,7 +886,7 @@ static int i2c_check_client_addr_validity(const struct i2c_client *client) * device uses a reserved address, then it shouldn't be probed. 7-bit * addressing is assumed, 10-bit address devices are rare and should be * explicitly enumerated. */ -static int i2c_check_addr_validity(unsigned short addr) +static int i2c_check_7bit_addr_validity_strict(unsigned short addr) { /* * Reserved addresses per I2C specification: @@ -809,7 +908,7 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp) struct i2c_client *client = i2c_verify_client(dev); int addr = *(int *)addrp; - if (client && client->addr == addr) + if (client && i2c_encode_flags_to_addr(client) == addr) return -EBUSY; return 0; } @@ -912,10 +1011,8 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, return; } - /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), - client->addr | ((client->flags & I2C_CLIENT_TEN) - ? 0xa000 : 0)); + i2c_encode_flags_to_addr(client)); } /** @@ -957,8 +1054,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); - /* Check for address validity */ - status = i2c_check_client_addr_validity(client); + status = i2c_check_addr_validity(client->addr, client->flags); if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); @@ -966,7 +1062,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) } /* Check for address business */ - status = i2c_check_addr_busy(adap, client->addr); + status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client)); if (status) goto out_err; @@ -1003,6 +1099,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { + if (client->dev.of_node) + of_node_clear_flag(client->dev.of_node, OF_POPULATED); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1129,6 +1227,16 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EINVAL; } + if ((info.addr & I2C_ADDR_OFFSET_TEN_BIT) == I2C_ADDR_OFFSET_TEN_BIT) { + info.addr &= ~I2C_ADDR_OFFSET_TEN_BIT; + info.flags |= I2C_CLIENT_TEN; + } + + if (info.addr & I2C_ADDR_OFFSET_SLAVE) { + info.addr &= ~I2C_ADDR_OFFSET_SLAVE; + info.flags |= I2C_CLIENT_SLAVE; + } + client = i2c_new_device(adap, &info); if (!client) return -EINVAL; @@ -1180,7 +1288,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { - if (client->addr == addr) { + if (i2c_encode_flags_to_addr(client) == addr) { dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", "delete_device", client->name, client->addr); @@ -1260,7 +1368,8 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, struct i2c_client *result; struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; - const __be32 *addr; + const __be32 *addr_be; + u32 addr; int len; dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); @@ -1271,20 +1380,31 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, return ERR_PTR(-EINVAL); } - addr = of_get_property(node, "reg", &len); - if (!addr || (len < sizeof(int))) { + addr_be = of_get_property(node, "reg", &len); + if (!addr_be || (len < sizeof(*addr_be))) { dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", node->full_name); return ERR_PTR(-EINVAL); } - info.addr = be32_to_cpup(addr); - if (info.addr > (1 << 10) - 1) { + addr = be32_to_cpup(addr_be); + if (addr & I2C_TEN_BIT_ADDRESS) { + addr &= ~I2C_TEN_BIT_ADDRESS; + info.flags |= I2C_CLIENT_TEN; + } + + if (addr & I2C_OWN_SLAVE_ADDRESS) { + addr &= ~I2C_OWN_SLAVE_ADDRESS; + info.flags |= I2C_CLIENT_SLAVE; + } + + if (i2c_check_addr_validity(addr, info.flags)) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", info.addr, node->full_name); return ERR_PTR(-EINVAL); } + info.addr = addr; info.of_node = of_node_get(node); info.archdata = &dev_ad; @@ -1311,8 +1431,11 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - for_each_available_child_of_node(adap->dev.of_node, node) + for_each_available_child_of_node(adap->dev.of_node, node) { + if (of_node_test_and_set_flag(node, OF_POPULATED)) + continue; of_i2c_register_device(adap, node); + } } static int of_dev_node_match(struct device *dev, void *data) @@ -1324,13 +1447,17 @@ static int of_dev_node_match(struct device *dev, void *data) struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) { struct device *dev; + struct i2c_client *client; - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); + dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); if (!dev) return NULL; - return i2c_verify_client(dev); + client = i2c_verify_client(dev); + if (!client) + put_device(dev); + + return client; } EXPORT_SYMBOL(of_find_i2c_device_by_node); @@ -1338,15 +1465,37 @@ EXPORT_SYMBOL(of_find_i2c_device_by_node); struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) { struct device *dev; + struct i2c_adapter *adapter; - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); + dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); if (!dev) return NULL; - return i2c_verify_adapter(dev); + adapter = i2c_verify_adapter(dev); + if (!adapter) + put_device(dev); + + return adapter; } EXPORT_SYMBOL(of_find_i2c_adapter_by_node); + +/* must call i2c_put_adapter() when done with returned i2c_adapter device */ +struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) +{ + struct i2c_adapter *adapter; + + adapter = of_find_i2c_adapter_by_node(node); + if (!adapter) + return NULL; + + if (!try_module_get(adapter->owner)) { + put_device(&adapter->dev); + adapter = NULL; + } + + return adapter; +} +EXPORT_SYMBOL(of_get_i2c_adapter_by_node); #else static void of_i2c_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_OF */ @@ -1673,7 +1822,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) * FIXME: This is old code and should ideally be replaced by an * alternative which results in decoupling the lifetime of the struct * device from the i2c_adapter, like spi or netdev do. Any solution - * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled! + * should be thoroughly tested with DEBUG_KOBJECT_RELEASE enabled! */ init_completion(&adap->dev_released); device_unregister(&adap->dev); @@ -1844,6 +1993,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, if (adap == NULL) return NOTIFY_OK; /* not for us */ + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) { + put_device(&adap->dev); + return NOTIFY_OK; + } + client = of_i2c_register_device(adap, rd->dn); put_device(&adap->dev); @@ -1854,6 +2008,10 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, } break; case OF_RECONFIG_CHANGE_REMOVE: + /* already depopulated? */ + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + /* find our device by node */ client = of_find_i2c_device_by_node(rd->dn); if (client == NULL) @@ -2229,14 +2387,14 @@ static int i2c_detect_address(struct i2c_client *temp_client, int err; /* Make sure the address is valid */ - err = i2c_check_addr_validity(addr); + err = i2c_check_7bit_addr_validity_strict(addr); if (err) { dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", addr); return err; } - /* Skip if already in use */ + /* Skip if already in use (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adapter, addr)) return 0; @@ -2346,13 +2504,13 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ - if (i2c_check_addr_validity(addr_list[i]) < 0) { + if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; } - /* Check address availability */ + /* Check address availability (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); @@ -2380,9 +2538,15 @@ struct i2c_adapter *i2c_get_adapter(int nr) mutex_lock(&core_lock); adapter = idr_find(&i2c_adapter_idr, nr); - if (adapter && !try_module_get(adapter->owner)) + if (!adapter) + goto exit; + + if (try_module_get(adapter->owner)) + get_device(&adapter->dev); + else adapter = NULL; + exit: mutex_unlock(&core_lock); return adapter; } @@ -2390,8 +2554,11 @@ EXPORT_SYMBOL(i2c_get_adapter); void i2c_put_adapter(struct i2c_adapter *adap) { - if (adap) - module_put(adap->owner); + if (!adap) + return; + + put_device(&adap->dev); + module_put(adap->owner); } EXPORT_SYMBOL(i2c_put_adapter); @@ -2909,23 +3076,90 @@ trace: } EXPORT_SYMBOL(i2c_smbus_xfer); +/** + * i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate + * @client: Handle to slave device + * @command: Byte interpreted by slave + * @length: Size of data block; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes + * @values: Byte array into which data will be read; big enough to hold + * the data returned by the slave. SMBus allows at most + * I2C_SMBUS_BLOCK_MAX bytes. + * + * This executes the SMBus "block read" protocol if supported by the adapter. + * If block read is not supported, it emulates it using either word or byte + * read protocols depending on availability. + * + * The addresses of the I2C slave device that are accessed with this function + * must be mapped to a linear region, so that a block read will have the same + * effect as a byte read. Before using this function you must double-check + * if the I2C slave does support exchanging a block transfer with a byte + * transfer. + */ +s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, + u8 command, u8 length, u8 *values) +{ + u8 i = 0; + int status; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + return i2c_smbus_read_i2c_block_data(client, command, length, values); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) + return -EOPNOTSUPP; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) { + while ((i + 2) <= length) { + status = i2c_smbus_read_word_data(client, command + i); + if (status < 0) + return status; + values[i] = status & 0xff; + values[i + 1] = status >> 8; + i += 2; + } + } + + while (i < length) { + status = i2c_smbus_read_byte_data(client, command + i); + if (status < 0) + return status; + values[i] = status; + i++; + } + + return i; +} +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); + #if IS_ENABLED(CONFIG_I2C_SLAVE) int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) { int ret; - if (!client || !slave_cb) + if (!client || !slave_cb) { + WARN(1, "insufficent data\n"); return -EINVAL; + } + + if (!(client->flags & I2C_CLIENT_SLAVE)) + dev_warn(&client->dev, "%s: client slave flag not set. You might see address collisions\n", + __func__); if (!(client->flags & I2C_CLIENT_TEN)) { /* Enforce stricter address checking */ - ret = i2c_check_addr_validity(client->addr); - if (ret) + ret = i2c_check_7bit_addr_validity_strict(client->addr); + if (ret) { + dev_err(&client->dev, "%s: invalid address\n", __func__); return ret; + } } - if (!client->adapter->algo->reg_slave) + if (!client->adapter->algo->reg_slave) { + dev_err(&client->dev, "%s: not supported by adapter\n", __func__); return -EOPNOTSUPP; + } client->slave_cb = slave_cb; @@ -2933,8 +3167,10 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) ret = client->adapter->algo->reg_slave(client); i2c_unlock_adapter(client->adapter); - if (ret) + if (ret) { client->slave_cb = NULL; + dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret); + } return ret; } @@ -2944,8 +3180,10 @@ int i2c_slave_unregister(struct i2c_client *client) { int ret; - if (!client->adapter->algo->unreg_slave) + if (!client->adapter->algo->unreg_slave) { + dev_err(&client->dev, "%s: not supported by adapter\n", __func__); return -EOPNOTSUPP; + } i2c_lock_adapter(client->adapter); ret = client->adapter->algo->unreg_slave(client); @@ -2953,6 +3191,8 @@ int i2c_slave_unregister(struct i2c_client *client) if (ret == 0) client->slave_cb = NULL; + else + dev_err(&client->dev, "%s: adapter returned error %d\n", __func__, ret); return ret; } diff --git a/kernel/drivers/i2c/i2c-dev.c b/kernel/drivers/i2c/i2c-dev.c index 71c7a3975..2413ec9f8 100644 --- a/kernel/drivers/i2c/i2c-dev.c +++ b/kernel/drivers/i2c/i2c-dev.c @@ -235,7 +235,7 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) return result; } -static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, +static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, unsigned long arg) { struct i2c_rdwr_ioctl_data rdwr_arg; @@ -250,7 +250,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, /* Put an arbitrary limit on the number of messages that can * be sent at once */ - if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) return -EINVAL; rdwr_pa = memdup_user(rdwr_arg.msgs, @@ -421,16 +421,6 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (cmd) { case I2C_SLAVE: case I2C_SLAVE_FORCE: - /* NOTE: devices set up to work with "new style" drivers - * can't use I2C_SLAVE, even when the device node is not - * bound to a driver. Only I2C_SLAVE_FORCE will work. - * - * Setting the PEC flag here won't affect kernel drivers, - * which will be using the i2c_client node registered with - * the driver model core. Likewise, when that client has - * the PEC flag already set, the i2c-dev driver won't see - * (or use) this setting. - */ if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) return -EINVAL; @@ -446,6 +436,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) client->flags &= ~I2C_M_TEN; return 0; case I2C_PEC: + /* + * Setting the PEC flag here won't affect kernel drivers, + * which will be using the i2c_client node registered with + * the driver model core. Likewise, when that client has + * the PEC flag already set, the i2c-dev driver won't see + * (or use) this setting. + */ if (arg) client->flags |= I2C_CLIENT_PEC; else @@ -456,7 +453,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(funcs, (unsigned long __user *)arg); case I2C_RDWR: - return i2cdev_ioctl_rdrw(client, arg); + return i2cdev_ioctl_rdwr(client, arg); case I2C_SMBUS: return i2cdev_ioctl_smbus(client, arg); diff --git a/kernel/drivers/i2c/i2c-mux.c b/kernel/drivers/i2c/i2c-mux.c index 2ba7c0fbc..00fc5b1c7 100644 --- a/kernel/drivers/i2c/i2c-mux.c +++ b/kernel/drivers/i2c/i2c-mux.c @@ -25,6 +25,7 @@ #include <linux/i2c.h> #include <linux/i2c-mux.h> #include <linux/of.h> +#include <linux/acpi.h> /* multiplexer per channel data */ struct i2c_mux_priv { @@ -173,6 +174,13 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, } } + /* + * Associate the mux channel with an ACPI node. + */ + if (has_acpi_companion(mux_dev)) + acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev), + chan_id); + if (force_nr) { priv->adap.nr = force_nr; ret = i2c_add_numbered_adapter(&priv->adap); diff --git a/kernel/drivers/i2c/i2c-slave-eeprom.c b/kernel/drivers/i2c/i2c-slave-eeprom.c index 822374654..b2039f94c 100644 --- a/kernel/drivers/i2c/i2c-slave-eeprom.c +++ b/kernel/drivers/i2c/i2c-slave-eeprom.c @@ -80,9 +80,6 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj struct eeprom_data *eeprom; unsigned long flags; - if (off + count > attr->size) - return -EFBIG; - eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); spin_lock_irqsave(&eeprom->buffer_lock, flags); @@ -98,9 +95,6 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob struct eeprom_data *eeprom; unsigned long flags; - if (off + count > attr->size) - return -EFBIG; - eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj)); spin_lock_irqsave(&eeprom->buffer_lock, flags); @@ -163,7 +157,6 @@ MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id); static struct i2c_driver i2c_slave_eeprom_driver = { .driver = { .name = "i2c-slave-eeprom", - .owner = THIS_MODULE, }, .probe = i2c_slave_eeprom_probe, .remove = i2c_slave_eeprom_remove, diff --git a/kernel/drivers/i2c/i2c-smbus.c b/kernel/drivers/i2c/i2c-smbus.c index 9ebf9cb4a..94765a819 100644 --- a/kernel/drivers/i2c/i2c-smbus.c +++ b/kernel/drivers/i2c/i2c-smbus.c @@ -89,7 +89,7 @@ static void smbus_alert(struct work_struct *work) * to high, because of slave transmit arbitration. After * responding, an SMBus device stops asserting SMBALERT#. * - * Note that SMBus 2.0 reserves 10-bit addresess for future + * Note that SMBus 2.0 reserves 10-bit addresses for future * use. We neither handle them, nor try to use PEC here. */ status = i2c_smbus_read_byte(ara); diff --git a/kernel/drivers/i2c/muxes/Kconfig b/kernel/drivers/i2c/muxes/Kconfig index f6d313e52..f06b0e246 100644 --- a/kernel/drivers/i2c/muxes/Kconfig +++ b/kernel/drivers/i2c/muxes/Kconfig @@ -7,7 +7,8 @@ menu "Multiplexer I2C Chip support" config I2C_ARB_GPIO_CHALLENGE tristate "GPIO-based I2C arbitration" - depends on GPIOLIB && OF + depends on GPIOLIB || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for an I2C multimaster arbitration scheme using GPIOs and a challenge & @@ -40,7 +41,7 @@ config I2C_MUX_PCA9541 config I2C_MUX_PCA954x tristate "Philips PCA954x I2C Mux/switches" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help If you say yes here you get support for the Philips PCA954x I2C mux/switch devices. @@ -60,4 +61,15 @@ config I2C_MUX_PINCTRL This driver can also be built as a module. If so, the module will be called pinctrl-i2cmux. +config I2C_MUX_REG + tristate "Register-based I2C multiplexer" + help + If you say yes to this option, support will be included for a + register based I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which is controlled + by a single register. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-reg. + endmenu diff --git a/kernel/drivers/i2c/muxes/Makefile b/kernel/drivers/i2c/muxes/Makefile index 465778b5d..e89799b76 100644 --- a/kernel/drivers/i2c/muxes/Makefile +++ b/kernel/drivers/i2c/muxes/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o +obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/kernel/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/kernel/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 5cf1b60b6..402e3a6c6 100644 --- a/kernel/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/kernel/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -196,7 +196,8 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) dev_err(dev, "Cannot parse i2c-parent\n"); return -EINVAL; } - arb->parent = of_find_i2c_adapter_by_node(parent_np); + arb->parent = of_get_i2c_adapter_by_node(parent_np); + of_node_put(parent_np); if (!arb->parent) { dev_err(dev, "Cannot find parent bus\n"); return -EPROBE_DEFER; diff --git a/kernel/drivers/i2c/muxes/i2c-mux-gpio.c b/kernel/drivers/i2c/muxes/i2c-mux-gpio.c index 70db99264..b8e11c16d 100644 --- a/kernel/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/kernel/drivers/i2c/muxes/i2c-mux-gpio.c @@ -76,6 +76,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); if (!adapter) return -EPROBE_DEFER; diff --git a/kernel/drivers/i2c/muxes/i2c-mux-pca9541.c b/kernel/drivers/i2c/muxes/i2c-mux-pca9541.c index 0c8d4d2cb..d0ba424ad 100644 --- a/kernel/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/kernel/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -386,7 +386,6 @@ static int pca9541_remove(struct i2c_client *client) static struct i2c_driver pca9541_driver = { .driver = { .name = "pca9541", - .owner = THIS_MODULE, }, .probe = pca9541_probe, .remove = pca9541_remove, diff --git a/kernel/drivers/i2c/muxes/i2c-mux-pca954x.c b/kernel/drivers/i2c/muxes/i2c-mux-pca954x.c index ea4aa9dfc..acfcef3d4 100644 --- a/kernel/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/kernel/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -300,7 +300,6 @@ static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", .pm = &pca954x_pm, - .owner = THIS_MODULE, }, .probe = pca954x_probe, .remove = pca954x_remove, diff --git a/kernel/drivers/i2c/muxes/i2c-mux-pinctrl.c b/kernel/drivers/i2c/muxes/i2c-mux-pinctrl.c index b48378c4b..b5a982ba8 100644 --- a/kernel/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/kernel/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -111,6 +111,7 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); if (!adapter) { dev_err(mux->dev, "Cannot find parent bus\n"); return -EPROBE_DEFER; diff --git a/kernel/drivers/i2c/muxes/i2c-mux-reg.c b/kernel/drivers/i2c/muxes/i2c-mux-reg.c new file mode 100644 index 000000000..5fbd5bd08 --- /dev/null +++ b/kernel/drivers/i2c/muxes/i2c-mux-reg.c @@ -0,0 +1,290 @@ +/* + * I2C multiplexer using a single register + * + * Copyright 2015 Freescale Semiconductor + * York Sun <yorksun@freescale.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. + */ + +#include <linux/i2c.h> +#include <linux/i2c-mux.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_data/i2c-mux-reg.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct regmux { + struct i2c_adapter *parent; + struct i2c_adapter **adap; /* child busses */ + struct i2c_mux_reg_platform_data data; +}; + +static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id) +{ + if (!mux->data.reg) + return -EINVAL; + + /* + * Write to the register, followed by a read to ensure the write is + * completed on a "posted" bus, for example PCI or write buffers. + * The endianness of reading doesn't matter and the return data + * is not used. + */ + switch (mux->data.reg_size) { + case 4: + if (mux->data.little_endian) + iowrite32(chan_id, mux->data.reg); + else + iowrite32be(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread32(mux->data.reg); + break; + case 2: + if (mux->data.little_endian) + iowrite16(chan_id, mux->data.reg); + else + iowrite16be(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread16(mux->data.reg); + break; + case 1: + iowrite8(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread8(mux->data.reg); + break; + } + + return 0; +} + +static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data, + unsigned int chan) +{ + struct regmux *mux = data; + + return i2c_mux_reg_set(mux, chan); +} + +static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data, + unsigned int chan) +{ + struct regmux *mux = data; + + if (mux->data.idle_in_use) + return i2c_mux_reg_set(mux, mux->data.idle); + + return 0; +} + +#ifdef CONFIG_OF +static int i2c_mux_reg_probe_dt(struct regmux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + struct resource res; + unsigned *values; + int i = 0; + + if (!np) + return -ENODEV; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); + if (!adapter) + return -EPROBE_DEFER; + + mux->parent = adapter; + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + if (of_find_property(np, "little-endian", NULL)) { + mux->data.little_endian = true; + } else if (of_find_property(np, "big-endian", NULL)) { + mux->data.little_endian = false; + } else { +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \ + defined(__LITTLE_ENDIAN) + mux->data.little_endian = true; +#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : \ + defined(__BIG_ENDIAN) + mux->data.little_endian = false; +#else +#error Endianness not defined? +#endif + } + if (of_find_property(np, "write-only", NULL)) + mux->data.write_only = true; + else + mux->data.write_only = false; + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (!of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle_in_use = true; + + /* map address from "reg" if exists */ + if (of_address_to_resource(np, 0, &res)) { + mux->data.reg_size = resource_size(&res); + mux->data.reg = devm_ioremap_resource(&pdev->dev, &res); + if (IS_ERR(mux->data.reg)) + return PTR_ERR(mux->data.reg); + } + + return 0; +} +#else +static int i2c_mux_reg_probe_dt(struct regmux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + +static int i2c_mux_reg_probe(struct platform_device *pdev) +{ + struct regmux *mux; + struct i2c_adapter *parent; + struct resource *res; + int (*deselect)(struct i2c_adapter *, void *, u32); + unsigned int class; + int i, ret, nr; + + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + platform_set_drvdata(pdev, mux); + + if (dev_get_platdata(&pdev->dev)) { + memcpy(&mux->data, dev_get_platdata(&pdev->dev), + sizeof(mux->data)); + + parent = i2c_get_adapter(mux->data.parent); + if (!parent) + return -EPROBE_DEFER; + + mux->parent = parent; + } else { + ret = i2c_mux_reg_probe_dt(mux, pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing device tree"); + return ret; + } + } + + if (!mux->data.reg) { + dev_info(&pdev->dev, + "Register not set, using platform resource\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mux->data.reg_size = resource_size(res); + mux->data.reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mux->data.reg)) + return PTR_ERR(mux->data.reg); + } + + if (mux->data.reg_size != 4 && mux->data.reg_size != 2 && + mux->data.reg_size != 1) { + dev_err(&pdev->dev, "Invalid register size\n"); + return -EINVAL; + } + + mux->adap = devm_kzalloc(&pdev->dev, + sizeof(*mux->adap) * mux->data.n_values, + GFP_KERNEL); + if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); + return -ENOMEM; + } + + if (mux->data.idle_in_use) + deselect = i2c_mux_reg_deselect; + else + deselect = NULL; + + for (i = 0; i < mux->data.n_values; i++) { + nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + class = mux->data.classes ? mux->data.classes[i] : 0; + + mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux, + nr, mux->data.values[i], + class, i2c_mux_reg_select, + deselect); + if (!mux->adap[i]) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto add_adapter_failed; + } + } + + dev_dbg(&pdev->dev, "%d port mux on %s adapter\n", + mux->data.n_values, mux->parent->name); + + return 0; + +add_adapter_failed: + for (; i > 0; i--) + i2c_del_mux_adapter(mux->adap[i - 1]); + + return ret; +} + +static int i2c_mux_reg_remove(struct platform_device *pdev) +{ + struct regmux *mux = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < mux->data.n_values; i++) + i2c_del_mux_adapter(mux->adap[i]); + + i2c_put_adapter(mux->parent); + + return 0; +} + +static const struct of_device_id i2c_mux_reg_of_match[] = { + { .compatible = "i2c-mux-reg", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_reg_of_match); + +static struct platform_driver i2c_mux_reg_driver = { + .probe = i2c_mux_reg_probe, + .remove = i2c_mux_reg_remove, + .driver = { + .name = "i2c-mux-reg", + }, +}; + +module_platform_driver(i2c_mux_reg_driver); + +MODULE_DESCRIPTION("Register-based I2C multiplexer driver"); +MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:i2c-mux-reg"); |