From c81109332068b44db4fd7b650c0e6bc0fc1411f1 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 19 Nov 2012 16:31:42 +0530 Subject: i2c: core: Remove definition of i2c_smbus_process_call i2c_smbus_process_call has no users in the kernel, so this can be removed. Documentation for the same has been updated accordingly. Fixes following sparse warning. drivers/i2c/i2c-core.c:1871:5: warning: symbol 'i2c_smbus_process_call' was not declared. Should it be static? [wsa: updated the documentation] Signed-off-by: Tushar Behera Signed-off-by: Wolfram Sang --- Documentation/i2c/smbus-protocol | 4 ++-- Documentation/i2c/writing-clients | 4 ++-- drivers/i2c/i2c-core.c | 23 ----------------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index d1f22618e14..6012b12b351 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -137,8 +137,8 @@ available for writes where the two data bytes are the other way around (not SMBus compliant, but very popular.) -SMBus Process Call: i2c_smbus_process_call() -============================================= +SMBus Process Call: +=================== This command selects a device register (through the Comm byte), sends 16 bits of data to it, and reads 16 bits of data in return. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 3a94b0e6f60..6b344b516bf 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -365,8 +365,6 @@ in terms of it. Never use this function directly! s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command); s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value); - s32 i2c_smbus_process_call(struct i2c_client *client, - u8 command, u16 value); s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values); s32 i2c_smbus_write_block_data(struct i2c_client *client, @@ -381,6 +379,8 @@ These ones were removed from i2c-core because they had no users, but could be added back later if needed: s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value); + s32 i2c_smbus_process_call(struct i2c_client *client, + u8 command, u16 value); s32 i2c_smbus_block_process_call(struct i2c_client *client, u8 command, u8 length, u8 *values); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e388590b44a..66a30f7ac88 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1865,29 +1865,6 @@ s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, } EXPORT_SYMBOL(i2c_smbus_write_word_data); -/** - * i2c_smbus_process_call - SMBus "process call" protocol - * @client: Handle to slave device - * @command: Byte interpreted by slave - * @value: 16-bit "word" being written - * - * This executes the SMBus "process call" protocol, returning negative errno - * else a 16-bit unsigned "word" received from the device. - */ -s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command, - u16 value) -{ - union i2c_smbus_data data; - int status; - data.word = value; - - status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_PROC_CALL, &data); - return (status < 0) ? status : data.word; -} -EXPORT_SYMBOL(i2c_smbus_process_call); - /** * i2c_smbus_read_block_data - SMBus "block read" protocol * @client: Handle to slave device -- cgit v1.2.3 From 81e34f913402284deed1a74ad7dcfa79396cbcc4 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Wed, 5 Dec 2012 10:43:07 +0100 Subject: drivers: misc: at24: mention other supported types in Kconfig As the at24 driver is able handle a bunch of serial storage chips other than EEPROMs this is now mentioned in Kconfig. Signed-off-by: Lars Poeschel Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index c9e695ea7c9..04f2e1fa9dd 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -1,13 +1,14 @@ menu "EEPROM support" config EEPROM_AT24 - tristate "I2C EEPROMs from most vendors" + tristate "I2C EEPROMs / RAMs / ROMs from most vendors" depends on I2C && SYSFS help - Enable this driver to get read/write support to most I2C EEPROMs, - after you configure the driver to know about each EEPROM on - your target board. Use these generic chip names, instead of - vendor-specific ones like at24c64 or 24lc02: + Enable this driver to get read/write support to most I2C EEPROMs + and compatible devices like FRAMs, SRAMs, ROMs etc. After you + configure the driver to know about each chip on your target + board. Use these generic chip names, instead of vendor-specific + ones like at24c64, 24lc02 or fm24c04: 24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08, 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024 -- cgit v1.2.3 From 5c38dc8911b86b7c49305e2f2b631cd1241f2d87 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Thu, 10 Jan 2013 15:07:42 +0100 Subject: i2c: nforce2: fix coding style issues avoid these checkpatch.pl issues : - ERROR: "foo * bar" should be "foo *bar" - ERROR: switch and case should be at the same indent - ERROR: "(foo*)" should be "(foo *)" - ERROR: do not use assignment in if condition - ERROR: space required before the open parenthesis '(' - WARNING: suspect code indent for conditional statements - WARNING: quoted string split across lines - WARNING: space prohibited between function name and open parenthesis '(' - WARNING: line over 80 characters also add spaces around some "+", "=", "*" Signed-off-by: Laurent Navet Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nforce2.c | 152 +++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index adac8542771..ac88f4000cc 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -60,7 +60,7 @@ #include MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Hans-Frieder Vogt "); +MODULE_AUTHOR("Hans-Frieder Vogt "); MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver"); @@ -188,9 +188,9 @@ static int nforce2_check_status(struct i2c_adapter *adap) } /* Return negative errno on error */ -static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, +static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, - u8 command, int size, union i2c_smbus_data * data) + u8 command, int size, union i2c_smbus_data *data) { struct nforce2_smbus *smbus = adap->algo_data; unsigned char protocol, pec; @@ -202,56 +202,54 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0; switch (size) { + case I2C_SMBUS_QUICK: + protocol |= NVIDIA_SMB_PRTCL_QUICK; + read_write = I2C_SMBUS_WRITE; + break; - case I2C_SMBUS_QUICK: - protocol |= NVIDIA_SMB_PRTCL_QUICK; - read_write = I2C_SMBUS_WRITE; - break; - - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, NVIDIA_SMB_CMD); - protocol |= NVIDIA_SMB_PRTCL_BYTE; - break; - - case I2C_SMBUS_BYTE_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, NVIDIA_SMB_DATA); - protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA; - break; - - case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word, NVIDIA_SMB_DATA); - outb_p(data->word >> 8, NVIDIA_SMB_DATA+1); - } - protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; - break; - - case I2C_SMBUS_BLOCK_DATA: - outb_p(command, NVIDIA_SMB_CMD); - if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { - dev_err(&adap->dev, - "Transaction failed " - "(requested block size: %d)\n", - len); - return -EINVAL; - } - outb_p(len, NVIDIA_SMB_BCNT); - for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) - outb_p(data->block[i + 1], - NVIDIA_SMB_DATA+i); + protocol |= NVIDIA_SMB_PRTCL_BYTE; + break; + + case I2C_SMBUS_BYTE_DATA: + outb_p(command, NVIDIA_SMB_CMD); + if (read_write == I2C_SMBUS_WRITE) + outb_p(data->byte, NVIDIA_SMB_DATA); + protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA; + break; + + case I2C_SMBUS_WORD_DATA: + outb_p(command, NVIDIA_SMB_CMD); + if (read_write == I2C_SMBUS_WRITE) { + outb_p(data->word, NVIDIA_SMB_DATA); + outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1); + } + protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; + break; + + case I2C_SMBUS_BLOCK_DATA: + outb_p(command, NVIDIA_SMB_CMD); + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { + dev_err(&adap->dev, + "Transaction failed (requested block size: %d)\n", + len); + return -EINVAL; } - protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; - break; + outb_p(len, NVIDIA_SMB_BCNT); + for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) + outb_p(data->block[i + 1], + NVIDIA_SMB_DATA + i); + } + protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; + break; - default: - dev_err(&adap->dev, "Unsupported transaction %d\n", size); - return -EOPNOTSUPP; + default: + dev_err(&adap->dev, "Unsupported transaction %d\n", size); + return -EOPNOTSUPP; } outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); @@ -265,28 +263,28 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, return 0; switch (size) { - - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: - data->byte = inb_p(NVIDIA_SMB_DATA); - break; - - case I2C_SMBUS_WORD_DATA: - data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); - break; - - case I2C_SMBUS_BLOCK_DATA: - len = inb_p(NVIDIA_SMB_BCNT); - if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { - dev_err(&adap->dev, "Transaction failed " - "(received block size: 0x%02x)\n", - len); - return -EPROTO; - } - for (i = 0; i < len; i++) - data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); - data->block[0] = len; - break; + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = inb_p(NVIDIA_SMB_DATA); + break; + + case I2C_SMBUS_WORD_DATA: + data->word = inb_p(NVIDIA_SMB_DATA) | + (inb_p(NVIDIA_SMB_DATA + 1) << 8); + break; + + case I2C_SMBUS_BLOCK_DATA: + len = inb_p(NVIDIA_SMB_BCNT); + if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { + dev_err(&adap->dev, + "Transaction failed (received block size: 0x%02x)\n", + len); + return -EPROTO; + } + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(NVIDIA_SMB_DATA + i); + data->block[0] = len; + break; } return 0; @@ -299,7 +297,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PEC | - (((struct nforce2_smbus*)adapter->algo_data)->blockops ? + (((struct nforce2_smbus *)adapter->algo_data)->blockops ? I2C_FUNC_SMBUS_BLOCK_DATA : 0); } @@ -327,7 +325,7 @@ static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { { 0 } }; -MODULE_DEVICE_TABLE (pci, nforce2_ids); +MODULE_DEVICE_TABLE(pci, nforce2_ids); static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, @@ -377,7 +375,8 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, release_region(smbus->base, smbus->size); return error; } - dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base); + dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", + smbus->base); return 0; } @@ -388,11 +387,12 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) int res1, res2; /* we support 2 SMBus adapters */ - if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL))) + smbuses = kzalloc(2 * sizeof(struct nforce2_smbus), GFP_KERNEL); + if (!smbuses) return -ENOMEM; pci_set_drvdata(dev, smbuses); - switch(dev->device) { + switch (dev->device) { case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: -- cgit v1.2.3 From 17a76b4b32aca7c19df6988213dfe2eb4b631431 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 17 Jan 2013 12:31:05 +0200 Subject: i2c-designware: always set the STOP bit after last byte If IC_EMPTYFIFO_HOLD_MASTER_EN is set to one, the DesignWare I2C controller doesn't generate STOP on the bus when the FIFO is empty. This violates the rules of Linux I2C stack as it requires that the STOP is issued once the i2c_transfer() is finished. However, there is no way to detect this from the hardware registers, so we must make sure that the STOP bit is always set once the last byte of the last message is transferred. This patch is based on the work of Dirk Brandewie. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index f5258c205de..94fd8187540 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -413,11 +413,23 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR); while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { + u32 cmd = 0; + + /* + * If IC_EMPTYFIFO_HOLD_MASTER_EN is set we must + * manually set the stop bit. However, it cannot be + * detected from the registers so we set it always + * when writing/reading the last byte. + */ + if (dev->msg_write_idx == dev->msgs_num - 1 && + buf_len == 1) + cmd |= BIT(9); + if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { - dw_writel(dev, 0x100, DW_IC_DATA_CMD); + dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD); rx_limit--; } else - dw_writel(dev, *buf++, DW_IC_DATA_CMD); + dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD); tx_limit--; buf_len--; } -- cgit v1.2.3 From 7272194ed391f9db8bb320c50d715e7e6bba8ff3 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 17 Jan 2013 12:31:06 +0200 Subject: i2c-designware: add minimal support for runtime PM In order to save power the device should be put to low power states whenever it is not being used. We implement this by enabling minimal runtime PM support. There isn't much to do for the device itself as it is disabled once the last transfer is completed but subsystem/domain runtime PM hooks can save more power by power gating the device etc. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 343357a2b5b..d8afc85420b 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include "i2c-designware-core.h" @@ -149,6 +150,10 @@ static int dw_i2c_probe(struct platform_device *pdev) } of_i2c_register_devices(adap); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_put(&pdev->dev); + return 0; err_free_irq: @@ -175,6 +180,8 @@ static int dw_i2c_remove(struct platform_device *pdev) struct resource *mem; platform_set_drvdata(pdev, NULL); + pm_runtime_get_sync(&pdev->dev); + i2c_del_adapter(&dev->adapter); put_device(&pdev->dev); @@ -186,6 +193,9 @@ static int dw_i2c_remove(struct platform_device *pdev) free_irq(dev->irq, dev); kfree(dev); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); return 0; -- cgit v1.2.3 From b61b14154b19e1ef1da9c1e283f0cf93470e0c70 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 17 Jan 2013 12:31:07 +0200 Subject: i2c-designware: add support for Intel Lynxpoint Intel Lynxpoint has two I2C controllers. These controllers are enumerated from ACPI namespace with IDs INT33C2 and INT33C3. Add support for these to the I2C DesignWare platform driver. This is based on the work of Dirk Brandewie. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 49 +++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d8afc85420b..d2a33e93f8a 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "i2c-designware-core.h" static struct i2c_algorithm i2c_dw_algo = { @@ -51,6 +52,42 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) return clk_get_rate(dev->clk)/1000; } +#ifdef CONFIG_ACPI +static int dw_i2c_acpi_configure(struct platform_device *pdev) +{ + struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct acpi_device *adev; + int busno, ret; + + if (!ACPI_HANDLE(&pdev->dev)) + return -ENODEV; + + ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); + if (ret) + return -ENODEV; + + dev->adapter.nr = -1; + if (adev->pnp.unique_id && !kstrtoint(adev->pnp.unique_id, 0, &busno)) + dev->adapter.nr = busno; + + dev->tx_fifo_depth = 32; + dev->rx_fifo_depth = 32; + return 0; +} + +static const struct acpi_device_id dw_i2c_acpi_match[] = { + { "INT33C2", 0 }, + { "INT33C3", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); +#else +static inline int dw_i2c_acpi_configure(struct platform_device *pdev) +{ + return -ENODEV; +} +#endif + static int dw_i2c_probe(struct platform_device *pdev) { struct dw_i2c_dev *dev; @@ -115,18 +152,22 @@ static int dw_i2c_probe(struct platform_device *pdev) r = -EBUSY; goto err_unuse_clocks; } - { + + /* Try first if we can configure the device from ACPI */ + r = dw_i2c_acpi_configure(pdev); + if (r) { u32 param1 = i2c_dw_read_comp_param(dev); dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; + dev->adapter.nr = pdev->id; } r = i2c_dw_init(dev); if (r) goto err_iounmap; i2c_dw_disable_int(dev); - r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev); + r = request_irq(dev->irq, i2c_dw_isr, IRQF_SHARED, pdev->name, dev); if (r) { dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); goto err_iounmap; @@ -141,14 +182,15 @@ static int dw_i2c_probe(struct platform_device *pdev) adap->algo = &i2c_dw_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; + ACPI_HANDLE_SET(&adap->dev, ACPI_HANDLE(&pdev->dev)); - adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); if (r) { dev_err(&pdev->dev, "failure adding adapter\n"); goto err_free_irq; } of_i2c_register_devices(adap); + acpi_i2c_register_devices(adap); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -243,6 +285,7 @@ static struct platform_driver dw_i2c_driver = { .name = "i2c_designware", .owner = THIS_MODULE, .of_match_table = of_match_ptr(dw_i2c_of_match), + .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), .pm = &dw_i2c_dev_pm_ops, }, }; -- cgit v1.2.3 From 2a2897bab2d3d50ab466cf908f03b62801f1ff56 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Sat, 5 Jan 2013 17:34:46 +0530 Subject: i2c: tegra: add support for Tegra114 SoC NVIDIA's Tegra114 has following enhanced feature in i2c controller: - Enable/disable control for per packet transfer complete interrupt. Earlier SoCs could not disable this. - Single clock source for standard/fast and HS mode clock speed. The clock divisor for fast/standard mode is added into the i2c controller to meet the HS and standard/fast mode of clock speed from single source. Add support for the above feature to make it functional on T114 SOCs. Signed-off-by: Laxman Dewangan Reviewed-by: Stephen Warren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 77 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 7b38877ffec..2dadb964c46 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -71,6 +71,8 @@ #define I2C_INT_TX_FIFO_DATA_REQ (1<<1) #define I2C_INT_RX_FIFO_DATA_REQ (1<<0) #define I2C_CLK_DIVISOR 0x06c +#define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16 +#define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8 #define DVC_CTRL_REG1 0x000 #define DVC_CTRL_REG1_INTR_EN (1<<10) @@ -117,10 +119,23 @@ enum msg_end_type { /** * struct tegra_i2c_hw_feature : Different HW support on Tegra * @has_continue_xfer_support: Continue transfer supports. + * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer + * complete interrupt per packet basis. + * @has_single_clk_source: The i2c controller has single clock source. Tegra30 + * and earlier Socs has two clock sources i.e. div-clk and + * fast-clk. + * @clk_divisor_hs_mode: Clock divisor in HS mode. + * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is + * applicable if there is no fast clock source i.e. single clock + * source. */ struct tegra_i2c_hw_feature { bool has_continue_xfer_support; + bool has_per_pkt_xfer_complete_irq; + bool has_single_clk_source; + int clk_divisor_hs_mode; + int clk_divisor_std_fast_mode; }; /** @@ -366,11 +381,13 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) { int ret; - ret = clk_prepare_enable(i2c_dev->fast_clk); - if (ret < 0) { - dev_err(i2c_dev->dev, - "Enabling fast clk failed, err %d\n", ret); - return ret; + if (!i2c_dev->hw->has_single_clk_source) { + ret = clk_prepare_enable(i2c_dev->fast_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, + "Enabling fast clk failed, err %d\n", ret); + return ret; + } } ret = clk_prepare_enable(i2c_dev->div_clk); if (ret < 0) { @@ -384,13 +401,16 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) { clk_disable_unprepare(i2c_dev->div_clk); - clk_disable_unprepare(i2c_dev->fast_clk); + if (!i2c_dev->hw->has_single_clk_source) + clk_disable_unprepare(i2c_dev->fast_clk); } static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; int err = 0; + int clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE; + u32 clk_divisor; tegra_i2c_clock_enable(i2c_dev); @@ -405,7 +425,15 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); - clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); + + clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1); + clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * clk_multiplier); + + /* Make sure clock divisor programmed correctly */ + clk_divisor = i2c_dev->hw->clk_divisor_hs_mode; + clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode << + I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT; + i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR); if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); @@ -547,6 +575,8 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, tegra_i2c_fill_tx_fifo(i2c_dev); int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; + if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) + int_mask |= I2C_INT_PACKET_XFER_COMPLETE; if (msg->flags & I2C_M_RD) int_mask |= I2C_INT_RX_FIFO_DATA_REQ; else if (i2c_dev->msg_buf_remaining) @@ -634,15 +664,32 @@ static const struct i2c_algorithm tegra_i2c_algo = { static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_continue_xfer_support = false, + .has_per_pkt_xfer_complete_irq = false, + .has_single_clk_source = false, + .clk_divisor_hs_mode = 3, + .clk_divisor_std_fast_mode = 0, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = false, + .has_single_clk_source = false, + .clk_divisor_hs_mode = 3, + .clk_divisor_std_fast_mode = 0, +}; + +static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .has_single_clk_source = true, + .clk_divisor_hs_mode = 1, + .clk_divisor_std_fast_mode = 0x19, }; #if defined(CONFIG_OF) /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, @@ -688,12 +735,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) return PTR_ERR(div_clk); } - fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); - if (IS_ERR(fast_clk)) { - dev_err(&pdev->dev, "missing bus clock"); - return PTR_ERR(fast_clk); - } - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); if (!i2c_dev) { dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev"); @@ -702,7 +743,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->base = base; i2c_dev->div_clk = div_clk; - i2c_dev->fast_clk = fast_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; @@ -733,6 +773,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) } init_completion(&i2c_dev->msg_complete); + if (!i2c_dev->hw->has_single_clk_source) { + fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); + if (IS_ERR(fast_clk)) { + dev_err(&pdev->dev, "missing fast clock"); + return PTR_ERR(fast_clk); + } + i2c_dev->fast_clk = fast_clk; + } + platform_set_drvdata(pdev, i2c_dev); ret = tegra_i2c_init(i2c_dev); -- cgit v1.2.3 From 631056c399d2bdf34ee147c99401fee093ee4bfe Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 5 Dec 2012 22:42:12 +0100 Subject: i2c: at91: add of_device_id entry for at91rm9200 Signed-off-by: Joachim Eastwood Acked-by: Ludovic Ddesroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 2bfc04d0a1b..3e287d83893 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -584,6 +584,9 @@ static const struct platform_device_id at91_twi_devtypes[] = { #if defined(CONFIG_OF) static const struct of_device_id atmel_twi_dt_ids[] = { { + .compatible = "atmel,at91rm9200-i2c", + .data = &at91rm9200_config, + } , { .compatible = "atmel,at91sam9260-i2c", .data = &at91sam9260_config, } , { -- cgit v1.2.3 From 24e9e157d5197e469a414d0f52ce04e8b539a715 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 24 Jan 2013 09:47:22 +0100 Subject: i2c: nomadik: adopt pinctrl support Amend the I2C nomadik pin controller to optionally take a pin control handle and set the state of the pins to: - "default" on boot, resume and before performing an i2c transfer - "idle" after initial default, after resume default, and after each i2c xfer - "sleep" on suspend() This should make it possible to optimize energy usage for the pins both for the suspend/resume cycle, and for runtime cases inbetween I2C transfers. Signed-off-by: Patrice Chotard Signed-off-by: Linus Walleij [wsa: fixed braces on one else-branch] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 8b2ffcf4532..dd6a6913bd7 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -26,6 +26,7 @@ #include #include #include +#include #define DRIVER_NAME "nmk-i2c" @@ -147,6 +148,10 @@ struct i2c_nmk_client { * @stop: stop condition. * @xfer_complete: acknowledge completion for a I2C message. * @result: controller propogated result. + * @pinctrl: pinctrl handle. + * @pins_default: default state for the pins. + * @pins_idle: idle state for the pins. + * @pins_sleep: sleep state for the pins. * @busy: Busy doing transfer. */ struct nmk_i2c_dev { @@ -160,6 +165,11 @@ struct nmk_i2c_dev { int stop; struct completion xfer_complete; int result; + /* Three pin states - default, idle & sleep */ + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_idle; + struct pinctrl_state *pins_sleep; bool busy; }; @@ -636,6 +646,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, goto out_clk; } + /* Optionaly enable pins to be muxed in and configured */ + if (!IS_ERR(dev->pins_default)) { + status = pinctrl_select_state(dev->pinctrl, + dev->pins_default); + if (status) + dev_err(&dev->adev->dev, + "could not set default pins\n"); + } + status = init_hw(dev); if (status) goto out; @@ -663,6 +682,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, out: clk_disable_unprepare(dev->clk); out_clk: + /* Optionally let pins go into idle state */ + if (!IS_ERR(dev->pins_idle)) { + status = pinctrl_select_state(dev->pinctrl, + dev->pins_idle); + if (status) + dev_err(&dev->adev->dev, + "could not set pins to idle state\n"); + } + pm_runtime_put_sync(&dev->adev->dev); dev->busy = false; @@ -857,15 +885,41 @@ static int nmk_i2c_suspend(struct device *dev) { struct amba_device *adev = to_amba_device(dev); struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + int ret; if (nmk_i2c->busy) return -EBUSY; + if (!IS_ERR(nmk_i2c->pins_sleep)) { + ret = pinctrl_select_state(nmk_i2c->pinctrl, + nmk_i2c->pins_sleep); + if (ret) + dev_err(dev, "could not set pins to sleep state\n"); + } + return 0; } static int nmk_i2c_resume(struct device *dev) { + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + int ret; + + /* First go to the default state */ + if (!IS_ERR(nmk_i2c->pins_default)) { + ret = pinctrl_select_state(nmk_i2c->pinctrl, + nmk_i2c->pins_default); + if (ret) + dev_err(dev, "could not set pins to default state\n"); + } + /* Then let's idle the pins until the next transfer happens */ + if (!IS_ERR(nmk_i2c->pins_idle)) { + ret = pinctrl_select_state(nmk_i2c->pinctrl, + nmk_i2c->pins_idle); + if (ret) + dev_err(dev, "could not set pins to idle state\n"); + } return 0; } #else @@ -953,6 +1007,40 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) dev->adev = adev; amba_set_drvdata(adev, dev); + dev->pinctrl = devm_pinctrl_get(&adev->dev); + if (IS_ERR(dev->pinctrl)) { + ret = PTR_ERR(dev->pinctrl); + goto err_pinctrl; + } + + dev->pins_default = pinctrl_lookup_state(dev->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(dev->pins_default)) { + dev_err(&adev->dev, "could not get default pinstate\n"); + } else { + ret = pinctrl_select_state(dev->pinctrl, + dev->pins_default); + if (ret) + dev_dbg(&adev->dev, "could not set default pinstate\n"); + } + + dev->pins_idle = pinctrl_lookup_state(dev->pinctrl, + PINCTRL_STATE_IDLE); + if (IS_ERR(dev->pins_idle)) { + dev_dbg(&adev->dev, "could not get idle pinstate\n"); + } else { + /* If possible, let's go to idle until the first transfer */ + ret = pinctrl_select_state(dev->pinctrl, + dev->pins_idle); + if (ret) + dev_dbg(&adev->dev, "could not set idle pinstate\n"); + } + + dev->pins_sleep = pinctrl_lookup_state(dev->pinctrl, + PINCTRL_STATE_SLEEP); + if (IS_ERR(dev->pins_sleep)) + dev_dbg(&adev->dev, "could not get sleep pinstate\n"); + dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res)); if (!dev->virtbase) { ret = -ENOMEM; @@ -1022,6 +1110,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) err_no_ioremap: amba_set_drvdata(adev, NULL); kfree(dev); + err_pinctrl: err_no_mem: return ret; -- cgit v1.2.3 From 876ae85c8b811668c2c115ea78c2241f562977fb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 24 Jan 2013 11:27:46 +0100 Subject: i2c: nomadik: drop superfluous variable initialization cppcheck rightfully reports those as "reassigned a value before the old one has been used." Signed-off-by: Wolfram Sang Cc: Linus Walleij --- drivers/i2c/busses/i2c-nomadik.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index dd6a6913bd7..5b1b1948128 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -412,8 +412,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; - u32 mcr; - u32 irq_mask = 0; + u32 mcr, irq_mask; int timeout; mcr = load_i2c_mcr_reg(dev, flags); @@ -482,8 +481,7 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; - u32 mcr; - u32 irq_mask = 0; + u32 mcr, irq_mask; int timeout; mcr = load_i2c_mcr_reg(dev, flags); @@ -731,8 +729,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) struct nmk_i2c_dev *dev = arg; u32 tft, rft; u32 count; - u32 misr; - u32 src = 0; + u32 misr, src; /* load Tx FIFO and Rx FIFO threshold values */ tft = readl(dev->virtbase + I2C_TFTR); -- cgit v1.2.3 From 669da30d4c972fe62e14a435abf909d19d9b9467 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 24 Jan 2013 15:41:06 +0530 Subject: i2c: s3c2410: Remove unnecessary label err_noclk err_noclk label redirects to a simple return statement. Move the return statement to the caller location and remove the label. Signed-off-by: Tushar Behera Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index a290d089cea..b7ca1f49d54 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1000,8 +1000,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!i2c->pdata) { - ret = -ENOMEM; - goto err_noclk; + dev_err(&pdev->dev, "no memory for platform data\n"); + return -ENOMEM; } i2c->quirks = s3c24xx_get_device_quirks(pdev); @@ -1025,8 +1025,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->clk = clk_get(&pdev->dev, "i2c"); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); - ret = -ENOENT; - goto err_noclk; + return -ENOENT; } dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); @@ -1133,8 +1132,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) err_clk: clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); - - err_noclk: return ret; } -- cgit v1.2.3 From 2b255b947f39d9360662abf6667957add6064646 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 24 Jan 2013 15:41:07 +0530 Subject: i2c: s3c2410: Convert to use devm_* APIs i2c-s3c2410 driver is modified to use devm_clk_get() and devm_request_irq(). This also simplifies the return path in driver's probe. Signed-off-by: Tushar Behera Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index b7ca1f49d54..4b6cc130eb7 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1022,7 +1022,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) /* find the clock and enable it */ i2c->dev = &pdev->dev; - i2c->clk = clk_get(&pdev->dev, "i2c"); + i2c->clk = devm_clk_get(&pdev->dev, "i2c"); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); return -ENOENT; @@ -1044,7 +1044,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->regs = devm_request_and_ioremap(&pdev->dev, res); if (i2c->regs == NULL) { - dev_err(&pdev->dev, "cannot map IO\n"); + dev_err(&pdev->dev, "cannot request and map IO\n"); ret = -ENXIO; goto err_clk; } @@ -1084,8 +1084,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) goto err_clk; } - ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, - dev_name(&pdev->dev), i2c); + ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0, + dev_name(&pdev->dev), i2c); if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); @@ -1095,7 +1095,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_register_cpufreq(i2c); if (ret < 0) { dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); - goto err_irq; + goto err_clk; } /* Note, previous versions of the driver used i2c_add_adapter() @@ -1126,12 +1126,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) err_cpufreq: s3c24xx_i2c_deregister_cpufreq(i2c); - err_irq: - free_irq(i2c->irq, i2c); - err_clk: clk_disable_unprepare(i2c->clk); - clk_put(i2c->clk); return ret; } @@ -1150,10 +1146,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) s3c24xx_i2c_deregister_cpufreq(i2c); i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); clk_disable_unprepare(i2c->clk); - clk_put(i2c->clk); if (pdev->dev.of_node && IS_ERR(i2c->pctrl)) s3c24xx_i2c_dt_gpio_free(i2c); -- cgit v1.2.3 From d16933b33914a6dff38a4ecbe8edce44a17898e8 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 24 Jan 2013 15:41:08 +0530 Subject: i2c: s3c2410: Move location of clk_prepare_enable() call in probe function In i2c-s3c2410 driver probe, only s3c24xx_i2c_init() needs the I2C clock to be enabled. Moving clk_prepare_enable() and clk_disable_unprepare() calls to around this function simplifies the return path of probe call. Signed-off-by: Tushar Behera Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4b6cc130eb7..4d1ba8d7d34 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1030,23 +1030,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); - clk_prepare_enable(i2c->clk); /* map the registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err_clk; + return -ENOENT; } i2c->regs = devm_request_and_ioremap(&pdev->dev, res); if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot request and map IO\n"); - ret = -ENXIO; - goto err_clk; + return -ENXIO; } dev_dbg(&pdev->dev, "registers %p (%p)\n", @@ -1064,16 +1061,18 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->pdata->cfg_gpio) { i2c->pdata->cfg_gpio(to_platform_device(i2c->dev)); } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) { - ret = -EINVAL; - goto err_clk; + return -EINVAL; } /* initialise the i2c controller */ + clk_prepare_enable(i2c->clk); ret = s3c24xx_i2c_init(i2c); - if (ret != 0) - goto err_clk; - + clk_disable_unprepare(i2c->clk); + if (ret != 0) { + dev_err(&pdev->dev, "I2C controller init failed\n"); + return ret; + } /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending */ @@ -1081,7 +1080,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) i2c->irq = ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_clk; + return ret; } ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0, @@ -1089,13 +1088,13 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_clk; + return ret; } ret = s3c24xx_i2c_register_cpufreq(i2c); if (ret < 0) { dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); - goto err_clk; + return ret; } /* Note, previous versions of the driver used i2c_add_adapter() @@ -1120,14 +1119,10 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) pm_runtime_enable(&i2c->adap.dev); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); - clk_disable_unprepare(i2c->clk); return 0; err_cpufreq: s3c24xx_i2c_deregister_cpufreq(i2c); - - err_clk: - clk_disable_unprepare(i2c->clk); return ret; } -- cgit v1.2.3 From dc6fea4456aeadd3452638668101f269fbb9fd0d Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 24 Jan 2013 15:41:09 +0530 Subject: i2c: s3c2410: Remove err_cpufreq label err_cpufreq label is now used only once. It can be removed and related code can be moved to the caller location. Signed-off-by: Tushar Behera Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-s3c2410.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4d1ba8d7d34..3479ca76d2a 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1109,7 +1109,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto err_cpufreq; + s3c24xx_i2c_deregister_cpufreq(i2c); + return ret; } of_i2c_register_devices(&i2c->adap); @@ -1120,10 +1121,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); return 0; - - err_cpufreq: - s3c24xx_i2c_deregister_cpufreq(i2c); - return ret; } /* s3c24xx_i2c_remove -- cgit v1.2.3 From fc91e401239a451f7f4269de0b0ae6d70d856d48 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 24 Jan 2013 13:56:21 +0100 Subject: i2c: mxs: Add PIO and mixed-DMA support Add support for the PIO mode and mixed PIO/DMA mode support. The mixed PIO/DMA is the default mode of operation. This shall leverage overhead that the driver creates due to setting up DMA descriptors even for very short transfers. The current boundary between PIO/DMA 8 bytes, transfers shorter than 8 bytes are transfered by PIO, longer transfers use DMA. The performance of write transfers remains unchanged, while there is a minor improvement of read performance. Reading 16KB EEPROM with DMA-only operations gives a read speed of 39.5KB/s, while with then new mixed-mode the speed is blazing 40.6KB/s. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 176 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index d6abaf2cf2e..e55736077d2 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -39,6 +39,7 @@ #define MXS_I2C_CTRL0_SET (0x04) #define MXS_I2C_CTRL0_SFTRST 0x80000000 +#define MXS_I2C_CTRL0_RUN 0x20000000 #define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000 #define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000 #define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000 @@ -64,6 +65,13 @@ #define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02 #define MXS_I2C_CTRL1_SLAVE_IRQ 0x01 +#define MXS_I2C_DATA (0xa0) + +#define MXS_I2C_DEBUG0 (0xb0) +#define MXS_I2C_DEBUG0_CLR (0xb8) + +#define MXS_I2C_DEBUG0_DMAREQ 0x80000000 + #define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \ MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \ MXS_I2C_CTRL1_EARLY_TERM_IRQ | \ @@ -298,6 +306,135 @@ write_init_pio_fail: return -EINVAL; } +static int mxs_i2c_pio_wait_dmareq(struct mxs_i2c_dev *i2c) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + while (!(readl(i2c->regs + MXS_I2C_DEBUG0) & + MXS_I2C_DEBUG0_DMAREQ)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cond_resched(); + } + + writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); + + return 0; +} + +static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + /* + * We do not use interrupts in the PIO mode. Due to the + * maximum transfer length being 8 bytes in PIO mode, the + * overhead of interrupt would be too large and this would + * neglect the gain from using the PIO mode. + */ + + while (!(readl(i2c->regs + MXS_I2C_CTRL1) & + MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ)) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + cond_resched(); + } + + writel(MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ, + i2c->regs + MXS_I2C_CTRL1_CLR); + + return 0; +} + +static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, + struct i2c_msg *msg, uint32_t flags) +{ + struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); + uint32_t addr_data = msg->addr << 1; + uint32_t data = 0; + int i, shifts_left, ret; + + /* Mute IRQs coming from this block. */ + writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_CLR); + + if (msg->flags & I2C_M_RD) { + addr_data |= I2C_SMBUS_READ; + + /* SELECT command. */ + writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_SELECT, + i2c->regs + MXS_I2C_CTRL0); + + ret = mxs_i2c_pio_wait_dmareq(i2c); + if (ret) + return ret; + + writel(addr_data, i2c->regs + MXS_I2C_DATA); + + ret = mxs_i2c_pio_wait_cplt(i2c); + if (ret) + return ret; + + /* READ command. */ + writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_READ | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len), + i2c->regs + MXS_I2C_CTRL0); + + for (i = 0; i < msg->len; i++) { + if ((i & 3) == 0) { + ret = mxs_i2c_pio_wait_dmareq(i2c); + if (ret) + return ret; + data = readl(i2c->regs + MXS_I2C_DATA); + } + msg->buf[i] = data & 0xff; + data >>= 8; + } + } else { + addr_data |= I2C_SMBUS_WRITE; + + /* WRITE command. */ + writel(MXS_I2C_CTRL0_RUN | MXS_CMD_I2C_WRITE | flags | + MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1), + i2c->regs + MXS_I2C_CTRL0); + + /* + * The LSB of data buffer is the first byte blasted across + * the bus. Higher order bytes follow. Thus the following + * filling schematic. + */ + data = addr_data << 24; + for (i = 0; i < msg->len; i++) { + data >>= 8; + data |= (msg->buf[i] << 24); + if ((i & 3) == 2) { + ret = mxs_i2c_pio_wait_dmareq(i2c); + if (ret) + return ret; + writel(data, i2c->regs + MXS_I2C_DATA); + } + } + + shifts_left = 24 - (i & 3) * 8; + if (shifts_left) { + data >>= shifts_left; + ret = mxs_i2c_pio_wait_dmareq(i2c); + if (ret) + return ret; + writel(data, i2c->regs + MXS_I2C_DATA); + } + } + + ret = mxs_i2c_pio_wait_cplt(i2c); + if (ret) + return ret; + + /* Clear any dangling IRQs and re-enable interrupts. */ + writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); + writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); + + return 0; +} + /* * Low level master read/write transaction. */ @@ -316,24 +453,37 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, if (msg->len == 0) return -EINVAL; - INIT_COMPLETION(i2c->cmd_complete); - i2c->cmd_err = 0; - - ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); - if (ret) - return ret; + /* + * The current boundary to select between PIO/DMA transfer method + * is set to 8 bytes, transfers shorter than 8 bytes are transfered + * using PIO mode while longer transfers use DMA. The 8 byte border is + * based on this empirical measurement and a lot of previous frobbing. + */ + if (msg->len < 8) { + ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); + if (ret) + mxs_i2c_reset(i2c); + } else { + i2c->cmd_err = 0; + INIT_COMPLETION(i2c->cmd_complete); + ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); + if (ret) + return ret; - ret = wait_for_completion_timeout(&i2c->cmd_complete, + ret = wait_for_completion_timeout(&i2c->cmd_complete, msecs_to_jiffies(1000)); - if (ret == 0) - goto timeout; + if (ret == 0) + goto timeout; + + if (i2c->cmd_err == -ENXIO) + mxs_i2c_reset(i2c); - if (i2c->cmd_err == -ENXIO) - mxs_i2c_reset(i2c); + ret = i2c->cmd_err; + } - dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err); + dev_dbg(i2c->dev, "Done with err=%d\n", ret); - return i2c->cmd_err; + return ret; timeout: dev_dbg(i2c->dev, "Timeout!\n"); -- cgit v1.2.3 From faf93ff6ed5f6406ca51ec6d60f85fa166fe545c Mon Sep 17 00:00:00 2001 From: Giridhar Maruthy Date: Thu, 24 Jan 2013 11:27:51 -0800 Subject: i2c: s3c2410: Add quirk to exclude GPIO config for exynos5440 Signed-off-by: Giridhar Maruthy Signed-off-by: Kukjin Kim Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt | 2 ++ drivers/i2c/busses/i2c-s3c2410.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt index e9611ace879..f98d4c5b5cc 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt @@ -8,6 +8,8 @@ Required properties: (b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c. (c) "samsung, s3c2440-hdmiphy-i2c", for s3c2440-like i2c used inside HDMIPHY block found on several samsung SoCs + (d) "samsung, exynos5440-i2c", for s3c2440-like i2c used + on EXYNOS5440 which does not need GPIO configuration. - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt number to the cpu. diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3479ca76d2a..5e33df7c6c8 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -111,6 +111,8 @@ static const struct of_device_id s3c24xx_i2c_match[] = { { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, { .compatible = "samsung,s3c2440-hdmiphy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, + { .compatible = "samsung,exynos5440-i2c", + .data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match); -- cgit v1.2.3 From c2db409cbc8751ccc7e6d2cc2e41af0d12ea637f Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 30 Jan 2013 15:25:32 +0000 Subject: i2c: i801: SMBus patch for Intel Avoton DeviceIDs This patch adds the PCU SMBus DeviceID for the Intel Avoton SOC. Signed-off-by: Seth Heasley 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 | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 157416e78cc..8d71d5705b2 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -22,6 +22,7 @@ Supported adapters: * Intel Panther Point (PCH) * Intel Lynx Point (PCH) * Intel Lynx Point-LP (PCH) + * Intel Avoton (SOC) 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 bdca5111eb9..77d28873b76 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -106,6 +106,7 @@ config I2C_I801 Panther Point (PCH) Lynx Point (PCH) Lynx Point-LP (PCH) + Avoton (SOC) 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 3092387f6ef..b00c29d8a5f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -53,6 +53,7 @@ Panther Point (PCH) 0x1e22 32 hard yes yes yes Lynx Point (PCH) 0x8c22 32 hard yes yes yes Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes + Avoton (SOC) 0x1f3c 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -162,6 +163,7 @@ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 +#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 @@ -798,6 +800,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, { 0, } }; -- cgit v1.2.3 From 626f0a2ff6bc9820b17c17958d5862262556892f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 30 Nov 2012 18:48:35 +0100 Subject: i2c: mxs: Implement arbitrary clock speed derivation algorithm This patch drops the i2c timing tables from this driver and instead derives the timing based from the requested clock sleep. The timing tables were completely wrong anyway when observed on a scope. This new algorithm is also only derived by using a scope, but it seems to produce much more accurate result. Signed-off-by: Marek Vasut Tested-by: Shawn Guo [wsa: changed messages from dev_err to dev_warn] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 94 ++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index e55736077d2..22d8ad35340 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -93,35 +93,6 @@ #define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ MXS_I2C_CTRL0_MASTER_MODE) -struct mxs_i2c_speed_config { - uint32_t timing0; - uint32_t timing1; - uint32_t timing2; -}; - -/* - * Timing values for the default 24MHz clock supplied into the i2c block. - * - * The bus can operate at 95kHz or at 400kHz with the following timing - * register configurations. The 100kHz mode isn't present because it's - * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode - * shall be close enough replacement. Therefore when the bus is configured - * for 100kHz operation, 95kHz timing settings are actually loaded. - * - * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4]. - */ -static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = { - .timing0 = 0x00780030, - .timing1 = 0x00800030, - .timing2 = 0x00300030, -}; - -static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = { - .timing0 = 0x000f0007, - .timing1 = 0x001f000f, - .timing2 = 0x00300030, -}; - /** * struct mxs_i2c_dev - per device, private MXS-I2C data * @@ -137,7 +108,9 @@ struct mxs_i2c_dev { struct completion cmd_complete; int cmd_err; struct i2c_adapter adapter; - const struct mxs_i2c_speed_config *speed; + + uint32_t timing0; + uint32_t timing1; /* DMA support components */ int dma_channel; @@ -153,9 +126,16 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) { stmp_reset_block(i2c->regs); - writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0); - writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1); - writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); + /* + * Configure timing for the I2C block. The I2C TIMING2 register has to + * be programmed with this particular magic number. The rest is derived + * from the XTAL speed and requested I2C speed. + * + * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4]. + */ + writel(i2c->timing0, i2c->regs + MXS_I2C_TIMING0); + writel(i2c->timing1, i2c->regs + MXS_I2C_TIMING1); + writel(0x00300030, i2c->regs + MXS_I2C_TIMING2); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); } @@ -553,6 +533,43 @@ static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param) return true; } +static void mxs_i2c_derive_timing(struct mxs_i2c_dev *i2c, int speed) +{ + /* The I2C block clock run at 24MHz */ + const uint32_t clk = 24000000; + uint32_t base; + uint16_t high_count, low_count, rcv_count, xmit_count; + struct device *dev = i2c->dev; + + if (speed > 540000) { + dev_warn(dev, "Speed too high (%d Hz), using 540 kHz\n", speed); + speed = 540000; + } else if (speed < 12000) { + dev_warn(dev, "Speed too low (%d Hz), using 12 kHz\n", speed); + speed = 12000; + } + + /* + * The timing derivation algorithm. There is no documentation for this + * algorithm available, it was derived by using the scope and fiddling + * with constants until the result observed on the scope was good enough + * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be + * possible to assume the algorithm works for other frequencies as well. + * + * Note it was necessary to cap the frequency on both ends as it's not + * possible to configure completely arbitrary frequency for the I2C bus + * clock. + */ + base = ((clk / speed) - 38) / 2; + high_count = base + 3; + low_count = base - 3; + rcv_count = (high_count * 3) / 4; + xmit_count = low_count / 4; + + i2c->timing0 = (high_count << 16) | rcv_count; + i2c->timing1 = (low_count << 16) | xmit_count; +} + static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) { uint32_t speed; @@ -572,12 +589,12 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) } ret = of_property_read_u32(node, "clock-frequency", &speed); - if (ret) + if (ret) { dev_warn(dev, "No I2C speed selected, using 100kHz\n"); - else if (speed == 400000) - i2c->speed = &mxs_i2c_400kHz_config; - else if (speed != 100000) - dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n"); + speed = 100000; + } + + mxs_i2c_derive_timing(i2c, speed); return 0; } @@ -621,7 +638,6 @@ static int mxs_i2c_probe(struct platform_device *pdev) return err; i2c->dev = dev; - i2c->speed = &mxs_i2c_95kHz_config; init_completion(&i2c->cmd_complete); -- cgit v1.2.3 From 05cf936846ca6aef1b34ba26054728fdbc154558 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Jan 2013 10:45:54 +0100 Subject: i2c: sh_mobile: cosmetic: trivially simplify 2 functions Reduce 2 boolean functions from "if (condition) return 1; return 0;" to "return condition;" Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index b6e7a83a829..34024f3a19f 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -349,20 +349,14 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, return ret; } -static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) +static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) { - if (pd->pos == -1) - return 1; - - return 0; + return pd->pos == -1; } -static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) +static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) { - if (pd->pos == (pd->msg->len - 1)) - return 1; - - return 0; + return pd->pos == pd->msg->len - 1; } static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, -- cgit v1.2.3 From 5687265b3127024089dc0b25956772405b9f53d3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Jan 2013 10:45:55 +0100 Subject: i2c: sh_mobile: fix timeout error handling In a timeout case return an error immediately from the driver's .master_xfer() method, instead of continuing and letting higher layers fail. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 34024f3a19f..daaf0ebe817 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -521,8 +521,11 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, k = wait_event_timeout(pd->wait, pd->sr & (ICSR_TACK | SW_DONE), 5 * HZ); - if (!k) + if (!k) { dev_err(pd->dev, "Transfer request timed out\n"); + err = -ETIMEDOUT; + break; + } retry_count = 1000; again: -- cgit v1.2.3 From 4b3823184f80c1d3950e5e63e2303653f2decdf8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Jan 2013 10:45:56 +0100 Subject: i2c: sh_mobile: eliminate an open-coded "goto" loop Eliminate an open-coded "goto" loop by introducing a function. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 60 +++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index daaf0ebe817..2767ea8e98a 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -495,6 +495,37 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) return 0; } +static int poll_busy(struct sh_mobile_i2c_data *pd) +{ + int i; + + for (i = 1000; i; i--) { + u_int8_t val = iic_rd(pd, ICSR); + + dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); + + /* the interrupt handler may wake us up before the + * transfer is finished, so poll the hardware + * until we're done. + */ + if (!(val & ICSR_BUSY)) { + /* handle missing acknowledge and arbitration lost */ + if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) + return -EIO; + break; + } + + udelay(10); + } + + if (!i) { + dev_err(pd->dev, "Polling timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) @@ -502,8 +533,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter); struct i2c_msg *msg; int err = 0; - u_int8_t val; - int i, k, retry_count; + int i, k; activate_ch(pd); @@ -527,31 +557,9 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, break; } - retry_count = 1000; -again: - val = iic_rd(pd, ICSR); - - dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); - - /* the interrupt handler may wake us up before the - * transfer is finished, so poll the hardware - * until we're done. - */ - if (val & ICSR_BUSY) { - udelay(10); - if (retry_count--) - goto again; - - err = -EIO; - dev_err(pd->dev, "Polling timed out\n"); + err = poll_busy(pd); + if (err < 0) break; - } - - /* handle missing acknowledge and arbitration lost */ - if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) { - err = -EIO; - break; - } } deactivate_ch(pd); -- cgit v1.2.3 From e789029761503f0cce03e8767a56ae099b88e1bd Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 17 Jan 2013 10:45:57 +0100 Subject: i2c: sh_mobile: don't send a stop condition by default inside transfers By default there should be no stop bit on I2C between single messages within transfers. Fix the driver to comply and only send a stop bit at the end of transfers or if I2C_M_STOP is set. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sh_mobile.c | 79 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2767ea8e98a..debf745c026 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -38,21 +38,21 @@ /* Transmit operation: */ /* */ /* 0 byte transmit */ -/* BUS: S A8 ACK P */ +/* BUS: S A8 ACK P(*) */ /* IRQ: DTE WAIT */ /* ICIC: */ /* ICCR: 0x94 0x90 */ /* ICDR: A8 */ /* */ /* 1 byte transmit */ -/* BUS: S A8 ACK D8(1) ACK P */ +/* BUS: S A8 ACK D8(1) ACK P(*) */ /* IRQ: DTE WAIT WAIT */ /* ICIC: -DTE */ /* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) */ /* */ /* 2 byte transmit */ -/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P */ +/* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */ /* IRQ: DTE WAIT WAIT WAIT */ /* ICIC: -DTE */ /* ICCR: 0x94 0x90 */ @@ -66,20 +66,20 @@ /* 0 byte receive - not supported since slave may hold SDA low */ /* */ /* 1 byte receive [TX] | [RX] */ -/* BUS: S A8 ACK | D8(1) ACK P */ +/* BUS: S A8 ACK | D8(1) ACK P(*) */ /* IRQ: DTE WAIT | WAIT DTE */ /* ICIC: -DTE | +DTE */ /* ICCR: 0x94 0x81 | 0xc0 */ /* ICDR: A8 | D8(1) */ /* */ /* 2 byte receive [TX]| [RX] */ -/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P */ +/* BUS: S A8 ACK | D8(1) ACK D8(2) ACK P(*) */ /* IRQ: DTE WAIT | WAIT WAIT DTE */ /* ICIC: -DTE | +DTE */ /* ICCR: 0x94 0x81 | 0xc0 */ /* ICDR: A8 | D8(1) D8(2) */ /* */ -/* 3 byte receive [TX] | [RX] */ +/* 3 byte receive [TX] | [RX] (*) */ /* BUS: S A8 ACK | D8(1) ACK D8(2) ACK D8(3) ACK P */ /* IRQ: DTE WAIT | WAIT WAIT WAIT DTE */ /* ICIC: -DTE | +DTE */ @@ -94,7 +94,7 @@ /* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/ */ /* SCL \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/ */ /* */ -/* S D7 D6 D5 D4 D3 D2 D1 D0 P */ +/* S D7 D6 D5 D4 D3 D2 D1 D0 P(*) */ /* ___ */ /* WAIT IRQ ________________________________/ \___________ */ /* TACK IRQ ____________________________________/ \_______ */ @@ -103,6 +103,11 @@ /* _______________________________________________ */ /* BUSY __/ \_ */ /* */ +/* (*) The STOP condition is only sent by the master at the end of the last */ +/* I2C message or if the I2C_M_STOP flag is set. Similarly, the BUSY bit is */ +/* only cleared after the STOP condition, so, between messages we have to */ +/* poll for the DTE bit. */ +/* */ enum sh_mobile_i2c_op { OP_START = 0, @@ -132,6 +137,7 @@ struct sh_mobile_i2c_data { struct i2c_msg *msg; int pos; int sr; + bool send_stop; }; #define IIC_FLAG_HAS_ICIC67 (1 << 0) @@ -322,7 +328,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, break; case OP_TX_STOP: /* write data and issue a stop afterwards */ iic_wr(pd, ICDR, data); - iic_wr(pd, ICCR, 0x90); + iic_wr(pd, ICCR, pd->send_stop ? 0x90 : 0x94); break; case OP_TX_TO_RX: /* select read mode */ iic_wr(pd, ICCR, 0x81); @@ -469,22 +475,25 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) +static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, + bool do_init) { if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { dev_err(pd->dev, "Unsupported zero length i2c read\n"); return -EIO; } - /* Initialize channel registers */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + if (do_init) { + /* Initialize channel registers */ + iic_set_clr(pd, ICCR, 0, ICCR_ICE); - /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); + /* Enable channel and configure rx ack */ + iic_set_clr(pd, ICCR, ICCR_ICE, 0); - /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl & 0xff); - iic_wr(pd, ICCH, pd->icch & 0xff); + /* Set the clock */ + iic_wr(pd, ICCL, pd->iccl & 0xff); + iic_wr(pd, ICCH, pd->icch & 0xff); + } pd->msg = usr_msg; pd->pos = -1; @@ -495,6 +504,30 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) return 0; } +static int poll_dte(struct sh_mobile_i2c_data *pd) +{ + int i; + + for (i = 1000; i; i--) { + u_int8_t val = iic_rd(pd, ICSR); + + if (val & ICSR_DTE) + break; + + if (val & ICSR_TACK) + return -EIO; + + udelay(10); + } + + if (!i) { + dev_warn(pd->dev, "Timeout polling for DTE!\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int poll_busy(struct sh_mobile_i2c_data *pd) { int i; @@ -539,13 +572,16 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, /* Process all messages */ for (i = 0; i < num; i++) { + bool do_start = pd->send_stop || !i; msg = &msgs[i]; + pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP; - err = start_ch(pd, msg); + err = start_ch(pd, msg, do_start); if (err) break; - i2c_op(pd, OP_START, 0); + if (do_start) + i2c_op(pd, OP_START, 0); /* The interrupt handler takes care of the rest... */ k = wait_event_timeout(pd->wait, @@ -557,7 +593,10 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, break; } - err = poll_busy(pd); + if (pd->send_stop) + err = poll_busy(pd); + else + err = poll_dte(pd); if (err < 0) break; } @@ -571,7 +610,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; } static struct i2c_algorithm sh_mobile_i2c_algorithm = { -- cgit v1.2.3 From 13f35ac14cd0a9a1c4f0034c4c40d0ae98844ce9 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 4 Feb 2013 14:54:10 -0500 Subject: i2c: Adding support for Intel iSMT SMBus 2.0 host controller The iSMT (Intel SMBus Message Transport) supports multi-master I2C/SMBus, as well as IPMI. It's operation is DMA-based and utilizes descriptors to initiate transactions on the bus. The iSMT hardware can act as both a master and a target, although this driver only supports being a master. Signed-off-by: Neil Horman Signed-off-by: Bill Brown Tested-by: Seth Heasley Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-ismt | 36 ++ drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-ismt.c | 963 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1010 insertions(+) create mode 100644 Documentation/i2c/busses/i2c-ismt create mode 100644 drivers/i2c/busses/i2c-ismt.c diff --git a/Documentation/i2c/busses/i2c-ismt b/Documentation/i2c/busses/i2c-ismt new file mode 100644 index 00000000000..737355822c0 --- /dev/null +++ b/Documentation/i2c/busses/i2c-ismt @@ -0,0 +1,36 @@ +Kernel driver i2c-ismt + +Supported adapters: + * Intel S12xx series SOCs + +Authors: + Bill Brown + + +Module Parameters +----------------- + +* bus_speed (unsigned int) +Allows changing of the bus speed. Normally, the bus speed is set by the BIOS +and never needs to be changed. However, some SMBus analyzers are too slow for +monitoring the bus during debug, thus the need for this module parameter. +Specify the bus speed in kHz. +Available bus frequency settings: + 0 no change + 80 kHz + 100 kHz + 400 kHz + 1000 kHz + + +Description +----------- + +The S12xx series of SOCs have a pair of integrated SMBus 2.0 controllers +targeted primarily at the microserver and storage markets. + +The S12xx series contain a pair of PCI functions. An output of lspci will show +something similar to the following: + + 00:13.0 System peripheral: Intel Corporation Centerton SMBus 2.0 Controller 0 + 00:13.1 System peripheral: Intel Corporation Centerton SMBus 2.0 Controller 1 diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 77d28873b76..87df863ba11 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -122,6 +122,16 @@ config I2C_ISCH This driver can also be built as a module. If so, the module will be called i2c-isch. +config I2C_ISMT + tristate "Intel iSMT SMBus Controller" + depends on PCI && X86 + help + If you say yes to this option, support will be included for the Intel + iSMT SMBus host controller interface. + + This driver can also be built as a module. If so, the module will be + called i2c-ismt. + config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)" depends on PCI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 6181f3ff263..23c9d55bc88 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_ISCH) += i2c-isch.o +obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c new file mode 100644 index 00000000000..3f7a9cb6dfd --- /dev/null +++ b/drivers/i2c/busses/i2c-ismt.c @@ -0,0 +1,963 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Supports the SMBus Message Transport (SMT) in the Intel Atom Processor + * S12xx Product Family. + * + * Features supported by this driver: + * Hardware PEC yes + * Block buffer yes + * Block process call transaction no + * Slave mode no + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* PCI Address Constants */ +#define SMBBAR 0 + +/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ +#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 +#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a + +#define ISMT_DESC_ENTRIES 32 /* number of descriptor entries */ +#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ + +/* Hardware Descriptor Constants - Control Field */ +#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ +#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ +#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ +#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ +#define ISMT_DESC_I2C 0x20 /* I2C Enable */ +#define ISMT_DESC_INT 0x40 /* Interrupt */ +#define ISMT_DESC_SOE 0x80 /* Stop On Error */ + +/* Hardware Descriptor Constants - Status Field */ +#define ISMT_DESC_SCS 0x01 /* Success */ +#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ +#define ISMT_DESC_NAK 0x08 /* NAK Received */ +#define ISMT_DESC_CRC 0x10 /* CRC Error */ +#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ +#define ISMT_DESC_COL 0x40 /* Collisions */ +#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ + +/* Macros */ +#define ISMT_DESC_ADDR_RW(addr, rw) (((addr) << 1) | (rw)) + +/* iSMT General Register address offsets (SMBBAR + ) */ +#define ISMT_GR_GCTRL 0x000 /* General Control */ +#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ +#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ +#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ +#define ISMT_GR_ERRSTS 0x018 /* Error Status */ +#define ISMT_GR_ERRINFO 0x01c /* Error Information */ + +/* iSMT Master Registers */ +#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ +#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ +#define ISMT_MSTR_MSTS 0x10c /* Master Status */ +#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ +#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ + +/* iSMT Miscellaneous Registers */ +#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ + +/* General Control Register (GCTRL) bit definitions */ +#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ +#define ISMT_GCTRL_KILL 0x08 /* Kill */ +#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ + +/* Master Control Register (MCTRL) bit definitions */ +#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ +#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ +#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ + +/* Master Status Register (MSTS) bit definitions */ +#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ +#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ +#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ +#define ISMT_MSTS_IP 0x01 /* In Progress */ + +/* Master Descriptor Size (MDS) bit definitions */ +#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ + +/* SMBus PHY Global Timing Register (SPGT) bit definitions */ +#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ +#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ +#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ +#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ +#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ + + +/* MSI Control Register (MSICTL) bit definitions */ +#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ + +/* iSMT Hardware Descriptor */ +struct ismt_desc { + u8 tgtaddr_rw; /* target address & r/w bit */ + u8 wr_len_cmd; /* write length in bytes or a command */ + u8 rd_len; /* read length */ + u8 control; /* control bits */ + u8 status; /* status bits */ + u8 retry; /* collision retry and retry count */ + u8 rxbytes; /* received bytes */ + u8 txbytes; /* transmitted bytes */ + u32 dptr_low; /* lower 32 bit of the data pointer */ + u32 dptr_high; /* upper 32 bit of the data pointer */ +} __packed; + +struct ismt_priv { + struct i2c_adapter adapter; + void *smba; /* PCI BAR */ + struct pci_dev *pci_dev; + struct ismt_desc *hw; /* descriptor virt base addr */ + dma_addr_t io_rng_dma; /* descriptor HW base addr */ + u8 head; /* ring buffer head pointer */ + struct completion cmp; /* interrupt completion */ + u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */ + bool using_msi; /* type of interrupt flag */ +}; + +/** + * ismt_ids - PCI device IDs supported by this driver + */ +static const DEFINE_PCI_DEVICE_TABLE(ismt_ids) = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, ismt_ids); + +/* Bus speed control bits for slow debuggers - refer to the docs for usage */ +static unsigned int bus_speed; +module_param(bus_speed, uint, S_IRUGO); +MODULE_PARM_DESC(bus_speed, "Bus Speed in kHz (0 = BIOS default)"); + +/** + * __ismt_desc_dump() - dump the contents of a specific descriptor + */ +static void __ismt_desc_dump(struct device *dev, const struct ismt_desc *desc) +{ + + dev_dbg(dev, "Descriptor struct: %p\n", desc); + dev_dbg(dev, "\ttgtaddr_rw=0x%02X\n", desc->tgtaddr_rw); + dev_dbg(dev, "\twr_len_cmd=0x%02X\n", desc->wr_len_cmd); + dev_dbg(dev, "\trd_len= 0x%02X\n", desc->rd_len); + dev_dbg(dev, "\tcontrol= 0x%02X\n", desc->control); + dev_dbg(dev, "\tstatus= 0x%02X\n", desc->status); + dev_dbg(dev, "\tretry= 0x%02X\n", desc->retry); + dev_dbg(dev, "\trxbytes= 0x%02X\n", desc->rxbytes); + dev_dbg(dev, "\ttxbytes= 0x%02X\n", desc->txbytes); + dev_dbg(dev, "\tdptr_low= 0x%08X\n", desc->dptr_low); + dev_dbg(dev, "\tdptr_high= 0x%08X\n", desc->dptr_high); +} +/** + * ismt_desc_dump() - dump the contents of a descriptor for debug purposes + * @priv: iSMT private data + */ +static void ismt_desc_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + struct ismt_desc *desc = &priv->hw[priv->head]; + + dev_dbg(dev, "Dump of the descriptor struct: 0x%X\n", priv->head); + __ismt_desc_dump(dev, desc); +} + +/** + * ismt_gen_reg_dump() - dump the iSMT General Registers + * @priv: iSMT private data + */ +static void ismt_gen_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT General Registers\n"); + dev_dbg(dev, " GCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_GCTRL, + readl(priv->smba + ISMT_GR_GCTRL)); + dev_dbg(dev, " SMTICL... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_GR_SMTICL, + (long long unsigned int)readq(priv->smba + ISMT_GR_SMTICL)); + dev_dbg(dev, " ERRINTMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINTMSK, + readl(priv->smba + ISMT_GR_ERRINTMSK)); + dev_dbg(dev, " ERRAERMSK : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRAERMSK, + readl(priv->smba + ISMT_GR_ERRAERMSK)); + dev_dbg(dev, " ERRSTS... : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRSTS, + readl(priv->smba + ISMT_GR_ERRSTS)); + dev_dbg(dev, " ERRINFO.. : (0x%p)=0x%X\n", + priv->smba + ISMT_GR_ERRINFO, + readl(priv->smba + ISMT_GR_ERRINFO)); +} + +/** + * ismt_mstr_reg_dump() - dump the iSMT Master Registers + * @priv: iSMT private data + */ +static void ismt_mstr_reg_dump(struct ismt_priv *priv) +{ + struct device *dev = &priv->pci_dev->dev; + + dev_dbg(dev, "Dump of the iSMT Master Registers\n"); + dev_dbg(dev, " MDBA..... : (0x%p)=0x%016llX\n", + priv->smba + ISMT_MSTR_MDBA, + (long long unsigned int)readq(priv->smba + ISMT_MSTR_MDBA)); + dev_dbg(dev, " MCTRL.... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MCTRL, + readl(priv->smba + ISMT_MSTR_MCTRL)); + dev_dbg(dev, " MSTS..... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MSTS, + readl(priv->smba + ISMT_MSTR_MSTS)); + dev_dbg(dev, " MDS...... : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_MDS, + readl(priv->smba + ISMT_MSTR_MDS)); + dev_dbg(dev, " RPOLICY.. : (0x%p)=0x%X\n", + priv->smba + ISMT_MSTR_RPOLICY, + readl(priv->smba + ISMT_MSTR_RPOLICY)); + dev_dbg(dev, " SPGT..... : (0x%p)=0x%X\n", + priv->smba + ISMT_SPGT, + readl(priv->smba + ISMT_SPGT)); +} + +/** + * ismt_submit_desc() - add a descriptor to the ring + * @priv: iSMT private data + */ +static void ismt_submit_desc(struct ismt_priv *priv) +{ + uint fmhp; + uint val; + + ismt_desc_dump(priv); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); + + /* Set the FMHP (Firmware Master Head Pointer)*/ + fmhp = ((priv->head + 1) % ISMT_DESC_ENTRIES) << 16; + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel((val & ~ISMT_MCTRL_FMHP) | fmhp, + priv->smba + ISMT_MSTR_MCTRL); + + /* Set the start bit */ + val = readl(priv->smba + ISMT_MSTR_MCTRL); + writel(val | ISMT_MCTRL_SS, + priv->smba + ISMT_MSTR_MCTRL); +} + +/** + * ismt_process_desc() - handle the completion of the descriptor + * @desc: the iSMT hardware descriptor + * @data: data buffer from the upper layer + * @priv: ismt_priv struct holding our dma buffer + * @size: SMBus transaction type + * @read_write: flag to indicate if this is a read or write + */ +static int ismt_process_desc(const struct ismt_desc *desc, + union i2c_smbus_data *data, + struct ismt_priv *priv, int size, + char read_write) +{ + u8 *dma_buffer = priv->dma_buffer; + + dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); + __ismt_desc_dump(&priv->pci_dev->dev, desc); + + if (desc->status & ISMT_DESC_SCS) { + if (read_write == I2C_SMBUS_WRITE && + size != I2C_SMBUS_PROC_CALL) + return 0; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = dma_buffer[0]; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = dma_buffer[0] | (dma_buffer[1] << 8); + break; + case I2C_SMBUS_BLOCK_DATA: + memcpy(&data->block[1], dma_buffer, desc->rxbytes); + data->block[0] = desc->rxbytes; + break; + } + return 0; + } + + if (likely(desc->status & ISMT_DESC_NAK)) + return -ENXIO; + + if (desc->status & ISMT_DESC_CRC) + return -EBADMSG; + + if (desc->status & ISMT_DESC_COL) + return -EAGAIN; + + if (desc->status & ISMT_DESC_LPR) + return -EPROTO; + + if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) + return -ETIMEDOUT; + + return -EIO; +} + +/** + * ismt_access() - process an SMBus command + * @adap: the i2c host adapter + * @addr: address of the i2c/SMBus target + * @flags: command options + * @read_write: read from or write to device + * @command: the i2c/SMBus command to issue + * @size: SMBus transaction type + * @data: read/write data buffer + */ +static int ismt_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int ret; + dma_addr_t dma_addr = 0; /* address of the data buffer */ + u8 dma_size = 0; + enum dma_data_direction dma_direction = 0; + struct ismt_desc *desc; + struct ismt_priv *priv = i2c_get_adapdata(adap); + struct device *dev = &priv->pci_dev->dev; + + desc = &priv->hw[priv->head]; + + /* Initialize the descriptor */ + memset(desc, 0, sizeof(struct ismt_desc)); + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); + + /* Initialize common control bits */ + if (likely(priv->using_msi)) + desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; + else + desc->control = ISMT_DESC_FAIR; + + if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK) + && (size != I2C_SMBUS_I2C_BLOCK_DATA)) + desc->control |= ISMT_DESC_PEC; + + switch (size) { + case I2C_SMBUS_QUICK: + dev_dbg(dev, "I2C_SMBUS_QUICK\n"); + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Send Byte + * The command field contains the write data + */ + dev_dbg(dev, "I2C_SMBUS_BYTE: WRITE\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + } else { + /* Receive Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE: READ\n"); + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = 1; + } + break; + + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* + * Write Byte + * Command plus 1 data byte + */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: WRITE\n"); + desc->wr_len_cmd = 2; + dma_size = 2; + dma_direction = DMA_TO_DEVICE; + priv->dma_buffer[0] = command; + priv->dma_buffer[1] = data->byte; + } else { + /* Read Byte */ + dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); + desc->control |= ISMT_DESC_CWRL; + desc->wr_len_cmd = command; + desc->rd_len = 1; + dma_size = 1; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Write Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: WRITE\n"); + desc->wr_len_cmd = 3; + dma_size = 3; + dma_direction = DMA_TO_DEVICE; + priv->dma_buffer[0] = command; + priv->dma_buffer[1] = data->word & 0xff; + priv->dma_buffer[2] = data->word >> 8; + } else { + /* Read Word */ + dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); + desc->wr_len_cmd = command; + desc->control |= ISMT_DESC_CWRL; + desc->rd_len = 2; + dma_size = 2; + dma_direction = DMA_FROM_DEVICE; + } + break; + + case I2C_SMBUS_PROC_CALL: + dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n"); + desc->wr_len_cmd = 3; + desc->rd_len = 2; + dma_size = 3; + dma_direction = DMA_BIDIRECTIONAL; + priv->dma_buffer[0] = command; + priv->dma_buffer[1] = data->word & 0xff; + priv->dma_buffer[2] = data->word >> 8; + break; + + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_WRITE) { + /* Block Write */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_BLK; + priv->dma_buffer[0] = command; + memcpy(&priv->dma_buffer[1], &data->block[1], dma_size); + } else { + /* Block Read */ + dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); + dma_size = I2C_SMBUS_BLOCK_MAX; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL); + } + break; + + default: + dev_err(dev, "Unsupported transaction %d\n", + size); + return -EOPNOTSUPP; + } + + /* map the data buffer */ + if (dma_size != 0) { + dev_dbg(dev, " dev=%p\n", dev); + dev_dbg(dev, " data=%p\n", data); + dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer); + dev_dbg(dev, " dma_size=%d\n", dma_size); + dev_dbg(dev, " dma_direction=%d\n", dma_direction); + + dma_addr = dma_map_single(dev, + priv->dma_buffer, + dma_size, + dma_direction); + + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "Error in mapping dma buffer %p\n", + priv->dma_buffer); + return -EIO; + } + + dev_dbg(dev, " dma_addr = 0x%016llX\n", + dma_addr); + + desc->dptr_low = lower_32_bits(dma_addr); + desc->dptr_high = upper_32_bits(dma_addr); + } + + INIT_COMPLETION(priv->cmp); + + /* Add the descriptor */ + ismt_submit_desc(priv); + + /* Now we wait for interrupt completion, 1s */ + ret = wait_for_completion_timeout(&priv->cmp, HZ*1); + + /* unmap the data buffer */ + if (dma_size != 0) + dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction); + + if (unlikely(!ret)) { + dev_err(dev, "completion wait timed out\n"); + ret = -ETIMEDOUT; + goto out; + } + + /* do any post processing of the descriptor here */ + ret = ismt_process_desc(desc, data, priv, size, read_write); + +out: + /* Update the ring pointer */ + priv->head++; + priv->head %= ISMT_DESC_ENTRIES; + + return ret; +} + +/** + * ismt_func() - report which i2c commands are supported by this adapter + * @adap: the i2c host adapter + */ +static u32 ismt_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_PEC; +} + +/** + * smbus_algorithm - the adapter algorithm and supported functionality + * @smbus_xfer: the adapter algorithm + * @functionality: functionality supported by the adapter + */ +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = ismt_access, + .functionality = ismt_func, +}; + +/** + * ismt_handle_isr() - interrupt handler bottom half + * @priv: iSMT private data + */ +static irqreturn_t ismt_handle_isr(struct ismt_priv *priv) +{ + complete(&priv->cmp); + + return IRQ_HANDLED; +} + + +/** + * ismt_do_interrupt() - IRQ interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_interrupt(int vec, void *data) +{ + u32 val; + struct ismt_priv *priv = data; + + /* + * check to see it's our interrupt, return IRQ_NONE if not ours + * since we are sharing interrupt + */ + val = readl(priv->smba + ISMT_MSTR_MSTS); + + if (!(val & (ISMT_MSTS_MIS | ISMT_MSTS_MEIS))) + return IRQ_NONE; + else + writel(val | ISMT_MSTS_MIS | ISMT_MSTS_MEIS, + priv->smba + ISMT_MSTR_MSTS); + + return ismt_handle_isr(priv); +} + +/** + * ismt_do_msi_interrupt() - MSI interrupt handler + * @vec: interrupt vector + * @data: iSMT private data + */ +static irqreturn_t ismt_do_msi_interrupt(int vec, void *data) +{ + return ismt_handle_isr(data); +} + +/** + * ismt_hw_init() - initialize the iSMT hardware + * @priv: iSMT private data + */ +static void ismt_hw_init(struct ismt_priv *priv) +{ + u32 val; + struct device *dev = &priv->pci_dev->dev; + + /* initialize the Master Descriptor Base Address (MDBA) */ + writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); + + /* initialize the Master Control Register (MCTRL) */ + writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); + + /* initialize the Master Status Register (MSTS) */ + writel(0, priv->smba + ISMT_MSTR_MSTS); + + /* initialize the Master Descriptor Size (MDS) */ + val = readl(priv->smba + ISMT_MSTR_MDS); + writel((val & ~ISMT_MDS_MASK) | (ISMT_DESC_ENTRIES - 1), + priv->smba + ISMT_MSTR_MDS); + + /* + * Set the SMBus speed (could use this for slow HW debuggers) + */ + + val = readl(priv->smba + ISMT_SPGT); + + switch (bus_speed) { + case 0: + break; + + case 80: + dev_dbg(dev, "Setting SMBus clock to 80 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_80K), + priv->smba + ISMT_SPGT); + break; + + case 100: + dev_dbg(dev, "Setting SMBus clock to 100 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_100K), + priv->smba + ISMT_SPGT); + break; + + case 400: + dev_dbg(dev, "Setting SMBus clock to 400 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_400K), + priv->smba + ISMT_SPGT); + break; + + case 1000: + dev_dbg(dev, "Setting SMBus clock to 1000 kHz\n"); + writel(((val & ~ISMT_SPGT_SPD_MASK) | ISMT_SPGT_SPD_1M), + priv->smba + ISMT_SPGT); + break; + + default: + dev_warn(dev, "Invalid SMBus clock speed, only 0, 80, 100, 400, and 1000 are valid\n"); + break; + } + + val = readl(priv->smba + ISMT_SPGT); + + switch (val & ISMT_SPGT_SPD_MASK) { + case ISMT_SPGT_SPD_80K: + bus_speed = 80; + break; + case ISMT_SPGT_SPD_100K: + bus_speed = 100; + break; + case ISMT_SPGT_SPD_400K: + bus_speed = 400; + break; + case ISMT_SPGT_SPD_1M: + bus_speed = 1000; + break; + } + dev_dbg(dev, "SMBus clock is running at %d kHz\n", bus_speed); +} + +/** + * ismt_dev_init() - initialize the iSMT data structures + * @priv: iSMT private data + */ +static int ismt_dev_init(struct ismt_priv *priv) +{ + /* allocate memory for the descriptor */ + priv->hw = dmam_alloc_coherent(&priv->pci_dev->dev, + (ISMT_DESC_ENTRIES + * sizeof(struct ismt_desc)), + &priv->io_rng_dma, + GFP_KERNEL); + if (!priv->hw) + return -ENOMEM; + + memset(priv->hw, 0, (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc))); + + priv->head = 0; + init_completion(&priv->cmp); + + return 0; +} + +/** + * ismt_int_init() - initialize interrupts + * @priv: iSMT private data + */ +static int ismt_int_init(struct ismt_priv *priv) +{ + int err; + + /* Try using MSI interrupts */ + err = pci_enable_msi(priv->pci_dev); + if (err) { + dev_warn(&priv->pci_dev->dev, + "Unable to use MSI interrupts, falling back to legacy\n"); + goto intx; + } + + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_msi_interrupt, + 0, + "ismt-msi", + priv); + if (err) { + pci_disable_msi(priv->pci_dev); + goto intx; + } + + priv->using_msi = true; + goto done; + + /* Try using legacy interrupts */ +intx: + err = devm_request_irq(&priv->pci_dev->dev, + priv->pci_dev->irq, + ismt_do_interrupt, + IRQF_SHARED, + "ismt-intx", + priv); + if (err) { + dev_err(&priv->pci_dev->dev, "no usable interrupts\n"); + return -ENODEV; + } + + priv->using_msi = false; + +done: + return 0; +} + +static struct pci_driver ismt_driver; + +/** + * ismt_probe() - probe for iSMT devices + * @pdev: PCI-Express device + * @id: PCI-Express device ID + */ +static int +ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct ismt_priv *priv; + unsigned long start, len; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + i2c_set_adapdata(&priv->adapter, priv); + priv->adapter.owner = THIS_MODULE; + + priv->adapter.class = I2C_CLASS_HWMON; + + priv->adapter.algo = &smbus_algorithm; + + /* set up the sysfs linkage to our parent device */ + priv->adapter.dev.parent = &pdev->dev; + + /* number of retries on lost arbitration */ + priv->adapter.retries = ISMT_MAX_RETRIES; + + priv->pci_dev = pdev; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n", + err); + return err; + } + + /* enable bus mastering */ + pci_set_master(pdev); + + /* Determine the address of the SMBus area */ + start = pci_resource_start(pdev, SMBBAR); + len = pci_resource_len(pdev, SMBBAR); + if (!start || !len) { + dev_err(&pdev->dev, + "SMBus base address uninitialized, upgrade BIOS\n"); + return -ENODEV; + } + + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus iSMT adapter at %lx", start); + + dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start); + dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len); + + err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]); + if (err) { + dev_err(&pdev->dev, "ACPI resource conflict!\n"); + return err; + } + + err = pci_request_region(pdev, SMBBAR, ismt_driver.name); + if (err) { + dev_err(&pdev->dev, + "Failed to request SMBus region 0x%lx-0x%lx\n", + start, start + len); + return err; + } + + priv->smba = pcim_iomap(pdev, SMBBAR, len); + if (!priv->smba) { + dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n"); + err = -ENODEV; + goto fail; + } + + if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || + (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { + if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || + (pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)) != 0)) { + dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", + pdev); + goto fail; + } + } + + err = ismt_dev_init(priv); + if (err) + goto fail; + + ismt_hw_init(priv); + + err = ismt_int_init(priv); + if (err) + goto fail; + + err = i2c_add_adapter(&priv->adapter); + if (err) { + dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n"); + err = -ENODEV; + goto fail; + } + return 0; + +fail: + pci_release_region(pdev, SMBBAR); + return err; +} + +/** + * ismt_remove() - release driver resources + * @pdev: PCI-Express device + */ +static void ismt_remove(struct pci_dev *pdev) +{ + struct ismt_priv *priv = pci_get_drvdata(pdev); + + i2c_del_adapter(&priv->adapter); + pci_release_region(pdev, SMBBAR); +} + +/** + * ismt_suspend() - place the device in suspend + * @pdev: PCI-Express device + * @mesg: PM message + */ +#ifdef CONFIG_PM +static int ismt_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, mesg)); + return 0; +} + +/** + * ismt_resume() - PCI resume code + * @pdev: PCI-Express device + */ +static int ismt_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return pci_enable_device(pdev); +} + +#else + +#define ismt_suspend NULL +#define ismt_resume NULL + +#endif + +static struct pci_driver ismt_driver = { + .name = "ismt_smbus", + .id_table = ismt_ids, + .probe = ismt_probe, + .remove = ismt_remove, + .suspend = ismt_suspend, + .resume = ismt_resume, +}; + +module_pci_driver(ismt_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Bill E. Brown "); +MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); -- cgit v1.2.3 From 4182b434bf760355a1516b1d3d9f73aa419eeeec Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 9 Feb 2013 19:14:00 +0100 Subject: i2c: at91: fix unsed variable warning when building with !CONFIG_OF Commit 70d46a2 "i2c: at91: add dt support to i2c-at91" added DT only support for at91sam9x5. Building i2c-at91 without CONFIG_OF now warns about at91sam9x5_config as being unused. drivers/i2c/busses/i2c-at91.c:556:30: warning: 'at91sam9x5_config' defined but not used [-Wunused-variable] Move at91sam9x5_config under the defined(CONFIG_OF) guard as new AT91 SoCs will be DT only. Signed-off-by: Joachim Eastwood Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 3e287d83893..3e4ad68e3bd 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -553,13 +553,6 @@ static struct at91_twi_pdata at91sam9g10_config = { .has_dma_support = false, }; -static struct at91_twi_pdata at91sam9x5_config = { - .clk_max_div = 7, - .clk_offset = 4, - .has_unre_flag = false, - .has_dma_support = true, -}; - static const struct platform_device_id at91_twi_devtypes[] = { { .name = "i2c-at91rm9200", @@ -582,6 +575,13 @@ static const struct platform_device_id at91_twi_devtypes[] = { }; #if defined(CONFIG_OF) +static struct at91_twi_pdata at91sam9x5_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = false, + .has_dma_support = true, +}; + static const struct of_device_id atmel_twi_dt_ids[] = { { .compatible = "atmel,at91rm9200-i2c", -- cgit v1.2.3 From b08369a174a183e88baa98ab5e3566a617a3a7f8 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 28 Jan 2013 10:44:12 +0100 Subject: i2c: isch: Add module parameter for backbone clock rate if divider is unset It was observed the Host Clock Divider was not written by the driver. It was still set to (default) 0, if not already set by BIOS, which caused garbage on SMBus. This driver adds a parameters which is used to calculate the divider appropriately for a default bitrate of 100 KHz. This new divider is only applied if the clock divider is still default 0. Signed-off-by: Alexander Stein Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-isch.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 4099f79c228..8c38aaa7417 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -40,6 +40,7 @@ /* SCH SMBus address offsets */ #define SMBHSTCNT (0 + sch_smba) #define SMBHSTSTS (1 + sch_smba) +#define SMBHSTCLK (2 + sch_smba) #define SMBHSTADD (4 + sch_smba) /* TSA */ #define SMBHSTCMD (5 + sch_smba) #define SMBHSTDAT0 (6 + sch_smba) @@ -58,6 +59,9 @@ static unsigned short sch_smba; static struct i2c_adapter sch_adapter; +static int backbone_speed = 33000; /* backbone speed in kHz */ +module_param(backbone_speed, int, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)"); /* * Start the i2c transaction -- the i2c_access will prepare the transaction @@ -156,6 +160,19 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp); return -EAGAIN; } + temp = inw(SMBHSTCLK); + if (!temp) { + /* + * We can't determine if we have 33 or 25 MHz clock for + * SMBus, so expect 33 MHz and calculate a bus clock of + * 100 kHz. If we actually run at 25 MHz the bus will be + * run ~75 kHz instead which should do no harm. + */ + dev_notice(&sch_adapter.dev, + "Clock divider unitialized. Setting defaults\n"); + outw(backbone_speed / (4 * 100), SMBHSTCLK); + } + dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size, (read_write)?"READ":"WRITE"); switch (size) { -- cgit v1.2.3 From 974d6a3797001c88e59ccb78567c6d71ac526c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Mon, 28 Jan 2013 22:21:05 +0100 Subject: i2c: sis630: Add SIS964 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-sis630 | 9 ++++ drivers/i2c/busses/Kconfig | 4 +- drivers/i2c/busses/i2c-sis630.c | 88 ++++++++++++++++++++++++------------- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630 index 0b969736693..ee794363107 100644 --- a/Documentation/i2c/busses/i2c-sis630 +++ b/Documentation/i2c/busses/i2c-sis630 @@ -4,9 +4,11 @@ Supported adapters: * Silicon Integrated Systems Corp (SiS) 630 chipset (Datasheet: available at http://www.sfr-fresh.com/linux) 730 chipset + 964 chipset * Possible other SiS chipsets ? Author: Alexander Malysh + Amaury Decrême - SiS964 support Module Parameters ----------------- @@ -18,6 +20,7 @@ Module Parameters * high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, what your BIOS use). DANGEROUS! This should be a bit faster, but freeze some systems (i.e. my Laptop). + SIS630/730 chip only. Description @@ -36,6 +39,12 @@ or like this: 00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02) 00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 +or like this: + +00:00.0 Host bridge: Silicon Integrated Systems [SiS] 760/M760 Host (rev 02) +00:02.0 ISA bridge: Silicon Integrated Systems [SiS] SiS964 [MuTIOL Media IO] + LPC Controller (rev 36) + in your 'lspci' output , then this driver is for your chipset. Thank You diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 87df863ba11..74e18bc0bf6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -197,11 +197,11 @@ config I2C_SIS5595 will be called i2c-sis5595. config I2C_SIS630 - tristate "SiS 630/730" + tristate "SiS 630/730/964" depends on PCI help If you say yes to this option, support will be included for the - SiS630 and SiS730 SMBus (a subset of I2C) interface. + SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface. This driver can also be built as a module. If so, the module will be called i2c-sis630. diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index de6dddb9f86..df8e20ab3a0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -41,6 +41,20 @@ Supports: SIS 630 SIS 730 + SIS 964 + + Notable differences between chips: + +------------------------+--------------------+-------------------+ + | | SIS630/730 | SIS964 | + +------------------------+--------------------+-------------------+ + | Clock | 14kHz/56kHz | 55.56kHz/27.78kHz | + | SMBus registers offset | 0x80 | 0xE0 | + | SMB_CNT | Bit 1 = Slave Busy | Bit 1 = Bus probe | + | (not used yet) | Bit 3 is reserved | Bit 3 = Last byte | + | SMB_PCOUNT | Offset + 0x06 | Offset + 0x14 | + | SMB_COUNT | 4:0 bits | 5:0 bits | + +------------------------+--------------------+-------------------+ + (Other differences don't affect the functions provided by the driver) Note: we assume there can only be one device, with one SMBus interface. */ @@ -55,22 +69,21 @@ #include #include -/* SIS630 SMBus registers */ -#define SMB_STS 0x80 /* status */ -#define SMB_EN 0x81 /* status enable */ -#define SMB_CNT 0x82 -#define SMBHOST_CNT 0x83 -#define SMB_ADDR 0x84 -#define SMB_CMD 0x85 -#define SMB_PCOUNT 0x86 /* processed count */ -#define SMB_COUNT 0x87 -#define SMB_BYTE 0x88 /* ~0x8F data byte field */ -#define SMBDEV_ADDR 0x90 -#define SMB_DB0 0x91 -#define SMB_DB1 0x92 -#define SMB_SAA 0x93 - -/* register count for request_region */ +/* SIS964 id is defined here as we are the only file using it */ +#define PCI_DEVICE_ID_SI_964 0x0964 + +/* SIS630/730/964 SMBus registers */ +#define SMB_STS 0x00 /* status */ +#define SMB_CNT 0x02 /* control */ +#define SMBHOST_CNT 0x03 /* host control */ +#define SMB_ADDR 0x04 /* address */ +#define SMB_CMD 0x05 /* command */ +#define SMB_COUNT 0x07 /* byte count */ +#define SMB_BYTE 0x08 /* ~0x8F data byte field */ + +/* register count for request_region + * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964 + */ #define SIS630_SMB_IOREGION 20 /* PCI address constants */ @@ -96,28 +109,30 @@ static struct pci_driver sis630_driver; static bool high_clock; static bool force; module_param(high_clock, bool, 0); -MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); +MODULE_PARM_DESC(high_clock, + "Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only)."); module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); -/* acpi base address */ -static unsigned short acpi_base; +/* SMBus base adress */ +static unsigned short smbus_base; /* supported chips */ static int supported[] = { PCI_DEVICE_ID_SI_630, PCI_DEVICE_ID_SI_730, + PCI_DEVICE_ID_SI_760, 0 /* terminates the list */ }; static inline u8 sis630_read(u8 reg) { - return inb(acpi_base + reg); + return inb(smbus_base + reg); } static inline void sis630_write(u8 reg, u8 data) { - outb(data, acpi_base + reg); + outb(data, smbus_base + reg); } static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock) @@ -394,6 +409,8 @@ static int sis630_setup(struct pci_dev *sis630_dev) unsigned char b; struct pci_dev *dummy = NULL; int retval, i; + /* acpi base address */ + unsigned short acpi_base; /* check for supported SiS devices */ for (i=0; supported[i] > 0 ; i++) { @@ -438,16 +455,25 @@ static int sis630_setup(struct pci_dev *sis630_dev) dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base); - retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, + if (supported[i] == PCI_DEVICE_ID_SI_760) + smbus_base = acpi_base + 0xE0; + else + smbus_base = acpi_base + 0x80; + + dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base); + + retval = acpi_check_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION, sis630_driver.name); if (retval) goto exit; /* Everything is happy, let's grab the memory and set things up. */ - if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, + if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION, sis630_driver.name)) { - dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " - "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); + dev_err(&sis630_dev->dev, + "I/O Region 0x%04hx-0x%04hx for SMBus already in use.\n", + smbus_base + SMB_STS, + smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1); retval = -EBUSY; goto exit; } @@ -456,7 +482,7 @@ static int sis630_setup(struct pci_dev *sis630_dev) exit: if (retval) - acpi_base = 0; + smbus_base = 0; return retval; } @@ -470,11 +496,13 @@ static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, .algo = &smbus_algorithm, + .retries = 3 }; static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, + { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) }, { 0, } }; @@ -491,17 +519,17 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) sis630_adapter.dev.parent = &dev->dev; snprintf(sis630_adapter.name, sizeof(sis630_adapter.name), - "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS); + "SMBus SIS630 adapter at %04hx", smbus_base + SMB_STS); return i2c_add_adapter(&sis630_adapter); } static void sis630_remove(struct pci_dev *dev) { - if (acpi_base) { + if (smbus_base) { i2c_del_adapter(&sis630_adapter); - release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION); - acpi_base = 0; + release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION); + smbus_base = 0; } } -- cgit v1.2.3 From aa9e7a39c5a5a77ff02670ef915f4c6712bc7658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Mon, 28 Jan 2013 22:21:06 +0100 Subject: i2c: sis630: clear sticky bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sticky bits must be cleared at the end of the transaction by writing a 1 to all fields. Datasheet: SMBus Status (SMB_STS) The following registers are all sticky bits and only can be cleared by writing a one to their corresponding fields. Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sis630.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index df8e20ab3a0..3124d807c05 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -213,10 +213,8 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) { - int temp = 0; - /* clear all status "sticky" bits */ - sis630_write(SMB_STS, temp); + sis630_write(SMB_STS, 0xFF); dev_dbg(&adap->dev, "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT)); -- cgit v1.2.3 From 499b9194ad7b7b6d7c06b01005508e5bcf3c8980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Mon, 28 Jan 2013 22:21:07 +0100 Subject: i2c: sis630: fix behavior after collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Datasheet on collision: SMBus Collision (SMBCOL_STS) This bit is set when a SMBus Collision condition occurs and SMBus Host loses in the bus arbitration. The software should clear this bit and re-start SMBus operation. As the status will be cleared in transaction_end, we can remove the sis630_write and prepare to return -EAGAIN to retry. Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sis630.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 3124d807c05..e152d36b94a 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -200,12 +200,7 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) if (temp & 0x04) { dev_err(&adap->dev, "Bus collision!\n"); - result = -EIO; - /* - TBD: Datasheet say: - the software should clear this bit and restart SMBUS operation. - Should we do it or user start request again? - */ + result = -EAGAIN; } return result; -- cgit v1.2.3 From a6e7d0efe0e21091682f62c4a72707a1adeef8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Mon, 28 Jan 2013 22:21:08 +0100 Subject: i2c: sis630: use hex to constants for SMBus commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces hexadecimal values by constants for SMBus commands. Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sis630.c | 45 ++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e152d36b94a..b2fa7415f7e 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -81,6 +81,21 @@ #define SMB_COUNT 0x07 /* byte count */ #define SMB_BYTE 0x08 /* ~0x8F data byte field */ +/* SMB_STS register */ +#define BYTE_DONE_STS 0x10 /* Byte Done Status / Block Array */ +#define SMBCOL_STS 0x04 /* Collision */ +#define SMBERR_STS 0x02 /* Device error */ + +/* SMB_CNT register */ +#define MSTO_EN 0x40 /* Host Master Timeout Enable */ +#define SMBCLK_SEL 0x20 /* Host master clock selection */ +#define SMB_PROBE 0x02 /* Bus Probe/Slave busy */ +#define SMB_HOSTBUSY 0x01 /* Host Busy */ + +/* SMBHOST_CNT register */ +#define SMB_KILL 0x20 /* Kill */ +#define SMB_START 0x10 /* Start */ + /* register count for request_region * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964 */ @@ -140,12 +155,14 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc int temp; /* Make sure the SMBus host is ready to start transmitting. */ - if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { - dev_dbg(&adap->dev, "SMBus busy (%02x).Resetting...\n",temp); + temp = sis630_read(SMB_CNT); + if ((temp & (SMB_PROBE | SMB_HOSTBUSY)) != 0x00) { + dev_dbg(&adap->dev, "SMBus busy (%02x). Resetting...\n", temp); /* kill smbus transaction */ - sis630_write(SMBHOST_CNT, 0x20); + sis630_write(SMBHOST_CNT, SMB_KILL); - if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) { + temp = sis630_read(SMB_CNT); + if (temp & (SMB_PROBE | SMB_HOSTBUSY)) { dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -EBUSY; } else { @@ -160,16 +177,16 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ if (high_clock) - sis630_write(SMB_CNT, 0x20); + sis630_write(SMB_CNT, SMBCLK_SEL); else - sis630_write(SMB_CNT, (*oldclock & ~0x40)); + sis630_write(SMB_CNT, (*oldclock & ~MSTO_EN)); /* clear all sticky bits */ temp = sis630_read(SMB_STS); sis630_write(SMB_STS, temp & 0x1e); /* start the transaction by setting bit 4 and size */ - sis630_write(SMBHOST_CNT,0x10 | (size & 0x07)); + sis630_write(SMBHOST_CNT, SMB_START | (size & 0x07)); return 0; } @@ -183,7 +200,7 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) msleep(1); temp = sis630_read(SMB_STS); /* check if block transmitted */ - if (size == SIS630_BLOCK_DATA && (temp & 0x10)) + if (size == SIS630_BLOCK_DATA && (temp & BYTE_DONE_STS)) break; } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT)); @@ -193,12 +210,12 @@ static int sis630_transaction_wait(struct i2c_adapter *adap, int size) result = -ETIMEDOUT; } - if (temp & 0x02) { + if (temp & SMBERR_STS) { dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); result = -ENXIO; } - if (temp & 0x04) { + if (temp & SMBCOL_STS) { dev_err(&adap->dev, "Bus collision!\n"); result = -EAGAIN; } @@ -217,8 +234,8 @@ static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) * restore old Host Master Clock if high_clock is set * and oldclock was not 56KHz */ - if (high_clock && !(oldclock & 0x20)) - sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20)); + if (high_clock && !(oldclock & SMBCLK_SEL)) + sis630_write(SMB_CNT, sis630_read(SMB_CNT) & ~SMBCLK_SEL); dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); } @@ -270,7 +287,7 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat we must clear sticky bit. clear SMBARY_STS */ - sis630_write(SMB_STS,0x10); + sis630_write(SMB_STS, BYTE_DONE_STS); } rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA); @@ -312,7 +329,7 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i); /* clear SMBARY_STS */ - sis630_write(SMB_STS,0x10); + sis630_write(SMB_STS, BYTE_DONE_STS); } while(len < data->block[0]); } -- cgit v1.2.3 From 97da42dcb48079860b31dc83cb6bc5af15f9fc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Mon, 28 Jan 2013 22:21:09 +0100 Subject: i2c: sis630: display unsigned hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch corrects the display of the acpi_base unsigned hex value. Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sis630.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index b2fa7415f7e..424545b5097 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -463,7 +463,7 @@ static int sis630_setup(struct pci_dev *sis630_dev) goto exit; } - dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base); + dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04hx\n", acpi_base); if (supported[i] == PCI_DEVICE_ID_SI_760) smbus_base = acpi_base + 0xE0; -- cgit v1.2.3 From 91991f34d71d4dd1d6333710d1e159db2f95e6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Decr=C3=AAme?= Date: Tue, 29 Jan 2013 21:22:26 +0100 Subject: i2c: sis630: checkpatch cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch corrects checkpatch errors. The changes has also been removed as it has less meaning with version control tools. Signed-off-by: Amaury Decrême Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-sis630.c | 214 ++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 105 deletions(-) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 424545b5097..36a9556d7cf 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -16,25 +16,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - Changes: - 24.08.2002 - Fixed the typo in sis630_access (Thanks to Mark M. Hoffman) - Changed sis630_transaction.(Thanks to Mark M. Hoffman) - 18.09.2002 - Added SIS730 as supported. - 21.09.2002 - Added high_clock module option.If this option is set - used Host Master Clock 56KHz (default 14KHz).For now we save old Host - Master Clock and after transaction completed restore (otherwise - it's confuse BIOS and hung Machine). - 24.09.2002 - Fixed typo in sis630_access - Fixed logical error by restoring of Host Master Clock - 31.07.2003 - Added block data read/write support. -*/ - /* Status: beta @@ -150,9 +131,10 @@ static inline void sis630_write(u8 reg, u8 data) outb(data, smbus_base + reg); } -static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock) +static int sis630_transaction_start(struct i2c_adapter *adap, int size, + u8 *oldclock) { - int temp; + int temp; /* Make sure the SMBus host is ready to start transmitting. */ temp = sis630_read(SMB_CNT); @@ -165,17 +147,18 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc if (temp & (SMB_PROBE | SMB_HOSTBUSY)) { dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -EBUSY; - } else { + } else { dev_dbg(&adap->dev, "Successful!\n"); } - } + } /* save old clock, so we can prevent machine for hung */ *oldclock = sis630_read(SMB_CNT); dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock); - /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */ + /* disable timeout interrupt, + * set Host Master Clock to 56KHz if requested */ if (high_clock) sis630_write(SMB_CNT, SMBCLK_SEL); else @@ -228,7 +211,8 @@ static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) /* clear all status "sticky" bits */ sis630_write(SMB_STS, 0xFF); - dev_dbg(&adap->dev, "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT)); + dev_dbg(&adap->dev, + "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT)); /* * restore old Host Master Clock if high_clock is set @@ -237,7 +221,8 @@ static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock) if (high_clock && !(oldclock & SMBCLK_SEL)) sis630_write(SMB_CNT, sis630_read(SMB_CNT) & ~SMBCLK_SEL); - dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); + dev_dbg(&adap->dev, + "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT)); } static int sis630_transaction(struct i2c_adapter *adap, int size) @@ -254,7 +239,8 @@ static int sis630_transaction(struct i2c_adapter *adap, int size) return result; } -static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *data, int read_write) +static int sis630_block_data(struct i2c_adapter *adap, + union i2c_smbus_data *data, int read_write) { int i, len = 0, rc = 0; u8 oldclock = 0; @@ -266,22 +252,26 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat else if (len > 32) len = 32; sis630_write(SMB_COUNT, len); - for (i=1; i <= len; i++) { - dev_dbg(&adap->dev, "set data 0x%02x\n", data->block[i]); + for (i = 1; i <= len; i++) { + dev_dbg(&adap->dev, + "set data 0x%02x\n", data->block[i]); /* set data */ - sis630_write(SMB_BYTE+(i-1)%8, data->block[i]); - if (i==8 || (len<8 && i==len)) { - dev_dbg(&adap->dev, "start trans len=%d i=%d\n",len ,i); + sis630_write(SMB_BYTE + (i - 1) % 8, data->block[i]); + if (i == 8 || (len < 8 && i == len)) { + dev_dbg(&adap->dev, + "start trans len=%d i=%d\n", len, i); /* first transaction */ rc = sis630_transaction_start(adap, SIS630_BLOCK_DATA, &oldclock); if (rc) return rc; - } - else if ((i-1)%8 == 7 || i==len) { - dev_dbg(&adap->dev, "trans_wait len=%d i=%d\n",len,i); - if (i>8) { - dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i); + } else if ((i - 1) % 8 == 7 || i == len) { + dev_dbg(&adap->dev, + "trans_wait len=%d i=%d\n", len, i); + if (i > 8) { + dev_dbg(&adap->dev, + "clear smbary_sts" + " len=%d i=%d\n", len, i); /* If this is not first transaction, we must clear sticky bit. @@ -292,13 +282,13 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA); if (rc) { - dev_dbg(&adap->dev, "trans_wait failed\n"); + dev_dbg(&adap->dev, + "trans_wait failed\n"); break; } } } - } - else { + } else { /* read request */ data->block[0] = len = 0; rc = sis630_transaction_start(adap, @@ -319,18 +309,22 @@ static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *dat if (data->block[0] > 32) data->block[0] = 32; - dev_dbg(&adap->dev, "block data read len=0x%x\n", data->block[0]); + dev_dbg(&adap->dev, + "block data read len=0x%x\n", data->block[0]); - for (i=0; i < 8 && len < data->block[0]; i++,len++) { - dev_dbg(&adap->dev, "read i=%d len=%d\n", i, len); - data->block[len+1] = sis630_read(SMB_BYTE+i); + for (i = 0; i < 8 && len < data->block[0]; i++, len++) { + dev_dbg(&adap->dev, + "read i=%d len=%d\n", i, len); + data->block[len + 1] = sis630_read(SMB_BYTE + + i); } - dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i); + dev_dbg(&adap->dev, + "clear smbary_sts len=%d i=%d\n", len, i); /* clear SMBARY_STS */ sis630_write(SMB_STS, BYTE_DONE_STS); - } while(len < data->block[0]); + } while (len < data->block[0]); } sis630_transaction_end(adap, oldclock); @@ -346,42 +340,47 @@ static s32 sis630_access(struct i2c_adapter *adap, u16 addr, int status; switch (size) { - case I2C_SMBUS_QUICK: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - size = SIS630_QUICK; - break; - case I2C_SMBUS_BYTE: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - if (read_write == I2C_SMBUS_WRITE) - sis630_write(SMB_CMD, command); - size = SIS630_BYTE; - break; - case I2C_SMBUS_BYTE_DATA: - sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01)); - sis630_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) - sis630_write(SMB_BYTE, data->byte); - size = SIS630_BYTE_DATA; - break; - case I2C_SMBUS_PROC_CALL: - case I2C_SMBUS_WORD_DATA: - sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01)); + case I2C_SMBUS_QUICK: + sis630_write(SMB_ADDR, + ((addr & 0x7f) << 1) | (read_write & 0x01)); + size = SIS630_QUICK; + break; + case I2C_SMBUS_BYTE: + sis630_write(SMB_ADDR, + ((addr & 0x7f) << 1) | (read_write & 0x01)); + if (read_write == I2C_SMBUS_WRITE) sis630_write(SMB_CMD, command); - if (read_write == I2C_SMBUS_WRITE) { - sis630_write(SMB_BYTE, data->word & 0xff); - sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8); - } - size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA); - break; - case I2C_SMBUS_BLOCK_DATA: - sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01)); - sis630_write(SMB_CMD, command); - size = SIS630_BLOCK_DATA; - return sis630_block_data(adap, data, read_write); - default: - dev_warn(&adap->dev, "Unsupported transaction %d\n", - size); - return -EOPNOTSUPP; + size = SIS630_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + sis630_write(SMB_ADDR, + ((addr & 0x7f) << 1) | (read_write & 0x01)); + sis630_write(SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) + sis630_write(SMB_BYTE, data->byte); + size = SIS630_BYTE_DATA; + break; + case I2C_SMBUS_PROC_CALL: + case I2C_SMBUS_WORD_DATA: + sis630_write(SMB_ADDR, + ((addr & 0x7f) << 1) | (read_write & 0x01)); + sis630_write(SMB_CMD, command); + if (read_write == I2C_SMBUS_WRITE) { + sis630_write(SMB_BYTE, data->word & 0xff); + sis630_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8); + } + size = (size == I2C_SMBUS_PROC_CALL ? + SIS630_PCALL : SIS630_WORD_DATA); + break; + case I2C_SMBUS_BLOCK_DATA: + sis630_write(SMB_ADDR, + ((addr & 0x7f) << 1) | (read_write & 0x01)); + sis630_write(SMB_CMD, command); + size = SIS630_BLOCK_DATA; + return sis630_block_data(adap, data, read_write); + default: + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); + return -EOPNOTSUPP; } status = sis630_transaction(adap, size); @@ -393,15 +392,16 @@ static s32 sis630_access(struct i2c_adapter *adap, u16 addr, return 0; } - switch(size) { - case SIS630_BYTE: - case SIS630_BYTE_DATA: - data->byte = sis630_read(SMB_BYTE); - break; - case SIS630_PCALL: - case SIS630_WORD_DATA: - data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8); - break; + switch (size) { + case SIS630_BYTE: + case SIS630_BYTE_DATA: + data->byte = sis630_read(SMB_BYTE); + break; + case SIS630_PCALL: + case SIS630_WORD_DATA: + data->word = sis630_read(SMB_BYTE) + + (sis630_read(SMB_BYTE + 1) << 8); + break; } return 0; @@ -409,9 +409,9 @@ static s32 sis630_access(struct i2c_adapter *adap, u16 addr, static u32 sis630_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_SMBUS_BLOCK_DATA; + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA; } static int sis630_setup(struct pci_dev *sis630_dev) @@ -423,19 +423,19 @@ static int sis630_setup(struct pci_dev *sis630_dev) unsigned short acpi_base; /* check for supported SiS devices */ - for (i=0; supported[i] > 0 ; i++) { - if ((dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy))) + for (i = 0; supported[i] > 0; i++) { + dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy); + if (dummy) break; /* found */ } if (dummy) { pci_dev_put(dummy); - } - else if (force) { - dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but " + } else if (force) { + dev_err(&sis630_dev->dev, + "WARNING: Can't detect SIS630 compatible device, but " "loading because of force option enabled\n"); - } - else { + } else { return -ENODEV; } @@ -443,7 +443,7 @@ static int sis630_setup(struct pci_dev *sis630_dev) Enable ACPI first , so we can accsess reg 74-75 in acpi io space and read acpi base addr */ - if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { + if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, &b)) { dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n"); retval = -ENODEV; goto exit; @@ -457,8 +457,10 @@ static int sis630_setup(struct pci_dev *sis630_dev) } /* Determine the ACPI base address */ - if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { - dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n"); + if (pci_read_config_word(sis630_dev, + SIS630_ACPI_BASE_REG, &acpi_base)) { + dev_err(&sis630_dev->dev, + "Error: Can't determine ACPI base address\n"); retval = -ENODEV; goto exit; } @@ -516,12 +518,14 @@ static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { { 0, } }; -MODULE_DEVICE_TABLE (pci, sis630_ids); +MODULE_DEVICE_TABLE(pci, sis630_ids); static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) { if (sis630_setup(dev)) { - dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n"); + dev_err(&dev->dev, + "SIS630 compatible bus not detected, " + "module not inserted.\n"); return -ENODEV; } -- cgit v1.2.3 From cb7f07a4c58659d971a60ebbb8547f6611278622 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sun, 10 Feb 2013 11:59:03 -0500 Subject: i2c: ismt: Add Seth and Myself as maintainers Adding Seth Heasley and Myself as maintainers for the i2c-ismt drvier Signed-off-by: Neil Horman Signed-off-by: "Heasley, Seth" Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8ae709e3452..5a5816c6880 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3750,6 +3750,13 @@ F: drivers/i2c/busses/i2c-sis96x.c F: drivers/i2c/busses/i2c-via.c F: drivers/i2c/busses/i2c-viapro.c +I2C/SMBUS ISMT DRIVER +M: Seth Heasley +M: Neil Horman +L: linux-i2c@vger.kernel.org +F: drivers/i2c/busses/i2c-ismt.c +F: Documentation/i2c/busses/i2c-ismt + I2C/SMBUS STUB DRIVER M: "Mark M. Hoffman" L: linux-i2c@vger.kernel.org -- cgit v1.2.3 From f3b54b9a066edeac5c06e1cdcd82e1cb1224aaef Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 11 Feb 2013 19:47:56 -0700 Subject: i2c: add bcm2835 driver This implements a very basic I2C host driver for the BCM2835 SoC. Missing features so far are: * 10-bit addressing. * DMA. Reviewed-by: Grant Likely Signed-off-by: Stephen Warren Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/brcm,bcm2835-i2c.txt | 20 ++ drivers/i2c/busses/Kconfig | 12 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-bcm2835.c | 342 +++++++++++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/brcm,bcm2835-i2c.txt create mode 100644 drivers/i2c/busses/i2c-bcm2835.c diff --git a/Documentation/devicetree/bindings/i2c/brcm,bcm2835-i2c.txt b/Documentation/devicetree/bindings/i2c/brcm,bcm2835-i2c.txt new file mode 100644 index 00000000000..e9de3756752 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/brcm,bcm2835-i2c.txt @@ -0,0 +1,20 @@ +Broadcom BCM2835 I2C controller + +Required properties: +- compatible : Should be "brcm,bcm2835-i2c". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks : The clock feeding the I2C controller. + +Recommended properties: +- clock-frequency : desired I2C bus clock frequency in Hz. + +Example: + +i2c@20205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; + clocks = <&clk_i2c>; + clock-frequency = <100000>; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 74e18bc0bf6..8cbd9cd1e0f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -330,6 +330,18 @@ config I2C_AU1550 This driver can also be built as a module. If so, the module will be called i2c-au1550. +config I2C_BCM2835 + tristate "Broadcom BCM2835 I2C controller" + depends on ARCH_BCM2835 + help + If you say yes to this option, support will be included for the + BCM2835 I2C controller. + + If you don't know what to do here, say N. + + This support is also available as a module. If so, the module + will be called i2c-bcm2835. + config I2C_BLACKFIN_TWI tristate "Blackfin TWI I2C support" depends on BLACKFIN diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 23c9d55bc88..8f4fc23b85b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o +obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c new file mode 100644 index 00000000000..ea4b08fc335 --- /dev/null +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -0,0 +1,342 @@ +/* + * BCM2835 master mode driver + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BCM2835_I2C_C 0x0 +#define BCM2835_I2C_S 0x4 +#define BCM2835_I2C_DLEN 0x8 +#define BCM2835_I2C_A 0xc +#define BCM2835_I2C_FIFO 0x10 +#define BCM2835_I2C_DIV 0x14 +#define BCM2835_I2C_DEL 0x18 +#define BCM2835_I2C_CLKT 0x1c + +#define BCM2835_I2C_C_READ BIT(0) +#define BCM2835_I2C_C_CLEAR BIT(4) /* bits 4 and 5 both clear */ +#define BCM2835_I2C_C_ST BIT(7) +#define BCM2835_I2C_C_INTD BIT(8) +#define BCM2835_I2C_C_INTT BIT(9) +#define BCM2835_I2C_C_INTR BIT(10) +#define BCM2835_I2C_C_I2CEN BIT(15) + +#define BCM2835_I2C_S_TA BIT(0) +#define BCM2835_I2C_S_DONE BIT(1) +#define BCM2835_I2C_S_TXW BIT(2) +#define BCM2835_I2C_S_RXR BIT(3) +#define BCM2835_I2C_S_TXD BIT(4) +#define BCM2835_I2C_S_RXD BIT(5) +#define BCM2835_I2C_S_TXE BIT(6) +#define BCM2835_I2C_S_RXF BIT(7) +#define BCM2835_I2C_S_ERR BIT(8) +#define BCM2835_I2C_S_CLKT BIT(9) +#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ + +#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000)) + +struct bcm2835_i2c_dev { + struct device *dev; + void __iomem *regs; + struct clk *clk; + int irq; + struct i2c_adapter adapter; + struct completion completion; + u32 msg_err; + u8 *msg_buf; + size_t msg_buf_remaining; +}; + +static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev, + u32 reg, u32 val) +{ + writel(val, i2c_dev->regs + reg); +} + +static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) +{ + return readl(i2c_dev->regs + reg); +} + +static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev) +{ + u32 val; + + while (i2c_dev->msg_buf_remaining) { + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + if (!(val & BCM2835_I2C_S_TXD)) + break; + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_FIFO, + *i2c_dev->msg_buf); + i2c_dev->msg_buf++; + i2c_dev->msg_buf_remaining--; + } +} + +static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) +{ + u32 val; + + while (i2c_dev->msg_buf_remaining) { + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + if (!(val & BCM2835_I2C_S_RXD)) + break; + *i2c_dev->msg_buf = bcm2835_i2c_readl(i2c_dev, + BCM2835_I2C_FIFO); + i2c_dev->msg_buf++; + i2c_dev->msg_buf_remaining--; + } +} + +static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) +{ + struct bcm2835_i2c_dev *i2c_dev = data; + u32 val, err; + + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val); + + err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); + if (err) { + i2c_dev->msg_err = err; + complete(&i2c_dev->completion); + return IRQ_HANDLED; + } + + if (val & BCM2835_I2C_S_RXD) { + bcm2835_drain_rxfifo(i2c_dev); + if (!(val & BCM2835_I2C_S_DONE)) + return IRQ_HANDLED; + } + + if (val & BCM2835_I2C_S_DONE) { + if (i2c_dev->msg_buf_remaining) + i2c_dev->msg_err = BCM2835_I2C_S_LEN; + else + i2c_dev->msg_err = 0; + complete(&i2c_dev->completion); + return IRQ_HANDLED; + } + + if (val & BCM2835_I2C_S_TXD) { + bcm2835_fill_txfifo(i2c_dev); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, + struct i2c_msg *msg) +{ + u32 c; + int time_left; + + i2c_dev->msg_buf = msg->buf; + i2c_dev->msg_buf_remaining = msg->len; + INIT_COMPLETION(i2c_dev->completion); + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + + if (msg->flags & I2C_M_RD) { + c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR; + } else { + c = BCM2835_I2C_C_INTT; + bcm2835_fill_txfifo(i2c_dev); + } + c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN; + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); + + time_left = wait_for_completion_timeout(&i2c_dev->completion, + BCM2835_I2C_TIMEOUT); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + if (!time_left) { + dev_err(i2c_dev->dev, "i2c transfer timed out\n"); + return -ETIMEDOUT; + } + + if (likely(!i2c_dev->msg_err)) + return 0; + + if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) && + (msg->flags & I2C_M_IGNORE_NAK)) + return 0; + + dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); + + if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) + return -EREMOTEIO; + else + return -EIO; +} + +static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) +{ + struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + int i; + int ret = 0; + + for (i = 0; i < num; i++) { + ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]); + if (ret) + break; + } + + return ret ?: i; +} + +static u32 bcm2835_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm bcm2835_i2c_algo = { + .master_xfer = bcm2835_i2c_xfer, + .functionality = bcm2835_i2c_func, +}; + +static int bcm2835_i2c_probe(struct platform_device *pdev) +{ + struct bcm2835_i2c_dev *i2c_dev; + struct resource *mem, *requested, *irq; + u32 bus_clk_rate, divider; + int ret; + struct i2c_adapter *adap; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&pdev->dev, "Cannot allocate i2c_dev\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, i2c_dev); + i2c_dev->dev = &pdev->dev; + init_completion(&i2c_dev->completion); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No mem resource\n"); + return -ENODEV; + } + + requested = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), + dev_name(&pdev->dev)); + if (!requested) { + dev_err(&pdev->dev, "Could not claim register region\n"); + return -EBUSY; + } + + i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + if (!i2c_dev->regs) { + dev_err(&pdev->dev, "Could not map registers\n"); + return -ENOMEM; + } + + i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c_dev->clk)) { + 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", + &bus_clk_rate); + if (ret < 0) { + dev_warn(&pdev->dev, + "Could not read clock-frequency property\n"); + bus_clk_rate = 100000; + } + + divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), 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, + * if the LSB is set, increment the divider to avoid any issue. + */ + if (divider & 1) + divider++; + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + + 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; + adap->class = I2C_CLASS_HWMON; + strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name)); + adap->algo = &bcm2835_i2c_algo; + adap->dev.parent = &pdev->dev; + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0); + + ret = i2c_add_adapter(adap); + if (ret) + free_irq(i2c_dev->irq, i2c_dev); + + return ret; +} + +static int bcm2835_i2c_remove(struct platform_device *pdev) +{ + struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + free_irq(i2c_dev->irq, i2c_dev); + i2c_del_adapter(&i2c_dev->adapter); + + return 0; +} + +static const struct of_device_id bcm2835_i2c_of_match[] = { + { .compatible = "brcm,bcm2835-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match); + +static struct platform_driver bcm2835_i2c_driver = { + .probe = bcm2835_i2c_probe, + .remove = bcm2835_i2c_remove, + .driver = { + .name = "i2c-bcm2835", + .owner = THIS_MODULE, + .of_match_table = bcm2835_i2c_of_match, + }, +}; +module_platform_driver(bcm2835_i2c_driver); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_DESCRIPTION("BCM2835 I2C bus adapter"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-bcm2835"); -- cgit v1.2.3 From a3fc0ff00a46c4b32e7214961a5be9a1dc39b60e Mon Sep 17 00:00:00 2001 From: James Ralston Date: Thu, 14 Feb 2013 09:15:33 +0000 Subject: i2c: i801: Add Device IDs for Intel Wellsburg PCH This patch adds the SMBus Device IDs for the Intel Wellsburg PCH Signed-off-by: James Ralston 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 | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 8d71d5705b2..d55b8ab2d10 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -23,6 +23,7 @@ Supported adapters: * Intel Lynx Point (PCH) * Intel Lynx Point-LP (PCH) * Intel Avoton (SOC) + * Intel Wellsburg (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 8cbd9cd1e0f..b588317f239 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -107,6 +107,7 @@ config I2C_I801 Lynx Point (PCH) Lynx Point-LP (PCH) Avoton (SOC) + Wellsburg (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 b00c29d8a5f..76febfb0976 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -54,6 +54,10 @@ Lynx Point (PCH) 0x8c22 32 hard yes yes yes Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes Avoton (SOC) 0x1f3c 32 hard yes yes yes + Wellsburg (PCH) 0x8d22 32 hard yes yes yes + Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes + Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes + Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -167,6 +171,10 @@ #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e +#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 struct i801_mux_config { @@ -801,6 +809,10 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, { 0, } }; @@ -1106,6 +1118,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: + case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: priv->features |= FEATURE_IDF; /* fall through */ default: -- cgit v1.2.3 From 724d5edac76d8c9a4198b74c80286df38ed81679 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Feb 2013 08:51:40 +0000 Subject: i2c: fix i2c-ismt.c printk format warning Fix printk format warning. dma_addr_t can be 32-bit or 64-bit, so cast it to long long for printing. This also matches the printk format specifier that is already used. drivers/i2c/busses/i2c-ismt.c:532:3: warning: format '%llX' expects argument of type 'long long unsigned int', but argument 4 has type 'dma_addr_t' [-Wformat] Signed-off-by: Randy Dunlap Acked-by: Neil Horman Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ismt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 3f7a9cb6dfd..e9205ee8cf9 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -530,7 +530,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, } dev_dbg(dev, " dma_addr = 0x%016llX\n", - dma_addr); + (unsigned long long)dma_addr); desc->dptr_low = lower_32_bits(dma_addr); desc->dptr_high = upper_32_bits(dma_addr); -- cgit v1.2.3 From 58823c72f6b95414fa11cb8a0e5f1d0e548c2f34 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 14 Feb 2013 18:13:33 +0530 Subject: i2c: tegra: remove warning dump if timeout happen in transfer If timeout error occurs in the i2c transfer then it was dumping warning of call stack. Remove the warning dump as there is may be possibility that some slave devices are busy and not responding the i2c communication. Signed-off-by: Laxman Dewangan Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 2dadb964c46..e58a58d7231 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -588,7 +588,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT); tegra_i2c_mask_irq(i2c_dev, int_mask); - if (WARN_ON(ret == 0)) { + if (ret == 0) { dev_err(i2c_dev->dev, "i2c transfer timed out\n"); tegra_i2c_init(i2c_dev); -- cgit v1.2.3 From 6beaddf243b2d4bbc9165fbd89429fa1a7526af1 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Mon, 18 Feb 2013 21:33:19 +0000 Subject: i2c: ocores: Fix pointer to integer cast warning After commit a000b8c1 [i2c: ocores: Add support for the GRLIB port of the controller and use function pointers for getreg and setreg function], compiling i2c-ocores.c for 64-bit gives the following warning: drivers/i2c/busses/i2c-ocores.c: In function 'ocores_i2c_of_probe': drivers/i2c/busses/i2c-ocores.c:334:15: warning: cast from pointer to integer of different size Fix it by casting the pointer to long. Signed-off-by: Jayachandran C Acked-by: Peter Korsgaard Acked-by: Andreas Larsson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-ocores.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index a873d0ad1ac..6afa02db115 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -331,7 +331,7 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, &i2c->reg_io_width); match = of_match_node(ocores_i2c_match, pdev->dev.of_node); - if (match && (int)match->data == TYPE_GRLIB) { + if (match && (long)match->data == TYPE_GRLIB) { dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); i2c->setreg = oc_setreg_grlib; i2c->getreg = oc_getreg_grlib; -- cgit v1.2.3 From 0a6d2246790512c88931ddbfedf3fd48e0979093 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 19 Feb 2013 22:50:10 +0000 Subject: i2c: pxa: remove incorrect __exit annotations The remove() methods should not be marked __exit unless we are using platform_driver_probe() which disables unbinding device from driver via sysfs. Signed-off-by: Dmitry Torokhov Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 1034d93fb83..4a79e768a4d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1215,7 +1215,7 @@ emalloc: return ret; } -static int __exit i2c_pxa_remove(struct platform_device *dev) +static int i2c_pxa_remove(struct platform_device *dev) { struct pxa_i2c *i2c = platform_get_drvdata(dev); @@ -1269,7 +1269,7 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, - .remove = __exit_p(i2c_pxa_remove), + .remove = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, -- cgit v1.2.3 From 55827f4aa6442ddd1d6a4e1e32f2f457eb113c22 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 15 Feb 2013 13:18:35 +0000 Subject: i2c: Remove unneeded xxx_set_drvdata(..., NULL) calls There is simply no reason to be manually setting the private driver data to NULL in the remove/fail to probe cases. This is just extra cruft code that can be removed. A few notes: * Nothing relies on drvdata being set to NULL. * The __device_release_driver() function eventually calls dev_set_drvdata(dev, NULL) anyway, so there's no need to do it twice. * I verified that there were no cases where xxx_get_drvdata() was being called in these drivers and checking for / relying on the NULL return value. This could be cleaned up kernel-wide but for now just take the baby step and remove from the i2c subsystem. Reported-by: Wolfram Sang Reported-by: Stephen Warren Signed-off-by: Doug Anderson Reviewed-by: Jean Delvare Acked-by: Peter Korsgaard Reviewed-by: Mika Westerberg Reviewed-by: Marek Vasut Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-au1550.c | 1 - drivers/i2c/busses/i2c-bfin-twi.c | 2 -- drivers/i2c/busses/i2c-cpm.c | 2 -- drivers/i2c/busses/i2c-davinci.c | 2 -- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 -- drivers/i2c/busses/i2c-designware-platdrv.c | 2 -- drivers/i2c/busses/i2c-eg20t.c | 2 -- drivers/i2c/busses/i2c-highlander.c | 4 ---- drivers/i2c/busses/i2c-i801.c | 1 - drivers/i2c/busses/i2c-ibm_iic.c | 3 --- drivers/i2c/busses/i2c-imx.c | 1 - drivers/i2c/busses/i2c-intel-mid.c | 2 -- drivers/i2c/busses/i2c-iop3xx.c | 2 -- drivers/i2c/busses/i2c-mpc.c | 2 -- drivers/i2c/busses/i2c-mxs.c | 2 -- drivers/i2c/busses/i2c-nomadik.c | 2 -- drivers/i2c/busses/i2c-ocores.c | 1 - drivers/i2c/busses/i2c-octeon.c | 5 +---- drivers/i2c/busses/i2c-omap.c | 3 --- drivers/i2c/busses/i2c-pca-platform.c | 1 - drivers/i2c/busses/i2c-pmcmsp.c | 2 -- drivers/i2c/busses/i2c-pnx.c | 2 -- drivers/i2c/busses/i2c-powermac.c | 1 - drivers/i2c/busses/i2c-puv3.c | 2 -- drivers/i2c/busses/i2c-pxa-pci.c | 2 -- drivers/i2c/busses/i2c-pxa.c | 2 -- drivers/i2c/busses/i2c-s6000.c | 1 - drivers/i2c/busses/i2c-sh7760.c | 1 - drivers/i2c/busses/i2c-stu300.c | 1 - drivers/i2c/busses/i2c-taos-evm.c | 2 -- drivers/i2c/busses/i2c-versatile.c | 2 -- drivers/i2c/busses/i2c-xiic.c | 2 -- drivers/i2c/busses/i2c-xlr.c | 1 - drivers/i2c/busses/scx200_acb.c | 1 - drivers/i2c/muxes/i2c-mux-gpio.c | 1 - 35 files changed, 1 insertion(+), 64 deletions(-) diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index b278298787d..b5b89239d62 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -376,7 +376,6 @@ static int i2c_au1550_remove(struct platform_device *pdev) { struct i2c_au1550_data *priv = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); i2c_del_adapter(&priv->adap); i2c_au1550_disable(priv); iounmap(priv->psc_base); diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 0cf780fd6ef..05080c449c6 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -724,8 +724,6 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) { struct bfin_twi_iface *iface = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); - i2c_del_adapter(&(iface->adap)); free_irq(iface->irq, iface); peripheral_free_list((unsigned short *)pdev->dev.platform_data); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 2e79c102419..3823623baa4 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -682,7 +682,6 @@ static int cpm_i2c_probe(struct platform_device *ofdev) out_shut: cpm_i2c_shutdown(cpm); out_free: - dev_set_drvdata(&ofdev->dev, NULL); kfree(cpm); return result; @@ -696,7 +695,6 @@ static int cpm_i2c_remove(struct platform_device *ofdev) cpm_i2c_shutdown(cpm); - dev_set_drvdata(&ofdev->dev, NULL); kfree(cpm); return 0; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 6a0a5531944..7d1e590a7bb 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -755,7 +755,6 @@ err_mem_ioremap: clk_put(dev->clk); dev->clk = NULL; err_free_mem: - platform_set_drvdata(pdev, NULL); put_device(&pdev->dev); kfree(dev); err_release_region: @@ -771,7 +770,6 @@ static int davinci_i2c_remove(struct platform_device *pdev) i2c_davinci_cpufreq_deregister(dev); - platform_set_drvdata(pdev, NULL); i2c_del_adapter(&dev->adapter); put_device(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 6add851e9de..7c5e383c350 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -319,7 +319,6 @@ err_free_irq: free_irq(pdev->irq, dev); err_iounmap: iounmap(dev->base); - pci_set_drvdata(pdev, NULL); put_device(&pdev->dev); kfree(dev); err_release_region: @@ -336,7 +335,6 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); - pci_set_drvdata(pdev, NULL); i2c_del_adapter(&dev->adapter); put_device(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d2a33e93f8a..0ceb6e1b0f6 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -207,7 +207,6 @@ err_unuse_clocks: clk_put(dev->clk); dev->clk = NULL; err_free_mem: - platform_set_drvdata(pdev, NULL); put_device(&pdev->dev); kfree(dev); err_release_region: @@ -221,7 +220,6 @@ static int dw_i2c_remove(struct platform_device *pdev) struct dw_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; - platform_set_drvdata(pdev, NULL); pm_runtime_get_sync(&pdev->dev); i2c_del_adapter(&dev->adapter); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 5e7886e7136..0f3752967c4 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -869,8 +869,6 @@ static void pch_i2c_remove(struct pci_dev *pdev) for (i = 0; i < adap_info->ch_num; i++) adap_info->pch_data[i].pch_base_address = NULL; - pci_set_drvdata(pdev, NULL); - pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 3351cc7ed11..436b0f25491 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -436,8 +436,6 @@ err_unmap: err: kfree(dev); - platform_set_drvdata(pdev, NULL); - return ret; } @@ -453,8 +451,6 @@ static int highlander_i2c_remove(struct platform_device *pdev) iounmap(dev->base); kfree(dev); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 76febfb0976..e1cf2e0e1f2 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1254,7 +1254,6 @@ static void i801_remove(struct pci_dev *dev) free_irq(dev->irq, priv); pci_release_region(dev, SMBBAR); - pci_set_drvdata(dev, NULL); kfree(priv); /* * do not call pci_disable_device(dev) since it can cause hard hangs on diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 33a2abb6c06..405a2e24045 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -773,7 +773,6 @@ error_cleanup: if (dev->vaddr) iounmap(dev->vaddr); - dev_set_drvdata(&ofdev->dev, NULL); kfree(dev); return ret; } @@ -785,8 +784,6 @@ static int iic_remove(struct platform_device *ofdev) { struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev); - dev_set_drvdata(&ofdev->dev, NULL); - i2c_del_adapter(&dev->adap); if (dev->irq) { diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index b9734747d61..c5d2ba3c4cd 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -605,7 +605,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev) /* remove adapter */ dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); i2c_del_adapter(&i2c_imx->adapter); - platform_set_drvdata(pdev, NULL); /* setup chip registers to defaults */ writeb(0, i2c_imx->base + IMX_I2C_IADR); diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index de3736bf646..323fa018ffd 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1069,7 +1069,6 @@ static int intel_mid_i2c_probe(struct pci_dev *dev, fail3: free_irq(dev->irq, mrst); fail2: - pci_set_drvdata(dev, NULL); kfree(mrst); fail1: iounmap(base); @@ -1087,7 +1086,6 @@ static void intel_mid_i2c_remove(struct pci_dev *dev) dev_err(&dev->dev, "Failed to delete i2c adapter"); free_irq(dev->irq, mrst); - pci_set_drvdata(dev, NULL); iounmap(mrst->base); kfree(mrst); pci_release_region(dev, 0); diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 2f99613fd67..bc993331c69 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -415,8 +415,6 @@ iop3xx_i2c_remove(struct platform_device *pdev) kfree(adapter_data); kfree(padapter); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index a69459e5c3f..5e705ee02f4 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -696,7 +696,6 @@ static int fsl_i2c_probe(struct platform_device *op) return result; fail_add: - dev_set_drvdata(&op->dev, NULL); free_irq(i2c->irq, i2c); fail_request: irq_dispose_mapping(i2c->irq); @@ -711,7 +710,6 @@ static int fsl_i2c_remove(struct platform_device *op) struct mpc_i2c *i2c = dev_get_drvdata(&op->dev); i2c_del_adapter(&i2c->adap); - dev_set_drvdata(&op->dev, NULL); if (i2c->irq) free_irq(i2c->irq, i2c); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 22d8ad35340..120f2464669 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -697,8 +697,6 @@ static int mxs_i2c_remove(struct platform_device *pdev) writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5b1b1948128..650293ff4d6 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1105,7 +1105,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) err_irq: iounmap(dev->virtbase); err_no_ioremap: - amba_set_drvdata(adev, NULL); kfree(dev); err_pinctrl: err_no_mem: @@ -1130,7 +1129,6 @@ static int nmk_i2c_remove(struct amba_device *adev) release_mem_region(res->start, resource_size(res)); clk_put(dev->clk); pm_runtime_disable(&adev->dev); - amba_set_drvdata(adev, NULL); kfree(dev); return 0; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 6afa02db115..dd3df76c2e3 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -451,7 +451,6 @@ static int ocores_i2c_remove(struct platform_device *pdev) /* remove adapter & data */ i2c_del_adapter(&i2c->adap); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 484ca771fdf..935585ef4d3 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -595,7 +595,7 @@ static int octeon_i2c_probe(struct platform_device *pdev) result = i2c_add_adapter(&i2c->adap); if (result < 0) { dev_err(i2c->dev, "failed to add adapter\n"); - goto fail_add; + goto out; } dev_info(i2c->dev, "version %s\n", DRV_VERSION); @@ -603,8 +603,6 @@ static int octeon_i2c_probe(struct platform_device *pdev) return 0; -fail_add: - platform_set_drvdata(pdev, NULL); out: return result; }; @@ -614,7 +612,6 @@ static int octeon_i2c_remove(struct platform_device *pdev) struct octeon_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); - platform_set_drvdata(pdev, NULL); return 0; }; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4cc2f0528c8..79d05128c77 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1262,7 +1262,6 @@ err_unuse_clocks: pm_runtime_put(dev->dev); pm_runtime_disable(&pdev->dev); err_free_mem: - platform_set_drvdata(pdev, NULL); return r; } @@ -1272,8 +1271,6 @@ static int omap_i2c_remove(struct platform_device *pdev) struct omap_i2c_dev *dev = platform_get_drvdata(pdev); int ret; - platform_set_drvdata(pdev, NULL); - i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (IS_ERR_VALUE(ret)) diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index a30d2f613c0..aa00df14e30 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -260,7 +260,6 @@ e_print: static int i2c_pca_pf_remove(struct platform_device *pdev) { struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); i2c_del_adapter(&i2c->adap); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 083d68cfaf0..f6389e2c9d0 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -349,7 +349,6 @@ static int pmcmsptwi_probe(struct platform_device *pldev) return 0; ret_unmap: - platform_set_drvdata(pldev, NULL); if (pmcmsptwi_data.irq) { pmcmsptwi_writel(0, pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET); @@ -374,7 +373,6 @@ static int pmcmsptwi_remove(struct platform_device *pldev) i2c_del_adapter(&pmcmsptwi_adapter); - platform_set_drvdata(pldev, NULL); if (pmcmsptwi_data.irq) { pmcmsptwi_writel(0, pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET); diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index ce4097012e9..5f39c6d8117 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -761,7 +761,6 @@ out_clkget: out_drvdata: kfree(alg_data); err_kzalloc: - platform_set_drvdata(pdev, NULL); return ret; } @@ -776,7 +775,6 @@ static int i2c_pnx_remove(struct platform_device *pdev) release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); clk_put(alg_data->clk); kfree(alg_data); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 0dd5b334d09..da54e673449 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -221,7 +221,6 @@ static int i2c_powermac_remove(struct platform_device *dev) printk(KERN_WARNING "i2c-powermac.c: Failed to remove bus %s !\n", adapter->name); - platform_set_drvdata(dev, NULL); memset(adapter, 0, sizeof(*adapter)); return 0; diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index d7c512d717a..261d7db437e 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -223,7 +223,6 @@ static int puv3_i2c_probe(struct platform_device *pdev) return 0; fail_add_adapter: - platform_set_drvdata(pdev, NULL); kfree(adapter); fail_nomem: release_mem_region(mem->start, resource_size(mem)); @@ -245,7 +244,6 @@ static int puv3_i2c_remove(struct platform_device *pdev) } put_device(&pdev->dev); - platform_set_drvdata(pdev, NULL); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 3d4985695ae..9639be86e53 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -128,7 +128,6 @@ static int ce4100_i2c_probe(struct pci_dev *dev, return 0; err_dev_add: - pci_set_drvdata(dev, NULL); kfree(sds); err_mem: pci_disable_device(dev); @@ -141,7 +140,6 @@ static void ce4100_i2c_remove(struct pci_dev *dev) unsigned int i; sds = pci_get_drvdata(dev); - pci_set_drvdata(dev, NULL); for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) platform_device_unregister(sds->pdev[i]); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 4a79e768a4d..1e88e8d66c5 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1219,8 +1219,6 @@ static int i2c_pxa_remove(struct platform_device *dev) { struct pxa_i2c *i2c = platform_get_drvdata(dev); - platform_set_drvdata(dev, NULL); - i2c_del_adapter(&i2c->adap); if (!i2c->use_pio) free_irq(i2c->irq, i2c); diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c index 008836409ef..7c1ca5aca08 100644 --- a/drivers/i2c/busses/i2c-s6000.c +++ b/drivers/i2c/busses/i2c-s6000.c @@ -365,7 +365,6 @@ static int s6i2c_remove(struct platform_device *pdev) { struct s6i2c_if *iface = platform_get_drvdata(pdev); i2c_wr16(iface, S6_I2C_ENABLE, 0); - platform_set_drvdata(pdev, NULL); i2c_del_adapter(&iface->adap); free_irq(iface->irq, iface); clk_disable(iface->clk); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 3a2253e1bf5..5351a2f3491 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -546,7 +546,6 @@ static int sh7760_i2c_remove(struct platform_device *pdev) release_resource(id->ioarea); kfree(id->ioarea); kfree(id); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 580a0c04cb4..f1912c8520f 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -975,7 +975,6 @@ stu300_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); /* Turn off everything */ stu300_wr8(0x00, dev->virtbase + I2C_CR); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index 26c352a0929..6ffa56e0851 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -271,7 +271,6 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) exit_close: serio_close(serio); exit_kfree: - serio_set_drvdata(serio, NULL); kfree(taos); exit: return err; @@ -285,7 +284,6 @@ static void taos_disconnect(struct serio *serio) i2c_unregister_device(taos->client); i2c_del_adapter(&taos->adapter); serio_close(serio); - serio_set_drvdata(serio, NULL); kfree(taos); dev_info(&serio->dev, "Disconnected from TAOS EVM\n"); diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index eec20db6246..f3a8790a07e 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -125,8 +125,6 @@ static int i2c_versatile_remove(struct platform_device *dev) { struct i2c_versatile *i2c = platform_get_drvdata(dev); - platform_set_drvdata(dev, NULL); - i2c_del_adapter(&i2c->adap); return 0; } diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index f042f6da0ac..332c720fb3f 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -784,8 +784,6 @@ static int xiic_i2c_remove(struct platform_device *pdev) xiic_deinit(i2c); - platform_set_drvdata(pdev, NULL); - free_irq(platform_get_irq(pdev, 0), i2c); iounmap(i2c->base); diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index a005265461d..86010293e23 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -257,7 +257,6 @@ static int xlr_i2c_remove(struct platform_device *pdev) priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 3862a953239..2d1d2c5653f 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -542,7 +542,6 @@ static int scx200_remove(struct platform_device *pdev) struct scx200_acb_iface *iface; iface = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); scx200_cleanup_iface(iface); return 0; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 9f50ef04a4b..abc2e55aa24 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -250,7 +250,6 @@ static int i2c_mux_gpio_remove(struct platform_device *pdev) for (i = 0; i < mux->data.n_gpios; i++) gpio_free(mux->gpio_base + mux->data.gpios[i]); - platform_set_drvdata(pdev, NULL); i2c_put_adapter(mux->parent); return 0; -- cgit v1.2.3