From f14cf2fb8d30f9dad2e532a4e3f1ed4ca82fbc3b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 20 Apr 2012 17:08:02 +0200 Subject: devicetree: bindings: gpio-i2c belongs to i2c not gpio gpio-i2c describes an I2C controller (using gpios for data and clock), so it must be described in i2c, not gpio. Signed-off-by: Wolfram Sang Acked-by: Rob Herring --- .../devicetree/bindings/gpio/gpio_i2c.txt | 32 ---------------------- Documentation/devicetree/bindings/i2c/gpio-i2c.txt | 32 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio_i2c.txt create mode 100644 Documentation/devicetree/bindings/i2c/gpio-i2c.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt b/Documentation/devicetree/bindings/gpio/gpio_i2c.txt deleted file mode 100644 index 4f8ec947c6bd..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio_i2c.txt +++ /dev/null @@ -1,32 +0,0 @@ -Device-Tree bindings for i2c gpio driver - -Required properties: - - compatible = "i2c-gpio"; - - gpios: sda and scl gpio - - -Optional properties: - - i2c-gpio,sda-open-drain: sda as open drain - - i2c-gpio,scl-open-drain: scl as open drain - - i2c-gpio,scl-output-only: scl as output only - - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) - - i2c-gpio,timeout-ms: timeout to get data - -Example nodes: - -i2c@0 { - compatible = "i2c-gpio"; - gpios = <&pioA 23 0 /* sda */ - &pioA 24 0 /* scl */ - >; - i2c-gpio,sda-open-drain; - i2c-gpio,scl-open-drain; - i2c-gpio,delay-us = <2>; /* ~100 kHz */ - #address-cells = <1>; - #size-cells = <0>; - - rv3029c2@56 { - compatible = "rv3029c2"; - reg = <0x56>; - }; -}; diff --git a/Documentation/devicetree/bindings/i2c/gpio-i2c.txt b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt new file mode 100644 index 000000000000..4f8ec947c6bd --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/gpio-i2c.txt @@ -0,0 +1,32 @@ +Device-Tree bindings for i2c gpio driver + +Required properties: + - compatible = "i2c-gpio"; + - gpios: sda and scl gpio + + +Optional properties: + - i2c-gpio,sda-open-drain: sda as open drain + - i2c-gpio,scl-open-drain: scl as open drain + - i2c-gpio,scl-output-only: scl as output only + - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) + - i2c-gpio,timeout-ms: timeout to get data + +Example nodes: + +i2c@0 { + compatible = "i2c-gpio"; + gpios = <&pioA 23 0 /* sda */ + &pioA 24 0 /* scl */ + >; + i2c-gpio,sda-open-drain; + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + + rv3029c2@56 { + compatible = "rv3029c2"; + reg = <0x56>; + }; +}; -- cgit v1.2.3-59-g8ed1b From cd4f2d4aa79ccbb2713f33f9c9f24ed21b5fc8fa Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 9 Jul 2012 18:22:53 +0200 Subject: i2c: mxs: Set I2C timing registers for mxs-i2c This patch configures the I2C bus timing registers according to information passed via DT. Currently, 100kHz and 400kHz modes are supported. The TIMING2 register value is wrong in the documentation for i.MX28! This was found and fixed by: Shawn Guo Signed-off-by: Marek Vasut Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mxs.txt | 3 ++ arch/arm/boot/dts/imx28.dtsi | 2 + drivers/i2c/busses/i2c-mxs.c | 66 +++++++++++++++++++++++ 3 files changed, 71 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt index 1bfc02de1b0c..30ac3a0557f7 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt @@ -4,6 +4,8 @@ Required properties: - compatible: Should be "fsl,-i2c" - reg: Should contain registers location and length - interrupts: Should contain ERROR and DMA interrupts +- clock-frequency: Desired I2C bus clock frequency in Hz. + Only 100000Hz and 400000Hz modes are supported. Examples: @@ -13,4 +15,5 @@ i2c0: i2c@80058000 { compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; }; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 4634cb861a59..9af1606b5d3c 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -381,6 +381,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x80058000 2000>; interrupts = <111 68>; + clock-frequency = <100000>; status = "disabled"; }; @@ -390,6 +391,7 @@ compatible = "fsl,imx28-i2c"; reg = <0x8005a000 2000>; interrupts = <110 69>; + clock-frequency = <100000>; status = "disabled"; }; diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 02ce1faeeeef..088c5c1ed17d 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -46,6 +46,10 @@ #define MXS_I2C_CTRL0_DIRECTION 0x00010000 #define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF) +#define MXS_I2C_TIMING0 (0x10) +#define MXS_I2C_TIMING1 (0x20) +#define MXS_I2C_TIMING2 (0x30) + #define MXS_I2C_CTRL1 (0x40) #define MXS_I2C_CTRL1_SET (0x44) #define MXS_I2C_CTRL1_CLR (0x48) @@ -97,6 +101,35 @@ #define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ MXS_I2C_CTRL0_MASTER_MODE) +struct mxs_i2c_speed_config { + uint32_t timing0; + uint32_t timing1; + uint32_t timing2; +}; + +/* + * Timing values for the default 24MHz clock supplied into the i2c block. + * + * The bus can operate at 95kHz or at 400kHz with the following timing + * register configurations. The 100kHz mode isn't present because it's + * values are not stated in the i.MX233/i.MX28 datasheet. The 95kHz mode + * shall be close enough replacement. Therefore when the bus is configured + * for 100kHz operation, 95kHz timing settings are actually loaded. + * + * For details, see i.MX233 [25.4.2 - 25.4.4] and i.MX28 [27.5.2 - 27.5.4]. + */ +static const struct mxs_i2c_speed_config mxs_i2c_95kHz_config = { + .timing0 = 0x00780030, + .timing1 = 0x00800030, + .timing2 = 0x00300030, +}; + +static const struct mxs_i2c_speed_config mxs_i2c_400kHz_config = { + .timing0 = 0x000f0007, + .timing1 = 0x001f000f, + .timing2 = 0x00300030, +}; + /** * struct mxs_i2c_dev - per device, private MXS-I2C data * @@ -112,11 +145,17 @@ struct mxs_i2c_dev { struct completion cmd_complete; u32 cmd_err; struct i2c_adapter adapter; + const struct mxs_i2c_speed_config *speed; }; static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) { stmp_reset_block(i2c->regs); + + writel(i2c->speed->timing0, i2c->regs + MXS_I2C_TIMING0); + writel(i2c->speed->timing1, i2c->regs + MXS_I2C_TIMING1); + writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2); + writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, i2c->regs + MXS_I2C_QUEUECTRL_SET); @@ -319,6 +358,28 @@ static const struct i2c_algorithm mxs_i2c_algo = { .functionality = mxs_i2c_func, }; +static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c) +{ + uint32_t speed; + struct device *dev = i2c->dev; + struct device_node *node = dev->of_node; + int ret; + + if (!node) + return -EINVAL; + + i2c->speed = &mxs_i2c_95kHz_config; + ret = of_property_read_u32(node, "clock-frequency", &speed); + if (ret) + dev_warn(dev, "No I2C speed selected, using 100kHz\n"); + else if (speed == 400000) + i2c->speed = &mxs_i2c_400kHz_config; + else if (speed != 100000) + dev_warn(dev, "Unsupported I2C speed selected, using 100kHz\n"); + + return 0; +} + static int __devinit mxs_i2c_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -358,6 +419,11 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) return err; i2c->dev = dev; + + err = mxs_i2c_get_ofdata(i2c); + if (err) + return err; + platform_set_drvdata(pdev, i2c); /* Do reset to enforce correct startup after pinmuxing */ -- cgit v1.2.3-59-g8ed1b From 9ae97a8996a6d6f66e2fbc221906e2406d6c261f Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 13 Jul 2012 19:14:22 +0530 Subject: i2c: i2c-ocores: DT bindings and minor fixes. Cleanups to i2c-cores, no change in logic, changes are: * Move i2c-ocores device tree documentation from source file to Documentation/devicetree/bindings/i2c/i2c-ocores.txt. * Add \n to dev_warn and dev_err messages where missing * Minor updates to the text and formatting fixes. Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 27 +++++++++++++ drivers/i2c/busses/i2c-ocores.c | 45 ++++------------------ 2 files changed, 34 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ocores.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt new file mode 100644 index 000000000000..bfec8941509c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -0,0 +1,27 @@ +Device tree configuration for i2c-ocores + +Required properties: +- compatible : "opencores,i2c-ocores" +- reg : bus address start and address range size of device +- interrupts : interrupt number +- regstep : size of device registers in bytes +- clock-frequency : frequency of bus clock in Hz +- #address-cells : should be <1> +- #size-cells : should be <0> + +Example: + + i2c0: ocores@a0000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "opencores,i2c-ocores"; + reg = <0xa0000000 0x8>; + interrupts = <10>; + regstep = <1>; + clock-frequency = <20000000>; + + dummy@60 { + compatible = "dummy"; + reg = <0x60>; + }; + }; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index d7d21d532557..f6e7ad9f60e9 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -10,40 +10,9 @@ */ /* - * Device tree configuration: - * - * Required properties: - * - compatible : "opencores,i2c-ocores" - * - reg : bus address start and address range size of device - * - interrupts : interrupt number - * - regstep : size of device registers in bytes - * - clock-frequency : frequency of bus clock in Hz - * - * Example: - * - * i2c0: ocores@a0000000 { - * compatible = "opencores,i2c-ocores"; - * reg = <0xa0000000 0x8>; - * interrupts = <10>; - * - * regstep = <1>; - * clock-frequency = <20000000>; - * - * -- Devices connected on this I2C bus get - * -- defined here; address- and size-cells - * -- apply to these child devices - * - * #address-cells = <1>; - * #size-cells = <0>; - * - * dummy@60 { - * compatible = "dummy"; - * reg = <60>; - * }; - * }; - * + * This driver can be used from the device tree, see + * Documentation/devicetree/bindings/i2c/ocore-i2c.txt */ - #include #include #include @@ -247,14 +216,14 @@ static struct i2c_adapter ocores_adapter = { }; #ifdef CONFIG_OF -static int ocores_i2c_of_probe(struct platform_device* pdev, - struct ocores_i2c* i2c) +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) { const __be32* val; val = of_get_property(pdev->dev.of_node, "regstep", NULL); if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'"); + dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); return -ENODEV; } i2c->regstep = be32_to_cpup(val); @@ -262,7 +231,7 @@ static int ocores_i2c_of_probe(struct platform_device* pdev, val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); if (!val) { dev_err(&pdev->dev, - "Missing required parameter 'clock-frequency'"); + "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } i2c->clock_khz = be32_to_cpup(val) / 1000; @@ -351,7 +320,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return 0; } -static int __devexit ocores_i2c_remove(struct platform_device* pdev) +static int __devexit ocores_i2c_remove(struct platform_device *pdev) { struct ocores_i2c *i2c = platform_get_drvdata(pdev); -- cgit v1.2.3-59-g8ed1b From 8bb986a816148d6e8fbaae23be0fee33d6a1ae3f Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:23 +0530 Subject: i2c: i2c-ocores: Use reg-shift property Deprecate 'regstep' property and use the standard 'reg-shift' property for register offset shifts. 'regstep' will still be supported as an optional property, but will give a warning when used. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 8 +++-- drivers/i2c/busses/i2c-ocores.c | 36 +++++++++++++--------- include/linux/i2c-ocores.h | 2 +- 3 files changed, 29 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index bfec8941509c..1c9334bfc39c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -4,11 +4,14 @@ Required properties: - compatible : "opencores,i2c-ocores" - reg : bus address start and address range size of device - interrupts : interrupt number -- regstep : size of device registers in bytes - clock-frequency : frequency of bus clock in Hz - #address-cells : should be <1> - #size-cells : should be <0> +Optional properties: +- reg-shift : device register offsets are shifted by this value +- regstep : deprecated, use reg-shift above + Example: i2c0: ocores@a0000000 { @@ -17,9 +20,10 @@ Example: compatible = "opencores,i2c-ocores"; reg = <0xa0000000 0x8>; interrupts = <10>; - regstep = <1>; clock-frequency = <20000000>; + reg-shift = <0>; /* 8 bit registers */ + dummy@60 { compatible = "dummy"; reg = <0x60>; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index f6e7ad9f60e9..9e0709d5fb36 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -25,10 +25,11 @@ #include #include #include +#include struct ocores_i2c { void __iomem *base; - int regstep; + u32 reg_shift; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -71,12 +72,12 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + reg * i2c->regstep); + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + reg * i2c->regstep); + return ioread8(i2c->base + (reg << i2c->reg_shift)); } static void ocores_process(struct ocores_i2c *i2c) @@ -219,22 +220,29 @@ static struct i2c_adapter ocores_adapter = { static int ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c) { - const __be32* val; - - val = of_get_property(pdev->dev.of_node, "regstep", NULL); - if (!val) { - dev_err(&pdev->dev, "Missing required parameter 'regstep'\n"); - return -ENODEV; + struct device_node *np = pdev->dev.of_node; + u32 val; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } } - i2c->regstep = be32_to_cpup(val); - val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); - if (!val) { + if (of_property_read_u32(np, "clock-frequency", &val)) { dev_err(&pdev->dev, "Missing required parameter 'clock-frequency'\n"); return -ENODEV; } - i2c->clock_khz = be32_to_cpup(val) / 1000; + i2c->clock_khz = val / 1000; return 0; } @@ -277,7 +285,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { - i2c->regstep = pdata->regstep; + i2c->reg_shift = pdata->reg_shift; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 4d5e57ff6614..5d95df2436f4 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -12,7 +12,7 @@ #define _LINUX_I2C_OCORES_H struct ocores_i2c_platform_data { - u32 regstep; /* distance between registers */ + u32 reg_shift; /* register offset shift value */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3-59-g8ed1b From 7326e38ffe894d0cd2904704b7d8c53d4a55d752 Mon Sep 17 00:00:00 2001 From: Ganesan Ramalingam Date: Fri, 13 Jul 2012 19:14:25 +0530 Subject: i2c: i2c-ocores: support for 16bit and 32bit IO Some architectures supports only 16-bit or 32-bit read/write access to their IO space. Add a 'reg-io-width' platform and OF parameter which specifies the IO width to support these platforms. reg-io-width can be specified as 1, 2 or 4, and has a default value of 1 if it is unspecified. Signed-off-by: Ganesan Ramalingam Signed-off-by: Jayachandran C Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-ocores.txt | 2 ++ drivers/i2c/busses/i2c-ocores.c | 21 +++++++++++++++++++-- include/linux/i2c-ocores.h | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index 1c9334bfc39c..c15781f4dc8c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -10,6 +10,7 @@ Required properties: Optional properties: - reg-shift : device register offsets are shifted by this value +- reg-io-width : io register width in bytes (1, 2 or 4) - regstep : deprecated, use reg-shift above Example: @@ -23,6 +24,7 @@ Example: clock-frequency = <20000000>; reg-shift = <0>; /* 8 bit registers */ + reg-io-width = <1>; /* 8 bit read/write */ dummy@60 { compatible = "dummy"; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 9e0709d5fb36..bffd5501ac2d 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -30,6 +30,7 @@ struct ocores_i2c { void __iomem *base; u32 reg_shift; + u32 reg_io_width; wait_queue_head_t wait; struct i2c_adapter adap; struct i2c_msg *msg; @@ -72,12 +73,22 @@ struct ocores_i2c { static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); + if (i2c->reg_io_width == 4) + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); + else if (i2c->reg_io_width == 2) + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); + else + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); } static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) { - return ioread8(i2c->base + (reg << i2c->reg_shift)); + if (i2c->reg_io_width == 4) + return ioread32(i2c->base + (reg << i2c->reg_shift)); + else if (i2c->reg_io_width == 2) + return ioread16(i2c->base + (reg << i2c->reg_shift)); + else + return ioread8(i2c->base + (reg << i2c->reg_shift)); } static void ocores_process(struct ocores_i2c *i2c) @@ -244,6 +255,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, } i2c->clock_khz = val / 1000; + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); return 0; } #else @@ -286,6 +299,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata) { i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; i2c->clock_khz = pdata->clock_khz; } else { ret = ocores_i2c_of_probe(pdev, i2c); @@ -293,6 +307,9 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return ret; } + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + ocores_init(i2c); init_waitqueue_head(&i2c->wait); diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h index 5d95df2436f4..1c06b5c7c308 100644 --- a/include/linux/i2c-ocores.h +++ b/include/linux/i2c-ocores.h @@ -13,6 +13,7 @@ struct ocores_i2c_platform_data { u32 reg_shift; /* register offset shift value */ + u32 reg_io_width; /* register io read/write width */ u32 clock_khz; /* input clock in kHz */ u8 num_devices; /* number of devices in the devices list */ struct i2c_board_info const *devices; /* devices connected to the bus */ -- cgit v1.2.3-59-g8ed1b From b61d15758941166b9cac41b87751dea21978bebc Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 22 Jul 2012 12:51:35 +0200 Subject: I2C: MV64XYZ: Add Device Tree support Extends the driver to get properties from device tree. Rather than pass the N & M factors in DT, use the more standard clock-frequency property. Calculate N & M at run time. In order to do this, we need to know tclk. So the driver uses clk_get() etc in order to get the clock and clk_get_rate() to determine the tclk rate. Not all platforms however have CLK, so some #ifdefery is needed to ensure the driver still compiles when CLK is not available. Signed-off-by: Andrew Lunn [wsa: converted some ints to u32 to match signedness] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/mrvl-i2c.txt | 19 ++- drivers/i2c/busses/i2c-mv64xxx.c | 133 ++++++++++++++++++++- 2 files changed, 146 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt index b891ee218354..0f7945019f6f 100644 --- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt @@ -1,4 +1,4 @@ -* I2C +* Marvell MMP I2C controller Required properties : @@ -32,3 +32,20 @@ Examples: interrupts = <58>; }; +* Marvell MV64XXX I2C controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : Should be "marvell,mv64xxx-i2c" + - interrupts : The interrupt number + - clock-frequency : Desired I2C bus clock frequency in Hz. + +Examples: + + i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + }; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6e70eea0cd2f..2e9d56719e99 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include /* Register defines */ #define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 @@ -98,6 +103,9 @@ struct mv64xxx_i2c_data { int rc; u32 freq_m; u32 freq_n; +#if defined(CONFIG_HAVE_CLK) + struct clk *clk; +#endif wait_queue_head_t waitq; spinlock_t lock; struct i2c_msg *msg; @@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base_p = 0; } +#ifdef CONFIG_OF +static int __devinit +mv64xxx_calc_freq(const int tclk, const int n, const int m) +{ + return tclk / (10 * (m + 1) * (2 << n)); +} + +static bool __devinit +mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, + u32 *best_m) +{ + int freq, delta, best_delta = INT_MAX; + int m, n; + + for (n = 0; n <= 7; n++) + for (m = 0; m <= 15; m++) { + freq = mv64xxx_calc_freq(tclk, n, m); + delta = req_freq - freq; + if (delta >= 0 && delta < best_delta) { + *best_m = m; + *best_n = n; + best_delta = delta; + } + if (best_delta == 0) + return true; + } + if (best_delta == INT_MAX) + return false; + return true; +} + +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + u32 bus_freq, tclk; + int rc = 0; + + /* CLK is mandatory when using DT to describe the i2c bus. We + * need to know tclk in order to calculate bus clock + * factors. + */ +#if !defined(CONFIG_HAVE_CLK) + /* Have OF but no CLK */ + return -ENODEV; +#else + if (IS_ERR(drv_data->clk)) { + rc = -ENODEV; + goto out; + } + tclk = clk_get_rate(drv_data->clk); + of_property_read_u32(np, "clock-frequency", &bus_freq); + if (!mv64xxx_find_baud_factors(bus_freq, tclk, + &drv_data->freq_n, &drv_data->freq_m)) { + rc = -EINVAL; + goto out; + } + drv_data->irq = irq_of_parse_and_map(np, 0); + + /* Its not yet defined how timeouts will be specified in device tree. + * So hard code the value to 1 second. + */ + drv_data->adapter.timeout = HZ; +out: + return rc; +#endif +} +#else /* CONFIG_OF */ +static int __devinit +mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, + struct device_node *np) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ + static int __devinit mv64xxx_i2c_probe(struct platform_device *pd) { @@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; int rc; - if (!pdata) + if ((!pdata && !pd->dev.of_node)) return -ENODEV; drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); @@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd) init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); - drv_data->freq_m = pdata->freq_m; - drv_data->freq_n = pdata->freq_n; - drv_data->irq = platform_get_irq(pd, 0); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + drv_data->clk = clk_get(&pd->dev, NULL); + if (!IS_ERR(drv_data->clk)) { + clk_prepare(drv_data->clk); + clk_enable(drv_data->clk); + } +#endif + if (pdata) { + drv_data->freq_m = pdata->freq_m; + drv_data->freq_n = pdata->freq_n; + drv_data->irq = platform_get_irq(pd, 0); + drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); + } else if (pd->dev.of_node) { + rc = mv64xxx_of_config(drv_data, pd->dev.of_node); + if (rc) + goto exit_unmap_regs; + } if (drv_data->irq < 0) { rc = -ENXIO; goto exit_unmap_regs; } + drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); drv_data->adapter.nr = pd->id; + drv_data->adapter.dev.of_node = pd->dev.of_node; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); @@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) goto exit_free_irq; } + of_i2c_register_devices(&drv_data->adapter); + return 0; exit_free_irq: free_irq(drv_data->irq, drv_data); exit_unmap_regs: +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif mv64xxx_i2c_unmap_regs(drv_data); exit_kfree: kfree(drv_data); @@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev) rc = i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); mv64xxx_i2c_unmap_regs(drv_data); +#if defined(CONFIG_HAVE_CLK) + /* Not all platforms have a clk */ + if (!IS_ERR(drv_data->clk)) { + clk_disable(drv_data->clk); + clk_unprepare(drv_data->clk); + } +#endif kfree(drv_data); return rc; } +static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = { + { .compatible = "marvell,mv64xxx-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); + static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, .remove = __devexit_p(mv64xxx_i2c_remove), .driver = { .owner = THIS_MODULE, .name = MV64XXX_I2C_CTLR_NAME, + .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table), }, }; -- cgit v1.2.3-59-g8ed1b