diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:41:53 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-26 09:41:53 -0800 |
commit | 52caa59ed335616c5254adff7911465a57ed9f14 (patch) | |
tree | de0a1e91850c9e439e82f83f228d89fee3b90b09 /drivers/i2c | |
parent | 4c8c225abf972ce422c241579ce1d4d27eaeb166 (diff) | |
parent | 55827f4aa6442ddd1d6a4e1e32f2f457eb113c22 (diff) |
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"Highlights:
- new drivers for Intel ismt & Broadcom bcm2835
- a number of drivers got support for more variants and mostly got
cleaned up on the way (sis630, i801, at91, tegra, designware)
- i2c got rid of all *_set_drvdata(..., NULL) on remove/probe failure
- removed the i2c_smbus_process_call from the core since there are no
users
- mxs can now switch between PIO and DMA depending on the message
size and the bus speed can now be arbitrary
In addition, there is the usual bunch of fixes, cleanups, devm_*
conversions, etc"
Fixed conflict (and buggy devm_* conversion) in i2c-s3c2410.c
* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (39 commits)
i2c: Remove unneeded xxx_set_drvdata(..., NULL) calls
i2c: pxa: remove incorrect __exit annotations
i2c: ocores: Fix pointer to integer cast warning
i2c: tegra: remove warning dump if timeout happen in transfer
i2c: fix i2c-ismt.c printk format warning
i2c: i801: Add Device IDs for Intel Wellsburg PCH
i2c: add bcm2835 driver
i2c: ismt: Add Seth and Myself as maintainers
i2c: sis630: checkpatch cleanup
i2c: sis630: display unsigned hex
i2c: sis630: use hex to constants for SMBus commands
i2c: sis630: fix behavior after collision
i2c: sis630: clear sticky bits
i2c: sis630: Add SIS964 support
i2c: isch: Add module parameter for backbone clock rate if divider is unset
i2c: at91: fix unsed variable warning when building with !CONFIG_OF
i2c: Adding support for Intel iSMT SMBus 2.0 host controller
i2c: sh_mobile: don't send a stop condition by default inside transfers
i2c: sh_mobile: eliminate an open-coded "goto" loop
i2c: sh_mobile: fix timeout error handling
...
Diffstat (limited to 'drivers/i2c')
48 files changed, 2224 insertions, 505 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8bb810e1900..a3725de9238 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -106,6 +106,8 @@ config I2C_I801 Panther Point (PCH) 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. @@ -121,6 +123,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 @@ -186,11 +198,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. @@ -319,6 +331,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 6181f3ff263..8f4fc23b85b 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 @@ -30,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-at91.c b/drivers/i2c/busses/i2c-at91.c index ebc22415469..75195e3f5dd 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,8 +575,18 @@ 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", + .data = &at91rm9200_config, + } , { .compatible = "atmel,at91sam9260-i2c", .data = &at91sam9260_config, } , { 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-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 <linux/clk.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#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 <swarren@wwwdotorg.org>"); +MODULE_DESCRIPTION("BCM2835 I2C bus adapter"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-bcm2835"); 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-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--; } 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 343357a2b5b..0ceb6e1b0f6 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -37,8 +37,10 @@ #include <linux/of_i2c.h> #include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/acpi.h> #include "i2c-designware-core.h" static struct i2c_algorithm i2c_dw_algo = { @@ -50,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; @@ -114,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; @@ -140,14 +182,19 @@ 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); + pm_runtime_put(&pdev->dev); return 0; @@ -160,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: @@ -174,7 +220,8 @@ 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); put_device(&pdev->dev); @@ -186,6 +233,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; @@ -233,6 +283,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, }, }; 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 3092387f6ef..e1cf2e0e1f2 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -53,6 +53,11 @@ 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 + 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 @@ -162,9 +167,14 @@ #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 +#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 { @@ -798,6 +808,11 @@ 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) }, + { 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, } }; @@ -1103,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: @@ -1236,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 a71ece63e91..82f20c60bb7 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-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) { diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c new file mode 100644 index 00000000000..e9205ee8cf9 --- /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 <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/stddef.h> +#include <linux/completion.h> +#include <linux/dma-mapping.h> +#include <linux/i2c.h> +#include <linux/acpi.h> +#include <linux/interrupt.h> + +#include <asm-generic/io-64-nonatomic-lo-hi.h> + +/* 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 + <addr>) */ +#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", + (unsigned long long)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 <bill.e.brown@intel.com>"); +MODULE_DESCRIPTION("Intel SMBus Message Transport (iSMT) driver"); 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 d6abaf2cf2e..120f2464669 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 | \ @@ -85,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 * @@ -129,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; @@ -145,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); } @@ -298,6 +286,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 +433,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"); @@ -403,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; @@ -422,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; } @@ -471,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); @@ -531,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-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 <linux/io.h> MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>"); +MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); 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: diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 8b2ffcf4532..650293ff4d6 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -26,6 +26,7 @@ #include <linux/platform_data/i2c-nomadik.h> #include <linux/of.h> #include <linux/of_i2c.h> +#include <linux/pinctrl/consumer.h> #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; }; @@ -402,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); @@ -472,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); @@ -636,6 +644,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 +680,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; @@ -703,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); @@ -857,15 +882,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 +1004,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; @@ -1020,8 +1105,8 @@ 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: return ret; @@ -1044,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 a337d08a392..0e1f8245e76 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -332,7 +332,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; @@ -452,7 +452,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 3ee188679cf..e02f9e36a7b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1260,7 +1260,6 @@ err_unuse_clocks: pm_runtime_put(dev->dev); pm_runtime_disable(&pdev->dev); err_free_mem: - platform_set_drvdata(pdev, NULL); return r; } @@ -1270,8 +1269,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 1034d93fb83..1e88e8d66c5 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1215,12 +1215,10 @@ 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); - platform_set_drvdata(dev, NULL); - i2c_del_adapter(&i2c->adap); if (!i2c->use_pio) free_irq(i2c->irq, i2c); @@ -1269,7 +1267,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, diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index c807a6d14f0..f6b880ba193 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); @@ -1000,8 +1002,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); @@ -1022,32 +1024,27 @@ 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"); - ret = -ENOENT; - goto err_noclk; + return -ENOENT; } 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_ioremap_resource(&pdev->dev, res); - if (IS_ERR(i2c->regs)) { - ret = PTR_ERR(i2c->regs); - goto err_clk; - } + if (IS_ERR(i2c->regs)) + return PTR_ERR(i2c->regs); dev_dbg(&pdev->dev, "registers %p (%p)\n", i2c->regs, res); @@ -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,21 +1080,21 @@ 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 = 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); - 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_irq; + return ret; } /* Note, previous versions of the driver used i2c_add_adapter() @@ -1110,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,21 +1120,7 @@ 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_irq: - free_irq(i2c->irq, i2c); - - err_clk: - clk_disable_unprepare(i2c->clk); - clk_put(i2c->clk); - - err_noclk: - return ret; } /* s3c24xx_i2c_remove @@ -1152,10 +1138,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); 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-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index b6e7a83a829..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); @@ -349,20 +355,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, @@ -475,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; @@ -501,6 +504,61 @@ 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; + + 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) @@ -508,53 +566,39 @@ 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); /* 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, pd->sr & (ICSR_TACK | SW_DONE), 5 * HZ); - if (!k) + if (!k) { dev_err(pd->dev, "Transfer request timed out\n"); - - 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 = -ETIMEDOUT; break; } - /* handle missing acknowledge and arbitration lost */ - if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) { - err = -EIO; + if (pd->send_stop) + err = poll_busy(pd); + else + err = poll_dte(pd); + if (err < 0) break; - } } deactivate_ch(pd); @@ -566,7 +610,7 @@ again: 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 = { diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index de6dddb9f86..36a9556d7cf 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -17,30 +17,25 @@ */ /* - 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 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 +50,36 @@ #include <linux/acpi.h> #include <linux/io.h> -/* 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 */ + +/* 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 + */ #define SIS630_SMB_IOREGION 20 /* PCI address constants */ @@ -96,65 +105,71 @@ 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) +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. */ - 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 { + } 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, 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; } @@ -168,7 +183,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)); @@ -178,19 +193,14 @@ 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 = -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; @@ -198,21 +208,21 @@ 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)); + 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 * 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)); + 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) @@ -229,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; @@ -241,39 +252,43 @@ 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. clear SMBARY_STS */ - sis630_write(SMB_STS,0x10); + sis630_write(SMB_STS, BYTE_DONE_STS); } 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, @@ -294,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,0x10); - } while(len < data->block[0]); + sis630_write(SMB_STS, BYTE_DONE_STS); + } while (len < data->block[0]); } sis630_transaction_end(adap, oldclock); @@ -321,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); @@ -368,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; @@ -384,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) @@ -394,21 +419,23 @@ 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++) { - 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; } @@ -416,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; @@ -430,24 +457,35 @@ 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; } - 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; + else + smbus_base = acpi_base + 0x80; + + dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base); - retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, + 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 +494,7 @@ static int sis630_setup(struct pci_dev *sis630_dev) exit: if (retval) - acpi_base = 0; + smbus_base = 0; return retval; } @@ -470,20 +508,24 @@ 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, } }; -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; } @@ -491,17 +533,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; } } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 60195b59063..0a6f941133f 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-tegra.c b/drivers/i2c/busses/i2c-tegra.c index f0d9923323e..36704e3ab3f 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -70,6 +70,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) @@ -116,10 +118,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; }; /** @@ -365,11 +380,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) { @@ -383,13 +400,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); @@ -404,7 +424,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); @@ -546,6 +574,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) @@ -557,7 +587,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); @@ -633,15 +663,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, }, @@ -685,12 +732,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"); @@ -699,7 +740,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; @@ -730,6 +770,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); 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 93f029e98c0..7945b05d3ea 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -256,7 +256,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/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 @@ -1866,29 +1866,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 * @command: Byte interpreted by slave 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; |