From 45f176aea60e9fe8c5fdf8e5c90e5c50c264d86f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 26 Sep 2013 19:36:11 -0700 Subject: i2c: i2c-dev: Create 'name' attribute automatically The 'name' attribute is needed for all i2c-dev class devices, meaning it can be created automatically by pointing to it in the class data structure. This simplifies the code and reduces the probability for race conditions (the name attribute should exist by the time the device is announced to user space). Signed-off-by: Guenter Roeck Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index c3ccdea..80b47e8 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -102,8 +102,8 @@ static void return_i2c_dev(struct i2c_dev *i2c_dev) kfree(i2c_dev); } -static ssize_t show_adapter_name(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt)); @@ -111,7 +111,13 @@ static ssize_t show_adapter_name(struct device *dev, return -ENODEV; return sprintf(buf, "%s\n", i2c_dev->adap->name); } -static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); +static DEVICE_ATTR_RO(name); + +static struct attribute *i2c_attrs[] = { + &dev_attr_name.attr, + NULL, +}; +ATTRIBUTE_GROUPS(i2c); /* ------------------------------------------------------------------------- */ @@ -562,15 +568,10 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy) res = PTR_ERR(i2c_dev->dev); goto error; } - res = device_create_file(i2c_dev->dev, &dev_attr_name); - if (res) - goto error_destroy; pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", adap->name, adap->nr); return 0; -error_destroy: - device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr)); error: return_i2c_dev(i2c_dev); return res; @@ -589,7 +590,6 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy) if (!i2c_dev) /* attach_adapter must have failed */ return 0; - device_remove_file(i2c_dev->dev, &dev_attr_name); return_i2c_dev(i2c_dev); device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr)); @@ -637,6 +637,7 @@ static int __init i2c_dev_init(void) res = PTR_ERR(i2c_dev_class); goto out_unreg_chrdev; } + i2c_dev_class->dev_groups = i2c_groups; /* Keep track of adapters which will be added or removed later */ res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); -- cgit v0.10.2 From 14d32f1794fd559e12f27e8b5c57053073bd75aa Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Sep 2013 14:36:44 +0200 Subject: i2c: rcar: (cosmetic) remove superfluous parenthesis A recent patch added even more superfluous parenthesis to those, which already were there. Remove them again. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index d2fe11d..15eef94 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -306,7 +306,7 @@ scgd_find: /* * keep icccr value */ - priv->icccr = (scgd << (cdf_width) | cdf); + priv->icccr = scgd << cdf_width | cdf; return 0; } -- cgit v0.10.2 From 8d0494037bb2af32a22563d40703c1263fca318d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Sep 2013 14:36:45 +0200 Subject: i2c: rcar: get clock rate only once and simplify calculation There is no need to repeatedly query clock frequency, where it is not expected to change. The complete loop can also trivially be replaced with a simple division. A further loop below the one, being simplified, could also be replaced, but that would get more complicated. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 15eef94..9325db4 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -231,6 +231,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, u32 round, ick; u32 scl; u32 cdf_width; + unsigned long rate; if (!clkp) { dev_err(dev, "there is no peripheral_clk\n"); @@ -264,15 +265,14 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, * clkp : peripheral_clk * F[] : integer up-valuation */ - for (cdf = 0; cdf < (1 << cdf_width); cdf++) { - ick = clk_get_rate(clkp) / (1 + cdf); - if (ick < 20000000) - goto ick_find; + rate = clk_get_rate(clkp); + cdf = rate / 20000000; + if (cdf >= 1 << cdf_width) { + dev_err(dev, "Input clock %lu too high\n", rate); + return -EIO; } - dev_err(dev, "there is no best CDF\n"); - return -EIO; + ick = rate / (cdf + 1); -ick_find: /* * it is impossible to calculate large scale * number on u32. separate it @@ -290,6 +290,12 @@ ick_find: * * Calculation result (= SCL) should be less than * bus_speed for hardware safety + * + * We could use something along the lines of + * div = ick / (bus_speed + 1) + 1; + * scgd = (div - 20 - round + 7) / 8; + * scl = ick / (20 + (scgd * 8) + round); + * (not fully verified) but that would get pretty involved */ for (scgd = 0; scgd < 0x40; scgd++) { scl = ick / (20 + (scgd * 8) + round); -- cgit v0.10.2 From 7679c0e19120ee7839adf1f05904cbfcc7a7c2b9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Sep 2013 14:36:46 +0200 Subject: i2c: rcar: add Device Tree support This patch adds Device Tree support to the i2c-rcar driver and respective documentation. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt new file mode 100644 index 0000000..897cfcd5 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -0,0 +1,23 @@ +I2C for R-Car platforms + +Required properties: +- compatible: Must be one of + "renesas,i2c-rcar" + "renesas,i2c-r8a7778" + "renesas,i2c-r8a7779" + "renesas,i2c-r8a7790" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt specifier. + +Optional properties: +- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this + propoerty indicates the default frequency 100 kHz. + +Examples : + +i2c0: i2c@e6500000 { + compatible = "renesas,i2c-rcar-h2"; + reg = <0 0xe6500000 0 0x428>; + interrupts = <0 174 0x4>; +}; diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 9325db4..1f285a3 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -638,6 +639,15 @@ static const struct i2c_algorithm rcar_i2c_algo = { .functionality = rcar_i2c_func, }; +static const struct of_device_id rcar_i2c_dt_ids[] = { + { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_H1 }, + { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_H1 }, + { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_H1 }, + { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_H2 }, + {}, +}; +MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); + static int rcar_i2c_probe(struct platform_device *pdev) { struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -655,10 +665,15 @@ static int rcar_i2c_probe(struct platform_device *pdev) } bus_speed = 100000; /* default 100 kHz */ - if (pdata && pdata->bus_speed) + ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed); + if (ret < 0 && pdata && pdata->bus_speed) bus_speed = pdata->bus_speed; - priv->devtype = platform_get_device_id(pdev)->driver_data; + if (pdev->dev.of_node) + priv->devtype = (long)of_match_device(rcar_i2c_dt_ids, + dev)->data; + else + priv->devtype = platform_get_device_id(pdev)->driver_data; ret = rcar_i2c_clock_calculate(priv, bus_speed, dev); if (ret < 0) @@ -679,6 +694,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->retries = 3; adap->dev.parent = dev; + adap->dev.of_node = dev->of_node; i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); @@ -726,6 +742,7 @@ static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .owner = THIS_MODULE, + .of_match_table = rcar_i2c_dt_ids, }, .probe = rcar_i2c_probe, .remove = rcar_i2c_remove, -- cgit v0.10.2 From 330c824a49cd49dd7e61c1e397fa4e7380ba2c68 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Sep 2013 14:36:47 +0200 Subject: i2c: rcar: fix clk_get() error handling When clk_get() fails, it returns an error code, not a NULL. This patch fixes such an error handling bug. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 1f285a3..98276eb 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -234,9 +234,9 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, u32 cdf_width; unsigned long rate; - if (!clkp) { - dev_err(dev, "there is no peripheral_clk\n"); - return -EIO; + if (IS_ERR(clkp)) { + dev_err(dev, "couldn't get clock\n"); + return PTR_ERR(clkp); } switch (priv->devtype) { -- cgit v0.10.2 From 991e7ecf1f1a2e2fa76387066342a5a6c4a28a76 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 12 Sep 2013 14:36:48 +0200 Subject: i2c: rcar: use per-device clock Using the same clock for all device instances is non-portable and obtaining clock references by an ID without using a device pointer is discouraged. This is also not needed, because on platforms, where this driver is used, suitable clocks are available for the I2C controllers, that are children of the peripheral clock and just pass its rate 1-to-1 to controllers. This patch switches the driver to obtain references to correct clocks. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 98276eb..8603f5e 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -227,7 +227,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, u32 bus_speed, struct device *dev) { - struct clk *clkp = clk_get(NULL, "peripheral_clk"); + struct clk *clkp = clk_get(dev, NULL); u32 scgd, cdf; u32 round, ick; u32 scl; -- cgit v0.10.2 From ab0dc7a81df2595a18b328d2c7031b00bd7efb1e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Sep 2013 14:31:29 +0900 Subject: i2c: xiic: Remove casting the return value which is a void pointer Casting the return value which is a void pointer is redundant. The conversion from void pointer to any other pointer type is guaranteed by the C programming language. Signed-off-by: Jingoo Han Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 4c8b368..6e7b09c 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -702,7 +702,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) if (irq < 0) goto resource_missing; - pdata = (struct xiic_i2c_platform_data *)dev_get_platdata(&pdev->dev); + pdata = dev_get_platdata(&pdev->dev); i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); if (!i2c) -- cgit v0.10.2 From 3c41aa710846c76400d6e8cf06600cc3eb8cbcc2 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 9 Sep 2013 14:32:25 +0900 Subject: i2c: bfin-twi: Remove casting the return value which is a void pointer Casting the return value which is a void pointer is redundant. The conversion from void pointer to any other pointer type is guaranteed by the C programming language. Signed-off-by: Jingoo Han Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 35a473b..3b9bd9a 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -675,7 +675,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) p_adap->retries = 3; rc = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), + dev_get_platdata(&pdev->dev), "i2c-bfin-twi"); if (rc) { dev_err(&pdev->dev, "Can't setup pin mux!\n"); @@ -723,7 +723,7 @@ out_error_add_adapter: free_irq(iface->irq, iface); out_error_req_irq: out_error_no_irq: - peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); out_error_pin_mux: iounmap(iface->regs_base); out_error_ioremap: @@ -739,7 +739,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) i2c_del_adapter(&(iface->adap)); free_irq(iface->irq, iface); - peripheral_free_list((unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); iounmap(iface->regs_base); kfree(iface); -- cgit v0.10.2 From 25f73ed5c67d17ecf8cefd560f55211cce726086 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 27 Sep 2013 15:06:28 -0400 Subject: misc: (at24) move header to linux/platform_data/ This patch moves the at24.h header from include/linux/i2c to include/linux/platform_data and updates existing support accordingly. It also fixes the following checkpatch warning: WARNING: please, no space before tabs #436: FILE: include/linux/platform_data/at24.h:31: + * ^Iu8 *mac_addr = ethernet_pdata->mac_addr;$ Signed-off-by: Vivien Didelot Signed-off-by: Wolfram Sang diff --git a/MAINTAINERS b/MAINTAINERS index 284969f..b9d19a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1396,7 +1396,7 @@ M: Wolfram Sang L: linux-i2c@vger.kernel.org S: Maintained F: drivers/misc/eeprom/at24.c -F: include/linux/i2c/at24.h +F: include/linux/platform_data/at24.h ATA OVER ETHERNET (AOE) DRIVER M: "Ed L. Cashin" diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index 0b153c8..f4f8735 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index 3284df0..947e134 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index c4bdc0a..66b5b3c 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index dd1fb24..f25a569 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 92b7f77..30ee81f 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 40bb9b5..f21fde9 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 2bc3651..db2df32 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index cd0f587..7aa105b 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index d843601..41c7c96 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index 19bb644..c5f9567 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index bc0261e..20cc53f 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c index e805ac2..592ddbe 100644 --- a/arch/arm/mach-imx/mach-pcm038.c +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c index b726cb1..ac504b6 100644 --- a/arch/arm/mach-imx/mach-pcm043.c +++ b/arch/arm/mach-imx/mach-pcm043.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c index 0910761..8825d12 100644 --- a/arch/arm/mach-imx/mach-vpr200.c +++ b/arch/arm/mach-imx/mach-vpr200.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include "common.h" diff --git a/arch/arm/mach-kirkwood/lacie_v2-common.c b/arch/arm/mach-kirkwood/lacie_v2-common.c index 4894959..8e3e433 100644 --- a/arch/arm/mach-kirkwood/lacie_v2-common.c +++ b/arch/arm/mach-kirkwood/lacie_v2-common.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index a7ce692..d68909b 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -300,7 +300,7 @@ static struct omap_lcd_config osk_lcd_config __initdata = { #ifdef CONFIG_OMAP_OSK_MISTRAL #include -#include +#include #include #include diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 33d159e..8dd0ec8 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 87e41a8..f780834 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index ba8342f..119efaf 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c index 62aea3e..01de542 100644 --- a/arch/arm/mach-pxa/stargate2.c +++ b/arch/arm/mach-pxa/stargate2.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index a83db46..4a18d49 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 5d4fd69..4ef01ab 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include /* * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. diff --git a/include/linux/i2c/at24.h b/include/linux/i2c/at24.h deleted file mode 100644 index 285025a..0000000 --- a/include/linux/i2c/at24.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * at24.h - platform_data for the at24 (generic eeprom) driver - * (C) Copyright 2008 by Pengutronix - * (C) Copyright 2012 by Wolfram Sang - * same license as the driver - */ - -#ifndef _LINUX_AT24_H -#define _LINUX_AT24_H - -#include -#include - -/** - * struct at24_platform_data - data to set up at24 (generic eeprom) driver - * @byte_len: size of eeprom in byte - * @page_size: number of byte which can be written in one go - * @flags: tunable options, check AT24_FLAG_* defines - * @setup: an optional callback invoked after eeprom is probed; enables kernel - code to access eeprom via memory_accessor, see example - * @context: optional parameter passed to setup() - * - * If you set up a custom eeprom type, please double-check the parameters. - * Especially page_size needs extra care, as you risk data loss if your value - * is bigger than what the chip actually supports! - * - * An example in pseudo code for a setup() callback: - * - * void get_mac_addr(struct memory_accessor *mem_acc, void *context) - * { - * u8 *mac_addr = ethernet_pdata->mac_addr; - * off_t offset = context; - * - * // Read MAC addr from EEPROM - * if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN) - * pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr); - * } - * - * This function pointer and context can now be set up in at24_platform_data. - */ - -struct at24_platform_data { - u32 byte_len; /* size (sum of all addr) */ - u16 page_size; /* for writes */ - u8 flags; -#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */ -#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ -#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ -#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ - - void (*setup)(struct memory_accessor *, void *context); - void *context; -}; - -#endif /* _LINUX_AT24_H */ diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h new file mode 100644 index 0000000..c42aa89 --- /dev/null +++ b/include/linux/platform_data/at24.h @@ -0,0 +1,55 @@ +/* + * at24.h - platform_data for the at24 (generic eeprom) driver + * (C) Copyright 2008 by Pengutronix + * (C) Copyright 2012 by Wolfram Sang + * same license as the driver + */ + +#ifndef _LINUX_AT24_H +#define _LINUX_AT24_H + +#include +#include + +/** + * struct at24_platform_data - data to set up at24 (generic eeprom) driver + * @byte_len: size of eeprom in byte + * @page_size: number of byte which can be written in one go + * @flags: tunable options, check AT24_FLAG_* defines + * @setup: an optional callback invoked after eeprom is probed; enables kernel + code to access eeprom via memory_accessor, see example + * @context: optional parameter passed to setup() + * + * If you set up a custom eeprom type, please double-check the parameters. + * Especially page_size needs extra care, as you risk data loss if your value + * is bigger than what the chip actually supports! + * + * An example in pseudo code for a setup() callback: + * + * void get_mac_addr(struct memory_accessor *mem_acc, void *context) + * { + * u8 *mac_addr = ethernet_pdata->mac_addr; + * off_t offset = context; + * + * // Read MAC addr from EEPROM + * if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN) + * pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr); + * } + * + * This function pointer and context can now be set up in at24_platform_data. + */ + +struct at24_platform_data { + u32 byte_len; /* size (sum of all addr) */ + u16 page_size; /* for writes */ + u8 flags; +#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */ +#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ +#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ +#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ + + void (*setup)(struct memory_accessor *, void *context); + void *context; +}; + +#endif /* _LINUX_AT24_H */ -- cgit v0.10.2 From 4e9053231a168646b3e17f4cab6eae3da66f7152 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 30 Sep 2013 09:04:25 +0530 Subject: i2c: remove redundant of_match_ptr The data structure of_match_ptr() protects is always compiled in. Hence of_match_ptr() is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 132369f..85e8ad6 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -795,7 +795,7 @@ static struct platform_driver davinci_i2c_driver = { .name = "i2c_davinci", .owner = THIS_MODULE, .pm = davinci_i2c_pm_ops, - .of_match_table = of_match_ptr(davinci_i2c_of_match), + .of_match_table = davinci_i2c_of_match, }, }; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d3e9cc3..8be7e42 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -911,7 +911,7 @@ static struct platform_driver mv64xxx_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, - .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table), + .of_match_table = mv64xxx_i2c_of_match_table, }, }; diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 74b41ae..cb9af93 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -238,7 +238,7 @@ static struct platform_driver i2c_arbitrator_driver = { .driver = { .owner = THIS_MODULE, .name = "i2c-arb-gpio-challenge", - .of_match_table = of_match_ptr(i2c_arbitrator_of_match), + .of_match_table = i2c_arbitrator_of_match, }, }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 5d4a99b..927a7de 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -279,7 +279,7 @@ static struct platform_driver i2c_mux_gpio_driver = { .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", - .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), + .of_match_table = i2c_mux_gpio_of_match, }, }; -- cgit v0.10.2 From 05308a6e98e9812c1c6ac64efb16f424d2efd3cb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:50:59 +0200 Subject: media: s5c73m3: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. The results of the expressions 'client->driver.driver->field' and 'client->dev.driver->field' are identical, so replace all occurrences of the former with the later. Signed-off-by: Lars-Peter Clausen Acked-by: Sylwester Nawrocki Signed-off-by: Wolfram Sang diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index b76ec0e..1083890 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1581,7 +1581,7 @@ static int s5c73m3_probe(struct i2c_client *client, oif_sd = &state->oif_sd; v4l2_subdev_init(sd, &s5c73m3_subdev_ops); - sd->owner = client->driver->driver.owner; + sd->owner = client->dev.driver->owner; v4l2_set_subdevdata(sd, state); strlcpy(sd->name, "S5C73M3", sizeof(sd->name)); -- cgit v0.10.2 From c7110f375be6609e9130c684aeda75bcfb771289 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:00 +0200 Subject: media: exynos4-is: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. The results of the expressions 'client->driver.driver->field' and 'client->dev.driver->field' are identical, so replace all occurrences of the former with the later. Signed-off-by: Lars-Peter Clausen Acked-by: Sylwester Nawrocki Signed-off-by: Wolfram Sang diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a835112..7a4ee4c 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -411,8 +411,8 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd, device_lock(&client->dev); - if (!client->driver || - !try_module_get(client->driver->driver.owner)) { + if (!client->dev.driver || + !try_module_get(client->dev.driver->owner)) { ret = -EPROBE_DEFER; v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", node->full_name); @@ -442,7 +442,7 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd, fmd->num_sensors++; mod_put: - module_put(client->driver->driver.owner); + module_put(client->dev.driver->owner); dev_put: device_unlock(&client->dev); put_device(&client->dev); -- cgit v0.10.2 From f9d32f25084ce7a27f966a0e71eae6ee0fe2f5ab Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:01 +0200 Subject: media: core: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. The results of the expressions 'client->driver.driver->field' and 'client->dev.driver->field' are identical, so replace all occurrences of the former with the later. Signed-off-by: Lars-Peter Clausen Acked-by: Hans Verkuil Signed-off-by: Wolfram Sang diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index ddc9379..4133af0 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -43,7 +43,7 @@ #define UNSET (-1U) -#define PREFIX (t->i2c->driver->driver.name) +#define PREFIX (t->i2c->dev.driver->name) /* * Driver modprobe parameters @@ -452,7 +452,7 @@ static void set_type(struct i2c_client *c, unsigned int type, } tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", - c->adapter->name, c->driver->driver.name, c->addr << 1, type, + c->adapter->name, c->dev.driver->name, c->addr << 1, type, t->mode_mask); return; @@ -556,7 +556,7 @@ static void tuner_lookup(struct i2c_adapter *adap, int mode_mask; if (pos->i2c->adapter != adap || - strcmp(pos->i2c->driver->driver.name, "tuner")) + strcmp(pos->i2c->dev.driver->name, "tuner")) continue; mode_mask = pos->mode_mask; diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 037d7a5..433d6d7 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -236,14 +236,14 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, v4l2_subdev_init(sd, ops); sd->flags |= V4L2_SUBDEV_FL_IS_I2C; /* the owner is the same as the i2c_client's driver owner */ - sd->owner = client->driver->driver.owner; + sd->owner = client->dev.driver->owner; sd->dev = &client->dev; /* i2c_client and v4l2_subdev point to one another */ v4l2_set_subdevdata(sd, client); i2c_set_clientdata(client, sd); /* initialize name */ snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", - client->driver->driver.name, i2c_adapter_id(client->adapter), + client->dev.driver->name, i2c_adapter_id(client->adapter), client->addr); } EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init); @@ -274,11 +274,11 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, loaded. This delay-load mechanism doesn't work if other drivers want to use the i2c device, so explicitly loading the module is the best alternative. */ - if (client == NULL || client->driver == NULL) + if (client == NULL || client->dev.driver == NULL) goto error; /* Lock the module so we can safely get the v4l2_subdev pointer */ - if (!try_module_get(client->driver->driver.owner)) + if (!try_module_get(client->dev.driver->owner)) goto error; sd = i2c_get_clientdata(client); @@ -287,7 +287,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, if (v4l2_device_register_subdev(v4l2_dev, sd)) sd = NULL; /* Decrease the module use count to match the first try_module_get. */ - module_put(client->driver->driver.owner); + module_put(client->dev.driver->owner); error: /* If we have a client but no subdev, then something went wrong and diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 16550c4..a707529 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -35,7 +35,7 @@ printk(level "%s %d-%04x: " fmt, name, i2c_adapter_id(adapter), addr , ## arg) #define v4l_client_printk(level, client, fmt, arg...) \ - v4l_printk(level, (client)->driver->driver.name, (client)->adapter, \ + v4l_printk(level, (client)->dev.driver->name, (client)->adapter, \ (client)->addr, fmt , ## arg) #define v4l_err(client, fmt, arg...) \ -- cgit v0.10.2 From 3ee81b7aefcc4d5c031dcac5df8683cadc7b6ee2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:02 +0200 Subject: drm: encoder_slave: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. The results of the expressions 'client->driver.driver->field' and 'client->dev.driver->field' are identical, so replace all occurrences of the former with the later. To get direct access to the i2c_driver struct use 'to_i2c_driver(client->dev.driver)'. Signed-off-by: Lars-Peter Clausen Signed-off-by: Wolfram Sang diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c index 0cfb60f..d18b88b 100644 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ b/drivers/gpu/drm/drm_encoder_slave.c @@ -67,12 +67,12 @@ int drm_i2c_encoder_init(struct drm_device *dev, goto fail; } - if (!client->driver) { + if (!client->dev.driver) { err = -ENODEV; goto fail_unregister; } - module = client->driver->driver.owner; + module = client->dev.driver->owner; if (!try_module_get(module)) { err = -ENODEV; goto fail_unregister; @@ -80,7 +80,7 @@ int drm_i2c_encoder_init(struct drm_device *dev, encoder->bus_priv = client; - encoder_drv = to_drm_i2c_encoder_driver(client->driver); + encoder_drv = to_drm_i2c_encoder_driver(to_i2c_driver(client->dev.driver)); err = encoder_drv->encoder_init(client, dev, encoder); if (err) @@ -111,7 +111,7 @@ void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder) { struct drm_encoder_slave *encoder = to_encoder_slave(drm_encoder); struct i2c_client *client = drm_i2c_encoder_get_client(drm_encoder); - struct module *module = client->driver->driver.owner; + struct module *module = client->dev.driver->owner; i2c_unregister_device(client); encoder->bus_priv = NULL; -- cgit v0.10.2 From 395c994264bba13b5de73d0a8da6842df8ac47bf Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:03 +0200 Subject: drm: nouveau: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. Use 'to_i2c_driver(client->dev.driver)' instead to get direct access to the i2c_driver struct. Signed-off-by: Lars-Peter Clausen Cc: Martin Peres Signed-off-by: Wolfram Sang diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c index 8b3adec..eae939d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c @@ -41,7 +41,8 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c, if (!client) return false; - if (!client->driver || client->driver->detect(client, info)) { + if (!client->dev.driver || + to_i2c_driver(client->dev.driver)->detect(client, info)) { i2c_unregister_device(client); return false; } -- cgit v0.10.2 From a7cde6d25c494e1bc8c4f89d3096b2fe077c5416 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:04 +0200 Subject: ALSA: ppc: keywest: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. Use 'to_i2c_driver(client->dev.driver)' instead to get direct access to the i2c_driver struct. Signed-off-by: Lars-Peter Clausen Acked-by: Takashi Iwai Signed-off-by: Wolfram Sang diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index 01aecc2..0d1c27e 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -65,7 +65,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter) * already bound. If not it means binding failed, and then there * is no point in keeping the device instantiated. */ - if (!keywest_ctx->client->driver) { + if (!keywest_ctx->client->dev.driver) { i2c_unregister_device(keywest_ctx->client); keywest_ctx->client = NULL; return -ENODEV; @@ -76,7 +76,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter) * This is safe because i2c-core holds the core_lock mutex for us. */ list_add_tail(&keywest_ctx->client->detected, - &keywest_ctx->client->driver->clients); + &to_i2c_driver(keywest_ctx->client->dev.driver)->clients); return 0; } -- cgit v0.10.2 From 40df24997f947ab5b745d570d56a003705868dcc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:05 +0200 Subject: ASoC: imx-wm8962: Don't use i2c_client->driver The 'driver' field of the i2c_client struct is redundant and is going to be removed. Check i2c_client->dev.driver instead to see if a driver is bound to the device. Signed-off-by: Lars-Peter Clausen Acked-by: Mark Brown Signed-off-by: Wolfram Sang diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 722afe6..cd106aa 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -215,7 +215,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) goto fail; } codec_dev = of_find_i2c_device_by_node(codec_np); - if (!codec_dev || !codec_dev->driver) { + if (!codec_dev || !codec_dev->dev.driver) { dev_err(&pdev->dev, "failed to find codec platform device\n"); ret = -EINVAL; goto fail; -- cgit v0.10.2 From 0acc2b321342aa813fa9fc485afb09fbc811f594 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 29 Sep 2013 10:51:06 +0200 Subject: i2c: Remove redundant 'driver' field from the i2c_client struct The 'driver' field of the i2c_client struct is redundant. The same data can be accessed through to_i2c_driver(client->dev.driver). The generated code for both approaches in more or less the same. E.g. on ARM the expression client->driver->command(...) generates ... ldr r3, [r0, #28] ldr r3, [r3, #32] blx r3 ... and the expression to_i2c_driver(client->dev.driver)->command(...) generates ... ldr r3, [r0, #160] ldr r3, [r3, #-4] blx r3 ... Other architectures will generate similar code. All users of the 'driver' field outside of the I2C core have already been converted. So this only leaves the core itself. This patch converts the remaining few users in the I2C core and then removes the 'driver' field from the i2c_client struct. Signed-off-by: Lars-Peter Clausen Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 29d3f04..430c001 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -248,17 +248,16 @@ static int i2c_device_probe(struct device *dev) driver = to_i2c_driver(dev->driver); if (!driver->probe || !driver->id_table) return -ENODEV; - client->driver = driver; + if (!device_can_wakeup(&client->dev)) device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe\n"); status = driver->probe(client, i2c_match_id(driver->id_table, client)); - if (status) { - client->driver = NULL; + if (status) i2c_set_clientdata(client, NULL); - } + return status; } @@ -279,10 +278,9 @@ static int i2c_device_remove(struct device *dev) dev->driver = NULL; status = 0; } - if (status == 0) { - client->driver = NULL; + if (status == 0) i2c_set_clientdata(client, NULL); - } + return status; } @@ -1606,9 +1604,14 @@ static int i2c_cmd(struct device *dev, void *_arg) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_cmd_arg *arg = _arg; + struct i2c_driver *driver; + + if (!client || !client->dev.driver) + return 0; - if (client && client->driver && client->driver->command) - client->driver->command(client, arg->cmd, arg->arg); + driver = to_i2c_driver(client->dev.driver); + if (driver->command) + driver->command(client, arg->cmd, arg->arg); return 0; } diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 44d4c60..c99b229 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -46,6 +46,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) { struct i2c_client *client = i2c_verify_client(dev); struct alert_data *data = addrp; + struct i2c_driver *driver; if (!client || client->addr != data->addr) return 0; @@ -54,12 +55,13 @@ static int smbus_do_alert(struct device *dev, void *addrp) /* * Drivers should either disable alerts, or provide at least - * a minimal handler. Lock so client->driver won't change. + * a minimal handler. Lock so the driver won't change. */ device_lock(dev); - if (client->driver) { - if (client->driver->alert) - client->driver->alert(client, data->flag); + if (client->dev.driver) { + driver = to_i2c_driver(client->dev.driver); + if (driver->alert) + driver->alert(client, data->flag); else dev_warn(&client->dev, "no driver alert()!\n"); } else diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 2ab11dc..eff50e0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -205,7 +205,6 @@ struct i2c_driver { * @name: Indicates the type of the device, usually a chip name that's * generic enough to hide second-sourcing and compatible revisions. * @adapter: manages the bus segment hosting this I2C device - * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) * @detected: member of an i2c_driver.clients list or i2c-core's @@ -222,7 +221,6 @@ struct i2c_client { /* _LOWER_ 7 bits */ char name[I2C_NAME_SIZE]; struct i2c_adapter *adapter; /* the adapter we sit on */ - struct i2c_driver *driver; /* and our access routines */ struct device dev; /* the device structure */ int irq; /* irq issued by device */ struct list_head detected; -- cgit v0.10.2 From 616228a164d4366f82d983c4a70d8006d9fb43f2 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Mon, 30 Sep 2013 01:23:53 +0200 Subject: i2c: mxs: distinguish i.MX23 and i.MX28 based I2C controller It seems the PIO mode does not work, or at least not like it works on a i.MX28. Each short transfer needs about one second (without an error message) but does not send anything on the I2C lines. Signed-off-by: Juergen Beisert Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index f4a0167..2cb0317 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -95,10 +95,17 @@ #define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ MXS_I2C_CTRL0_MASTER_MODE) +enum mxs_i2c_devtype { + MXS_I2C_UNKNOWN = 0, + MXS_I2C_V1, + MXS_I2C_V2, +}; + /** * struct mxs_i2c_dev - per device, private MXS-I2C data * * @dev: driver model device node + * @dev_type: distinguish i.MX23/i.MX28 features * @regs: IO registers pointer * @cmd_complete: completion object for transaction wait * @cmd_err: error code for last transaction @@ -106,6 +113,7 @@ */ struct mxs_i2c_dev { struct device *dev; + enum mxs_i2c_devtype dev_type; void __iomem *regs; struct completion cmd_complete; int cmd_err; @@ -495,6 +503,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, * 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. + * Note: this special feature only works on i.MX28 SoC */ i2c->cmd_err = 0; if (0) { /* disable PIO mode until a proper fix is made */ @@ -680,8 +689,28 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) return 0; } +static struct platform_device_id mxs_i2c_devtype[] = { + { + .name = "imx23-i2c", + .driver_data = MXS_I2C_V1, + }, { + .name = "imx28-i2c", + .driver_data = MXS_I2C_V2, + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype); + +static const struct of_device_id mxs_i2c_dt_ids[] = { + { .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], }, + { .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids); + static int mxs_i2c_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(mxs_i2c_dt_ids, &pdev->dev); struct device *dev = &pdev->dev; struct mxs_i2c_dev *i2c; struct i2c_adapter *adap; @@ -693,6 +722,11 @@ static int mxs_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; + if (of_id) { + const struct platform_device_id *device_id = of_id->data; + i2c->dev_type = device_id->driver_data; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); @@ -768,12 +802,6 @@ static int mxs_i2c_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id mxs_i2c_dt_ids[] = { - { .compatible = "fsl,imx28-i2c", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids); - static struct platform_driver mxs_i2c_driver = { .driver = { .name = DRIVER_NAME, -- cgit v0.10.2 From 29faeb388a1af5c2175e79ce52173c45a262924a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 6 Oct 2013 14:02:13 +0200 Subject: i2c: mxs: Rework the PIO mode operation Analyze and rework the PIO mode operation. The PIO mode operation was unreliable on MX28, by analyzing the bus with LA, the checks for when data were available or were to be sent were wrong. The PIO WRITE has to be completely reworked as it multiple problems. The MX23 datasheet helped here, see comments in the code for details. The problems boil down to: - RUN bit in CTRL0 must be set after DATA register was written - The PIO transfer must be 4 bytes long tops, otherwise use clock stretching. Both of these fixes are implemented. The PIO READ operation can only be done for up to four bytes as we are unable to read out the data from the DATA register fast enough. This patch also tries to document the investigation within the code. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 2cb0317..5deb88b 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -1,6 +1,7 @@ /* * Freescale MXS I2C bus driver * + * Copyright (C) 2012-2013 Marek Vasut * Copyright (C) 2011-2012 Wolfram Sang, Pengutronix e.K. * * based on a (non-working) driver which was: @@ -64,6 +65,7 @@ #define MXS_I2C_CTRL1_SLAVE_IRQ 0x01 #define MXS_I2C_STAT (0x50) +#define MXS_I2C_STAT_GOT_A_NAK 0x10000000 #define MXS_I2C_STAT_BUS_BUSY 0x00000800 #define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400 @@ -299,48 +301,11 @@ write_init_pio_fail: return -EINVAL; } -static int mxs_i2c_pio_wait_dmareq(struct mxs_i2c_dev *i2c) +static int mxs_i2c_pio_wait_xfer_end(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(); - } - - return 0; -} - -static int mxs_i2c_pio_wait_cplt(struct mxs_i2c_dev *i2c, int last) -{ - 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); - - /* - * When ending a transfer with a stop, we have to wait for the bus to - * go idle before we report the transfer as completed. Otherwise the - * start of the next transfer may race with the end of the current one. - */ - while (last && (readl(i2c->regs + MXS_I2C_STAT) & - (MXS_I2C_STAT_BUS_BUSY | MXS_I2C_STAT_CLK_GEN_BUSY))) { + while (readl(i2c->regs + MXS_I2C_CTRL0) & MXS_I2C_CTRL0_RUN) { if (time_after(jiffies, timeout)) return -ETIMEDOUT; cond_resched(); @@ -378,106 +343,208 @@ static void mxs_i2c_pio_trigger_cmd(struct mxs_i2c_dev *i2c, u32 cmd) writel(reg, i2c->regs + MXS_I2C_CTRL0); } +/* + * Start WRITE transaction on the I2C bus. By studying i.MX23 datasheet, + * CTRL0::PIO_MODE bit description clarifies the order in which the registers + * must be written during PIO mode operation. First, the CTRL0 register has + * to be programmed with all the necessary bits but the RUN bit. Then the + * payload has to be written into the DATA register. Finally, the transmission + * is executed by setting the RUN bit in CTRL0. + */ +static void mxs_i2c_pio_trigger_write_cmd(struct mxs_i2c_dev *i2c, u32 cmd, + u32 data) +{ + writel(cmd, i2c->regs + MXS_I2C_CTRL0); + writel(data, i2c->regs + MXS_I2C_DATA); + writel(MXS_I2C_CTRL0_RUN, i2c->regs + MXS_I2C_CTRL0_SET); +} + 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; + int i, ret, xlen = 0, xmit = 0; + uint32_t start; /* Mute IRQs coming from this block. */ writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_CLR); + /* + * MX23 idea: + * - Enable CTRL0::PIO_MODE (1 << 24) + * - Enable CTRL1::ACK_MODE (1 << 27) + * + * WARNING! The MX23 is broken in some way, even if it claims + * to support PIO, when we try to transfer any amount of data + * that is not aligned to 4 bytes, the DMA engine will have + * bits in DEBUG1::DMA_BYTES_ENABLES still set even after the + * transfer. This in turn will mess up the next transfer as + * the block it emit one byte write onto the bus terminated + * with a NAK+STOP. A possible workaround is to reset the IP + * block after every PIO transmission, which might just work. + * + * NOTE: The CTRL0::PIO_MODE description is important, since + * it outlines how the PIO mode is really supposed to work. + */ + if (msg->flags & I2C_M_RD) { + /* + * PIO READ transfer: + * + * This transfer MUST be limited to 4 bytes maximum. It is not + * possible to transfer more than four bytes via PIO, since we + * can not in any way make sure we can read the data from the + * DATA register fast enough. Besides, the RX FIFO is only four + * bytes deep, thus we can only really read up to four bytes at + * time. Finally, there is no bit indicating us that new data + * arrived at the FIFO and can thus be fetched from the DATA + * register. + */ + BUG_ON(msg->len > 4); + addr_data |= I2C_SMBUS_READ; /* SELECT command. */ - mxs_i2c_pio_trigger_cmd(i2c, MXS_CMD_I2C_SELECT); - - ret = mxs_i2c_pio_wait_dmareq(i2c); - if (ret) - return ret; - - writel(addr_data, i2c->regs + MXS_I2C_DATA); - writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); - - ret = mxs_i2c_pio_wait_cplt(i2c, 0); - if (ret) - return ret; + mxs_i2c_pio_trigger_write_cmd(i2c, MXS_CMD_I2C_SELECT, + addr_data); - if (mxs_i2c_pio_check_error_state(i2c)) + ret = mxs_i2c_pio_wait_xfer_end(i2c); + if (ret) { + dev_err(i2c->dev, + "PIO: Failed to send SELECT command!\n"); goto cleanup; + } /* READ command. */ mxs_i2c_pio_trigger_cmd(i2c, MXS_CMD_I2C_READ | flags | MXS_I2C_CTRL0_XFER_COUNT(msg->len)); + ret = mxs_i2c_pio_wait_xfer_end(i2c); + if (ret) { + dev_err(i2c->dev, + "PIO: Failed to send SELECT command!\n"); + goto cleanup; + } + + data = readl(i2c->regs + MXS_I2C_DATA); 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); - writel(MXS_I2C_DEBUG0_DMAREQ, - i2c->regs + MXS_I2C_DEBUG0_CLR); - } msg->buf[i] = data & 0xff; data >>= 8; } } else { + /* + * PIO WRITE transfer: + * + * The code below implements clock stretching to circumvent + * the possibility of kernel not being able to supply data + * fast enough. It is possible to transfer arbitrary amount + * of data using PIO write. + */ addr_data |= I2C_SMBUS_WRITE; - /* WRITE command. */ - mxs_i2c_pio_trigger_cmd(i2c, - MXS_CMD_I2C_WRITE | flags | - MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1)); - /* * 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; + + /* Start the transfer with START condition. */ + start = MXS_I2C_CTRL0_PRE_SEND_START; + + /* If the transfer is long, use clock stretching. */ + if (msg->len > 3) + start |= MXS_I2C_CTRL0_RETAIN_CLOCK; + 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); - writel(MXS_I2C_DEBUG0_DMAREQ, - i2c->regs + MXS_I2C_DEBUG0_CLR); + + xmit = 0; + + /* This is the last transfer of the message. */ + if (i + 1 == msg->len) { + /* Add optional STOP flag. */ + start |= flags; + /* Remove RETAIN_CLOCK bit. */ + start &= ~MXS_I2C_CTRL0_RETAIN_CLOCK; + xmit = 1; } - } - 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); + /* Four bytes are ready in the "data" variable. */ + if ((i & 3) == 2) + xmit = 1; + + /* Nothing interesting happened, continue stuffing. */ + if (!xmit) + continue; + + /* + * Compute the size of the transfer and shift the + * data accordingly. + * + * i = (4k + 0) .... xlen = 2 + * i = (4k + 1) .... xlen = 3 + * i = (4k + 2) .... xlen = 4 + * i = (4k + 3) .... xlen = 1 + */ + + if ((i % 4) == 3) + xlen = 1; + else + xlen = (i % 4) + 2; + + data >>= (4 - xlen) * 8; + + dev_dbg(i2c->dev, + "PIO: len=%i pos=%i total=%i [W%s%s%s]\n", + xlen, i, msg->len, + start & MXS_I2C_CTRL0_PRE_SEND_START ? "S" : "", + start & MXS_I2C_CTRL0_POST_SEND_STOP ? "E" : "", + start & MXS_I2C_CTRL0_RETAIN_CLOCK ? "C" : ""); + writel(MXS_I2C_DEBUG0_DMAREQ, i2c->regs + MXS_I2C_DEBUG0_CLR); + + mxs_i2c_pio_trigger_write_cmd(i2c, + start | MXS_I2C_CTRL0_MASTER_MODE | + MXS_I2C_CTRL0_DIRECTION | + MXS_I2C_CTRL0_XFER_COUNT(xlen), data); + + /* The START condition is sent only once. */ + start &= ~MXS_I2C_CTRL0_PRE_SEND_START; + + /* Wait for the end of the transfer. */ + ret = mxs_i2c_pio_wait_xfer_end(i2c); + if (ret) { + dev_err(i2c->dev, + "PIO: Failed to finish WRITE cmd!\n"); + break; + } + + /* Check NAK here. */ + ret = readl(i2c->regs + MXS_I2C_STAT) & + MXS_I2C_STAT_GOT_A_NAK; + if (ret) { + ret = -ENXIO; + goto cleanup; + } } } - ret = mxs_i2c_pio_wait_cplt(i2c, flags & MXS_I2C_CTRL0_POST_SEND_STOP); - if (ret) - return ret; - /* make sure we capture any occurred error into cmd_err */ - mxs_i2c_pio_check_error_state(i2c); + ret = mxs_i2c_pio_check_error_state(i2c); cleanup: /* 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; + return ret; } /* @@ -487,8 +554,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); - int ret, err; + int ret; int flags; + int use_pio = 0; flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; @@ -499,20 +567,25 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, return -EINVAL; /* - * 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. - * Note: this special feature only works on i.MX28 SoC + * The MX28 I2C IP block can only do PIO READ for transfer of to up + * 4 bytes of length. The write transfer is not limited as it can use + * clock stretching to avoid FIFO underruns. */ + if ((msg->flags & I2C_M_RD) && (msg->len <= 4)) + use_pio = 1; + if (!(msg->flags & I2C_M_RD) && (msg->len < 7)) + use_pio = 1; + + /* Disable PIO on MX23. */ + if (i2c->dev_type == MXS_I2C_V1) + use_pio = 0; + i2c->cmd_err = 0; - if (0) { /* disable PIO mode until a proper fix is made */ + if (use_pio) { ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); - if (ret) { - err = mxs_i2c_reset(i2c); - if (err) - return err; - } + /* No need to reset the block if NAK was received. */ + if (ret && (ret != -ENXIO)) + mxs_i2c_reset(i2c); } else { INIT_COMPLETION(i2c->cmd_complete); ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); @@ -523,9 +596,11 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, msecs_to_jiffies(1000)); if (ret == 0) goto timeout; + + ret = i2c->cmd_err; } - if (i2c->cmd_err == -ENXIO) { + if (ret == -ENXIO) { /* * If the transfer fails with a NAK from the slave the * controller halts until it gets told to return to idle state. @@ -534,8 +609,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, i2c->regs + MXS_I2C_CTRL1_SET); } - ret = i2c->cmd_err; - dev_dbg(i2c->dev, "Done with err=%d\n", ret); return ret; @@ -823,6 +896,7 @@ static void __exit mxs_i2c_exit(void) } module_exit(mxs_i2c_exit); +MODULE_AUTHOR("Marek Vasut "); MODULE_AUTHOR("Wolfram Sang "); MODULE_DESCRIPTION("MXS I2C Bus Driver"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 19e221bed222bbcaa0436265028de3346df89024 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 30 Sep 2013 01:23:55 +0200 Subject: i2c: mxs: Fix PIO mode on i.MX23 The i.MX23 I2C controller is also capable of PIO, but needs a little harder push to behave. The controller needs to be reset after every PIO/DMA operation for some reason, otherwise in rare cases, the controller can hang or emit bytes onto the bus. Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 5deb88b..0c74038 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -35,10 +35,12 @@ #define MXS_I2C_CTRL0 (0x00) #define MXS_I2C_CTRL0_SET (0x04) +#define MXS_I2C_CTRL0_CLR (0x08) #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_PIO_MODE 0x01000000 #define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000 #define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000 #define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000 @@ -69,10 +71,9 @@ #define MXS_I2C_STAT_BUS_BUSY 0x00000800 #define MXS_I2C_STAT_CLK_GEN_BUSY 0x00000400 -#define MXS_I2C_DATA (0xa0) +#define MXS_I2C_DATA(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x60 : 0xa0) -#define MXS_I2C_DEBUG0 (0xb0) -#define MXS_I2C_DEBUG0_CLR (0xb8) +#define MXS_I2C_DEBUG0_CLR(i2c) ((i2c->dev_type == MXS_I2C_V1) ? 0x78 : 0xb8) #define MXS_I2C_DEBUG0_DMAREQ 0x80000000 @@ -355,7 +356,11 @@ static void mxs_i2c_pio_trigger_write_cmd(struct mxs_i2c_dev *i2c, u32 cmd, u32 data) { writel(cmd, i2c->regs + MXS_I2C_CTRL0); - writel(data, i2c->regs + MXS_I2C_DATA); + + if (i2c->dev_type == MXS_I2C_V1) + writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_SET); + + writel(data, i2c->regs + MXS_I2C_DATA(i2c)); writel(MXS_I2C_CTRL0_RUN, i2c->regs + MXS_I2C_CTRL0_SET); } @@ -388,7 +393,6 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, * NOTE: The CTRL0::PIO_MODE description is important, since * it outlines how the PIO mode is really supposed to work. */ - if (msg->flags & I2C_M_RD) { /* * PIO READ transfer: @@ -429,7 +433,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, goto cleanup; } - data = readl(i2c->regs + MXS_I2C_DATA); + data = readl(i2c->regs + MXS_I2C_DATA(i2c)); for (i = 0; i < msg->len; i++) { msg->buf[i] = data & 0xff; data >>= 8; @@ -508,7 +512,7 @@ static int mxs_i2c_pio_setup_xfer(struct i2c_adapter *adap, start & MXS_I2C_CTRL0_RETAIN_CLOCK ? "C" : ""); writel(MXS_I2C_DEBUG0_DMAREQ, - i2c->regs + MXS_I2C_DEBUG0_CLR); + i2c->regs + MXS_I2C_DEBUG0_CLR(i2c)); mxs_i2c_pio_trigger_write_cmd(i2c, start | MXS_I2C_CTRL0_MASTER_MODE | @@ -544,6 +548,10 @@ cleanup: writel(MXS_I2C_IRQ_MASK, i2c->regs + MXS_I2C_CTRL1_CLR); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); + /* Clear the PIO_MODE on i.MX23 */ + if (i2c->dev_type == MXS_I2C_V1) + writel(MXS_I2C_CTRL0_PIO_MODE, i2c->regs + MXS_I2C_CTRL0_CLR); + return ret; } @@ -576,10 +584,6 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, if (!(msg->flags & I2C_M_RD) && (msg->len < 7)) use_pio = 1; - /* Disable PIO on MX23. */ - if (i2c->dev_type == MXS_I2C_V1) - use_pio = 0; - i2c->cmd_err = 0; if (use_pio) { ret = mxs_i2c_pio_setup_xfer(adap, msg, flags); @@ -609,6 +613,20 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, i2c->regs + MXS_I2C_CTRL1_SET); } + /* + * WARNING! + * The i.MX23 is strange. After each and every operation, it's I2C IP + * block must be reset, otherwise the IP block will misbehave. This can + * be observed on the bus by the block sending out one single byte onto + * the bus. In case such an error happens, bit 27 will be set in the + * DEBUG0 register. This bit is not documented in the i.MX23 datasheet + * and is marked as "TBD" instead. To reset this bit to a correct state, + * reset the whole block. Since the block reset does not take long, do + * reset the block after every transfer to play safe. + */ + if (i2c->dev_type == MXS_I2C_V1) + mxs_i2c_reset(i2c); + dev_dbg(i2c->dev, "Done with err=%d\n", ret); return ret; -- cgit v0.10.2 From 4edd65e63fe4a998164a8d7d8c8c86f4300825d7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 16 Oct 2013 15:26:33 +0530 Subject: i2c: Include linux/of.h header 'of_match_ptr' is defined in linux/of.h. Include it explicitly to avoid build breakage in the future. Signed-off-by: Sachin Kamat Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index bfa02c6..d9f7e18 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -15,6 +15,7 @@ #include #include #include +#include #include struct i2c_gpio_private_data { diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 1a9ea25..c9a352f 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -23,6 +23,7 @@ #include #include #include +#include #define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */ #define I2C_PNX_SPEED_KHZ_DEFAULT 100 diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3747b9b..bf8fb94 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 6e7b09c..fc2716a 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -40,6 +40,7 @@ #include #include #include +#include #define DRIVER_NAME "xiic-i2c" diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 69a9173..b3d0574 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -24,6 +24,7 @@ #include #include #include +#include struct i2c_mux_pinctrl { struct device *dev; -- cgit v0.10.2 From 250ad590d6f12d93f4d85be305b0a598d609232e Mon Sep 17 00:00:00 2001 From: Ionut Nicu Date: Fri, 11 Oct 2013 14:17:10 +0200 Subject: i2c: mux: gpio: use gpio_set_value_cansleep() Some gpio chips may have get/set operations that can sleep. gpio_set_value() only works for chips which do not sleep, for the others we will get a kernel warning. Using gpio_set_value_cansleep() will work for both chips that do sleep and those who don't. Signed-off-by: Ionut Nicu Acked-by: Peter Korsgaard Signed-off-by: Wolfram Sang Cc: stable@kernel.org diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 927a7de..cf93f10 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -30,8 +30,8 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) int i; for (i = 0; i < mux->data.n_gpios; i++) - gpio_set_value(mux->gpio_base + mux->data.gpios[i], - val & (1 << i)); + gpio_set_value_cansleep(mux->gpio_base + mux->data.gpios[i], + val & (1 << i)); } static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) -- cgit v0.10.2 From 8c0ec2500eeb89749341884a972860d7f9e56f9c Mon Sep 17 00:00:00 2001 From: Ionut Nicu Date: Fri, 11 Oct 2013 12:09:57 +0200 Subject: i2c: mux: gpio: use reg value for i2c_add_mux_adapter The i2c-mux driver requires that the chan_id parameter passed to the i2c_add_mux_adapter() function is equal to the reg value for that adapter: for_each_child_of_node(mux_dev->of_node, child) { ret = of_property_read_u32(child, "reg", ®); if (ret) continue; if (chan_id == reg) { priv->adap.dev.of_node = child; break; } } The i2c-mux-gpio driver uses an internal logical index for chan_id when calling i2c_add_mux_adapter() instead of using the reg value. Because of this, there will problems in selecting the right adapter when the i2c-mux-gpio's index into mux->data.values doesn't match the reg value. An example of such a case: mux->data.values = { 1, 0 } For chan_id = 0, i2c-mux will bind the adapter to the of_node with reg = <0>, but when it will call the select() callback with chan_id set to 0, the i2c-mux-gpio will use it as an index into mux->data.values and it will actually select the bus with reg = <1>. Signed-off-by: Ionut Nicu Acked-by: Alexander Sverdlin Signed-off-by: Wolfram Sang Cc: stable@kernel.org diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index cf93f10..3d12e85 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -38,7 +38,7 @@ static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) { struct gpiomux *mux = data; - i2c_mux_gpio_set(mux, mux->data.values[chan]); + i2c_mux_gpio_set(mux, chan); return 0; } @@ -224,7 +224,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, - i, class, + mux->data.values[i], class, i2c_mux_gpio_select, deselect); if (!mux->adap[i]) { ret = -ENODEV; -- cgit v0.10.2 From f887605d25c1514b06b1a0e0477f85f27f23664d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 28 Oct 2013 23:49:23 +0100 Subject: i2c: sh_mobile: Convert to clk_prepare/unprepare Turn clk_enable() and clk_disable() calls into clk_prepare_enable() and clk_disable_unprepare() to get ready for the migration to the common clock framework. Signed-off-by: Laurent Pinchart Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 55110dd..1d79585 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -235,7 +235,7 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) int offset; /* Get clock rate after clock is enabled */ - clk_enable(pd->clk); + clk_prepare_enable(pd->clk); i2c_clk_khz = clk_get_rate(pd->clk) / 1000; i2c_clk_khz /= pd->clks_per_count; @@ -270,14 +270,14 @@ static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) pd->icic &= ~ICIC_ICCHB8; out: - clk_disable(pd->clk); + clk_disable_unprepare(pd->clk); } static void activate_ch(struct sh_mobile_i2c_data *pd) { /* Wake up device and enable clock */ pm_runtime_get_sync(pd->dev); - clk_enable(pd->clk); + clk_prepare_enable(pd->clk); /* Enable channel and configure rx ack */ iic_set_clr(pd, ICCR, ICCR_ICE, 0); @@ -300,7 +300,7 @@ static void deactivate_ch(struct sh_mobile_i2c_data *pd) iic_set_clr(pd, ICCR, 0, ICCR_ICE); /* Disable clock and mark device as idle */ - clk_disable(pd->clk); + clk_disable_unprepare(pd->clk); pm_runtime_put_sync(pd->dev); } -- cgit v0.10.2 From 5edb1062e54cffe84b0bfa9ffdfdad337e635d7d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 29 Oct 2013 23:37:38 +0100 Subject: i2c: sh_mobile & rcar: Enable the driver on all ARM platforms Renesas ARM platforms are transitioning from single-platform to multi-platform kernels using the new ARCH_SHMOBILE_MULTI. Make the driver available on all ARM platforms to enable it on both ARCH_SHMOBILE and ARCH_SHMOBILE_MULTI, and increase build testing coverage with COMPILE_TEST. Signed-off-by: Laurent Pinchart Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index cdcbd83..7c4bb071 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -665,7 +665,7 @@ config I2C_SH7760 config I2C_SH_MOBILE tristate "SuperH Mobile I2C Controller" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARM || COMPILE_TEST help If you say yes to this option, support will be included for the built-in I2C interface on the Renesas SH-Mobile processor. @@ -768,7 +768,7 @@ config I2C_XLR config I2C_RCAR tristate "Renesas R-Car I2C Controller" - depends on ARCH_SHMOBILE && I2C + depends on ARM || COMPILE_TEST help If you say yes to this option, support will be included for the R-Car I2C controller. -- cgit v0.10.2 From e55fea0c50452449403bc8645fa3a6205dd74547 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Oct 2013 11:46:22 +0300 Subject: i2c: scmi: remove some bogus NULL checks "obj" can't be NULL here. We already know that "pkg->package.elements" gives us a valid pointer so the next pointer after that is also non-NULL. Signed-off-by: Dan Carpenter Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index c447e8d..5992355 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -223,7 +223,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, goto out; obj = pkg->package.elements + 1; - if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { + if (obj->type != ACPI_TYPE_INTEGER) { ACPI_ERROR((AE_INFO, "Invalid argument type")); result = -EIO; goto out; @@ -235,7 +235,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: case I2C_SMBUS_WORD_DATA: - if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) { + if (obj->type != ACPI_TYPE_INTEGER) { ACPI_ERROR((AE_INFO, "Invalid argument type")); result = -EIO; goto out; @@ -246,7 +246,7 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, data->byte = obj->integer.value; break; case I2C_SMBUS_BLOCK_DATA: - if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) { + if (obj->type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, "Invalid argument type")); result = -EIO; goto out; -- cgit v0.10.2 From 043a3f113ce41e3e6fdbb49551df75e82e8c4ae7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Oct 2013 01:04:32 -0700 Subject: i2c: rcar: fixup rcar type naming b720423a2627f045133bec39a31fe2bc0dab86f3 (i2c: rcar: add rcar-H2 support) added R-Car H2 support on i2c-rcar. The R-Car I2C type is based on SoC generation (Gen1 = E1/M1/H1, Gen2 = E2/M2/H2), but added naming was H1/H2 instead of Gen1/Gen2. Gen1/Gen2 is better naming on this driver. Signed-off-by: Kuninori Morimoto Acked-by: Simon Horman Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 8603f5e..2c2fd7c 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -103,8 +103,8 @@ enum { #define ID_NACK (1 << 4) enum rcar_i2c_type { - I2C_RCAR_H1, - I2C_RCAR_H2, + I2C_RCAR_GEN1, + I2C_RCAR_GEN2, }; struct rcar_i2c_priv { @@ -240,10 +240,10 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, } switch (priv->devtype) { - case I2C_RCAR_H1: + case I2C_RCAR_GEN1: cdf_width = 2; break; - case I2C_RCAR_H2: + case I2C_RCAR_GEN2: cdf_width = 3; break; default: @@ -640,10 +640,10 @@ static const struct i2c_algorithm rcar_i2c_algo = { }; static const struct of_device_id rcar_i2c_dt_ids[] = { - { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_H1 }, - { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_H1 }, - { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_H1 }, - { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_H2 }, + { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, + { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 }, + { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, + { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -731,9 +731,9 @@ static int rcar_i2c_remove(struct platform_device *pdev) } static struct platform_device_id rcar_i2c_id_table[] = { - { "i2c-rcar", I2C_RCAR_H1 }, - { "i2c-rcar_h1", I2C_RCAR_H1 }, - { "i2c-rcar_h2", I2C_RCAR_H2 }, + { "i2c-rcar", I2C_RCAR_GEN1 }, + { "i2c-rcar_gen1", I2C_RCAR_GEN1 }, + { "i2c-rcar_gen2", I2C_RCAR_GEN2 }, {}, }; MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table); -- cgit v0.10.2 From 8a73cd4cfa159918da405d9645deca842590e2fe Mon Sep 17 00:00:00 2001 From: Naveen Krishna Ch Date: Wed, 16 Oct 2013 11:00:42 +0530 Subject: i2c: exynos5: add High Speed I2C controller driver Adds support for High Speed I2C driver found in Exynos5 and later SoCs from Samsung. Driver only supports Device Tree method. Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Taekgyun Ko Reviewed-by: Simon Glass Signed-off-by: Yuvaraj Kumar C D Signed-off-by: Andrew Bresticker [wsa: rebased to v3.12-rc4 (no of_i2c.h anymore)] Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt new file mode 100644 index 0000000..056732c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt @@ -0,0 +1,44 @@ +* Samsung's High Speed I2C controller + +The Samsung's High Speed I2C controller is used to interface with I2C devices +at various speeds ranging from 100khz to 3.4Mhz. + +Required properties: + - compatible: value should be. + -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + - #address-cells: always 1 (for i2c addresses) + - #size-cells: always 0 + + - Pinctrl: + - pinctrl-0: Pin control group to be used for this controller. + - pinctrl-names: Should contain only one value - "default". + +Optional properties: + - clock-frequency: Desired operating frequency in Hz of the bus. + -> If not specified, the bus operates in fast-speed mode at + at 100khz. + -> If specified, the bus operates in high-speed mode only if the + clock-frequency is >= 1Mhz. + +Example: + +hsi2c@12ca0000 { + compatible = "samsung,exynos5-hsi2c"; + reg = <0x12ca0000 0x100>; + interrupts = <56>; + clock-frequency = <100000>; + + pinctrl-0 = <&i2c4_bus>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + }; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7c4bb071..80e5530 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -436,6 +436,13 @@ config I2C_EG20T ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. +config I2C_EXYNOS5 + tristate "Exynos5 high-speed I2C driver" + depends on ARCH_EXYNOS5 && OF + help + Say Y here to include support for high-speed I2C controller in the + Exynos5 based Samsung SoCs. + config I2C_GPIO tristate "GPIO-based bitbanging I2C" depends on GPIOLIB diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index d00997f..d1ad371 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -42,6 +42,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o +obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c new file mode 100644 index 0000000..aca3991 --- /dev/null +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -0,0 +1,774 @@ +/** + * i2c-exynos5.c - Samsung Exynos5 I2C Controller Driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * HSI2C controller from Samsung supports 2 modes of operation + * 1. Auto mode: Where in master automatically controls the whole transaction + * 2. Manual mode: Software controls the transaction by issuing commands + * START, READ, WRITE, STOP, RESTART in I2C_MANUAL_CMD register. + * + * Operation mode can be selected by setting AUTO_MODE bit in I2C_CONF register + * + * Special bits are available for both modes of operation to set commands + * and for checking transfer status + */ + +/* Register Map */ +#define HSI2C_CTL 0x00 +#define HSI2C_FIFO_CTL 0x04 +#define HSI2C_TRAILIG_CTL 0x08 +#define HSI2C_CLK_CTL 0x0C +#define HSI2C_CLK_SLOT 0x10 +#define HSI2C_INT_ENABLE 0x20 +#define HSI2C_INT_STATUS 0x24 +#define HSI2C_ERR_STATUS 0x2C +#define HSI2C_FIFO_STATUS 0x30 +#define HSI2C_TX_DATA 0x34 +#define HSI2C_RX_DATA 0x38 +#define HSI2C_CONF 0x40 +#define HSI2C_AUTO_CONF 0x44 +#define HSI2C_TIMEOUT 0x48 +#define HSI2C_MANUAL_CMD 0x4C +#define HSI2C_TRANS_STATUS 0x50 +#define HSI2C_TIMING_HS1 0x54 +#define HSI2C_TIMING_HS2 0x58 +#define HSI2C_TIMING_HS3 0x5C +#define HSI2C_TIMING_FS1 0x60 +#define HSI2C_TIMING_FS2 0x64 +#define HSI2C_TIMING_FS3 0x68 +#define HSI2C_TIMING_SLA 0x6C +#define HSI2C_ADDR 0x70 + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) +#define HSI2C_TXCHON (1u << 7) +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) +#define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) + +/* As per user manual FIFO max depth is 64bytes */ +#define HSI2C_FIFO_MAX 0x40 +/* default trigger levels for Tx and Rx FIFOs */ +#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30) +#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xf) + +/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +/* I2C_INT_STAT Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL (1u << 1) +#define HSI2C_INT_TX_UNDERRUN (1u << 2) +#define HSI2C_INT_TX_OVERRUN (1u << 3) +#define HSI2C_INT_RX_UNDERRUN (1u << 4) +#define HSI2C_INT_RX_OVERRUN (1u << 5) +#define HSI2C_INT_TRAILING (1u << 6) +#define HSI2C_INT_I2C (1u << 9) + +/* I2C_FIFO_STAT Register bits */ +#define HSI2C_RX_FIFO_EMPTY (1u << 24) +#define HSI2C_RX_FIFO_FULL (1u << 23) +#define HSI2C_RX_FIFO_LVL(x) ((x >> 16) & 0x7f) +#define HSI2C_TX_FIFO_EMPTY (1u << 8) +#define HSI2C_TX_FIFO_FULL (1u << 7) +#define HSI2C_TX_FIFO_LVL(x) ((x >> 0) & 0x7f) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) +#define HSI2C_TIMEOUT_MASK 0xff + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_TIMEOUT_AUTO (1u << 4) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) + +/* I2C_ADDR register bits */ +#define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0) +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) +#define HSI2C_MASTER_ID(x) ((x & 0xff) << 24) +#define MASTER_ID(x) ((x & 0x7) + 0x08) + +/* + * Controller operating frequency, timing values for operation + * are calculated against this frequency + */ +#define HSI2C_HS_TX_CLOCK 1000000 +#define HSI2C_FS_TX_CLOCK 100000 +#define HSI2C_HIGH_SPD 1 +#define HSI2C_FAST_SPD 0 + +#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) + +struct exynos5_i2c { + struct i2c_adapter adap; + unsigned int suspended:1; + + struct i2c_msg *msg; + struct completion msg_complete; + unsigned int msg_ptr; + + unsigned int irq; + + void __iomem *regs; + struct clk *clk; + struct device *dev; + int state; + + spinlock_t lock; /* IRQ synchronization */ + + /* + * Since the TRANS_DONE bit is cleared on read, and we may read it + * either during an IRQ or after a transaction, keep track of its + * state here. + */ + int trans_done; + + /* Controller operating frequency */ + unsigned int fs_clock; + unsigned int hs_clock; + + /* + * HSI2C Controller can operate in + * 1. High speed upto 3.4Mbps + * 2. Fast speed upto 1Mbps + */ + int speed_mode; +}; + +static const struct of_device_id exynos5_i2c_match[] = { + { .compatible = "samsung,exynos5-hsi2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos5_i2c_match); + +static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) +{ + writel(readl(i2c->regs + HSI2C_INT_STATUS), + i2c->regs + HSI2C_INT_STATUS); +} + +/* + * exynos5_i2c_set_timing: updates the registers with appropriate + * timing values calculated + * + * Returns 0 on success, -EINVAL if the cycle length cannot + * be calculated. + */ +static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) +{ + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + unsigned int t_sr_release; + unsigned int t_ftl_cycle; + unsigned int clkin = clk_get_rate(i2c->clk); + unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle; + unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ? + i2c->hs_clock : i2c->fs_clock; + + /* + * FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * utemp1 = (TSCLK_L + TSCLK_H + 2) + */ + t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (div = 0; div < 256; div++) { + utemp1 = utemp0 / (div + 1); + + /* + * SCL_L and SCL_H each has max value of 255 + * Hence, For the clk_cycle to the have right value + * utemp1 has to be less then 512 and more than 4. + */ + if ((utemp1 < 512) && (utemp1 > 4)) { + clk_cycle = utemp1 - 2; + break; + } else if (div == 255) { + dev_warn(i2c->dev, "Failed to calculate divisor"); + return -EINVAL; + } + } + + t_scl_l = clk_cycle / 2; + t_scl_h = clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = div << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + dev_dbg(i2c->dev, "tSTART_SU: %X, tSTART_HD: %X, tSTOP_SU: %X\n", + t_start_su, t_start_hd, t_stop_su); + dev_dbg(i2c->dev, "tDATA_SU: %X, tSCL_L: %X, tSCL_H: %X\n", + t_data_su, t_scl_l, t_scl_h); + dev_dbg(i2c->dev, "nClkDiv: %X, tSR_RELEASE: %X\n", + div, t_sr_release); + dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd); + + if (mode == HSI2C_HIGH_SPD) { + writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1); + writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2); + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); + } else { + writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_FS1); + writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_FS2); + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); + } + writel(i2c_timing_sla, i2c->regs + HSI2C_TIMING_SLA); + + return 0; +} + +static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c) +{ + /* + * Configure the Fast speed timing values + * Even the High Speed mode initially starts with Fast mode + */ + if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) { + dev_err(i2c->dev, "HSI2C FS Clock set up failed\n"); + return -EINVAL; + } + + /* configure the High speed timing values */ + if (i2c->speed_mode == HSI2C_HIGH_SPD) { + if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) { + dev_err(i2c->dev, "HSI2C HS Clock set up failed\n"); + return -EINVAL; + } + } + + return 0; +} + +/* + * exynos5_i2c_init: configures the controller for I2C functionality + * Programs I2C controller for Master mode operation + */ +static void exynos5_i2c_init(struct exynos5_i2c *i2c) +{ + u32 i2c_conf = readl(i2c->regs + HSI2C_CONF); + u32 i2c_timeout = readl(i2c->regs + HSI2C_TIMEOUT); + + /* Clear to disable Timeout */ + i2c_timeout &= ~HSI2C_TIMEOUT_EN; + writel(i2c_timeout, i2c->regs + HSI2C_TIMEOUT); + + writel((HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + i2c->regs + HSI2C_CTL); + writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL); + + if (i2c->speed_mode == HSI2C_HIGH_SPD) { + writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)), + i2c->regs + HSI2C_ADDR); + i2c_conf |= HSI2C_HS_MODE; + } + + writel(i2c_conf | HSI2C_AUTO_MODE, i2c->regs + HSI2C_CONF); +} + +static void exynos5_i2c_reset(struct exynos5_i2c *i2c) +{ + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(i2c->regs + HSI2C_CTL); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, i2c->regs + HSI2C_CTL); + + i2c_ctl = readl(i2c->regs + HSI2C_CTL); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, i2c->regs + HSI2C_CTL); + + /* We don't expect calculations to fail during the run */ + exynos5_hsi2c_clock_setup(i2c); + /* Initialize the configure registers */ + exynos5_i2c_init(i2c); +} + +/* + * exynos5_i2c_irq: top level IRQ servicing routine + * + * INT_STATUS registers gives the interrupt details. Further, + * FIFO_STATUS or TRANS_STATUS registers are to be check for detailed + * state of the bus. + */ +static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) +{ + struct exynos5_i2c *i2c = dev_id; + u32 fifo_level, int_status, fifo_status, trans_status; + unsigned char byte; + int len = 0; + + i2c->state = -EINVAL; + + spin_lock(&i2c->lock); + + int_status = readl(i2c->regs + HSI2C_INT_STATUS); + writel(int_status, i2c->regs + HSI2C_INT_STATUS); + fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); + + /* handle interrupt related to the transfer status */ + if (int_status & HSI2C_INT_I2C) { + trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); + if (trans_status & HSI2C_NO_DEV_ACK) { + dev_dbg(i2c->dev, "No ACK from device\n"); + i2c->state = -ENXIO; + goto stop; + } else if (trans_status & HSI2C_NO_DEV) { + dev_dbg(i2c->dev, "No device\n"); + i2c->state = -ENXIO; + goto stop; + } else if (trans_status & HSI2C_TRANS_ABORT) { + dev_dbg(i2c->dev, "Deal with arbitration lose\n"); + i2c->state = -EAGAIN; + goto stop; + } else if (trans_status & HSI2C_TIMEOUT_AUTO) { + dev_dbg(i2c->dev, "Accessing device timed out\n"); + i2c->state = -EAGAIN; + goto stop; + } else if (trans_status & HSI2C_TRANS_DONE) { + i2c->trans_done = 1; + i2c->state = 0; + } + } + + if ((i2c->msg->flags & I2C_M_RD) && (int_status & + (HSI2C_INT_TRAILING | HSI2C_INT_RX_ALMOSTFULL))) { + fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); + fifo_level = HSI2C_RX_FIFO_LVL(fifo_status); + len = min(fifo_level, i2c->msg->len - i2c->msg_ptr); + + while (len > 0) { + byte = (unsigned char) + readl(i2c->regs + HSI2C_RX_DATA); + i2c->msg->buf[i2c->msg_ptr++] = byte; + len--; + } + i2c->state = 0; + } else if (int_status & HSI2C_INT_TX_ALMOSTEMPTY) { + fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); + fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); + + len = HSI2C_FIFO_MAX - fifo_level; + if (len > (i2c->msg->len - i2c->msg_ptr)) + len = i2c->msg->len - i2c->msg_ptr; + + while (len > 0) { + byte = i2c->msg->buf[i2c->msg_ptr++]; + writel(byte, i2c->regs + HSI2C_TX_DATA); + len--; + } + i2c->state = 0; + } + + stop: + if ((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) || + (i2c->state < 0)) { + writel(0, i2c->regs + HSI2C_INT_ENABLE); + exynos5_i2c_clr_pend_irq(i2c); + complete(&i2c->msg_complete); + } + + spin_unlock(&i2c->lock); + + return IRQ_HANDLED; +} + +/* + * exynos5_i2c_wait_bus_idle + * + * Wait for the bus to go idle, indicated by the MASTER_BUSY bit being + * cleared. + * + * Returns -EBUSY if the bus cannot be bought to idle + */ +static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) +{ + unsigned long stop_time; + u32 trans_status; + + /* wait for 100 milli seconds for the bus to be idle */ + stop_time = jiffies + msecs_to_jiffies(100) + 1; + do { + trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); + if (!(trans_status & HSI2C_MASTER_BUSY)) + return 0; + + usleep_range(50, 200); + } while (time_before(jiffies, stop_time)); + + return -EBUSY; +} + +/* + * exynos5_i2c_message_start: Configures the bus and starts the xfer + * i2c: struct exynos5_i2c pointer for the current bus + * stop: Enables stop after transfer if set. Set for last transfer of + * in the list of messages. + * + * Configures the bus for read/write function + * Sets chip address to talk to, message length to be sent. + * Enables appropriate interrupts and sends start xfer command. + */ +static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) +{ + u32 i2c_ctl; + u32 int_en = HSI2C_INT_I2C_EN; + u32 i2c_auto_conf = 0; + u32 fifo_ctl; + unsigned long flags; + + i2c_ctl = readl(i2c->regs + HSI2C_CTL); + i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); + fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN; + + if (i2c->msg->flags & I2C_M_RD) { + i2c_ctl |= HSI2C_RXCHON; + + i2c_auto_conf = HSI2C_READ_WRITE; + + fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL); + int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | + HSI2C_INT_TRAILING_EN); + } else { + i2c_ctl |= HSI2C_TXCHON; + + fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL); + int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; + } + + writel(HSI2C_SLV_ADDR_MAS(i2c->msg->addr), i2c->regs + HSI2C_ADDR); + + writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL); + writel(i2c_ctl, i2c->regs + HSI2C_CTL); + + + /* + * Enable interrupts before starting the transfer so that we don't + * miss any INT_I2C interrupts. + */ + spin_lock_irqsave(&i2c->lock, flags); + writel(int_en, i2c->regs + HSI2C_INT_ENABLE); + + if (stop == 1) + i2c_auto_conf |= HSI2C_STOP_AFTER_TRANS; + i2c_auto_conf |= i2c->msg->len; + i2c_auto_conf |= HSI2C_MASTER_RUN; + writel(i2c_auto_conf, i2c->regs + HSI2C_AUTO_CONF); + spin_unlock_irqrestore(&i2c->lock, flags); +} + +static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, + struct i2c_msg *msgs, int stop) +{ + unsigned long timeout; + int ret; + + i2c->msg = msgs; + i2c->msg_ptr = 0; + i2c->trans_done = 0; + + INIT_COMPLETION(i2c->msg_complete); + + exynos5_i2c_message_start(i2c, stop); + + timeout = wait_for_completion_timeout(&i2c->msg_complete, + EXYNOS5_I2C_TIMEOUT); + if (timeout == 0) + ret = -ETIMEDOUT; + else + ret = i2c->state; + + /* + * If this is the last message to be transfered (stop == 1) + * Then check if the bus can be brought back to idle. + */ + if (ret == 0 && stop) + ret = exynos5_i2c_wait_bus_idle(i2c); + + if (ret < 0) { + exynos5_i2c_reset(i2c); + if (ret == -ETIMEDOUT) + dev_warn(i2c->dev, "%s timeout\n", + (msgs->flags & I2C_M_RD) ? "rx" : "tx"); + } + + /* Return the state as in interrupt routine */ + return ret; +} + +static int exynos5_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data; + int i = 0, ret = 0, stop = 0; + + if (i2c->suspended) { + dev_err(i2c->dev, "HS-I2C is not initialzed.\n"); + return -EIO; + } + + clk_prepare_enable(i2c->clk); + + for (i = 0; i < num; i++, msgs++) { + stop = (i == num - 1); + + ret = exynos5_i2c_xfer_msg(i2c, msgs, stop); + + if (ret < 0) + goto out; + } + + if (i == num) { + ret = num; + } else { + /* Only one message, cannot access the device */ + if (i == 1) + ret = -EREMOTEIO; + else + ret = i; + + dev_warn(i2c->dev, "xfer message failed\n"); + } + + out: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static u32 exynos5_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +static const struct i2c_algorithm exynos5_i2c_algorithm = { + .master_xfer = exynos5_i2c_xfer, + .functionality = exynos5_i2c_func, +}; + +static int exynos5_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct exynos5_i2c *i2c; + struct resource *mem; + unsigned int op_clock; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); + if (!i2c) { + dev_err(&pdev->dev, "no memory for state\n"); + return -ENOMEM; + } + + if (of_property_read_u32(np, "clock-frequency", &op_clock)) { + i2c->speed_mode = HSI2C_FAST_SPD; + i2c->fs_clock = HSI2C_FS_TX_CLOCK; + } else { + if (op_clock >= HSI2C_HS_TX_CLOCK) { + i2c->speed_mode = HSI2C_HIGH_SPD; + i2c->fs_clock = HSI2C_FS_TX_CLOCK; + i2c->hs_clock = op_clock; + } else { + i2c->speed_mode = HSI2C_FAST_SPD; + i2c->fs_clock = op_clock; + } + } + + strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &exynos5_i2c_algorithm; + i2c->adap.retries = 3; + + i2c->dev = &pdev->dev; + i2c->clk = devm_clk_get(&pdev->dev, "hsi2c"); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return -ENOENT; + } + + clk_prepare_enable(i2c->clk); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(i2c->regs)) { + ret = PTR_ERR(i2c->regs); + goto err_clk; + } + + i2c->adap.dev.of_node = np; + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = &pdev->dev; + + /* Clear pending interrupts from u-boot or misc causes */ + exynos5_i2c_clr_pend_irq(i2c); + + spin_lock_init(&i2c->lock); + init_completion(&i2c->msg_complete); + + i2c->irq = ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n"); + ret = -EINVAL; + goto err_clk; + } + + ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + dev_name(&pdev->dev), i2c); + + if (ret != 0) { + dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", i2c->irq); + goto err_clk; + } + + ret = exynos5_hsi2c_clock_setup(i2c); + if (ret) + goto err_clk; + + exynos5_i2c_init(i2c); + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + goto err_clk; + } + + platform_set_drvdata(pdev, i2c); + + clk_disable_unprepare(i2c->clk); + + return 0; + + err_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int exynos5_i2c_remove(struct platform_device *pdev) +{ + struct exynos5_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + + return 0; +} + +static int exynos5_i2c_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct exynos5_i2c *i2c = platform_get_drvdata(pdev); + + i2c->suspended = 1; + + return 0; +} + +static int exynos5_i2c_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct exynos5_i2c *i2c = platform_get_drvdata(pdev); + int ret = 0; + + clk_prepare_enable(i2c->clk); + + ret = exynos5_hsi2c_clock_setup(i2c); + if (ret) { + clk_disable_unprepare(i2c->clk); + return ret; + } + + exynos5_i2c_init(i2c); + clk_disable_unprepare(i2c->clk); + i2c->suspended = 0; + + return 0; +} + +static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq, + exynos5_i2c_resume_noirq); + +static struct platform_driver exynos5_i2c_driver = { + .probe = exynos5_i2c_probe, + .remove = exynos5_i2c_remove, + .driver = { + .owner = THIS_MODULE, + .name = "exynos5-hsi2c", + .pm = &exynos5_i2c_dev_pm_ops, + .of_match_table = exynos5_i2c_match, + }, +}; + +module_platform_driver(exynos5_i2c_driver); + +MODULE_DESCRIPTION("Exynos5 HS-I2C Bus driver"); +MODULE_AUTHOR("Naveen Krishna Chatradhi, "); +MODULE_AUTHOR("Taekgyun Ko, "); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 85b4fab2696000369176dd222dc3001d4a7e0fa6 Mon Sep 17 00:00:00 2001 From: Maxime COQUELIN Date: Wed, 6 Nov 2013 09:25:12 +0100 Subject: i2c: i2c-st: Add ST I2C controller This patch adds support to SSC (Synchronous Serial Controller) I2C driver. This IP also supports SPI protocol, but this is not the aim of this driver. This IP is embedded in all ST SoCs for Set-top box platorms, and supports I2C Standard and Fast modes. Signed-off-by: Maxime Coquelin Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-st.txt b/Documentation/devicetree/bindings/i2c/i2c-st.txt new file mode 100644 index 0000000..437e0db --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-st.txt @@ -0,0 +1,41 @@ +ST SSC binding, for I2C mode operation + +Required properties : +- compatible : Must be "st,comms-ssc-i2c" or "st,comms-ssc4-i2c" +- reg : Offset and length of the register set for the device +- interrupts : the interrupt specifier +- clock-names: Must contain "ssc". +- clocks: Must contain an entry for each name in clock-names. See the common + clock bindings. +- A pinctrl state named "default" must be defined to set pins in mode of + operation for I2C transfer. + +Optional properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, + the default 100 kHz frequency will be used. As only Normal and Fast modes + are supported, possible values are 100000 and 400000. +- st,i2c-min-scl-pulse-width-us : The minimum valid SCL pulse width that is + allowed through the deglitch circuit. In units of us. +- st,i2c-min-sda-pulse-width-us : The minimum valid SDA pulse width that is + allowed through the deglitch circuit. In units of us. +- A pinctrl state named "idle" could be defined to set pins in idle state + when I2C instance is not performing a transfer. +- A pinctrl state named "sleep" could be defined to set pins in sleep state + when driver enters in suspend. + + + +Example : + +i2c0: i2c@fed40000 { + compatible = "st,comms-ssc4-i2c"; + reg = <0xfed40000 0x110>; + interrupts = ; + clocks = <&CLK_S_ICN_REG_0>; + clock-names = "ssc"; + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0_default>; + st,i2c-min-scl-pulse-width-us = <0>; + st,i2c-min-sda-pulse-width-us = <5>; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 80e5530..0126462 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -702,6 +702,16 @@ config I2C_SIRF This driver can also be built as a module. If so, the module will be called i2c-sirf. +config I2C_ST + tristate "STMicroelectronics SSC I2C support" + depends on ARCH_STI + help + Enable this option to add support for STMicroelectronics SoCs + hardware SSC (Synchronous Serial Controller) as an I2C controller. + + This driver can also be built as module. If so, the module + will be called i2c-st. + config I2C_STU300 tristate "ST Microelectronics DDC I2C interface" depends on MACH_U300 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index d1ad371..e129486 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o +obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c new file mode 100644 index 0000000..fa57c5e --- /dev/null +++ b/drivers/i2c/busses/i2c-st.c @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2013 STMicroelectronics + * + * I2C master mode controller driver, used in STMicroelectronics devices. + * + * Author: Maxime Coquelin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SSC registers */ +#define SSC_BRG 0x000 +#define SSC_TBUF 0x004 +#define SSC_RBUF 0x008 +#define SSC_CTL 0x00C +#define SSC_IEN 0x010 +#define SSC_STA 0x014 +#define SSC_I2C 0x018 +#define SSC_SLAD 0x01C +#define SSC_REP_START_HOLD 0x020 +#define SSC_START_HOLD 0x024 +#define SSC_REP_START_SETUP 0x028 +#define SSC_DATA_SETUP 0x02C +#define SSC_STOP_SETUP 0x030 +#define SSC_BUS_FREE 0x034 +#define SSC_TX_FSTAT 0x038 +#define SSC_RX_FSTAT 0x03C +#define SSC_PRE_SCALER_BRG 0x040 +#define SSC_CLR 0x080 +#define SSC_NOISE_SUPP_WIDTH 0x100 +#define SSC_PRSCALER 0x104 +#define SSC_NOISE_SUPP_WIDTH_DATAOUT 0x108 +#define SSC_PRSCALER_DATAOUT 0x10c + +/* SSC Control */ +#define SSC_CTL_DATA_WIDTH_9 0x8 +#define SSC_CTL_DATA_WIDTH_MSK 0xf +#define SSC_CTL_BM 0xf +#define SSC_CTL_HB BIT(4) +#define SSC_CTL_PH BIT(5) +#define SSC_CTL_PO BIT(6) +#define SSC_CTL_SR BIT(7) +#define SSC_CTL_MS BIT(8) +#define SSC_CTL_EN BIT(9) +#define SSC_CTL_LPB BIT(10) +#define SSC_CTL_EN_TX_FIFO BIT(11) +#define SSC_CTL_EN_RX_FIFO BIT(12) +#define SSC_CTL_EN_CLST_RX BIT(13) + +/* SSC Interrupt Enable */ +#define SSC_IEN_RIEN BIT(0) +#define SSC_IEN_TIEN BIT(1) +#define SSC_IEN_TEEN BIT(2) +#define SSC_IEN_REEN BIT(3) +#define SSC_IEN_PEEN BIT(4) +#define SSC_IEN_AASEN BIT(6) +#define SSC_IEN_STOPEN BIT(7) +#define SSC_IEN_ARBLEN BIT(8) +#define SSC_IEN_NACKEN BIT(10) +#define SSC_IEN_REPSTRTEN BIT(11) +#define SSC_IEN_TX_FIFO_HALF BIT(12) +#define SSC_IEN_RX_FIFO_HALF_FULL BIT(14) + +/* SSC Status */ +#define SSC_STA_RIR BIT(0) +#define SSC_STA_TIR BIT(1) +#define SSC_STA_TE BIT(2) +#define SSC_STA_RE BIT(3) +#define SSC_STA_PE BIT(4) +#define SSC_STA_CLST BIT(5) +#define SSC_STA_AAS BIT(6) +#define SSC_STA_STOP BIT(7) +#define SSC_STA_ARBL BIT(8) +#define SSC_STA_BUSY BIT(9) +#define SSC_STA_NACK BIT(10) +#define SSC_STA_REPSTRT BIT(11) +#define SSC_STA_TX_FIFO_HALF BIT(12) +#define SSC_STA_TX_FIFO_FULL BIT(13) +#define SSC_STA_RX_FIFO_HALF BIT(14) + +/* SSC I2C Control */ +#define SSC_I2C_I2CM BIT(0) +#define SSC_I2C_STRTG BIT(1) +#define SSC_I2C_STOPG BIT(2) +#define SSC_I2C_ACKG BIT(3) +#define SSC_I2C_AD10 BIT(4) +#define SSC_I2C_TXENB BIT(5) +#define SSC_I2C_REPSTRTG BIT(11) +#define SSC_I2C_SLAVE_DISABLE BIT(12) + +/* SSC Tx FIFO Status */ +#define SSC_TX_FSTAT_STATUS 0x07 + +/* SSC Rx FIFO Status */ +#define SSC_RX_FSTAT_STATUS 0x07 + +/* SSC Clear bit operation */ +#define SSC_CLR_SSCAAS BIT(6) +#define SSC_CLR_SSCSTOP BIT(7) +#define SSC_CLR_SSCARBL BIT(8) +#define SSC_CLR_NACK BIT(10) +#define SSC_CLR_REPSTRT BIT(11) + +/* SSC Clock Prescaler */ +#define SSC_PRSC_VALUE 0x0f + + +#define SSC_TXFIFO_SIZE 0x8 +#define SSC_RXFIFO_SIZE 0x8 + +enum st_i2c_mode { + I2C_MODE_STANDARD, + I2C_MODE_FAST, + I2C_MODE_END, +}; + +/** + * struct st_i2c_timings - per-Mode tuning parameters + * @rate: I2C bus rate + * @rep_start_hold: I2C repeated start hold time requirement + * @rep_start_setup: I2C repeated start set up time requirement + * @start_hold: I2C start hold time requirement + * @data_setup_time: I2C data set up time requirement + * @stop_setup_time: I2C stop set up time requirement + * @bus_free_time: I2C bus free time requirement + * @sda_pulse_min_limit: I2C SDA pulse mini width limit + */ +struct st_i2c_timings { + u32 rate; + u32 rep_start_hold; + u32 rep_start_setup; + u32 start_hold; + u32 data_setup_time; + u32 stop_setup_time; + u32 bus_free_time; + u32 sda_pulse_min_limit; +}; + +/** + * struct st_i2c_client - client specific data + * @addr: 8-bit slave addr, including r/w bit + * @count: number of bytes to be transfered + * @xfered: number of bytes already transferred + * @buf: data buffer + * @result: result of the transfer + * @stop: last I2C msg to be sent, i.e. STOP to be generated + */ +struct st_i2c_client { + u8 addr; + u32 count; + u32 xfered; + u8 *buf; + int result; + bool stop; +}; + +/** + * struct st_i2c_dev - private data of the controller + * @adap: I2C adapter for this controller + * @dev: device for this controller + * @base: virtual memory area + * @complete: completion of I2C message + * @irq: interrupt line for th controller + * @clk: hw ssc block clock + * @mode: I2C mode of the controller. Standard or Fast only supported + * @scl_min_width_us: SCL line minimum pulse width in us + * @sda_min_width_us: SDA line minimum pulse width in us + * @client: I2C transfert information + * @busy: I2C transfer on-going + */ +struct st_i2c_dev { + struct i2c_adapter adap; + struct device *dev; + void __iomem *base; + struct completion complete; + int irq; + struct clk *clk; + int mode; + u32 scl_min_width_us; + u32 sda_min_width_us; + struct st_i2c_client client; + bool busy; +}; + +static inline void st_i2c_set_bits(void __iomem *reg, u32 mask) +{ + writel_relaxed(readl_relaxed(reg) | mask, reg); +} + +static inline void st_i2c_clr_bits(void __iomem *reg, u32 mask) +{ + writel_relaxed(readl_relaxed(reg) & ~mask, reg); +} + +/* From I2C Specifications v0.5 */ +static struct st_i2c_timings i2c_timings[] = { + [I2C_MODE_STANDARD] = { + .rate = 100000, + .rep_start_hold = 4000, + .rep_start_setup = 4700, + .start_hold = 4000, + .data_setup_time = 250, + .stop_setup_time = 4000, + .bus_free_time = 4700, + }, + [I2C_MODE_FAST] = { + .rate = 400000, + .rep_start_hold = 600, + .rep_start_setup = 600, + .start_hold = 600, + .data_setup_time = 100, + .stop_setup_time = 600, + .bus_free_time = 1300, + }, +}; + +static void st_i2c_flush_rx_fifo(struct st_i2c_dev *i2c_dev) +{ + int count, i; + + /* + * Counter only counts up to 7 but fifo size is 8... + * When fifo is full, counter is 0 and RIR bit of status register is + * set + */ + if (readl_relaxed(i2c_dev->base + SSC_STA) & SSC_STA_RIR) + count = SSC_RXFIFO_SIZE; + else + count = readl_relaxed(i2c_dev->base + SSC_RX_FSTAT) & + SSC_RX_FSTAT_STATUS; + + for (i = 0; i < count; i++) + readl_relaxed(i2c_dev->base + SSC_RBUF); +} + +static void st_i2c_soft_reset(struct st_i2c_dev *i2c_dev) +{ + /* + * FIFO needs to be emptied before reseting the IP, + * else the controller raises a BUSY error. + */ + st_i2c_flush_rx_fifo(i2c_dev); + + st_i2c_set_bits(i2c_dev->base + SSC_CTL, SSC_CTL_SR); + st_i2c_clr_bits(i2c_dev->base + SSC_CTL, SSC_CTL_SR); +} + +/** + * st_i2c_hw_config() - Prepare SSC block, calculate and apply tuning timings + * @i2c_dev: Controller's private data + */ +static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev) +{ + unsigned long rate; + u32 val, ns_per_clk; + struct st_i2c_timings *t = &i2c_timings[i2c_dev->mode]; + + st_i2c_soft_reset(i2c_dev); + + val = SSC_CLR_REPSTRT | SSC_CLR_NACK | SSC_CLR_SSCARBL | + SSC_CLR_SSCAAS | SSC_CLR_SSCSTOP; + writel_relaxed(val, i2c_dev->base + SSC_CLR); + + /* SSC Control register setup */ + val = SSC_CTL_PO | SSC_CTL_PH | SSC_CTL_HB | SSC_CTL_DATA_WIDTH_9; + writel_relaxed(val, i2c_dev->base + SSC_CTL); + + rate = clk_get_rate(i2c_dev->clk); + ns_per_clk = 1000000000 / rate; + + /* Baudrate */ + val = rate / (2 * t->rate); + writel_relaxed(val, i2c_dev->base + SSC_BRG); + + /* Pre-scaler baudrate */ + writel_relaxed(1, i2c_dev->base + SSC_PRE_SCALER_BRG); + + /* Enable I2C mode */ + writel_relaxed(SSC_I2C_I2CM, i2c_dev->base + SSC_I2C); + + /* Repeated start hold time */ + val = t->rep_start_hold / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_REP_START_HOLD); + + /* Repeated start set up time */ + val = t->rep_start_setup / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_REP_START_SETUP); + + /* Start hold time */ + val = t->start_hold / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_START_HOLD); + + /* Data set up time */ + val = t->data_setup_time / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_DATA_SETUP); + + /* Stop set up time */ + val = t->stop_setup_time / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_STOP_SETUP); + + /* Bus free time */ + val = t->bus_free_time / ns_per_clk; + writel_relaxed(val, i2c_dev->base + SSC_BUS_FREE); + + /* Prescalers set up */ + val = rate / 10000000; + writel_relaxed(val, i2c_dev->base + SSC_PRSCALER); + writel_relaxed(val, i2c_dev->base + SSC_PRSCALER_DATAOUT); + + /* Noise suppression witdh */ + val = i2c_dev->scl_min_width_us * rate / 100000000; + writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH); + + /* Noise suppression max output data delay width */ + val = i2c_dev->sda_min_width_us * rate / 100000000; + writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT); +} + +static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev) +{ + u32 sta; + int i; + + for (i = 0; i < 10; i++) { + sta = readl_relaxed(i2c_dev->base + SSC_STA); + if (!(sta & SSC_STA_BUSY)) + return 0; + + usleep_range(2000, 4000); + } + + dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta); + + return -EBUSY; +} + +/** + * st_i2c_write_tx_fifo() - Write a byte in the Tx FIFO + * @i2c_dev: Controller's private data + * @byte: Data to write in the Tx FIFO + */ +static inline void st_i2c_write_tx_fifo(struct st_i2c_dev *i2c_dev, u8 byte) +{ + u16 tbuf = byte << 1; + + writel_relaxed(tbuf | 1, i2c_dev->base + SSC_TBUF); +} + +/** + * st_i2c_wr_fill_tx_fifo() - Fill the Tx FIFO in write mode + * @i2c_dev: Controller's private data + * + * This functions fills the Tx FIFO with I2C transfert buffer when + * in write mode. + */ +static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev) +{ + struct st_i2c_client *c = &i2c_dev->client; + u32 tx_fstat, sta; + int i; + + sta = readl_relaxed(i2c_dev->base + SSC_STA); + if (sta & SSC_STA_TX_FIFO_FULL) + return; + + tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT); + tx_fstat &= SSC_TX_FSTAT_STATUS; + + if (c->count < (SSC_TXFIFO_SIZE - tx_fstat)) + i = c->count; + else + i = SSC_TXFIFO_SIZE - tx_fstat; + + for (; i > 0; i--, c->count--, c->buf++) + st_i2c_write_tx_fifo(i2c_dev, *c->buf); +} + +/** + * st_i2c_rd_fill_tx_fifo() - Fill the Tx FIFO in read mode + * @i2c_dev: Controller's private data + * + * This functions fills the Tx FIFO with fixed pattern when + * in read mode to trigger clock. + */ +static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max) +{ + struct st_i2c_client *c = &i2c_dev->client; + u32 tx_fstat, sta; + int i; + + sta = readl_relaxed(i2c_dev->base + SSC_STA); + if (sta & SSC_STA_TX_FIFO_FULL) + return; + + tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT); + tx_fstat &= SSC_TX_FSTAT_STATUS; + + if (max < (SSC_TXFIFO_SIZE - tx_fstat)) + i = max; + else + i = SSC_TXFIFO_SIZE - tx_fstat; + + for (; i > 0; i--, c->xfered++) + st_i2c_write_tx_fifo(i2c_dev, 0xff); +} + +static void st_i2c_read_rx_fifo(struct st_i2c_dev *i2c_dev) +{ + struct st_i2c_client *c = &i2c_dev->client; + u32 i, sta; + u16 rbuf; + + sta = readl_relaxed(i2c_dev->base + SSC_STA); + if (sta & SSC_STA_RIR) { + i = SSC_RXFIFO_SIZE; + } else { + i = readl_relaxed(i2c_dev->base + SSC_RX_FSTAT); + i &= SSC_RX_FSTAT_STATUS; + } + + for (; (i > 0) && (c->count > 0); i--, c->count--) { + rbuf = readl_relaxed(i2c_dev->base + SSC_RBUF) >> 1; + *c->buf++ = (u8)rbuf & 0xff; + } + + if (i) { + dev_err(i2c_dev->dev, "Unexpected %d bytes in rx fifo\n", i); + st_i2c_flush_rx_fifo(i2c_dev); + } +} + +/** + * st_i2c_terminate_xfer() - Send either STOP or REPSTART condition + * @i2c_dev: Controller's private data + */ +static void st_i2c_terminate_xfer(struct st_i2c_dev *i2c_dev) +{ + struct st_i2c_client *c = &i2c_dev->client; + + st_i2c_clr_bits(i2c_dev->base + SSC_IEN, SSC_IEN_TEEN); + st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG); + + if (c->stop) { + st_i2c_set_bits(i2c_dev->base + SSC_IEN, SSC_IEN_STOPEN); + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); + } else { + st_i2c_set_bits(i2c_dev->base + SSC_IEN, SSC_IEN_REPSTRTEN); + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_REPSTRTG); + } +} + +/** + * st_i2c_handle_write() - Handle FIFO empty interrupt in case of write + * @i2c_dev: Controller's private data + */ +static void st_i2c_handle_write(struct st_i2c_dev *i2c_dev) +{ + struct st_i2c_client *c = &i2c_dev->client; + + st_i2c_flush_rx_fifo(i2c_dev); + + if (!c->count) + /* End of xfer, send stop or repstart */ + st_i2c_terminate_xfer(i2c_dev); + else + st_i2c_wr_fill_tx_fifo(i2c_dev); +} + +/** + * st_i2c_handle_write() - Handle FIFO enmpty interrupt in case of read + * @i2c_dev: Controller's private data + */ +static void st_i2c_handle_read(struct st_i2c_dev *i2c_dev) +{ + struct st_i2c_client *c = &i2c_dev->client; + u32 ien; + + /* Trash the address read back */ + if (!c->xfered) { + readl_relaxed(i2c_dev->base + SSC_RBUF); + st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_TXENB); + } else { + st_i2c_read_rx_fifo(i2c_dev); + } + + if (!c->count) { + /* End of xfer, send stop or repstart */ + st_i2c_terminate_xfer(i2c_dev); + } else if (c->count == 1) { + /* Penultimate byte to xfer, disable ACK gen. */ + st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_ACKG); + + /* Last received byte is to be handled by NACK interrupt */ + ien = SSC_IEN_NACKEN | SSC_IEN_ARBLEN; + writel_relaxed(ien, i2c_dev->base + SSC_IEN); + + st_i2c_rd_fill_tx_fifo(i2c_dev, c->count); + } else { + st_i2c_rd_fill_tx_fifo(i2c_dev, c->count - 1); + } +} + +/** + * st_i2c_isr() - Interrupt routine + * @irq: interrupt number + * @data: Controller's private data + */ +static irqreturn_t st_i2c_isr_thread(int irq, void *data) +{ + struct st_i2c_dev *i2c_dev = data; + struct st_i2c_client *c = &i2c_dev->client; + u32 sta, ien; + int it; + + ien = readl_relaxed(i2c_dev->base + SSC_IEN); + sta = readl_relaxed(i2c_dev->base + SSC_STA); + + /* Use __fls() to check error bits first */ + it = __fls(sta & ien); + if (it < 0) { + dev_dbg(i2c_dev->dev, "spurious it (sta=0x%04x, ien=0x%04x)\n", + sta, ien); + return IRQ_NONE; + } + + switch (1 << it) { + case SSC_STA_TE: + if (c->addr & I2C_M_RD) + st_i2c_handle_read(i2c_dev); + else + st_i2c_handle_write(i2c_dev); + break; + + case SSC_STA_STOP: + case SSC_STA_REPSTRT: + writel_relaxed(0, i2c_dev->base + SSC_IEN); + complete(&i2c_dev->complete); + break; + + case SSC_STA_NACK: + writel_relaxed(SSC_CLR_NACK, i2c_dev->base + SSC_CLR); + + /* Last received byte handled by NACK interrupt */ + if ((c->addr & I2C_M_RD) && (c->count == 1) && (c->xfered)) { + st_i2c_handle_read(i2c_dev); + break; + } + + it = SSC_IEN_STOPEN | SSC_IEN_ARBLEN; + writel_relaxed(it, i2c_dev->base + SSC_IEN); + + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); + c->result = -EIO; + break; + + case SSC_STA_ARBL: + writel_relaxed(SSC_CLR_SSCARBL, i2c_dev->base + SSC_CLR); + + it = SSC_IEN_STOPEN | SSC_IEN_ARBLEN; + writel_relaxed(it, i2c_dev->base + SSC_IEN); + + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG); + c->result = -EIO; + break; + + default: + dev_err(i2c_dev->dev, + "it %d unhandled (sta=0x%04x)\n", it, sta); + } + + /* + * Read IEN register to ensure interrupt mask write is effective + * before re-enabling interrupt at GIC level, and thus avoid spurious + * interrupts. + */ + readl(i2c_dev->base + SSC_IEN); + + return IRQ_HANDLED; +} + +/** + * st_i2c_xfer_msg() - Transfer a single I2C message + * @i2c_dev: Controller's private data + * @msg: I2C message to transfer + * @is_first: first message of the sequence + * @is_last: last message of the sequence + */ +static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, + bool is_first, bool is_last) +{ + struct st_i2c_client *c = &i2c_dev->client; + u32 ctl, i2c, it; + unsigned long timeout; + int ret; + + c->addr = (u8)(msg->addr << 1); + c->addr |= (msg->flags & I2C_M_RD); + c->buf = msg->buf; + c->count = msg->len; + c->xfered = 0; + c->result = 0; + c->stop = is_last; + + INIT_COMPLETION(i2c_dev->complete); + + ctl = SSC_CTL_EN | SSC_CTL_MS | SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO; + st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl); + + i2c = SSC_I2C_TXENB; + if (c->addr & I2C_M_RD) + i2c |= SSC_I2C_ACKG; + st_i2c_set_bits(i2c_dev->base + SSC_I2C, i2c); + + /* Write slave address */ + st_i2c_write_tx_fifo(i2c_dev, c->addr); + + /* Pre-fill Tx fifo with data in case of write */ + if (!(c->addr & I2C_M_RD)) + st_i2c_wr_fill_tx_fifo(i2c_dev); + + it = SSC_IEN_NACKEN | SSC_IEN_TEEN | SSC_IEN_ARBLEN; + writel_relaxed(it, i2c_dev->base + SSC_IEN); + + if (is_first) { + ret = st_i2c_wait_free_bus(i2c_dev); + if (ret) + return ret; + + st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG); + } + + timeout = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + ret = c->result; + + if (!timeout) { + dev_err(i2c_dev->dev, "Write to slave 0x%x timed out\n", + c->addr); + ret = -ETIMEDOUT; + } + + i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG; + st_i2c_clr_bits(i2c_dev->base + SSC_I2C, i2c); + + writel_relaxed(SSC_CLR_SSCSTOP | SSC_CLR_REPSTRT, + i2c_dev->base + SSC_CLR); + + return ret; +} + +/** + * st_i2c_xfer() - Transfer a single I2C message + * @i2c_adap: Adapter pointer to the controller + * @msgs: Pointer to data to be written. + * @num: Number of messages to be executed + */ +static int st_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + int ret, i; + + i2c_dev->busy = true; + + ret = clk_prepare_enable(i2c_dev->clk); + if (ret) { + dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n"); + return ret; + } + + pinctrl_pm_select_default_state(i2c_dev->dev); + + st_i2c_hw_config(i2c_dev); + + for (i = 0; (i < num) && !ret; i++) + ret = st_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0, i == num - 1); + + pinctrl_pm_select_idle_state(i2c_dev->dev); + + clk_disable_unprepare(i2c_dev->clk); + + i2c_dev->busy = false; + + return (ret < 0) ? ret : i; +} + +#ifdef CONFIG_PM_SLEEP +static int st_i2c_suspend(struct device *dev) +{ + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + if (i2c_dev->busy) + return -EBUSY; + + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int st_i2c_resume(struct device *dev) +{ + pinctrl_pm_select_default_state(dev); + /* Go in idle state if available */ + pinctrl_pm_select_idle_state(dev); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume); +#define ST_I2C_PM (&st_i2c_pm) +#else +#define ST_I2C_PM NULL +#endif + +static u32 st_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm st_i2c_algo = { + .master_xfer = st_i2c_xfer, + .functionality = st_i2c_func, +}; + +static int st_i2c_of_get_deglitch(struct device_node *np, + struct st_i2c_dev *i2c_dev) +{ + int ret; + + ret = of_property_read_u32(np, "st,i2c-min-scl-pulse-width-us", + &i2c_dev->scl_min_width_us); + if ((ret == -ENODATA) || (ret == -EOVERFLOW)) { + dev_err(i2c_dev->dev, "st,i2c-min-scl-pulse-width-us invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "st,i2c-min-sda-pulse-width-us", + &i2c_dev->sda_min_width_us); + if ((ret == -ENODATA) || (ret == -EOVERFLOW)) { + dev_err(i2c_dev->dev, "st,i2c-min-sda-pulse-width-us invalid\n"); + return ret; + } + + return 0; +} + +static int st_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct st_i2c_dev *i2c_dev; + struct resource *res; + u32 clk_rate; + struct i2c_adapter *adap; + int ret; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) { + dev_err(&pdev->dev, "IRQ missing or invalid\n"); + return -EINVAL; + } + + i2c_dev->clk = of_clk_get_by_name(np, "ssc"); + if (IS_ERR(i2c_dev->clk)) { + dev_err(&pdev->dev, "Unable to request clock\n"); + return PTR_ERR(i2c_dev->clk); + } + + i2c_dev->mode = I2C_MODE_STANDARD; + ret = of_property_read_u32(np, "clock-frequency", &clk_rate); + if ((!ret) && (clk_rate == 400000)) + i2c_dev->mode = I2C_MODE_FAST; + + i2c_dev->dev = &pdev->dev; + + ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq, + NULL, st_i2c_isr_thread, + IRQF_ONESHOT, pdev->name, i2c_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); + return ret; + } + + pinctrl_pm_select_default_state(i2c_dev->dev); + /* In case idle state available, select it */ + pinctrl_pm_select_idle_state(i2c_dev->dev); + + ret = st_i2c_of_get_deglitch(np, i2c_dev); + if (ret) + return ret; + + adap = &i2c_dev->adap; + i2c_set_adapdata(adap, i2c_dev); + snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%x)", res->start); + adap->owner = THIS_MODULE; + adap->timeout = 2 * HZ; + adap->retries = 0; + adap->algo = &st_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + init_completion(&i2c_dev->complete); + + ret = i2c_add_adapter(adap); + if (ret) { + dev_err(&pdev->dev, "Failed to add adapter\n"); + return ret; + } + + platform_set_drvdata(pdev, i2c_dev); + + dev_info(i2c_dev->dev, "%s initialized\n", adap->name); + + return 0; +} + +static int st_i2c_remove(struct platform_device *pdev) +{ + struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c_dev->adap); + + return 0; +} + +static struct of_device_id st_i2c_match[] = { + { .compatible = "st,comms-ssc-i2c", }, + { .compatible = "st,comms-ssc4-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, st_i2c_match); + +static struct platform_driver st_i2c_driver = { + .driver = { + .name = "st-i2c", + .owner = THIS_MODULE, + .of_match_table = st_i2c_match, + .pm = ST_I2C_PM, + }, + .probe = st_i2c_probe, + .remove = st_i2c_remove, +}; + +module_platform_driver(st_i2c_driver); + +MODULE_AUTHOR("Maxime Coquelin "); +MODULE_DESCRIPTION("STMicroelectronics I2C driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 3cd0c2dfb482c90dd0547ec492c32adeb31e2bd5 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 6 Nov 2013 15:09:18 +0530 Subject: i2c: exynos5: Remove incorrect clk_disable_unprepare clk_disable_unprepare in remove causes an imbalance and hence gives the below crash on module remove. While at it also remove some duplicate code from probe. / $ rmmod i2c-exynos5 [ 6.996374] ------------[ cut here ]------------ [ 6.999523] WARNING: CPU: 2 PID: 1137 at drivers/clk/clk.c:842 clk_disable+0x18/0x24() [ 7.007403] Modules linked in: i2c_exynos5(-) [ 7.011747] CPU: 2 PID: 1137 Comm: rmmod Not tainted 3.12.0-next-20131105-00083-g16f4799-dirty #21 [ 7.020696] [] (unwind_backtrace+0x0/0xf4) from [] (show_stack+0x10/0x14) [ 7.029190] [] (show_stack+0x10/0x14) from [] (dump_stack+0x7c/0xb0) [ 7.037255] [] (dump_stack+0x7c/0xb0) from [] (warn_slowpath_common+0x6c/0x88) [ 7.046190] [] (warn_slowpath_common+0x6c/0x88) from [] (warn_slowpath_null+0x1c/0x24) [ 7.055818] [] (warn_slowpath_null+0x1c/0x24) from [] (clk_disable+0x18/0x24) [ 7.064670] [] (clk_disable+0x18/0x24) from [] (exynos5_i2c_remove+0x1c/0x34 [i2c_exynos5]) [ 7.074736] [] (exynos5_i2c_remove+0x1c/0x34 [i2c_exynos5]) from [] (__device_release_driver+0x58/0xb0) [ 7.085836] [] (__device_release_driver+0x58/0xb0) from [] (driver_detach+0xac/0xb0) [ 7.095291] [] (driver_detach+0xac/0xb0) from [] (bus_remove_driver+0x4c/0xa0) [ 7.104227] [] (bus_remove_driver+0x4c/0xa0) from [] (SyS_delete_module+0x124/0x194) [ 7.113682] [] (SyS_delete_module+0x124/0x194) from [] (ret_fast_syscall+0x0/0x30) [ 7.122957] ---[ end trace 23bb6e4e0bf52196 ]--- Signed-off-by: Sachin Kamat Acked-by: Naveen Krishna Chatradhi Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index aca3991..da39ff0 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -702,10 +702,6 @@ static int exynos5_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - clk_disable_unprepare(i2c->clk); - - return 0; - err_clk: clk_disable_unprepare(i2c->clk); return ret; @@ -716,7 +712,6 @@ static int exynos5_i2c_remove(struct platform_device *pdev) struct exynos5_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); - clk_disable_unprepare(i2c->clk); return 0; } -- cgit v0.10.2 From afc659241258b40b683998ec801d25d276529f43 Mon Sep 17 00:00:00 2001 From: James Ralston Date: Mon, 4 Nov 2013 09:29:48 -0800 Subject: i2c: i801: Add Device IDs for Intel Wildcat Point-LP PCH This patch adds the SMBus Device IDs for the Intel Wildcat Point-LP PCH. Signed-off-by: James Ralston Signed-off-by: Wolfram Sang diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index d29dea0..7b0dcdb 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -25,6 +25,7 @@ Supported adapters: * Intel Avoton (SOC) * Intel Wellsburg (PCH) * Intel Coleto Creek (PCH) + * Intel Wildcat Point-LP (PCH) Datasheets: Publicly available at the Intel website On Intel Patsburg and later chipsets, both the normal host SMBus controller diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0126462..9feea17 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -109,6 +109,7 @@ config I2C_I801 Avoton (SOC) Wellsburg (PCH) Coleto Creek (PCH) + Wildcat Point-LP (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 4296d17..737e298 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -59,6 +59,7 @@ Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes Coleto Creek (PCH) 0x23b0 32 hard yes yes yes + Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -177,6 +178,7 @@ #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 +#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 struct i801_mux_config { char *gpio_chip; @@ -819,6 +821,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { 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) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, { 0, } }; -- cgit v0.10.2 From 25b3dfc87bff80317d67ddd2cd4cfb91e6fe7d79 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 12 Nov 2013 11:57:30 +0200 Subject: i2c: designware: add new ACPI IDs Newer Intel PCHs with LPSS have the same Designware I2C controllers than Haswell but the ACPI IDs differ. Add these IDs to the driver list. Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 4c1b605..c4ca1aa 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -103,6 +103,8 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C2", 0 }, { "INT33C3", 0 }, + { "INT3432", 0 }, + { "INT3433", 0 }, { "80860F41", 0 }, { } }; -- cgit v0.10.2 From 2dc9688a106886db7191d30f30ffd61fde827efd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 11 Nov 2013 22:23:50 +0800 Subject: i2c: wmt: add missing clk_disable_unprepare() on error Add the missing clk_disable_unprepare() before return from wmt_i2c_reset_hardware() in the error handling case. Signed-off-by: Wei Yongjun Signed-off-by: Wolfram Sang Cc: stable@kernel.org # 3.11+ diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index c65da3d..4bf9507 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -349,6 +349,7 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) err = clk_set_rate(i2c_dev->clk, 20000000); if (err) { dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); + clk_disable_unprepare(i2c_dev->clk); return err; } -- cgit v0.10.2 From de546c8a964accfbfc9c584e5fc1e4c3f5336a18 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 14 Nov 2013 15:08:42 -0800 Subject: i2c: cbus-gpio: Fix device tree binding Looks like we're missing two lines needed to make it work properly with device tree. Signed-off-by: Tony Lindgren Tested-by: Aaro Koskinen Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c index 2d46f13..ce7ffba 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -246,6 +246,7 @@ static int cbus_i2c_probe(struct platform_device *pdev) adapter->owner = THIS_MODULE; adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = &pdev->dev; + adapter->dev.of_node = pdev->dev.of_node; adapter->nr = pdev->id; adapter->timeout = HZ; adapter->algo = &cbus_i2c_algo; @@ -289,6 +290,7 @@ static struct platform_driver cbus_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "i2c-cbus-gpio", + .of_match_table = of_match_ptr(i2c_cbus_dt_ids), }, }; module_platform_driver(cbus_i2c_driver); -- cgit v0.10.2 From 93d17247118ca533edd489f8e09bde417f4720ce Mon Sep 17 00:00:00 2001 From: Tim Kryger Date: Thu, 14 Nov 2013 13:02:13 -0800 Subject: i2c: bcm-kona: Introduce Broadcom I2C Driver Introduce support for Broadcom Serial Controller (BSC) I2C bus found in the Kona family of Mobile SoCs. FIFO hardware is utilized but only standard mode (100kHz), fast mode (400kHz), fast mode plus (1MHz), and I2C high-speed (3.4 MHz) bus speeds are supported. Signed-off-by: Tim Kryger Reviewed-by: Matt Porter Reviewed-by: Markus Mayer [wsa: fixed Kconfig sorting, squashed broken out patches into one] Signed-off-by: Wolfram Sang diff --git a/Documentation/devicetree/bindings/i2c/i2c-bcm-kona.txt b/Documentation/devicetree/bindings/i2c/i2c-bcm-kona.txt new file mode 100644 index 0000000..1b87b74 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-bcm-kona.txt @@ -0,0 +1,35 @@ +Broadcom Kona Family I2C +========================= + +This I2C controller is used in the following Broadcom SoCs: + + BCM11130 + BCM11140 + BCM11351 + BCM28145 + BCM28155 + +Required Properties +------------------- +- compatible: "brcm,bcm11351-i2c", "brcm,kona-i2c" +- reg: Physical base address and length of controller registers +- interrupts: The interrupt number used by the controller +- clocks: clock specifier for the kona i2c external clock +- clock-frequency: The I2C bus frequency in Hz +- #address-cells: Should be <1> +- #size-cells: Should be <0> + +Refer to clocks/clock-bindings.txt for generic clock consumer +properties. + +Example: + +i2c@3e016000 { + compatible = "brcm,bcm11351-i2c","brcm,kona-i2c"; + reg = <0x3e016000 0x80>; + interrupts = ; + clocks = <&bsc1_clk>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 9feea17..3b26129 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -346,6 +346,16 @@ config I2C_BCM2835 This support is also available as a module. If so, the module will be called i2c-bcm2835. +config I2C_BCM_KONA + tristate "BCM Kona I2C adapter" + depends on ARCH_BCM_MOBILE + default y + help + If you say yes to this option, support will be included for the + I2C interface on the Broadcom Kona family of processors. + + If you do not need KONA I2C inteface, say N. + 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 e129486..c73eb0e 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o # Other I2C/SMBus bus drivers obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o +obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c new file mode 100644 index 0000000..7b7b762 --- /dev/null +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -0,0 +1,908 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Hardware register offsets and field defintions */ +#define CS_OFFSET 0x00000020 +#define CS_ACK_SHIFT 3 +#define CS_ACK_MASK 0x00000008 +#define CS_ACK_CMD_GEN_START 0x00000000 +#define CS_ACK_CMD_GEN_RESTART 0x00000001 +#define CS_CMD_SHIFT 1 +#define CS_CMD_CMD_NO_ACTION 0x00000000 +#define CS_CMD_CMD_START_RESTART 0x00000001 +#define CS_CMD_CMD_STOP 0x00000002 +#define CS_EN_SHIFT 0 +#define CS_EN_CMD_ENABLE_BSC 0x00000001 + +#define TIM_OFFSET 0x00000024 +#define TIM_PRESCALE_SHIFT 6 +#define TIM_P_SHIFT 3 +#define TIM_NO_DIV_SHIFT 2 +#define TIM_DIV_SHIFT 0 + +#define DAT_OFFSET 0x00000028 + +#define TOUT_OFFSET 0x0000002c + +#define TXFCR_OFFSET 0x0000003c +#define TXFCR_FIFO_FLUSH_MASK 0x00000080 +#define TXFCR_FIFO_EN_MASK 0x00000040 + +#define IER_OFFSET 0x00000044 +#define IER_READ_COMPLETE_INT_MASK 0x00000010 +#define IER_I2C_INT_EN_MASK 0x00000008 +#define IER_FIFO_INT_EN_MASK 0x00000002 +#define IER_NOACK_EN_MASK 0x00000001 + +#define ISR_OFFSET 0x00000048 +#define ISR_RESERVED_MASK 0xffffff60 +#define ISR_CMDBUSY_MASK 0x00000080 +#define ISR_READ_COMPLETE_MASK 0x00000010 +#define ISR_SES_DONE_MASK 0x00000008 +#define ISR_ERR_MASK 0x00000004 +#define ISR_TXFIFOEMPTY_MASK 0x00000002 +#define ISR_NOACK_MASK 0x00000001 + +#define CLKEN_OFFSET 0x0000004C +#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080 +#define CLKEN_M_SHIFT 4 +#define CLKEN_N_SHIFT 1 +#define CLKEN_CLKEN_MASK 0x00000001 + +#define FIFO_STATUS_OFFSET 0x00000054 +#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004 +#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010 + +#define HSTIM_OFFSET 0x00000058 +#define HSTIM_HS_MODE_MASK 0x00008000 +#define HSTIM_HS_HOLD_SHIFT 10 +#define HSTIM_HS_HIGH_PHASE_SHIFT 5 +#define HSTIM_HS_SETUP_SHIFT 0 + +#define PADCTL_OFFSET 0x0000005c +#define PADCTL_PAD_OUT_EN_MASK 0x00000004 + +#define RXFCR_OFFSET 0x00000068 +#define RXFCR_NACK_EN_SHIFT 7 +#define RXFCR_READ_COUNT_SHIFT 0 +#define RXFIFORDOUT_OFFSET 0x0000006c + +/* Locally used constants */ +#define MAX_RX_FIFO_SIZE 64U /* bytes */ +#define MAX_TX_FIFO_SIZE 64U /* bytes */ + +#define STD_EXT_CLK_FREQ 13000000UL +#define HS_EXT_CLK_FREQ 104000000UL + +#define MASTERCODE 0x08 /* Mastercodes are 0000_1xxxb */ + +#define I2C_TIMEOUT 100 /* msecs */ + +/* Operations that can be commanded to the controller */ +enum bcm_kona_cmd_t { + BCM_CMD_NOACTION = 0, + BCM_CMD_START, + BCM_CMD_RESTART, + BCM_CMD_STOP, +}; + +enum bus_speed_index { + BCM_SPD_100K = 0, + BCM_SPD_400K, + BCM_SPD_1MHZ, +}; + +enum hs_bus_speed_index { + BCM_SPD_3P4MHZ = 0, +}; + +/* Internal divider settings for standard mode, fast mode and fast mode plus */ +struct bus_speed_cfg { + uint8_t time_m; /* Number of cycles for setup time */ + uint8_t time_n; /* Number of cycles for hold time */ + uint8_t prescale; /* Prescale divider */ + uint8_t time_p; /* Timing coefficient */ + uint8_t no_div; /* Disable clock divider */ + uint8_t time_div; /* Post-prescale divider */ +}; + +/* Internal divider settings for high-speed mode */ +struct hs_bus_speed_cfg { + uint8_t hs_hold; /* Number of clock cycles SCL stays low until + the end of bit period */ + uint8_t hs_high_phase; /* Number of clock cycles SCL stays high + before it falls */ + uint8_t hs_setup; /* Number of clock cycles SCL stays low + before it rises */ + uint8_t prescale; /* Prescale divider */ + uint8_t time_p; /* Timing coefficient */ + uint8_t no_div; /* Disable clock divider */ + uint8_t time_div; /* Post-prescale divider */ +}; + +static const struct bus_speed_cfg std_cfg_table[] = { + [BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02}, + [BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02}, + [BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03}, +}; + +static const struct hs_bus_speed_cfg hs_cfg_table[] = { + [BCM_SPD_3P4MHZ] = {0x01, 0x08, 0x14, 0x00, 0x06, 0x01, 0x00}, +}; + +struct bcm_kona_i2c_dev { + struct device *device; + + void __iomem *base; + int irq; + struct clk *external_clk; + + struct i2c_adapter adapter; + + struct completion done; + + const struct bus_speed_cfg *std_cfg; + const struct hs_bus_speed_cfg *hs_cfg; +}; + +static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev, + enum bcm_kona_cmd_t cmd) +{ + dev_dbg(dev->device, "%s, %d\n", __func__, cmd); + + switch (cmd) { + case BCM_CMD_NOACTION: + writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) | + (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), + dev->base + CS_OFFSET); + break; + + case BCM_CMD_START: + writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) | + (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) | + (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), + dev->base + CS_OFFSET); + break; + + case BCM_CMD_RESTART: + writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) | + (CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) | + (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), + dev->base + CS_OFFSET); + break; + + case BCM_CMD_STOP: + writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) | + (CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT), + dev->base + CS_OFFSET); + break; + + default: + dev_err(dev->device, "Unknown command %d\n", cmd); + } +} + +static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev) +{ + writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK, + dev->base + CLKEN_OFFSET); +} + +static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev) +{ + writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK, + dev->base + CLKEN_OFFSET); +} + +static irqreturn_t bcm_kona_i2c_isr(int irq, void *devid) +{ + struct bcm_kona_i2c_dev *dev = devid; + uint32_t status = readl(dev->base + ISR_OFFSET); + + if ((status & ~ISR_RESERVED_MASK) == 0) + return IRQ_NONE; + + /* Must flush the TX FIFO when NAK detected */ + if (status & ISR_NOACK_MASK) + writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK, + dev->base + TXFCR_OFFSET); + + writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET); + complete_all(&dev->done); + + return IRQ_HANDLED; +} + +/* Wait for ISR_CMDBUSY_MASK to go low before writing to CS, DAT, or RCD */ +static int bcm_kona_i2c_wait_if_busy(struct bcm_kona_i2c_dev *dev) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT); + + while (readl(dev->base + ISR_OFFSET) & ISR_CMDBUSY_MASK) + if (time_after(jiffies, timeout)) { + dev_err(dev->device, "CMDBUSY timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +/* Send command to I2C bus */ +static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev, + enum bcm_kona_cmd_t cmd) +{ + int rc; + unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT); + + /* Make sure the hardware is ready */ + rc = bcm_kona_i2c_wait_if_busy(dev); + if (rc < 0) + return rc; + + /* Unmask the session done interrupt */ + writel(IER_I2C_INT_EN_MASK, dev->base + IER_OFFSET); + + /* Mark as incomplete before sending the command */ + INIT_COMPLETION(dev->done); + + /* Send the command */ + bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd); + + /* Wait for transaction to finish or timeout */ + time_left = wait_for_completion_timeout(&dev->done, time_left); + + /* Mask all interrupts */ + writel(0, dev->base + IER_OFFSET); + + if (!time_left) { + dev_err(dev->device, "controller timed out\n"); + rc = -ETIMEDOUT; + } + + /* Clear command */ + bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION); + + return rc; +} + +/* Read a single RX FIFO worth of data from the i2c bus */ +static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev, + uint8_t *buf, unsigned int len, + unsigned int last_byte_nak) +{ + unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT); + + /* Mark as incomplete before starting the RX FIFO */ + INIT_COMPLETION(dev->done); + + /* Unmask the read complete interrupt */ + writel(IER_READ_COMPLETE_INT_MASK, dev->base + IER_OFFSET); + + /* Start the RX FIFO */ + writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) | + (len << RXFCR_READ_COUNT_SHIFT), + dev->base + RXFCR_OFFSET); + + /* Wait for FIFO read to complete */ + time_left = wait_for_completion_timeout(&dev->done, time_left); + + /* Mask all interrupts */ + writel(0, dev->base + IER_OFFSET); + + if (!time_left) { + dev_err(dev->device, "RX FIFO time out\n"); + return -EREMOTEIO; + } + + /* Read data from FIFO */ + for (; len > 0; len--, buf++) + *buf = readl(dev->base + RXFIFORDOUT_OFFSET); + + return 0; +} + +/* Read any amount of data using the RX FIFO from the i2c bus */ +static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev, + struct i2c_msg *msg) +{ + unsigned int bytes_to_read = MAX_RX_FIFO_SIZE; + unsigned int last_byte_nak = 0; + unsigned int bytes_read = 0; + int rc; + + uint8_t *tmp_buf = msg->buf; + + while (bytes_read < msg->len) { + if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) { + last_byte_nak = 1; /* NAK last byte of transfer */ + bytes_to_read = msg->len - bytes_read; + } + + rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read, + last_byte_nak); + if (rc < 0) + return -EREMOTEIO; + + bytes_read += bytes_to_read; + tmp_buf += bytes_to_read; + } + + return 0; +} + +/* Write a single byte of data to the i2c bus */ +static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data, + unsigned int nak_expected) +{ + int rc; + unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT); + unsigned int nak_received; + + /* Make sure the hardware is ready */ + rc = bcm_kona_i2c_wait_if_busy(dev); + if (rc < 0) + return rc; + + /* Clear pending session done interrupt */ + writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET); + + /* Unmask the session done interrupt */ + writel(IER_I2C_INT_EN_MASK, dev->base + IER_OFFSET); + + /* Mark as incomplete before sending the data */ + INIT_COMPLETION(dev->done); + + /* Send one byte of data */ + writel(data, dev->base + DAT_OFFSET); + + /* Wait for byte to be written */ + time_left = wait_for_completion_timeout(&dev->done, time_left); + + /* Mask all interrupts */ + writel(0, dev->base + IER_OFFSET); + + if (!time_left) { + dev_dbg(dev->device, "controller timed out\n"); + return -ETIMEDOUT; + } + + nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0; + + if (nak_received ^ nak_expected) { + dev_dbg(dev->device, "unexpected NAK/ACK\n"); + return -EREMOTEIO; + } + + return 0; +} + +/* Write a single TX FIFO worth of data to the i2c bus */ +static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev, + uint8_t *buf, unsigned int len) +{ + int k; + unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT); + unsigned int fifo_status; + + /* Mark as incomplete before sending data to the TX FIFO */ + INIT_COMPLETION(dev->done); + + /* Unmask the fifo empty and nak interrupt */ + writel(IER_FIFO_INT_EN_MASK | IER_NOACK_EN_MASK, + dev->base + IER_OFFSET); + + /* Disable IRQ to load a FIFO worth of data without interruption */ + disable_irq(dev->irq); + + /* Write data into FIFO */ + for (k = 0; k < len; k++) + writel(buf[k], (dev->base + DAT_OFFSET)); + + /* Enable IRQ now that data has been loaded */ + enable_irq(dev->irq); + + /* Wait for FIFO to empty */ + do { + time_left = wait_for_completion_timeout(&dev->done, time_left); + fifo_status = readl(dev->base + FIFO_STATUS_OFFSET); + } while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK)); + + /* Mask all interrupts */ + writel(0, dev->base + IER_OFFSET); + + /* Check if there was a NAK */ + if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) { + dev_err(dev->device, "unexpected NAK\n"); + return -EREMOTEIO; + } + + /* Check if a timeout occured */ + if (!time_left) { + dev_err(dev->device, "completion timed out\n"); + return -EREMOTEIO; + } + + return 0; +} + + +/* Write any amount of data using TX FIFO to the i2c bus */ +static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev, + struct i2c_msg *msg) +{ + unsigned int bytes_to_write = MAX_TX_FIFO_SIZE; + unsigned int bytes_written = 0; + int rc; + + uint8_t *tmp_buf = msg->buf; + + while (bytes_written < msg->len) { + if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE) + bytes_to_write = msg->len - bytes_written; + + rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf, + bytes_to_write); + if (rc < 0) + return -EREMOTEIO; + + bytes_written += bytes_to_write; + tmp_buf += bytes_to_write; + } + + return 0; +} + +/* Send i2c address */ +static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev, + struct i2c_msg *msg) +{ + unsigned char addr; + + if (msg->flags & I2C_M_TEN) { + /* First byte is 11110XX0 where XX is upper 2 bits */ + addr = 0xF0 | ((msg->addr & 0x300) >> 7); + if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) + return -EREMOTEIO; + + /* Second byte is the remaining 8 bits */ + addr = msg->addr & 0xFF; + if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) + return -EREMOTEIO; + + if (msg->flags & I2C_M_RD) { + /* For read, send restart command */ + if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0) + return -EREMOTEIO; + + /* Then re-send the first byte with the read bit set */ + addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01; + if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) + return -EREMOTEIO; + } + } else { + addr = msg->addr << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) + return -EREMOTEIO; + } + + return 0; +} + +static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev) +{ + writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK, + dev->base + CLKEN_OFFSET); +} + +static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev) +{ + writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK, + dev->base + HSTIM_OFFSET); + + writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) | + (dev->std_cfg->time_p << TIM_P_SHIFT) | + (dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) | + (dev->std_cfg->time_div << TIM_DIV_SHIFT), + dev->base + TIM_OFFSET); + + writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) | + (dev->std_cfg->time_n << CLKEN_N_SHIFT) | + CLKEN_CLKEN_MASK, + dev->base + CLKEN_OFFSET); +} + +static void bcm_kona_i2c_config_timing_hs(struct bcm_kona_i2c_dev *dev) +{ + writel((dev->hs_cfg->prescale << TIM_PRESCALE_SHIFT) | + (dev->hs_cfg->time_p << TIM_P_SHIFT) | + (dev->hs_cfg->no_div << TIM_NO_DIV_SHIFT) | + (dev->hs_cfg->time_div << TIM_DIV_SHIFT), + dev->base + TIM_OFFSET); + + writel((dev->hs_cfg->hs_hold << HSTIM_HS_HOLD_SHIFT) | + (dev->hs_cfg->hs_high_phase << HSTIM_HS_HIGH_PHASE_SHIFT) | + (dev->hs_cfg->hs_setup << HSTIM_HS_SETUP_SHIFT), + dev->base + HSTIM_OFFSET); + + writel(readl(dev->base + HSTIM_OFFSET) | HSTIM_HS_MODE_MASK, + dev->base + HSTIM_OFFSET); +} + +static int bcm_kona_i2c_switch_to_hs(struct bcm_kona_i2c_dev *dev) +{ + int rc; + + /* Send mastercode at standard speed */ + rc = bcm_kona_i2c_write_byte(dev, MASTERCODE, 1); + if (rc < 0) { + pr_err("High speed handshake failed\n"); + return rc; + } + + /* Configure external clock to higher frequency */ + rc = clk_set_rate(dev->external_clk, HS_EXT_CLK_FREQ); + if (rc) { + dev_err(dev->device, "%s: clk_set_rate returned %d\n", + __func__, rc); + return rc; + } + + /* Reconfigure internal dividers */ + bcm_kona_i2c_config_timing_hs(dev); + + /* Send a restart command */ + rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART); + if (rc < 0) + dev_err(dev->device, "High speed restart command failed\n"); + + return rc; +} + +static int bcm_kona_i2c_switch_to_std(struct bcm_kona_i2c_dev *dev) +{ + int rc; + + /* Reconfigure internal dividers */ + bcm_kona_i2c_config_timing(dev); + + /* Configure external clock to lower frequency */ + rc = clk_set_rate(dev->external_clk, STD_EXT_CLK_FREQ); + if (rc) { + dev_err(dev->device, "%s: clk_set_rate returned %d\n", + __func__, rc); + } + + return rc; +} + +/* Master transfer function */ +static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter, + struct i2c_msg msgs[], int num) +{ + struct bcm_kona_i2c_dev *dev = i2c_get_adapdata(adapter); + struct i2c_msg *pmsg; + int rc = 0; + int i; + + rc = clk_prepare_enable(dev->external_clk); + if (rc) { + dev_err(dev->device, "%s: peri clock enable failed. err %d\n", + __func__, rc); + return rc; + } + + /* Enable pad output */ + writel(0, dev->base + PADCTL_OFFSET); + + /* Enable internal clocks */ + bcm_kona_i2c_enable_clock(dev); + + /* Send start command */ + rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START); + if (rc < 0) { + dev_err(dev->device, "Start command failed rc = %d\n", rc); + goto xfer_disable_pad; + } + + /* Switch to high speed if applicable */ + if (dev->hs_cfg) { + rc = bcm_kona_i2c_switch_to_hs(dev); + if (rc < 0) + goto xfer_send_stop; + } + + /* Loop through all messages */ + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + + /* Send restart for subsequent messages */ + if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) { + rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART); + if (rc < 0) { + dev_err(dev->device, + "restart cmd failed rc = %d\n", rc); + goto xfer_send_stop; + } + } + + /* Send slave address */ + if (!(pmsg->flags & I2C_M_NOSTART)) { + rc = bcm_kona_i2c_do_addr(dev, pmsg); + if (rc < 0) { + dev_err(dev->device, + "NAK from addr %2.2x msg#%d rc = %d\n", + pmsg->addr, i, rc); + goto xfer_send_stop; + } + } + + /* Perform data transfer */ + if (pmsg->flags & I2C_M_RD) { + rc = bcm_kona_i2c_read_fifo(dev, pmsg); + if (rc < 0) { + dev_err(dev->device, "read failure\n"); + goto xfer_send_stop; + } + } else { + rc = bcm_kona_i2c_write_fifo(dev, pmsg); + if (rc < 0) { + dev_err(dev->device, "write failure"); + goto xfer_send_stop; + } + } + } + + rc = num; + +xfer_send_stop: + /* Send a STOP command */ + bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP); + + /* Return from high speed if applicable */ + if (dev->hs_cfg) { + int hs_rc = bcm_kona_i2c_switch_to_std(dev); + + if (hs_rc) + rc = hs_rc; + } + +xfer_disable_pad: + /* Disable pad output */ + writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET); + + /* Stop internal clock */ + bcm_kona_i2c_disable_clock(dev); + + clk_disable_unprepare(dev->external_clk); + + return rc; +} + +static uint32_t bcm_kona_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm bcm_algo = { + .master_xfer = bcm_kona_i2c_xfer, + .functionality = bcm_kona_i2c_functionality, +}; + +static int bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev) +{ + unsigned int bus_speed; + int ret = of_property_read_u32(dev->device->of_node, "clock-frequency", + &bus_speed); + if (ret < 0) { + dev_err(dev->device, "missing clock-frequency property\n"); + return -ENODEV; + } + + switch (bus_speed) { + case 100000: + dev->std_cfg = &std_cfg_table[BCM_SPD_100K]; + break; + case 400000: + dev->std_cfg = &std_cfg_table[BCM_SPD_400K]; + break; + case 1000000: + dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ]; + break; + case 3400000: + /* Send mastercode at 100k */ + dev->std_cfg = &std_cfg_table[BCM_SPD_100K]; + dev->hs_cfg = &hs_cfg_table[BCM_SPD_3P4MHZ]; + break; + default: + pr_err("%d hz bus speed not supported\n", bus_speed); + pr_err("Valid speeds are 100khz, 400khz, 1mhz, and 3.4mhz\n"); + return -EINVAL; + } + + return 0; +} + +static int bcm_kona_i2c_probe(struct platform_device *pdev) +{ + int rc = 0; + struct bcm_kona_i2c_dev *dev; + struct i2c_adapter *adap; + struct resource *iomem; + + /* Allocate memory for private data structure */ + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + platform_set_drvdata(pdev, dev); + dev->device = &pdev->dev; + init_completion(&dev->done); + + /* Map hardware registers */ + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(dev->device, iomem); + if (IS_ERR(dev->base)) + return -ENOMEM; + + /* Get and enable external clock */ + dev->external_clk = devm_clk_get(dev->device, NULL); + if (IS_ERR(dev->external_clk)) { + dev_err(dev->device, "couldn't get clock\n"); + return -ENODEV; + } + + rc = clk_set_rate(dev->external_clk, STD_EXT_CLK_FREQ); + if (rc) { + dev_err(dev->device, "%s: clk_set_rate returned %d\n", + __func__, rc); + return rc; + } + + rc = clk_prepare_enable(dev->external_clk); + if (rc) { + dev_err(dev->device, "couldn't enable clock\n"); + return rc; + } + + /* Parse bus speed */ + if (bcm_kona_i2c_assign_bus_speed(dev)) + goto probe_disable_clk; + + /* Enable internal clocks */ + bcm_kona_i2c_enable_clock(dev); + + /* Configure internal dividers */ + bcm_kona_i2c_config_timing(dev); + + /* Disable timeout */ + writel(0, dev->base + TOUT_OFFSET); + + /* Enable autosense */ + bcm_kona_i2c_enable_autosense(dev); + + /* Enable TX FIFO */ + writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK, + dev->base + TXFCR_OFFSET); + + /* Mask all interrupts */ + writel(0, dev->base + IER_OFFSET); + + /* Clear all pending interrupts */ + writel(ISR_CMDBUSY_MASK | + ISR_READ_COMPLETE_MASK | + ISR_SES_DONE_MASK | + ISR_ERR_MASK | + ISR_TXFIFOEMPTY_MASK | + ISR_NOACK_MASK, + dev->base + ISR_OFFSET); + + /* Get the interrupt number */ + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq < 0) { + dev_err(dev->device, "no irq resource\n"); + rc = -ENODEV; + goto probe_disable_clk; + } + + /* register the ISR handler */ + rc = devm_request_irq(&pdev->dev, dev->irq, bcm_kona_i2c_isr, + IRQF_SHARED, pdev->name, dev); + if (rc) { + dev_err(dev->device, "failed to request irq %i\n", dev->irq); + goto probe_disable_clk; + } + + /* Enable the controller but leave it idle */ + bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION); + + /* Disable pad output */ + writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET); + + /* Disable internal clock */ + bcm_kona_i2c_disable_clock(dev); + + /* Disable external clock */ + clk_disable_unprepare(dev->external_clk); + + /* Add the i2c adapter */ + adap = &dev->adapter; + i2c_set_adapdata(adap, dev); + adap->owner = THIS_MODULE; + strlcpy(adap->name, "Broadcom I2C adapter", sizeof(adap->name)); + adap->algo = &bcm_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + rc = i2c_add_adapter(adap); + if (rc) { + dev_err(dev->device, "failed to add adapter\n"); + return rc; + } + + dev_info(dev->device, "device registered successfully\n"); + + return 0; + +probe_disable_clk: + bcm_kona_i2c_disable_clock(dev); + clk_disable_unprepare(dev->external_clk); + + return rc; +} + +static int bcm_kona_i2c_remove(struct platform_device *pdev) +{ + struct bcm_kona_i2c_dev *dev = platform_get_drvdata(pdev); + + i2c_del_adapter(&dev->adapter); + + return 0; +} + +static const struct of_device_id bcm_kona_i2c_of_match[] = { + {.compatible = "brcm,kona-i2c",}, + {}, +}; +MODULE_DEVICE_TABLE(of, kona_i2c_of_match); + +static struct platform_driver bcm_kona_i2c_driver = { + .driver = { + .name = "bcm-kona-i2c", + .owner = THIS_MODULE, + .of_match_table = bcm_kona_i2c_of_match, + }, + .probe = bcm_kona_i2c_probe, + .remove = bcm_kona_i2c_remove, +}; +module_platform_driver(bcm_kona_i2c_driver); + +MODULE_AUTHOR("Tim Kryger "); +MODULE_DESCRIPTION("Broadcom Kona I2C Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 5e47eec00425830bfaf30f80a1a4f603dc60ae93 Mon Sep 17 00:00:00 2001 From: Andreas Werner Date: Sun, 17 Nov 2013 18:46:20 +0100 Subject: i2c: i2c-eg20t: do not print error message in syslog if no ACK received Using the i2c-eg20t driver and call i2cdetect or probe on the bus, the driver will print a lot of error messages if there was no ACK received. i2cdetect normally print a table with all the available devices. If there is no device on the address, the table will be empty. Currently with the i2c-eg20t driver, the table is not visible because the error messages destroy the table. Error message: pch_i2c_getack return -71 This patch prevent the driver to print the messages to syslog. The pch_i2c_wait_for_check_xfer function is the only one who is calling pch_i2c_getack, so we can delete the function and add the read to pch_i2c_wait_for_check_xfer. If no ACK is received, the Message will be printed as a dbg message. Fixed print message to be a one liner so we can grep for the error message. Tested on Intel Atom E6xx and Eg20t Chipset. Signed-off-by: Andreas Werner Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 0f37529..ff15ae9 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -312,24 +312,6 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap) } /** - * pch_i2c_getack() - to confirm ACK/NACK - * @adap: Pointer to struct i2c_algo_pch_data. - */ -static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap) -{ - u32 reg_val; - void __iomem *p = adap->pch_base_address; - reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK; - - if (reg_val != 0) { - pch_err(adap, "return%d\n", -EPROTO); - return -EPROTO; - } - - return 0; -} - -/** * pch_i2c_stop() - generate stop condition in normal mode. * @adap: Pointer to struct i2c_algo_pch_data. */ @@ -344,6 +326,7 @@ static void pch_i2c_stop(struct i2c_algo_pch_data *adap) static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap) { long ret; + void __iomem *p = adap->pch_base_address; ret = wait_event_timeout(pch_event, (adap->pch_event_flag != 0), msecs_to_jiffies(1000)); @@ -366,10 +349,9 @@ static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap) adap->pch_event_flag = 0; - if (pch_i2c_getack(adap)) { - pch_dbg(adap, "Receive NACK for slave address" - "setting\n"); - return -EIO; + if (ioread32(p + PCH_I2CSR) & PCH_GETACK) { + pch_dbg(adap, "Receive NACK for slave address setting\n"); + return -ENXIO; } return 0; -- cgit v0.10.2 From cfff1f4a9367bfe0d88413e8807f8369e9564729 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 18 Nov 2013 21:03:08 +0800 Subject: i2c: bcm-kona: fix error return code in bcm_kona_i2c_probe() Fix to return a negative error code from the bus speed parse error handling case instead of 0. Signed-off-by: Wei Yongjun Reviewed-by: Tim Kryger Signed-off-by: Wolfram Sang diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index 7b7b762..eb1ce6e 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -792,7 +792,8 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) } /* Parse bus speed */ - if (bcm_kona_i2c_assign_bus_speed(dev)) + rc = bcm_kona_i2c_assign_bus_speed(dev); + if (rc) goto probe_disable_clk; /* Enable internal clocks */ -- cgit v0.10.2