i2c: OMAP: Add DT support for i2c controller
authorBenoit Cousson <b-cousson@ti.com>
Thu, 22 Dec 2011 14:56:36 +0000 (15:56 +0100)
committerBen Dooks <ben-linux@fluff.org>
Tue, 17 Jan 2012 22:44:57 +0000 (22:44 +0000)
Add initial DT support to retrieve the frequency using a
DT attribute instead of the pdata pointer if of_node exist.

Add documentation for omap i2c controller binding.

Based on original patches from Manju and Grant.

Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Reviewed-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Documentation/devicetree/bindings/i2c/omap-i2c.txt [new file with mode: 0644]
drivers/i2c/busses/i2c-omap.c

diff --git a/Documentation/devicetree/bindings/i2c/omap-i2c.txt b/Documentation/devicetree/bindings/i2c/omap-i2c.txt
new file mode 100644 (file)
index 0000000..56564aa
--- /dev/null
@@ -0,0 +1,30 @@
+I2C for OMAP platforms
+
+Required properties :
+- compatible : Must be "ti,omap3-i2c" or "ti,omap4-i2c"
+- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Recommended properties :
+- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise
+  the default 100 kHz frequency will be used.
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Note: Current implementation will fetch base address, irq and dma
+from omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples :
+
+i2c1: i2c@0 {
+    compatible = "ti,omap3-i2c";
+    #address-cells = <1>;
+    #size-cells = <0>;
+    ti,hwmods = "i2c1";
+    clock-frequency = <400000>;
+};
index e0733b7760798da9e76baa7215128259a25e24ff..f713eac550470cdac3139952e4229b639c05f798 100644 (file)
@@ -37,6 +37,9 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
@@ -182,7 +185,9 @@ struct omap_i2c_dev {
        u32                     latency;        /* maximum mpu wkup latency */
        void                    (*set_mpu_wkup_lat)(struct device *dev,
                                                    long latency);
-       u32                     speed;          /* Speed of bus in Khz */
+       u32                     speed;          /* Speed of bus in kHz */
+       u32                     dtrev;          /* extra revision from DT */
+       u32                     flags;
        u16                     cmd_err;
        u8                      *buf;
        u8                      *regs;
@@ -266,11 +271,7 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
 
 static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 {
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
-
-       if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
                omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
                omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
                omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
@@ -291,13 +292,10 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
 
 static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
-       struct omap_i2c_bus_platform_data *pdata;
        u16 iv;
 
-       pdata = dev->dev->platform_data;
-
        dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
-       if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
                omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
        else
                omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
@@ -320,9 +318,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        unsigned long timeout;
        unsigned long internal_clk = 0;
        struct clk *fclk;
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
 
        if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
                /* Disable I2C controller before soft reset */
@@ -373,7 +368,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
        }
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 
-       if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
+       if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
                /*
                 * The I2C functional clock is the armxor_ck, so there's
                 * no need to get "armxor_ck" separately.  Now, if OMAP2420
@@ -397,7 +392,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        psc = fclk_rate / 12000000;
        }
 
-       if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
+       if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
 
                /*
                 * HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -406,7 +401,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                 * The filter is iclk (fclk for HS) period.
                 */
                if (dev->speed > 400 ||
-                              pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
+                              dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
                        internal_clk = 19200;
                else if (dev->speed > 100)
                        internal_clk = 9600;
@@ -475,7 +470,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
 
        dev->errata = 0;
 
-       if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
                dev->errata |= I2C_OMAP_ERRATA_I207;
 
        /* Enable interrupts */
@@ -484,7 +479,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
                                (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-       if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
                dev->pscstate = psc;
                dev->scllstate = scll;
                dev->sclhstate = sclh;
@@ -804,9 +799,6 @@ omap_i2c_isr(int this_irq, void *dev_id)
        u16 bits;
        u16 stat, w;
        int err, count = 0;
-       struct omap_i2c_bus_platform_data *pdata;
-
-       pdata = dev->dev->platform_data;
 
        if (pm_runtime_suspended(dev->dev))
                return IRQ_NONE;
@@ -873,7 +865,7 @@ complete:
                                         * Data reg in 2430, omap3 and
                                         * omap4 is 8 bit wide
                                         */
-                                       if (pdata->flags &
+                                       if (dev->flags &
                                                 OMAP_I2C_FLAG_16BIT_DATA_REG) {
                                                if (dev->buf_len) {
                                                        *dev->buf++ = w >> 8;
@@ -916,7 +908,7 @@ complete:
                                         * Data reg in 2430, omap3 and
                                         * omap4 is 8 bit wide
                                         */
-                                       if (pdata->flags &
+                                       if (dev->flags &
                                                 OMAP_I2C_FLAG_16BIT_DATA_REG) {
                                                if (dev->buf_len) {
                                                        w |= *dev->buf++ << 8;
@@ -963,6 +955,32 @@ static const struct i2c_algorithm omap_i2c_algo = {
        .functionality  = omap_i2c_func,
 };
 
+#ifdef CONFIG_OF
+static struct omap_i2c_bus_platform_data omap3_pdata = {
+       .rev = OMAP_I2C_IP_VERSION_1,
+       .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+                OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+                OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_i2c_bus_platform_data omap4_pdata = {
+       .rev = OMAP_I2C_IP_VERSION_2,
+};
+
+static const struct of_device_id omap_i2c_of_match[] = {
+       {
+               .compatible = "ti,omap4-i2c",
+               .data = &omap4_pdata,
+       },
+       {
+               .compatible = "ti,omap3-i2c",
+               .data = &omap3_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
+#endif
+
 static int __devinit
 omap_i2c_probe(struct platform_device *pdev)
 {
@@ -970,9 +988,10 @@ omap_i2c_probe(struct platform_device *pdev)
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
        struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node      *node = pdev->dev.of_node;
+       const struct of_device_id *match;
        irq_handler_t isr;
        int r;
-       u32 speed = 0;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -999,15 +1018,24 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_release_region;
        }
 
-       if (pdata != NULL) {
-               speed = pdata->clkrate;
+       match = of_match_device(omap_i2c_of_match, &pdev->dev);
+       if (match) {
+               u32 freq = 100000; /* default to 100000 Hz */
+
+               pdata = match->data;
+               dev->dtrev = pdata->rev;
+               dev->flags = pdata->flags;
+
+               of_property_read_u32(node, "clock-frequency", &freq);
+               /* convert DT freq value in Hz into kHz for speed */
+               dev->speed = freq / 1000;
+       } else if (pdata != NULL) {
+               dev->speed = pdata->clkrate;
+               dev->flags = pdata->flags;
                dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
-       } else {
-               speed = 100;    /* Default speed */
-               dev->set_mpu_wkup_lat = NULL;
+               dev->dtrev = pdata->rev;
        }
 
-       dev->speed = speed;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
        dev->base = ioremap(mem->start, resource_size(mem));
@@ -1018,9 +1046,9 @@ omap_i2c_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
 
-       dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
+       dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
 
-       if (pdata->rev == OMAP_I2C_IP_VERSION_2)
+       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
                dev->regs = (u8 *)reg_map_ip_v2;
        else
                dev->regs = (u8 *)reg_map_ip_v1;
@@ -1033,7 +1061,7 @@ omap_i2c_probe(struct platform_device *pdev)
        if (dev->rev <= OMAP_I2C_REV_ON_3430)
                dev->errata |= I2C_OMAP3_1P153;
 
-       if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) {
+       if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
                u16 s;
 
                /* Set up the fifo size - Get total size */
@@ -1056,7 +1084,7 @@ omap_i2c_probe(struct platform_device *pdev)
                /* calculate wakeup latency constraint for MPU */
                if (dev->set_mpu_wkup_lat != NULL)
                        dev->latency = (1000000 * dev->fifo_size) /
-                                      (1000 * speed / 8);
+                                      (1000 * dev->speed / 8);
        }
 
        /* reset ASAP, clearing any IRQs */
@@ -1072,7 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
 
        dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
-                pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
 
        pm_runtime_put(dev->dev);
 
@@ -1083,6 +1111,7 @@ omap_i2c_probe(struct platform_device *pdev)
        strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
        adap->algo = &omap_i2c_algo;
        adap->dev.parent = &pdev->dev;
+       adap->dev.of_node = pdev->dev.of_node;
 
        /* i2c device drivers may be active on return from add_adapter() */
        adap->nr = pdev->id;
@@ -1092,6 +1121,8 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_free_irq;
        }
 
+       of_i2c_register_devices(adap);
+
        return 0;
 
 err_free_irq:
@@ -1164,6 +1195,7 @@ static struct platform_driver omap_i2c_driver = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
                .pm     = OMAP_I2C_PM_OPS,
+               .of_match_table = of_match_ptr(omap_i2c_of_match),
        },
 };