diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/Kconfig | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bcm-iproc.c | 461 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-cadence.c | 189 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-baytrail.c | 160 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 83 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 12 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-pcidrv.c | 41 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 20 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 33 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 91 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pmcmsp.c | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-rk3x.c | 99 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 2 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 162 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-pca954x.c | 11 |
17 files changed, 1045 insertions, 354 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 8c9e619f302..78fbee46362 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -35,11 +35,11 @@ config ACPI_I2C_OPREGION if I2C config I2C_BOARDINFO - boolean + bool default y config I2C_COMPAT - boolean "Enable compatibility bits for old user-space" + bool "Enable compatibility bits for old user-space" default y help Say Y here if you intend to run lm-sensors 3.1.1 or older, or any diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ab838d9e28b..22da9c2ffa2 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -79,7 +79,7 @@ config I2C_AMD8111 config I2C_HIX5HD2 tristate "Hix5hd2 high-speed I2C driver" - depends on ARCH_HIX5HD2 + depends on ARCH_HIX5HD2 || COMPILE_TEST help Say Y here to include support for high-speed I2C controller in the Hisilicon based hix5hd2 SoCs. @@ -372,6 +372,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_IPROC + tristate "Broadcom iProc I2C controller" + depends on ARCH_BCM_IPROC || COMPILE_TEST + default ARCH_BCM_IPROC + help + If you say yes to this option, support will be included for the + Broadcom iProc I2C controller. + + If you don't know what to do here, say N. + config I2C_BCM_KONA tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE @@ -465,6 +475,16 @@ config I2C_DESIGNWARE_PCI This driver can also be built as a module. If so, the module will be called i2c-designware-pci. +config I2C_DESIGNWARE_BAYTRAIL + bool "Intel Baytrail I2C semaphore support" + depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI + help + This driver enables managed host access to the PMIC I2C bus on select + Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows + the host to request uninterrupted access to the PMIC's I2C bus from + the platform firmware controlling it. You should say Y if running on + a BayTrail system using the AXP288. + config I2C_EFM32 tristate "EFM32 I2C controller" depends on ARCH_EFM32 || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 56388f658d2..3638feb6677 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o +obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o @@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o i2c-designware-platform-objs := i2c-designware-platdrv.o +i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c new file mode 100644 index 00000000000..d3c89157b33 --- /dev/null +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -0,0 +1,461 @@ +/* + * 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/delay.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/slab.h> + +#define CFG_OFFSET 0x00 +#define CFG_RESET_SHIFT 31 +#define CFG_EN_SHIFT 30 +#define CFG_M_RETRY_CNT_SHIFT 16 +#define CFG_M_RETRY_CNT_MASK 0x0f + +#define TIM_CFG_OFFSET 0x04 +#define TIM_CFG_MODE_400_SHIFT 31 + +#define M_FIFO_CTRL_OFFSET 0x0c +#define M_FIFO_RX_FLUSH_SHIFT 31 +#define M_FIFO_TX_FLUSH_SHIFT 30 +#define M_FIFO_RX_CNT_SHIFT 16 +#define M_FIFO_RX_CNT_MASK 0x7f +#define M_FIFO_RX_THLD_SHIFT 8 +#define M_FIFO_RX_THLD_MASK 0x3f + +#define M_CMD_OFFSET 0x30 +#define M_CMD_START_BUSY_SHIFT 31 +#define M_CMD_STATUS_SHIFT 25 +#define M_CMD_STATUS_MASK 0x07 +#define M_CMD_STATUS_SUCCESS 0x0 +#define M_CMD_STATUS_LOST_ARB 0x1 +#define M_CMD_STATUS_NACK_ADDR 0x2 +#define M_CMD_STATUS_NACK_DATA 0x3 +#define M_CMD_STATUS_TIMEOUT 0x4 +#define M_CMD_PROTOCOL_SHIFT 9 +#define M_CMD_PROTOCOL_MASK 0xf +#define M_CMD_PROTOCOL_BLK_WR 0x7 +#define M_CMD_PROTOCOL_BLK_RD 0x8 +#define M_CMD_PEC_SHIFT 8 +#define M_CMD_RD_CNT_SHIFT 0 +#define M_CMD_RD_CNT_MASK 0xff + +#define IE_OFFSET 0x38 +#define IE_M_RX_FIFO_FULL_SHIFT 31 +#define IE_M_RX_THLD_SHIFT 30 +#define IE_M_START_BUSY_SHIFT 28 + +#define IS_OFFSET 0x3c +#define IS_M_RX_FIFO_FULL_SHIFT 31 +#define IS_M_RX_THLD_SHIFT 30 +#define IS_M_START_BUSY_SHIFT 28 + +#define M_TX_OFFSET 0x40 +#define M_TX_WR_STATUS_SHIFT 31 +#define M_TX_DATA_SHIFT 0 +#define M_TX_DATA_MASK 0xff + +#define M_RX_OFFSET 0x44 +#define M_RX_STATUS_SHIFT 30 +#define M_RX_STATUS_MASK 0x03 +#define M_RX_PEC_ERR_SHIFT 29 +#define M_RX_DATA_SHIFT 0 +#define M_RX_DATA_MASK 0xff + +#define I2C_TIMEOUT_MESC 100 +#define M_TX_RX_FIFO_SIZE 64 + +enum bus_speed_index { + I2C_SPD_100K = 0, + I2C_SPD_400K, +}; + +struct bcm_iproc_i2c_dev { + struct device *device; + int irq; + + void __iomem *base; + + struct i2c_adapter adapter; + + struct completion done; + int xfer_is_done; +}; + +/* + * Can be expanded in the future if more interrupt status bits are utilized + */ +#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT) + +static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = data; + u32 status = readl(iproc_i2c->base + IS_OFFSET); + + status &= ISR_MASK; + + if (!status) + return IRQ_NONE; + + writel(status, iproc_i2c->base + IS_OFFSET); + iproc_i2c->xfer_is_done = 1; + complete_all(&iproc_i2c->done); + + return IRQ_HANDLED; +} + +static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c, + struct i2c_msg *msg) +{ + u32 val; + + val = readl(iproc_i2c->base + M_CMD_OFFSET); + val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK; + + switch (val) { + case M_CMD_STATUS_SUCCESS: + return 0; + + case M_CMD_STATUS_LOST_ARB: + dev_dbg(iproc_i2c->device, "lost bus arbitration\n"); + return -EAGAIN; + + case M_CMD_STATUS_NACK_ADDR: + dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr); + return -ENXIO; + + case M_CMD_STATUS_NACK_DATA: + dev_dbg(iproc_i2c->device, "NAK data\n"); + return -ENXIO; + + case M_CMD_STATUS_TIMEOUT: + dev_dbg(iproc_i2c->device, "bus timeout\n"); + return -ETIMEDOUT; + + default: + dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val); + return -EIO; + } +} + +static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c, + struct i2c_msg *msg) +{ + int ret, i; + u8 addr; + u32 val; + unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC); + + /* need to reserve one byte in the FIFO for the slave address */ + if (msg->len > M_TX_RX_FIFO_SIZE - 1) { + dev_err(iproc_i2c->device, + "only support data length up to %u bytes\n", + M_TX_RX_FIFO_SIZE - 1); + return -EOPNOTSUPP; + } + + /* check if bus is busy */ + if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) & + BIT(M_CMD_START_BUSY_SHIFT))) { + dev_warn(iproc_i2c->device, "bus is busy\n"); + return -EBUSY; + } + + /* format and load slave address into the TX FIFO */ + addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0); + writel(addr, iproc_i2c->base + M_TX_OFFSET); + + /* for a write transaction, load data into the TX FIFO */ + if (!(msg->flags & I2C_M_RD)) { + for (i = 0; i < msg->len; i++) { + val = msg->buf[i]; + + /* mark the last byte */ + if (i == msg->len - 1) + val |= 1 << M_TX_WR_STATUS_SHIFT; + + writel(val, iproc_i2c->base + M_TX_OFFSET); + } + } + + /* mark as incomplete before starting the transaction */ + reinit_completion(&iproc_i2c->done); + iproc_i2c->xfer_is_done = 0; + + /* + * Enable the "start busy" interrupt, which will be triggered after the + * transaction is done, i.e., the internal start_busy bit, transitions + * from 1 to 0. + */ + writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET); + + /* + * Now we can activate the transfer. For a read operation, specify the + * number of bytes to read + */ + val = 1 << M_CMD_START_BUSY_SHIFT; + if (msg->flags & I2C_M_RD) { + val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) | + (msg->len << M_CMD_RD_CNT_SHIFT); + } else { + val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT); + } + writel(val, iproc_i2c->base + M_CMD_OFFSET); + + time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left); + + /* disable all interrupts */ + writel(0, iproc_i2c->base + IE_OFFSET); + /* read it back to flush the write */ + readl(iproc_i2c->base + IE_OFFSET); + + /* make sure the interrupt handler isn't running */ + synchronize_irq(iproc_i2c->irq); + + if (!time_left && !iproc_i2c->xfer_is_done) { + dev_err(iproc_i2c->device, "transaction timed out\n"); + + /* flush FIFOs */ + val = (1 << M_FIFO_RX_FLUSH_SHIFT) | + (1 << M_FIFO_TX_FLUSH_SHIFT); + writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET); + return -ETIMEDOUT; + } + + ret = bcm_iproc_i2c_check_status(iproc_i2c, msg); + if (ret) { + /* flush both TX/RX FIFOs */ + val = (1 << M_FIFO_RX_FLUSH_SHIFT) | + (1 << M_FIFO_TX_FLUSH_SHIFT); + writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET); + return ret; + } + + /* + * For a read operation, we now need to load the data from FIFO + * into the memory buffer + */ + if (msg->flags & I2C_M_RD) { + for (i = 0; i < msg->len; i++) { + msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >> + M_RX_DATA_SHIFT) & M_RX_DATA_MASK; + } + } + + return 0; +} + +static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter, + struct i2c_msg msgs[], int num) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter); + int ret, i; + + /* go through all messages */ + for (i = 0; i < num; i++) { + ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]); + if (ret) { + dev_dbg(iproc_i2c->device, "xfer failed\n"); + return ret; + } + } + + return num; +} + +static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm bcm_iproc_algo = { + .master_xfer = bcm_iproc_i2c_xfer, + .functionality = bcm_iproc_i2c_functionality, +}; + +static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) +{ + unsigned int bus_speed; + u32 val; + int ret = of_property_read_u32(iproc_i2c->device->of_node, + "clock-frequency", &bus_speed); + if (ret < 0) { + dev_info(iproc_i2c->device, + "unable to interpret clock-frequency DT property\n"); + bus_speed = 100000; + } + + if (bus_speed < 100000) { + dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n", + bus_speed); + dev_err(iproc_i2c->device, + "valid speeds are 100khz and 400khz\n"); + return -EINVAL; + } else if (bus_speed < 400000) { + bus_speed = 100000; + } else { + bus_speed = 400000; + } + + val = readl(iproc_i2c->base + TIM_CFG_OFFSET); + val &= ~(1 << TIM_CFG_MODE_400_SHIFT); + val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT; + writel(val, iproc_i2c->base + TIM_CFG_OFFSET); + + dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed); + + return 0; +} + +static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c) +{ + u32 val; + + /* put controller in reset */ + val = readl(iproc_i2c->base + CFG_OFFSET); + val |= 1 << CFG_RESET_SHIFT; + val &= ~(1 << CFG_EN_SHIFT); + writel(val, iproc_i2c->base + CFG_OFFSET); + + /* wait 100 usec per spec */ + udelay(100); + + /* bring controller out of reset */ + val &= ~(1 << CFG_RESET_SHIFT); + writel(val, iproc_i2c->base + CFG_OFFSET); + + /* flush TX/RX FIFOs and set RX FIFO threshold to zero */ + val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT); + writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET); + + /* disable all interrupts */ + writel(0, iproc_i2c->base + IE_OFFSET); + + /* clear all pending interrupts */ + writel(0xffffffff, iproc_i2c->base + IS_OFFSET); + + return 0; +} + +static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c, + bool enable) +{ + u32 val; + + val = readl(iproc_i2c->base + CFG_OFFSET); + if (enable) + val |= BIT(CFG_EN_SHIFT); + else + val &= ~BIT(CFG_EN_SHIFT); + writel(val, iproc_i2c->base + CFG_OFFSET); +} + +static int bcm_iproc_i2c_probe(struct platform_device *pdev) +{ + int irq, ret = 0; + struct bcm_iproc_i2c_dev *iproc_i2c; + struct i2c_adapter *adap; + struct resource *res; + + iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c), + GFP_KERNEL); + if (!iproc_i2c) + return -ENOMEM; + + platform_set_drvdata(pdev, iproc_i2c); + iproc_i2c->device = &pdev->dev; + init_completion(&iproc_i2c->done); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res); + if (IS_ERR(iproc_i2c->base)) + return PTR_ERR(iproc_i2c->base); + + ret = bcm_iproc_i2c_init(iproc_i2c); + if (ret) + return ret; + + ret = bcm_iproc_i2c_cfg_speed(iproc_i2c); + if (ret) + return ret; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(iproc_i2c->device, "no irq resource\n"); + return irq; + } + iproc_i2c->irq = irq; + + ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0, + pdev->name, iproc_i2c); + if (ret < 0) { + dev_err(iproc_i2c->device, "unable to request irq %i\n", irq); + return ret; + } + + bcm_iproc_i2c_enable_disable(iproc_i2c, true); + + adap = &iproc_i2c->adapter; + i2c_set_adapdata(adap, iproc_i2c); + strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name)); + adap->algo = &bcm_iproc_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + ret = i2c_add_adapter(adap); + if (ret) { + dev_err(iproc_i2c->device, "failed to add adapter\n"); + return ret; + } + + return 0; +} + +static int bcm_iproc_i2c_remove(struct platform_device *pdev) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev); + + /* make sure there's no pending interrupt when we remove the adapter */ + writel(0, iproc_i2c->base + IE_OFFSET); + readl(iproc_i2c->base + IE_OFFSET); + synchronize_irq(iproc_i2c->irq); + + i2c_del_adapter(&iproc_i2c->adapter); + bcm_iproc_i2c_enable_disable(iproc_i2c, false); + + return 0; +} + +static const struct of_device_id bcm_iproc_i2c_of_match[] = { + { .compatible = "brcm,iproc-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match); + +static struct platform_driver bcm_iproc_i2c_driver = { + .driver = { + .name = "bcm-iproc-i2c", + .of_match_table = bcm_iproc_i2c_of_match, + }, + .probe = bcm_iproc_i2c_probe, + .remove = bcm_iproc_i2c_remove, +}; +module_platform_driver(bcm_iproc_i2c_driver); + +MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>"); +MODULE_DESCRIPTION("Broadcom iProc I2C Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 626f74ecd4b..7d7a14cdadf 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -128,6 +128,7 @@ * @suspended: Flag holding the device's PM status * @send_count: Number of bytes still expected to send * @recv_count: Number of bytes still expected to receive + * @curr_recv_count: Number of bytes to be received in current transfer * @irq: IRQ number * @input_clk: Input clock to I2C controller * @i2c_clk: Maximum I2C clock speed @@ -146,6 +147,7 @@ struct cdns_i2c { u8 suspended; unsigned int send_count; unsigned int recv_count; + unsigned int curr_recv_count; int irq; unsigned long input_clk; unsigned int i2c_clk; @@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) */ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) { - unsigned int isr_status, avail_bytes; - unsigned int bytes_to_recv, bytes_to_send; + unsigned int isr_status, avail_bytes, updatetx; + unsigned int bytes_to_send; struct cdns_i2c *id = ptr; /* Signal completion only after everything is updated */ int done_flag = 0; irqreturn_t status = IRQ_NONE; isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); + cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); /* Handling nack and arbitration lost interrupt */ if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) { @@ -197,89 +200,112 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) status = IRQ_HANDLED; } - /* Handling Data interrupt */ - if ((isr_status & CDNS_I2C_IXR_DATA) && - (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) { - /* Always read data interrupt threshold bytes */ - bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH; - id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH; - avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); - - /* - * if the tranfer size register value is zero, then - * check for the remaining bytes and update the - * transfer size register. - */ - if (!avail_bytes) { - if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, - CDNS_I2C_XFER_SIZE_OFFSET); - else - cdns_i2c_writereg(id->recv_count, - CDNS_I2C_XFER_SIZE_OFFSET); - } + /* + * Check if transfer size register needs to be updated again for a + * large data receive operation. + */ + updatetx = 0; + if (id->recv_count > id->curr_recv_count) + updatetx = 1; + + /* When receiving, handle data interrupt and completion interrupt */ + if (id->p_recv_buf && + ((isr_status & CDNS_I2C_IXR_COMP) || + (isr_status & CDNS_I2C_IXR_DATA))) { + /* Read data if receive data valid is set */ + while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & + CDNS_I2C_SR_RXDV) { + /* + * Clear hold bit that was set for FIFO control if + * RX data left is less than FIFO depth, unless + * repeated start is selected. + */ + if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) && + !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); - /* Process the data received */ - while (bytes_to_recv--) *(id->p_recv_buf)++ = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); + id->recv_count--; + id->curr_recv_count--; - if (!id->bus_hold_flag && - (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) - cdns_i2c_clear_bus_hold(id); + if (updatetx && + (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) + break; + } - status = IRQ_HANDLED; - } + /* + * The controller sends NACK to the slave when transfer size + * register reaches zero without considering the HOLD bit. + * This workaround is implemented for large data transfers to + * maintain transfer size non-zero while performing a large + * receive operation. + */ + if (updatetx && + (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) { + /* wait while fifo is full */ + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != + (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH)) + ; - /* Handling Transfer Complete interrupt */ - if (isr_status & CDNS_I2C_IXR_COMP) { - if (!id->p_recv_buf) { /* - * If the device is sending data If there is further - * data to be sent. Calculate the available space - * in FIFO and fill the FIFO with that many bytes. + * Check number of bytes to be received against maximum + * transfer size and update register accordingly. */ - if (id->send_count) { - avail_bytes = CDNS_I2C_FIFO_DEPTH - - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); - if (id->send_count > avail_bytes) - bytes_to_send = avail_bytes; - else - bytes_to_send = id->send_count; - - while (bytes_to_send--) { - cdns_i2c_writereg( - (*(id->p_send_buf)++), - CDNS_I2C_DATA_OFFSET); - id->send_count--; - } + if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) > + CDNS_I2C_TRANSFER_SIZE) { + cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE + + CDNS_I2C_FIFO_DEPTH; } else { - /* - * Signal the completion of transaction and - * clear the hold bus bit if there are no - * further messages to be processed. - */ - done_flag = 1; + cdns_i2c_writereg(id->recv_count - + CDNS_I2C_FIFO_DEPTH, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; } - if (!id->send_count && !id->bus_hold_flag) - cdns_i2c_clear_bus_hold(id); - } else { + } + + /* Clear hold (if not repeated start) and signal completion */ + if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) { if (!id->bus_hold_flag) cdns_i2c_clear_bus_hold(id); + done_flag = 1; + } + + status = IRQ_HANDLED; + } + + /* When sending, handle transfer complete interrupt */ + if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) { + /* + * If there is more data to be sent, calculate the + * space available in FIFO and fill with that many bytes. + */ + if (id->send_count) { + avail_bytes = CDNS_I2C_FIFO_DEPTH - + cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + cdns_i2c_writereg( + (*(id->p_send_buf)++), + CDNS_I2C_DATA_OFFSET); + id->send_count--; + } + } else { /* - * If the device is receiving data, then signal - * the completion of transaction and read the data - * present in the FIFO. Signal the completion of - * transaction. + * Signal the completion of transaction and + * clear the hold bus bit if there are no + * further messages to be processed. */ - while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & - CDNS_I2C_SR_RXDV) { - *(id->p_recv_buf)++ = - cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); - id->recv_count--; - } done_flag = 1; } + if (!id->send_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); status = IRQ_HANDLED; } @@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) if (id->err_status) status = IRQ_HANDLED; - cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET); - if (done_flag) complete(&id->xfer_done); @@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) if (id->p_msg->flags & I2C_M_RECV_LEN) id->recv_count = I2C_SMBUS_BLOCK_MAX + 1; + id->curr_recv_count = id->recv_count; + /* * Check for the message size against FIFO depth and set the * 'hold bus' bit if it is greater than FIFO depth. @@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) * receive if it is less than transfer size and transfer size if * it is more. Enable the interrupts. */ - if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) + if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET); - else + id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; + } else { cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); + } + /* Clear the bus hold flag if bytes to receive is less than FIFO size */ if (!id->bus_hold_flag && ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && @@ -516,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, * processed with a repeated start. */ if (num > 1) { + /* + * This controller does not give completion interrupt after a + * master receive message if HOLD bit is set (repeated start), + * resulting in SW timeout. Hence, if a receive message is + * followed by any other message, an error is returned + * indicating that this sequence is not supported. + */ + for (count = 0; count < num - 1; count++) { + if (msgs[count].flags & I2C_M_RD) { + dev_warn(adap->dev.parent, + "Can't do repeated start after a receive message\n"); + return -EOPNOTSUPP; + } + } id->bus_hold_flag = 1; reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); reg |= CDNS_I2C_CR_HOLD; diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c new file mode 100644 index 00000000000..5f1ff4cc5c3 --- /dev/null +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -0,0 +1,160 @@ +/* + * Intel BayTrail PMIC I2C bus semaphore implementaion + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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/module.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/acpi.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <asm/iosf_mbi.h> +#include "i2c-designware-core.h" + +#define SEMAPHORE_TIMEOUT 100 +#define PUNIT_SEMAPHORE 0x7 + +static unsigned long acquired; + +static int get_sem(struct device *dev, u32 *sem) +{ + u32 reg_val; + int ret; + + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE, + ®_val); + if (ret) { + dev_err(dev, "iosf failed to read punit semaphore\n"); + return ret; + } + + *sem = reg_val & 0x1; + + return 0; +} + +static void reset_semaphore(struct device *dev) +{ + u32 data; + + if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + PUNIT_SEMAPHORE, &data)) { + dev_err(dev, "iosf failed to reset punit semaphore during read\n"); + return; + } + + data = data & 0xfffffffe; + if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + PUNIT_SEMAPHORE, data)) + dev_err(dev, "iosf failed to reset punit semaphore during write\n"); +} + +int baytrail_i2c_acquire(struct dw_i2c_dev *dev) +{ + u32 sem = 0; + int ret; + unsigned long start, end; + + if (!dev || !dev->dev) + return -ENODEV; + + if (!dev->acquire_lock) + return 0; + + /* host driver writes 0x2 to side band semaphore register */ + ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, + PUNIT_SEMAPHORE, 0x2); + if (ret) { + dev_err(dev->dev, "iosf punit semaphore request failed\n"); + return ret; + } + + /* host driver waits for bit 0 to be set in semaphore register */ + start = jiffies; + end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); + while (!time_after(jiffies, end)) { + ret = get_sem(dev->dev, &sem); + if (!ret && sem) { + acquired = jiffies; + dev_dbg(dev->dev, "punit semaphore acquired after %ums\n", + jiffies_to_msecs(jiffies - start)); + return 0; + } + + usleep_range(1000, 2000); + } + + dev_err(dev->dev, "punit semaphore timed out, resetting\n"); + reset_semaphore(dev->dev); + + ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, + PUNIT_SEMAPHORE, &sem); + if (!ret) + dev_err(dev->dev, "iosf failed to read punit semaphore\n"); + else + dev_err(dev->dev, "PUNIT SEM: %d\n", sem); + + WARN_ON(1); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL(baytrail_i2c_acquire); + +void baytrail_i2c_release(struct dw_i2c_dev *dev) +{ + if (!dev || !dev->dev) + return; + + if (!dev->acquire_lock) + return; + + reset_semaphore(dev->dev); + dev_dbg(dev->dev, "punit semaphore held for %ums\n", + jiffies_to_msecs(jiffies - acquired)); +} +EXPORT_SYMBOL(baytrail_i2c_release); + +int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) +{ + acpi_status status; + unsigned long long shared_host = 0; + acpi_handle handle; + + if (!dev || !dev->dev) + return 0; + + handle = ACPI_HANDLE(dev->dev); + if (!handle) + return 0; + + status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); + + if (ACPI_FAILURE(status)) + return 0; + + if (shared_host) { + dev_info(dev->dev, "I2C bus managed by PUNIT\n"); + dev->acquire_lock = baytrail_i2c_acquire; + dev->release_lock = baytrail_i2c_release; + dev->pm_runtime_disabled = true; + } + + if (!iosf_mbi_available()) + return -EPROBE_DEFER; + + return 0; +} +EXPORT_SYMBOL(i2c_dw_eval_lock_support); + +MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); +MODULE_DESCRIPTION("Baytrail I2C Semaphore driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 23628b7bfb8..6e25c010e69 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -170,10 +170,10 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset) u32 value; if (dev->accessor_flags & ACCESS_16BIT) - value = readw(dev->base + offset) | - (readw(dev->base + offset + 2) << 16); + value = readw_relaxed(dev->base + offset) | + (readw_relaxed(dev->base + offset + 2) << 16); else - value = readl(dev->base + offset); + value = readl_relaxed(dev->base + offset); if (dev->accessor_flags & ACCESS_SWAP) return swab32(value); @@ -187,10 +187,10 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) b = swab32(b); if (dev->accessor_flags & ACCESS_16BIT) { - writew((u16)b, dev->base + offset); - writew((u16)(b >> 16), dev->base + offset + 2); + writew_relaxed((u16)b, dev->base + offset); + writew_relaxed((u16)(b >> 16), dev->base + offset + 2); } else { - writel(b, dev->base + offset); + writel_relaxed(b, dev->base + offset); } } @@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev) u32 hcnt, lcnt; u32 reg; u32 sda_falling_time, scl_falling_time; + int ret; + + if (dev->acquire_lock) { + ret = dev->acquire_lock(dev); + if (ret) { + dev_err(dev->dev, "couldn't acquire bus ownership\n"); + return ret; + } + } input_clock_khz = dev->get_clk_rate_khz(dev); @@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) } else if (reg != DW_IC_COMP_TYPE_VALUE) { dev_err(dev->dev, "Unknown Synopsys component type: " "0x%08x\n", reg); + if (dev->release_lock) + dev->release_lock(dev); return -ENODEV; } @@ -309,40 +320,39 @@ int i2c_dw_init(struct dw_i2c_dev *dev) sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ - /* Standard-mode */ - hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 4000, /* tHD;STA = tHIGH = 4.0 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 4700, /* tLOW = 4.7 us */ - scl_falling_time, - 0); /* No offset */ - - /* Allow platforms to specify the ideal HCNT and LCNT values */ + /* Set SCL timing parameters for standard-mode */ if (dev->ss_hcnt && dev->ss_lcnt) { hcnt = dev->ss_hcnt; lcnt = dev->ss_lcnt; + } else { + hcnt = i2c_dw_scl_hcnt(input_clock_khz, + 4000, /* tHD;STA = tHIGH = 4.0 us */ + sda_falling_time, + 0, /* 0: DW default, 1: Ideal */ + 0); /* No offset */ + lcnt = i2c_dw_scl_lcnt(input_clock_khz, + 4700, /* tLOW = 4.7 us */ + scl_falling_time, + 0); /* No offset */ } dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - /* Fast-mode */ - hcnt = i2c_dw_scl_hcnt(input_clock_khz, - 600, /* tHD;STA = tHIGH = 0.6 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(input_clock_khz, - 1300, /* tLOW = 1.3 us */ - scl_falling_time, - 0); /* No offset */ - + /* Set SCL timing parameters for fast-mode */ if (dev->fs_hcnt && dev->fs_lcnt) { hcnt = dev->fs_hcnt; lcnt = dev->fs_lcnt; + } else { + hcnt = i2c_dw_scl_hcnt(input_clock_khz, + 600, /* tHD;STA = tHIGH = 0.6 us */ + sda_falling_time, + 0, /* 0: DW default, 1: Ideal */ + 0); /* No offset */ + lcnt = i2c_dw_scl_lcnt(input_clock_khz, + 1300, /* tLOW = 1.3 us */ + scl_falling_time, + 0); /* No offset */ } dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); @@ -364,6 +374,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev) /* configure the i2c master */ dw_writel(dev, dev->master_cfg , DW_IC_CON); + + if (dev->release_lock) + dev->release_lock(dev); return 0; } EXPORT_SYMBOL_GPL(i2c_dw_init); @@ -627,6 +640,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->abort_source = 0; dev->rx_outstanding = 0; + if (dev->acquire_lock) { + ret = dev->acquire_lock(dev); + if (ret) { + dev_err(dev->dev, "couldn't acquire bus ownership\n"); + goto done_nolock; + } + } + ret = i2c_dw_wait_bus_not_busy(dev); if (ret < 0) goto done; @@ -672,6 +693,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = -EIO; done: + if (dev->release_lock) + dev->release_lock(dev); + +done_nolock: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); mutex_unlock(&dev->lock); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 5a410ef17ab..9630222abf3 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -61,6 +61,9 @@ * @ss_lcnt: standard speed LCNT value * @fs_hcnt: fast speed HCNT value * @fs_lcnt: fast speed LCNT value + * @acquire_lock: function to acquire a hardware lock on the bus + * @release_lock: function to release a hardware lock on the bus + * @pm_runtime_disabled: true if pm runtime is disabled * * HCNT and LCNT parameters can be used if the platform knows more accurate * values than the one computed based only on the input clock frequency. @@ -101,6 +104,9 @@ struct dw_i2c_dev { u16 ss_lcnt; u16 fs_hcnt; u16 fs_lcnt; + int (*acquire_lock)(struct dw_i2c_dev *dev); + void (*release_lock)(struct dw_i2c_dev *dev); + bool pm_runtime_disabled; }; #define ACCESS_SWAP 0x00000001 @@ -119,3 +125,9 @@ 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); + +#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) +extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev); +#else +static inline int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) { return 0; } +#endif diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index acb40f95db7..6643d2dc0b2 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * Copyright (C) 2011 Intel corporation. + * Copyright (C) 2011, 2015 Intel Corporation. * * ---------------------------------------------------------------------------- * @@ -40,10 +40,6 @@ #define DRIVER_NAME "i2c-designware-pci" enum dw_pci_ctl_id_t { - moorestown_0, - moorestown_1, - moorestown_2, - medfield_0, medfield_1, medfield_2, @@ -101,28 +97,7 @@ static struct dw_scl_sda_cfg hsw_config = { .sda_hold = 0x9, }; -static struct dw_pci_controller dw_pci_controllers[] = { - [moorestown_0] = { - .bus_num = 0, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [moorestown_1] = { - .bus_num = 1, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [moorestown_2] = { - .bus_num = 2, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, +static struct dw_pci_controller dw_pci_controllers[] = { [medfield_0] = { .bus_num = 0, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, @@ -170,7 +145,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .tx_fifo_depth = 32, .rx_fifo_depth = 32, - .clk_khz = 100000, .functionality = I2C_FUNC_10BIT_ADDR, .scl_sda_cfg = &byt_config, }, @@ -179,7 +153,6 @@ static struct dw_pci_controller dw_pci_controllers[] = { .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .tx_fifo_depth = 32, .rx_fifo_depth = 32, - .clk_khz = 100000, .functionality = I2C_FUNC_10BIT_ADDR, .scl_sda_cfg = &hsw_config, }, @@ -259,7 +232,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->functionality = controller->functionality | DW_DEFAULT_FUNCTIONALITY; - dev->master_cfg = controller->bus_cfg; + dev->master_cfg = controller->bus_cfg; if (controller->scl_sda_cfg) { cfg = controller->scl_sda_cfg; dev->ss_hcnt = cfg->ss_hcnt; @@ -325,12 +298,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) MODULE_ALIAS("i2c_designware-pci"); static const struct pci_device_id i2_designware_pci_ids[] = { - /* Moorestown */ - { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, - { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, - { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 }, /* Medfield */ - { PCI_VDEVICE(INTEL, 0x0817), medfield_3,}, + { PCI_VDEVICE(INTEL, 0x0817), medfield_3 }, { PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, { PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, { PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, @@ -348,7 +317,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9c61), haswell }, { PCI_VDEVICE(INTEL, 0x9c62), haswell }, /* Braswell / Cherrytrail */ - { PCI_VDEVICE(INTEL, 0x22C1), baytrail,}, + { PCI_VDEVICE(INTEL, 0x22C1), baytrail }, { PCI_VDEVICE(INTEL, 0x22C2), baytrail }, { PCI_VDEVICE(INTEL, 0x22C3), baytrail }, { PCI_VDEVICE(INTEL, 0x22C4), baytrail }, diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 2b463c313e4..c270f5f9a8f 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -195,6 +195,10 @@ static int dw_i2c_probe(struct platform_device *pdev) clk_freq = pdata->i2c_scl_freq; } + r = i2c_dw_eval_lock_support(dev); + if (r) + return r; + dev->functionality = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | @@ -257,10 +261,14 @@ static int dw_i2c_probe(struct platform_device *pdev) return r; } - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); + if (dev->pm_runtime_disabled) { + pm_runtime_forbid(&pdev->dev); + } else { + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + } return 0; } @@ -310,7 +318,9 @@ static int dw_i2c_resume(struct device *dev) struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); clk_prepare_enable(i_dev->clk); - i2c_dw_init(i_dev); + + if (!i_dev->pm_runtime_disabled) + i2c_dw_init(i_dev); return 0; } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 7f3a9fe9bf4..d7b26fc6f43 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -201,7 +201,7 @@ struct imx_i2c_struct { void __iomem *base; wait_queue_head_t queue; unsigned long i2csr; - unsigned int disable_delay; + unsigned int disable_delay; int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ unsigned int cur_clk; @@ -295,7 +295,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma->chan_tx = dma_request_slave_channel(dev, "tx"); if (!dma->chan_tx) { dev_dbg(dev, "can't request DMA tx channel\n"); - ret = -ENODEV; goto fail_al; } @@ -313,7 +312,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma->chan_rx = dma_request_slave_channel(dev, "rx"); if (!dma->chan_rx) { dev_dbg(dev, "can't request DMA rx channel\n"); - ret = -ENODEV; goto fail_tx; } @@ -481,8 +479,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) i2c_clk_rate = clk_get_rate(i2c_imx->clk); if (i2c_imx->cur_clk == i2c_clk_rate) return; - else - i2c_imx->cur_clk = i2c_clk_rate; + + i2c_imx->cur_clk = i2c_clk_rate; div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; if (div < i2c_clk_div[0].div) @@ -490,7 +488,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) i = i2c_imx->hwdata->ndivs - 1; else - for (i = 0; i2c_clk_div[i].div < div; i++); + for (i = 0; i2c_clk_div[i].div < div; i++) + ; /* Store divider value */ i2c_imx->ifdr = i2c_clk_div[i].val; @@ -628,9 +627,9 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, result = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); - if (result <= 0) { + if (result == 0) { dmaengine_terminate_all(dma->chan_using); - return result ?: -ETIMEDOUT; + return -ETIMEDOUT; } /* Waiting for transfer complete. */ @@ -686,9 +685,9 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, result = wait_for_completion_timeout( &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); - if (result <= 0) { + if (result == 0) { dmaengine_terminate_all(dma->chan_using); - return result ?: -ETIMEDOUT; + return -ETIMEDOUT; } /* waiting for transfer complete. */ @@ -822,6 +821,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; + result = i2c_imx_trx_complete(i2c_imx); if (result) return result; @@ -917,15 +917,16 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, /* write/read data */ #ifdef CONFIG_I2C_DEBUG_BUS temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, " - "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__, + dev_dbg(&i2c_imx->adapter.dev, + "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", + __func__, (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0), (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0), (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0)); temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); dev_dbg(&i2c_imx->adapter.dev, - "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, " - "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__, + "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", + __func__, (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0), (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0), (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), @@ -1004,7 +1005,7 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.owner = THIS_MODULE; i2c_imx->adapter.algo = &i2c_imx_algo; i2c_imx->adapter.dev.parent = &pdev->dev; - i2c_imx->adapter.nr = pdev->id; + i2c_imx->adapter.nr = pdev->id; i2c_imx->adapter.dev.of_node = pdev->dev.of_node; i2c_imx->base = base; @@ -1063,7 +1064,7 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.name); dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); - /* Init DMA config if support*/ + /* Init DMA config if supported */ i2c_imx_dma_request(i2c_imx, phy_addr); return 0; /* Return OK */ diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 7249b5b1e5d..abf5db7e441 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -12,6 +12,7 @@ * kind, whether express or implied. */ +#include <linux/clk.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> @@ -35,7 +36,9 @@ struct ocores_i2c { int pos; int nmsgs; int state; /* see STATE_ */ - int clock_khz; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); u8 (*getreg)(struct ocores_i2c *i2c, int reg); }; @@ -215,21 +218,34 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) return -ETIMEDOUT; } -static void ocores_init(struct ocores_i2c *i2c) +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) { int prescale; + int diff; u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); /* make sure the device is disabled */ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); - prescale = (i2c->clock_khz / (5*100)) - 1; + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); /* Init the device */ oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN); + + return 0; } @@ -304,6 +320,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; u32 val; + u32 clock_frequency; + bool clock_frequency_present; if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { /* no 'reg-shift', check for deprecated 'regstep' */ @@ -319,12 +337,42 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, } } - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, - "Missing required parameter 'clock-frequency'\n"); - return -ENODEV; + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } } - i2c->clock_khz = val / 1000; of_property_read_u32(pdev->dev.of_node, "reg-io-width", &i2c->reg_io_width); @@ -368,7 +416,8 @@ static int ocores_i2c_probe(struct platform_device *pdev) if (pdata) { i2c->reg_shift = pdata->reg_shift; i2c->reg_io_width = pdata->reg_io_width; - i2c->clock_khz = pdata->clock_khz; + i2c->ip_clock_khz = pdata->clock_khz; + i2c->bus_clock_khz = 100; } else { ret = ocores_i2c_of_probe(pdev, i2c); if (ret) @@ -402,7 +451,9 @@ static int ocores_i2c_probe(struct platform_device *pdev) } } - ocores_init(i2c); + ret = ocores_init(&pdev->dev, i2c); + if (ret) + return ret; init_waitqueue_head(&i2c->wait); ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, @@ -446,6 +497,9 @@ static int ocores_i2c_remove(struct platform_device *pdev) /* remove adapter & data */ i2c_del_adapter(&i2c->adap); + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; } @@ -458,6 +512,8 @@ static int ocores_i2c_suspend(struct device *dev) /* make sure the device is disabled */ oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN)); + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); return 0; } @@ -465,9 +521,20 @@ static int ocores_i2c_resume(struct device *dev) { struct ocores_i2c *i2c = dev_get_drvdata(dev); - ocores_init(i2c); + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); - return 0; + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); } static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 44f03eed00d..d37d9db6681 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -148,13 +148,6 @@ static inline u32 pmcmsptwi_clock_to_reg( return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff); } -static inline void pmcmsptwi_reg_to_clock( - u32 reg, struct pmcmsptwi_clock *clock) -{ - clock->filter = (reg >> 12) & 0xf; - clock->clock = reg & 0x03ff; -} - static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg) { return ((cfg->arbf & 0xf) << 12) | diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 92462843db6..5f96b1b3e3a 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -102,6 +102,9 @@ struct rk3x_i2c { /* Settings */ unsigned int scl_frequency; + unsigned int scl_rise_ns; + unsigned int scl_fall_ns; + unsigned int sda_fall_ns; /* Synchronization & notification */ spinlock_t lock; @@ -435,6 +438,9 @@ out: * * @clk_rate: I2C input clock rate * @scl_rate: Desired SCL rate + * @scl_rise_ns: How many ns it takes for SCL to rise. + * @scl_fall_ns: How many ns it takes for SCL to fall. + * @sda_fall_ns: How many ns it takes for SDA to fall. * @div_low: Divider output for low * @div_high: Divider output for high * @@ -443,11 +449,16 @@ out: * too high, we silently use the highest possible rate. */ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, + unsigned long scl_rise_ns, + unsigned long scl_fall_ns, + unsigned long sda_fall_ns, unsigned long *div_low, unsigned long *div_high) { - unsigned long min_low_ns, min_high_ns; - unsigned long max_data_hold_ns; + unsigned long spec_min_low_ns, spec_min_high_ns; + unsigned long spec_setup_start, spec_max_data_hold_ns; unsigned long data_hold_buffer_ns; + + unsigned long min_low_ns, min_high_ns; unsigned long max_low_ns, min_total_ns; unsigned long clk_rate_khz, scl_rate_khz; @@ -469,29 +480,50 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, scl_rate = 1000; /* - * min_low_ns: The minimum number of ns we need to hold low - * to meet i2c spec - * min_high_ns: The minimum number of ns we need to hold high - * to meet i2c spec - * max_low_ns: The maximum number of ns we can hold low - * to meet i2c spec + * min_low_ns: The minimum number of ns we need to hold low to + * meet I2C specification, should include fall time. + * min_high_ns: The minimum number of ns we need to hold high to + * meet I2C specification, should include rise time. + * max_low_ns: The maximum number of ns we can hold low to meet + * I2C specification. * - * Note: max_low_ns should be (max data hold time * 2 - buffer) + * Note: max_low_ns should be (maximum data hold time * 2 - buffer) * This is because the i2c host on Rockchip holds the data line * for half the low time. */ if (scl_rate <= 100000) { - min_low_ns = 4700; - min_high_ns = 4000; - max_data_hold_ns = 3450; + /* Standard-mode */ + spec_min_low_ns = 4700; + spec_setup_start = 4700; + spec_min_high_ns = 4000; + spec_max_data_hold_ns = 3450; data_hold_buffer_ns = 50; } else { - min_low_ns = 1300; - min_high_ns = 600; - max_data_hold_ns = 900; + /* Fast-mode */ + spec_min_low_ns = 1300; + spec_setup_start = 600; + spec_min_high_ns = 600; + spec_max_data_hold_ns = 900; data_hold_buffer_ns = 50; } - max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns; + min_high_ns = scl_rise_ns + spec_min_high_ns; + + /* + * Timings for repeated start: + * - controller appears to drop SDA at .875x (7/8) programmed clk high. + * - controller appears to keep SCL high for 2x programmed clk high. + * + * We need to account for those rules in picking our "high" time so + * we meet tSU;STA and tHD;STA times. + */ + min_high_ns = max(min_high_ns, + DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875)); + min_high_ns = max(min_high_ns, + DIV_ROUND_UP((scl_rise_ns + spec_setup_start + + sda_fall_ns + spec_min_high_ns), 2)); + + min_low_ns = scl_fall_ns + spec_min_low_ns; + max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns; min_total_ns = min_low_ns + min_high_ns; /* Adjust to avoid overflow */ @@ -510,8 +542,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, min_div_for_hold = (min_low_div + min_high_div); /* - * This is the maximum divider so we don't go over the max. - * We don't round up here (we round down) since this is a max. + * This is the maximum divider so we don't go over the maximum. + * We don't round up here (we round down) since this is a maximum. */ max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000); @@ -544,7 +576,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, scl_rate_khz * 8 * min_total_ns); - /* Don't allow it to go over the max */ + /* Don't allow it to go over the maximum */ if (ideal_low_div > max_low_div) ideal_low_div = max_low_div; @@ -588,9 +620,9 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) u64 t_low_ns, t_high_ns; int ret; - ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low, - &div_high); - + ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns, + i2c->scl_fall_ns, i2c->sda_fall_ns, + &div_low, &div_high); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency); clk_enable(i2c->clk); @@ -633,9 +665,10 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long switch (event) { case PRE_RATE_CHANGE: if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency, - &div_low, &div_high) != 0) { + i2c->scl_rise_ns, i2c->scl_fall_ns, + i2c->sda_fall_ns, + &div_low, &div_high) != 0) return NOTIFY_STOP; - } /* scale up */ if (ndata->new_rate > ndata->old_rate) @@ -859,6 +892,24 @@ static int rk3x_i2c_probe(struct platform_device *pdev) i2c->scl_frequency = DEFAULT_SCL_RATE; } + /* + * Read rise and fall time from device tree. If not available use + * the default maximum timing from the specification. + */ + if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns", + &i2c->scl_rise_ns)) { + if (i2c->scl_frequency <= 100000) + i2c->scl_rise_ns = 1000; + else + i2c->scl_rise_ns = 300; + } + if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns", + &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->scl_fall_ns; + strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &rk3x_i2c_algorithm; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 28b87e68350..29f14331dd9 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -286,6 +286,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) if (rx_fifo_avail > 0 && buf_remaining > 0) { BUG_ON(buf_remaining > 3); val = i2c_readl(i2c_dev, I2C_RX_FIFO); + val = cpu_to_le32(val); memcpy(buf, &val, buf_remaining); buf_remaining = 0; rx_fifo_avail--; @@ -344,6 +345,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) if (tx_fifo_avail > 0 && buf_remaining > 0) { BUG_ON(buf_remaining > 3); memcpy(&val, buf, buf_remaining); + val = le32_to_cpu(val); /* Again update before writing to FIFO to make sure isr sees. */ i2c_dev->msg_buf_remaining = 0; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e9eae57a2b5..210cf4874cb 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -102,7 +102,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) struct acpi_resource_i2c_serialbus *sb; sb = &ares->data.i2c_serial_bus; - if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + 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; @@ -698,101 +698,6 @@ static void i2c_device_shutdown(struct device *dev) driver->shutdown(client); } -#ifdef CONFIG_PM_SLEEP -static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg) -{ - struct i2c_client *client = i2c_verify_client(dev); - struct i2c_driver *driver; - - if (!client || !dev->driver) - return 0; - driver = to_i2c_driver(dev->driver); - if (!driver->suspend) - return 0; - return driver->suspend(client, mesg); -} - -static int i2c_legacy_resume(struct device *dev) -{ - struct i2c_client *client = i2c_verify_client(dev); - struct i2c_driver *driver; - - if (!client || !dev->driver) - return 0; - driver = to_i2c_driver(dev->driver); - if (!driver->resume) - return 0; - return driver->resume(client); -} - -static int i2c_device_pm_suspend(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_suspend(dev); - else - return i2c_legacy_suspend(dev, PMSG_SUSPEND); -} - -static int i2c_device_pm_resume(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_resume(dev); - else - return i2c_legacy_resume(dev); -} - -static int i2c_device_pm_freeze(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_freeze(dev); - else - return i2c_legacy_suspend(dev, PMSG_FREEZE); -} - -static int i2c_device_pm_thaw(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_thaw(dev); - else - return i2c_legacy_resume(dev); -} - -static int i2c_device_pm_poweroff(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_poweroff(dev); - else - return i2c_legacy_suspend(dev, PMSG_HIBERNATE); -} - -static int i2c_device_pm_restore(struct device *dev) -{ - const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - - if (pm) - return pm_generic_restore(dev); - else - return i2c_legacy_resume(dev); -} -#else /* !CONFIG_PM_SLEEP */ -#define i2c_device_pm_suspend NULL -#define i2c_device_pm_resume NULL -#define i2c_device_pm_freeze NULL -#define i2c_device_pm_thaw NULL -#define i2c_device_pm_poweroff NULL -#define i2c_device_pm_restore NULL -#endif /* !CONFIG_PM_SLEEP */ - static void i2c_client_dev_release(struct device *dev) { kfree(to_i2c_client(dev)); @@ -804,6 +709,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", dev->type == &i2c_client_type ? to_i2c_client(dev)->name : to_i2c_adapter(dev)->name); } +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) @@ -817,8 +723,6 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } - -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); static struct attribute *i2c_dev_attrs[] = { @@ -827,29 +731,7 @@ static struct attribute *i2c_dev_attrs[] = { &dev_attr_modalias.attr, NULL }; - -static struct attribute_group i2c_dev_attr_group = { - .attrs = i2c_dev_attrs, -}; - -static const struct attribute_group *i2c_dev_attr_groups[] = { - &i2c_dev_attr_group, - NULL -}; - -static const struct dev_pm_ops i2c_device_pm_ops = { - .suspend = i2c_device_pm_suspend, - .resume = i2c_device_pm_resume, - .freeze = i2c_device_pm_freeze, - .thaw = i2c_device_pm_thaw, - .poweroff = i2c_device_pm_poweroff, - .restore = i2c_device_pm_restore, - SET_RUNTIME_PM_OPS( - pm_generic_runtime_suspend, - pm_generic_runtime_resume, - NULL - ) -}; +ATTRIBUTE_GROUPS(i2c_dev); struct bus_type i2c_bus_type = { .name = "i2c", @@ -857,12 +739,11 @@ struct bus_type i2c_bus_type = { .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, - .pm = &i2c_device_pm_ops, }; EXPORT_SYMBOL_GPL(i2c_bus_type); static struct device_type i2c_client_type = { - .groups = i2c_dev_attr_groups, + .groups = i2c_dev_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, }; @@ -1261,6 +1142,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return count; } +static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device); /* * And of course let the users delete the devices they instantiated, if @@ -1315,8 +1197,6 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, "delete_device"); return res; } - -static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device); static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device); @@ -1326,18 +1206,10 @@ static struct attribute *i2c_adapter_attrs[] = { &dev_attr_delete_device.attr, NULL }; - -static struct attribute_group i2c_adapter_attr_group = { - .attrs = i2c_adapter_attrs, -}; - -static const struct attribute_group *i2c_adapter_attr_groups[] = { - &i2c_adapter_attr_group, - NULL -}; +ATTRIBUTE_GROUPS(i2c_adapter); struct device_type i2c_adapter_type = { - .groups = i2c_adapter_attr_groups, + .groups = i2c_adapter_groups, .release = i2c_adapter_dev_release, }; EXPORT_SYMBOL_GPL(i2c_adapter_type); @@ -1419,8 +1291,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; - request_module("%s%s", I2C_MODULE_PREFIX, info.type); - result = i2c_new_device(adap, &info); if (result == NULL) { dev_err(&adap->dev, "of_i2c: Failure registering %s\n", @@ -1796,11 +1666,15 @@ void i2c_del_adapter(struct i2c_adapter *adap) /* device name is gone after device_unregister */ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); - /* clean up the sysfs representation */ + /* wait until all references to the device are gone + * + * 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! + */ init_completion(&adap->dev_released); device_unregister(&adap->dev); - - /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); /* free bus id */ @@ -1859,14 +1733,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - /* Drivers should switch to dev_pm_ops instead. */ - if (driver->suspend) - pr_warn("i2c-core: driver [%s] using legacy suspend method\n", - driver->driver.name); - if (driver->resume) - pr_warn("i2c-core: driver [%s] using legacy resume method\n", - driver->driver.name); - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index ec11b404b43..3d8f4fe2e47 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -41,6 +41,7 @@ #include <linux/i2c-mux.h> #include <linux/i2c/pca954x.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pm.h> #include <linux/slab.h> @@ -186,6 +187,8 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *of_node = client->dev.of_node; + bool idle_disconnect_dt; struct gpio_desc *gpio; int num, force, class; struct pca954x *data; @@ -217,8 +220,13 @@ static int pca954x_probe(struct i2c_client *client, data->type = id->driver_data; data->last_chan = 0; /* force the first selection */ + idle_disconnect_dt = of_node && + of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); + /* Now create an adapter for each channel */ for (num = 0; num < chips[data->type].nchans; num++) { + bool idle_disconnect_pd = false; + force = 0; /* dynamic adap number */ class = 0; /* no class by default */ if (pdata) { @@ -229,12 +237,13 @@ static int pca954x_probe(struct i2c_client *client, } else /* discard unconfigured channels */ break; + idle_disconnect_pd = pdata->modes[num].deselect_on_exit; } data->virt_adaps[num] = i2c_add_mux_adapter(adap, &client->dev, client, force, num, class, pca954x_select_chan, - (pdata && pdata->modes[num].deselect_on_exit) + (idle_disconnect_pd || idle_disconnect_dt) ? pca954x_deselect_mux : NULL); if (data->virt_adaps[num] == NULL) { |