diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 10 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-master.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 63 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 36 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pca-platform.c | 34 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 61 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-qup.c | 1471 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-scmi.c | 35 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-stm32f4.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-synquacer.c | 667 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-xiic.c | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-xlp9xx.c | 78 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-base.c | 58 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-of.c | 30 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-smbus.c | 16 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.h | 1 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-pca954x.c | 55 |
20 files changed, 1880 insertions, 760 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4c0895165727..c4865b08d7fb 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -979,6 +979,16 @@ config I2C_SUN6I_P2WI This interface is used to connect to specific PMIC devices (like the AXP221). +config I2C_SYNQUACER + tristate "Socionext SynQuacer I2C controller" + depends on ARCH_SYNQUACER || COMPILE_TEST + help + Say Y here to include support for the I2C controller used in some + Fujitsu and Socionext SoCs. + + This driver can also be built as a module. If so, the module + will be called i2c-synquacer. + config I2C_TEGRA tristate "NVIDIA Tegra internal I2C controller" depends on ARCH_TEGRA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 9e475a54e36e..189e34ba050f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o +obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 05732531829f..fd36c39ddf4e 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -163,7 +163,7 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); - } else { + } else if (dev->sda_hold_time) { dev_warn(dev->dev, "Hardware too old to adjust SDA hold time.\n"); } diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index b02428498f6d..12ec8484e653 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -128,6 +128,10 @@ #define HSI2C_TIMEOUT_EN (1u << 31) #define HSI2C_TIMEOUT_MASK 0xff +/* I2C_MANUAL_CMD register bits */ +#define HSI2C_CMD_READ_DATA (1u << 4) +#define HSI2C_CMD_SEND_STOP (1u << 2) + /* I2C_TRANS_STATUS register bits */ #define HSI2C_MASTER_BUSY (1u << 17) #define HSI2C_SLAVE_BUSY (1u << 16) @@ -441,12 +445,6 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->state = -ETIMEDOUT; goto stop; } - - trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); - if ((trans_status & HSI2C_MASTER_ST_MASK) == HSI2C_MASTER_ST_LOSE) { - i2c->state = -EAGAIN; - goto stop; - } } else if (int_status & HSI2C_INT_I2C) { trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (trans_status & HSI2C_NO_DEV_ACK) { @@ -544,6 +542,57 @@ static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) return -EBUSY; } +static void exynos5_i2c_bus_recover(struct exynos5_i2c *i2c) +{ + u32 val; + + val = readl(i2c->regs + HSI2C_CTL) | HSI2C_RXCHON; + writel(val, i2c->regs + HSI2C_CTL); + val = readl(i2c->regs + HSI2C_CONF) & ~HSI2C_AUTO_MODE; + writel(val, i2c->regs + HSI2C_CONF); + + /* + * Specification says master should send nine clock pulses. It can be + * emulated by sending manual read command (nine pulses for read eight + * bits + one pulse for NACK). + */ + writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD); + exynos5_i2c_wait_bus_idle(i2c); + writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD); + exynos5_i2c_wait_bus_idle(i2c); + + val = readl(i2c->regs + HSI2C_CTL) & ~HSI2C_RXCHON; + writel(val, i2c->regs + HSI2C_CTL); + val = readl(i2c->regs + HSI2C_CONF) | HSI2C_AUTO_MODE; + writel(val, i2c->regs + HSI2C_CONF); +} + +static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) +{ + unsigned long timeout; + + if (i2c->variant->hw != HSI2C_EXYNOS7) + return; + + /* + * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction + * indicates that bus is stuck (SDA is low). In such case bus recovery + * can be performed. + */ + timeout = jiffies + msecs_to_jiffies(100); + for (;;) { + u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS); + + if ((st & HSI2C_MASTER_ST_MASK) != HSI2C_MASTER_ST_LOSE) + return; + + if (time_is_before_jiffies(timeout)) + return; + + exynos5_i2c_bus_recover(i2c); + } +} + /* * exynos5_i2c_message_start: Configures the bus and starts the xfer * i2c: struct exynos5_i2c pointer for the current bus @@ -598,6 +647,8 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL); writel(i2c_ctl, i2c->regs + HSI2C_CTL); + exynos5_i2c_bus_check(i2c); + /* * Enable interrupts before starting the transfer so that we don't * miss any INT_I2C interrupts. diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 999557729ad2..d7267dd9c7bf 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -194,6 +194,7 @@ struct imx_i2c_dma { struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; + struct notifier_block clk_change_nb; void __iomem *base; wait_queue_head_t queue; unsigned long i2csr; @@ -467,15 +468,14 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) return 0; } -static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) +static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, + unsigned int i2c_clk_rate) { struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; - unsigned int i2c_clk_rate; unsigned int div; int i; /* Divider value calculation */ - i2c_clk_rate = clk_get_rate(i2c_imx->clk); if (i2c_imx->cur_clk == i2c_clk_rate) return; @@ -510,6 +510,20 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) #endif } +static int i2c_imx_clk_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct clk_notifier_data *ndata = data; + struct imx_i2c_struct *i2c_imx = container_of(&ndata->clk, + struct imx_i2c_struct, + clk); + + if (action & POST_RATE_CHANGE) + i2c_imx_set_clk(i2c_imx, ndata->new_rate); + + return NOTIFY_OK; +} + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) { unsigned int temp = 0; @@ -517,8 +531,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); - i2c_imx_set_clk(i2c_imx); - imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); /* Enable I2C controller */ imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); @@ -1131,6 +1143,9 @@ static int i2c_imx_probe(struct platform_device *pdev) "clock-frequency", &i2c_imx->bitrate); if (ret < 0 && pdata && pdata->bitrate) i2c_imx->bitrate = pdata->bitrate; + i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call; + clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); + i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); /* Set up chip registers to defaults */ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, @@ -1141,12 +1156,12 @@ static int i2c_imx_probe(struct platform_device *pdev) 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; + goto clk_notifier_unregister; /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) - goto rpm_disable; + goto clk_notifier_unregister; pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); @@ -1162,6 +1177,8 @@ static int i2c_imx_probe(struct platform_device *pdev) return 0; /* Return OK */ +clk_notifier_unregister: + clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); rpm_disable: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1195,6 +1212,7 @@ static int i2c_imx_remove(struct platform_device *pdev) imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); + clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); clk_disable_unprepare(i2c_imx->clk); pm_runtime_put_noidle(&pdev->dev); @@ -1208,7 +1226,7 @@ static int i2c_imx_runtime_suspend(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); - clk_disable_unprepare(i2c_imx->clk); + clk_disable(i2c_imx->clk); return 0; } @@ -1218,7 +1236,7 @@ static int i2c_imx_runtime_resume(struct device *dev) struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(i2c_imx->clk); + ret = clk_enable(i2c_imx->clk); if (ret) dev_err(dev, "can't enable I2C clock, ret=%d\n", ret); diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 440fe4a96e68..a5a95ea5b81a 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -845,12 +845,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, */ if (of_device_is_compatible(np, "marvell,mv78230-i2c")) { drv_data->offload_enabled = true; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "marvell,mv78230-a0-i2c")) { drv_data->offload_enabled = false; - drv_data->errata_delay = true; + /* The delay is only needed in standard mode (100kHz) */ + if (bus_freq <= 100000) + drv_data->errata_delay = true; } if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c")) diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 853a2abedb05..bc2707ffd409 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -173,33 +173,19 @@ static int i2c_pca_pf_probe(struct platform_device *pdev) i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = np; + i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset-gpios", GPIOD_OUT_LOW); + if (IS_ERR(i2c->gpio)) + return PTR_ERR(i2c->gpio); + + i2c->adap.timeout = HZ; + ret = device_property_read_u32(&pdev->dev, "clock-frequency", + &i2c->algo_data.i2c_clock); + if (ret) + i2c->algo_data.i2c_clock = 59000; + if (platform_data) { i2c->adap.timeout = platform_data->timeout; i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed; - if (gpio_is_valid(platform_data->gpio)) { - ret = devm_gpio_request_one(&pdev->dev, - platform_data->gpio, - GPIOF_ACTIVE_LOW, - i2c->adap.name); - if (ret == 0) { - i2c->gpio = gpio_to_desc(platform_data->gpio); - gpiod_direction_output(i2c->gpio, 0); - } else { - dev_warn(&pdev->dev, "Registering gpio failed!\n"); - i2c->gpio = NULL; - } - } - } else if (np) { - i2c->adap.timeout = HZ; - i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset-gpios", GPIOD_OUT_LOW); - if (IS_ERR(i2c->gpio)) - return PTR_ERR(i2c->gpio); - of_property_read_u32_index(np, "clock-frequency", 0, - &i2c->algo_data.i2c_clock); - } else { - i2c->adap.timeout = HZ; - i2c->algo_data.i2c_clock = 59000; - i2c->gpio = NULL; } i2c->algo_data.data = i2c; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 462948e2c535..90946a8b9a75 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -40,7 +40,6 @@ #include <linux/dmi.h> #include <linux/acpi.h> #include <linux/io.h> -#include <linux/mutex.h> /* PIIX4 SMBus address offsets */ @@ -153,10 +152,7 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { /* * SB800 globals - * piix4_mutex_sb800 protects piix4_port_sel_sb800 and the pair - * of I/O ports at SB800_PIIX4_SMB_IDX. */ -static DEFINE_MUTEX(piix4_mutex_sb800); static u8 piix4_port_sel_sb800; static u8 piix4_port_mask_sb800; static u8 piix4_port_shift_sb800; @@ -298,12 +294,19 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, else smb_en = (aux) ? 0x28 : 0x2c; - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) { + dev_err(&PIIX4_dev->dev, + "SMB base address index region 0x%x already in use.\n", + SB800_PIIX4_SMB_IDX); + return -EBUSY; + } + outb_p(smb_en, SB800_PIIX4_SMB_IDX); smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX); smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1); - mutex_unlock(&piix4_mutex_sb800); + + release_region(SB800_PIIX4_SMB_IDX, 2); if (!smb_en) { smb_en_status = smba_en_lo & 0x10; @@ -373,7 +376,12 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, break; } } else { - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, + "sb800_piix4_smb")) { + release_region(piix4_smba, SMBIOSIZE); + return -EBUSY; + } + outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX); port_sel = inb_p(SB800_PIIX4_SMB_IDX + 1); piix4_port_sel_sb800 = (port_sel & 0x01) ? @@ -381,7 +389,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, SB800_PIIX4_PORT_IDX; piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK; piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT; - mutex_unlock(&piix4_mutex_sb800); + release_region(SB800_PIIX4_SMB_IDX, 2); } dev_info(&PIIX4_dev->dev, @@ -462,13 +470,13 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */ - msleep(2); + usleep_range(2000, 2100); else - msleep(1); + usleep_range(250, 500); while ((++timeout < MAX_TIMEOUT) && ((temp = inb_p(SMBHSTSTS)) & 0x01)) - msleep(1); + usleep_range(250, 500); /* If the SMBus is still busy, we give up */ if (timeout == MAX_TIMEOUT) { @@ -679,7 +687,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, u8 port; int retval; - mutex_lock(&piix4_mutex_sb800); + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) + return -EBUSY; /* Request the SMBUS semaphore, avoid conflicts with the IMC */ smbslvcnt = inb_p(SMBSLVCNT); @@ -695,8 +704,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, } while (--retries); /* SMBus is still owned by the IMC, we give up */ if (!retries) { - mutex_unlock(&piix4_mutex_sb800); - return -EBUSY; + retval = -EBUSY; + goto release; } /* @@ -753,8 +762,8 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, if ((size == I2C_SMBUS_BLOCK_DATA) && adapdata->notify_imc) piix4_imc_wakeup(); - mutex_unlock(&piix4_mutex_sb800); - +release: + release_region(SB800_PIIX4_SMB_IDX, 2); return retval; } @@ -899,13 +908,6 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) bool notify_imc = false; is_sb800 = true; - if (!request_region(SB800_PIIX4_SMB_IDX, 2, "smba_idx")) { - dev_err(&dev->dev, - "SMBus base address index region 0x%x already in use!\n", - SB800_PIIX4_SMB_IDX); - return -EBUSY; - } - if (dev->vendor == PCI_VENDOR_ID_AMD && dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS) { u8 imc; @@ -922,20 +924,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) /* base address location etc changed in SB800 */ retval = piix4_setup_sb800(dev, id, 0); - if (retval < 0) { - release_region(SB800_PIIX4_SMB_IDX, 2); + if (retval < 0) return retval; - } /* * Try to register multiplexed main SMBus adapter, * give up if we can't */ retval = piix4_add_adapters_sb800(dev, retval, notify_imc); - if (retval < 0) { - release_region(SB800_PIIX4_SMB_IDX, 2); + if (retval < 0) return retval; - } } else { retval = piix4_setup(dev, id); if (retval < 0) @@ -983,11 +981,8 @@ static void piix4_adap_remove(struct i2c_adapter *adap) if (adapdata->smba) { i2c_del_adapter(adap); - if (adapdata->port == (0 << piix4_port_shift_sb800)) { + if (adapdata->port == (0 << piix4_port_shift_sb800)) release_region(adapdata->smba, SMBIOSIZE); - if (adapdata->sb800_main) - release_region(SB800_PIIX4_SMB_IDX, 2); - } kfree(adapdata); kfree(adap); } diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 08f8e0107642..904dfec7ab96 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1,17 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2013, 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2014, Sony Mobile Communications AB. * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <linux/acpi.h> @@ -73,8 +64,11 @@ #define QUP_IN_SVC_FLAG BIT(9) #define QUP_MX_OUTPUT_DONE BIT(10) #define QUP_MX_INPUT_DONE BIT(11) +#define OUT_BLOCK_WRITE_REQ BIT(12) +#define IN_BLOCK_READ_REQ BIT(13) /* I2C mini core related values */ +#define QUP_NO_INPUT BIT(7) #define QUP_CLOCK_AUTO_GATE BIT(13) #define I2C_MINI_CORE (2 << 8) #define I2C_N_VAL 15 @@ -113,6 +107,7 @@ #define QUP_TAG_V2_DATAWR 0x82 #define QUP_TAG_V2_DATAWR_STOP 0x83 #define QUP_TAG_V2_DATARD 0x85 +#define QUP_TAG_V2_DATARD_NACK 0x86 #define QUP_TAG_V2_DATARD_STOP 0x87 /* Status, Error flags */ @@ -127,23 +122,87 @@ #define ONE_BYTE 0x1 #define QUP_I2C_MX_CONFIG_DURING_RUN BIT(31) +/* Maximum transfer length for single DMA descriptor */ #define MX_TX_RX_LEN SZ_64K #define MX_BLOCKS (MX_TX_RX_LEN / QUP_READ_LIMIT) +/* Maximum transfer length for all DMA descriptors */ +#define MX_DMA_TX_RX_LEN (2 * MX_TX_RX_LEN) +#define MX_DMA_BLOCKS (MX_DMA_TX_RX_LEN / QUP_READ_LIMIT) -/* Max timeout in ms for 32k bytes */ -#define TOUT_MAX 300 +/* + * Minimum transfer timeout for i2c transfers in seconds. It will be added on + * the top of maximum transfer time calculated from i2c bus speed to compensate + * the overheads. + */ +#define TOUT_MIN 2 /* Default values. Use these if FW query fails */ #define DEFAULT_CLK_FREQ 100000 #define DEFAULT_SRC_CLK 20000000 +/* + * Max tags length (start, stop and maximum 2 bytes address) for each QUP + * data transfer + */ +#define QUP_MAX_TAGS_LEN 4 +/* Max data length for each DATARD tags */ +#define RECV_MAX_DATA_LEN 254 +/* TAG length for DATA READ in RX FIFO */ +#define READ_RX_TAGS_LEN 2 + +/* + * count: no of blocks + * pos: current block number + * tx_tag_len: tx tag length for current block + * rx_tag_len: rx tag length for current block + * data_len: remaining data length for current message + * cur_blk_len: data length for current block + * total_tx_len: total tx length including tag bytes for current QUP transfer + * total_rx_len: total rx length including tag bytes for current QUP transfer + * tx_fifo_data_pos: current byte number in TX FIFO word + * tx_fifo_free: number of free bytes in current QUP block write. + * rx_fifo_data_pos: current byte number in RX FIFO word + * fifo_available: number of available bytes in RX FIFO for current + * QUP block read + * tx_fifo_data: QUP TX FIFO write works on word basis (4 bytes). New byte write + * to TX FIFO will be appended in this data and will be written to + * TX FIFO when all the 4 bytes are available. + * rx_fifo_data: QUP RX FIFO read works on word basis (4 bytes). This will + * contains the 4 bytes of RX data. + * cur_data: pointer to tell cur data position for current message + * cur_tx_tags: pointer to tell cur position in tags + * tx_tags_sent: all tx tag bytes have been written in FIFO word + * send_last_word: for tx FIFO, last word send is pending in current block + * rx_bytes_read: if all the bytes have been read from rx FIFO. + * rx_tags_fetched: all the rx tag bytes have been fetched from rx fifo word + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non BAM xfer. + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non BAM xfer. + * tags: contains tx tag bytes for current QUP transfer + */ struct qup_i2c_block { - int count; - int pos; - int tx_tag_len; - int rx_tag_len; - int data_len; - u8 tags[6]; + int count; + int pos; + int tx_tag_len; + int rx_tag_len; + int data_len; + int cur_blk_len; + int total_tx_len; + int total_rx_len; + int tx_fifo_data_pos; + int tx_fifo_free; + int rx_fifo_data_pos; + int fifo_available; + u32 tx_fifo_data; + u32 rx_fifo_data; + u8 *cur_data; + u8 *cur_tx_tags; + bool tx_tags_sent; + bool send_last_word; + bool rx_tags_fetched; + bool rx_bytes_read; + bool is_tx_blk_mode; + bool is_rx_blk_mode; + u8 tags[6]; }; struct qup_i2c_tag { @@ -155,6 +214,7 @@ struct qup_i2c_bam { struct qup_i2c_tag tag; struct dma_chan *dma; struct scatterlist *sg; + unsigned int sg_cnt; }; struct qup_i2c_dev { @@ -171,7 +231,9 @@ struct qup_i2c_dev { int out_blk_sz; int in_blk_sz; + int blk_xfer_limit; unsigned long one_byte_t; + unsigned long xfer_timeout; struct qup_i2c_block blk; struct i2c_msg *msg; @@ -184,23 +246,37 @@ struct qup_i2c_dev { /* To check if this is the last msg */ bool is_last; + bool is_smbus_read; /* To configure when bus is in run state */ - int config_run; + u32 config_run; /* dma parameters */ bool is_dma; + /* To check if the current transfer is using DMA */ + bool use_dma; + unsigned int max_xfer_sg_len; + unsigned int tag_buf_pos; + /* The threshold length above which block mode will be used */ + unsigned int blk_mode_threshold; struct dma_pool *dpool; struct qup_i2c_tag start_tag; struct qup_i2c_bam brx; struct qup_i2c_bam btx; struct completion xfer; + /* function to write data in tx fifo */ + void (*write_tx_fifo)(struct qup_i2c_dev *qup); + /* function to read data from rx fifo */ + void (*read_rx_fifo)(struct qup_i2c_dev *qup); + /* function to write tags in tx fifo for i2c read transfer */ + void (*write_rx_tags)(struct qup_i2c_dev *qup); }; static irqreturn_t qup_i2c_interrupt(int irq, void *dev) { struct qup_i2c_dev *qup = dev; + struct qup_i2c_block *blk = &qup->blk; u32 bus_err; u32 qup_err; u32 opflags; @@ -226,17 +302,65 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) if (bus_err) writel(bus_err, qup->base + QUP_I2C_STATUS); + /* + * Check for BAM mode and returns if already error has come for current + * transfer. In Error case, sometimes, QUP generates more than one + * interrupt. + */ + if (qup->use_dma && (qup->qup_err || qup->bus_err)) + return IRQ_HANDLED; + /* Reset the QUP State in case of error */ if (qup_err || bus_err) { - writel(QUP_RESET_STATE, qup->base + QUP_STATE); + /* + * Don’t reset the QUP state in case of BAM mode. The BAM + * flush operation needs to be scheduled in transfer function + * which will clear the remaining schedule descriptors in BAM + * HW FIFO and generates the BAM interrupt. + */ + if (!qup->use_dma) + writel(QUP_RESET_STATE, qup->base + QUP_STATE); goto done; } - if (opflags & QUP_IN_SVC_FLAG) + if (opflags & QUP_OUT_SVC_FLAG) { + writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + + if (opflags & OUT_BLOCK_WRITE_REQ) { + blk->tx_fifo_free += qup->out_blk_sz; + if (qup->msg->flags & I2C_M_RD) + qup->write_rx_tags(qup); + else + qup->write_tx_fifo(qup); + } + } + + if (opflags & QUP_IN_SVC_FLAG) { writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL); - if (opflags & QUP_OUT_SVC_FLAG) - writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); + if (!blk->is_rx_blk_mode) { + blk->fifo_available += qup->in_fifo_sz; + qup->read_rx_fifo(qup); + } else if (opflags & IN_BLOCK_READ_REQ) { + blk->fifo_available += qup->in_blk_sz; + qup->read_rx_fifo(qup); + } + } + + if (qup->msg->flags & I2C_M_RD) { + if (!blk->rx_bytes_read) + return IRQ_HANDLED; + } else { + /* + * Ideally, QUP_MAX_OUTPUT_DONE_FLAG should be checked + * for FIFO mode also. But, QUP_MAX_OUTPUT_DONE_FLAG lags + * behind QUP_OUTPUT_SERVICE_FLAG sometimes. The only reason + * of interrupt for write message in FIFO mode is + * QUP_MAX_OUTPUT_DONE_FLAG condition. + */ + if (blk->is_tx_blk_mode && !(opflags & QUP_MX_OUTPUT_DONE)) + return IRQ_HANDLED; + } done: qup->qup_err = qup_err; @@ -303,147 +427,47 @@ static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state) return 0; } -/** - * qup_i2c_wait_ready - wait for a give number of bytes in tx/rx path - * @qup: The qup_i2c_dev device - * @op: The bit/event to wait on - * @val: value of the bit to wait on, 0 or 1 - * @len: The length the bytes to be transferred - */ -static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, - int len) +/* Check if I2C bus returns to IDLE state */ +static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) { unsigned long timeout; - 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 */ timeout = jiffies + len * 4; - for (;;) { - opflags = readl(qup->base + QUP_OPERATIONAL); status = readl(qup->base + QUP_I2C_STATUS); + if (!(status & I2C_STATUS_BUS_ACTIVE)) + break; - if (((opflags & op) >> shift) == val) { - if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { - if (!(status & I2C_STATUS_BUS_ACTIVE)) { - ret = 0; - goto done; - } - } else { - ret = 0; - goto done; - } - } - - if (time_after(jiffies, timeout)) { + 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, - struct i2c_msg *msg) -{ - /* Number of entries to shift out, including the tags */ - int total = msg->len + qup->blk.tx_tag_len; - - total |= qup->config_run; - - if (total < qup->out_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_WRITE_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_OUTPUT_CNT); - } -} - -static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg) -{ - /* Number of entries to shift out, including the start */ - int total = msg->len + 1; - - if (total < qup->out_fifo_sz) { - /* FIFO mode */ - writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_WRITE_CNT); - } else { - /* BLOCK mode (transfer data on chunks) */ - writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN, - qup->base + QUP_IO_MODE); - writel(total, qup->base + QUP_MX_OUTPUT_CNT); - } -} - -static int check_for_fifo_space(struct qup_i2c_dev *qup) -{ - int ret; - - ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); - if (ret) - goto out; - - ret = qup_i2c_wait_ready(qup, QUP_OUT_FULL, - RESET_BIT, 4 * ONE_BYTE); - if (ret) { - /* Fifo is full. Drain out the fifo */ - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - if (ret) - goto out; - ret = qup_i2c_wait_ready(qup, QUP_OUT_NOT_EMPTY, - RESET_BIT, 256 * ONE_BYTE); - if (ret) { - dev_err(qup->dev, "timeout for fifo out full"); - goto out; - } - - ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE); - if (ret) - goto out; + usleep_range(len, len * 2); } -out: return ret; } -static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) +static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) { + struct qup_i2c_block *blk = &qup->blk; + struct i2c_msg *msg = qup->msg; u32 addr = msg->addr << 1; u32 qup_tag; int idx; u32 val; - int ret = 0; if (qup->pos == 0) { val = QUP_TAG_START | addr; idx = 1; + blk->tx_fifo_free--; } else { val = 0; idx = 0; } - while (qup->pos < msg->len) { - /* Check that there's space in the FIFO for our pair */ - ret = check_for_fifo_space(qup); - if (ret) - return ret; - + while (blk->tx_fifo_free && qup->pos < msg->len) { if (qup->pos == msg->len - 1) qup_tag = QUP_TAG_STOP; else @@ -460,70 +484,24 @@ static int qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg) qup->pos++; idx++; + blk->tx_fifo_free--; } - - ret = qup_i2c_change_state(qup, QUP_RUN_STATE); - - return ret; } static void qup_i2c_set_blk_data(struct qup_i2c_dev *qup, struct i2c_msg *msg) { - memset(&qup->blk, 0, sizeof(qup->blk)); - + qup->blk.pos = 0; qup->blk.data_len = msg->len; - qup->blk.count = (msg->len + QUP_READ_LIMIT - 1) / QUP_READ_LIMIT; - - /* 4 bytes for first block and 2 writes for rest */ |