diff options
Diffstat (limited to 'drivers/i2c')
83 files changed, 3176 insertions, 1730 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 78fbee463628..d223650a97e4 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -88,8 +88,8 @@ config I2C_SMBUS tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO help Say Y here if you want support for SMBus extensions to the I2C - specification. At the moment, the only supported extension is - the SMBus alert protocol. + specification. At the moment, two extensions are supported: + the SMBus Alert protocol and the SMBus Host Notify protocol. This support is also available as a module. If so, the module will be called i2c-smbus. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f167021b8c21..6d94e2ec5b4f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -91,6 +91,7 @@ config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI select CHECK_SIGNATURE if X86 && DMI + select I2C_SMBUS help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -397,7 +398,7 @@ config I2C_BCM_KONA config I2C_BRCMSTB tristate "BRCM Settop I2C controller" - depends on ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST default y help If you say yes to this option, support will be included for the @@ -490,7 +491,9 @@ config I2C_DESIGNWARE_PCI config I2C_DESIGNWARE_BAYTRAIL bool "Intel Baytrail I2C semaphore support" - depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI + depends on ACPI + depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \ + (I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y) 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 @@ -635,7 +638,7 @@ config I2C_LPC2K config I2C_MESON tristate "Amlogic Meson I2C controller" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST help If you say yes to this option, support will be included for the I2C interface on the Amlogic Meson family of SoCs. @@ -833,7 +836,7 @@ config I2C_SH7760 config I2C_SH_MOBILE tristate "SuperH Mobile I2C Controller" depends on HAS_DMA - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST + depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST help If you say yes to this option, support will be included for the built-in I2C interface on the Renesas SH-Mobile processor. @@ -924,7 +927,7 @@ config I2C_UNIPHIER_F config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS + depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || COMPILE_TEST select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile @@ -953,6 +956,17 @@ config I2C_OCTEON This driver can also be built as a module. If so, the module will be called i2c-octeon. +config I2C_THUNDERX + tristate "Cavium ThunderX I2C bus support" + depends on 64BIT && PCI && (ARM64 || COMPILE_TEST) + select I2C_SMBUS + help + Say yes if you want to support the I2C serial bus on Cavium + ThunderX SOC. + + This driver can also be built as a module. If so, the module + will be called i2c-thunderx. + config I2C_XILINX tristate "Xilinx I2C Controller" depends on HAS_IOMEM diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37f2819b4560..29764cc20a44 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -91,7 +91,10 @@ 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 +i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o +i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o +obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 6c7113d990f8..274908cd1fde 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -378,11 +378,8 @@ static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id) amd756_ioport); error = i2c_add_adapter(&amd756_smbus); - if (error) { - dev_err(&pdev->dev, - "Adapter registration failed, module not inserted\n"); + if (error) goto out_err; - } return 0; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index f23372669f77..0b86c6173e07 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -38,6 +38,7 @@ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ #define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ #define AUTOSUSPEND_TIMEOUT 2000 +#define AT91_I2C_MAX_ALT_CMD_DATA_SIZE 256 /* AT91 TWI register definitions */ #define AT91_TWI_CR 0x0000 /* Control Register */ @@ -141,6 +142,7 @@ struct at91_twi_dev { unsigned twi_cwgr_reg; struct at91_twi_pdata *pdata; bool use_dma; + bool use_alt_cmd; bool recv_len_abort; u32 fifo_size; struct at91_twi_dma dma; @@ -269,7 +271,7 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev) /* send stop when last byte has been written */ if (--dev->buf_len == 0) - if (!dev->pdata->has_alt_cmd) + if (!dev->use_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); @@ -292,7 +294,7 @@ 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); - if (!dev->pdata->has_alt_cmd) + if (!dev->use_alt_cmd) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } @@ -410,7 +412,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->pdata->has_alt_cmd && dev->buf_len == 1) + if (!dev->use_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); @@ -426,7 +428,7 @@ static void at91_twi_read_data_dma_callback(void *data) dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_FROM_DEVICE); - if (!dev->pdata->has_alt_cmd) { + if (!dev->use_alt_cmd) { /* The last two bytes have to be read without using dma */ dev->buf += dev->buf_len - 2; dev->buf_len = 2; @@ -443,7 +445,7 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) 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; + buf_len = (dev->use_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 */ @@ -651,7 +653,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) unsigned start_flags = AT91_TWI_START; /* if only one byte is to be read, immediately stop transfer */ - if (!has_alt_cmd && dev->buf_len <= 1 && + if (!dev->use_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); @@ -745,7 +747,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; + bool is_read; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); @@ -768,14 +770,16 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) at91_twi_write(dev, AT91_TWI_IADR, internal_address); } + dev->use_alt_cmd = false; is_read = (m_start->flags & I2C_M_RD); if (dev->pdata->has_alt_cmd) { - if (m_start->len > 0) { + if (m_start->len > 0 && + m_start->len < AT91_I2C_MAX_ALT_CMD_DATA_SIZE) { 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; + dev->use_alt_cmd = true; } else { at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS); } @@ -784,7 +788,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag | - ((!use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); + ((!dev->use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); dev->buf_len = m_start->len; dev->buf = m_start->buf; @@ -1118,8 +1122,6 @@ static int at91_twi_probe(struct platform_device *pdev) rc = i2c_add_numbered_adapter(&dev->adapter); if (rc) { - dev_err(dev->dev, "Adapter %s registration failed\n", - dev->adapter.name); clk_disable_unprepare(dev->clk); pm_runtime_disable(dev->dev); diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index c335cc7852f9..4351a9343058 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -545,7 +545,11 @@ static int axxia_i2c_probe(struct platform_device *pdev) return ret; } - clk_prepare_enable(idev->i2c_clk); + ret = clk_prepare_enable(idev->i2c_clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return ret; + } i2c_set_adapdata(&idev->adapter, idev); strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); @@ -560,7 +564,7 @@ static int axxia_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&idev->adapter); if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); + clk_disable_unprepare(idev->i2c_clk); return ret; } diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 19c843828fe2..326b3db02c48 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -158,7 +158,7 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) if (status & BIT(IS_M_START_BUSY_SHIFT)) { iproc_i2c->xfer_is_done = 1; - complete_all(&iproc_i2c->done); + complete(&iproc_i2c->done); } writel(status, iproc_i2c->base + IS_OFFSET); @@ -488,13 +488,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) 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; + return i2c_add_adapter(adap); } static int bcm_iproc_i2c_remove(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index ac9f47679c3a..4e489a9d16fb 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -229,7 +229,7 @@ static irqreturn_t bcm_kona_i2c_isr(int irq, void *devid) dev->base + TXFCR_OFFSET); writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET); - complete_all(&dev->done); + complete(&dev->done); return IRQ_HANDLED; } @@ -643,7 +643,7 @@ static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter, if (rc < 0) { dev_err(dev->device, "restart cmd failed rc = %d\n", rc); - goto xfer_send_stop; + goto xfer_send_stop; } } @@ -858,10 +858,8 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) adap->dev.of_node = pdev->dev.of_node; rc = i2c_add_adapter(adap); - if (rc) { - dev_err(dev->device, "failed to add adapter\n"); + if (rc) return rc; - } dev_info(dev->device, "device registered successfully\n"); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 818b051d25e6..d4f3239b5686 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -253,7 +253,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "Could not get clock\n"); + if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get clock\n"); return PTR_ERR(i2c_dev->clk); } diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 025686d41640..29d00c4f7824 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -685,10 +685,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); rc = i2c_add_numbered_adapter(p_adap); - if (rc < 0) { - dev_err(&pdev->dev, "Can't add i2c adapter!\n"); + if (rc < 0) goto out_error; - } platform_set_drvdata(pdev, iface); diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 6a8cfc1344b2..0652281662a8 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -228,7 +228,7 @@ static irqreturn_t brcmstb_i2c_isr(int irq, void *devid) return IRQ_NONE; brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); - complete_all(&dev->done); + complete(&dev->done); dev_dbg(dev->device, "isr handled"); return IRQ_HANDLED; @@ -343,10 +343,9 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, struct bsc_regs *pi2creg = dev->bsc_regmap; int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; int data_regsz = brcmstb_i2c_get_data_regsz(dev); - int xfersz = brcmstb_i2c_get_xfersz(dev); /* see if the transaction needs to check NACK conditions */ - if (no_ack || len <= xfersz) { + if (no_ack) { cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK : CMD_WR_NOACK; pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; @@ -649,10 +648,8 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) 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"); + if (rc) goto probe_errorout; - } dev_info(dev->device, "%s@%dhz registered in %s mode\n", int_name ? int_name : " ", dev->clk_freq_hz, diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 90bbd9f9dd8f..686971263bef 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -767,7 +767,7 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id) * depending on the scaling direction. * * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK - * to acknowedge the change, NOTIFY_DONE if the notification is + * to acknowledge the change, NOTIFY_DONE if the notification is * considered irrelevant. */ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long @@ -963,10 +963,8 @@ static int cdns_i2c_probe(struct platform_device *pdev) } ret = i2c_add_adapter(&id->adap); - if (ret < 0) { - dev_err(&pdev->dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto err_clk_dis; - } /* * Cadence I2C controller has a bug wherein it generates diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index ee57c1e865e2..d89bde2c5da2 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -665,10 +665,8 @@ static int cpm_i2c_probe(struct platform_device *ofdev) cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; result = i2c_add_numbered_adapter(&cpm->adap); - if (result < 0) { - dev_err(&ofdev->dev, "Unable to register with I2C\n"); + if (result < 0) goto out_shut; - } dev_dbg(&ofdev->dev, "hw routines for %s registered.\n", cpm->adap.name); diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index a0d95ff682ae..9b36a7b3befd 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -215,7 +215,7 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], msg->outsize = request_len; msg->insize = response_len; - result = cros_ec_cmd_xfer(bus->ec, msg); + result = cros_ec_cmd_xfer_status(bus->ec, msg); if (result < 0) { dev_err(dev, "Error transferring EC i2c message %d\n", result); goto exit; @@ -281,10 +281,8 @@ static int ec_i2c_probe(struct platform_device *pdev) bus->adap.retries = I2C_MAX_RETRIES; err = i2c_add_adapter(&bus->adap); - if (err) { - dev_err(dev, "cannot register i2c adapter\n"); + if (err) return err; - } platform_set_drvdata(pdev, bus); return err; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index a8bdcb5292f5..9e7ef5cf5d49 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -846,10 +846,8 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(&pdev->dev, "failure adding adapter\n"); + if (r) goto err_unuse_clocks; - } return 0; diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 99b54be6ba73..1fe93c43215c 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -42,6 +42,8 @@ #define DW_IC_SS_SCL_LCNT 0x18 #define DW_IC_FS_SCL_HCNT 0x1c #define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_HS_SCL_HCNT 0x24 +#define DW_IC_HS_SCL_LCNT 0x28 #define DW_IC_INTR_STAT 0x2c #define DW_IC_INTR_MASK 0x30 #define DW_IC_RAW_INTR_STAT 0x34 @@ -89,12 +91,17 @@ DW_IC_INTR_TX_ABRT | \ DW_IC_INTR_STOP_DET) -#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_TFE BIT(2) +#define DW_IC_STATUS_MST_ACTIVITY BIT(5) #define DW_IC_ERR_TX_ABRT 0x1 #define DW_IC_TAR_10BITADDR_MASTER BIT(12) +#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) +#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2) + /* * status codes */ @@ -252,10 +259,15 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) { + dw_writel(dev, enable, DW_IC_ENABLE); +} + +static void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) +{ int timeout = 100; do { - dw_writel(dev, enable, DW_IC_ENABLE); + __i2c_dw_enable(dev, enable); if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) return; @@ -282,6 +294,28 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +static int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) +{ + int ret; + + if (!dev->acquire_lock) + return 0; + + ret = dev->acquire_lock(dev); + if (!ret) + return 0; + + dev_err(dev->dev, "couldn't acquire bus ownership\n"); + + return ret; +} + +static void i2c_dw_release_lock(struct dw_i2c_dev *dev) +{ + if (dev->release_lock) + dev->release_lock(dev); +} + /** * i2c_dw_init() - initialize the designware i2c master hardware * @dev: device private data @@ -293,17 +327,13 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) int i2c_dw_init(struct dw_i2c_dev *dev) { u32 hcnt, lcnt; - u32 reg; + u32 reg, comp_param1; 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; - } - } + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; reg = dw_readl(dev, DW_IC_COMP_TYPE); if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { @@ -315,13 +345,14 @@ 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); + i2c_dw_release_lock(dev); return -ENODEV; } + comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); + /* Disable the adapter */ - __i2c_dw_enable(dev, false); + __i2c_dw_enable_and_wait(dev, false); /* set standard and fast speed deviders for high/low periods */ @@ -347,8 +378,11 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - /* Set SCL timing parameters for fast-mode */ - if (dev->fs_hcnt && dev->fs_lcnt) { + /* Set SCL timing parameters for fast-mode or fast-mode plus */ + if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { + hcnt = dev->fp_hcnt; + lcnt = dev->fp_lcnt; + } else if (dev->fs_hcnt && dev->fs_lcnt) { hcnt = dev->fs_hcnt; lcnt = dev->fs_lcnt; } else { @@ -366,14 +400,35 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) == + DW_IC_CON_SPEED_HIGH) { + if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) + != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { + dev_err(dev->dev, "High Speed not supported!\n"); + dev->master_cfg &= ~DW_IC_CON_SPEED_MASK; + dev->master_cfg |= DW_IC_CON_SPEED_FAST; + } else if (dev->hs_hcnt && dev->hs_lcnt) { + hcnt = dev->hs_hcnt; + lcnt = dev->hs_lcnt; + dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); + dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); + dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", + hcnt, lcnt); + } + } + /* Configure SDA Hold Time if required */ - if (dev->sda_hold_time) { - reg = dw_readl(dev, DW_IC_COMP_VERSION); - if (reg >= DW_IC_SDA_HOLD_MIN_VERS) + reg = dw_readl(dev, DW_IC_COMP_VERSION); + if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { + if (dev->sda_hold_time) { dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - else - dev_warn(dev->dev, - "Hardware too old to adjust SDA hold time."); + } else { + /* Keep previous hold time setting if no one set it */ + dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD); + } + } else { + dev_warn(dev->dev, + "Hardware too old to adjust SDA hold time.\n"); } /* Configure Tx/Rx FIFO threshold levels */ @@ -383,8 +438,8 @@ 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); + i2c_dw_release_lock(dev); + return 0; } EXPORT_SYMBOL_GPL(i2c_dw_init); @@ -411,27 +466,45 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) { struct i2c_msg *msgs = dev->msgs; - u32 ic_con, ic_tar = 0; + u32 ic_tar = 0; + bool enabled; - /* Disable the adapter */ - __i2c_dw_enable(dev, false); + enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1; + + if (enabled) { + u32 ic_status; + + /* + * Only disable adapter if ic_tar and ic_con can't be + * dynamically updated + */ + ic_status = dw_readl(dev, DW_IC_STATUS); + if (!dev->dynamic_tar_update_enabled || + (ic_status & DW_IC_STATUS_MST_ACTIVITY) || + !(ic_status & DW_IC_STATUS_TFE)) { + __i2c_dw_enable_and_wait(dev, false); + enabled = false; + } + } /* if the slave address is ten bit address, enable 10BITADDR */ - ic_con = dw_readl(dev, DW_IC_CON); - if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) { - ic_con |= DW_IC_CON_10BITADDR_MASTER; + if (dev->dynamic_tar_update_enabled) { /* * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing - * mode has to be enabled via bit 12 of IC_TAR register. - * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be - * detected from registers. + * mode has to be enabled via bit 12 of IC_TAR register, + * otherwise bit 4 of IC_CON is used. */ - ic_tar = DW_IC_TAR_10BITADDR_MASTER; + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_tar = DW_IC_TAR_10BITADDR_MASTER; } else { - ic_con &= ~DW_IC_CON_10BITADDR_MASTER; - } + u32 ic_con = dw_readl(dev, DW_IC_CON); - dw_writel(dev, ic_con, DW_IC_CON); + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_con |= DW_IC_CON_10BITADDR_MASTER; + else + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + dw_writel(dev, ic_con, DW_IC_CON); + } /* * Set the slave (target) address and enable 10-bit addressing mode @@ -442,8 +515,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* enforce disabled interrupts (due to HW issues) */ i2c_dw_disable_int(dev); - /* Enable the adapter */ - __i2c_dw_enable(dev, true); + if (!enabled) + __i2c_dw_enable(dev, true); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); @@ -624,7 +697,8 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) } /* - * Prepare controller for a transaction and call i2c_dw_xfer_msg + * Prepare controller for a transaction and start transfer by calling + * i2c_dw_xfer_init() */ static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -647,13 +721,9 @@ 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_acquire_lock(dev); + if (ret) + goto done_nolock; ret = i2c_dw_wait_bus_not_busy(dev); if (ret < 0) @@ -663,7 +733,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) { + if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_dw_init(dev); @@ -671,16 +741,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) goto done; } - /* - * We must disable the adapter before returning and signaling the end - * of the current transfer. Otherwise the hardware might continue - * generating interrupts which in turn causes a race condition with - * the following transfer. Needs some more investigation if the - * additional interrupts are a hardware bug or this driver doesn't - * handle them correctly yet. - */ - __i2c_dw_enable(dev, false); - if (dev->msg_err) { ret = dev->msg_err; goto done; @@ -700,8 +760,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = -EIO; done: - if (dev->release_lock) - dev->release_lock(dev); + i2c_dw_release_lock(dev); done_nolock: pm_runtime_mark_last_busy(dev->dev); @@ -818,9 +877,19 @@ static 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) + if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) + || dev->msg_err) { + /* + * We must disable interruts before returning and signaling + * the end of the current transfer. Otherwise the hardware + * might continue generating interrupts for non-existent + * transfers. + */ + i2c_dw_disable_int(dev); + dw_readl(dev, DW_IC_CLR_INTR); + complete(&dev->cmd_complete); - else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { + } 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); @@ -833,7 +902,7 @@ tx_aborted: void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ - __i2c_dw_enable(dev, false); + __i2c_dw_enable_and_wait(dev, false); /* Disable all interupts */ dw_writel(dev, 0, DW_IC_INTR_MASK); @@ -857,6 +926,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; int r; + u32 reg; init_completion(&dev->cmd_complete); @@ -864,6 +934,26 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) if (r) return r; + r = i2c_dw_acquire_lock(dev); + if (r) + return r; + + /* + * Test if dynamic TAR update is enabled in this controller by writing + * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this + * field is read-only so it should not succeed + */ + reg = dw_readl(dev, DW_IC_CON); + dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON); + + if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) == + (reg & DW_IC_CON_10BITADDR_MASTER)) { + dev->dynamic_tar_update_enabled = true; + dev_dbg(dev->dev, "Dynamic TAR update enabled"); + } + + i2c_dw_release_lock(dev); + snprintf(adap->name, sizeof(adap->name), "Synopsys DesignWare I2C adapter"); adap->retries = 3; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index cd409e7fbc71..0d44d2ae7d4c 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -26,6 +26,8 @@ #define DW_IC_CON_MASTER 0x1 #define DW_IC_CON_SPEED_STD 0x2 #define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_SPEED_HIGH 0x6 +#define DW_IC_CON_SPEED_MASK 0x6 #define DW_IC_CON_10BITADDR_MASTER 0x10 #define DW_IC_CON_RESTART_EN 0x20 #define DW_IC_CON_SLAVE_DISABLE 0x40 @@ -56,10 +58,15 @@ * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo * @rx_outstanding: current master-rx elements in tx fifo + * @clk_freq: bus clock frequency * @ss_hcnt: standard speed HCNT value * @ss_lcnt: standard speed LCNT value * @fs_hcnt: fast speed HCNT value * @fs_lcnt: fast speed LCNT value + * @fp_hcnt: fast plus HCNT value + * @fp_lcnt: fast plus LCNT value + * @hs_hcnt: high speed HCNT value + * @hs_lcnt: high 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 @@ -95,6 +102,7 @@ struct dw_i2c_dev { unsigned int tx_fifo_depth; unsigned int rx_fifo_depth; int rx_outstanding; + u32 clk_freq; u32 sda_hold_time; u32 sda_falling_time; u32 scl_falling_time; @@ -102,9 +110,14 @@ struct dw_i2c_dev { u16 ss_lcnt; u16 fs_hcnt; u16 fs_lcnt; + u16 fp_hcnt; + u16 fp_lcnt; + u16 hs_hcnt; + u16 hs_lcnt; int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_runtime_disabled; + bool dynamic_tar_update_enabled; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 7368be000c96..96f8230cd2d3 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, 2015 Intel Corporation. + * Copyright (C) 2011, 2015, 2016 Intel Corporation. * * ---------------------------------------------------------------------------- * @@ -23,31 +23,27 @@ * */ -#include <linux/kernel.h> -#include <linux/module.h> +#include <linux/acpi.h> #include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/errno.h> -#include <linux/sched.h> #include <linux/err.h> +#include <linux/errno.h> +#include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/pm_runtime.h> -#include <linux/acpi.h> +#include <linux/sched.h> +#include <linux/slab.h> + #include "i2c-designware-core.h" #define DRIVER_NAME "i2c-designware-pci" enum dw_pci_ctl_id_t { - medfield_0, - medfield_1, - medfield_2, - medfield_3, - medfield_4, - medfield_5, - + medfield, + merrifield, baytrail, haswell, }; @@ -68,6 +64,7 @@ struct dw_pci_controller { u32 clk_khz; u32 functionality; struct dw_scl_sda_cfg *scl_sda_cfg; + int (*setup)(struct pci_dev *pdev, struct dw_pci_controller *c); }; #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ @@ -80,6 +77,14 @@ struct dw_pci_controller { I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) +/* Merrifield HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg mrfld_config = { + .ss_hcnt = 0x2f8, + .fs_hcnt = 0x87, + .ss_lcnt = 0x37b, + .fs_lcnt = 0x10a, +}; + /* BayTrail HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg byt_config = { .ss_hcnt = 0x200, @@ -98,48 +103,60 @@ static struct dw_scl_sda_cfg hsw_config = { .sda_hold = 0x9, }; +static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) +{ + switch (pdev->device) { + case 0x0817: + c->bus_cfg &= ~DW_IC_CON_SPEED_MASK; + c->bus_cfg |= DW_IC_CON_SPEED_STD; + case 0x0818: + case 0x0819: + c->bus_num = pdev->device - 0x817 + 3; + return 0; + case 0x082C: + case 0x082D: + case 0x082E: + c->bus_num = pdev->device - 0x82C + 0; + return 0; + } + return -ENODEV; +} + +static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) +{ + /* + * On Intel Merrifield the user visible i2c busses are enumerated + * [1..7]. So, we add 1 to shift the default range. Besides that the + * first PCI slot provides 4 functions, that's why we have to add 0 to + * the first slot and 4 to the next one. + */ + switch (PCI_SLOT(pdev->devfn)) { + case 8: + c->bus_num = PCI_FUNC(pdev->devfn) + 0 + 1; + return 0; + case 9: + c->bus_num = PCI_FUNC(pdev->devfn) + 4 + 1; + return 0; + } + return -ENODEV; +} + static struct dw_pci_controller dw_pci_controllers[] = { - [medfield_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, - }, - [medfield_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, - }, - [medfield_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, - }, - [medfield_3] = { - .bus_num = 3, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_4] = { - .bus_num = 4, + [medfield] = { + .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, + .setup = mfld_setup, }, - [medfield_5] = { - .bus_num = 5, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, + [merrifield] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, + .tx_fifo_depth = 64, + .rx_fifo_depth = 64, + .scl_sda_cfg = &mrfld_config, + .setup = mrfld_setup, }, [baytrail] = { .bus_num = -1, @@ -190,7 +207,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct dw_i2c_dev *dev; struct i2c_adapter *adap; int r; - struct dw_pci_controller *controller; + struct dw_pci_controller *controller; struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { @@ -224,6 +241,13 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->base = pcim_iomap_table(pdev)[0]; dev->dev = &pdev->dev; dev->irq = pdev->irq; + + if (controller->setup) { + r = controller->setup(pdev, controller); + if (r) + return r; + } + dev->functionality = controller->functionality | DW_DEFAULT_FUNCTIONALITY; @@ -276,12 +300,15 @@ MODULE_ALIAS("i2c_designware-pci"); static const struct pci_device_id i2_designware_pci_ids[] = { /* Medfield */ - { PCI_VDEVICE(INTEL, 0x0817), medfield_3 }, - { PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, - { PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, - { PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, - { PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, - { PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, + { PCI_VDEVICE(INTEL, 0x0817), medfield }, + { PCI_VDEVICE(INTEL, 0x0818), medfield }, + { PCI_VDEVICE(INTEL, 0x0819), medfield }, + { PCI_VDEVICE(INTEL, 0x082C), medfield }, + { PCI_VDEVICE(INTEL, 0x082D), medfield }, + { PCI_VDEVICE(INTEL, 0x082E), medfield }, + /* Merrifield */ + { PCI_VDEVICE(INTEL, 0x1195), merrifield }, + { PCI_VDEVICE(INTEL, 0x1196), merrifield }, /* Baytrail */ { PCI_VDEVICE(INTEL, 0x0F41), baytrail }, { PCI_VDEVICE(INTEL, 0x0F42), baytrail }, diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d656657b805c..0b42a12171f3 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -107,6 +107,8 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL); dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &dev->sda_hold_time); + dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL); + dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL); id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (id && id->driver_data) @@ -155,7 +157,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct resource *mem; int irq, r; - u32 clk_freq, ht = 0; + u32 acpi_speed, ht = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -175,10 +177,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); /* fast mode by default because of legacy reasons */ - clk_freq = 400000; + dev->clk_freq = 400000; if (pdata) { - clk_freq = pdata->i2c_scl_freq; + dev->clk_freq = pdata->i2c_scl_freq; } else { device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", &ht); @@ -187,17 +189,24 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", &dev->scl_falling_time); device_property_read_u32(&pdev->dev, "clock-frequency", - &clk_freq); + &dev->clk_freq); } + acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev); + if (acpi_speed) + dev->clk_freq = acpi_speed; + if (has_acpi_companion(&pdev->dev)) dw_i2c_acpi_configure(pdev); /* - * Only standard mode at 100kHz and fast mode at 400kHz are supported. + * Only standard mode at 100kHz, fast mode at 400kHz, + * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported. */ - if (clk_freq != 100000 && clk_freq != 400000) { - dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); + if (dev->clk_freq != 100000 && dev->clk_freq != 400000 + && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { + dev_err(&pdev->dev, + "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported"); return -EINVAL; } @@ -212,12 +221,20 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; - if (clk_freq == 100000) - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | - DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_STD; - else - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | - DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; + + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN; + + switch (dev->clk_freq) { + case 100000: + dev->master_cfg |= DW_IC_CON_SPEED_STD; + break; + case 3400000: + dev->master_cfg |= DW_IC_CON_SPEED_HIGH; + break; + default: + dev->master_cfg |= DW_IC_CON_SPEED_FAST; + } dev->clk = devm_clk_get(&pdev->dev, NULL); if (!i2c_dw_plat_prepare_clk(dev, true)) { diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index b19a310bf9b3..f718ee4e3332 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -487,10 +487,8 @@ static int diolan_u2c_probe(struct usb_interface *interface, /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dev->adapter); - if (ret < 0) { - dev_err(&interface->dev, "failed to add I2C adapter\n"); + if (ret < 0) goto error_free; - } dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n"); diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index f2eb4f76591f..8acda2aa1558 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -228,10 +228,8 @@ static int dln2_i2c_probe(struct platform_device *pdev) /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dln2->adapter); - if (ret < 0) { - dev_err(dev, "failed to add I2C adapter: %d\n", ret); + if (ret < 0) goto out_disable; - } return 0; diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index 8eff62738877..aa336ba89aa3 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -433,12 +433,11 @@ static int efm32_i2c_probe(struct platform_device *pdev) ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq (%d)\n", ret); - return ret; + goto err_disable_clk; } ret = i2c_add_adapter(&ddata->adapter); if (ret) { - dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret); free_irq(ddata->irq, ddata); err_disable_clk: diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 137125b5eae7..5ce71ce7b6c4 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -773,13 +773,6 @@ static int pch_i2c_probe(struct pci_dev *pdev, /* Set the number of I2C channel instance */ adap_info->ch_num = id->driver_data; - ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, - KBUILD_MODNAME, adap_info); - if (ret) { - pch_pci_err(pdev, "request_irq FAILED\n"); - goto err_request_irq; - } - for (i = 0; i < adap_info->ch_num; i++) { pch_adap = &adap_info->pch_data[i].pch_adapter; adap_info->pch_i2c_suspended = false; @@ -797,6 +790,17 @@ static int pch_i2c_probe(struct pci_dev *pdev, pch_adap->dev.of_node = pdev->dev.of_node; pch_adap->dev.parent = &pdev->dev; + } + + ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, + KBUILD_MODNAME, adap_info); + if (ret) { + pch_pci_err(pdev, "request_irq FAILED\n"); + goto err_request_irq; + } + + for (i = 0; i < adap_info->ch_num; i++) { + pch_adap = &adap_info->pch_data[i].pch_adapter; pch_i2c_init(&adap_info->pch_data[i]); diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 92e8c0ce1625..8af62fb3fe41 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -319,16 +319,6 @@ static struct isa_driver i2c_elektor_driver = { }, }; -static int __init i2c_pcfisa_init(void) -{ - return isa_register_driver(&i2c_elektor_driver, 1); -} - -static void __exit i2c_pcfisa_exit(void) -{ - isa_unregister_driver(&i2c_elektor_driver); -} - MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); @@ -338,6 +328,4 @@ module_param(irq, int, 0); module_param(clock, int, 0); module_param(own, int, 0); module_param(mmapped, int, 0); - -module_init(i2c_pcfisa_init); -module_exit(i2c_pcfisa_exit); +module_isa_driver(i2c_elektor_driver, 1); diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index c0e3ada02876..bea607149972 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -796,10 +796,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev) exynos5_i2c_reset(i2c); ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + if (ret < 0) goto err_clk; - } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 7c6966434ee7..ae7f3180f7e8 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -478,10 +478,8 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) pm_runtime_enable(priv->dev); ret = i2c_add_adapter(&priv->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + if (ret < 0) goto err_runtime; - } return ret; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 64b1208bca5e..08847e8b8998 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,6 +64,7 @@ * 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 + * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -72,6 +73,7 @@ * Block process call transaction no * I2C block read transaction yes (doesn't use the block buffer) * Slave mode no + * SMBus Host Notify yes * Interrupt processing yes * * See the file Documentation/i2c/busses/i2c-i801 for details. @@ -86,6 +88,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> #include <linux/acpi.h> #include <linux/io.h> #include <linux/dmi.h> @@ -96,8 +99,7 @@ #include <linux/platform_data/itco_wdt.h> #include <linux/pm_runtime.h> -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI #include <linux/gpio.h> #include <linux/i2c-mux-gpio.h> #endif @@ -113,6 +115,10 @@ #define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ #define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ #define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ +#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ +#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDDAT(p) (22 + (p)->smba) /* ICH3 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -144,6 +150,10 @@ /* TCO configuration bits for TCOCTL */ #define TCOCTL_EN 0x0100 +/* Auxiliary status register bits, ICH4+ only */ +#define SMBAUXSTS_CRCE 1 +#define SMBAUXSTS_STCO 2 + /* Auxiliary control register bits, ICH4+ only */ #define SMBAUXCTL_CRC 1 #define SMBAUXCTL_E32B 2 @@ -177,6 +187,12 @@ #define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_HOST_BUSY 0x01 +/* Host Notify Status registers bits */ +#define SMBSLVSTS_HST_NTFY_STS 1 + +/* Host Notify Command registers bits */ +#define SMBSLVCMD_HST_NTFY_INTREN 0x01 + #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ SMBHSTSTS_DEV_ERR) @@ -211,6 +227,7 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 +#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 struct i801_mux_config { char *gpio_chip; @@ -239,19 +256,29 @@ struct i801_priv { int len; u8 *data; -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; #endif struct platform_device *tco_pdev; + + /* + * If set to true the host controller registers are reserved for + * ACPI AML use. Protected by acpi_lock. + */ + bool acpi_reserved; + struct mutex acpi_lock; + struct smbus_host_notify *host_notify; }; +#define SMBHSTNTFY_SIZE 8 + #define FEATURE_SMBUS_PEC (1 << 0) #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_I2C_BLOCK_READ (1 << 3) #define FEATURE_IRQ (1 << 4) +#define FEATURE_HOST_NOTIFY (1 << 5) /* Not really a feature, but it's convenient to handle it as such */ #define FEATURE_IDF (1 << 15) #define FEATURE_TCO (1 << 16) @@ -262,6 +289,7 @@ static const char *i801_feature_names[] = { "Block process call", "I2C block read", "Interrupt", + "SMBus Host Notify", }; static unsigned int disable_features; @@ -270,7 +298,8 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" "\t\t 0x01 disable SMBus PEC\n" "\t\t 0x02 disable the block buffer\n" "\t\t 0x08 disable the I2C block read functionality\n" - "\t\t 0x10 don't use interrupts "); + "\t\t 0x10 don't use interrupts\n" + "\t\t 0x20 disable SMBus Host Notify "); /* Make sure the SMBus host is ready to start transmitting. Return 0 if it is, -EBUSY if it is not. */ @@ -298,6 +327,29 @@ static int i801_check_pre(struct i801_priv *priv) } } + /* + * Clear CRC status if needed. + * During normal operation, i801_check_post() takes care + * of it after every operation. We do it here only in case + * the hardware was already in this state when the driver + * started. + */ + if (priv->features & FEATURE_SMBUS_PEC) { + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_dbg(&priv->pci_dev->dev, + "Clearing aux status flags (%02x)\n", status); + outb_p(status, SMBAUXSTS(priv)); + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing aux status flags (%02x)\n", + status); + return -EBUSY; + } + } + } + return 0; } @@ -341,8 +393,30 @@ static int i801_check_post(struct i801_priv *priv, int status) dev_err(&priv->pci_dev->dev, "Transaction failed\n"); } if (status & SMBHSTSTS_DEV_ERR) { - result = -ENXIO; - dev_dbg(&priv->pci_dev->dev, "No response\n"); + /* + * This may be a PEC error, check and clear it. + * + * AUXSTS is handled differently from HSTSTS. + * For HSTSTS, i801_isr() or i801_wait_intr() + * has already cleared the error bits in hardware, + * and we are passed a copy of the original value + * in "status". + * For AUXSTS, the hardware register is left + * for us to handle here. + * This is asymmetric, slightly iffy, but safe, + * since all this code is serialized and the CRCE + * bit is harmless as long as it's cleared before + * the next operation. + */ + if ((priv->features & FEATURE_SMBUS_PEC) && + (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { + outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); + result = -EBADMSG; + dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + } else { + result = -ENXIO; + dev_dbg(&priv->pci_dev->dev, "No response\n"); + } } if (status & SMBHSTSTS_BUS_ERR) { result = -EAGAIN; @@ -504,8 +578,23 @@ static void i801_isr_byte_done(struct i801_priv *priv) outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } +static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) +{ + unsigned short addr; + unsigned int data; + + addr = inb_p(SMBNTFDADD(priv)) >> 1; + data = inw_p(SMBNTFDDAT(priv)); + + i2c_handle_smbus_host_notify(priv->host_notify, addr, data); + + /* clear Host Notify bit and return */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + return IRQ_HANDLED; +} + /* - * There are two kinds of interrupts: + * There are three kinds of interrupts: * * 1) i801 signals transaction completion with one of these interrupts: * INTR - Success @@ -517,6 +606,8 @@ static void i801_isr_byte_done(struct i801_priv *priv) * * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt * occurs for each byte of a byte-by-byte to prepare the next byte. + * + * 3) Host Notify interrupts */ static irqreturn_t i801_isr(int irq, void *dev_id) { @@ -529,6 +620,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id) if (!(pcists & SMBPCISTS_INTS)) return IRQ_NONE; + if (priv->features & FEATURE_HOST_NOTIFY) { + status = inb_p(SMBSLVSTS(priv)); + if (status & SMBSLVSTS_HST_NTFY_STS) + return i801_host_notify_isr(priv); + } + status = inb_p(SMBHSTSTS(priv)); if (status & SMBHSTSTS_BYTE_DONE) i801_isr_byte_done(priv); @@ -540,7 +637,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id) status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; if (status) { outb_p(status, SMBHSTSTS(priv)); - priv->status |= status; + priv->status = status; wake_up(&priv->waitq); } @@ -718,6 +815,12 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, int ret = 0, xact = 0; struct i801_priv *priv = i2c_get_adapdata(adap); + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) { + mutex_unlock(&priv->acpi_lock); + return -EBUSY; + } + pm_runtime_get_sync(&priv->pci_dev->dev); hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) @@ -820,6 +923,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, out: pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); return ret; } @@ -833,7 +937,28 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ((priv->features & FEATURE_I2C_BLOCK_READ) ? - I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | + ((priv->features & FEATURE_HOST_NOTIFY) ? + I2C_FUNC_SMBUS_HOST_NOTIFY : 0); +} + +static int i801_enable_host_notify(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return -ENOTSUPP; + + if (!priv->host_notify) + priv->host_notify = i2c_setup_smbus_host_notify(adapter); + if (!priv->host_notify) + return -ENOMEM; + + outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv)); + /* clear Host Notify bit to allow a new notification */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + + return 0; } static const struct i2c_algorithm smbus_algorithm = { @@ -883,6 +1008,7 @@ static const struct pci_device_id i801_ids[] = { { 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) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, { 0, } }; @@ -1008,8 +1134,7 @@ static void __init input_apanel_init(void) {} static void i801_probe_optional_slaves(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, @@ -1257,6 +1382,83 @@ static void i801_add_tco(struct i801_priv *priv) priv->tco_pdev = pdev; } +#ifdef CONFIG_ACPI +static acpi_status +i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, + u64 *value, void *handler_context, void *region_context) +{ + struct i801_priv *priv = handler_context; + struct pci_dev *pdev = priv->pci_dev; + acpi_status status; + + /* + * Once BIOS AML code touches the OpRegion we warn and inhibit any + * further access from the driver itself. This device is now owned + * by the system firmware. + */ + mutex_lock(&priv->acpi_lock); + + if (!priv->acpi_reserved) { + priv->acpi_reserved = true; + + dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); + dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); + + /* + * BIOS is accessing the host controller so prevent it from + * suspending automatically from now on. + */ + pm_runtime_get_sync(&pdev->dev); + } + + if ((function & ACPI_IO_MASK) == ACPI_READ) + status = acpi_os_read_port(address, (u32 *)value, bits); + else + status = acpi_os_write_port(address, (u32)*value, bits); + + mutex_unlock(&priv->acpi_lock); + + return status; +} + +static int i801_acpi_probe(struct i801_priv *priv) +{ + struct acpi_device *adev; + acpi_status status; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (adev) { + status = acpi_install_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, + NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; + } + + return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); +} + +static void i801_acpi_remove(struct i801_priv *priv) +{ + struct acpi_device *adev; + + adev = ACPI_COMPANION(&priv->pci_dev->dev); + if (!adev) + return; + + acpi_remove_address_space_handler(adev->handle, + ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); + + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) + pm_runtime_put(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); +} +#else +static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } +static inline void i801_acpi_remove(struct i801_priv *priv) { } +#endif + static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { unsigned char temp; @@ -1274,6 +1476,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->adapter.dev.parent = &dev->dev; ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); priv->adapter.retries = 3; + mutex_init(&priv->acpi_lock); priv->pci_dev = dev; switch (dev->device) { @@ -1282,11 +1485,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: case PCI_DEVICE_ID_INTEL_DNV_SMBUS: + case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_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; + /* If we have ACPI based watchdog use that instead */ + if (!acpi_has_watchdog()) + priv->features |= FEATURE_TCO; + priv->features |= FEATURE_HOST_NOTIFY; break; case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: @@ -1306,6 +1513,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features |= FEATURE_BLOCK_BUFFER; /* fall through */ case PCI_DEVICE_ID_INTEL_82801CA_3: + priv->features |= FEATURE_HOST_NOTIFY; + /* fall through */ case PCI_DEVICE_ID_INTEL_82801BA_2: case PCI_DEVICE_ID_INTEL_82801AB_3: case PCI_DEVICE_ID_INTEL_82801AA_3: @@ -1336,10 +1545,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - err = acpi_check_resource_conflict(&dev->resource[SMBBAR]); - if (err) { + if (i801_acpi_probe(priv)) return -ENODEV; - } err = pcim_iomap_regions(dev, 1 << SMBBAR, dev_driver_string(&dev->dev)); @@ -1348,6 +1555,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) "Failed to request SMBus region 0x%lx-0x%Lx\n", priv->smba, (unsigned long long)pci_resource_end(dev, SMBBAR)); + i801_acpi_remove(priv); return err; } @@ -1411,10 +1619,19 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) "SMBus I801 adapter at %04lx", priv->smba); err = i2c_add_adapter(&priv->adapter); if (err) { - dev_err(&dev->dev, "Failed to add SMBus adapter\n"); + i801_acpi_remove(priv); return err; } + /* + * Enable Host Notify for chips that supports it. + * It is done after i2c_add_adapter() so that we are sure the work queue + * is not used if i2c_add_adapter() fails. + */ + err = i801_enable_host_notify(&priv->adapter); + if (err && err != -ENOTSUPP) + dev_warn(&dev->dev, "Unable to enable SMBus Host Notify\n"); + i801_probe_optional_slaves(priv); /* We ignore errors - multiplexing is optional */ i801_add_mux(priv); @@ -1438,6 +1655,7 @@ static void i801_remove(struct pci_dev *dev) i801_del_mux(priv); i2c_del_adapter(&priv->adapter); + i801_acpi_remove(priv); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); platform_device_unregister(priv->tco_pdev); @@ -1460,6 +1678,14 @@ static int i801_suspend(struct device *dev) static int i801_resume(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); + struct i801_priv *priv = pci_get_drvdata(pci_dev); + int err; + + err = i801_enable_host_notify(&priv->adapter); + if (err && err != -ENOTSUPP) + dev_warn(dev, "Unable to enable SMBus Host Notify\n"); + return 0; } #endif diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index cdaa7be2cd1b..412b91d255ad 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -751,10 +751,8 @@ static int iic_probe(struct platform_device *ofdev) adap->timeout = HZ; ret = i2c_add_adapter(adap); - if (ret < 0) { - dev_err(&ofdev->dev, "failed to register i2c adapter\n"); + if (ret < 0) goto error_cleanup; - } dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index ea20425b6972..db8e8b40569d 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1394,10 +1394,8 @@ static int img_i2c_probe(struct platform_device *pdev) goto disable_clk; ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (ret < 0) goto disable_clk; - } return 0; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 1844bc9f7cd5..592a8f26a708 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -984,11 +984,24 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); } -static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, +/* + * We switch SCL and SDA to their GPIO function and do some bitbanging + * for bus recovery. These alternative pinmux settings can be + * described in the device tree by a separate pinctrl state "gpio". If + * this is missing this is not a big problem, the only implication is + * that we can't do bus recovery. + */ +static int 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 = devm_pinctrl_get(&pdev->dev); + if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) { + dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n"); + return PTR_ERR(i2c_imx->pinctrl); + } + 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, @@ -1001,7 +1014,7 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); - return; + return 0; } dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", @@ -1011,6 +1024,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; rinfo->recover_bus = i2c_generic_gpio_recovery; i2c_imx->adapter.bus_recovery_info = rinfo; + + return 0; } static u32 i2c_imx_func(struct i2c_adapter *adapter) @@ -1081,12 +1096,6 @@ static int i2c_imx_probe(struct platform_device *pdev) 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); @@ -1125,14 +1134,16 @@ 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); + /* Init optional bus recovery function */ + ret = i2c_imx_init_recovery_info(i2c_imx, pdev); + /* Give it another chance if pinctrl used is not ready yet */ + if (ret == -EPROBE_DEFER) + goto rpm_disable; /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); - if (ret < 0) { - dev_err(&pdev->dev, "registration failed\n"); + if (ret < 0) goto rpm_disable; - } pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index c2f25f19d76f..0cf1379f4e80 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -288,10 +288,8 @@ static int smbus_sch_probe(struct platform_device *dev) "SMBus SCH adapter at %04x", sch_smba); retval = i2c_add_adapter(&sch_adapter); - if (retval) { - dev_err(&dev->dev, "Couldn't register adapter!\n"); + if (retval) sch_smba = 0; - } return retval; } diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 1c8707710098..f573448d2132 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -922,10 +922,8 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; err = i2c_add_adapter(&priv->adapter); - if (err) { - dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n"); + if (err) return -ENODEV; - } return 0; } diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index ba14a863b451..b8ea62105f42 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -791,10 +791,6 @@ static int jz4780_i2c_probe(struct platform_device *pdev) jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); - i2c->cmd = 0; - memset(i2c->cmd_buf, 0, BUFSIZE); - memset(i2c->data_buf, 0, BUFSIZE); - i2c->irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, dev_name(&pdev->dev), i2c); @@ -802,10 +798,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev) goto err; ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to add bus\n"); + if (ret < 0) goto err; - } return 0; diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 586a15205e61..9b1fef455a89 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -432,10 +432,8 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) 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"); + if (ret < 0) goto fail_clk; - } dev_info(&pdev->dev, "LPC2K I2C adapter\n"); diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 71d3929adf54..2aa61bbbd307 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -211,7 +211,7 @@ static void meson_i2c_stop(struct meson_i2c *i2c) meson_i2c_add_token(i2c, TOKEN_STOP); } else { i2c->state = STATE_IDLE; - complete_all(&i2c->done); + complete(&i2c->done); } } @@ -238,7 +238,7 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) dev_dbg(i2c->dev, "error bit set\n"); i2c->error = -ENXIO; i2c->state = STATE_IDLE; - complete_all(&i2c->done); + complete(&i2c->done); goto out; } @@ -269,7 +269,7 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) break; case STATE_STOP: i2c->state = STATE_IDLE; - complete_all(&i2c->done); + complete(&i2c->done); break; case STATE_IDLE: break; @@ -453,7 +453,6 @@ static int meson_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { - dev_err(&pdev->dev, "can't register adapter\n"); clk_unprepare(i2c->clk); return ret; } @@ -473,6 +472,7 @@ static int meson_i2c_remove(struct platform_device *pdev) static const struct of_device_id meson_i2c_match[] = { { .compatible = "amlogic,meson6-i2c" }, + { .compatible = "amlogic,meson-gxbb-i2c" }, { }, }; MODULE_DEVICE_TABLE(of, meson_i2c_match); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 48ecffecc0ed..565a49a0c564 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -737,10 +737,8 @@ static int fsl_i2c_probe(struct platform_device *op) i2c->adap.dev.of_node = of_node_get(op->dev.of_node); result = i2c_add_adapter(&i2c->adap); - if (result < 0) { - dev_err(i2c->dev, "failed to add adapter\n"); + if (result < 0) goto fail_add; - } return result; diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index d9373e60be8a..4a7d9bc2142b 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -786,10 +786,8 @@ static int mtk_i2c_probe(struct platform_device *pdev) 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"); + if (ret) return ret; - } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 033846cdf266..5738556b6aac 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -868,7 +868,6 @@ static int mxs_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, i2c); err = i2c_add_numbered_adapter(adap); if (err) { - dev_err(dev, "Failed to add adapter (%d)\n", err); writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); return err; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 42fcc9458432..374b35e7e450 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -366,7 +366,6 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, error = i2c_add_adapter(&smbus->adapter); if (error) { - dev_err(&smbus->adapter.dev, "Failed to register adapter.\n"); release_region(smbus->base, smbus->size); return error; } diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index bcd17e8cbcb4..da6609d62848 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1046,10 +1046,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) adap->name, dev->virtbase); ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&adev->dev, "failed to add adapter\n"); + if (ret) goto err_no_adap; - } pm_runtime_put(&adev->dev); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index dfa7a4b4a91d..34f1889a4073 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -379,6 +379,7 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, if (!clock_frequency_present) { dev_err(&pdev->dev, "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); return -ENODEV; } i2c->ip_clock_khz = clock_frequency / 1000; @@ -467,20 +468,21 @@ static int ocores_i2c_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", i2c->reg_io_width); - return -EINVAL; + ret = -EINVAL; + goto err_clk; } } ret = ocores_init(&pdev->dev, i2c); if (ret) - return ret; + goto err_clk; init_waitqueue_head(&i2c->wait); ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, pdev->name, i2c); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - return ret; + goto err_clk; } /* hook up driver to tree */ @@ -492,10 +494,8 @@ static int ocores_i2c_probe(struct platform_device *pdev) /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); - return ret; - } + if (ret) + goto err_clk; /* add in known devices to the bus */ if (pdata) { @@ -504,6 +504,10 @@ static int ocores_i2c_probe(struct platform_device *pdev) } return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); + return ret; } static int ocores_i2c_remove(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon-core.c index aa5f01efd826..419b54bfc7c7 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -4,280 +4,127 @@ * * Portions Copyright (C) 2010 - 2016 Cavium, Inc. * - * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. + * This file contains the shared part of the driver for the i2c adapter in + * Cavium Networks' OCTEON processors and ThunderX SOCs. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -#include <linux/atomic.h> -#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/io.h> -#include <linux/of.h> - -#include <asm/octeon/octeon.h> - -#define DRV_NAME "i2c-octeon" - -/* Register offsets */ -#define SW_TWSI 0x00 -#define TWSI_INT 0x10 -#define SW_TWSI_EXT 0x18 - -/* Controller command patterns */ -#define SW_TWSI_V BIT_ULL(63) /* Valid bit */ -#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */ -#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */ -#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */ -#define SW_TWSI_SIZE_SHIFT 52 -#define SW_TWSI_ADDR_SHIFT 40 -#define SW_TWSI_IA_SHIFT 32 /* Internal address */ - -/* Controller opcode word (bits 60:57) */ -#define SW_TWSI_OP_SHIFT 57 -#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */ - -/* Controller extended opcode word (bits 34:32) */ -#define SW_TWSI_EOP_SHIFT 32 -#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT) - -/* Controller command and status bits */ -#define TWSI_CTL_CE 0x80 /* High level controller enable */ -#define TWSI_CTL_ENAB 0x40 /* Bus enable */ -#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */ -#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */ -#define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */ -#define TWSI_CTL_AAK 0x04 /* Assert ACK */ - -/* Status values */ -#define STAT_ERROR 0x00 -#define STAT_START 0x08 -#define STAT_REP_START 0x10 -#define STAT_TXADDR_ACK 0x18 -#define STAT_TXADDR_NAK 0x20 -#define STAT_TXDATA_ACK 0x28 -#define STAT_TXDATA_NAK 0x30 -#define STAT_LOST_ARB_38 0x38 -#define STAT_RXADDR_ACK 0x40 -#define STAT_RXADDR_NAK 0x48 -#define STAT_RXDATA_ACK 0x50 -#define STAT_RXDATA_NAK 0x58 -#define STAT_SLAVE_60 0x60 -#define STAT_LOST_ARB_68 0x68 -#define STAT_SLAVE_70 0x70 -#define STAT_LOST_ARB_78 0x78 -#define STAT_SLAVE_80 0x80 -#define STAT_SLAVE_88 0x88 -#define STAT_GENDATA_ACK 0x90 -#define STAT_GENDATA_NAK 0x98 -#define STAT_SLAVE_A0 0xA0 -#define STAT_SLAVE_A8 0xA8 -#define STAT_LOST_ARB_B0 0xB0 -#define STAT_SLAVE_LOST 0xB8 -#define STAT_SLAVE_NAK 0xC0 -#define STAT_SLAVE_ACK 0xC8 -#define STAT_AD2W_ACK 0xD0 -#define STAT_AD2W_NAK 0xD8 -#define STAT_IDLE 0xF8 - -/* TWSI_INT values */ -#define TWSI_INT_ST_INT BIT_ULL(0) -#define TWSI_INT_TS_INT BIT_ULL(1) -#define TWSI_INT_CORE_INT BIT_ULL(2) -#define TWSI_INT_ST_EN BIT_ULL(4) -#define TWSI_INT_TS_EN BIT_ULL(5) -#define TWSI_INT_CORE_EN BIT_ULL(6) -#define TWSI_INT_SDA_OVR BIT_ULL(8) -#define TWSI_INT_SCL_OVR BIT_ULL(9) -#define TWSI_INT_SDA BIT_ULL(10) -#define TWSI_INT_SCL BIT_ULL(11) - -#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */ - -struct octeon_i2c { - wait_queue_head_t queue; - struct i2c_adapter adap; - int irq; - int hlc_irq; /* For cn7890 only */ - u32 twsi_freq; - int sys_freq; - void __iomem *twsi_base; - struct device *dev; - bool hlc_enabled; - bool broken_irq_mode; - bool broken_irq_check; - void (*int_enable)(struct octeon_i2c *); - void (*int_disable)(struct octeon_i2c *); - void (*hlc_int_enable)(struct octeon_i2c *); - void (*hlc_int_disable)(struct octeon_i2c *); - atomic_t int_enable_cnt; - atomic_t hlc_int_enable_cnt; -}; - -static void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) -{ - __raw_writeq(val, addr); - __raw_readq(addr); /* wait for write to land */ -} - -/** - * octeon_i2c_reg_write - write an I2C core register - * @i2c: The struct octeon_i2c - * @eop_reg: Register selector - * @data: Value to be written - * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. - */ -static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) -{ - u64 tmp; - __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI); - do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI); - } while ((tmp & SW_TWSI_V) != 0); -} - -#define octeon_i2c_ctl_write(i2c, val) \ - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val) -#define octeon_i2c_data_write(i2c, val) \ - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val) +#include "i2c-octeon-core.h" -/** - * octeon_i2c_reg_read - read lower bits of an I2C core register - * @i2c: The struct octeon_i2c - * @eop_reg: Register selector - * - * Returns the data. - * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. - */ -static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg) +/* interrupt service routine */ +irqreturn_t octeon_i2c_isr(int irq, void *dev_id) { - u64 tmp; + struct octeon_i2c *i2c = dev_id; - __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI); - do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI); - } while ((tmp & SW_TWSI_V) != 0); + i2c->int_disable(i2c); + wake_up(&i2c->queue); - return tmp & 0xFF; + return IRQ_HANDLED; } -#define octeon_i2c_ctl_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL) -#define octeon_i2c_data_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA) -#define octeon_i2c_stat_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT) - -/** - * octeon_i2c_read_int - read the TWSI_INT register - * @i2c: The struct octeon_i2c - * - * Returns the value of the register. - */ -static u64 octeon_i2c_read_int(struct octeon_i2c *i2c) +static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) { - return __raw_readq(i2c->twsi_base + TWSI_INT); + return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); } -/** - * octeon_i2c_write_int - write the TWSI_INT register - * @i2c: The struct octeon_i2c - * @data: Value to be written - */ -static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) +static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) { - octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT); -} + if (octeon_i2c_test_iflg(i2c)) + return true; -/** - * octeon_i2c_int_enable - enable the CORE interrupt - * @i2c: The struct octeon_i2c - * - * The interrupt will be asserted when there is non-STAT_IDLE state in - * the SW_TWSI_EOP_TWSI_STAT register. - */ -static void octeon_i2c_int_enable(struct octeon_i2c *i2c) -{ - octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN); -} + if (*first) { + *first = false; + return false; + } -/* disable the CORE interrupt */ -static void octeon_i2c_int_disable(struct octeon_i2c *i2c) -{ - /* clear TS/ST/IFLG events */ - octeon_i2c_write_int(i2c, 0); + /* + * IRQ has signaled an event but IFLG hasn't changed. + * Sleep and retry once. + */ + usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); + return octeon_i2c_test_iflg(i2c); } /** - * octeon_i2c_int_enable78 - enable the CORE interrupt + * octeon_i2c_wait - wait for the IFLG to be set * @i2c: The struct octeon_i2c * - * The interrupt will be asserted when there is non-STAT_IDLE state in the - * SW_TWSI_EOP_TWSI_STAT register. + * Returns 0 on success, otherwise a negative errno. */ -static void octeon_i2c_int_enable78(struct octeon_i2c *i2c) -{ - atomic_inc_return(&i2c->int_enable_cnt); - enable_irq(i2c->irq); -} - -static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq) +static int octeon_i2c_wait(struct octeon_i2c *i2c) { - int count; + long time_left; + bool first = true; /* - * The interrupt can be disabled in two places, but we only - * want to make the disable_irq_nosync() call once, so keep - * track with the atomic variable. + * Some chip revisions don't assert the irq in the interrupt + * controller. So we must poll for the IFLG change. */ - count = atomic_dec_if_positive(cnt); - if (count >= 0) - disable_irq_nosync(irq); + if (i2c->broken_irq_mode) { + u64 end = get_jiffies_64() + i2c->adap.timeout; + + while (!octeon_i2c_test_iflg(i2c) && + time_before64(get_jiffies_64(), end)) + usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); + + return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT; + } + + i2c->int_enable(i2c); + time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), + i2c->adap.timeout); + i2c->int_disable(i2c); + + if (i2c->broken_irq_check && !time_left && + octeon_i2c_test_iflg(i2c)) { + dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); + i2c->broken_irq_mode = true; + return 0; + } + + if (!time_left) + return -ETIMEDOUT; + + return 0; } -/* disable the CORE interrupt */ -static void octeon_i2c_int_disable78(struct octeon_i2c *i2c) +static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) { - __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq); + return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0; } -/** - * octeon_i2c_hlc_int_enable78 - enable the ST interrupt - * @i2c: The struct octeon_i2c - * - * The interrupt will be asserted when there is non-STAT_IDLE state in - * the SW_TWSI_EOP_TWSI_STAT register. - */ -static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c) +static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first) { - atomic_inc_return(&i2c->hlc_int_enable_cnt); - enable_irq(i2c->hlc_irq); + /* check if valid bit is cleared */ + if (octeon_i2c_hlc_test_valid(i2c)) + return true; + + if (*first) { + *first = false; + return false; + } + + /* + * IRQ has signaled an event but valid bit isn't cleared. + * Sleep and retry once. + */ + usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); + return octeon_i2c_hlc_test_valid(i2c); } -/* disable the ST interrupt */ -static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c) +static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) { - __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq); + /* clear ST/TS events, listen for neither */ + octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT); } /* @@ -321,83 +168,41 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c) octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); } -/* interrupt service routine */ -static irqreturn_t octeon_i2c_isr(int irq, void *dev_id) -{ - struct octeon_i2c *i2c = dev_id; - - i2c->int_disable(i2c); - wake_up(&i2c->queue); - - return IRQ_HANDLED; -} - -/* HLC interrupt service routine */ -static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id) -{ - struct octeon_i2c *i2c = dev_id; - - i2c->hlc_int_disable(i2c); - wake_up(&i2c->queue); - - return IRQ_HANDLED; -} - -static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) -{ - return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); -} - -static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) -{ - if (octeon_i2c_test_iflg(i2c)) - return true; - - if (*first) { - *first = false; - return false; - } - - /* - * IRQ has signaled an event but IFLG hasn't changed. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_test_iflg(i2c); -} - /** - * octeon_i2c_wait - wait for the IFLG to be set + * octeon_i2c_hlc_wait - wait for an HLC operation to complete * @i2c: The struct octeon_i2c * - * Returns 0 on success, otherwise a negative errno. + * Returns 0 on success, otherwise -ETIMEDOUT. */ -static int octeon_i2c_wait(struct octeon_i2c *i2c) +static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) { - long time_left; - bool first = 1; + bool first = true; + int time_left; /* - * Some chip revisions don't assert the irq in the interrupt - * controller. So we must poll for the IFLG change. + * Some cn38xx boards don't assert the irq in the interrupt + * controller. So we must poll for the valid bit change. */ if (i2c->broken_irq_mode) { u64 end = get_jiffies_64() + i2c->adap.timeout; - while (!octeon_i2c_test_iflg(i2c) && + while (!octeon_i2c_hlc_test_valid(i2c) && time_before64(get_jiffies_64(), end)) usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT; + return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT; } - i2c->int_enable(i2c); - time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), + i2c->hlc_int_enable(i2c); + time_left = wait_event_timeout(i2c->queue, + octeon_i2c_hlc_test_ready(i2c, &first), i2c->adap.timeout); - i2c->int_disable(i2c); + i2c->hlc_int_disable(i2c); + if (!time_left) + octeon_i2c_hlc_int_clear(i2c); if (i2c->broken_irq_check && !time_left && - octeon_i2c_test_iflg(i2c)) { + octeon_i2c_hlc_test_valid(i2c)) { dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); i2c->broken_irq_mode = true; return 0; @@ -405,13 +210,21 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) if (!time_left) return -ETIMEDOUT; - return 0; } static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) { - u8 stat = octeon_i2c_stat_read(i2c); + u8 stat; + + /* + * This is ugly... in HLC mode the status is not in the status register + * but in the lower 8 bits of SW_TWSI. + */ + if (i2c->hlc_enabled) + stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + else + stat = octeon_i2c_stat_read(i2c); switch (stat) { /* Everything is fine */ @@ -470,83 +283,157 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) } } -static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) +static int octeon_i2c_recovery(struct octeon_i2c *i2c) { - return (__raw_readq(i2c->twsi_base + SW_TWSI) & SW_TWSI_V) == 0; + int ret; + + ret = i2c_recover_bus(&i2c->adap); + if (ret) + /* recover failed, try hardware re-init */ + ret = octeon_i2c_init_lowlevel(i2c); + return ret; } -static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first) +/** + * octeon_i2c_start - send START to the bus + * @i2c: The struct octeon_i2c + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_start(struct octeon_i2c *i2c) { - /* check if valid bit is cleared */ - if (octeon_i2c_hlc_test_valid(i2c)) - return true; + int ret; + u8 stat; - if (*first) { - *first = false; - return false; - } + octeon_i2c_hlc_disable(i2c); - /* - * IRQ has signaled an event but valid bit isn't cleared. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_hlc_test_valid(i2c); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA); + ret = octeon_i2c_wait(i2c); + if (ret) + goto error; + + stat = octeon_i2c_stat_read(i2c); + if (stat == STAT_START || stat == STAT_REP_START) + /* START successful, bail out */ + return 0; + +error: + /* START failed, try to recover */ + ret = octeon_i2c_recovery(i2c); + return (ret) ? ret : -EAGAIN; } -static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) +/* send STOP to the bus */ +static void octeon_i2c_stop(struct octeon_i2c *i2c) { - octeon_i2c_write_int(i2c, TWSI_INT_ST_EN); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP); } -static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) +/** + * octeon_i2c_read - receive data from the bus via low-level controller + * @i2c: The struct octeon_i2c + * @target: Target address + * @data: Pointer to the location to store the data + * @rlength: Length of the data + * @recv_len: flag for length byte + * + * The address is sent over the bus, then the data is read. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_read(struct octeon_i2c *i2c, int target, + u8 *data, u16 *rlength, bool recv_len) { - /* clear ST/TS events, listen for neither */ - octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT); + int i, result, length = *rlength; + bool final_read = false; + + octeon_i2c_data_write(i2c, (target << 1) | 1); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + /* address OK ? */ + result = octeon_i2c_check_status(i2c, false); + if (result) + return result; + + for (i = 0; i < length; i++) { + /* + * For the last byte to receive TWSI_CTL_AAK must not be set. + * + * A special case is I2C_M_RECV_LEN where we don't know the + * additional length yet. If recv_len is set we assume we're + * not reading the final byte and therefore need to set + * TWSI_CTL_AAK. + */ + if ((i + 1 == length) && !(recv_len && i == 0)) + final_read = true; + + /* clear iflg to allow next event */ + if (final_read) + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); + else + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + data[i] = octeon_i2c_data_read(i2c, &result); + if (result) + return result; + if (recv_len && i == 0) { + if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) + return -EPROTO; + length += data[i]; + } + + result = octeon_i2c_check_status(i2c, final_read); + if (result) + return result; + } + *rlength = length; + return 0; } /** - * octeon_i2c_hlc_wait - wait for an HLC operation to complete + * octeon_i2c_write - send data to the bus via low-level controller * @i2c: The struct octeon_i2c + * @target: Target address + * @data: Pointer to the data to be sent + * @length: Length of the data * - * Returns 0 on success, otherwise -ETIMEDOUT. + * The address is sent over the bus, then the data. + * + * Returns 0 on success, otherwise a negative errno. */ -static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) +static int octeon_i2c_write(struct octeon_i2c *i2c, int target, + const u8 *data, int length) { - bool first = 1; - int time_left; + int i, result; - /* - * Some cn38xx boards don't assert the irq in the interrupt - * controller. So we must poll for the valid bit change. - */ - if (i2c->broken_irq_mode) { - u64 end = get_jiffies_64() + i2c->adap.timeout; + octeon_i2c_data_write(i2c, target << 1); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - while (!octeon_i2c_hlc_test_valid(i2c) && - time_before64(get_jiffies_64(), end)) - usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); + result = octeon_i2c_wait(i2c); + if (result) + return result; - return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT; - } + for (i = 0; i < length; i++) { + result = octeon_i2c_check_status(i2c, false); + if (result) + return result; - i2c->hlc_int_enable(i2c); - time_left = wait_event_timeout(i2c->queue, - octeon_i2c_hlc_test_ready(i2c, &first), - i2c->adap.timeout); - i2c->hlc_int_disable(i2c); - if (!time_left) - octeon_i2c_hlc_int_clear(i2c); + octeon_i2c_data_write(i2c, data[i]); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - if (i2c->broken_irq_check && !time_left && - octeon_i2c_hlc_test_valid(i2c)) { - dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); - i2c->broken_irq_mode = true; - return 0; + result = octeon_i2c_wait(i2c); + if (result) + return result; } - if (!time_left) - return -ETIMEDOUT; return 0; } @@ -570,20 +457,20 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) else cmd |= SW_TWSI_OP_7; - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; + return octeon_i2c_check_status(i2c, false); for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[0].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -620,19 +507,17 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) ext |= (u64)msgs[0].buf[j] << (8 * i); - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); } - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - ret = octeon_i2c_check_status(i2c, false); + return octeon_i2c_check_status(i2c, false); err: return ret; @@ -663,27 +548,27 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs cmd |= SW_TWSI_EIA; ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT; - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); } else { cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; } octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; + return octeon_i2c_check_status(i2c, false); for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[1].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -730,27 +615,85 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg set_ext = true; } if (set_ext) - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - ret = octeon_i2c_check_status(i2c, false); + return octeon_i2c_check_status(i2c, false); err: return ret; } +/** + * octeon_i2c_xfer - The driver's master_xfer function + * @adap: Pointer to the i2c_adapter structure + * @msgs: Pointer to the messages to be processed + * @num: Length of the MSGS array + * + * Returns the number of messages processed, or a negative errno on failure. + */ +int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct octeon_i2c *i2c = i2c_get_adapdata(adap); + int i, ret = 0; + + if (num == 1) { + if (msgs[0].len > 0 && msgs[0].len <= 8) { + if (msgs[0].flags & I2C_M_RD) + ret = octeon_i2c_hlc_read(i2c, msgs); + else + ret = octeon_i2c_hlc_write(i2c, msgs); + goto out; + } + } else if (num == 2) { + if ((msgs[0].flags & I2C_M_RD) == 0 && + (msgs[1].flags & I2C_M_RECV_LEN) == 0 && + msgs[0].len > 0 && msgs[0].len <= 2 && + msgs[1].len > 0 && msgs[1].len <= 8 && + msgs[0].addr == msgs[1].addr) { + if (msgs[1].flags & I2C_M_RD) + ret = octeon_i2c_hlc_comp_read(i2c, msgs); + else + ret = octeon_i2c_hlc_comp_write(i2c, msgs); + goto out; + } + } + + for (i = 0; ret == 0 && i < num; i++) { + struct i2c_msg *pmsg = &msgs[i]; + + /* zero-length messages are not supported */ + if (!pmsg->len) { + ret = -EOPNOTSUPP; + break; + } + + ret = octeon_i2c_start(i2c); + if (ret) + return ret; + + if (pmsg->flags & I2C_M_RD) + ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf, + &pmsg->len, pmsg->flags & I2C_M_RECV_LEN); + else + ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf, + pmsg->len); + } + octeon_i2c_stop(i2c); +out: + return (ret != 0) ? ret : num; +} + /* calculate and set clock divisors */ -static void octeon_i2c_set_clock(struct octeon_i2c *i2c) +void octeon_i2c_set_clock(struct octeon_i2c *i2c) { int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; @@ -791,7 +734,7 @@ static void octeon_i2c_set_clock(struct octeon_i2c *i2c) octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); } -static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) +int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) { u8 status = 0; int tries; @@ -818,216 +761,6 @@ static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) return 0; } -static int octeon_i2c_recovery(struct octeon_i2c *i2c) -{ - int ret; - - ret = i2c_recover_bus(&i2c->adap); - if (ret) - /* recover failed, try hardware re-init */ - ret = octeon_i2c_init_lowlevel(i2c); - return ret; -} - -/** - * octeon_i2c_start - send START to the bus - * @i2c: The struct octeon_i2c - * - * Returns 0 on success, otherwise a negative errno. - */ -static int octeon_i2c_start(struct octeon_i2c *i2c) -{ - int ret; - u8 stat; - - octeon_i2c_hlc_disable(i2c); - - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA); - ret = octeon_i2c_wait(i2c); - if (ret) - goto error; - - stat = octeon_i2c_stat_read(i2c); - if (stat == STAT_START || stat == STAT_REP_START) - /* START successful, bail out */ - return 0; - -error: - /* START failed, try to recover */ - ret = octeon_i2c_recovery(i2c); - return (ret) ? ret : -EAGAIN; -} - -/* send STOP to the bus */ -static void octeon_i2c_stop(struct octeon_i2c *i2c) -{ - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP); -} - -/** - * octeon_i2c_write - send data to the bus via low-level controller - * @i2c: The struct octeon_i2c - * @target: Target address - * @data: Pointer to the data to be sent - * @length: Length of the data - * - * The address is sent over the bus, then the data. - * - * Returns 0 on success, otherwise a negative errno. - */ -static int octeon_i2c_write(struct octeon_i2c *i2c, int target, - const u8 *data, int length) -{ - int i, result; - - octeon_i2c_data_write(i2c, target << 1); - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - - for (i = 0; i < length; i++) { - result = octeon_i2c_check_status(i2c, false); - if (result) - return result; - - octeon_i2c_data_write(i2c, data[i]); - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - } - - return 0; -} - -/** - * octeon_i2c_read - receive data from the bus via low-level controller - * @i2c: The struct octeon_i2c - * @target: Target address - * @data: Pointer to the location to store the data - * @rlength: Length of the data - * @recv_len: flag for length byte - * - * The address is sent over the bus, then the data is read. - * - * Returns 0 on success, otherwise a negative errno. - */ -static int octeon_i2c_read(struct octeon_i2c *i2c, int target, - u8 *data, u16 *rlength, bool recv_len) -{ - int i, result, length = *rlength; - bool final_read = false; - - octeon_i2c_data_write(i2c, (target << 1) | 1); - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - - /* address OK ? */ - result = octeon_i2c_check_status(i2c, false); - if (result) - return result; - - for (i = 0; i < length; i++) { - /* for the last byte TWSI_CTL_AAK must not be set */ - if (i + 1 == length) - final_read = true; - - /* clear iflg to allow next event */ - if (final_read) - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - else - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_AAK); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - - data[i] = octeon_i2c_data_read(i2c); - if (recv_len && i == 0) { - if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) { - dev_err(i2c->dev, - "%s: read len > I2C_SMBUS_BLOCK_MAX %d\n", - __func__, data[i]); - return -EPROTO; - } - length += data[i]; - } - - result = octeon_i2c_check_status(i2c, final_read); - if (result) - return result; - } - *rlength = length; - return 0; -} - -/** - * octeon_i2c_xfer - The driver's master_xfer function - * @adap: Pointer to the i2c_adapter structure - * @msgs: Pointer to the messages to be processed - * @num: Length of the MSGS array - * - * Returns the number of messages processed, or a negative errno on failure. - */ -static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) -{ - struct octeon_i2c *i2c = i2c_get_adapdata(adap); - int i, ret = 0; - - if (num == 1) { - if (msgs[0].len > 0 && msgs[0].len <= 8) { - if (msgs[0].flags & I2C_M_RD) - ret = octeon_i2c_hlc_read(i2c, msgs); - else - ret = octeon_i2c_hlc_write(i2c, msgs); - goto out; - } - } else if (num == 2) { - if ((msgs[0].flags & I2C_M_RD) == 0 && - (msgs[1].flags & I2C_M_RECV_LEN) == 0 && - msgs[0].len > 0 && msgs[0].len <= 2 && - msgs[1].len > 0 && msgs[1].len <= 8 && - msgs[0].addr == msgs[1].addr) { - if (msgs[1].flags & I2C_M_RD) - ret = octeon_i2c_hlc_comp_read(i2c, msgs); - else - ret = octeon_i2c_hlc_comp_write(i2c, msgs); - goto out; - } - } - - for (i = 0; ret == 0 && i < num; i++) { - struct i2c_msg *pmsg = &msgs[i]; - - /* zero-length messages are not supported */ - if (!pmsg->len) { - ret = -EOPNOTSUPP; - break; - } - - ret = octeon_i2c_start(i2c); - if (ret) - return ret; - - if (pmsg->flags & I2C_M_RD) - ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf, - &pmsg->len, pmsg->flags & I2C_M_RECV_LEN); - else - ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf, - pmsg->len); - } - octeon_i2c_stop(i2c); -out: - return (ret != 0) ? ret : num; -} - static int octeon_i2c_get_scl(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); @@ -1041,7 +774,7 @@ static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); - octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR); + octeon_i2c_write_int(i2c, val ? 0 : TWSI_INT_SCL_OVR); } static int octeon_i2c_get_sda(struct i2c_adapter *adap) @@ -1057,13 +790,14 @@ static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); + octeon_i2c_hlc_disable(i2c); + /* - * The stop resets the state machine, does not _transmit_ STOP unless - * engine was active. + * Bring control register to a good state regardless + * of HLC state. */ - octeon_i2c_stop(i2c); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - octeon_i2c_hlc_disable(i2c); octeon_i2c_write_int(i2c, 0); } @@ -1071,10 +805,19 @@ static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); + /* + * Generate STOP to finish the unfinished transaction. + * Can't generate STOP via the TWSI CTL register + * since it could bring the TWSI controller into an inoperable state. + */ + octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR); + udelay(5); + octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR); + udelay(5); octeon_i2c_write_int(i2c, 0); } -static struct i2c_bus_recovery_info octeon_i2c_recovery_info = { +struct i2c_bus_recovery_info octeon_i2c_recovery_info = { .recover_bus = i2c_generic_scl_recovery, .get_scl = octeon_i2c_get_scl, .set_scl = octeon_i2c_set_scl, @@ -1082,171 +825,3 @@ static struct i2c_bus_recovery_info octeon_i2c_recovery_info = { .prepare_recovery = octeon_i2c_prepare_recovery, .unprepare_recovery = octeon_i2c_unprepare_recovery, }; - -static u32 octeon_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | - I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; -} - -static const struct i2c_algorithm octeon_i2c_algo = { - .master_xfer = octeon_i2c_xfer, - .functionality = octeon_i2c_functionality, -}; - -static struct i2c_adapter octeon_i2c_ops = { - .owner = THIS_MODULE, - .name = "OCTEON adapter", - .algo = &octeon_i2c_algo, -}; - -static int octeon_i2c_probe(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - int irq, result = 0, hlc_irq = 0; - struct resource *res_mem; - struct octeon_i2c *i2c; - bool cn78xx_style; - - cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi"); - if (cn78xx_style) { - hlc_irq = platform_get_irq(pdev, 0); - if (hlc_irq < 0) - return hlc_irq; - - irq = platform_get_irq(pdev, 2); - if (irq < 0) - return irq; - } else { - /* All adaptors have an irq. */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - } - - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) { - result = -ENOMEM; - goto out; - } - i2c->dev = &pdev->dev; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem); - if (IS_ERR(i2c->twsi_base)) { - result = PTR_ERR(i2c->twsi_base); - goto out; - } - - /* - * "clock-rate" is a legacy binding, the official binding is - * "clock-frequency". Try the official one first and then - * fall back if it doesn't exist. - */ - if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) && - of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) { - dev_err(i2c->dev, - "no I2C 'clock-rate' or 'clock-frequency' property\n"); - result = -ENXIO; - goto out; - } - - i2c->sys_freq = octeon_get_io_clock_rate(); - - init_waitqueue_head(&i2c->queue); - - i2c->irq = irq; - - if (cn78xx_style) { - i2c->hlc_irq = hlc_irq; - - i2c->int_enable = octeon_i2c_int_enable78; - i2c->int_disable = octeon_i2c_int_disable78; - i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78; - i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78; - - irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN); - irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN); - - result = devm_request_irq(&pdev->dev, i2c->hlc_irq, - octeon_i2c_hlc_isr78, 0, - DRV_NAME, i2c); - if (result < 0) { - dev_err(i2c->dev, "failed to attach interrupt\n"); - goto out; - } - } else { - i2c->int_enable = octeon_i2c_int_enable; - i2c->int_disable = octeon_i2c_int_disable; - i2c->hlc_int_enable = octeon_i2c_hlc_int_enable; - i2c->hlc_int_disable = octeon_i2c_int_disable; - } - - result = devm_request_irq(&pdev->dev, i2c->irq, - octeon_i2c_isr, 0, DRV_NAME, i2c); - if (result < 0) { - dev_err(i2c->dev, "failed to attach interrupt\n"); - goto out; - } - - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) - i2c->broken_irq_check = true; - - result = octeon_i2c_init_lowlevel(i2c); - if (result) { - dev_err(i2c->dev, "init low level failed\n"); - goto out; - } - - octeon_i2c_set_clock(i2c); - - i2c->adap = octeon_i2c_ops; - i2c->adap.timeout = msecs_to_jiffies(2); - i2c->adap.retries = 5; - i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; - i2c->adap.dev.parent = &pdev->dev; - i2c->adap.dev.of_node = node; - i2c_set_adapdata(&i2c->adap, i2c); - platform_set_drvdata(pdev, i2c); - - result = i2c_add_adapter(&i2c->adap); - if (result < 0) { - dev_err(i2c->dev, "failed to add adapter\n"); - goto out; - } - dev_info(i2c->dev, "probed\n"); - return 0; - -out: - return result; -}; - -static int octeon_i2c_remove(struct platform_device *pdev) -{ - struct octeon_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); - return 0; -}; - -static const struct of_device_id octeon_i2c_match[] = { - { .compatible = "cavium,octeon-3860-twsi", }, - { .compatible = "cavium,octeon-7890-twsi", }, - {}, -}; -MODULE_DEVICE_TABLE(of, octeon_i2c_match); - -static struct platform_driver octeon_i2c_driver = { - .probe = octeon_i2c_probe, - .remove = octeon_i2c_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = octeon_i2c_match, - }, -}; - -module_platform_driver(octeon_i2c_driver); - -MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); -MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h new file mode 100644 index 000000000000..1db7c835a454 --- /dev/null +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -0,0 +1,216 @@ +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/pci.h> + +/* Controller command patterns */ +#define SW_TWSI_V BIT_ULL(63) /* Valid bit */ +#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */ +#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */ +#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */ +#define SW_TWSI_SIZE_SHIFT 52 +#define SW_TWSI_ADDR_SHIFT 40 +#define SW_TWSI_IA_SHIFT 32 /* Internal address */ + +/* Controller opcode word (bits 60:57) */ +#define SW_TWSI_OP_SHIFT 57 +#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */ + +/* Controller extended opcode word (bits 34:32) */ +#define SW_TWSI_EOP_SHIFT 32 +#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT) + +/* Controller command and status bits */ +#define TWSI_CTL_CE 0x80 /* High level controller enable */ +#define TWSI_CTL_ENAB 0x40 /* Bus enable */ +#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */ +#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */ +#define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */ +#define TWSI_CTL_AAK 0x04 /* Assert ACK */ + +/* Status values */ +#define STAT_ERROR 0x00 +#define STAT_START 0x08 +#define STAT_REP_START 0x10 +#define STAT_TXADDR_ACK 0x18 +#define STAT_TXADDR_NAK 0x20 +#define STAT_TXDATA_ACK 0x28 +#define STAT_TXDATA_NAK 0x30 +#define STAT_LOST_ARB_38 0x38 +#define STAT_RXADDR_ACK 0x40 +#define STAT_RXADDR_NAK 0x48 +#define STAT_RXDATA_ACK 0x50 +#define STAT_RXDATA_NAK 0x58 +#define STAT_SLAVE_60 0x60 +#define STAT_LOST_ARB_68 0x68 +#define STAT_SLAVE_70 0x70 +#define STAT_LOST_ARB_78 0x78 +#define STAT_SLAVE_80 0x80 +#define STAT_SLAVE_88 0x88 +#define STAT_GENDATA_ACK 0x90 +#define STAT_GENDATA_NAK 0x98 +#define STAT_SLAVE_A0 0xA0 +#define STAT_SLAVE_A8 0xA8 +#define STAT_LOST_ARB_B0 0xB0 +#define STAT_SLAVE_LOST 0xB8 +#define STAT_SLAVE_NAK 0xC0 +#define STAT_SLAVE_ACK 0xC8 +#define STAT_AD2W_ACK 0xD0 +#define STAT_AD2W_NAK 0xD8 +#define STAT_IDLE 0xF8 + +/* TWSI_INT values */ +#define TWSI_INT_ST_INT BIT_ULL(0) +#define TWSI_INT_TS_INT BIT_ULL(1) +#define TWSI_INT_CORE_INT BIT_ULL(2) +#define TWSI_INT_ST_EN BIT_ULL(4) +#define TWSI_INT_TS_EN BIT_ULL(5) +#define TWSI_INT_CORE_EN BIT_ULL(6) +#define TWSI_INT_SDA_OVR BIT_ULL(8) +#define TWSI_INT_SCL_OVR BIT_ULL(9) +#define TWSI_INT_SDA BIT_ULL(10) +#define TWSI_INT_SCL BIT_ULL(11) + +#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */ + +/* Register offsets */ +struct octeon_i2c_reg_offset { + unsigned int sw_twsi; + unsigned int twsi_int; + unsigned int sw_twsi_ext; +}; + +#define SW_TWSI(x) (x->roff.sw_twsi) +#define TWSI_INT(x) (x->roff.twsi_int) +#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext) + +struct octeon_i2c { + wait_queue_head_t queue; + struct i2c_adapter adap; + struct octeon_i2c_reg_offset roff; + struct clk *clk; + int irq; + int hlc_irq; /* For cn7890 only */ + u32 twsi_freq; + int sys_freq; + void __iomem *twsi_base; + struct device *dev; + bool hlc_enabled; + bool broken_irq_mode; + bool broken_irq_check; + void (*int_enable)(struct octeon_i2c *); + void (*int_disable)(struct octeon_i2c *); + void (*hlc_int_enable)(struct octeon_i2c *); + void (*hlc_int_disable)(struct octeon_i2c *); + atomic_t int_enable_cnt; + atomic_t hlc_int_enable_cnt; +#if IS_ENABLED(CONFIG_I2C_THUNDERX) + struct msix_entry i2c_msix; +#endif + struct i2c_smbus_alert_setup alert_data; + struct i2c_client *ara; +}; + +static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) +{ + __raw_writeq(val, addr); + __raw_readq(addr); /* wait for write to land */ +} + +/** + * octeon_i2c_reg_write - write an I2C core register + * @i2c: The struct octeon_i2c + * @eop_reg: Register selector + * @data: Value to be written + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) +{ + u64 tmp; + + __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c)); + + readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, tmp & SW_TWSI_V, + I2C_OCTEON_EVENT_WAIT, i2c->adap.timeout); +} + +#define octeon_i2c_ctl_write(i2c, val) \ + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val) +#define octeon_i2c_data_write(i2c, val) \ + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val) + +/** + * octeon_i2c_reg_read - read lower bits of an I2C core register + * @i2c: The struct octeon_i2c + * @eop_reg: Register selector + * + * Returns the data. + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, + int *error) +{ + u64 tmp; + int ret; + + __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c)); + + ret = readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, + tmp & SW_TWSI_V, I2C_OCTEON_EVENT_WAIT, + i2c->adap.timeout); + if (error) + *error = ret; + return tmp & 0xFF; +} + +#define octeon_i2c_ctl_read(i2c) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL) +#define octeon_i2c_data_read(i2c, error) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error) +#define octeon_i2c_stat_read(i2c) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL) + +/** + * octeon_i2c_read_int - read the TWSI_INT register + * @i2c: The struct octeon_i2c + * + * Returns the value of the register. + */ +static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c) +{ + return __raw_readq(i2c->twsi_base + TWSI_INT(i2c)); +} + +/** + * octeon_i2c_write_int - write the TWSI_INT register + * @i2c: The struct octeon_i2c + * @data: Value to be written + */ +static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) +{ + octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c)); +} + +/* Prototypes */ +irqreturn_t octeon_i2c_isr(int irq, void *dev_id); +int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); +int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c); +void octeon_i2c_set_clock(struct octeon_i2c *i2c); +extern struct i2c_bus_recovery_info octeon_i2c_recovery_info; diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c new file mode 100644 index 000000000000..917524ce6890 --- /dev/null +++ b/drivers/i2c/busses/i2c-octeon-platdrv.c @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2009-2010 + * Nokia Siemens Networks, michael.lawnick.ext@nsn.com + * + * Portions Copyright (C) 2010 - 2016 Cavium, Inc. + * + * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/atomic.h> +#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/of.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> + +#include <asm/octeon/octeon.h> +#include "i2c-octeon-core.h" + +#define DRV_NAME "i2c-octeon" + +/** + * octeon_i2c_int_enable - enable the CORE interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in + * the SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN); +} + +/* disable the CORE interrupt */ +static void octeon_i2c_int_disable(struct octeon_i2c *i2c) +{ + /* clear TS/ST/IFLG events */ + octeon_i2c_write_int(i2c, 0); +} + +/** + * octeon_i2c_int_enable78 - enable the CORE interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in the + * SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_int_enable78(struct octeon_i2c *i2c) +{ + atomic_inc_return(&i2c->int_enable_cnt); + enable_irq(i2c->irq); +} + +static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq) +{ + int count; + + /* + * The interrupt can be disabled in two places, but we only + * want to make the disable_irq_nosync() call once, so keep + * track with the atomic variable. + */ + count = atomic_dec_if_positive(cnt); + if (count >= 0) + disable_irq_nosync(irq); +} + +/* disable the CORE interrupt */ +static void octeon_i2c_int_disable78(struct octeon_i2c *i2c) +{ + __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq); +} + +/** + * octeon_i2c_hlc_int_enable78 - enable the ST interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in + * the SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c) +{ + atomic_inc_return(&i2c->hlc_int_enable_cnt); + enable_irq(i2c->hlc_irq); +} + +/* disable the ST interrupt */ +static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c) +{ + __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq); +} + +/* HLC interrupt service routine */ +static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id) +{ + struct octeon_i2c *i2c = dev_id; + + i2c->hlc_int_disable(i2c); + wake_up(&i2c->queue); + + return IRQ_HANDLED; +} + +static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, TWSI_INT_ST_EN); +} + +static u32 octeon_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; +} + +static const struct i2c_algorithm octeon_i2c_algo = { + .master_xfer = octeon_i2c_xfer, + .functionality = octeon_i2c_functionality, +}; + +static struct i2c_adapter octeon_i2c_ops = { + .owner = THIS_MODULE, + .name = "OCTEON adapter", + .algo = &octeon_i2c_algo, +}; + +static int octeon_i2c_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + int irq, result = 0, hlc_irq = 0; + struct resource *res_mem; + struct octeon_i2c *i2c; + bool cn78xx_style; + + cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi"); + if (cn78xx_style) { + hlc_irq = platform_get_irq(pdev, 0); + if (hlc_irq < 0) + return hlc_irq; + + irq = platform_get_irq(pdev, 2); + if (irq < 0) + return irq; + } else { + /* All adaptors have an irq. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + } + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + result = -ENOMEM; + goto out; + } + i2c->dev = &pdev->dev; + + i2c->roff.sw_twsi = 0x00; + i2c->roff.twsi_int = 0x10; + i2c->roff.sw_twsi_ext = 0x18; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(i2c->twsi_base)) { + result = PTR_ERR(i2c->twsi_base); + goto out; + } + + /* + * "clock-rate" is a legacy binding, the official binding is + * "clock-frequency". Try the official one first and then + * fall back if it doesn't exist. + */ + if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) && + of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) { + dev_err(i2c->dev, + "no I2C 'clock-rate' or 'clock-frequency' property\n"); + result = -ENXIO; + goto out; + } + + i2c->sys_freq = octeon_get_io_clock_rate(); + + init_waitqueue_head(&i2c->queue); + + i2c->irq = irq; + + if (cn78xx_style) { + i2c->hlc_irq = hlc_irq; + + i2c->int_enable = octeon_i2c_int_enable78; + i2c->int_disable = octeon_i2c_int_disable78; + i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78; + i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78; + + irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN); + irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN); + + result = devm_request_irq(&pdev->dev, i2c->hlc_irq, + octeon_i2c_hlc_isr78, 0, + DRV_NAME, i2c); + if (result < 0) { + dev_err(i2c->dev, "failed to attach interrupt\n"); + goto out; + } + } else { + i2c->int_enable = octeon_i2c_int_enable; + i2c->int_disable = octeon_i2c_int_disable; + i2c->hlc_int_enable = octeon_i2c_hlc_int_enable; + i2c->hlc_int_disable = octeon_i2c_int_disable; + } + + result = devm_request_irq(&pdev->dev, i2c->irq, + octeon_i2c_isr, 0, DRV_NAME, i2c); + if (result < 0) { + dev_err(i2c->dev, "failed to attach interrupt\n"); + goto out; + } + + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) + i2c->broken_irq_check = true; + + result = octeon_i2c_init_lowlevel(i2c); + if (result) { + dev_err(i2c->dev, "init low level failed\n"); + goto out; + } + + octeon_i2c_set_clock(i2c); + + i2c->adap = octeon_i2c_ops; + i2c->adap.timeout = msecs_to_jiffies(2); + i2c->adap.retries = 5; + i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = node; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + result = i2c_add_adapter(&i2c->adap); + if (result < 0) + goto out; + dev_info(i2c->dev, "probed\n"); + return 0; + +out: + return result; +}; + +static int octeon_i2c_remove(struct platform_device *pdev) +{ + struct octeon_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + return 0; +}; + +static const struct of_device_id octeon_i2c_match[] = { + { .compatible = "cavium,octeon-3860-twsi", }, + { .compatible = "cavium,octeon-7890-twsi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_i2c_match); + +static struct platform_driver octeon_i2c_driver = { + .probe = octeon_i2c_probe, + .remove = octeon_i2c_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = octeon_i2c_match, + }, +}; + +module_platform_driver(octeon_i2c_driver); + +MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); +MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ab1279b8e240..c7da0c42baee 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1425,10 +1425,8 @@ omap_i2c_probe(struct platform_device *pdev) /* 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(omap->dev, "failure adding adapter\n"); + if (r) goto err_unuse_clocks; - } dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, major, minor, omap->speed); diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index 75dd6d041241..11e2a1fc10e9 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -71,7 +71,7 @@ static int i2c_opal_send_request(u32 bus_id, struct opal_i2c_request *req) if (rc) goto exit; - rc = be64_to_cpu(msg.params[1]); + rc = opal_get_async_rc(msg); if (rc != OPAL_SUCCESS) { rc = i2c_opal_translate_error(rc); goto exit; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index e0eb4ca0102e..ba88f17f636c 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -193,23 +193,12 @@ static struct isa_driver pca_isa_driver = { } }; -static int __init pca_isa_init(void) -{ - return isa_register_driver(&pca_isa_driver, 1); -} - -static void __exit pca_isa_exit(void) -{ - isa_unregister_driver(&pca_isa_driver); -} - MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver"); MODULE_LICENSE("GPL"); module_param(base, ulong, 0); MODULE_PARM_DESC(base, "I/O base address"); - module_param(irq, int, 0); MODULE_PARM_DESC(irq, "IRQ"); module_param(clock, int, 0); @@ -220,6 +209,4 @@ MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t" "\t\t\t\tFast: 100100 - 400099\n" "\t\t\t\tFast+: 400100 - 10000099\n" "\t\t\t\tTurbo: Up to 1265800"); - -module_init(pca_isa_init); -module_exit(pca_isa_exit); +module_isa_driver(pca_isa_driver, 1); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 23d1c167b5d7..c2268cdf38e8 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -694,7 +694,6 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, retval = i2c_add_adapter(adap); if (retval) { - dev_err(&dev->dev, "Couldn't register adapter!\n"); kfree(adapdata); kfree(adap); release_region(smba, SMBIOSIZE); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 2c40edbf6224..217c78711d65 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -329,10 +329,8 @@ static int pmcmsptwi_probe(struct platform_device *pldev) i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data); rc = i2c_add_adapter(&pmcmsptwi_adapter); - if (rc) { - dev_err(&pldev->dev, "Unable to register I2C adapter\n"); + if (rc) goto ret_unmap; - } return 0; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 7ea67aa46fb7..fd5f9d2bf6d9 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -714,10 +714,8 @@ static int i2c_pnx_probe(struct platform_device *pdev) /* Register this adapter with the I2C subsystem */ ret = i2c_add_numbered_adapter(&alg_data->adapter); - if (ret < 0) { - dev_err(&pdev->dev, "I2C: Failed to add bus\n"); + if (ret < 0) goto out_clock; - } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", alg_data->adapter.name, res->start, alg_data->irq); diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index 82b6f02544da..0c8b1571886d 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -212,11 +212,8 @@ static int puv3_i2c_probe(struct platform_device *pdev) adapter->nr = pdev->id; rc = i2c_add_numbered_adapter(adapter); - if (rc) { - dev_err(&pdev->dev, "Adapter '%s' registration failed\n", - adapter->name); + if (rc) goto fail_add_adapter; - } dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); return 0; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 0d351954db02..e28b825b0433 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1292,10 +1292,8 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&dev->dev, "failed to add bus: %d\n", ret); + if (ret < 0) goto ereqirq; - } platform_set_drvdata(dev, i2c); diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index cc6439ab3f71..a8497cfdae6f 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) bus_err &= I2C_STATUS_ERROR_MASK; qup_err &= QUP_STATUS_ERROR_FLAGS; - if (qup_err) { - /* Clear Error interrupt */ + /* Clear the error bits in QUP_ERROR_FLAGS */ + if (qup_err) writel(qup_err, qup->base + QUP_ERROR_FLAGS); - goto done; - } - if (bus_err) { - /* Clear Error interrupt */ + /* Clear the error bits in QUP_I2C_STATUS */ + if (bus_err) + writel(bus_err, qup->base + QUP_I2C_STATUS); + + /* Reset the QUP State in case of error */ + if (qup_err || bus_err) { writel(QUP_RESET_STATE, qup->base + QUP_STATE); goto done; } @@ -310,6 +312,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, u32 opflags; u32 status; u32 shift = __ffs(op); + int ret = 0; len *= qup->one_byte_t; /* timeout after a wait of twice the max time */ @@ -321,18 +324,28 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, if (((opflags & op) >> shift) == val) { if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { - if (!(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (!(status & I2C_STATUS_BUS_ACTIVE)) { + ret = 0; + goto done; + } } else { - return 0; + ret = 0; + goto done; } } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + goto done; + } usleep_range(len, len * 2); } + +done: + if (qup->bus_err || qup->qup_err) + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; + + return ret; } static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, @@ -585,8 +598,8 @@ static void qup_i2c_bam_cb(void *data) } static int qup_sg_set_buf(struct scatterlist *sg, void *buf, - struct qup_i2c_tag *tg, unsigned int buflen, - struct qup_i2c_dev *qup, int map, int dir) + unsigned int buflen, struct qup_i2c_dev *qup, + int dir) { int ret; @@ -595,9 +608,6 @@ static int qup_sg_set_buf(struct scatterlist *sg, void *buf, if (!ret) return -EINVAL; - if (!map) - sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start); - return 0; } @@ -649,37 +659,37 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, u8 *tags; while (idx < num) { - blocks = (msg->len + limit) / limit; - rem = msg->len % limit; tx_len = 0, len = 0, i = 0; qup->is_last = (idx == (num - 1)); qup_i2c_set_blk_data(qup, msg); + blocks = qup->blk.count; + rem = msg->len - (blocks - 1) * limit; + if (msg->flags & I2C_M_RD) { rx_nents += (blocks * 2) + 1; tx_nents += 1; while (qup->blk.pos < blocks) { - /* length set to '0' implies 256 bytes */ - tlen = (i == (blocks - 1)) ? rem : 0; + tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + len]; len += qup_i2c_set_tags(tags, qup, msg, 1); + qup->blk.data_len -= tlen; /* scratch buf to read the start and len tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &qup->brx.tag.start[0], - &qup->brx.tag, - 2, qup, 0, 0); + 2, qup, DMA_FROM_DEVICE); if (ret) return ret; ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &msg->buf[limit * i], - NULL, tlen, qup, - 1, DMA_FROM_DEVICE); + tlen, qup, + DMA_FROM_DEVICE); if (ret) return ret; @@ -688,7 +698,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->start_tag.start[off], - &qup->start_tag, len, qup, 0, 0); + len, qup, DMA_TO_DEVICE); if (ret) return ret; @@ -696,30 +706,28 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, /* scratch buf to read the BAM EOT and FLUSH tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &qup->brx.tag.start[0], - &qup->brx.tag, 2, - qup, 0, 0); + 2, qup, DMA_FROM_DEVICE); if (ret) return ret; } else { tx_nents += (blocks * 2); while (qup->blk.pos < blocks) { - tlen = (i == (blocks - 1)) ? rem : 0; + tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + tx_len]; len = qup_i2c_set_tags(tags, qup, msg, 1); + qup->blk.data_len -= tlen; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], - tags, - &qup->start_tag, len, - qup, 0, 0); + tags, len, + qup, DMA_TO_DEVICE); if (ret) return ret; tx_len += len; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &msg->buf[limit * i], - NULL, tlen, qup, 1, - DMA_TO_DEVICE); + tlen, qup, DMA_TO_DEVICE); if (ret) return ret; i++; @@ -738,8 +746,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, QUP_BAM_FLUSH_STOP; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->btx.tag.start[0], - &qup->btx.tag, len, - qup, 0, 0); + len, qup, DMA_TO_DEVICE); if (ret) return ret; tx_nents += 1; @@ -801,39 +808,35 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } if (ret || qup->bus_err || qup->qup_err) { - if (qup->bus_err & QUP_I2C_NACK_FLAG) { - msg--; - dev_err(qup->dev, "NACK from %x\n", msg->addr); - ret = -EIO; + if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { + dev_err(qup->dev, "change to run state timed out"); + goto desc_err; + } - if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { - dev_err(qup->dev, "change to run state timed out"); - return ret; - } + if (rx_nents) + writel(QUP_BAM_INPUT_EOT, + qup->base + QUP_OUT_FIFO_BASE); - if (rx_nents) - writel(QUP_BAM_INPUT_EOT, - qup->base + QUP_OUT_FIFO_BASE); + writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE); - writel(QUP_BAM_FLUSH_STOP, - qup->base + QUP_OUT_FIFO_BASE); + qup_i2c_flush(qup); - qup_i2c_flush(qup); + /* wait for remaining interrupts to occur */ + if (!wait_for_completion_timeout(&qup->xfer, HZ)) + dev_err(qup->dev, "flush timed out\n"); - /* wait for remaining interrupts to occur */ - if (!wait_for_completion_timeout(&qup->xfer, HZ)) - dev_err(qup->dev, "flush timed out\n"); + qup_i2c_rel_dma(qup); - qup_i2c_rel_dma(qup); - } + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; } +desc_err: dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE); if (rx_nents) dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents, DMA_FROM_DEVICE); -desc_err: + return ret; } @@ -849,9 +852,6 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, if (ret) goto out; - qup->bus_err = 0; - qup->qup_err = 0; - writel(0, qup->base + QUP_MX_INPUT_CNT); writel(0, qup->base + QUP_MX_OUTPUT_CNT); @@ -889,12 +889,8 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, ret = -ETIMEDOUT; } - if (qup->bus_err || qup->qup_err) { - if (qup->bus_err & QUP_I2C_NACK_FLAG) { - dev_err(qup->dev, "NACK from %x\n", msg->addr); - ret = -EIO; - } - } + if (qup->bus_err || qup->qup_err) + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; return ret; } @@ -1020,7 +1016,7 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr, len, val; - addr = (msg->addr << 1) | 1; + addr = i2c_8bit_addr_from_msg(msg); /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */ len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len; @@ -1186,6 +1182,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, if (ret < 0) goto out; + qup->bus_err = 0; + qup->qup_err = 0; + writel(1, qup->base + QUP_SW_RESET); ret = qup_i2c_poll_state(qup, QUP_RESET_STATE); if (ret) @@ -1235,6 +1234,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, struct qup_i2c_dev *qup = i2c_get_adapdata(adap); int ret, len, idx = 0, use_dma = 0; + qup->bus_err = 0; + qup->qup_err = 0; + ret = pm_runtime_get_sync(qup->dev); if (ret < 0) goto out; @@ -1268,6 +1270,8 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, } } + idx = 0; + do { if (msgs[idx].len == 0) { ret = -EINVAL; @@ -1407,27 +1411,21 @@ static int qup_i2c_probe(struct platform_device *pdev) /* 2 tag bytes for each block + 5 for start, stop tags */ size = blocks * 2 + 5; - qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev, - size, 4, 0); - qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL, - &qup->start_tag.addr); + qup->start_tag.start = devm_kzalloc(&pdev->dev, + size, GFP_KERNEL); if (!qup->start_tag.start) { ret = -ENOMEM; goto fail_dma; } - qup->brx.tag.start = dma_pool_alloc(qup->dpool, - GFP_KERNEL, - &qup->brx.tag.addr); + qup->brx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL); if (!qup->brx.tag.start) { ret = -ENOMEM; goto fail_dma; } - qup->btx.tag.start = dma_pool_alloc(qup->dpool, - GFP_KERNEL, - &qup->btx.tag.addr); + qup->btx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL); if (!qup->btx.tag.start) { ret = -ENOMEM; goto fail_dma; @@ -1566,13 +1564,6 @@ static int qup_i2c_remove(struct platform_device *pdev) struct qup_i2c_dev *qup = platform_get_drvdata(pdev); if (qup->is_dma) { - dma_pool_free(qup->dpool, qup->start_tag.start, - qup->start_tag.addr); - dma_pool_free(qup->dpool, qup->brx.tag.start, - qup->brx.tag.addr); - dma_pool_free(qup->dpool, qup->btx.tag.start, - qup->btx.tag.addr); - dma_pool_destroy(qup->dpool); dma_release_channel(qup->btx.dma); dma_release_channel(qup->brx.dma); } @@ -1608,7 +1599,8 @@ static int qup_i2c_pm_resume_runtime(struct device *device) #ifdef CONFIG_PM_SLEEP static int qup_i2c_suspend(struct device *device) { - qup_i2c_pm_suspend_runtime(device); + if (!pm_runtime_suspended(device)) + return qup_i2c_pm_suspend_runtime(device); return 0; } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 52407f3c9e1c..726615e54f2a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -378,7 +378,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) } dma_addr = dma_map_single(chan->device->dev, buf, len, dir); - if (dma_mapping_error(dev, dma_addr)) { + if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(dev, "dma map failed, using PIO\n"); return; } @@ -802,6 +802,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .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 }, + { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -875,10 +876,8 @@ static int rcar_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); ret = i2c_add_numbered_adapter(adap); - if (ret < 0) { - dev_err(dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto out_pm_disable; - } dev_info(dev, "probed\n"); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index d7e3af671543..6263ea82d6ac 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -383,10 +383,8 @@ static int riic_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, riic); diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 80bed02cd942..50702c7bb244 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -58,6 +58,12 @@ enum { #define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ #define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ +#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8) + +#define REG_CON_SDA_CFG(cfg) ((cfg) << 8) +#define REG_CON_STA_CFG(cfg) ((cfg) << 12) +#define REG_CON_STO_CFG(cfg) ((cfg) << 14) + /* REG_MRXADDR bits */ #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ @@ -75,6 +81,77 @@ enum { #define WAIT_TIMEOUT 1000 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ +/** + * struct i2c_spec_values: + * @min_hold_start_ns: min hold time (repeated) START condition + * @min_low_ns: min LOW period of the SCL clock + * @min_high_ns: min HIGH period of the SCL cloc + * @min_setup_start_ns: min set-up time for a repeated START conditio + * @max_data_hold_ns: max data hold time + * @min_data_setup_ns: min data set-up time + * @min_setup_stop_ns: min set-up time for STOP condition + * @min_hold_buffer_ns: min bus free time between a STOP and + * START condition + */ +struct i2c_spec_values { + unsigned long min_hold_start_ns; + unsigned long min_low_ns; + unsigned long min_high_ns; + unsigned long min_setup_start_ns; + unsigned long max_data_hold_ns; + unsigned long min_data_setup_ns; + unsigned long min_setup_stop_ns; + unsigned long min_hold_buffer_ns; +}; + +static const struct i2c_spec_values standard_mode_spec = { + .min_hold_start_ns = 4000, + .min_low_ns = 4700, + .min_high_ns = 4000, + .min_setup_start_ns = 4700, + .max_data_hold_ns = 3450, + .min_data_setup_ns = 250, + .min_setup_stop_ns = 4000, + .min_hold_buffer_ns = 4700, +}; + +static const struct i2c_spec_values fast_mode_spec = { + .min_hold_start_ns = 600, + .min_low_ns = 1300, + .min_high_ns = 600, + .min_setup_start_ns = 600, + .max_data_hold_ns = 900, + .min_data_setup_ns = 100, + .min_setup_stop_ns = 600, + .min_hold_buffer_ns = 1300, +}; + +static const struct i2c_spec_values fast_mode_plus_spec = { + .min_hold_start_ns = 260, + .min_low_ns = 500, + .min_high_ns = 260, + .min_setup_start_ns = 260, + .max_data_hold_ns = 400, + .min_data_setup_ns = 50, + .min_setup_stop_ns = 260, + .min_hold_buffer_ns = 500, +}; + +/** + * struct rk3x_i2c_calced_timings: + * @div_low: Divider output for low + * @div_high: Divider output for high + * @tuning: Used to adjust setup/hold data time, + * setup/hold start time and setup stop time for + * v1's calc_timings, the tuning should all be 0 + * for old hardware anyone using v0's calc_timings. + */ +struct rk3x_i2c_calced_timings { + unsigned long div_low; + unsigned long div_high; + unsigned int tuning; +}; + enum rk3x_i2c_state { STATE_IDLE, STATE_START, @@ -85,11 +162,35 @@ enum rk3x_i2c_state { /** * @grf_offset: offset inside the grf regmap for setting the i2c type + * @calc_timings: Callback function for i2c timing information calculated */ struct rk3x_i2c_soc_data { int grf_offset; + int (*calc_timings)(unsigned long, struct i2c_timings *, + struct rk3x_i2c_calced_timings *); }; +/** + * struct rk3x_i2c - private data of the controller + * @adap: corresponding I2C adapter + * @dev: device for this controller + * @soc_data: related soc data struct + * @regs: virtual memory area + * @clk: function clk for rk3399 or function & Bus clks for others + * @pclk: Bus clk for rk3399 + * @clk_rate_nb: i2c clk rate change notify + * @t: I2C known timing information + * @lock: spinlock for the i2c bus + * @wait: the waitqueue to wait for i2c transfer + * @busy: the condition for the event to wait for + * @msg: current i2c message + * @addr: addr of i2c slave device + * @mode: mode of i2c transfer + * @is_last_msg: flag determines whether it is the last msg in this transfer + * @state: state of i2c transfer + * @processed: byte length which has been send or received + * @error: error code for i2c transfer + */ struct rk3x_i2c { struct i2c_adapter adap; struct device *dev; @@ -98,6 +199,7 @@ struct rk3x_i2c { /* Hardware resources */ void __iomem *regs; struct clk *clk; + struct clk *pclk; struct notifier_block clk_rate_nb; /* Settings */ @@ -116,7 +218,7 @@ struct rk3x_i2c { /* I2C state machine */ enum rk3x_i2c_state state; - unsigned int processed; /* sent/received bytes */ + unsigned int processed; int error; }; @@ -142,13 +244,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { - u32 val; + u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; - rk3x_i2c_clean_ipd(i2c); i2c_writel(i2c, REG_INT_START, REG_IEN); /* enable adapter with correct mode, send START condition */ - val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; /* if we want to react to NACK, set ACTACK bit */ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) @@ -189,7 +290,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) * get the intended effect by resetting its internal state * and issuing an ordinary START. */ - i2c_writel(i2c, 0, REG_CON); + ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + i2c_writel(i2c, ctrl, REG_CON); /* signal that we are finished with the current msg */ wake_up(&i2c->wait); @@ -431,26 +533,37 @@ out: } /** + * Get timing values of I2C specification + * + * @speed: Desired SCL frequency + * + * Returns: Matched i2c spec values. + */ +static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) +{ + if (speed <= 100000) + return &standard_mode_spec; + else if (speed <= 400000) + return &fast_mode_spec; + else + return &fast_mode_plus_spec; +} + +/** * Calculate divider values for desired SCL frequency * * @clk_rate: I2C input clock rate - * @t: Known I2C timing information. - * @div_low: Divider output for low - * @div_high: Divider output for high + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs * * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. */ -static int rk3x_i2c_calc_divs(unsigned long clk_rate, - struct i2c_timings *t, - unsigned long *div_low, - unsigned long *div_high) +static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, + struct i2c_timings *t, + struct rk3x_i2c_calced_timings *t_calc) { - 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; @@ -462,6 +575,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long min_div_for_hold, min_total_div; unsigned long extra_div, extra_low_div, ideal_low_div; + unsigned long data_hold_buffer_ns = 50; + const struct i2c_spec_values *spec; int ret = 0; /* Only support standard-mode and fast-mode */ @@ -484,22 +599,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * This is because the i2c host on Rockchip holds the data line * for half the low time. */ - if (t->bus_freq_hz <= 100000) { - /* 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 { - /* 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; - } - min_high_ns = t->scl_rise_ns + spec_min_high_ns; + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + min_high_ns = t->scl_rise_ns + spec->min_high_ns; /* * Timings for repeated start: @@ -509,14 +610,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * 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((t->scl_rise_ns + spec_setup_start) * 1000, 875)); - min_high_ns = max(min_high_ns, - DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start + - t->sda_fall_ns + spec_min_high_ns), 2)); - - min_low_ns = t->scl_fall_ns + spec_min_low_ns; - max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns; + min_high_ns = max(min_high_ns, DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875)); + min_high_ns = max(min_high_ns, DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns + + spec->min_high_ns), 2)); + + min_low_ns = t->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 */ @@ -552,8 +653,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * Time needed to meet hold requirements is important. * Just use that. */ - *div_low = min_low_div; - *div_high = min_high_div; + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; } else { /* * We've got to distribute some time among the low and high @@ -582,25 +683,185 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, /* Give low the "ideal" and give high whatever extra is left */ extra_low_div = ideal_low_div - min_low_div; - *div_low = ideal_low_div; - *div_high = min_high_div + (extra_div - extra_low_div); + t_calc->div_low = ideal_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); } /* * Adjust to the fact that the hardware has an implicit "+1". * NOTE: Above calculations always produce div_low > 0 and div_high > 0. */ - *div_low = *div_low - 1; - *div_high = *div_high - 1; + t_calc->div_low--; + t_calc->div_high--; /* Maximum divider supported by hw is 0xffff */ - if (*div_low > 0xffff) { - *div_low = 0xffff; + if (t_calc->div_low > 0xffff) { + t_calc->div_low = 0xffff; ret = -EINVAL; } - if (*div_high > 0xffff) { - *div_high = 0xffff; + if (t_calc->div_high > 0xffff) { + t_calc->div_high = 0xffff; + ret = -EINVAL; + } + + return ret; +} + +/** + * Calculate timing values for desired SCL frequency + * + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + * The following formulas are v1's method to calculate timings. + * + * l = divl + 1; + * h = divh + 1; + * s = sda_update_config + 1; + * u = start_setup_config + 1; + * p = stop_setup_config + 1; + * T = Tclk_i2c; + * + * tHigh = 8 * h * T; + * tLow = 8 * l * T; + * + * tHD;sda = (l * s + 1) * T; + * tSU;sda = [(8 - s) * l + 1] * T; + * tI2C = 8 * (l + h) * T; + * + * tSU;sta = (8h * u + 1) * T; + * tHD;sta = [8h * (u + 1) - 1] * T; + * tSU;sto = (8h * p + 1) * T; + */ +static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, + struct i2c_timings *t, + struct rk3x_i2c_calced_timings *t_calc) +{ + unsigned long min_low_ns, min_high_ns; + unsigned long min_setup_start_ns, min_setup_data_ns; + unsigned long min_setup_stop_ns, max_hold_data_ns; + + unsigned long clk_rate_khz, scl_rate_khz; + + unsigned long min_low_div, min_high_div; + + unsigned long min_div_for_hold, min_total_div; + unsigned long extra_div, extra_low_div; + unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg; + + const struct i2c_spec_values *spec; + int ret = 0; + + /* Support standard-mode, fast-mode and fast-mode plus */ + if (WARN_ON(t->bus_freq_hz > 1000000)) + t->bus_freq_hz = 1000000; + + /* prevent scl_rate_khz from becoming 0 */ + if (WARN_ON(t->bus_freq_hz < 1000)) + t->bus_freq_hz = 1000; + + /* + * 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. + */ + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + + /* calculate min-divh and min-divl */ + clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); + scl_rate_khz = t->bus_freq_hz / 1000; + min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); + + min_high_ns = t->scl_rise_ns + spec->min_high_ns; + min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); + + min_low_ns = t->scl_fall_ns + spec->min_low_ns; + min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); + + /* + * Final divh and divl must be greater than 0, otherwise the + * hardware would not output the i2c clk. + */ + min_high_div = (min_high_div < 1) ? 2 : min_high_div; + min_low_div = (min_low_div < 1) ? 2 : min_low_div; + + /* These are the min dividers needed for min hold times. */ + min_div_for_hold = (min_low_div + min_high_div); + + /* + * 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. + */ + if (min_div_for_hold >= min_total_div) { + /* + * Time needed to meet hold requirements is important. + * Just use that. + */ + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; + } else { + /* + * We've got to distribute some time among the low and high + * so we don't run too fast. + * We'll try to split things up by the scale of min_low_div and + * min_high_div, biasing slightly towards having a higher div + * for low (spend more time low). + */ + extra_div = min_total_div - min_div_for_hold; + extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, + min_div_for_hold); + + t_calc->div_low = min_low_div + extra_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); + } + + /* + * calculate sda data hold count by the rules, data_upd_st:3 + * is a appropriate value to reduce calculated times. + */ + for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) { + max_hold_data_ns = DIV_ROUND_UP((sda_update_cfg + * (t_calc->div_low) + 1) + * 1000000, clk_rate_khz); + min_setup_data_ns = DIV_ROUND_UP(((8 - sda_update_cfg) + * (t_calc->div_low) + 1) + * 1000000, clk_rate_khz); + if ((max_hold_data_ns < spec->max_data_hold_ns) && + (min_setup_data_ns > spec->min_data_setup_ns)) + break; + } + + /* calculate setup start config */ + min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns; + stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns + - 1000000, 8 * 1000000 * (t_calc->div_high)); + + /* calculate setup stop config */ + min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns; + stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns + - 1000000, 8 * 1000000 * (t_calc->div_high)); + + t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) | + REG_CON_STA_CFG(--stp_sta_cfg) | + REG_CON_STO_CFG(--stp_sto_cfg); + + t_calc->div_low--; + t_calc->div_high--; + + /* Maximum divider supported by hw is 0xffff */ + if (t_calc->div_low > 0xffff) { + t_calc->div_low = 0xffff; + ret = -EINVAL; + } + + if (t_calc->div_high > 0xffff) { + t_calc->div_high = 0xffff; ret = -EINVAL; } @@ -610,19 +871,31 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) { struct i2c_timings *t = &i2c->t; - unsigned long div_low, div_high; + struct rk3x_i2c_calced_timings calc; u64 t_low_ns, t_high_ns; + unsigned long flags; + u32 val; int ret; - ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high); + ret = i2c->soc_data->calc_timings(clk_rate, t, &calc); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz); - clk_enable(i2c->clk); - i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV); - clk_disable(i2c->clk); + clk_enable(i2c->pclk); + + spin_lock_irqsave(&i2c->lock, flags); + val = i2c_readl(i2c, REG_CON); + val &= ~REG_CON_TUNING_MASK; + val |= calc.tuning; + i2c_writel(i2c, val, REG_CON); + i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), + REG_CLKDIV); + spin_unlock_irqrestore(&i2c->lock, flags); + + clk_disable(i2c->pclk); - t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate); - t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate); + t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate); + t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000, + clk_rate); dev_dbg(i2c->dev, "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n", clk_rate / 1000, @@ -644,7 +917,7 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) * Code adapted from i2c-cadence.c. * * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK - * to acknowedge the change, NOTIFY_DONE if the notification is + * to acknowledge the change, NOTIFY_DONE if the notification is * considered irrelevant. */ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long @@ -652,12 +925,17 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long { struct clk_notifier_data *ndata = data; struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb); - unsigned long div_low, div_high; + struct rk3x_i2c_calced_timings calc; switch (event) { case PRE_RATE_CHANGE: - if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, - &div_low, &div_high) != 0) + /* + * Try the calculation (but don't store the result) ahead of + * time to see if we need to block the clock change. Timings + * shouldn't actually take effect until rk3x_i2c_adapt_div(). + */ + if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t, + &calc) != 0) return NOTIFY_STOP; /* scale up */ @@ -767,12 +1045,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, { struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; unsigned long timeout, flags; + u32 val; int ret = 0; int i; spin_lock_irqsave(&i2c->lock, flags); clk_enable(i2c->clk); + clk_enable(i2c->pclk); i2c->is_last_msg = false; @@ -806,7 +1086,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); - i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); + val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + val |= REG_CON_EN | REG_CON_STOP; + i2c_writel(i2c, val, REG_CON); i2c->state = STATE_IDLE; @@ -820,12 +1102,23 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, } } + clk_disable(i2c->pclk); clk_disable(i2c->clk); + spin_unlock_irqrestore(&i2c->lock, flags); return ret < 0 ? ret : num; } +static __maybe_unused int rk3x_i2c_resume(struct device *dev) +{ + struct rk3x_i2c *i2c = dev_get_drvdata(dev); + + rk3x_i2c_adapt_div(i2c, clk_get_rate(i2c->clk)); + + return 0; +} + static u32 rk3x_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; @@ -836,17 +1129,52 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = { .functionality = rk3x_i2c_func, }; -static struct rk3x_i2c_soc_data soc_data[3] = { - { .grf_offset = 0x154 }, /* rk3066 */ - { .grf_offset = 0x0a4 }, /* rk3188 */ - { .grf_offset = -1 }, /* no I2C switching needed */ +static const struct rk3x_i2c_soc_data rk3066_soc_data = { + .grf_offset = 0x154, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3188_soc_data = { + .grf_offset = 0x0a4, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3228_soc_data = { + .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3288_soc_data = { + .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3399_soc_data = { + .grf_offset = -1, + .calc_timings = rk3x_i2c_v1_calc_timings, }; static const struct of_device_id rk3x_i2c_match[] = { - { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] }, - { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] }, - { .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] }, - { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, + { + .compatible = "rockchip,rk3066-i2c", + .data = (void *)&rk3066_soc_data + }, + { + .compatible = "rockchip,rk3188-i2c", + .data = (void *)&rk3188_soc_data + }, + { + .compatible = "rockchip,rk3228-i2c", + .data = (void *)&rk3228_soc_data + }, + { + .compatible = "rockchip,rk3288-i2c", + .data = (void *)&rk3288_soc_data + }, + { + .compatible = "rockchip,rk3399-i2c", + .data = (void *)&rk3399_soc_data + }, {}, }; MODULE_DEVICE_TABLE(of, rk3x_i2c_match); @@ -886,12 +1214,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - i2c->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "cannot get clock\n"); - return PTR_ERR(i2c->clk); - } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(i2c->regs)) @@ -945,27 +1267,52 @@ static int rk3x_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); + if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { + /* Only one clock to use for bus clock and peripheral clock */ + i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->pclk = i2c->clk; + } else { + i2c->clk = devm_clk_get(&pdev->dev, "i2c"); + i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + } + + if (IS_ERR(i2c->clk)) { + ret = PTR_ERR(i2c->clk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret); + return ret; + } + if (IS_ERR(i2c->pclk)) { + ret = PTR_ERR(i2c->pclk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret); + return ret; + } + ret = clk_prepare(i2c->clk); if (ret < 0) { - dev_err(&pdev->dev, "Could not prepare clock\n"); + dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret); return ret; } + ret = clk_prepare(i2c->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret); + goto err_clk; + } i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); if (ret != 0) { dev_err(&pdev->dev, "Unable to register clock notifier\n"); - goto err_clk; + goto err_pclk; } clk_rate = clk_get_rate(i2c->clk); rk3x_i2c_adapt_div(i2c, clk_rate); ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "Could not register adapter\n"); + if (ret < 0) goto err_clk_notifier; - } dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); @@ -973,6 +1320,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) err_clk_notifier: clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); +err_pclk: + clk_unprepare(i2c->pclk); err_clk: clk_unprepare(i2c->clk); return ret; @@ -985,17 +1334,21 @@ static int rk3x_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); + clk_unprepare(i2c->pclk); clk_unprepare(i2c->clk); return 0; } +static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume); + static struct platform_driver rk3x_i2c_driver = { .probe = rk3x_i2c_probe, .remove = rk3x_i2c_remove, .driver = { .name = "rk3x-i2c", .of_match_table = rk3x_i2c_match, + .pm = &rk3x_i2c_pm_ops, }, }; diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index ced9c6a308d1..89d8b41b6668 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -125,7 +125,7 @@ static struct i2c_algorithm osif_algorithm = { #define USB_OSIF_VENDOR_ID 0x1964 #define USB_OSIF_PRODUCT_ID 0x0001 -static struct usb_device_id osif_table[] = { +static const struct usb_device_id osif_table[] = { { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) }, { } }; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 38dc1cacfd8b..499af26e736e 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1215,7 +1215,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) 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); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 24968384b401..c2005c789d2b 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -510,10 +510,8 @@ static int sh7760_i2c_probe(struct platform_device *pdev) } ret = i2c_add_numbered_adapter(&id->adap); - if (ret < 0) { - dev_err(&pdev->dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto out4; - } platform_set_drvdata(pdev, id); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 6fb3e2645992..192f36f00e4d 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -610,7 +610,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) return; dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir); - if (dma_mapping_error(pd->dev, dma_addr)) { + if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(pd->dev, "dma map failed, using PIO\n"); return; } @@ -981,7 +981,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { sh_mobile_i2c_release_dma(pd); - dev_err(&dev->dev, "cannot add numbered adapter\n"); return ret; } diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 792a42bdd335..95e81d0f72b4 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -387,10 +387,8 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY); err = i2c_add_numbered_adapter(adap); - if (err < 0) { - dev_err(&pdev->dev, "Can't add new i2c adapter\n"); + if (err < 0) goto out; - } clk_disable(clk); diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 944ec4205084..1371547ce1a3 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -874,10 +874,8 @@ static int st_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->complete); ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, i2c_dev); diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 460c134832ac..dc63236b45b2 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -920,11 +920,8 @@ static int stu300_probe(struct platform_device *pdev) /* i2c device drivers may be active on return from add_adapter() */ ret = i2c_add_numbered_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "failure adding ST Micro DDC " - "I2C adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, dev); dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n", diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 445398c314a3..4af9bbae20df 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -28,6 +28,9 @@ #include <linux/of_device.h> #include <linux/module.h> #include <linux/reset.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pm_runtime.h> +#include <linux/iopoll.h> #include <asm/unaligned.h> @@ -36,21 +39,21 @@ #define I2C_CNFG 0x000 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 -#define I2C_CNFG_PACKET_MODE_EN (1<<10) -#define I2C_CNFG_NEW_MASTER_FSM (1<<11) -#define I2C_CNFG_MULTI_MASTER_MODE (1<<17) +#define I2C_CNFG_PACKET_MODE_EN BIT(10) +#define I2C_CNFG_NEW_MASTER_FSM BIT(11) +#define I2C_CNFG_MULTI_MASTER_MODE BIT(17) #define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 -#define I2C_SL_CNFG_NACK (1<<1) -#define I2C_SL_CNFG_NEWSL (1<<2) +#define I2C_SL_CNFG_NACK BIT(1) +#define I2C_SL_CNFG_NEWSL BIT(2) #define I2C_SL_ADDR1 0x02c #define I2C_SL_ADDR2 0x030 #define I2C_TX_FIFO 0x050 #define I2C_RX_FIFO 0x054 #define I2C_PACKET_TRANSFER_STATUS 0x058 #define I2C_FIFO_CONTROL 0x05c -#define I2C_FIFO_CONTROL_TX_FLUSH (1<<1) -#define I2C_FIFO_CONTROL_RX_FLUSH (1<<0) +#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1) +#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0) #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5 #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2 #define I2C_FIFO_STATUS 0x060 @@ -60,26 +63,26 @@ #define I2C_FIFO_STATUS_RX_SHIFT 0 #define I2C_INT_MASK 0x064 #define I2C_INT_STATUS 0x068 -#define I2C_INT_PACKET_XFER_COMPLETE (1<<7) -#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6) -#define I2C_INT_TX_FIFO_OVERFLOW (1<<5) -#define I2C_INT_RX_FIFO_UNDERFLOW (1<<4) -#define I2C_INT_NO_ACK (1<<3) -#define I2C_INT_ARBITRATION_LOST (1<<2) -#define I2C_INT_TX_FIFO_DATA_REQ (1<<1) -#define I2C_INT_RX_FIFO_DATA_REQ (1<<0) +#define I2C_INT_PACKET_XFER_COMPLETE BIT(7) +#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6) +#define I2C_INT_TX_FIFO_OVERFLOW BIT(5) +#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4) +#define I2C_INT_NO_ACK BIT(3) +#define I2C_INT_ARBITRATION_LOST BIT(2) +#define I2C_INT_TX_FIFO_DATA_REQ BIT(1) +#define I2C_INT_RX_FIFO_DATA_REQ BIT(0) #define I2C_CLK_DIVISOR 0x06c #define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16 #define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8 #define DVC_CTRL_REG1 0x000 -#define DVC_CTRL_REG1_INTR_EN (1<<10) +#define DVC_CTRL_REG1_INTR_EN BIT(10) #define DVC_CTRL_REG2 0x004 #define DVC_CTRL_REG3 0x008 -#define DVC_CTRL_REG3_SW_PROG (1<<26) -#define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30) +#define DVC_CTRL_REG3_SW_PROG BIT(26) +#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30) #define DVC_STATUS 0x00c -#define DVC_STATUS_I2C_DONE_INTR (1<<30) +#define DVC_STATUS_I2C_DONE_INTR BIT(30) #define I2C_ERR_NONE 0x00 #define I2C_ERR_NO_ACK 0x01 @@ -89,26 +92,28 @@ #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 #define PACKET_HEADER0_PACKET_ID_SHIFT 16 #define PACKET_HEADER0_CONT_ID_SHIFT 12 -#define PACKET_HEADER0_PROTOCOL_I2C (1<<4) - -#define I2C_HEADER_HIGHSPEED_MODE (1<<22) -#define I2C_HEADER_CONT_ON_NAK (1<<21) -#define I2C_HEADER_SEND_START_BYTE (1<<20) -#define I2C_HEADER_READ (1<<19) -#define I2C_HEADER_10BIT_ADDR (1<<18) -#define I2C_HEADER_IE_ENABLE (1<<17) -#define I2C_HEADER_REPEAT_START (1<<16) -#define I2C_HEADER_CONTINUE_XFER (1<<15) +#define PACKET_HEADER0_PROTOCOL_I2C BIT(4) + +#define I2C_HEADER_HIGHSPEED_MODE BIT(22) +#define I2C_HEADER_CONT_ON_NAK BIT(21) +#define I2C_HEADER_SEND_START_BYTE BIT(20) +#define I2C_HEADER_READ BIT(19) +#define I2C_HEADER_10BIT_ADDR BIT(18) +#define I2C_HEADER_IE_ENABLE BIT(17) +#define I2C_HEADER_REPEAT_START BIT(16) +#define I2C_HEADER_CONTINUE_XFER BIT(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) +#define I2C_MSTR_CONFIG_LOAD BIT(0) +#define I2C_SLV_CONFIG_LOAD BIT(1) +#define I2C_TIMEOUT_CONFIG_LOAD BIT(2) #define I2C_CLKEN_OVERRIDE 0x090 -#define I2C_MST_CORE_CLKEN_OVR (1 << 0) +#define I2C_MST_CORE_CLKEN_OVR BIT(0) + +#define I2C_CONFIG_LOAD_TIMEOUT 1000000 /* * msg_end_type: The bus control which need to be send at end of transfer. @@ -191,9 +196,11 @@ struct tegra_i2c_dev { u16 clk_divisor_non_hs_mode; bool is_suspended; bool is_multimaster_mode; + spinlock_t xfer_lock; }; -static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) +static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, + unsigned long reg) { writel(val, i2c_dev->base + reg); } @@ -244,15 +251,17 @@ static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data, static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) { - u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); - int_mask &= ~mask; + u32 int_mask; + + int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask; i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); } static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) { - u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); - int_mask |= mask; + u32 int_mask; + + int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask; i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); } @@ -260,6 +269,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); + val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); @@ -385,7 +395,8 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) */ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) { - u32 val = 0; + u32 val; + val = dvc_readl(i2c_dev, DVC_CTRL_REG3); val |= DVC_CTRL_REG3_SW_PROG; val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN; @@ -396,9 +407,15 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) dvc_writel(i2c_dev, val, DVC_CTRL_REG1); } -static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) +static int tegra_i2c_runtime_resume(struct device *dev) { + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; + + ret = pinctrl_pm_select_default_state(i2c_dev->dev); + if (ret) + return ret; + if (!i2c_dev->hw->has_single_clk_source) { ret = clk_enable(i2c_dev->fast_clk); if (ret < 0) { @@ -407,32 +424,66 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) return ret; } } + ret = clk_enable(i2c_dev->div_clk); if (ret < 0) { dev_err(i2c_dev->dev, "Enabling div clk failed, err %d\n", ret); clk_disable(i2c_dev->fast_clk); + return ret; } - return ret; + + return 0; } -static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) +static int tegra_i2c_runtime_suspend(struct device *dev) { + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); + clk_disable(i2c_dev->div_clk); if (!i2c_dev->hw->has_single_clk_source) clk_disable(i2c_dev->fast_clk); + + return pinctrl_pm_select_idle_state(i2c_dev->dev); +} + +static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) +{ + unsigned long reg_offset; + void __iomem *addr; + u32 val; + int err; + + if (i2c_dev->hw->has_config_load_reg) { + reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD); + addr = i2c_dev->base + reg_offset; + i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); + if (in_interrupt()) + err = readl_poll_timeout_atomic(addr, val, val == 0, + 1000, I2C_CONFIG_LOAD_TIMEOUT); + else + err = readl_poll_timeout(addr, val, val == 0, + 1000, I2C_CONFIG_LOAD_TIMEOUT); + + if (err) { + dev_warn(i2c_dev->dev, + "timeout waiting for config load\n"); + return err; + } + } + + return 0; } static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; - int err = 0; + int err; u32 clk_divisor; - unsigned long timeout = jiffies + HZ; - err = tegra_i2c_clock_enable(i2c_dev); + err = pm_runtime_get_sync(i2c_dev->dev); if (err < 0) { - dev_err(i2c_dev->dev, "Clock enable failed %d\n", err); + dev_err(i2c_dev->dev, "runtime resume failed %d\n", err); return err; } @@ -460,54 +511,59 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); + sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); - } val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); - if (tegra_i2c_flush_fifos(i2c_dev)) - err = -ETIMEDOUT; + err = tegra_i2c_flush_fifos(i2c_dev); + if (err) + goto err; if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg) i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE); - 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"); - err = -ETIMEDOUT; - goto err; - } - msleep(1); - } - } + err = tegra_i2c_wait_for_config_load(i2c_dev); + if (err) + goto err; if (i2c_dev->irq_disabled) { - i2c_dev->irq_disabled = 0; + i2c_dev->irq_disabled = false; enable_irq(i2c_dev->irq); } err: - tegra_i2c_clock_disable(i2c_dev); + pm_runtime_put(i2c_dev->dev); return err; } +static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev) +{ + u32 cnfg; + + cnfg = i2c_readl(i2c_dev, I2C_CNFG); + if (cnfg & I2C_CNFG_PACKET_MODE_EN) + i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG); + + return tegra_i2c_wait_for_config_load(i2c_dev); +} + static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) { u32 status; const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; struct tegra_i2c_dev *i2c_dev = dev_id; + unsigned long flags; status = i2c_readl(i2c_dev, I2C_INT_STATUS); + spin_lock_irqsave(&i2c_dev->xfer_lock, flags); if (status == 0) { dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), @@ -517,12 +573,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) if (!i2c_dev->irq_disabled) { disable_irq_nosync(i2c_dev->irq); - i2c_dev->irq_disabled = 1; + i2c_dev->irq_disabled = true; } goto err; } if (unlikely(status & status_err)) { + tegra_i2c_disable_packet_mode(i2c_dev); if (status & I2C_INT_NO_ACK) i2c_dev->msg_err |= I2C_ERR_NO_ACK; if (status & I2C_INT_ARBITRATION_LOST) @@ -552,7 +609,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) BUG_ON(i2c_dev->msg_buf_remaining); complete(&i2c_dev->msg_complete); } - return IRQ_HANDLED; + goto done; err: /* An error occurred, mask all interrupts */ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | @@ -563,6 +620,8 @@ err: dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); complete(&i2c_dev->msg_complete); +done: + spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); return IRQ_HANDLED; } @@ -572,6 +631,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, u32 packet_header; u32 int_mask; unsigned long time_left; + unsigned long flags; tegra_i2c_flush_fifos(i2c_dev); @@ -584,6 +644,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, i2c_dev->msg_read = (msg->flags & I2C_M_RD); reinit_completion(&i2c_dev->msg_complete); + spin_lock_irqsave(&i2c_dev->xfer_lock, flags); + + int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; + tegra_i2c_unmask_irq(i2c_dev, int_mask); + packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | PACKET_HEADER0_PROTOCOL_I2C | (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) | @@ -613,14 +678,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, if (!(msg->flags & I2C_M_RD)) tegra_i2c_fill_tx_fifo(i2c_dev); - int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) int_mask |= I2C_INT_PACKET_XFER_COMPLETE; if (msg->flags & I2C_M_RD) int_mask |= I2C_INT_RX_FIFO_DATA_REQ; else if (i2c_dev->msg_buf_remaining) int_mask |= I2C_INT_TX_FIFO_DATA_REQ; + tegra_i2c_unmask_irq(i2c_dev, int_mask); + spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n", i2c_readl(i2c_dev, I2C_INT_MASK)); @@ -643,9 +709,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, return 0; /* - * NACK interrupt is generated before the I2C controller generates the - * STOP condition on the bus. So wait for 2 clock periods before resetting - * the controller so that STOP condition has been delivered properly. + * NACK interrupt is generated before the I2C controller generates + * the STOP condition on the bus. So wait for 2 clock periods + * before resetting the controller so that the STOP condition has + * been delivered properly. */ if (i2c_dev->msg_err == I2C_ERR_NO_ACK) udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate)); @@ -670,14 +737,15 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (i2c_dev->is_suspended) return -EBUSY; - ret = tegra_i2c_clock_enable(i2c_dev); + ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) { - dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret); + dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret); return ret; } for (i = 0; i < num; i++) { enum msg_end_type end_type = MSG_END_STOP; + if (i < (num - 1)) { if (msgs[i + 1].flags & I2C_M_NOSTART) end_type = MSG_END_CONTINUE; @@ -688,7 +756,9 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (ret) break; } - tegra_i2c_clock_disable(i2c_dev); + + pm_runtime_put(i2c_dev->dev); + return ret ?: i; } @@ -825,7 +895,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) div_clk = devm_clk_get(&pdev->dev, "div-clk"); if (IS_ERR(div_clk)) { - dev_err(&pdev->dev, "missing controller clock"); + dev_err(&pdev->dev, "missing controller clock\n"); return PTR_ERR(div_clk); } @@ -843,27 +913,22 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->rst = devm_reset_control_get(&pdev->dev, "i2c"); if (IS_ERR(i2c_dev->rst)) { - dev_err(&pdev->dev, "missing controller reset"); + dev_err(&pdev->dev, "missing controller reset\n"); return PTR_ERR(i2c_dev->rst); } tegra_i2c_parse_dt(i2c_dev); - i2c_dev->hw = &tegra20_i2c_hw; - - if (pdev->dev.of_node) { - i2c_dev->hw = of_device_get_match_data(&pdev->dev); - i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, - "nvidia,tegra20-i2c-dvc"); - } else if (pdev->id == 3) { - i2c_dev->is_dvc = 1; - } + i2c_dev->hw = of_device_get_match_data(&pdev->dev); + i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra20-i2c-dvc"); init_completion(&i2c_dev->msg_complete); + spin_lock_init(&i2c_dev->xfer_lock); if (!i2c_dev->hw->has_single_clk_source) { fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); if (IS_ERR(fast_clk)) { - dev_err(&pdev->dev, "missing fast clock"); + dev_err(&pdev->dev, "missing fast clock\n"); return PTR_ERR(fast_clk); } i2c_dev->fast_clk = fast_clk; @@ -900,19 +965,28 @@ static int tegra_i2c_probe(struct platform_device *pdev) goto unprepare_fast_clk; } + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = tegra_i2c_runtime_resume(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "runtime resume failed\n"); + goto unprepare_div_clk; + } + } + if (i2c_dev->is_multimaster_mode) { ret = clk_enable(i2c_dev->div_clk); if (ret < 0) { dev_err(i2c_dev->dev, "div_clk enable failed %d\n", ret); - goto unprepare_div_clk; + goto disable_rpm; } } ret = tegra_i2c_init(i2c_dev); if (ret) { - dev_err(&pdev->dev, "Failed to initialize i2c controller"); - goto unprepare_div_clk; + dev_err(&pdev->dev, "Failed to initialize i2c controller\n"); + goto disable_div_clk; } ret = devm_request_irq(&pdev->dev, i2c_dev->irq, @@ -925,17 +999,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); i2c_dev->adapter.owner = THIS_MODULE; i2c_dev->adapter.class = I2C_CLASS_DEPRECATED; - strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter", + strlcpy(i2c_dev->adapter.name, dev_name(&pdev->dev), sizeof(i2c_dev->adapter.name)); i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; i2c_dev->adapter.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c_dev->adapter); - if (ret) { - dev_err(&pdev->dev, "Failed to add I2C adapter\n"); + if (ret) goto disable_div_clk; - } return 0; @@ -943,6 +1015,11 @@ disable_div_clk: if (i2c_dev->is_multimaster_mode) clk_disable(i2c_dev->div_clk); +disable_rpm: + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_i2c_runtime_suspend(&pdev->dev); + unprepare_div_clk: clk_unprepare(i2c_dev->div_clk); @@ -956,11 +1033,16 @@ unprepare_fast_clk: static int tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + i2c_del_adapter(&i2c_dev->adapter); if (i2c_dev->is_multimaster_mode) clk_disable(i2c_dev->div_clk); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_i2c_runtime_suspend(&pdev->dev); + clk_unprepare(i2c_dev->div_clk); if (!i2c_dev->hw->has_single_clk_source) clk_unprepare(i2c_dev->fast_clk); @@ -988,20 +1070,19 @@ static int tegra_i2c_resume(struct device *dev) i2c_lock_adapter(&i2c_dev->adapter); ret = tegra_i2c_init(i2c_dev); - - if (ret) { - i2c_unlock_adapter(&i2c_dev->adapter); - return ret; - } - - i2c_dev->is_suspended = false; + if (!ret) + i2c_dev->is_suspended = false; i2c_unlock_adapter(&i2c_dev->adapter); - return 0; + return ret; } -static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); +static const struct dev_pm_ops tegra_i2c_pm = { + SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) +}; #define TEGRA_I2C_PM (&tegra_i2c_pm) #else #define TEGRA_I2C_PM NULL diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c new file mode 100644 index 000000000000..bba5b429f69c --- /dev/null +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -0,0 +1,259 @@ +/* + * Cavium ThunderX i2c driver. + * + * Copyright (C) 2015,2016 Cavium Inc. + * Authors: Fred Martin <fmartin@caviumnetworks.com> + * Jan Glauber <jglauber@cavium.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/acpi.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/pci.h> + +#include "i2c-octeon-core.h" + +#define DRV_NAME "i2c-thunderx" + +#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012 + +#define SYS_FREQ_DEFAULT 700000000 + +#define TWSI_INT_ENA_W1C 0x1028 +#define TWSI_INT_ENA_W1S 0x1030 + +/* + * Enable the CORE interrupt. + * The interrupt will be asserted when there is non-STAT_IDLE state in the + * SW_TWSI_EOP_TWSI_STAT register. + */ +static void thunder_i2c_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_CORE_INT, + i2c->twsi_base + TWSI_INT_ENA_W1S); +} + +/* + * Disable the CORE interrupt. + */ +static void thunder_i2c_int_disable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_CORE_INT, + i2c->twsi_base + TWSI_INT_ENA_W1C); +} + +static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT, + i2c->twsi_base + TWSI_INT_ENA_W1S); +} + +static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT, + i2c->twsi_base + TWSI_INT_ENA_W1C); +} + +static u32 thunderx_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; +} + +static const struct i2c_algorithm thunderx_i2c_algo = { + .master_xfer = octeon_i2c_xfer, + .functionality = thunderx_i2c_functionality, +}; + +static struct i2c_adapter thunderx_i2c_ops = { + .owner = THIS_MODULE, + .name = "ThunderX adapter", + .algo = &thunderx_i2c_algo, +}; + +static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) +{ + int ret; + + i2c->clk = clk_get(dev, NULL); + if (IS_ERR(i2c->clk)) { + i2c->clk = NULL; + goto skip; + } + + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto skip; + i2c->sys_freq = clk_get_rate(i2c->clk); + +skip: + if (!i2c->sys_freq) + i2c->sys_freq = SYS_FREQ_DEFAULT; +} + +static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) +{ + if (!clk) + return; + clk_disable_unprepare(clk); + clk_put(clk); +} + +static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, + struct device_node *node) +{ + u32 type; + + if (!node) + return -EINVAL; + + i2c->alert_data.irq = irq_of_parse_and_map(node, 0); + if (!i2c->alert_data.irq) + return -EINVAL; + + type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq)); + i2c->alert_data.alert_edge_triggered = + (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0; + + i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); + if (!i2c->ara) + return -ENODEV; + return 0; +} + +static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c, + struct device_node *node) +{ + /* TODO: ACPI support */ + if (!acpi_disabled) + return -EOPNOTSUPP; + + return thunder_i2c_smbus_setup_of(i2c, node); +} + +static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c) +{ + if (i2c->ara) + i2c_unregister_device(i2c->ara); +} + +static int thunder_i2c_probe_pci(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct octeon_i2c *i2c; + int ret; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->roff.sw_twsi = 0x1000; + i2c->roff.twsi_int = 0x1010; + i2c->roff.sw_twsi_ext = 0x1018; + + i2c->dev = dev; + pci_set_drvdata(pdev, i2c); + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret) + return ret; + + i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!i2c->twsi_base) + return -EINVAL; + + thunder_i2c_clock_enable(dev, i2c); + ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq); + if (ret) + i2c->twsi_freq = 100000; + + init_waitqueue_head(&i2c->queue); + + i2c->int_enable = thunder_i2c_int_enable; + i2c->int_disable = thunder_i2c_int_disable; + i2c->hlc_int_enable = thunder_i2c_hlc_int_enable; + i2c->hlc_int_disable = thunder_i2c_hlc_int_disable; + + ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1); + if (ret) + goto error; + + ret = devm_request_irq(dev, i2c->i2c_msix.vector, octeon_i2c_isr, 0, + DRV_NAME, i2c); + if (ret) + goto error; + + ret = octeon_i2c_init_lowlevel(i2c); + if (ret) + goto error; + + octeon_i2c_set_clock(i2c); + + i2c->adap = thunderx_i2c_ops; + i2c->adap.retries = 5; + i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; + i2c->adap.dev.parent = dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + "Cavium ThunderX i2c adapter at %s", dev_name(dev)); + i2c_set_adapdata(&i2c->adap, i2c); + + ret = i2c_add_adapter(&i2c->adap); + if (ret) + goto error; + + dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq); + + ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node); + if (ret) + dev_info(dev, "SMBUS alert not active on this bus\n"); + + return 0; + +error: + thunder_i2c_clock_disable(dev, i2c->clk); + return ret; +} + +static void thunder_i2c_remove_pci(struct pci_dev *pdev) +{ + struct octeon_i2c *i2c = pci_get_drvdata(pdev); + + thunder_i2c_smbus_remove(i2c); + thunder_i2c_clock_disable(&pdev->dev, i2c->clk); + i2c_del_adapter(&i2c->adap); +} + +static const struct pci_device_id thunder_i2c_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table); + +static struct pci_driver thunder_i2c_pci_driver = { + .name = DRV_NAME, + .id_table = thunder_i2c_pci_id_table, + .probe = thunder_i2c_probe_pci, + .remove = thunder_i2c_remove_pci, +}; + +module_pci_driver(thunder_i2c_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fred Martin <fmartin@caviumnetworks.com>"); +MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC"); diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index aeead0d27d10..db9105e52c79 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -14,6 +14,7 @@ #include <linux/clk.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -348,14 +349,19 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, 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) { + u32 status; + int ret; + + ret = readl_poll_timeout(priv->membase + UNIPHIER_FI2C_SR, + status, + (status & UNIPHIER_FI2C_SR_STS) && + !(status & UNIPHIER_FI2C_SR_BB), + 1, 20); + if (ret) { dev_err(&adap->dev, "stop condition was not completed.\n"); uniphier_fi2c_recover(priv); - return -EBUSY; + return ret; } } @@ -455,54 +461,25 @@ static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = { .unprepare_recovery = uniphier_fi2c_unprepare_recovery, }; -static int uniphier_fi2c_clk_init(struct device *dev, - struct uniphier_fi2c_priv *priv) +static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv, + u32 bus_speed, unsigned long clk_rate) { - 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) { - dev_err(dev, "clock-frequency should not be zero\n"); - return -EINVAL; - } - - 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); - } + u32 tmp; - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(priv->clk); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - return -EINVAL; - } + tmp = readl(priv->membase + UNIPHIER_FI2C_CR); + tmp |= UNIPHIER_FI2C_CR_MST; + writel(tmp, priv->membase + UNIPHIER_FI2C_CR); uniphier_fi2c_reset(priv); - clk_count = clk_rate / bus_speed; + tmp = 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); + writel(tmp, priv->membase + UNIPHIER_FI2C_CYC); + writel(tmp / 2, priv->membase + UNIPHIER_FI2C_LCTL); + writel(tmp / 2, priv->membase + UNIPHIER_FI2C_SSUT); + writel(tmp / 16, priv->membase + UNIPHIER_FI2C_DSUT); uniphier_fi2c_prepare_operation(priv); - - return 0; } static int uniphier_fi2c_probe(struct platform_device *pdev) @@ -510,8 +487,9 @@ 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; + u32 bus_speed; + unsigned long clk_rate; + int irq, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -528,6 +506,31 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) return irq; } + if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED; + + if (!bus_speed || bus_speed > UNIPHIER_FI2C_MAX_SPEED) { + dev_err(dev, "invalid clock-frequency %d\n", bus_speed); + return -EINVAL; + } + + 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); + if (!clk_rate) { + dev_err(dev, "input clock rate should not be zero\n"); + ret = -EINVAL; + goto err; + } + init_completion(&priv->comp); priv->adap.owner = THIS_MODULE; priv->adap.algo = &uniphier_fi2c_algo; @@ -538,9 +541,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); - ret = uniphier_fi2c_clk_init(dev, priv); - if (ret) - goto err; + uniphier_fi2c_hw_init(priv, bus_speed, clk_rate); ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, pdev->name, priv); @@ -550,11 +551,6 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) } 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); diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 475a5eb514e2..56e92af46ddc 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -316,50 +316,15 @@ static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = { .unprepare_recovery = uniphier_i2c_unprepare_recovery, }; -static int uniphier_i2c_clk_init(struct device *dev, - struct uniphier_i2c_priv *priv) +static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv, + u32 bus_speed, unsigned long clk_rate) { - 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) { - dev_err(dev, "clock-frequency should not be zero\n"); - return -EINVAL; - } - - 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); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - return -EINVAL; - } - 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) @@ -367,8 +332,9 @@ 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; + u32 bus_speed; + unsigned long clk_rate; + int irq, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -385,6 +351,31 @@ static int uniphier_i2c_probe(struct platform_device *pdev) return irq; } + if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_I2C_DEFAULT_SPEED; + + if (!bus_speed || bus_speed > UNIPHIER_I2C_MAX_SPEED) { + dev_err(dev, "invalid clock-frequency %d\n", bus_speed); + return -EINVAL; + } + + 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); + if (!clk_rate) { + dev_err(dev, "input clock rate should not be zero\n"); + ret = -EINVAL; + goto err; + } + init_completion(&priv->comp); priv->adap.owner = THIS_MODULE; priv->adap.algo = &uniphier_i2c_algo; @@ -395,9 +386,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); - ret = uniphier_i2c_clk_init(dev, priv); - if (ret) - goto err; + uniphier_i2c_hw_init(priv, bus_speed, clk_rate); ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, priv); @@ -407,11 +396,6 @@ static int uniphier_i2c_probe(struct platform_device *pdev) } 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); diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 240637f01d11..c73d2d22009e 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -70,28 +70,14 @@ static int i2c_versatile_probe(struct platform_device *dev) struct resource *r; int ret; + i2c = devm_kzalloc(&dev->dev, sizeof(struct i2c_versatile), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) { - ret = -EINVAL; - goto err_out; - } - - if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) { - ret = -EBUSY; - goto err_out; - } - - i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL); - if (!i2c) { - ret = -ENOMEM; - goto err_release; - } - - i2c->base = ioremap(r->start, resource_size(r)); - if (!i2c->base) { - ret = -ENOMEM; - goto err_free; - } + i2c->base = devm_ioremap_resource(&dev->dev, r); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); writel(SCL | SDA, i2c->base + I2C_CONTROLS); @@ -105,18 +91,12 @@ static int i2c_versatile_probe(struct platform_device *dev) i2c->adap.nr = dev->id; ret = i2c_bit_add_numbered_bus(&i2c->adap); - if (ret >= 0) { - platform_set_drvdata(dev, i2c); - return 0; - } - - iounmap(i2c->base); - err_free: - kfree(i2c); - err_release: - release_mem_region(r->start, resource_size(r)); - err_out: - return ret; + if (ret < 0) + return ret; + + platform_set_drvdata(dev, i2c); + + return 0; } static int i2c_versatile_remove(struct platform_device *dev) diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index e1e3a85596c5..fbd0fd59f312 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -432,10 +432,8 @@ static int wmt_i2c_probe(struct platform_device *pdev) } err = i2c_add_adapter(adap); - if (err) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (err) return err; - } platform_set_drvdata(pdev, i2c_dev); diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 4233f5695352..263685c7a512 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -418,7 +418,6 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) 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; } diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 74f54f2f471f..66bce3b311a1 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -804,7 +804,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); xiic_deinit(i2c); goto err_clk_dis; } diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index c941418f06f5..2a972ed7aa0d 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -6,6 +6,7 @@ * warranty of any kind, whether express or implied. */ +#include <linux/acpi.h> #include <linux/completion.h> #include <linux/i2c.h> #include <linux/init.h> @@ -341,11 +342,10 @@ static struct i2c_algorithm xlp9xx_i2c_algo = { static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, struct xlp9xx_i2c_dev *priv) { - struct device_node *np = pdev->dev.of_node; u32 freq; int err; - err = of_property_read_u32(np, "clock-frequency", &freq); + err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); if (err) { freq = XLP9XX_I2C_DEFAULT_FREQ; dev_dbg(&pdev->dev, "using default frequency %u\n", freq); @@ -400,10 +400,8 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adapter, priv); err = i2c_add_adapter(&priv->adapter); - if (err) { - dev_err(&pdev->dev, "failed to add I2C adapter!\n"); + if (err) return err; - } platform_set_drvdata(pdev, priv); dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); @@ -429,12 +427,21 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = { { /* sentinel */ }, }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { + {"BRCM9007", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); +#endif + static struct platform_driver xlp9xx_i2c_driver = { .probe = xlp9xx_i2c_probe, .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", .of_match_table = xlp9xx_i2c_of_match, + .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), }, }; diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index 613c3a4f2c51..0968f59b6df5 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -432,10 +432,8 @@ static int xlr_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); ret = i2c_add_numbered_adapter(&priv->adap); - if (ret < 0) { - dev_err(&priv->adap.dev, "Failed to add i2c bus.\n"); + if (ret < 0) return ret; - } platform_set_drvdata(pdev, priv); dev_info(&priv->adap.dev, "Added I2C Bus.\n"); diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index e33022e2d459..6e5fac6a5262 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -56,9 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. */ -int __init -i2c_register_board_info(int busnum, - struct i2c_board_info const *info, unsigned len) +int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ed7002dd9401..5ab67219f71e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,8 @@ I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com> */ +#define pr_fmt(fmt) "i2c-core: " fmt + #include <dt-bindings/i2c/i2c.h> #include <asm/uaccess.h> #include <linux/acpi.h> @@ -86,7 +88,7 @@ void i2c_transfer_trace_unreg(void) } #if defined(CONFIG_ACPI) -struct acpi_i2c_handler_data { +struct i2c_acpi_handler_data { struct acpi_connection_info info; struct i2c_adapter *adapter; }; @@ -101,18 +103,20 @@ struct gsb_buffer { }; } __packed; -struct acpi_i2c_lookup { +struct i2c_acpi_lookup { struct i2c_board_info *info; acpi_handle adapter_handle; acpi_handle device_handle; + acpi_handle search_handle; + u32 speed; + u32 min_speed; }; -static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) +static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) { - struct acpi_i2c_lookup *lookup = data; + struct i2c_acpi_lookup *lookup = data; struct i2c_board_info *info = lookup->info; struct acpi_resource_i2c_serialbus *sb; - acpi_handle adapter_handle; acpi_status status; if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) @@ -122,95 +126,146 @@ static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) return 1; - /* - * 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; - } + &lookup->adapter_handle); + if (!ACPI_SUCCESS(status)) + return 1; + + info->addr = sb->slave_address; + lookup->speed = sb->connection_speed; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; return 1; } -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) +static int i2c_acpi_do_lookup(struct acpi_device *adev, + struct i2c_acpi_lookup *lookup) { - struct i2c_adapter *adapter = data; + struct i2c_board_info *info = lookup->info; 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; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - if (acpi_bus_get_status(adev) || !adev->status.present) - return AE_OK; - - memset(&info, 0, sizeof(info)); - info.fwnode = acpi_fwnode_handle(adev); + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) + return -EINVAL; - memset(&lookup, 0, sizeof(lookup)); - lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); - lookup.device_handle = handle; - lookup.info = &info; + memset(info, 0, sizeof(*info)); + lookup->device_handle = acpi_device_handle(adev); - /* - * Look up for I2cSerialBus resource with ResourceSource that - * matches with this adapter. - */ + /* Look up for I2cSerialBus resource */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_find_address, &lookup); + i2c_acpi_fill_info, lookup); acpi_dev_free_resource_list(&resource_list); - if (ret < 0 || !info.addr) - return AE_OK; + if (ret < 0 || !info->addr) + return -EINVAL; + + return 0; +} + +static int i2c_acpi_get_info(struct acpi_device *adev, + struct i2c_board_info *info, + struct i2c_adapter *adapter, + acpi_handle *adapter_handle) +{ + struct list_head resource_list; + struct resource_entry *entry; + struct i2c_acpi_lookup lookup; + int ret; + + memset(&lookup, 0, sizeof(lookup)); + lookup.info = info; + + ret = i2c_acpi_do_lookup(adev, &lookup); + if (ret) + return ret; + + if (adapter) { + /* The adapter must match the one in I2cSerialBus() connector */ + if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle) + return -ENODEV; + } else { + struct acpi_device *adapter_adev; + + /* The adapter must be present */ + if (acpi_bus_get_device(lookup.adapter_handle, &adapter_adev)) + return -ENODEV; + if (acpi_bus_get_status(adapter_adev) || + !adapter_adev->status.present) + return -ENODEV; + } + + info->fwnode = acpi_fwnode_handle(adev); + if (adapter_handle) + *adapter_handle = lookup.adapter_handle; /* Then fill IRQ number if any */ + INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (ret < 0) - return AE_OK; + return -EINVAL; resource_list_for_each_entry(entry, &resource_list) { if (resource_type(entry->res) == IORESOURCE_IRQ) { - info.irq = entry->res->start; + info->irq = entry->res->start; break; } } acpi_dev_free_resource_list(&resource_list); + strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type)); + + return 0; +} + +static void i2c_acpi_register_device(struct i2c_adapter *adapter, + struct acpi_device *adev, + struct i2c_board_info *info) +{ adev->power.flags.ignore_parent = true; - strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); - if (!i2c_new_device(adapter, &info)) { + acpi_device_set_enumerated(adev); + + if (!i2c_new_device(adapter, info)) { adev->power.flags.ignore_parent = false; dev_err(&adapter->dev, "failed to add I2C device %s from ACPI\n", dev_name(&adev->dev)); } +} + +static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct acpi_device *adev; + struct i2c_board_info info; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (i2c_acpi_get_info(adev, &info, adapter, NULL)) + return AE_OK; + + i2c_acpi_register_device(adapter, adev, &info); return AE_OK; } -#define ACPI_I2C_MAX_SCAN_DEPTH 32 +#define I2C_ACPI_MAX_SCAN_DEPTH 32 /** - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter * * Enumerate all I2C slave devices behind this adapter by walking the ACPI * namespace. When a device is found it will be added to the Linux device * model and bound to the corresponding ACPI handle. */ -static void acpi_i2c_register_devices(struct i2c_adapter *adap) +static void i2c_acpi_register_devices(struct i2c_adapter *adap) { acpi_status status; @@ -218,15 +273,145 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap) return; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_I2C_MAX_SCAN_DEPTH, - acpi_i2c_add_device, NULL, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_add_device, NULL, adap, NULL); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } +static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_acpi_lookup *lookup = data; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (i2c_acpi_do_lookup(adev, lookup)) + return AE_OK; + + if (lookup->search_handle != lookup->adapter_handle) + return AE_OK; + + if (lookup->speed <= lookup->min_speed) + lookup->min_speed = lookup->speed; + + return AE_OK; +} + +/** + * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI + * @dev: The device owning the bus + * + * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves + * devices connected to this bus and use the speed of slowest device. + * + * Returns the speed in Hz or zero + */ +u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + struct i2c_acpi_lookup lookup; + struct i2c_board_info dummy; + acpi_status status; + + if (!has_acpi_companion(dev)) + return 0; + + memset(&lookup, 0, sizeof(lookup)); + lookup.search_handle = ACPI_HANDLE(dev); + lookup.min_speed = UINT_MAX; + lookup.info = &dummy; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_lookup_speed, NULL, + &lookup, NULL); + + if (ACPI_FAILURE(status)) { + dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); + return 0; + } + + return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; +} +EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); + +static int i2c_acpi_match_adapter(struct device *dev, void *data) +{ + struct i2c_adapter *adapter = i2c_verify_adapter(dev); + + if (!adapter) + return 0; + + return ACPI_HANDLE(dev) == (acpi_handle)data; +} + +static int i2c_acpi_match_device(struct device *dev, void *data) +{ + return ACPI_COMPANION(dev) == data; +} + +static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, handle, + i2c_acpi_match_adapter); + return dev ? i2c_verify_adapter(dev) : NULL; +} + +static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, adev, i2c_acpi_match_device); + return dev ? i2c_verify_client(dev) : NULL; +} + +static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, + void *arg) +{ + struct acpi_device *adev = arg; + struct i2c_board_info info; + acpi_handle adapter_handle; + struct i2c_adapter *adapter; + struct i2c_client *client; + + switch (value) { + case ACPI_RECONFIG_DEVICE_ADD: + if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle)) + break; + + adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); + if (!adapter) + break; + + i2c_acpi_register_device(adapter, adev, &info); + break; + case ACPI_RECONFIG_DEVICE_REMOVE: + if (!acpi_device_enumerated(adev)) + break; + + client = i2c_acpi_find_client_by_adev(adev); + if (!client) + break; + + i2c_unregister_device(client); + put_device(&client->dev); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block i2c_acpi_notifier = { + .notifier_call = i2c_acpi_notify, +}; #else /* CONFIG_ACPI */ -static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } +extern struct notifier_block i2c_acpi_notifier; #endif /* CONFIG_ACPI */ #ifdef CONFIG_ACPI_I2C_OPREGION @@ -291,12 +476,12 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, } static acpi_status -acpi_i2c_space_handler(u32 function, acpi_physical_address command, +i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, void *handler_context, void *region_context) { struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct acpi_i2c_handler_data *data = handler_context; + struct i2c_acpi_handler_data *data = handler_context; struct acpi_connection_info *info = &data->info; struct acpi_resource_i2c_serialbus *sb; struct i2c_adapter *adapter = data->adapter; @@ -400,7 +585,8 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, break; default: - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); ret = AE_BAD_PARAMETER; goto err; } @@ -414,10 +600,10 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, } -static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -428,7 +614,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) if (!handle) return -ENODEV; - data = kzalloc(sizeof(struct acpi_i2c_handler_data), + data = kzalloc(sizeof(struct i2c_acpi_handler_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -442,7 +628,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler, + &i2c_acpi_space_handler, NULL, data); if (ACPI_FAILURE(status)) { @@ -456,10 +642,10 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) return 0; } -static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -472,7 +658,7 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler); + &i2c_acpi_space_handler); status = acpi_bus_get_private_data(handle, (void **)&data); if (ACPI_SUCCESS(status)) @@ -481,10 +667,10 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_bus_detach_private_data(handle); } #else /* CONFIG_ACPI_I2C_OPREGION */ -static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { } -static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { return 0; } #endif /* CONFIG_ACPI_I2C_OPREGION */ @@ -666,6 +852,47 @@ int i2c_recover_bus(struct i2c_adapter *adap) } EXPORT_SYMBOL_GPL(i2c_recover_bus); +static void i2c_init_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + char *err_str; + + if (!bri) + return; + + if (!bri->recover_bus) { + err_str = "no recover_bus() found"; + goto err; + } + + /* Generic GPIO recovery */ + if (bri->recover_bus == i2c_generic_gpio_recovery) { + if (!gpio_is_valid(bri->scl_gpio)) { + err_str = "invalid SCL gpio"; + goto err; + } + + if (gpio_is_valid(bri->sda_gpio)) + bri->get_sda = get_sda_gpio_value; + else + bri->get_sda = NULL; + + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + } else if (bri->recover_bus == i2c_generic_scl_recovery) { + /* Generic SCL recovery */ + if (!bri->set_scl || !bri->get_scl) { + err_str = "no {get|set}_scl() found"; + goto err; + } + } + + return; + err: + dev_err(&adap->dev, "Not using recovery: %s\n", err_str); + adap->bus_recovery_info = NULL; +} + static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -716,7 +943,7 @@ static int i2c_device_probe(struct device *dev) status = 0; if (status) - dev_warn(&client->dev, "failed to set up wakeup irq"); + dev_warn(&client->dev, "failed to set up wakeup irq\n"); } dev_dbg(dev, "probe\n"); @@ -1071,8 +1298,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) return client; out_err: - dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, status); + dev_err(&adap->dev, + "Failed to register i2c client %s at 0x%02x (%d)\n", + client->name, client->addr, status); out_err_silent: kfree(client); return NULL; @@ -1089,6 +1317,8 @@ void i2c_unregister_device(struct i2c_client *client) { if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); + if (ACPI_COMPANION(&client->dev)) + acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1145,6 +1375,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) } EXPORT_SYMBOL_GPL(i2c_new_dummy); +/** + * i2c_new_secondary_device - Helper to get the instantiated secondary address + * and create the associated device + * @client: Handle to the primary client + * @name: Handle to specify which secondary address to get + * @default_addr: Used as a fallback if no secondary address was specified + * Context: can sleep + * + * I2C clients can be composed of multiple I2C slaves bound together in a single + * component. The I2C client driver then binds to the master I2C slave and needs + * to create I2C dummy clients to communicate with all the other slaves. + * + * This function creates and returns an I2C dummy client whose I2C address is + * retrieved from the platform firmware based on the given slave name. If no + * address is specified by the firmware default_addr is used. + * + * On DT-based platforms the address is retrieved from the "reg" property entry + * cell whose "reg-names" value matches the slave name. + * + * This returns the new i2c client, which should be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client *i2c_new_secondary_device(struct i2c_client *client, + const char *name, + u16 default_addr) +{ + struct device_node *np = client->dev.of_node; + u32 addr = default_addr; + int i; + + if (np) { + i = of_property_match_string(np, "reg-names", name); + if (i >= 0) + of_property_read_u32_index(np, "reg", i, &addr); + } + + dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); + return i2c_new_dummy(client->adapter, addr); +} +EXPORT_SYMBOL_GPL(i2c_new_secondary_device); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -1155,21 +1426,19 @@ static void i2c_adapter_dev_release(struct device *dev) complete(&adap->dev_released); } -/* - * This function is only needed for mutex_lock_nested, so it is never - * called unless locking correctness checking is enabled. Thus we - * make it inline to avoid a compiler warning. That's what gcc ends up - * doing anyway. - */ -static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) +unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) { unsigned int depth = 0; while ((adapter = i2c_parent_is_i2c_adapter(adapter))) depth++; + WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES, + "adapter depth exceeds lockdep subclass limit\n"); + return depth; } +EXPORT_SYMBOL_GPL(i2c_adapter_depth); /* * Let users instantiate I2C devices through sysfs. This can be used when @@ -1504,8 +1773,8 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, if (driver->attach_adapter) { dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", driver->driver.name); - dev_warn(&adap->dev, "Please use another way to instantiate " - "your i2c_client\n"); + dev_warn(&adap->dev, + "Please use another way to instantiate your i2c_client\n"); /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } @@ -1517,9 +1786,15 @@ static int __process_new_adapter(struct device_driver *d, void *data) return i2c_do_add_adapter(to_i2c_driver(d), data); } +static const struct i2c_lock_operations i2c_adapter_lock_ops = { + .lock_bus = i2c_adapter_lock_bus, + .trylock_bus = i2c_adapter_trylock_bus, + .unlock_bus = i2c_adapter_unlock_bus, +}; + static int i2c_register_adapter(struct i2c_adapter *adap) { - int res = 0; + int res = -EINVAL; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) { @@ -1528,23 +1803,17 @@ static int i2c_register_adapter(struct i2c_adapter *adap) } /* Sanity checks */ - if (unlikely(adap->name[0] == '\0')) { - pr_err("i2c-core: Attempt to register an adapter with " - "no name!\n"); - return -EINVAL; - } - if (unlikely(!adap->algo)) { - pr_err("i2c-core: Attempt to register adapter '%s' with " - "no algo!\n", adap->name); - return -EINVAL; - } + if (WARN(!adap->name[0], "i2c adapter has no name")) + goto out_list; - if (!adap->lock_bus) { - adap->lock_bus = i2c_adapter_lock_bus; - adap->trylock_bus = i2c_adapter_trylock_bus; - adap->unlock_bus = i2c_adapter_unlock_bus; + if (!adap->algo) { + pr_err("adapter '%s': no algo supplied!\n", adap->name); + goto out_list; } + if (!adap->lock_ops) + adap->lock_ops = &i2c_adapter_lock_ops; + rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); mutex_init(&adap->userspace_clients_lock); @@ -1558,8 +1827,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); - if (res) + if (res) { + pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); goto out_list; + } dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); @@ -1575,45 +1846,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) "Failed to create compatibility class link\n"); #endif - /* bus recovery specific initialization */ - if (adap->bus_recovery_info) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + i2c_init_recovery(adap); - if (!bri->recover_bus) { - dev_err(&adap->dev, "No recover_bus() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - - bri->get_scl = get_scl_gpio_value; - bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { - /* Generic SCL recovery */ - if (!bri->set_scl || !bri->get_scl) { - dev_err(&adap->dev, "No {get|set}_scl() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - } - } - } - -exit_recovery: /* create pre-declared device nodes */ of_i2c_register_devices(adap); - acpi_i2c_register_devices(adap); - acpi_i2c_install_space_handler(adap); + i2c_acpi_register_devices(adap); + i2c_acpi_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -1641,13 +1879,12 @@ out_list: */ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) { - int id; + int id; mutex_lock(&core_lock); - id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, - GFP_KERNEL); + id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id == -ENOSPC ? -EBUSY : id; return i2c_register_adapter(adap); @@ -1684,7 +1921,7 @@ int i2c_add_adapter(struct i2c_adapter *adapter) id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id; adapter->nr = id; @@ -1782,12 +2019,11 @@ void i2c_del_adapter(struct i2c_adapter *adap) found = idr_find(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); if (found != adap) { - pr_debug("i2c-core: attempting to delete unregistered " - "adapter [%s]\n", adap->name); + pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name); return; } - acpi_i2c_remove_space_handler(adap); + i2c_acpi_remove_space_handler(adap); /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, @@ -1943,7 +2179,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); + pr_debug("driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ @@ -1970,7 +2206,7 @@ void i2c_del_driver(struct i2c_driver *driver) i2c_for_each_dev(driver, __process_removed_driver); driver_unregister(&driver->driver); - pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); + pr_debug("driver [%s] unregistered\n", driver->driver.name); } EXPORT_SYMBOL(i2c_del_driver); @@ -2061,8 +2297,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, put_device(&adap->dev); if (IS_ERR(client)) { - pr_err("%s: failed to create for '%s'\n", - __func__, rd->dn->full_name); + dev_err(&adap->dev, "failed to create client for '%s'\n", + rd->dn->full_name); return notifier_from_errno(PTR_ERR(client)); } break; @@ -2123,6 +2359,8 @@ static int __init i2c_init(void) if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); + if (IS_ENABLED(CONFIG_ACPI)) + WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier)); return 0; @@ -2138,6 +2376,8 @@ bus_err: static void __exit i2c_exit(void) { + if (IS_ENABLED(CONFIG_ACPI)) + WARN_ON(acpi_reconfig_notifier_unregister(&i2c_acpi_notifier)); if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); i2c_del_driver(&dummy_driver); @@ -2309,15 +2549,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (adap->algo->master_xfer) { #ifdef DEBUG for (ret = 0; ret < num; ret++) { - dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " - "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) - ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, + dev_dbg(&adap->dev, + "master_xfer[%d] %c, addr=0x%02x, len=%d%s\n", + ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W', + msgs[ret].addr, msgs[ret].len, (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif if (in_atomic() || irqs_disabled()) { - ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT); + ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; @@ -2477,9 +2718,9 @@ static int i2c_detect_address(struct i2c_client *temp_client, /* Consistency check */ if (info.type[0] == '\0') { - dev_err(&adapter->dev, "%s detection function provided " - "no name for 0x%x\n", driver->driver.name, - addr); + dev_err(&adapter->dev, + "%s detection function provided no name for 0x%x\n", + driver->driver.name, addr); } else { struct i2c_client *client; @@ -2517,9 +2758,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) /* Warn that the adapter lost class based instantiation */ if (adapter->class == I2C_CLASS_DEPRECATED) { dev_dbg(&adapter->dev, - "This adapter dropped support for I2C classes and " - "won't auto-detect %s devices anymore. If you need it, check " - "'Documentation/i2c/instantiating-devices' for alternatives.\n", + "This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. " + "If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n", driver->driver.name); return 0; } @@ -2535,8 +2775,9 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) temp_client->adapter = adapter; for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, address_list[i]); + dev_dbg(&adapter->dev, + "found normal entry for adapter %d, addr 0x%02x\n", + adap_id, address_list[i]); temp_client->addr = address_list[i]; err = i2c_detect_address(temp_client, driver); if (unlikely(err)) @@ -2568,15 +2809,16 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ 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]); + dev_warn(&adap->dev, "Invalid 7-bit address 0x%02x\n", + addr_list[i]); continue; } /* 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]); + dev_dbg(&adap->dev, + "Address 0x%02x already in use, not probing\n", + addr_list[i]); continue; } @@ -2679,7 +2921,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) cpec = i2c_smbus_msg_pec(cpec, msg); if (rpec != cpec) { - pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", + pr_debug("Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); return -EBADMSG; } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6ecfd76270f2..66f323fd3982 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -485,13 +485,8 @@ static int i2cdev_open(struct inode *inode, struct file *file) unsigned int minor = iminor(inode); struct i2c_client *client; struct i2c_adapter *adap; - struct i2c_dev *i2c_dev; - - i2c_dev = i2c_dev_get_by_minor(minor); - if (!i2c_dev) - return -ENODEV; - adap = i2c_get_adapter(i2c_dev->adap->nr); + adap = i2c_get_adapter(minor); if (!adap) return -ENODEV; diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 8eee98634cda..83768e85a919 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -159,7 +159,7 @@ static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) return 0; /* mux_lock not locked, failure */ if (!(flags & I2C_LOCK_ROOT_ADAPTER)) return 1; /* we only want mux_lock, success */ - if (parent->trylock_bus(parent, flags)) + if (i2c_trylock_bus(parent, flags)) return 1; /* parent locked too, success */ rt_mutex_unlock(&parent->mux_lock); return 0; /* parent not locked, failure */ @@ -193,7 +193,7 @@ static int i2c_parent_trylock_bus(struct i2c_adapter *adapter, if (!rt_mutex_trylock(&parent->mux_lock)) return 0; /* mux_lock not locked, failure */ - if (parent->trylock_bus(parent, flags)) + if (i2c_trylock_bus(parent, flags)) return 1; /* parent locked too, success */ rt_mutex_unlock(&parent->mux_lock); return 0; /* parent not locked, failure */ @@ -255,6 +255,10 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, muxc->dev = dev; if (flags & I2C_MUX_LOCKED) muxc->mux_locked = true; + if (flags & I2C_MUX_ARBITRATOR) + muxc->arbitrator = true; + if (flags & I2C_MUX_GATE) + muxc->gate = true; muxc->select = select; muxc->deselect = deselect; muxc->max_adapters = max_adapters; @@ -263,6 +267,18 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, } EXPORT_SYMBOL_GPL(i2c_mux_alloc); +static const struct i2c_lock_operations i2c_mux_lock_ops = { + .lock_bus = i2c_mux_lock_bus, + .trylock_bus = i2c_mux_trylock_bus, + .unlock_bus = i2c_mux_unlock_bus, +}; + +static const struct i2c_lock_operations i2c_parent_lock_ops = { + .lock_bus = i2c_parent_lock_bus, + .trylock_bus = i2c_parent_trylock_bus, + .unlock_bus = i2c_parent_unlock_bus, +}; + int i2c_mux_add_adapter(struct i2c_mux_core *muxc, u32 force_nr, u32 chan_id, unsigned int class) @@ -312,15 +328,10 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, priv->adap.retries = parent->retries; priv->adap.timeout = parent->timeout; priv->adap.quirks = parent->quirks; - if (muxc->mux_locked) { - priv->adap.lock_bus = i2c_mux_lock_bus; - priv->adap.trylock_bus = i2c_mux_trylock_bus; - priv->adap.unlock_bus = i2c_mux_unlock_bus; - } else { - priv->adap.lock_bus = i2c_parent_lock_bus; - priv->adap.trylock_bus = i2c_parent_trylock_bus; - priv->adap.unlock_bus = i2c_parent_unlock_bus; - } + if (muxc->mux_locked) + priv->adap.lock_ops = &i2c_mux_lock_ops; + else + priv->adap.lock_ops = &i2c_parent_lock_ops; /* Sanity check on class */ if (i2c_mux_parent_classes(parent) & class) @@ -335,18 +346,42 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, * nothing if !CONFIG_OF. */ if (muxc->dev->of_node) { - struct device_node *child; + struct device_node *dev_node = muxc->dev->of_node; + struct device_node *mux_node, *child = NULL; u32 reg; - for_each_child_of_node(muxc->dev->of_node, child) { - ret = of_property_read_u32(child, "reg", ®); - if (ret) - continue; - if (chan_id == reg) { - priv->adap.dev.of_node = child; - break; + if (muxc->arbitrator) + mux_node = of_get_child_by_name(dev_node, "i2c-arb"); + else if (muxc->gate) + mux_node = of_get_child_by_name(dev_node, "i2c-gate"); + else + mux_node = of_get_child_by_name(dev_node, "i2c-mux"); + + if (mux_node) { + /* A "reg" property indicates an old-style DT entry */ + if (!of_property_read_u32(mux_node, "reg", ®)) { + of_node_put(mux_node); + mux_node = NULL; + } + } + + if (!mux_node) + mux_node = of_node_get(dev_node); + else if (muxc->arbitrator || muxc->gate) + child = of_node_get(mux_node); + + if (!child) { + for_each_child_of_node(mux_node, child) { + ret = of_property_read_u32(child, "reg", ®); + if (ret) + continue; + if (chan_id == reg) + break; } } + + priv->adap.dev.of_node = child; + of_node_put(mux_node); } /* diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index abb55d3e76f3..b0d2679c60d1 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -33,7 +33,8 @@ struct i2c_smbus_alert { struct alert_data { unsigned short addr; - u8 flag:1; + enum i2c_alert_protocol type; + unsigned int data; }; /* If this is the alerting device, notify its driver */ @@ -56,7 +57,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); if (driver->alert) - driver->alert(client, data->flag); + driver->alert(client, data->type, data->data); else dev_warn(&client->dev, "no driver alert()!\n"); } else @@ -96,8 +97,9 @@ static void smbus_alert(struct work_struct *work) if (status < 0) break; - data.flag = status & 1; + data.data = status & 1; data.addr = status >> 1; + data.type = I2C_PROTOCOL_SMBUS_ALERT; if (data.addr == prev_addr) { dev_warn(&ara->dev, "Duplicate SMBALERT# from dev " @@ -105,7 +107,7 @@ static void smbus_alert(struct work_struct *work) break; } dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n", - data.addr, data.flag); + data.addr, data.data); /* Notify driver for the device which issued the alert */ device_for_each_child(&ara->adapter->dev, &data, @@ -239,6 +241,108 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) } EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); +static void smbus_host_notify_work(struct work_struct *work) +{ + struct alert_data alert; + struct i2c_adapter *adapter; + unsigned long flags; + u16 payload; + u8 addr; + struct smbus_host_notify *data; + + data = container_of(work, struct smbus_host_notify, work); + + spin_lock_irqsave(&data->lock, flags); + payload = data->payload; + addr = data->addr; + adapter = data->adapter; + + /* clear the pending bit and release the spinlock */ + data->pending = false; + spin_unlock_irqrestore(&data->lock, flags); + + if (!adapter || !addr) + return; + + alert.type = I2C_PROTOCOL_SMBUS_HOST_NOTIFY; + alert.addr = addr; + alert.data = payload; + + device_for_each_child(&adapter->dev, &alert, smbus_do_alert); +} + +/** + * i2c_setup_smbus_host_notify - Allocate a new smbus_host_notify for the given + * I2C adapter. + * @adapter: the adapter we want to associate a Host Notify function + * + * Returns a struct smbus_host_notify pointer on success, and NULL on failure. + * The resulting smbus_host_notify must not be freed afterwards, it is a + * managed resource already. + */ +struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap) +{ + struct smbus_host_notify *host_notify; + + host_notify = devm_kzalloc(&adap->dev, sizeof(struct smbus_host_notify), + GFP_KERNEL); + if (!host_notify) + return NULL; + + host_notify->adapter = adap; + + spin_lock_init(&host_notify->lock); + INIT_WORK(&host_notify->work, smbus_host_notify_work); + + return host_notify; +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify); + +/** + * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct + * I2C client. + * @host_notify: the struct host_notify attached to the relevant adapter + * @addr: the I2C address of the notifying device + * @data: the payload of the notification + * Context: can't sleep + * + * Helper function to be called from an I2C bus driver's interrupt + * handler. It will schedule the Host Notify work, in turn calling the + * corresponding I2C device driver's alert function. + * + * host_notify should be a valid pointer previously returned by + * i2c_setup_smbus_host_notify(). + */ +int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data) +{ + unsigned long flags; + struct i2c_adapter *adapter; + + if (!host_notify || !host_notify->adapter) + return -EINVAL; + + adapter = host_notify->adapter; + + spin_lock_irqsave(&host_notify->lock, flags); + + if (host_notify->pending) { + spin_unlock_irqrestore(&host_notify->lock, flags); + dev_warn(&adapter->dev, "Host Notify already scheduled.\n"); + return -EBUSY; + } + + host_notify->payload = data; + host_notify->addr = addr; + + /* Mark that there is a pending notification and release the lock */ + host_notify->pending = true; + spin_unlock_irqrestore(&host_notify->lock, flags); + + return schedule_work(&host_notify->work); +} +EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); + module_i2c_driver(smbalert_driver); MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index a90bbc4037dd..86fc2d4c081b 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -130,7 +130,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) return -EINVAL; } - muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0, + muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), I2C_MUX_ARBITRATOR, i2c_arbitrator_select, i2c_arbitrator_deselect); if (!muxc) return -ENOMEM; diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 8de073aed001..b3893f6282ba 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -37,8 +37,6 @@ struct i2c_demux_pinctrl_priv { struct i2c_demux_pinctrl_chan chan[]; }; -static struct property status_okay = { .name = "status", .length = 3, .value = "ok" }; - static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct i2c_demux_pinctrl_priv *priv = adap->algo_data; @@ -68,7 +66,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np); if (!adap) { ret = -ENODEV; - goto err; + goto err_with_revert; } p = devm_pinctrl_get_select(adap->dev.parent, priv->bus_name); @@ -103,8 +101,11 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne err_with_put: i2c_put_adapter(adap); + err_with_revert: + of_changeset_revert(&priv->chan[new_chan].chgset); err: dev_err(priv->dev, "failed to setup demux-adapter %d (%d)\n", new_chan, ret); + priv->cur_chan = -EINVAL; return ret; } @@ -190,6 +191,7 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct i2c_demux_pinctrl_priv *priv; + struct property *props; int num_chan, i, j, err; num_chan = of_count_phandle_with_args(np, "i2c-parent", NULL); @@ -200,7 +202,10 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + num_chan * sizeof(struct i2c_demux_pinctrl_chan), GFP_KERNEL); - if (!priv) + + props = devm_kcalloc(&pdev->dev, num_chan, sizeof(*props), GFP_KERNEL); + + if (!priv || !props) return -ENOMEM; err = of_property_read_string(np, "i2c-bus-name", &priv->bus_name); @@ -218,8 +223,12 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) } priv->chan[i].parent_np = adap_np; + props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL); + props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); + props[i].length = 3; + of_changeset_init(&priv->chan[i].chgset); - of_changeset_update_property(&priv->chan[i].chgset, adap_np, &status_okay); + of_changeset_update_property(&priv->chan[i].chgset, adap_np, &props[i]); } priv->num_chan = num_chan; diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 3cb8af635db5..4ea7e691afc7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -85,6 +85,13 @@ static const struct i2c_device_id pca9541_id[] = { MODULE_DEVICE_TABLE(i2c, pca9541_id); +#ifdef CONFIG_OF +static const struct of_device_id pca9541_of_match[] = { + { .compatible = "nxp,pca9541" }, + {} +}; +#endif + /* * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() * as they will try to lock the adapter a second time. @@ -349,7 +356,8 @@ static int pca9541_probe(struct i2c_client *client, force = 0; if (pdata) force = pdata->modes[0].adap_id; - muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0, + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, pca9541_select_chan, pca9541_release_chan); if (!muxc) return -ENOMEM; @@ -382,6 +390,7 @@ static int pca9541_remove(struct i2c_client *client) static struct i2c_driver pca9541_driver = { .driver = { .name = "pca9541", + .of_match_table = of_match_ptr(pca9541_of_match), }, .probe = pca9541_probe, .remove = pca9541_remove, diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 528e755c468f..1091346f2480 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -42,6 +42,7 @@ #include <linux/i2c/pca954x.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/pm.h> #include <linux/slab.h> @@ -58,14 +59,6 @@ enum pca_type { pca_9548, }; -struct pca954x { - enum pca_type type; - - u8 last_chan; /* last register value */ - u8 deselect; - struct i2c_client *client; -}; - struct chip_desc { u8 nchans; u8 enable; /* used for muxes only */ @@ -75,6 +68,14 @@ struct chip_desc { } muxtype; }; +struct pca954x { + const struct chip_desc *chip; + + u8 last_chan; /* last register value */ + u8 deselect; + struct i2c_client *client; +}; + /* Provide specs for the PCA954x types we know about */ static const struct chip_desc chips[] = { [pca_9540] = { @@ -119,6 +120,20 @@ static const struct i2c_device_id pca954x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca954x_id); +#ifdef CONFIG_OF +static const struct of_device_id pca954x_of_match[] = { + { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, + { .compatible = "nxp,pca9542", .data = &chips[pca_9542] }, + { .compatible = "nxp,pca9543", .data = &chips[pca_9543] }, + { .compatible = "nxp,pca9544", .data = &chips[pca_9544] }, + { .compatible = "nxp,pca9545", .data = &chips[pca_9545] }, + { .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, + { .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, + { .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, + {} +}; +#endif + /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() for this as they will try to lock adapter a second time */ static int pca954x_reg_write(struct i2c_adapter *adap, @@ -151,7 +166,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) { struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; - const struct chip_desc *chip = &chips[data->type]; + const struct chip_desc *chip = data->chip; u8 regval; int ret = 0; @@ -164,7 +179,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) /* Only select the channel if its different from the last channel */ if (data->last_chan != regval) { ret = pca954x_reg_write(muxc->parent, client, regval); - data->last_chan = regval; + data->last_chan = ret ? 0 : regval; } return ret; @@ -197,6 +212,7 @@ static int pca954x_probe(struct i2c_client *client, int num, force, class; struct i2c_mux_core *muxc; struct pca954x *data; + const struct of_device_id *match; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) @@ -226,14 +242,19 @@ static int pca954x_probe(struct i2c_client *client, return -ENODEV; } - data->type = id->driver_data; + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); + else + data->chip = &chips[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++) { + for (num = 0; num < data->chip->nchans; num++) { bool idle_disconnect_pd = false; force = 0; /* dynamic adap number */ @@ -263,7 +284,7 @@ static int pca954x_probe(struct i2c_client *client, dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", - num, chips[data->type].muxtype == pca954x_ismux + num, data->chip->muxtype == pca954x_ismux ? "mux" : "switch", client->name); return 0; @@ -299,6 +320,7 @@ static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", .pm = &pca954x_pm, + .of_match_table = of_match_ptr(pca954x_of_match), }, .probe = pca954x_probe, .remove = pca954x_remove, diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 6773cadf7c9f..c6a90b4a9c62 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -145,7 +145,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, mux->data.idle_in_use = true; /* map address from "reg" if exists */ - if (of_address_to_resource(np, 0, &res)) { + if (of_address_to_resource(np, 0, &res) == 0) { mux->data.reg_size = resource_size(&res); mux->data.reg = devm_ioremap_resource(&pdev->dev, &res); if (IS_ERR(mux->data.reg)) @@ -260,6 +260,7 @@ static struct platform_driver i2c_mux_reg_driver = { .remove = i2c_mux_reg_remove, .driver = { .name = "i2c-mux-reg", + .of_match_table = of_match_ptr(i2c_mux_reg_of_match), }, }; |