From a4b5363a51fc78fad89368ae5b7c504bcb10f66d Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Sun, 5 May 2019 03:31:55 +0000 Subject: i2c: imx: Use __maybe_unused instead of #if CONFIG_PM Use __maybe_unused for runtime PM related functions instead of #if CONFIG_PM to simply the code. Signed-off-by: Anson Huang Reviewed-by: Dong Aisheng Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/i2c/busses') 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, -- cgit v1.2.3 From c245d94ed106c4ebb8a4bc1d08b78e3c39c38afb Mon Sep 17 00:00:00 2001 From: Rayagonda Kokatanur Date: Thu, 9 May 2019 09:51:48 +0530 Subject: i2c: iproc: Add multi byte read-write support for slave mode Add multiple byte read-write support for slave mode. Signed-off-by: Rayagonda Kokatanur Signed-off-by: Srinath Mannam Reviewed-by: Ray Jui Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm-iproc.c | 117 +++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 64 deletions(-) (limited to 'drivers/i2c/busses') 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 */ -- cgit v1.2.3 From 80e406865b8ca22c4dadb1357e4bcbcc8fe9d57f Mon Sep 17 00:00:00 2001 From: Kamal Dasu Date: Thu, 9 May 2019 14:04:36 -0700 Subject: i2c: Allow selecting BCM2835 I2C controllers on ARCH_BRCMSTB ARCH_BRCMSTB platforms have the BCM2835 I2C controllers, allow selecting the i2c-bcm2835 driver on such platforms. Signed-off-by: Kamal Dasu Signed-off-by: Florian Fainelli Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ee5dfb5aee2a..3b7055148044 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -436,7 +436,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. -- cgit v1.2.3 From c1fee0c4a2ad63147a9260939114a0f78537d051 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 20 May 2019 16:01:33 +0200 Subject: i2c: meson: update with SPDX Licence identifier Signed-off-by: Neil Armstrong Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-meson.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 90f5d0407d73..f530d9a0450b 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * I2C bus driver for Amlogic Meson SoCs * * Copyright (C) 2014 Beniamino Galvani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include -- cgit v1.2.3 From 12cb084d0dd87c36db88a2c659e4083fed0ab571 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Wed, 22 May 2019 19:05:16 +0200 Subject: i2c: jz4780: Drop dependency on MACH_JZ4780 Depending on MACH_JZ4780 prevent us from creating a generic kernel that works on more than one MIPS board. Instead, we just depend on MIPS being set. Signed-off-by: Paul Cercueil Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3b7055148044..0621f3f59213 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -692,7 +692,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. -- cgit v1.2.3 From cb7302fbe365cd079b7481720daf04e5e1925ac0 Mon Sep 17 00:00:00 2001 From: Ajay Gupta Date: Fri, 7 Jun 2019 09:34:19 -0700 Subject: i2c: nvidia-gpu: refactor master_xfer Added a local variable "send_stop" to simplify "goto" statements. The "send_stop" handles below two case 1) When first i2c start fails and so i2c stop is not sent before exiting 2) When i2c stop failed after all transfers and we do not need to send another stop before exiting. Signed-off-by: Ajay Gupta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nvidia-gpu.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 1c8f708f212b..7678a460bf9a 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c @@ -169,6 +169,7 @@ 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; /* @@ -182,37 +183,40 @@ 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); + } return status; } -- cgit v1.2.3 From d4a4f927e4ddcf70320b03a6a687d55839721f7b Mon Sep 17 00:00:00 2001 From: Ajay Gupta Date: Fri, 7 Jun 2019 09:34:20 -0700 Subject: i2c: nvidia-gpu: add runtime pm support Enable runtime pm support with autosuspend delay of three second. This is to make sure I2C client device Cypress CCGx has completed all transaction. Signed-off-by: Ajay Gupta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nvidia-gpu.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 7678a460bf9a..364244ffb5bf 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c @@ -176,6 +176,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap, * 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 */ @@ -217,6 +218,8 @@ exit: 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; } @@ -336,6 +339,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: @@ -349,10 +357,21 @@ 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); @@ -361,7 +380,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *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", -- cgit v1.2.3 From 9f2e244d0a39eb437f98324ac315e605e48636db Mon Sep 17 00:00:00 2001 From: Ajay Gupta Date: Fri, 7 Jun 2019 09:34:22 -0700 Subject: i2c: nvidia-gpu: resume ccgx i2c client Cypress USB Type-C CCGx controller firmware version 3.1.10 (which is being used in many NVIDIA GPU cards) has known issue of not triggering interrupt when a USB device is hot plugged to runtime resume the controller. If any GPU card gets latest kernel with runtime pm support but does not get latest fixed firmware then also it should continue to work and therefore a workaround is required to check for any connector change event The workaround is to request runtime resume of i2c client which is UCSI Cypress CCGx driver. CCG driver will call the ISR for any connector change event only if NVIDIA GPU has old CCG firmware with the known issue. Signed-off-by: Ajay Gupta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nvidia-gpu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 364244ffb5bf..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) @@ -268,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); @@ -281,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; @@ -377,6 +376,13 @@ 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; } -- cgit v1.2.3 From 19b07cb4a187fe5d72519491fc2d11a3a7af1219 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Thu, 6 Jun 2019 20:18:45 +0200 Subject: i2c: i801: Register optional lis3lv02d I2C device on Dell machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dell platform team told us that some (DMI whitelisted) Dell Latitude machines have ST microelectronics accelerometer at I2C address 0x29. Presence of that ST microelectronics accelerometer is verified by existence of SMO88xx ACPI device which represent that accelerometer. Unfortunately ACPI device does not specify I2C address. This patch registers lis3lv02d device for selected Dell Latitude machines at I2C address 0x29 after detection. And for Dell Vostro V131 machine at I2C address 0x1d which was manually detected. Finally commit a7ae81952cda ("i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR") allowed to use i2c-i801 driver on Dell machines so lis3lv02d correctly initialize accelerometer. Tested on Dell Latitude E6440. Signed-off-by: Pali Rohár Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 117 ++++++++++++++++++++++++++++++++++++ drivers/platform/x86/dell-smo8800.c | 1 + 2 files changed, 118 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 679c6c41f64b..c5bdaf35cd09 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1142,6 +1142,120 @@ 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; + + for (i = 0; i < ARRAY_SIZE(acpi_smo8800_ids); ++i) { + if (strcmp(hid, acpi_smo8800_ids[i]) == 0) { + *((bool *)return_value) = true; + return AE_CTRL_TERMINATE; + } + } + + return AE_OK; +} + +static bool is_dell_system_with_lis3lv02d(void) +{ + bool found; + const char *vendor; + + vendor = dmi_get_system_info(DMI_SYS_VENDOR); + if (strcmp(vendor, "Dell Inc.") != 0) + 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) { @@ -1160,6 +1274,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) {} diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c index 1d87237bc731..317bdddb6bfe 100644 --- a/drivers/platform/x86/dell-smo8800.c +++ b/drivers/platform/x86/dell-smo8800.c @@ -207,6 +207,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 }, -- cgit v1.2.3 From 095561f476abb09c2495b1e0a45a5ebb50a33b27 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Thu, 6 Jun 2019 21:52:20 +1000 Subject: i2c: fsi: Create busses for all ports Currently we only create an I2C bus for the ports listed in the device-tree for that master. There's no real reason for this since we can discover the number of ports the master supports by looking at the port_max field of the status register. This patch re-works the bus add logic so that we always create buses for each port, unless the bus is marked as unavailable in the DT. This is useful since it ensures that all the buses provided by the CFAM I2C master are accessible to debug tools. Signed-off-by: Oliver O'Halloran Reviewed-by: Eddie James Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-fsi.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/i2c/busses') 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); -- cgit v1.2.3 From c84663cbdb4d880ce6e4c7f7503f62235df66ff6 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 11 Jun 2019 03:51:08 -0700 Subject: i2c: tegra: clean up macros Clean up macros by: 1) removing unused macros 2) replace constants by macro BIT() Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index ebaa78d17d6e..1cefaa7fff44 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,21 @@ #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 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 +98,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 +123,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 -- cgit v1.2.3 From 233d0ab6ffdc1a1ada5d393c1b6ba55dbc669764 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 11 Jun 2019 03:51:09 -0700 Subject: i2c: tegra: remove unnecessary variable init Remove variable initializations in functions that are followed by assignments before use Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 1cefaa7fff44..c3de6d0d8d19 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -689,7 +689,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); @@ -1218,7 +1218,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], { 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) { @@ -1489,7 +1489,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; -- cgit v1.2.3 From 26955a7bbfca698b024e1ff750b2d8e3d3f74118 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 11 Jun 2019 03:51:10 -0700 Subject: i2c: tegra: fix alignment and spacing violations Fix checkpatch.pl alignment and blank line check(s) in i2c-tegra.c Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index c3de6d0d8d19..343b09a109b3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -295,7 +295,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; @@ -303,7 +303,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)); @@ -318,13 +318,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); } @@ -669,10 +669,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, @@ -1013,7 +1014,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; @@ -1150,9 +1152,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 ? @@ -1214,7 +1215,7 @@ 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; @@ -1260,14 +1261,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 = { @@ -1611,7 +1613,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; @@ -1680,6 +1682,7 @@ static const struct dev_pm_ops tegra_i2c_pm = { 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 -- cgit v1.2.3 From 9d174476ddc137d3b47b3336f32edaa0ad40e158 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 11 Jun 2019 03:51:11 -0700 Subject: i2c: tegra: add spinlock definition comment Fix checkpatch.pl CHECK as follows: CHECK: spinlock_t definition without comment + spinlock_t xfer_lock; Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 343b09a109b3..29e12cae55a4 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -269,6 +269,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; -- cgit v1.2.3 From fbbe4941f0dd36b5d39a4a1796aca8ce1f8efdf5 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 11 Jun 2019 03:51:12 -0700 Subject: i2c: tegra: fix msleep warning Fix checkpatch.pl WARNING for delay of approximately 1msec in flush i2c FIFO polling loop by using usleep_range(1000, 2000): WARNING: msleep < 20ms can sleep for up to 20ms; see ... Documentation/timers/timers-howto.txt + msleep(1); Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 29e12cae55a4..e5d41b58c99d 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -476,7 +476,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; } -- cgit v1.2.3 From bebff81fb8b9216eb4fba22cf910553621ae3477 Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Sat, 8 Jun 2019 10:14:43 -0700 Subject: i2c: bcm2835: Model Divider in CCF Model the I2C bus clock divider as a part of the Core Clock Framework. Primarily this removes the clk_get_rate() call from each transfer. This call causes problems for slave drivers that themselves have internal clock components that are controlled by an I2C interface. When the slave's internal clock component is prepared, the prepare lock is obtained, and it makes calls to the I2C subsystem to command the hardware to activate the clock. In order to perform the I2C transfer, this driver sets the divider, which requires it to get the parent clock rate, which it does with clk_get_rate(). Unfortunately, this function will try to take the clock prepare lock, which is already held by the slave's internal clock calls creating a deadlock. Modeling the divider in the CCF natively removes this dependency and the divider value is only set upon changing the bus clock frequency or changes in the parent clock that cascade down to this divisor. This obviates the need to set the divider with every transfer and avoids the deadlock described above. It also should provide better clock debugging and save a few cycles on each transfer due to not having to recalcuate the divider value. Signed-off-by: Annaliese McDermond Acked-by: Stefan Wahren Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 145 ++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 31 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d2fbb4bb4a43..5b556274cdb6 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include #include @@ -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,62 @@ 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, + const char *mclk_name, + struct bcm2835_i2c_dev *i2c_dev) +{ + struct clk_init_data init; + struct clk_bcm2835_i2c *priv; + char name[32]; + + snprintf(name, sizeof(name), "%s_div", dev_name(dev)); + + 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 +337,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 +346,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 +400,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) struct resource *mem, *irq; int ret; struct i2c_adapter *adap; + const char *mclk_name; + struct clk *bus_clk; + u32 bus_clk_rate; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) @@ -351,21 +416,6 @@ 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) - dev_err(&pdev->dev, "Could not get clock\n"); - return PTR_ERR(i2c_dev->clk); - } - - ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &i2c_dev->bus_clk_rate); - if (ret < 0) { - dev_warn(&pdev->dev, - "Could not read clock-frequency property\n"); - i2c_dev->bus_clk_rate = 100000; - } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "No IRQ resource\n"); @@ -380,6 +430,35 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) return -ENODEV; } + mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0); + + bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, 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", + &bus_clk_rate); + if (ret < 0) { + dev_warn(&pdev->dev, + "Could not read clock-frequency property\n"); + 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; + } + adap = &i2c_dev->adapter; i2c_set_adapdata(adap, i2c_dev); adap->owner = THIS_MODULE; @@ -402,6 +481,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); -- cgit v1.2.3 From ed7357c9f9b6a560992446c37260be25e514c4ab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 May 2019 23:50:13 +0200 Subject: i2c: s3c2410: Convert to use GPIO descriptors The S3C2410 does some funny dance around its pins: - First try to call back to the platform to get and control some GPIO pins - If this doesn't work, it tries to get a pin control handle - If this doesn't work, it retrieves two GPIOs from the device tree node and does nothing with them If we're gonna retrieve two GPIOs and do nothing with them, we might as well do it using the GPIO descriptor API. When we use the resource management API, the code gets smaller. Signed-off-by: Linus Walleij Acked-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 47 ++++++++-------------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 53bc021f4a5a..ed06a8535d63 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -122,7 +122,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; @@ -956,53 +956,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 /* @@ -1231,9 +1205,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; } -- cgit v1.2.3 From fdb7e884ad617f8aa69abdd7f39e3fdac85e081e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 1 Jun 2019 00:37:56 +0200 Subject: i2c: iop: Use GPIO descriptors The IOP3xx has some elaborate code to directly slam the GPIO lines multiplexed with I2C down low before enablement, apparently a workaround for a hardware bug found in the early chips. After consulting the developer documentation for IOP80321 and IOP80331 I can clearly see that this may be useful for IOP80321 family (mach-iop32x) but it is highly dubious for any 80331 series or later chip: in these chips the lines are not multiplexed for UARTs. We convert the code to pass optional GPIO descriptors and register these only on the 80321-based boards where it makes sense, optionally obtain them in the driver and use the gpiod_set_raw_value() to ascertain the line gets driven low when needed. The GPIO driver does not give the GPIO chip a reasonable label so the patch also adds that so that these machine descriptor tables can be used. Signed-off-by: Linus Walleij Acked-by: Arnd Bergmann Acked-by: Dan Williams Signed-off-by: Wolfram Sang --- arch/arm/include/asm/hardware/iop3xx.h | 2 ++ arch/arm/mach-iop32x/em7210.c | 3 +++ arch/arm/mach-iop32x/glantank.c | 3 +++ arch/arm/mach-iop32x/iq31244.c | 3 +++ arch/arm/mach-iop32x/iq80321.c | 3 +++ arch/arm/mach-iop32x/n2100.c | 2 ++ arch/arm/plat-iop/i2c.c | 24 ++++++++++++++++++++++++ drivers/gpio/gpio-iop.c | 1 + drivers/i2c/busses/i2c-iop3xx.c | 32 +++++++++++++++++++++----------- drivers/i2c/busses/i2c-iop3xx.h | 2 ++ 10 files changed, 64 insertions(+), 11 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h index 2594a95ff19a..a15d08160e8f 100644 --- a/arch/arm/include/asm/hardware/iop3xx.h +++ b/arch/arm/include/asm/hardware/iop3xx.h @@ -305,6 +305,8 @@ extern struct platform_device iop3xx_dma_1_channel; extern struct platform_device iop3xx_aau_channel; extern struct platform_device iop3xx_i2c0_device; extern struct platform_device iop3xx_i2c1_device; +extern struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup; +extern struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup; #endif diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c index 77e1ff057303..d2bcbac6b7f2 100644 --- a/arch/arm/mach-iop32x/em7210.c +++ b/arch/arm/mach-iop32x/em7210.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -211,6 +212,8 @@ static void __init em7210_init_machine(void) { register_iop32x_gpio(); platform_device_register(&em7210_serial_device); + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&em7210_flash_device); diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c index 547b2342d61a..4c4995007d17 100644 --- a/arch/arm/mach-iop32x/glantank.c +++ b/arch/arm/mach-iop32x/glantank.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -189,6 +190,8 @@ static void glantank_power_off(void) static void __init glantank_init_machine(void) { register_iop32x_gpio(); + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&glantank_flash_device); diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c index 0e1392b20d18..56a64ffd3824 100644 --- a/arch/arm/mach-iop32x/iq31244.c +++ b/arch/arm/mach-iop32x/iq31244.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -285,6 +286,8 @@ void ep80219_power_off(void) static void __init iq31244_init_machine(void) { register_iop32x_gpio(); + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq31244_flash_device); diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c index 66782ff1f46a..02abbf9efd54 100644 --- a/arch/arm/mach-iop32x/iq80321.c +++ b/arch/arm/mach-iop32x/iq80321.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -172,6 +173,8 @@ static struct platform_device iq80321_serial_device = { static void __init iq80321_init_machine(void) { register_iop32x_gpio(); + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); + gpiod_add_lookup_table(&iop3xx_i2c1_gpio_lookup); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq80321_flash_device); diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c index 23e8c93515d4..c780b6e82ad9 100644 --- a/arch/arm/mach-iop32x/n2100.c +++ b/arch/arm/mach-iop32x/n2100.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -345,6 +346,7 @@ device_initcall(n2100_request_gpios); static void __init n2100_init_machine(void) { register_iop32x_gpio(); + gpiod_add_lookup_table(&iop3xx_i2c0_gpio_lookup); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&n2100_flash_device); platform_device_register(&n2100_serial_device); diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c index 88215ad031a2..bac20f7f5f8a 100644 --- a/arch/arm/plat-iop/i2c.c +++ b/arch/arm/plat-iop/i2c.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,29 @@ #define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1 #endif +/* + * Each of the I2C busses have corresponding GPIO lines, and the driver + * need to access these directly to drive the bus low at times. + */ + +struct gpiod_lookup_table iop3xx_i2c0_gpio_lookup = { + .dev_id = "IOP3xx-I2C.0", + .table = { + GPIO_LOOKUP("gpio-iop", 7, "scl", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-iop", 6, "sda", GPIO_ACTIVE_HIGH), + { } + }, +}; + +struct gpiod_lookup_table iop3xx_i2c1_gpio_lookup = { + .dev_id = "IOP3xx-I2C.1", + .table = { + GPIO_LOOKUP("gpio-iop", 5, "scl", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio-iop", 4, "sda", GPIO_ACTIVE_HIGH), + { } + }, +}; + static struct resource iop3xx_i2c0_resources[] = { [0] = { .start = 0xfffff680, diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index 11b77d868c89..e9546d6c7451 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -40,6 +40,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/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index a34cb3848280..eafc1a4d8656 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "i2c-iop3xx.h" @@ -71,17 +71,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 | @@ -434,6 +433,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 2d6929c2bd92..231897838386 100644 --- a/drivers/i2c/busses/i2c-iop3xx.h +++ b/drivers/i2c/busses/i2c-iop3xx.h @@ -98,6 +98,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 */ -- cgit v1.2.3 From aa5ae06515a451d543d9ab37e2c14f97a5ba4519 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Jun 2019 19:45:27 +0300 Subject: i2c: i801: Fix kernel crash in is_dell_system_with_lis3lv02d() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit 19b07cb4a187 ("i2c: i801: Register optional lis3lv02d I2C device on Dell machines") introduced a new check in order to enumerate some slave devices on Dell machines. Though, it brings a regression on machines where DMI vendor is not set. BUG: kernel NULL pointer dereference, address: 0000000000000000 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 8 PID: 1 Comm: swapper/0 Not tainted 5.2.0-rc4-next-20190613+ #317 RIP: 0010:strcmp+0xc/0x20 To fix this crash, check if vendor field is present before accessing to it. Fixes: 19b07cb4a187 ("i2c: i801: Register optional lis3lv02d I2C device on Dell machines") Signed-off-by: Andy Shevchenko Reviewed-by: Pali Rohár Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c5bdaf35cd09..7d14b6729772 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1188,7 +1188,7 @@ static bool is_dell_system_with_lis3lv02d(void) const char *vendor; vendor = dmi_get_system_info(DMI_SYS_VENDOR); - if (strcmp(vendor, "Dell Inc.") != 0) + if (!vendor || strcmp(vendor, "Dell Inc.")) return false; /* -- cgit v1.2.3 From d680a50cb9c59669d4f695f732731ed298a31bec Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 27 May 2019 12:29:39 +0200 Subject: i2c: tegra: Avoid error message on deferred probe If the driver defers probe because of a missing clock, avoid outputting an error message. The clock will show up eventually. Signed-off-by: Thierry Reding Acked-by: Jon Hunter Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index e5d41b58c99d..30daf7341e83 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -1509,7 +1509,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); } -- cgit v1.2.3 From d9ce957d414bf871a57da332dff033a501698b9c Mon Sep 17 00:00:00 2001 From: Sagar Shrikant Kadam Date: Sat, 1 Jun 2019 11:41:14 +0530 Subject: i2c: ocores: add support for i2c device on Sifive FU540-c000 SoC Update device id table for Opencore's I2C master based re-implementation used in FU540-c000 chipset on HiFive Unleashed platform. Device ID's include Sifive, soc-specific device for chip specific tweaks and sifive IP block specific device for generic programming model. Signed-off-by: Sagar Shrikant Kadam Reviewed-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index c3dabee0aa35..b334fa2329ba 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -82,6 +82,7 @@ struct ocores_i2c { #define TYPE_OCORES 0 #define TYPE_GRLIB 1 +#define TYPE_SIFIVE_REV0 2 static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) { @@ -462,6 +463,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); -- cgit v1.2.3 From c45d4ba8673196e3adc70d4a6b3752c74dd64c98 Mon Sep 17 00:00:00 2001 From: Sagar Shrikant Kadam Date: Sat, 1 Jun 2019 11:41:15 +0530 Subject: i2c: ocores: add polling mode workaround for Sifive FU540-C000 SoC The i2c-ocore driver already has a polling mode interface.But it needs a workaround for FU540 Chipset on HiFive unleashed board (RevA00). There is an erratum in FU540 chip that prevents interrupt driven i2c transfers from working, and also the I2C controller's interrupt bit cannot be cleared if set, due to this the existing i2c polling mode interface added in mainline earlier doesn't work, and CPU stall's infinitely, when-ever i2c transfer is initiated. Ref: commit dd7dbf0eb090 ("i2c: ocores: refactor setup for polling") The workaround / fix under OCORES_FLAG_BROKEN_IRQ is particularly for FU540-COOO SoC. The polling function identifies a SiFive device based on the device node and enables the workaround. Signed-off-by: Sagar Shrikant Kadam Reviewed-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index b334fa2329ba..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; @@ -84,6 +85,8 @@ struct ocores_i2c { #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) { iowrite8(value, i2c->base + (reg << i2c->reg_shift)); @@ -236,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; @@ -353,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; + } } } @@ -595,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; @@ -677,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; -- cgit v1.2.3 From acc8abcb2a9ca26318d86f53addf952dea930ab7 Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Thu, 6 Jun 2019 22:37:47 -0700 Subject: i2c: tegra: Add suspend-resume support Post suspend I2C registers have power on reset values. Before any transfer initialize I2C registers to prevent I2C transfer timeout and implement suspend and resume callbacks needed. Fix below errors post suspend: 1) Tegra I2C transfer timeout during jetson tx2 resume: [ 27.520613] pca953x 1-0074: calling pca953x_resume+0x0/0x1b0 @ 2939, parent: i2c-1 [ 27.633623] tegra-i2c 3160000.i2c: i2c transfer timed out [ 27.639162] pca953x 1-0074: Unable to sync registers 0x3-0x5. -110 [ 27.645336] pca953x 1-0074: Failed to sync GPIO dir registers: -110 [ 27.651596] PM: dpm_run_callback(): pca953x_resume+0x0/0x1b0 returns -110 [ 27.658375] pca953x 1-0074: pca953x_resume+0x0/0x1b0 returned -110 after 127152 usecs [ 27.666194] PM: Device 1-0074 failed to resume: error -110 2) Tegra I2C transfer timeout error on jetson Xavier post resume. Remove i2c bus lock-unlock calls in resume callback as i2c_mark_adapter_* (suspended-resumed) help ensure i2c core calls from client are not executed before i2c-tegra resume. Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 30daf7341e83..1ed15af46542 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -1681,7 +1681,31 @@ 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) }; -- cgit v1.2.3 From c3c2889b8a2c9dfccca5aad647878ae0032dfc69 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 12 Jun 2019 15:26:50 +0100 Subject: i2c: qcom-geni: Signify successful driver probe The Qualcomm Geni I2C driver currently probes silently which can be confusing when debugging potential issues. Add a low level (INFO) print when each I2C controller is successfully initially set-up. Signed-off-by: Lee Jones Acked-by: Ard Biesheuvel Acked-by: Bjorn Andersson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index db075bc0d952..eec13c72d644 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -584,6 +584,8 @@ static int geni_i2c_probe(struct platform_device *pdev) return ret; } + dev_dbg(&pdev->dev, "Geni-I2C adaptor successfully added\n"); + return 0; } -- cgit v1.2.3 From c9913ac42135cf7f1c8986bcb175c5a7dda126e6 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 12 Jun 2019 15:26:49 +0100 Subject: i2c: qcom-geni: Provide support for ACPI Add a match table to allow automatic probing of ACPI device QCOM0220. Ignore clock attainment errors. Set default clock frequency value. Signed-off-by: Lee Jones Acked-by: Ard Biesheuvel Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index eec13c72d644..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 #include #include #include @@ -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"); @@ -662,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), }, }; -- cgit v1.2.3 From af668d6518dcf7106bf4eef1641d8143842dc9cc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 21 Jun 2019 14:36:24 +0300 Subject: i2c: i801: Use match_string() helper to simplify the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit match_string() returns the array index of a matching string. Use it instead of the open-coded implementation. Signed-off-by: Andy Shevchenko Reviewed-by: Pali Rohár Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 7d14b6729772..88e4dd2adbfe 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -1172,14 +1173,12 @@ static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, if (!hid) return AE_OK; - for (i = 0; i < ARRAY_SIZE(acpi_smo8800_ids); ++i) { - if (strcmp(hid, acpi_smo8800_ids[i]) == 0) { - *((bool *)return_value) = true; - return AE_CTRL_TERMINATE; - } - } + i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); + if (i < 0) + return AE_OK; - return AE_OK; + *((bool *)return_value) = true; + return AE_CTRL_TERMINATE; } static bool is_dell_system_with_lis3lv02d(void) -- cgit v1.2.3 From 79b4499524ed659fb76323efc30f3dc03967c88f Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Mon, 17 Jun 2019 09:53:01 +0200 Subject: i2c: stm32f7: fix the get_irq error cases During probe, return the "get_irq" error value instead of -EINVAL which allows the driver to be deferred probed if needed. Fix also the case where of_irq_get() returns a negative value. Note : On failure of_irq_get() returns 0 or a negative value while platform_get_irq() returns a negative value. Fixes: aeb068c57214 ("i2c: i2c-stm32f7: add driver") Reviewed-by: Pierre-Yves MORDRET Signed-off-by: Fabien Dessenne Signed-off-by: Fabrice Gasnier Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 48337bef5b87..3d90c0bb049e 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -1816,15 +1815,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 +1834,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); -- cgit v1.2.3 From 315cd67c945351f8a569500f8ab16b7fa94026e8 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 18 Jun 2019 17:06:50 +0000 Subject: i2c: i801: Add Block Write-Block Read Process Call support Add SMBUS 2.0 Block Write-Block Read Process Call command support. Signed-off-by: Alexander Sverdlin Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 2 +- drivers/i2c/busses/i2c-i801.c | 43 +++++++++++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 7 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index ee9984f35868..cafb7e05f951 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -88,7 +88,7 @@ SMBus controller. Process Call Support -------------------- -Not supported. +Block process call is supported on the 82801EB (ICH5) and later chips. I2C Block Read Support diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 88e4dd2adbfe..70d48f4fba95 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -77,7 +77,7 @@ * 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 @@ -178,6 +178,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) @@ -518,10 +519,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 */ @@ -533,12 +547,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; @@ -676,6 +690,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; @@ -807,7 +824,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, @@ -899,6 +917,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); @@ -959,6 +986,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) ? @@ -1654,6 +1683,7 @@ 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: + priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; priv->features |= FEATURE_SMBUS_PEC; @@ -1673,6 +1703,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 */ -- cgit v1.2.3 From 9be1485accd4a0375170b93f90894e7728029078 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 20 Jun 2019 13:51:26 +0300 Subject: i2c: i801: Add support for Intel Elkhart Lake Add PCI ID for Intel Elkhart Lake PCH. Signed-off-by: Jarkko Nikula Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 4 ++++ 3 files changed, 6 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index cafb7e05f951..d247edcb0f99 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -37,6 +37,7 @@ Supported adapters: * Intel Cedar Fork (PCH) * Intel Ice Lake (PCH) * Intel Comet Lake (PCH) + * Intel Elkhart Lake (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0621f3f59213..07c86cd058cd 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -143,6 +143,7 @@ config I2C_I801 Cedar Fork (PCH) Ice Lake (PCH) Comet Lake (PCH) + Elkhart Lake (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 70d48f4fba95..82005291bcf3 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -72,6 +72,7 @@ * 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 * * Features supported by this driver: * Software PEC no @@ -244,6 +245,7 @@ #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 +#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 struct i801_mux_config { char *gpio_chip; @@ -1071,6 +1073,7 @@ 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) }, { 0, } }; @@ -1683,6 +1686,7 @@ 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: priv->features |= FEATURE_BLOCK_PROC; priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; -- cgit v1.2.3 From 57ca968b69ecb741f6f8e643666e21635b6828bc Mon Sep 17 00:00:00 2001 From: Bitan Biswas Date: Tue, 18 Jun 2019 04:09:42 -0700 Subject: i2c: tegra: remove BUG() macro The usage of BUG() macro is generally discouraged in kernel, unless it's a problem that results in a physical damage or loss of data. This patch removes unnecessary BUG() macros and replaces the rest with warning. Signed-off-by: Bitan Biswas Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 47 +++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 1ed15af46542..9fcb13beeb8f 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -73,6 +73,7 @@ #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 @@ -489,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) >> @@ -515,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); @@ -523,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; @@ -581,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); @@ -847,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)) { @@ -876,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; -- cgit v1.2.3 From d308dfbf62eff897d71968d764f21a78678ee0a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Jun 2019 12:58:33 +0200 Subject: i2c: mux/i801: Switch to use descriptor passing This switches the i801 GPIO mux to use GPIO descriptors for handling the GPIO lines. The previous hack which was reaching inside the GPIO chips etc cannot live on. We pass descriptors along with the GPIO mux device at creation instead. The GPIO mux was only used by way of platform data with a platform device from one place in the kernel: the i801 i2c bus driver. Let's just associate the GPIO descriptor table with the actual device like everyone else and dynamically create a descriptor table passed along with the GPIO i2c mux. This enables simplification of the GPIO i2c mux driver to use only the descriptor API and the OF probe path gets simplified in the process. The i801 driver was registering the GPIO i2c mux with PLATFORM_DEVID_AUTO which would make it hard to predict the device name and assign the descriptor table properly, but this seems to be a mistake to begin with: all of the GPIO mux devices are hardcoded to look up GPIO lines from the "gpio_ich" GPIO chip. If there are more than one mux, there is certainly more than one gpio chip as well, and then we have more serious problems. Switch to PLATFORM_DEVID_NONE instead. There can be only one. Cc: Mika Westerberg Cc: Andy Shevchenko Cc: Peter Rosin Cc: Jean Delvare Signed-off-by: Serge Semin Signed-off-by: Linus Walleij Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg [Removed a newline, suggested by Andy. /Peter] Signed-off-by: Peter Rosin --- drivers/i2c/busses/i2c-i801.c | 37 +++++++-- drivers/i2c/muxes/i2c-mux-gpio.c | 116 ++++++++--------------------- include/linux/platform_data/i2c-mux-gpio.h | 7 -- 3 files changed, 60 insertions(+), 100 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 679c6c41f64b..bf484cd775ec 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -107,7 +107,7 @@ #include #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI -#include +#include #include #endif @@ -274,6 +274,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; @@ -1258,7 +1259,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; @@ -1270,17 +1272,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; @@ -1293,6 +1314,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) diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 13882a2a4f60..fd482feafb19 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -14,13 +14,14 @@ #include #include #include -#include +#include +#include +/* FIXME: stop poking around inside gpiolib */ #include "../../gpio/gpiolib.h" -#include struct gpiomux { struct i2c_mux_gpio_platform_data data; - unsigned gpio_base; + int ngpios; struct gpio_desc **gpios; }; @@ -30,8 +31,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) @@ -52,12 +52,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) @@ -65,8 +59,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; @@ -103,29 +97,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 @@ -142,8 +113,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) @@ -158,29 +129,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; @@ -194,7 +155,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; @@ -203,34 +163,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; } @@ -253,10 +207,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); @@ -266,14 +216,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/include/linux/platform_data/i2c-mux-gpio.h b/include/linux/platform_data/i2c-mux-gpio.h index 4406108201fe..28f288eed652 100644 --- a/include/linux/platform_data/i2c-mux-gpio.h +++ b/include/linux/platform_data/i2c-mux-gpio.h @@ -22,10 +22,6 @@ * position * @n_values: Number of multiplexer positions (busses to instantiate) * @classes: Optional I2C auto-detection classes - * @gpio_chip: Optional GPIO chip name; if set, GPIO pin numbers are given - * relative to the base GPIO number of that chip - * @gpios: Array of GPIO numbers used to control MUX - * @n_gpios: Number of GPIOs used to control MUX * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used */ struct i2c_mux_gpio_platform_data { @@ -34,9 +30,6 @@ struct i2c_mux_gpio_platform_data { const unsigned *values; int n_values; const unsigned *classes; - char *gpio_chip; - const unsigned *gpios; - int n_gpios; unsigned idle; }; -- cgit v1.2.3 From 4a5cfa39465cad25dd736d7ceba8a5d32eea4ecc Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Fri, 21 Jun 2019 03:52:49 -0700 Subject: i2c: bcm2835: Move IRQ request after clock code in probe If any of the clock code in the probe fails and returns, the IRQ will not be freed. Moving the IRQ request to last allows it to be freed on any errors further up in the probe function. devm_ calls can apparently not be used because there are some potential race conditions that will arise. Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF") Signed-off-by: Annaliese McDermond Acked-by: Stefan Wahren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 5b556274cdb6..512c63871bd3 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -416,20 +416,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c_dev->regs)) return PTR_ERR(i2c_dev->regs); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "No IRQ resource\n"); - return -ENODEV; - } - i2c_dev->irq = irq->start; - - ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, - dev_name(&pdev->dev), i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Could not request IRQ\n"); - return -ENODEV; - } - mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0); bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev); @@ -459,6 +445,20 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) return ret; } + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "No IRQ resource\n"); + return -ENODEV; + } + i2c_dev->irq = irq->start; + + ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, + dev_name(&pdev->dev), i2c_dev); + if (ret) { + dev_err(&pdev->dev, "Could not request IRQ\n"); + return -ENODEV; + } + adap = &i2c_dev->adapter; i2c_set_adapdata(adap, i2c_dev); adap->owner = THIS_MODULE; -- cgit v1.2.3 From 9de93b04df16b055824e3f1f13fedb90fbcf2e4f Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Fri, 21 Jun 2019 03:52:50 -0700 Subject: i2c: bcm2835: Ensure clock exists when probing Probe function fails to recognize that upstream clock actually doesn't yet exist because clock driver has not been initialized. Actually try to go get the clock and test for its existence before trying to set up a downstream clock based upon it. This fixes a bug that causes the i2c driver not to work with monolithic kernels. Fixes: bebff81fb8b9 ("i2c: bcm2835: Model Divider in CCF") Signed-off-by: Annaliese McDermond Acked-by: Stefan Wahren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 512c63871bd3..67752f7b0371 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -154,15 +154,18 @@ static const struct clk_ops clk_bcm2835_i2c_ops = { }; static struct clk *bcm2835_i2c_register_div(struct device *dev, - const char *mclk_name, + 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 }; @@ -400,8 +403,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) struct resource *mem, *irq; int ret; struct i2c_adapter *adap; - const char *mclk_name; struct clk *bus_clk; + struct clk *mclk; u32 bus_clk_rate; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); @@ -416,9 +419,14 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c_dev->regs)) return PTR_ERR(i2c_dev->regs); - mclk_name = of_clk_get_parent_name(pdev->dev.of_node, 0); + 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(mclk); + } - bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk_name, i2c_dev); + 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"); -- cgit v1.2.3 From d04913ec5f89f13760f8e8411c93cee542560d68 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 17 Jun 2019 10:31:17 +0200 Subject: i2c: mt7621: Add MediaTek MT7621/7628/7688 I2C driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a driver for the I2C controller found on the MediaTek MT7621/7628/7688 SoC's. The base version of this driver was done by Steven Liu (according to the copyright and MODULE_AUTHOR lines). It can be found in the OpenWRT repositories (v4.14 at the time I looked). The base driver had many issues, which are disccussed here: https://en.forum.labs.mediatek.com/t/openwrt-15-05-loads-non-working-i2c-kernel-module-for-mt7688/1286/3 >From this link an enhanced driver version (complete rewrite, mayor changes: support clock stretching, repeated start, ACK handling and unlimited message length) from Jan Breuer can be found here: https://gist.github.com/j123b567/9b555b635c2b4069d716b24198546954 This patch now adds this enhanced I2C driver to mainline. Changes by Stefan Roese for upstreaming: - Add devicetree bindings - checkpatch clean - Use module_platform_driver() - Minor cosmetic enhancements - Removed IO warpped functions - Use readl_relaxed_poll_timeout() and drop poll_down_timeout() - Removed superfluous barrier() in mtk_i2c_reset() - Use i2c_8bit_addr_from_msg() - Added I2C_FUNC_PROTOCOL_MANGLING - Removed adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; Signed-off-by: Stefan Roese Tested-by: René van Dorst Signed-off-by: Wolfram Sang --- MAINTAINERS | 7 + drivers/i2c/busses/Kconfig | 7 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-mt7621.c | 357 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 372 insertions(+) create mode 100644 drivers/i2c/busses/i2c-mt7621.c (limited to 'drivers/i2c/busses') diff --git a/MAINTAINERS b/MAINTAINERS index 429c6c624861..9fd1714e2bab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9944,6 +9944,13 @@ L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/mediatek/mt7601u/ +MEDIATEK MT7621/28/88 I2C DRIVER +M: Stefan Roese +L: linux-i2c@vger.kernel.org +S: Maintained +F: drivers/i2c/busses/i2c-mt7621.c +F: Documentation/devicetree/bindings/i2c/i2c-mt7621.txt + MEDIATEK NAND CONTROLLER DRIVER M: Xiaolei Li L: linux-mtd@lists.infradead.org diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 07c86cd058cd..68b677be1fa4 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -747,6 +747,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-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c new file mode 100644 index 000000000000..2a1cb414766d --- /dev/null +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drivers/i2c/busses/i2c-mt7621.c + * + * Copyright (C) 2013 Steven Liu + * Copyright (C) 2016 Michael Lee + * Copyright (C) 2018 Jan Breuer + * + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. + * (C) 2014 Sittisak + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = { + .owner = THIS_MODULE, + .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"); -- cgit v1.2.3 From 473fbdf7d8d345f7e57618b769fbdff9da40424d Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 4 Jun 2019 15:20:51 +0200 Subject: i2c: i2c-stm32f7: Add I2C_SMBUS_I2C_BLOCK_DATA support This patch adds the support of I2C_SMBUS_I2C_BLOCK_DATA transaction type for the stm32f7 SMBUS Controller. Use emulated I2C_SMBUS_I2C_BLOCK_DATA transactions as there is no specific hardware in STM32 I2C to manage this (e.g. like no need for PEC here). Emulated transfer will fall back calling i2c transfer method where there's already support for DMAs for example. So, use the I2C_FUNC_SMBUS_I2C_BLOCK in stm32f7_i2c_func(), and rely on emulated transfer by returning -EOPNOTSUPP in the smbus_xfer() routine for such a case. Signed-off-by: Fabrice Gasnier Reviewed-by: Pierre-Yves MORDRET Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-stm32f7.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 3d90c0bb049e..266d1c269b83 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -952,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; @@ -1802,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 = { -- cgit v1.2.3 From 856078bf642b985cbe856886d7f396b81c169ec2 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 1 Jul 2019 16:15:33 +0300 Subject: i2c: i801: Fix PCI ID sorting I managed to break sorting in PCI ID defines in my last two patches: commit 5cd1c56c42be ("i2c: i801: Add support for Intel Comet Lake") commit 9be1485accd4 ("i2c: i801: Add support for Intel Elkhart Lake") Fix them up. Signed-off-by: Jarkko Nikula Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 763a8d6cc336..dbcafbcc8e06 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -211,6 +211,7 @@ STATUS_ERROR_FLAGS) /* Older devices have their ID defined in */ +#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 @@ -228,6 +229,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 @@ -244,8 +246,6 @@ #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 -#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 struct i801_mux_config { char *gpio_chip; -- cgit v1.2.3 From 051d769f0a36b4642897d909cef980f944ae20ab Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 1 Jul 2019 16:15:34 +0300 Subject: i2c: i801: Add support for Intel Tiger Lake Add SMBUS PCI ID for Intel Tiger Lake -LP. Signed-off-by: Jarkko Nikula Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 4 ++++ 3 files changed, 6 insertions(+) (limited to 'drivers/i2c/busses') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index d247edcb0f99..04b5de80ce4e 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -38,6 +38,7 @@ Supported adapters: * Intel Ice Lake (PCH) * Intel Comet Lake (PCH) * Intel Elkhart Lake (PCH) + * Intel Tiger Lake (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 68b677be1fa4..09367fc014c3 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -144,6 +144,7 @@ config I2C_I801 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. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index dbcafbcc8e06..9db190783684 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -73,6 +73,7 @@ * 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 @@ -241,6 +242,7 @@ #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 @@ -1075,6 +1077,7 @@ static const struct pci_device_id i801_ids[] = { { 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, } }; @@ -1710,6 +1713,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) 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; -- cgit v1.2.3 From 998bcae4d6267f9737d758dc648851318a29ddde Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Sun, 23 Jun 2019 23:13:53 +0200 Subject: i2c: cpm: remove casting dma_alloc Generated by: alloc_cast.cocci Signed-off-by: Vasyl Gomonovych Acked-by: Jochen Friedrich Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-cpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 8a8ca945561b..72b539c4f561 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -540,7 +540,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; -- cgit v1.2.3 From cc6b9dfb2c5769afeb3335048173c730bdf8dbe1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 29 Jun 2019 02:44:21 +0000 Subject: i2c: mt7621: Fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Reviewed-by: Stefan Roese Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mt7621.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/i2c/busses') diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 2a1cb414766d..62df8379bc89 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -343,7 +343,6 @@ static struct platform_driver mtk_i2c_driver = { .probe = mtk_i2c_probe, .remove = mtk_i2c_remove, .driver = { - .owner = THIS_MODULE, .name = "i2c-mt7621", .of_match_table = i2c_mtk_dt_ids, }, -- cgit v1.2.3