diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-16 06:10:39 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-16 06:10:39 +0200 |
commit | 273cbf61c3ddee9574ef1f4959b9bc6db5b24271 (patch) | |
tree | 1eb8a54d416453ad7c6adbf57ab05dce2587a012 /drivers | |
parent | Merge tag 'for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/lin... (diff) | |
parent | i2c: mt7621: Fix platform_no_drv_owner.cocci warnings (diff) | |
download | linux-273cbf61c3ddee9574ef1f4959b9bc6db5b24271.tar.xz linux-273cbf61c3ddee9574ef1f4959b9bc6db5b24271.zip |
Merge branch 'i2c/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"New stuff from the I2C world:
- in the core, getting irqs from ACPI is now similar to OF
- new driver for MediaTek MT7621/7628/7688 SoCs
- bcm2835, i801, and tegra drivers got some more attention
- GPIO API cleanups
- cleanups in the core headers
- lots of usual driver updates"
* 'i2c/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (74 commits)
i2c: mt7621: Fix platform_no_drv_owner.cocci warnings
i2c: cpm: remove casting dma_alloc
dt-bindings: i2c: sun6i-p2wi: Fix the binding example
dt-bindings: i2c: mv64xxx: Fix the example compatible
i2c: i801: Documentation update
i2c: i801: Add support for Intel Tiger Lake
i2c: i801: Fix PCI ID sorting
dt-bindings: i2c-stm32: document optional dmas
i2c: i2c-stm32f7: Add I2C_SMBUS_I2C_BLOCK_DATA support
i2c: core: Tidy up handling of init_irq
i2c: core: Move ACPI gpio IRQ handling into i2c_acpi_get_irq
i2c: core: Move ACPI IRQ handling to probe time
i2c: acpi: Factor out getting the IRQ from ACPI
i2c: acpi: Use available IRQ helper functions
i2c: core: Allow whole core to use i2c_dev_irq_from_resources
eeprom: at24: modify a comment referring to platform data
dt-bindings: i2c: omap: Add new compatible for J721E SoCs
dt-bindings: i2c: mv64xxx: Add YAML schemas
dt-bindings: i2c: sun6i-p2wi: Add YAML schemas
i2c: mt7621: Add MediaTek MT7621/7628/7688 I2C driver
...
Diffstat (limited to 'drivers')
31 files changed, 1274 insertions, 473 deletions
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index e355c5961eb9..7390b5ca09e3 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -36,6 +36,7 @@ static int iop3xx_gpio_probe(struct platform_device *pdev) gc->base = 0; gc->owner = THIS_MODULE; + gc->label = "gpio-iop"; return devm_gpiochip_add_data(&pdev->dev, gc, NULL); } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ee5dfb5aee2a..09367fc014c3 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -143,6 +143,8 @@ config I2C_I801 Cedar Fork (PCH) Ice Lake (PCH) Comet Lake (PCH) + Elkhart Lake (PCH) + Tiger Lake (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -436,7 +438,7 @@ config I2C_AXXIA config I2C_BCM2835 tristate "Broadcom BCM2835 I2C controller" - depends on ARCH_BCM2835 + depends on ARCH_BCM2835 || ARCH_BRCMSTB help If you say yes to this option, support will be included for the BCM2835 I2C controller. @@ -692,7 +694,7 @@ config I2C_IOP3XX config I2C_JZ4780 tristate "JZ4780 I2C controller interface support" - depends on MACH_JZ4780 || COMPILE_TEST + depends on MIPS || COMPILE_TEST help If you say yes to this option, support will be included for the Ingenic JZ4780 I2C controller. @@ -746,6 +748,13 @@ config I2C_MT65XX If you want to use MediaTek(R) I2C interface, say Y or M here. If unsure, say N. +config I2C_MT7621 + tristate "MT7621/MT7628 I2C Controller" + depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || COMPILE_TEST + help + Say Y here to include support for I2C controller in the + MediaTek MT7621/MT7628 SoCs. + config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index a3245231b0b7..80c23895eaaf 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o +obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index a845b8decac8..2c7f145a036e 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -165,12 +165,6 @@ enum i2c_slave_read_status { I2C_SLAVE_RX_END, }; -enum i2c_slave_xfer_dir { - I2C_SLAVE_DIR_READ = 0, - I2C_SLAVE_DIR_WRITE, - I2C_SLAVE_DIR_NONE, -}; - enum bus_speed_index { I2C_SPD_100K = 0, I2C_SPD_400K, @@ -203,7 +197,6 @@ struct bcm_iproc_i2c_dev { struct i2c_msg *msg; struct i2c_client *slave; - enum i2c_slave_xfer_dir xfer_dir; /* bytes that have been transferred */ unsigned int tx_bytes; @@ -219,7 +212,8 @@ struct bcm_iproc_i2c_dev { | BIT(IS_M_RX_THLD_SHIFT)) #define ISR_MASK_SLAVE (BIT(IS_S_START_BUSY_SHIFT)\ - | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)) + | BIT(IS_S_RX_EVENT_SHIFT) | BIT(IS_S_RD_EVENT_SHIFT)\ + | BIT(IS_S_TX_UNDERRUN_SHIFT)) static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave); static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave); @@ -297,15 +291,11 @@ static void bcm_iproc_i2c_slave_init( /* clear all pending slave interrupts */ iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE); - /* Enable interrupt register for any READ event */ - val = BIT(IE_S_RD_EVENT_SHIFT); /* Enable interrupt register to indicate a valid byte in receive fifo */ - val |= BIT(IE_S_RX_EVENT_SHIFT); + val = BIT(IE_S_RX_EVENT_SHIFT); /* Enable interrupt register for the Slave BUSY command */ val |= BIT(IE_S_START_BUSY_SHIFT); iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); - - iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE; } static void bcm_iproc_i2c_check_slave_status( @@ -314,8 +304,11 @@ static void bcm_iproc_i2c_check_slave_status( u32 val; val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); - val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; + /* status is valid only when START_BUSY is cleared after it was set */ + if (val & BIT(S_CMD_START_BUSY_SHIFT)) + return; + val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; if (val == S_CMD_STATUS_TIMEOUT) { dev_err(iproc_i2c->device, "slave random stretch time timeout\n"); @@ -327,70 +320,66 @@ static void bcm_iproc_i2c_check_slave_status( } static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, - u32 status) + u32 status) { - u8 value; u32 val; - u32 rd_status; - u32 tmp; + u8 value, rx_status; - /* Start of transaction. check address and populate the direction */ - if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_NONE) { - tmp = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); - rd_status = (tmp >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK; - /* This condition checks whether the request is a new request */ - if (((rd_status == I2C_SLAVE_RX_START) && - (status & BIT(IS_S_RX_EVENT_SHIFT))) || - ((rd_status == I2C_SLAVE_RX_END) && - (status & BIT(IS_S_RD_EVENT_SHIFT)))) { - - /* Last bit is W/R bit. - * If 1 then its a read request(by master). - */ - iproc_i2c->xfer_dir = tmp & SLAVE_READ_WRITE_BIT_MASK; - if (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE) - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_REQUESTED, &value); - else - i2c_slave_event(iproc_i2c->slave, + /* Slave RX byte receive */ + if (status & BIT(IS_S_RX_EVENT_SHIFT)) { + val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); + rx_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK; + if (rx_status == I2C_SLAVE_RX_START) { + /* Start of SMBUS for Master write */ + i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_WRITE_REQUESTED, &value); - } - } - /* read request from master */ - if ((status & BIT(IS_S_RD_EVENT_SHIFT)) && - (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_WRITE)) { - i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_READ_PROCESSED, &value); - iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); + value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_WRITE_RECEIVED, &value); + } else if (status & BIT(IS_S_RD_EVENT_SHIFT)) { + /* Start of SMBUS for Master Read */ + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_READ_REQUESTED, &value); + iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); - val = BIT(S_CMD_START_BUSY_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); - } + val = BIT(S_CMD_START_BUSY_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); - /* write request from master */ - if ((status & BIT(IS_S_RX_EVENT_SHIFT)) && - (iproc_i2c->xfer_dir == I2C_SLAVE_DIR_READ)) { - val = iproc_i2c_rd_reg(iproc_i2c, S_RX_OFFSET); - /* Its a write request by Master to Slave. - * We read data present in receive FIFO - */ - value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); + /* + * Enable interrupt for TX FIFO becomes empty and + * less than PKT_LENGTH bytes were output on the SMBUS + */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val |= BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + } else { + /* Master write other than start */ + value = (u8)((val >> S_RX_DATA_SHIFT) & S_RX_DATA_MASK); + i2c_slave_event(iproc_i2c->slave, + I2C_SLAVE_WRITE_RECEIVED, &value); + } + } else if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { + /* Master read other than start */ i2c_slave_event(iproc_i2c->slave, - I2C_SLAVE_WRITE_RECEIVED, &value); - - /* check the status for the last byte of the transaction */ - rd_status = (val >> S_RX_STATUS_SHIFT) & S_RX_STATUS_MASK; - if (rd_status == I2C_SLAVE_RX_END) - iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE; + I2C_SLAVE_READ_PROCESSED, &value); - dev_dbg(iproc_i2c->device, "\nread value = 0x%x\n", value); + iproc_i2c_wr_reg(iproc_i2c, S_TX_OFFSET, value); + val = BIT(S_CMD_START_BUSY_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_CMD_OFFSET, val); } /* Stop */ if (status & BIT(IS_S_START_BUSY_SHIFT)) { i2c_slave_event(iproc_i2c->slave, I2C_SLAVE_STOP, &value); - iproc_i2c->xfer_dir = I2C_SLAVE_DIR_NONE; + /* + * Enable interrupt for TX FIFO becomes empty and + * less than PKT_LENGTH bytes were output on the SMBUS + */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); } /* clear interrupt status */ diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d2fbb4bb4a43..67752f7b0371 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -4,6 +4,8 @@ */ #include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> #include <linux/completion.h> #include <linux/err.h> #include <linux/i2c.h> @@ -51,9 +53,7 @@ struct bcm2835_i2c_dev { struct device *dev; void __iomem *regs; - struct clk *clk; int irq; - u32 bus_clk_rate; struct i2c_adapter adapter; struct completion completion; struct i2c_msg *curr_msg; @@ -74,12 +74,17 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) return readl(i2c_dev->regs + reg); } -static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) +#define to_clk_bcm2835_i2c(_hw) container_of(_hw, struct clk_bcm2835_i2c, hw) +struct clk_bcm2835_i2c { + struct clk_hw hw; + struct bcm2835_i2c_dev *i2c_dev; +}; + +static int clk_bcm2835_i2c_calc_divider(unsigned long rate, + unsigned long parent_rate) { - u32 divider, redl, fedl; + u32 divider = DIV_ROUND_UP(parent_rate, rate); - divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), - i2c_dev->bus_clk_rate); /* * Per the datasheet, the register is always interpreted as an even * number, by rounding down. In other words, the LSB is ignored. So, @@ -88,12 +93,23 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) if (divider & 1) divider++; if ((divider < BCM2835_I2C_CDIV_MIN) || - (divider > BCM2835_I2C_CDIV_MAX)) { - dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n"); + (divider > BCM2835_I2C_CDIV_MAX)) return -EINVAL; - } - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + return divider; +} + +static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw); + u32 redl, fedl; + u32 divider = clk_bcm2835_i2c_calc_divider(rate, parent_rate); + + if (divider == -EINVAL) + return -EINVAL; + + bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DIV, divider); /* * Number of core clocks to wait after falling edge before @@ -108,12 +124,65 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) */ redl = max(divider / 4, 1u); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL, + bcm2835_i2c_writel(div->i2c_dev, BCM2835_I2C_DEL, (fedl << BCM2835_I2C_FEDL_SHIFT) | (redl << BCM2835_I2C_REDL_SHIFT)); return 0; } +static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate); + + return DIV_ROUND_UP(*parent_rate, divider); +} + +static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_bcm2835_i2c *div = to_clk_bcm2835_i2c(hw); + u32 divider = bcm2835_i2c_readl(div->i2c_dev, BCM2835_I2C_DIV); + + return DIV_ROUND_UP(parent_rate, divider); +} + +static const struct clk_ops clk_bcm2835_i2c_ops = { + .set_rate = clk_bcm2835_i2c_set_rate, + .round_rate = clk_bcm2835_i2c_round_rate, + .recalc_rate = clk_bcm2835_i2c_recalc_rate, +}; + +static struct clk *bcm2835_i2c_register_div(struct device *dev, + struct clk *mclk, + struct bcm2835_i2c_dev *i2c_dev) +{ + struct clk_init_data init; + struct clk_bcm2835_i2c *priv; + char name[32]; + const char *mclk_name; + + snprintf(name, sizeof(name), "%s_div", dev_name(dev)); + + mclk_name = __clk_get_name(mclk); + + init.ops = &clk_bcm2835_i2c_ops; + init.name = name; + init.parent_names = (const char* []) { mclk_name }; + init.num_parents = 1; + init.flags = 0; + + priv = devm_kzalloc(dev, sizeof(struct clk_bcm2835_i2c), GFP_KERNEL); + if (priv == NULL) + return ERR_PTR(-ENOMEM); + + priv->hw.init = &init; + priv->i2c_dev = i2c_dev; + + clk_hw_register_clkdev(&priv->hw, "div", dev_name(dev)); + return devm_clk_register(dev, &priv->hw); +} + static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev) { u32 val; @@ -271,7 +340,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], { struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); unsigned long time_left; - int i, ret; + int i; for (i = 0; i < (num - 1); i++) if (msgs[i].flags & I2C_M_RD) { @@ -280,10 +349,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], return -EOPNOTSUPP; } - ret = bcm2835_i2c_set_divider(i2c_dev); - if (ret) - return ret; - i2c_dev->curr_msg = msgs; i2c_dev->num_msgs = num; reinit_completion(&i2c_dev->completion); @@ -338,6 +403,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) struct resource *mem, *irq; int ret; struct i2c_adapter *adap; + struct clk *bus_clk; + struct clk *mclk; + u32 bus_clk_rate; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) @@ -351,19 +419,38 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c_dev->regs)) return PTR_ERR(i2c_dev->regs); - i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c_dev->clk)) { - if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER) + mclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mclk)) { + if (PTR_ERR(mclk) != -EPROBE_DEFER) dev_err(&pdev->dev, "Could not get clock\n"); - return PTR_ERR(i2c_dev->clk); + return PTR_ERR(mclk); + } + + bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev); + + if (IS_ERR(bus_clk)) { + dev_err(&pdev->dev, "Could not register clock\n"); + return PTR_ERR(bus_clk); } ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &i2c_dev->bus_clk_rate); + &bus_clk_rate); if (ret < 0) { dev_warn(&pdev->dev, "Could not read clock-frequency property\n"); - i2c_dev->bus_clk_rate = 100000; + bus_clk_rate = 100000; + } + + ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate); + if (ret < 0) { + dev_err(&pdev->dev, "Could not set clock frequency\n"); + return ret; + } + + ret = clk_prepare_enable(bus_clk); + if (ret) { + dev_err(&pdev->dev, "Couldn't prepare clock"); + return ret; } irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -402,6 +489,10 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) static int bcm2835_i2c_remove(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div"); + + clk_rate_exclusive_put(bus_clk); + clk_disable_unprepare(bus_clk); free_irq(i2c_dev->irq, i2c_dev); i2c_del_adapter(&i2c_dev->adapter); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 187900594e3d..1213e1932ccb 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -531,7 +531,9 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm) } out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1)); - cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL); + cpm->txbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev, + CPM_MAX_READ + 1, + &cpm->txdma[i], GFP_KERNEL); if (!cpm->txbuf[i]) { ret = -ENOMEM; goto out_muram; diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index 1e2be2219a60..da5eb3960def 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -658,13 +658,29 @@ static const struct i2c_algorithm fsi_i2c_algorithm = { .functionality = fsi_i2c_functionality, }; +static struct device_node *fsi_i2c_find_port_of_node(struct device_node *fsi, + int port) +{ + struct device_node *np; + u32 port_no; + int rc; + + for_each_child_of_node(fsi, np) { + rc = of_property_read_u32(np, "reg", &port_no); + if (!rc && port_no == port) + return np; + } + + return NULL; +} + static int fsi_i2c_probe(struct device *dev) { struct fsi_i2c_master *i2c; struct fsi_i2c_port *port; struct device_node *np; + u32 port_no, ports, stat; int rc; - u32 port_no; i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) @@ -678,10 +694,16 @@ static int fsi_i2c_probe(struct device *dev) if (rc) return rc; - /* Add adapter for each i2c port of the master. */ - for_each_available_child_of_node(dev->of_node, np) { - rc = of_property_read_u32(np, "reg", &port_no); - if (rc || port_no > USHRT_MAX) + rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); + if (rc) + return rc; + + ports = FIELD_GET(I2C_STAT_MAX_PORT, stat) + 1; + dev_dbg(dev, "I2C master has %d ports\n", ports); + + for (port_no = 0; port_no < ports; port_no++) { + np = fsi_i2c_find_port_of_node(dev->of_node, port_no); + if (np && !of_device_is_available(np)) continue; port = kzalloc(sizeof(*port), GFP_KERNEL); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ac7f7817dc89..f2956936c3f2 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,12 +64,14 @@ * Cedar Fork (PCH) 0x18df 32 hard yes yes yes * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes * Comet Lake (PCH) 0x02a3 32 hard yes yes yes + * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes + * Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes * * Features supported by this driver: * Software PEC no * Hardware PEC yes * Block buffer yes - * Block process call transaction no + * Block process call transaction yes * I2C block read transaction yes (doesn't use the block buffer) * Slave mode no * SMBus Host Notify yes @@ -92,6 +94,7 @@ #include <linux/io.h> #include <linux/dmi.h> #include <linux/slab.h> +#include <linux/string.h> #include <linux/wait.h> #include <linux/err.h> #include <linux/platform_device.h> @@ -99,7 +102,7 @@ #include <linux/pm_runtime.h> #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -#include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/platform_data/i2c-mux-gpio.h> #endif @@ -169,6 +172,7 @@ #define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ +#define I801_BLOCK_PROC_CALL 0x1C /* I801 Host Control register bits */ #define SMBHSTCNT_INTREN BIT(0) @@ -200,6 +204,7 @@ STATUS_ERROR_FLAGS) /* Older devices have their ID defined in <linux/pci_ids.h> */ +#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 #define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df #define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df @@ -217,6 +222,7 @@ #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 #define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 @@ -228,12 +234,12 @@ #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 #define PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS 0x9da3 +#define PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS 0xa0a3 #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 #define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 -#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 struct i801_mux_config { char *gpio_chip; @@ -266,6 +272,7 @@ struct i801_priv { #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; + struct gpiod_lookup_table *lookup; #endif struct platform_device *tco_pdev; @@ -509,10 +516,23 @@ static int i801_transaction(struct i801_priv *priv, int xact) static int i801_block_transaction_by_block(struct i801_priv *priv, union i2c_smbus_data *data, - char read_write, int hwpec) + char read_write, int command, + int hwpec) { int i, len; int status; + int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; + + switch (command) { + case I2C_SMBUS_BLOCK_PROC_CALL: + xact |= I801_BLOCK_PROC_CALL; + break; + case I2C_SMBUS_BLOCK_DATA: + xact |= I801_BLOCK_DATA; + break; + default: + return -EOPNOTSUPP; + } inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ @@ -524,12 +544,12 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, outb_p(data->block[i+1], SMBBLKDAT(priv)); } - status = i801_transaction(priv, I801_BLOCK_DATA | - (hwpec ? SMBHSTCNT_PEC_EN : 0)); + status = i801_transaction(priv, xact); if (status) return status; - if (read_write == I2C_SMBUS_READ) { + if (read_write == I2C_SMBUS_READ || + command == I2C_SMBUS_BLOCK_PROC_CALL) { len = inb_p(SMBHSTDAT0(priv)); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) return -EPROTO; @@ -667,6 +687,9 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, int result; const struct i2c_adapter *adap = &priv->adapter; + if (command == I2C_SMBUS_BLOCK_PROC_CALL) + return -EOPNOTSUPP; + result = i801_check_pre(priv); if (result < 0) return result; @@ -798,7 +821,8 @@ static int i801_block_transaction(struct i801_priv *priv, && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0) result = i801_block_transaction_by_block(priv, data, - read_write, hwpec); + read_write, + command, hwpec); else result = i801_block_transaction_byte_by_byte(priv, data, read_write, @@ -890,6 +914,15 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, outb_p(command, SMBHSTCMD(priv)); block = 1; break; + case I2C_SMBUS_BLOCK_PROC_CALL: + /* + * Bit 0 of the slave address register always indicate a write + * command. + */ + outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); + block = 1; + break; default: dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", size); @@ -950,6 +983,8 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((priv->features & FEATURE_BLOCK_PROC) ? + I2C_FUNC_SMBUS_BLOCK_PROC_CALL : 0) | ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | ((priv->features & FEATURE_HOST_NOTIFY) ? @@ -1033,6 +1068,8 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, { 0, } }; @@ -1134,6 +1171,118 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) } } +/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ +static const char *const acpi_smo8800_ids[] = { + "SMO8800", + "SMO8801", + "SMO8810", + "SMO8811", + "SMO8820", + "SMO8821", + "SMO8830", + "SMO8831", +}; + +static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + struct acpi_device_info *info; + acpi_status status; + char *hid; + int i; + + status = acpi_get_object_info(obj_handle, &info); + if (!ACPI_SUCCESS(status) || !(info->valid & ACPI_VALID_HID)) + return AE_OK; + + hid = info->hardware_id.string; + if (!hid) + return AE_OK; + + i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); + if (i < 0) + return AE_OK; + + *((bool *)return_value) = true; + return AE_CTRL_TERMINATE; +} + +static bool is_dell_system_with_lis3lv02d(void) +{ + bool found; + const char *vendor; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (!vendor || strcmp(vendor, "Dell Inc.")) + return false; + + /* + * Check that ACPI device SMO88xx is present and is functioning. + * Function acpi_get_devices() already filters all ACPI devices + * which are not present or are not functioning. + * ACPI device SMO88xx represents our ST microelectronics lis3lv02d + * accelerometer but unfortunately ACPI does not provide any other + * information (like I2C address). + */ + found = false; + acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, + (void **)&found); + + return found; +} + +/* + * Accelerometer's I2C address is not specified in DMI nor ACPI, + * so it is needed to define mapping table based on DMI product names. + */ +static const struct { + const char *dmi_product_name; + unsigned short i2c_addr; +} dell_lis3lv02d_devices[] = { + /* + * Dell platform team told us that these Latitude devices have + * ST microelectronics accelerometer at I2C address 0x29. + */ + { "Latitude E5250", 0x29 }, + { "Latitude E5450", 0x29 }, + { "Latitude E5550", 0x29 }, + { "Latitude E6440", 0x29 }, + { "Latitude E6440 ATG", 0x29 }, + { "Latitude E6540", 0x29 }, + /* + * Additional individual entries were added after verification. + */ + { "Vostro V131", 0x1d }, +}; + +static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) +{ + struct i2c_board_info info; + const char *dmi_product_name; + int i; + + dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); + for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { + if (strcmp(dmi_product_name, + dell_lis3lv02d_devices[i].dmi_product_name) == 0) + break; + } + + if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { + dev_warn(&priv->pci_dev->dev, + "Accelerometer lis3lv02d is present on SMBus but its" + " address is unknown, skipping registration\n"); + return; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = dell_lis3lv02d_devices[i].i2c_addr; + strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE); + i2c_new_device(&priv->adapter, &info); +} + /* Register optional slaves */ static void i801_probe_optional_slaves(struct i801_priv *priv) { @@ -1152,6 +1301,9 @@ static void i801_probe_optional_slaves(struct i801_priv *priv) if (dmi_name_in_vendors("FUJITSU")) dmi_walk(dmi_check_onboard_devices, &priv->adapter); + + if (is_dell_system_with_lis3lv02d()) + register_dell_lis3lv02d_i2c_device(priv); } #else static void __init input_apanel_init(void) {} @@ -1250,7 +1402,8 @@ static int i801_add_mux(struct i801_priv *priv) struct device *dev = &priv->adapter.dev; const struct i801_mux_config *mux_config; struct i2c_mux_gpio_platform_data gpio_data; - int err; + struct gpiod_lookup_table *lookup; + int err, i; if (!priv->mux_drvdata) return 0; @@ -1262,17 +1415,36 @@ static int i801_add_mux(struct i801_priv *priv) gpio_data.values = mux_config->values; gpio_data.n_values = mux_config->n_values; gpio_data.classes = mux_config->classes; - gpio_data.gpio_chip = mux_config->gpio_chip; - gpio_data.gpios = mux_config->gpios; - gpio_data.n_gpios = mux_config->n_gpios; gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; - /* Register the mux device */ + /* Register GPIO descriptor lookup table */ + lookup = devm_kzalloc(dev, + struct_size(lookup, table, mux_config->n_gpios), + GFP_KERNEL); + if (!lookup) + return -ENOMEM; + lookup->dev_id = "i2c-mux-gpio"; + for (i = 0; i < mux_config->n_gpios; i++) { + lookup->table[i].chip_label = mux_config->gpio_chip; + lookup->table[i].chip_hwnum = mux_config->gpios[i]; + lookup->table[i].con_id = "mux"; + } + gpiod_add_lookup_table(lookup); + priv->lookup = lookup; + + /* + * Register the mux device, we use PLATFORM_DEVID_NONE here + * because since we are referring to the GPIO chip by name we are + * anyways in deep trouble if there is more than one of these + * devices, and there should likely only be one platform controller + * hub. + */ priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio", - PLATFORM_DEVID_AUTO, &gpio_data, + PLATFORM_DEVID_NONE, &gpio_data, sizeof(struct i2c_mux_gpio_platform_data)); if (IS_ERR(priv->mux_pdev)) { err = PTR_ERR(priv->mux_pdev); + gpiod_remove_lookup_table(lookup); priv->mux_pdev = NULL; dev_err(dev, "Failed to register i2c-mux-gpio device\n"); return err; @@ -1285,6 +1457,8 @@ static void i801_del_mux(struct i801_priv *priv) { if (priv->mux_pdev) platform_device_unregister(priv->mux_pdev); + if (priv->lookup) + gpiod_remove_lookup_table(priv->lookup); } static unsigned int i801_get_adapter_class(struct i801_priv *priv) @@ -1530,6 +1704,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: + case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: + priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; priv->features |= FEATURE_SMBUS_PEC; @@ -1549,6 +1726,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features |= FEATURE_IDF; /* fall through */ default: + priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; /* fall through */ diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index fd70b110e8f4..b1b8b938d7f4 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1220,8 +1220,7 @@ static int i2c_imx_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int i2c_imx_runtime_suspend(struct device *dev) +static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); @@ -1230,7 +1229,7 @@ static int i2c_imx_runtime_suspend(struct device *dev) return 0; } -static int i2c_imx_runtime_resume(struct device *dev) +static int __maybe_unused i2c_imx_runtime_resume(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); int ret; @@ -1246,17 +1245,13 @@ static const struct dev_pm_ops i2c_imx_pm_ops = { SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL) }; -#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops) -#else -#define I2C_IMX_PM_OPS NULL -#endif /* CONFIG_PM */ static struct platform_driver i2c_imx_driver = { .probe = i2c_imx_probe, .remove = i2c_imx_remove, .driver = { .name = DRIVER_NAME, - .pm = I2C_IMX_PM_OPS, + .pm = &i2c_imx_pm_ops, .of_match_table = i2c_imx_dt_ids, }, .id_table = imx_i2c_devtype, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 87ce788ab90c..38556381f4ca 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -35,7 +35,7 @@ #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include "i2c-iop3xx.h" @@ -68,17 +68,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap) /* * Every time unit enable is asserted, GPOD needs to be cleared - * on IOP3XX to avoid data corruption on the bus. + * on IOP3XX to avoid data corruption on the bus. We use the + * gpiod_set_raw_value() to make sure the 0 hits the hardware + * GPOD register. These descriptors are only passed along to + * the device if this is necessary. */ -#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X) - if (iop3xx_adap->id == 0) { - gpio_set_value(7, 0); - gpio_set_value(6, 0); - } else { - gpio_set_value(5, 0); - gpio_set_value(4, 0); - } -#endif + if (iop3xx_adap->gpio_scl) + gpiod_set_raw_value(iop3xx_adap->gpio_scl, 0); + if (iop3xx_adap->gpio_sda) + gpiod_set_raw_value(iop3xx_adap->gpio_sda, 0); + /* NB SR bits not same position as CR IE bits :-( */ iop3xx_adap->SR_enabled = IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD | @@ -431,6 +430,17 @@ iop3xx_i2c_probe(struct platform_device *pdev) goto free_adapter; } + adapter_data->gpio_scl = devm_gpiod_get_optional(&pdev->dev, + "scl", + GPIOD_ASIS); + if (IS_ERR(adapter_data->gpio_scl)) + return PTR_ERR(adapter_data->gpio_scl); + adapter_data->gpio_sda = devm_gpiod_get_optional(&pdev->dev, + "sda", + GPIOD_ASIS); + if (IS_ERR(adapter_data->gpio_sda)) + return PTR_ERR(adapter_data->gpio_sda); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENODEV; diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h index 53ca1fc9b84c..143548335504 100644 --- a/drivers/i2c/busses/i2c-iop3xx.h +++ b/drivers/i2c/busses/i2c-iop3xx.h @@ -92,6 +92,8 @@ struct i2c_algo_iop3xx_data { spinlock_t lock; u32 SR_enabled, SR_received; int id; + struct gpio_desc *gpio_scl; + struct gpio_desc *gpio_sda; }; #endif /* I2C_IOP3XX_H */ diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c new file mode 100644 index 000000000000..62df8379bc89 --- /dev/null +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/i2c/busses/i2c-mt7621.c + * + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> + * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> + * Copyright (C) 2018 Jan Breuer <jan.breuer@jaybee.cz> + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak <sittisaks@hotmail.com> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/reset.h> + +#define REG_SM0CFG2_REG 0x28 +#define REG_SM0CTL0_REG 0x40 +#define REG_SM0CTL1_REG 0x44 +#define REG_SM0D0_REG 0x50 +#define REG_SM0D1_REG 0x54 +#define REG_PINTEN_REG 0x5c +#define REG_PINTST_REG 0x60 +#define REG_PINTCL_REG 0x64 + +/* REG_SM0CFG2_REG */ +#define SM0CFG2_IS_AUTOMODE BIT(0) + +/* REG_SM0CTL0_REG */ +#define SM0CTL0_ODRAIN BIT(31) +#define SM0CTL0_CLK_DIV_MASK (0x7ff << 16) +#define SM0CTL0_CLK_DIV_MAX 0x7ff +#define SM0CTL0_CS_STATUS BIT(4) +#define SM0CTL0_SCL_STATE BIT(3) +#define SM0CTL0_SDA_STATE BIT(2) +#define SM0CTL0_EN BIT(1) +#define SM0CTL0_SCL_STRETCH BIT(0) + +/* REG_SM0CTL1_REG */ +#define SM0CTL1_ACK_MASK (0xff << 16) +#define SM0CTL1_PGLEN_MASK (0x7 << 8) +#define SM0CTL1_PGLEN(x) ((((x) - 1) << 8) & SM0CTL1_PGLEN_MASK) +#define SM0CTL1_READ (5 << 4) +#define SM0CTL1_READ_LAST (4 << 4) +#define SM0CTL1_STOP (3 << 4) +#define SM0CTL1_WRITE (2 << 4) +#define SM0CTL1_START (1 << 4) +#define SM0CTL1_MODE_MASK (0x7 << 4) +#define SM0CTL1_TRI BIT(0) + +/* timeout waiting for I2C devices to respond */ +#define TIMEOUT_MS 1000 + +struct mtk_i2c { + void __iomem *base; + struct device *dev; + struct i2c_adapter adap; + u32 bus_freq; + u32 clk_div; + u32 flags; + struct clk *clk; +}; + +static int mtk_i2c_wait_idle(struct mtk_i2c *i2c) +{ + int ret; + u32 val; + + ret = readl_relaxed_poll_timeout(i2c->base + REG_SM0CTL1_REG, + val, !(val & SM0CTL1_TRI), + 10, TIMEOUT_MS * 1000); + if (ret) + dev_dbg(i2c->dev, "idle err(%d)\n", ret); + + return ret; +} + +static void mtk_i2c_reset(struct mtk_i2c *i2c) +{ + int ret; + + ret = device_reset(i2c->adap.dev.parent); + if (ret) + dev_err(i2c->dev, "I2C reset failed!\n"); + + /* + * Don't set SM0CTL0_ODRAIN as its bit meaning is inverted. To + * configure open-drain mode, this bit needs to be cleared. + */ + iowrite32(((i2c->clk_div << 16) & SM0CTL0_CLK_DIV_MASK) | SM0CTL0_EN | + SM0CTL0_SCL_STRETCH, i2c->base + REG_SM0CTL0_REG); + iowrite32(0, i2c->base + REG_SM0CFG2_REG); +} + +static void mtk_i2c_dump_reg(struct mtk_i2c *i2c) +{ + dev_dbg(i2c->dev, + "SM0CFG2 %08x, SM0CTL0 %08x, SM0CTL1 %08x, SM0D0 %08x, SM0D1 %08x\n", + ioread32(i2c->base + REG_SM0CFG2_REG), + ioread32(i2c->base + REG_SM0CTL0_REG), + ioread32(i2c->base + REG_SM0CTL1_REG), + ioread32(i2c->base + REG_SM0D0_REG), + ioread32(i2c->base + REG_SM0D1_REG)); +} + +static int mtk_i2c_check_ack(struct mtk_i2c *i2c, u32 expected) +{ + u32 ack = readl_relaxed(i2c->base + REG_SM0CTL1_REG); + u32 ack_expected = (expected << 16) & SM0CTL1_ACK_MASK; + + return ((ack & ack_expected) == ack_expected) ? 0 : -ENXIO; +} + +static int mtk_i2c_master_start(struct mtk_i2c *i2c) +{ + iowrite32(SM0CTL1_START | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG); + return mtk_i2c_wait_idle(i2c); +} + +static int mtk_i2c_master_stop(struct mtk_i2c *i2c) +{ + iowrite32(SM0CTL1_STOP | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG); + return mtk_i2c_wait_idle(i2c); +} + +static int mtk_i2c_master_cmd(struct mtk_i2c *i2c, u32 cmd, int page_len) +{ + iowrite32(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(page_len), + i2c->base + REG_SM0CTL1_REG); + return mtk_i2c_wait_idle(i2c); +} + +static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct mtk_i2c *i2c; + struct i2c_msg *pmsg; + u16 addr; + int i, j, ret, len, page_len; + u32 cmd; + u32 data[2]; + + i2c = i2c_get_adapdata(adap); + + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + + /* wait hardware idle */ + ret = mtk_i2c_wait_idle(i2c); + if (ret) + goto err_timeout; + + /* start sequence */ + ret = mtk_i2c_master_start(i2c); + if (ret) + goto err_timeout; + + /* write address */ + if (pmsg->flags & I2C_M_TEN) { + /* 10 bits address */ + addr = 0xf0 | ((pmsg->addr >> 7) & 0x06); + addr |= (pmsg->addr & 0xff) << 8; + if (pmsg->flags & I2C_M_RD) + addr |= 1; + iowrite32(addr, i2c->base + REG_SM0D0_REG); + ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 2); + if (ret) + goto err_timeout; + } else { + /* 7 bits address */ + addr = i2c_8bit_addr_from_msg(pmsg); + iowrite32(addr, i2c->base + REG_SM0D0_REG); + ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 1); + if (ret) + goto err_timeout; + } + + /* check address ACK */ + if (!(pmsg->flags & I2C_M_IGNORE_NAK)) { + ret = mtk_i2c_check_ack(i2c, BIT(0)); + if (ret) + goto err_ack; + } + + /* transfer data */ + for (len = pmsg->len, j = 0; len > 0; len -= 8, j += 8) { + page_len = (len >= 8) ? 8 : len; + + if (pmsg->flags & I2C_M_RD) { + cmd = (len > 8) ? + SM0CTL1_READ : SM0CTL1_READ_LAST; + } else { + memcpy(data, &pmsg->buf[j], page_len); + iowrite32(data[0], i2c->base + REG_SM0D0_REG); + iowrite32(data[1], i2c->base + REG_SM0D1_REG); + cmd = SM0CTL1_WRITE; + } + + ret = mtk_i2c_master_cmd(i2c, cmd, page_len); + if (ret) + goto err_timeout; + + if (pmsg->flags & I2C_M_RD) { + data[0] = ioread32(i2c->base + REG_SM0D0_REG); + data[1] = ioread32(i2c->base + REG_SM0D1_REG); + memcpy(&pmsg->buf[j], data, page_len); + } else { + if (!(pmsg->flags & I2C_M_IGNORE_NAK)) { + ret = mtk_i2c_check_ack(i2c, + (1 << page_len) + - 1); + if (ret) + goto err_ack; + } + } + } + } + + ret = mtk_i2c_master_stop(i2c); + if (ret) + goto err_timeout; + + /* the return value is number of executed messages */ + return i; + +err_ack: + ret = mtk_i2c_master_stop(i2c); + if (ret) + goto err_timeout; + return -ENXIO; + +err_timeout: + mtk_i2c_dump_reg(i2c); + mtk_i2c_reset(i2c); + return ret; +} + +static u32 mtk_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; +} + +static const struct i2c_algorithm mtk_i2c_algo = { + .master_xfer = mtk_i2c_master_xfer, + .functionality = mtk_i2c_func, +}; + +static const struct of_device_id i2c_mtk_dt_ids[] = { + { .compatible = "mediatek,mt7621-i2c" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids); + +static void mtk_i2c_init(struct mtk_i2c *i2c) +{ + i2c->clk_div = clk_get_rate(i2c->clk) / i2c->bus_freq - 1; + if (i2c->clk_div < 99) + i2c->clk_div = 99; + if (i2c->clk_div > SM0CTL0_CLK_DIV_MAX) + i2c->clk_div = SM0CTL0_CLK_DIV_MAX; + + mtk_i2c_reset(i2c); +} + +static int mtk_i2c_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mtk_i2c *i2c; + struct i2c_adapter *adap; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "no clock defined\n"); + return PTR_ERR(i2c->clk); + } + ret = clk_prepare_enable(i2c->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock\n"); + return ret; + } + + i2c->dev = &pdev->dev; + + if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->bus_freq)) + i2c->bus_freq = 100000; + + if (i2c->bus_freq == 0) { + dev_warn(i2c->dev, "clock-frequency 0 not supported\n"); + return -EINVAL; + } + + adap = &i2c->adap; + adap->owner = THIS_MODULE; + adap->algo = &mtk_i2c_algo; + adap->retries = 3; + adap->dev.parent = &pdev->dev; + i2c_set_adapdata(adap, i2c); + adap->dev.of_node = pdev->dev.of_node; + strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + + platform_set_drvdata(pdev, i2c); + + mtk_i2c_init(i2c); + + ret = i2c_add_adapter(adap); + if (ret < 0) + return ret; + + dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000); + + return ret; +} + +static int mtk_i2c_remove(struct platform_device *pdev) +{ + struct mtk_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adap); + + return 0; +} + +static struct platform_driver mtk_i2c_driver = { + .probe = mtk_i2c_probe, + .remove = mtk_i2c_remove, + .driver = { + .name = "i2c-mt7621", + .of_match_table = i2c_mtk_dt_ids, + }, +}; + +module_platform_driver(mtk_i2c_driver); + +MODULE_AUTHOR("Steven Liu"); +MODULE_DESCRIPTION("MT7621 I2C host driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:MT7621-I2C"); diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 1c8f708f212b..cfc76b5de726 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c @@ -51,6 +51,7 @@ struct gpu_i2c_dev { void __iomem *regs; struct i2c_adapter adapter; struct i2c_board_info *gpu_ccgx_ucsi; + struct i2c_client *ccgx_client; }; static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd) @@ -169,12 +170,14 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap, { struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap); int status, status2; + bool send_stop = true; int i, j; /* * The controller supports maximum 4 byte read due to known * limitation of sending STOP after every read. */ + pm_runtime_get_sync(i2cd->dev); for (i = 0; i < num; i++) { if (msgs[i].flags & I2C_M_RD) { /* program client address before starting read */ @@ -182,37 +185,42 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap, /* gpu_i2c_read has implicit start */ status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len); if (status < 0) - goto stop; + goto exit; } else { u8 addr = i2c_8bit_addr_from_msg(msgs + i); status = gpu_i2c_start(i2cd); if (status < 0) { if (i == 0) - return status; - goto stop; + send_stop = false; + goto exit; } status = gpu_i2c_write(i2cd, addr); if (status < 0) - goto stop; + goto exit; for (j = 0; j < msgs[i].len; j++) { status = gpu_i2c_write(i2cd, msgs[i].buf[j]); if (status < 0) - goto stop; + goto exit; } } } + send_stop = false; status = gpu_i2c_stop(i2cd); if (status < 0) - return status; - - return i; -stop: - status2 = gpu_i2c_stop(i2cd); - if (status2 < 0) - dev_err(i2cd->dev, "i2c stop failed %d\n", status2); + goto exit; + + status = i; +exit: + if (send_stop) { + status2 = gpu_i2c_stop(i2cd); + if (status2 < 0) + dev_err(i2cd->dev, "i2c stop failed %d\n", status2); + } + pm_runtime_mark_last_busy(i2cd->dev); + pm_runtime_put_autosuspend(i2cd->dev); return status; } @@ -261,8 +269,6 @@ static const struct property_entry ccgx_props[] = { static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) { - struct i2c_client *ccgx_client; - i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev, sizeof(*i2cd->gpu_ccgx_ucsi), GFP_KERNEL); @@ -274,8 +280,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) i2cd->gpu_ccgx_ucsi->addr = 0x8; i2cd->gpu_ccgx_ucsi->irq = irq; i2cd->gpu_ccgx_ucsi->properties = ccgx_props; - ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi); - if (!ccgx_client) + i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi); + if (!i2cd->ccgx_client) return -ENODEV; return 0; @@ -332,6 +338,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto del_adapter; } + pm_runtime_set_autosuspend_delay(&pdev->dev, 3000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_allow(&pdev->dev); + return 0; del_adapter: @@ -345,19 +356,38 @@ static void gpu_i2c_remove(struct pci_dev *pdev) { struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev); + pm_runtime_get_noresume(i2cd->dev); i2c_del_adapter(&i2cd->adapter); pci_free_irq_vectors(pdev); } +/* + * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work + * correctly. Without it, lspci shows runtime pm status as "D0" for the card. + * Documentation/power/pci.txt also insists for driver to provide this. + */ +static __maybe_unused int gpu_i2c_suspend(struct device *dev) +{ + return 0; +} + static __maybe_unused int gpu_i2c_resume(struct device *dev) { struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev); gpu_enable_i2c_bus(i2cd); + /* + * Runtime resume ccgx client so that it can see for any + * connector change event. Old ccg firmware has known + * issue of not triggering interrupt when a device is + * connected to runtime resume the controller. + */ + pm_request_resume(&i2cd->ccgx_client->dev); return 0; } -static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL); +static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume, + NULL); static struct pci_driver gpu_i2c_driver = { .name = "nvidia-gpu", diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index c3dabee0aa35..4117f1abc7c6 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -35,6 +35,7 @@ struct ocores_i2c { int iobase; u32 reg_shift; u32 reg_io_width; + unsigned long flags; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -82,6 +83,9 @@ struct ocores_i2c { #define TYPE_OCORES 0 #define TYPE_GRLIB 1 +#define TYPE_SIFIVE_REV0 2 + +#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */ static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) { @@ -235,9 +239,12 @@ static irqreturn_t ocores_isr(int irq, void *dev_id) struct ocores_i2c *i2c = dev_id; u8 stat = oc_getreg(i2c, OCI2C_STATUS); - if (!(stat & OCI2C_STAT_IF)) + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) { + if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY)) + return IRQ_NONE; + } else if (!(stat & OCI2C_STAT_IF)) { return IRQ_NONE; - + } ocores_process(i2c, stat); return IRQ_HANDLED; @@ -352,6 +359,11 @@ static void ocores_process_polling(struct ocores_i2c *i2c) ret = ocores_isr(-1, i2c); if (ret == IRQ_NONE) break; /* all messages have been transferred */ + else { + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) + if (i2c->state == STATE_DONE) + break; + } } } @@ -462,6 +474,14 @@ static const struct of_device_id ocores_i2c_match[] = { .compatible = "aeroflexgaisler,i2cmst", .data = (void *)TYPE_GRLIB, }, + { + .compatible = "sifive,fu540-c000-i2c", + .data = (void *)TYPE_SIFIVE_REV0, + }, + { + .compatible = "sifive,i2c0", + .data = (void *)TYPE_SIFIVE_REV0, + }, {}, }; MODULE_DEVICE_TABLE(of, ocores_i2c_match); @@ -586,6 +606,7 @@ static int ocores_i2c_probe(struct platform_device *pdev) { struct ocores_i2c *i2c; struct ocores_i2c_platform_data *pdata; + const struct of_device_id *match; struct resource *res; int irq; int ret; @@ -668,6 +689,14 @@ static int ocores_i2c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq == -ENXIO) { ocores_algorithm.master_xfer = ocores_xfer_polling; + + /* + * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for + * FU540-C000 SoC in polling mode. + */ + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_SIFIVE_REV0) + i2c->flags |= OCORES_FLAG_BROKEN_IRQ; } else { if (irq < 0) return irq; diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db075bc0d952..a89bfce5388e 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +#include <linux/acpi.h> #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/err.h> @@ -483,6 +484,14 @@ static const struct i2c_algorithm geni_i2c_algo = { .functionality = geni_i2c_func, }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id geni_i2c_acpi_match[] = { + { "QCOM0220"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); +#endif + static int geni_i2c_probe(struct platform_device *pdev) { struct geni_i2c_dev *gi2c; @@ -502,7 +511,7 @@ static int geni_i2c_probe(struct platform_device *pdev) return PTR_ERR(gi2c->se.base); gi2c->se.clk = devm_clk_get(&pdev->dev, "se"); - if (IS_ERR(gi2c->se.clk)) { + if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(&pdev->dev)) { ret = PTR_ERR(gi2c->se.clk); dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); return ret; @@ -516,6 +525,9 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->clk_freq_out = KHZ(100); } + if (has_acpi_companion(&pdev->dev)) + ACPI_COMPANION_SET(&gi2c->adap.dev, ACPI_COMPANION(&pdev->dev)); + gi2c->irq = platform_get_irq(pdev, 0); if (gi2c->irq < 0) { dev_err(&pdev->dev, "IRQ error for i2c-geni\n"); @@ -584,6 +596,8 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + dev_dbg(&pdev->dev, "Geni-I2C adaptor successfully added\n"); + return 0; } @@ -660,6 +674,7 @@ static struct platform_driver geni_i2c_driver = { .name = "geni_i2c", .pm = &geni_i2c_pm_ops, .of_match_table = geni_i2c_dt_match, + .acpi_match_table = ACPI_PTR(geni_i2c_acpi_match), }, }; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index c9510d085c34..d97fb857b0ea 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -24,7 +24,7 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> @@ -113,7 +113,7 @@ struct s3c24xx_i2c { struct i2c_adapter adap; struct s3c2410_platform_i2c *pdata; - int gpios[2]; + struct gpio_desc *gpios[2]; struct pinctrl *pctrl; #if defined(CONFIG_ARM_S3C24XX_CPUFREQ) struct notifier_block freq_transition; @@ -947,53 +947,27 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) #ifdef CONFIG_OF static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { - int idx, gpio, ret; + int i; if (i2c->quirks & QUIRK_NO_GPIO) return 0; - for (idx = 0; idx < 2; idx++) { - gpio = of_get_gpio(i2c->dev->of_node, idx); - if (!gpio_is_valid(gpio)) { - dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); - goto free_gpio; - } - i2c->gpios[idx] = gpio; - - ret = gpio_request(gpio, "i2c-bus"); - if (ret) { - dev_err(i2c->dev, "gpio [%d] request failed (%d)\n", - gpio, ret); - goto free_gpio; + for (i = 0; i < 2; i++) { + i2c->gpios[i] = devm_gpiod_get_index(i2c->dev, NULL, + i, GPIOD_ASIS); + if (IS_ERR(i2c->gpios[i])) { + dev_err(i2c->dev, "i2c gpio invalid at index %d\n", i); + return -EINVAL; } } return 0; - -free_gpio: - while (--idx >= 0) - gpio_free(i2c->gpios[idx]); - return -EINVAL; } -static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) -{ - unsigned int idx; - - if (i2c->quirks & QUIRK_NO_GPIO) - return; - - for (idx = 0; idx < 2; idx++) - gpio_free(i2c->gpios[idx]); -} #else static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { return 0; } - -static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) -{ -} #endif /* @@ -1222,9 +1196,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); - if (pdev->dev.of_node && IS_ERR(i2c->pctrl)) - s3c24xx_i2c_dt_gpio_free(i2c); - return 0; } diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 48337bef5b87..266d1c269b83 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pinctrl/consumer.h> @@ -953,6 +952,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr2 &= ~STM32F7_I2C_CR2_RD_WRN; f7_msg->read_write = I2C_SMBUS_READ; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* Rely on emulated i2c transfer (through master_xfer) */ + return -EOPNOTSUPP; default: dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); return -EOPNOTSUPP; @@ -1803,7 +1805,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap) I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | - I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC; + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC | + I2C_FUNC_SMBUS_I2C_BLOCK; } static struct i2c_algorithm stm32f7_i2c_algo = { @@ -1816,15 +1819,14 @@ static struct i2c_algorithm stm32f7_i2c_algo = { static int stm32f7_i2c_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct stm32f7_i2c_dev *i2c_dev; const struct stm32f7_i2c_setup *setup; struct resource *res; - u32 irq_error, irq_event, clk_rate, rise_time, fall_time; + u32 clk_rate, rise_time, fall_time; struct i2c_adapter *adap; struct reset_control *rst; dma_addr_t phy_addr; - int ret; + int irq_error, irq_event, ret; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) @@ -1836,16 +1838,20 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) return PTR_ERR(i2c_dev->base); phy_addr = (dma_addr_t)res->start; - irq_event = irq_of_parse_and_map(np, 0); - if (!irq_event) { - dev_err(&pdev->dev, "IRQ event missing or invalid\n"); - return -EINVAL; + irq_event = platform_get_irq(pdev, 0); + if (irq_event <= 0) { + if (irq_event != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", + irq_event); + return irq_event ? : -ENOENT; } - irq_error = irq_of_parse_and_map(np, 1); - if (!irq_error) { - dev_err(&pdev->dev, "IRQ error missing or invalid\n"); - return -EINVAL; + irq_error = platform_get_irq(pdev, 1); + if (irq_error <= 0) { + if (irq_error != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", + irq_error); + return irq_error ? : -ENOENT; } i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index ebaa78d17d6e..9fcb13beeb8f 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -54,20 +54,15 @@ #define I2C_INT_STATUS 0x068 #define I2C_INT_BUS_CLR_DONE BIT(11) #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 BIT(10) -#define DVC_CTRL_REG2 0x004 #define DVC_CTRL_REG3 0x008 #define DVC_CTRL_REG3_SW_PROG BIT(26) #define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30) @@ -75,24 +70,22 @@ #define DVC_STATUS_I2C_DONE_INTR BIT(30) #define I2C_ERR_NONE 0x00 -#define I2C_ERR_NO_ACK 0x01 -#define I2C_ERR_ARBITRATION_LOST 0x02 -#define I2C_ERR_UNKNOWN_INTERRUPT 0x04 +#define I2C_ERR_NO_ACK BIT(0) +#define I2C_ERR_ARBITRATION_LOST BIT(1) +#define I2C_ERR_UNKNOWN_INTERRUPT BIT(2) +#define I2C_ERR_RX_BUFFER_OVERFLOW BIT(3) #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 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_BUS_CLEAR_CNFG 0x084 @@ -106,8 +99,6 @@ #define I2C_CONFIG_LOAD 0x08C #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 BIT(0) @@ -133,7 +124,6 @@ #define I2C_STANDARD_MODE 100000 #define I2C_FAST_MODE 400000 #define I2C_FAST_PLUS_MODE 1000000 -#define I2C_HS_MODE 3500000 /* Packet header size in bytes */ #define I2C_PACKET_HEADER_SIZE 12 @@ -280,6 +270,7 @@ struct tegra_i2c_dev { u32 bus_clk_rate; u16 clk_divisor_non_hs_mode; bool is_multimaster_mode; + /* xfer_lock: lock to serialize transfer submission and processing */ spinlock_t xfer_lock; struct dma_chan *tx_dma_chan; struct dma_chan *rx_dma_chan; @@ -306,7 +297,7 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) * to the I2C block inside the DVC block */ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, - unsigned long reg) + unsigned long reg) { if (i2c_dev->is_dvc) reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40; @@ -314,7 +305,7 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, } static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, - unsigned long reg) + unsigned long reg) { writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); @@ -329,13 +320,13 @@ static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) } static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data, - unsigned long reg, int len) + unsigned long reg, int len) { writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len); } static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data, - unsigned long reg, int len) + unsigned long reg, int len) { readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len); } @@ -486,7 +477,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); return -ETIMEDOUT; } - msleep(1); + usleep_range(1000, 2000); } return 0; } @@ -499,6 +490,13 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) size_t buf_remaining = i2c_dev->msg_buf_remaining; int words_to_transfer; + /* + * Catch overflow due to message fully sent + * before the check for RX FIFO availability. + */ + if (WARN_ON_ONCE(!(i2c_dev->msg_buf_remaining))) + return -EINVAL; + if (i2c_dev->hw->has_mst_fifo) { val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS); rx_fifo_avail = (val & I2C_MST_FIFO_STATUS_RX_MASK) >> @@ -525,7 +523,11 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) * prevent overwriting past the end of buf */ if (rx_fifo_avail > 0 && buf_remaining > 0) { - BUG_ON(buf_remaining > 3); + /* + * buf_remaining > 3 check not needed as rx_fifo_avail == 0 + * when (words_to_transfer was > rx_fifo_avail) earlier + * in this function. + */ val = i2c_readl(i2c_dev, I2C_RX_FIFO); val = cpu_to_le32(val); memcpy(buf, &val, buf_remaining); @@ -533,7 +535,10 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) rx_fifo_avail--; } - BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0); + /* RX FIFO must be drained, otherwise it's an Overflow case. */ + if (WARN_ON_ONCE(rx_fifo_avail)) + return -EINVAL; + i2c_dev->msg_buf_remaining = buf_remaining; i2c_dev->msg_buf = buf; @@ -591,7 +596,11 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) * boundary and fault. */ if (tx_fifo_avail > 0 && buf_remaining > 0) { - BUG_ON(buf_remaining > 3); + /* + * buf_remaining > 3 check not needed as tx_fifo_avail == 0 + * when (words_to_transfer was > tx_fifo_avail) earlier + * in this function for non-zero words_to_transfer. + */ memcpy(&val, buf, buf_remaining); val = le32_to_cpu(val); @@ -680,10 +689,11 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) 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); + 1000, + I2C_CONFIG_LOAD_TIMEOUT); else - err = readl_poll_timeout(addr, val, val == 0, - 1000, I2C_CONFIG_LOAD_TIMEOUT); + err = readl_poll_timeout(addr, val, val == 0, 1000, + I2C_CONFIG_LOAD_TIMEOUT); if (err) { dev_warn(i2c_dev->dev, @@ -700,7 +710,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit) u32 val; int err; u32 clk_divisor, clk_multiplier; - u32 tsu_thd = 0; + u32 tsu_thd; u8 tlow, thigh; err = pm_runtime_get_sync(i2c_dev->dev); @@ -856,10 +866,15 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) if (!i2c_dev->is_curr_dma_xfer) { if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) { - if (i2c_dev->msg_buf_remaining) - tegra_i2c_empty_rx_fifo(i2c_dev); - else - BUG(); + if (tegra_i2c_empty_rx_fifo(i2c_dev)) { + /* + * Overflow error condition: message fully sent, + * with no XFER_COMPLETE interrupt but hardware + * asks to transfer more. + */ + i2c_dev->msg_err |= I2C_ERR_RX_BUFFER_OVERFLOW; + goto err; + } } if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) { @@ -885,7 +900,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) if (status & I2C_INT_PACKET_XFER_COMPLETE) { if (i2c_dev->is_curr_dma_xfer) i2c_dev->msg_buf_remaining = 0; - BUG_ON(i2c_dev->msg_buf_remaining); + /* + * Underflow error condition: XFER_COMPLETE before message + * fully sent. + */ + if (WARN_ON_ONCE(i2c_dev->msg_buf_remaining)) { + i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT; + goto err; + } complete(&i2c_dev->msg_complete); } goto done; @@ -1024,7 +1046,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap) } static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, - struct i2c_msg *msg, enum msg_end_type end_state) + struct i2c_msg *msg, + enum msg_end_type end_state) { u32 packet_header; u32 int_mask; @@ -1161,9 +1184,8 @@ unlock: if (err) return err; - time_left = wait_for_completion_timeout( - &i2c_dev->dma_complete, - msecs_to_jiffies(xfer_time)); + time_left = wait_for_completion_timeout(&i2c_dev->dma_complete, + msecs_to_jiffies(xfer_time)); if (time_left == 0) { dev_err(i2c_dev->dev, "DMA transfer timeout\n"); dmaengine_terminate_sync(i2c_dev->msg_read ? @@ -1225,11 +1247,11 @@ unlock: } static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - int num) + int num) { struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); int i; - int ret = 0; + int ret; ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) { @@ -1271,14 +1293,15 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) { struct device_node *np = i2c_dev->dev->of_node; int ret; + bool multi_mode; ret = of_property_read_u32(np, "clock-frequency", - &i2c_dev->bus_clk_rate); + &i2c_dev->bus_clk_rate); if (ret) i2c_dev->bus_clk_rate = 100000; /* default clock rate */ - i2c_dev->is_multimaster_mode = of_property_read_bool(np, - "multi-master"); + multi_mode = of_property_read_bool(np, "multi-master"); + i2c_dev->is_multimaster_mode = multi_mode; } static const struct i2c_algorithm tegra_i2c_algo = { @@ -1500,7 +1523,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) void __iomem *base; phys_addr_t base_phys; int irq; - int ret = 0; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base_phys = res->start; @@ -1517,7 +1540,9 @@ 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\n"); + if (PTR_ERR(div_clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "missing controller clock\n"); + return PTR_ERR(div_clk); } @@ -1622,7 +1647,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, i2c_dev->irq, - tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); + tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); if (ret) { dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); goto release_dma; @@ -1687,10 +1712,35 @@ static int tegra_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP +static int tegra_i2c_suspend(struct device *dev) +{ + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); + + i2c_mark_adapter_suspended(&i2c_dev->adapter); + + return 0; +} + +static int tegra_i2c_resume(struct device *dev) +{ + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); + int err; + + err = tegra_i2c_init(i2c_dev, false); + if (err) + return err; + + i2c_mark_adapter_resumed(&i2c_dev->adapter); + + return 0; +} + static const struct dev_pm_ops tegra_i2c_pm = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume, NULL) }; + #define TEGRA_I2C_PM (&tegra_i2c_pm) #else #define TEGRA_I2C_PM NULL diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 428a82c3a35f..4dbbc9a35f65 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -132,13 +132,52 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, return 0; } +static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) +{ + int *irq = data; + struct resource r; + + if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) + *irq = i2c_dev_irq_from_resources(&r, 1); + + return 1; /* No need to add resource to the list */ +} + +/** + * i2c_acpi_get_irq - get device IRQ number from ACPI + * @client: Pointer to the I2C client device + * + * Find the IRQ number used by a specific client device. + * + * Return: The IRQ number or an error code. + */ +int i2c_acpi_get_irq(struct i2c_client *client) +{ + struct acpi_device *adev = ACPI_COMPANION(&client->dev); + struct list_head resource_list; + int irq = -ENOENT; + int ret; + + INIT_LIST_HEAD(&resource_list); + + ret = acpi_dev_get_resources(adev, &resource_list, + i2c_acpi_add_resource, &irq); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&resource_list); + + if (irq == -ENOENT) + irq = acpi_dev_gpio_irq_get(adev, 0); + + return irq; +} + 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; @@ -172,21 +211,6 @@ static int i2c_acpi_get_info(struct acpi_device *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 -EINVAL; - - resource_list_for_each_entry(entry, &resource_list) { - if (resource_type(entry->res) == IORESOURCE_IRQ) { - info->irq = entry->res->start; - break; - } - } - - acpi_dev_free_resource_list(&resource_list); - acpi_set_modalias(adev, dev_name(&adev->dev), info->type, sizeof(info->type)); diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 9e43508d4567..f26ed495d384 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -314,6 +314,8 @@ static int i2c_device_probe(struct device *dev) driver = to_i2c_driver(dev->driver); + client->irq = client->init_irq; + if (!client->irq && !driver->disable_i2c_core_irq_mapping) { int irq = -ENOENT; @@ -327,7 +329,7 @@ static int i2c_device_probe(struct device *dev) if (irq == -EINVAL || irq == -ENODATA) irq = of_irq_get(dev->of_node, 0); } else if (ACPI_COMPANION(dev)) { - irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); + irq = i2c_acpi_get_irq(client); } if (irq == -EPROBE_DEFER) return irq; @@ -424,7 +426,7 @@ static int i2c_device_remove(struct device *dev) dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); - client->irq = client->init_irq; + client->irq = 0; if (client->flags & I2C_CLIENT_HOST_NOTIFY) pm_runtime_put(&client->adapter->dev); @@ -679,8 +681,8 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, i2c_encode_flags_to_addr(client)); } -static int i2c_dev_irq_from_resources(const struct resource *resources, - unsigned int num_resources) +int i2c_dev_irq_from_resources(const struct resource *resources, + unsigned int num_resources) { struct irq_data *irqd; int i; @@ -721,7 +723,7 @@ static int i2c_dev_irq_from_resources(const struct resource *resources, * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or an ERR_PTR to describe the error. */ -static struct i2c_client * +struct i2c_client * i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client; @@ -741,7 +743,6 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf if (!client->init_irq) client->init_irq = i2c_dev_irq_from_resources(info->resources, info->num_resources); - client->irq = client->init_irq; strlcpy(client->name, info->type, sizeof(client->name)); @@ -887,8 +888,7 @@ static struct i2c_driver dummy_driver = { * This returns the new i2c client, which should be saved for later use with * i2c_unregister_device(); or an ERR_PTR to describe the error. */ -static struct i2c_client * -i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address) +struct i2c_client *i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address) { struct i2c_board_info info = { I2C_BOARD_INFO("dummy", address), @@ -1663,7 +1663,7 @@ EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); /* ------------------------------------------------------------------------- */ -int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)) +int i2c_for_each_dev(void *data, int (*fn)(struct device *dev, void *data)) { int res; @@ -2276,7 +2276,7 @@ struct i2c_client * i2c_new_probed_device(struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list, - int (*probe)(struct i2c_adapter *, unsigned short addr)) + int (*probe)(struct i2c_adapter *adap, unsigned short addr)) { int i; diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 2eb59a260ad4..d1c48dec7118 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/sysfs.h> #include "i2c-core.h" diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 851c11b4c0f3..517d98be68d2 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -19,6 +19,8 @@ extern struct list_head __i2c_board_list; extern int __i2c_first_dynamic_bus_num; int i2c_check_7bit_addr_validity_strict(unsigned short addr); +int i2c_dev_irq_from_resources(const struct resource *resources, + unsigned int num_resources); /* * We only allow atomic transfers for very late communication, e.g. to send @@ -61,6 +63,8 @@ const struct acpi_device_id * i2c_acpi_match_device(const struct acpi_device_id *matches, struct i2c_client *client); void i2c_acpi_register_devices(struct i2c_adapter *adap); + +int i2c_acpi_get_irq(struct i2c_client *client); #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } static inline const struct acpi_device_id * @@ -69,6 +73,11 @@ i2c_acpi_match_device(const struct acpi_device_id *matches, { return NULL; } + +static inline int i2c_acpi_get_irq(struct i2c_client *client) +{ + return 0; +} #endif /* CONFIG_ACPI */ extern struct notifier_block i2c_acpi_notifier; diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 603252fa1284..774507b54b57 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/slab.h> +#include <linux/sysfs.h> /* multiplexer per channel data */ struct i2c_mux_priv { @@ -243,8 +244,7 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, { struct i2c_mux_core *muxc; - muxc = devm_kzalloc(dev, sizeof(*muxc) - + max_adapters * sizeof(muxc->adapter[0]) + muxc = devm_kzalloc(dev, struct_size(muxc, adapter, max_adapters) + sizeof_priv, GFP_KERNEL); if (!muxc) return NULL; diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 255c598dcfc8..6dc88902c189 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -6,12 +6,11 @@ */ #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/i2c.h> #include <linux/i2c-mux.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -19,22 +18,16 @@ /** * struct i2c_arbitrator_data - Driver data for I2C arbitrator * - * @our_gpio: GPIO we'll use to claim. - * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO == - * this then consider it released. - * @their_gpio: GPIO that the other side will use to claim. - * @their_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO == - * this then consider it released. + * @our_gpio: GPIO descriptor we'll use to claim. + * @their_gpio: GPIO descriptor that the other side will use to claim. * @slew_delay_us: microseconds to wait for a GPIO to go high. * @wait_retry_us: we'll attempt another claim after this many microseconds. * @wait_free_us: we'll give up after this many microseconds. */ struct i2c_arbitrator_data { - int our_gpio; - int our_gpio_release; - int their_gpio; - int their_gpio_release; + struct gpio_desc *our_gpio; + struct gpio_desc *their_gpio; unsigned int slew_delay_us; unsigned int wait_retry_us; unsigned int wait_free_us; @@ -55,15 +48,15 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan) stop_time = jiffies + usecs_to_jiffies(arb->wait_free_us) + 1; do { /* Indicate that we want to claim the bus */ - gpio_set_value(arb->our_gpio, !arb->our_gpio_release); + gpiod_set_value(arb->our_gpio, 1); udelay(arb->slew_delay_us); /* Wait for the other master to release it */ stop_retry = jiffies + usecs_to_jiffies(arb->wait_retry_us) + 1; while (time_before(jiffies, stop_retry)) { - int gpio_val = !!gpio_get_value(arb->their_gpio); + int gpio_val = gpiod_get_value(arb->their_gpio); - if (gpio_val == arb->their_gpio_release) { + if (!gpio_val) { /* We got it, so return */ return 0; } @@ -72,13 +65,13 @@ static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan) } /* It didn't release, so give up, wait, and try again */ - gpio_set_value(arb->our_gpio, arb->our_gpio_release); + gpiod_set_value(arb->our_gpio, 0); usleep_range(arb->wait_retry_us, arb->wait_retry_us * 2); } while (time_before(jiffies, stop_time)); /* Give up, release our claim */ - gpio_set_value(arb->our_gpio, arb->our_gpio_release); + gpiod_set_value(arb->our_gpio, 0); udelay(arb->slew_delay_us); dev_err(muxc->dev, "Could not claim bus, timeout\n"); return -EBUSY; @@ -94,7 +87,7 @@ static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan) const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc); /* Release the bus and wait for the other master to notice */ - gpio_set_value(arb->our_gpio, arb->our_gpio_release); + gpiod_set_value(arb->our_gpio, 0); udelay(arb->slew_delay_us); return 0; @@ -107,8 +100,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) struct device_node *parent_np; struct i2c_mux_core *muxc; struct i2c_arbitrator_data *arb; - enum of_gpio_flags gpio_flags; - unsigned long out_init; + struct gpio_desc *dummy; int ret; /* We only support probing from device tree; no platform_data */ @@ -129,45 +121,28 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, muxc); - /* Request GPIOs */ - ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags); - if (!gpio_is_valid(ret)) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Error getting our-claim-gpio\n"); - return ret; - } - arb->our_gpio = ret; - arb->our_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW); - out_init = (gpio_flags & OF_GPIO_ACTIVE_LOW) ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - ret = devm_gpio_request_one(dev, arb->our_gpio, out_init, - "our-claim-gpio"); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Error requesting our-claim-gpio\n"); - return ret; + /* Request GPIOs, our GPIO as unclaimed to begin with */ + arb->our_gpio = devm_gpiod_get(dev, "our-claim", GPIOD_OUT_LOW); + if (IS_ERR(arb->our_gpio)) { + dev_err(dev, "could not get \"our-claim\" GPIO (%ld)\n", + PTR_ERR(arb->our_gpio)); + return PTR_ERR(arb->our_gpio); } - ret = of_get_named_gpio_flags(np, "their-claim-gpios", 0, &gpio_flags); - if (!gpio_is_valid(ret)) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Error getting their-claim-gpio\n"); - return ret; - } - arb->their_gpio = ret; - arb->their_gpio_release = !!(gpio_flags & OF_GPIO_ACTIVE_LOW); - ret = devm_gpio_request_one(dev, arb->their_gpio, GPIOF_IN, - "their-claim-gpio"); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Error requesting their-claim-gpio\n"); - return ret; + arb->their_gpio = devm_gpiod_get(dev, "their-claim", GPIOD_IN); + if (IS_ERR(arb->their_gpio)) { + dev_err(dev, "could not get \"their-claim\" GPIO (%ld)\n", + PTR_ERR(arb->their_gpio)); + return PTR_ERR(arb->their_gpio); } /* At the moment we only support a single two master (us + 1 other) */ - if (gpio_is_valid(of_get_named_gpio(np, "their-claim-gpios", 1))) { + dummy = devm_gpiod_get_index(dev, "their-claim", 1, GPIOD_IN); + if (!IS_ERR(dummy)) { dev_err(dev, "Only one other master is supported\n"); return -EINVAL; + } else if (PTR_ERR(dummy) == -EPROBE_DEFER) { + return -EPROBE_DEFER; } /* Arbitration parameters */ diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 14dc2deba283..4effe563e9e8 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -11,13 +11,14 @@ #include <linux/platform_device.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/bits.h> +#include <linux/gpio/consumer.h> +/* FIXME: stop poking around inside gpiolib */ #include "../../gpio/gpiolib.h" -#include <linux/of_gpio.h> struct gpiomux { struct i2c_mux_gpio_platform_data data; - unsigned gpio_base; + int ngpios; struct gpio_desc **gpios; }; @@ -27,8 +28,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) values[0] = val; - gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL, - values); + gpiod_set_array_value_cansleep(mux->ngpios, mux->gpios, NULL, values); } static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) @@ -49,12 +49,6 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) return 0; } -static int match_gpio_chip_by_label(struct gpio_chip *chip, - void *data) -{ - return !strcmp(chip->label, data); -} - #ifdef CONFIG_OF static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, struct platform_device *pdev) @@ -62,8 +56,8 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, struct device_node *np = pdev->dev.of_node; struct device_node *adapter_np, *child; struct i2c_adapter *adapter; - unsigned *values, *gpios; - int i = 0, ret; + unsigned *values; + int i = 0; if (!np) return -ENODEV; @@ -100,29 +94,6 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, if (of_property_read_u32(np, "idle-state", &mux->data.idle)) mux->data.idle = I2C_MUX_GPIO_NO_IDLE; - mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); - if (mux->data.n_gpios < 0) { - dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); - return -EINVAL; - } - - gpios = devm_kcalloc(&pdev->dev, - mux->data.n_gpios, sizeof(*mux->data.gpios), - GFP_KERNEL); - if (!gpios) { - dev_err(&pdev->dev, "Cannot allocate gpios array"); - return -ENOMEM; - } - - for (i = 0; i < mux->data.n_gpios; i++) { - ret = of_get_named_gpio(np, "mux-gpios", i); - if (ret < 0) - return ret; - gpios[i] = ret; - } - - mux->data.gpios = gpios; - return 0; } #else @@ -139,8 +110,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) struct gpiomux *mux; struct i2c_adapter *parent; struct i2c_adapter *root; - unsigned initial_state, gpio_base; - int i, ret; + unsigned initial_state; + int i, ngpios, ret; mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); if (!mux) @@ -155,29 +126,19 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) sizeof(mux->data)); } - /* - * If a GPIO chip name is provided, the GPIO pin numbers provided are - * relative to its base GPIO number. Otherwise they are absolute. - */ - if (mux->data.gpio_chip) { - struct gpio_chip *gpio; - - gpio = gpiochip_find(mux->data.gpio_chip, - match_gpio_chip_by_label); - if (!gpio) - return -EPROBE_DEFER; - - gpio_base = gpio->base; - } else { - gpio_base = 0; + ngpios = gpiod_count(&pdev->dev, "mux"); + if (ngpios <= 0) { + dev_err(&pdev->dev, "no valid gpios provided\n"); + return ngpios ?: -EINVAL; } + mux->ngpios = ngpios; parent = i2c_get_adapter(mux->data.parent); if (!parent) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - mux->data.n_gpios * sizeof(*mux->gpios), 0, + ngpios * sizeof(*mux->gpios), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; @@ -191,7 +152,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) root = i2c_root_adapter(&parent->dev); muxc->mux_locked = true; - mux->gpio_base = gpio_base; if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { initial_state = mux->data.idle; @@ -200,34 +160,28 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) initial_state = mux->data.values[0]; } - for (i = 0; i < mux->data.n_gpios; i++) { + for (i = 0; i < ngpios; i++) { struct device *gpio_dev; - struct gpio_desc *gpio_desc; - - ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); - if (ret) { - dev_err(&pdev->dev, "Failed to request GPIO %d\n", - mux->data.gpios[i]); - goto err_request_gpio; + struct gpio_desc *gpiod; + enum gpiod_flags flag; + + if (initial_state & BIT(i)) + flag = GPIOD_OUT_HIGH; + else + flag = GPIOD_OUT_LOW; + gpiod = devm_gpiod_get_index(&pdev->dev, "mux", i, flag); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + goto alloc_failed; } - ret = gpio_direction_output(gpio_base + mux->data.gpios[i], - initial_state & (1 << i)); - if (ret) { - dev_err(&pdev->dev, - "Failed to set direction of GPIO %d to output\n", - mux->data.gpios[i]); - i++; /* gpio_request above succeeded, so must free */ - goto err_request_gpio; - } - - gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]); - mux->gpios[i] = gpio_desc; + mux->gpios[i] = gpiod; if (!muxc->mux_locked) continue; - gpio_dev = &gpio_desc->gdev->dev; + /* FIXME: find a proper way to access the GPIO device */ + gpio_dev = &gpiod->gdev->dev; muxc->mux_locked = i2c_root_adapter(gpio_dev) == root; } @@ -250,10 +204,6 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) add_adapter_failed: i2c_mux_del_adapters(muxc); - i = mux->data.n_gpios; -err_request_gpio: - for (; i > 0; i--) - gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -263,14 +213,8 @@ alloc_failed: static int i2c_mux_gpio_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); - struct gpiomux *mux = i2c_mux_priv(muxc); - int i; i2c_mux_del_adapters(muxc); - - for (i = 0; i < mux->data.n_gpios; i++) - gpio_free(mux->gpio_base + mux->data.gpios[i]); - i2c_put_adapter(muxc->parent); return 0; diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 41603586f8fa..f1bb00a11ad6 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -16,7 +16,7 @@ struct i2c_mux_pinctrl { struct pinctrl *pinctrl; - struct pinctrl_state **states; + struct pinctrl_state *states[]; }; static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan) @@ -93,14 +93,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(parent); muxc = i2c_mux_alloc(parent, dev, num_names, - sizeof(*mux) + num_names * sizeof(*mux->states), + struct_size(mux, states, num_names), 0, i2c_mux_pinctrl_select, NULL); if (!muxc) { ret = -ENOMEM; goto err_put_parent; } mux = i2c_mux_priv(muxc); - mux->states = (struct pinctrl_state **)(mux + 1); platform_set_drvdata(pdev, muxc); diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 63aa541c9608..35bf2477693d 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -507,38 +507,24 @@ static const struct at24_chip_data *at24_get_chip_data(struct device *dev) return cdata; } -static void at24_remove_dummy_clients(struct at24_data *at24) -{ - int i; - - for (i = 1; i < at24->num_addresses; i++) - i2c_unregister_device(at24->client[i].client); -} - static int at24_make_dummy_client(struct at24_data *at24, unsigned int index, struct regmap_config *regmap_config) { struct i2c_client *base_client, *dummy_client; - unsigned short int addr; struct regmap *regmap; struct device *dev; base_client = at24->client[0].client; dev = &base_client->dev; - addr = base_client->addr + index; - dummy_client = i2c_new_dummy(base_client->adapter, - base_client->addr + index); - if (!dummy_client) { - dev_err(dev, "address 0x%02x unavailable\n", addr); - return -EADDRINUSE; - } + dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter, + base_client->addr + index); + if (IS_ERR(dummy_client)) + return PTR_ERR(dummy_client); regmap = devm_regmap_init_i2c(dummy_client, regmap_config); - if (IS_ERR(regmap)) { - i2c_unregister_device(dummy_client); + if (IS_ERR(regmap)) return PTR_ERR(regmap); - } at24->client[index].client = dummy_client; at24->client[index].regmap = regmap; @@ -580,7 +566,6 @@ static int at24_probe(struct i2c_client *client) unsigned int i, num_addresses; struct at24_data *at24; struct regmap *regmap; - size_t at24_size; bool writable; u8 test_byte; int err; @@ -597,8 +582,8 @@ static int at24_probe(struct i2c_client *client) if (err) /* * This is slow, but we can't know all eeproms, so we better - * play safe. Specifying custom eeprom-types via platform_data - * is recommended anyhow. + * play safe. Specifying custom eeprom-types via device tree + * or properties is recommended anyhow. */ page_size = 1; @@ -664,8 +649,8 @@ static int at24_probe(struct i2c_client *client) if (IS_ERR(regmap)) return PTR_ERR(regmap); - at24_size = sizeof(*at24) + num_addresses * sizeof(struct at24_client); - at24 = devm_kzalloc(dev, at24_size, GFP_KERNEL); + at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses), + GFP_KERNEL); if (!at24) return -ENOMEM; @@ -693,27 +678,8 @@ static int at24_probe(struct i2c_client *client) /* use dummy devices for multiple-address chips */ for (i = 1; i < num_addresses; i++) { err = at24_make_dummy_client(at24, i, ®map_config); - if (err) { - at24_remove_dummy_clients(at24); + if (err) return err; - } - } - - i2c_set_clientdata(client, at24); - - /* enable runtime pm */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - /* - * Perform a one-byte test read to verify that the - * chip is functional. - */ - err = at24_read(at24, 0, &test_byte, 1); - pm_runtime_idle(dev); - if (err) { - err = -ENODEV; - goto err_clients; } nvmem_config.name = dev_name(dev); @@ -731,9 +697,24 @@ static int at24_probe(struct i2c_client *client) nvmem_config.size = byte_len; at24->nvmem = devm_nvmem_register(dev, &nvmem_config); - if (IS_ERR(at24->nvmem)) { - err = PTR_ERR(at24->nvmem); - goto err_clients; + if (IS_ERR(at24->nvmem)) + return PTR_ERR(at24->nvmem); + + i2c_set_clientdata(client, at24); + + /* enable runtime pm */ + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + /* + * Perform a one-byte test read to verify that the + * chip is functional. + */ + err = at24_read(at24, 0, &test_byte, 1); + pm_runtime_idle(dev); + if (err) { + pm_runtime_disable(dev); + return -ENODEV; } dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n", @@ -741,21 +722,10 @@ static int at24_probe(struct i2c_client *client) writable ? "writable" : "read-only", at24->write_max); return 0; - -err_clients: - at24_remove_dummy_clients(at24); - pm_runtime_disable(dev); - - return err; } static int at24_remove(struct i2c_client *client) { - struct at24_data *at24; - - at24 = i2c_get_clientdata(client); - - at24_remove_dummy_clients(at24); pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c index 5cdb09cba077..bfcc1d1b9b96 100644 --- a/drivers/platform/x86/dell-smo8800.c +++ b/drivers/platform/x86/dell-smo8800.c @@ -198,6 +198,7 @@ static int smo8800_remove(struct acpi_device *device) return 0; } +/* NOTE: Keep this list in sync with drivers/i2c/busses/i2c-i801.c */ static const struct acpi_device_id smo8800_ids[] = { { "SMO8800", 0 }, { "SMO8801", 0 }, diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 7850b851cecd..ba288b964dc8 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, return ret; } +EXPORT_SYMBOL_GPL(ucsi_send_command); +int ucsi_resume(struct ucsi *ucsi) +{ + struct ucsi_control ctrl; + + /* Restore UCSI notification enable mask after system resume */ + UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL); + return ucsi_send_command(ucsi, &ctrl, NULL, 0); +} +EXPORT_SYMBOL_GPL(ucsi_resume); /* -------------------------------------------------------------------------- */ void ucsi_altmode_update_active(struct ucsi_connector *con) diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 1e2981aef629..de87d0b8319d 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, void *retval, size_t size); void ucsi_altmode_update_active(struct ucsi_connector *con); +int ucsi_resume(struct ucsi *ucsi); #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE) struct typec_altmode * diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index bf63074675fc..f7a79a23ebed 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -14,6 +14,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <asm/unaligned.h> #include "ucsi.h" @@ -107,12 +109,21 @@ struct version_format { __le16 build; u8 patch; u8 ver; +#define CCG_VERSION_PATCH(x) ((x) << 16) +#define CCG_VERSION(x) ((x) << 24) #define CCG_VERSION_MIN_SHIFT (0) #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT) #define CCG_VERSION_MAJ_SHIFT (4) #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT) } __packed; +/* + * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue + * of missing interrupt when a device is connected for runtime resume + */ +#define CCG_FW_BUILD_NVIDIA (('n' << 8) | 'v') +#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10)) + struct version_info { struct version_format base; struct version_format app; @@ -170,6 +181,7 @@ struct ucsi_ccg { struct ccg_dev_info info; /* version info for boot, primary and secondary */ struct version_info version[FW2 + 1]; + u32 fw_version; /* CCG HPI communication flags */ unsigned long flags; #define RESET_PENDING 0 @@ -183,6 +195,8 @@ struct ucsi_ccg { /* fw build with vendor information */ u16 fw_build; + bool run_isr; /* flag to call ISR routine during resume */ + struct work_struct pm_work; }; static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -210,6 +224,19 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) if (quirks && quirks->max_read_len) max_read_len = quirks->max_read_len; + if (uc->fw_build == CCG_FW_BUILD_NVIDIA && + uc->fw_version <= CCG_OLD_FW_VERSION) { + mutex_lock(&uc->lock); + /* + * Do not schedule pm_work to run ISR in + * ucsi_ccg_runtime_resume() after pm_runtime_get_sync() + * since we are already in ISR path. + */ + uc->run_isr = false; + mutex_unlock(&uc->lock); + } + + pm_runtime_get_sync(uc->dev); while (rem_len > 0) { msgs[1].buf = &data[len - rem_len]; rlen = min_t(u16, rem_len, max_read_len); @@ -218,12 +245,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (status < 0) { dev_err(uc->dev, "i2c_transfer failed %d\n", status); + pm_runtime_put_sync(uc->dev); return status; } rab += rlen; rem_len -= rlen; } + pm_runtime_put_sync(uc->dev); return 0; } @@ -249,13 +278,28 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) msgs[0].len = len + sizeof(rab); msgs[0].buf = buf; + if (uc->fw_build == CCG_FW_BUILD_NVIDIA && + uc->fw_version <= CCG_OLD_FW_VERSION) { + mutex_lock(&uc->lock); + /* + * Do not schedule pm_work to run ISR in + * ucsi_ccg_runtime_resume() after pm_runtime_get_sync() + * since we are already in ISR path. + */ + uc->run_isr = false; + mutex_unlock(&uc->lock); + } + + pm_runtime_get_sync(uc->dev); status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (status < 0) { dev_err(uc->dev, "i2c_transfer failed %d\n", status); + pm_runtime_put_sync(uc->dev); kfree(buf); return status; } + pm_runtime_put_sync(uc->dev); kfree(buf); return 0; } @@ -375,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static void ccg_pm_workaround_work(struct work_struct *pm_work) +{ + struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work); + + ucsi_notify(uc->ucsi); +} + static int get_fw_info(struct ucsi_ccg *uc) { int err; @@ -384,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc) if (err < 0) return err; + uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) | + CCG_VERSION_PATCH(uc->version[FW2].app.patch); + err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), sizeof(uc->info)); if (err < 0) @@ -732,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, } /* compare input version with FWCT version */ - cur_version = le16_to_cpu(app->build) | app->patch << 16 | - app->ver << 24; + cur_version = le16_to_cpu(app->build) | CCG_VERSION_PATCH(app->patch) | + CCG_VERSION(app->ver); - new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 | - fw_cfg.app.ver << 24; + new_version = le16_to_cpu(fw_cfg.app.build) | + CCG_VERSION_PATCH(fw_cfg.app.patch) | + CCG_VERSION(fw_cfg.app.ver); if (!ccg_check_vendor_version(uc, app, &fw_cfg)) goto out_release_firmware; @@ -1078,8 +1133,10 @@ static int ucsi_ccg_probe(struct i2c_client *client, uc->ppm.sync = ucsi_ccg_sync; uc->dev = dev; uc->client = client; + uc->run_isr = true; mutex_init(&uc->lock); INIT_WORK(&uc->work, ccg_update_firmware); + INIT_WORK(&uc->pm_work, ccg_pm_workaround_work); /* Only fail FW flashing when FW build information is not provided */ status = device_property_read_u16(dev, "ccgx,firmware-build", @@ -1136,6 +1193,10 @@ static int ucsi_ccg_probe(struct i2c_client *client, if (status) dev_err(uc->dev, "cannot create sysfs group: %d\n", status); + pm_runtime_set_active(uc->dev); + pm_runtime_enable(uc->dev); + pm_runtime_idle(uc->dev); + return 0; } @@ -1143,8 +1204,10 @@ static int ucsi_ccg_remove(struct i2c_client *client) { struct ucsi_ccg *uc = i2c_get_clientdata(client); + cancel_work_sync(&uc->pm_work); cancel_work_sync(&uc->work); ucsi_unregister_ppm(uc->ucsi); + pm_runtime_disable(uc->dev); free_irq(uc->irq, uc); sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group); @@ -1157,9 +1220,56 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = { }; MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id); +static int ucsi_ccg_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ucsi_ccg *uc = i2c_get_clientdata(client); + + return ucsi_resume(uc->ucsi); +} + +static int ucsi_ccg_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int ucsi_ccg_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ucsi_ccg *uc = i2c_get_clientdata(client); + bool schedule = true; + + /* + * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue + * of missing interrupt when a device is connected for runtime resume. + * Schedule a work to call ISR as a workaround. + */ + if (uc->fw_build == CCG_FW_BUILD_NVIDIA && + uc->fw_version <= CCG_OLD_FW_VERSION) { + mutex_lock(&uc->lock); + if (!uc->run_isr) { + uc->run_isr = true; + schedule = false; + } + mutex_unlock(&uc->lock); + + if (schedule) + schedule_work(&uc->pm_work); + } + + return 0; +} + +static const struct dev_pm_ops ucsi_ccg_pm = { + .resume = ucsi_ccg_resume, + .runtime_suspend = ucsi_ccg_runtime_suspend, + .runtime_resume = ucsi_ccg_runtime_resume, +}; + static struct i2c_driver ucsi_ccg_driver = { .driver = { .name = "ucsi_ccg", + .pm = &ucsi_ccg_pm, }, .probe = ucsi_ccg_probe, .remove = ucsi_ccg_remove, |