Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra...
[cascardo/linux.git] / arch / arm / mach-shmobile / setup-r8a7740.c
index 5548518..986dca6 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
@@ -33,7 +35,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(100)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c00)),
 };
 
 static struct platform_device scif0_device = {
@@ -51,7 +53,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(101)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c20)),
 };
 
 static struct platform_device scif1_device = {
@@ -69,7 +71,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(102)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c40)),
 };
 
 static struct platform_device scif2_device = {
@@ -87,7 +89,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(103)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0c60)),
 };
 
 static struct platform_device scif3_device = {
@@ -105,7 +107,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(104)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d20)),
 };
 
 static struct platform_device scif4_device = {
@@ -123,7 +125,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(105)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d40)),
 };
 
 static struct platform_device scif5_device = {
@@ -141,7 +143,7 @@ static struct plat_sci_port scif6_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(106)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x04c0)),
 };
 
 static struct platform_device scif6_device = {
@@ -159,7 +161,7 @@ static struct plat_sci_port scif7_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFA,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(107)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x04e0)),
 };
 
 static struct platform_device scif7_device = {
@@ -177,7 +179,7 @@ static struct plat_sci_port scifb_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIFB,
-       .irqs           = SCIx_IRQ_MUXED(gic_spi(108)),
+       .irqs           = SCIx_IRQ_MUXED(evt2irq(0x0d60)),
 };
 
 static struct platform_device scifb_device = {
@@ -205,7 +207,7 @@ static struct resource cmt10_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = gic_spi(58),
+               .start  = evt2irq(0x0b00),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -233,10 +235,114 @@ static struct platform_device *r8a7740_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+/* I2C */
+static struct resource i2c0_resources[] = {
+       [0] = {
+               .name   = "IIC0",
+               .start  = 0xfff20000,
+               .end    = 0xfff20425 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0xe00),
+               .end    = intcs_evt2irq(0xe60),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource i2c1_resources[] = {
+       [0] = {
+               .name   = "IIC1",
+               .start  = 0xe6c20000,
+               .end    = 0xe6c20425 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x780), /* IIC1_ALI1 */
+               .end    = evt2irq(0x7e0), /* IIC1_DTEI1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device i2c0_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 0,
+       .resource       = i2c0_resources,
+       .num_resources  = ARRAY_SIZE(i2c0_resources),
+};
+
+static struct platform_device i2c1_device = {
+       .name           = "i2c-sh_mobile",
+       .id             = 1,
+       .resource       = i2c1_resources,
+       .num_resources  = ARRAY_SIZE(i2c1_resources),
+};
+
+static struct platform_device *r8a7740_late_devices[] __initdata = {
+       &i2c0_device,
+       &i2c1_device,
+};
+
+#define ICCR   0x0004
+#define ICSTART        0x0070
+
+#define i2c_read(reg, offset)          ioread8(reg + offset)
+#define i2c_write(reg, offset, data)   iowrite8(data, reg + offset)
+
+/*
+ * r8a7740 chip has lasting errata on I2C I/O pad reset.
+ * this is work-around for it.
+ */
+static void r8a7740_i2c_workaround(struct platform_device *pdev)
+{
+       struct resource *res;
+       void __iomem *reg;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               pr_err("r8a7740 i2c workaround fail (cannot find resource)\n");
+               return;
+       }
+
+       reg = ioremap(res->start, resource_size(res));
+       if (unlikely(!reg)) {
+               pr_err("r8a7740 i2c workaround fail (cannot map IO)\n");
+               return;
+       }
+
+       i2c_write(reg, ICCR, i2c_read(reg, ICCR) | 0x80);
+       i2c_read(reg, ICCR); /* dummy read */
+
+       i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
+       i2c_read(reg, ICSTART); /* dummy read */
+
+       mdelay(100);
+
+       i2c_write(reg, ICCR, 0x01);
+       i2c_read(reg, ICCR);
+       i2c_write(reg, ICSTART, 0x00);
+       i2c_read(reg, ICSTART);
+
+       i2c_write(reg, ICCR, 0x10);
+       mdelay(100);
+       i2c_write(reg, ICCR, 0x00);
+       mdelay(100);
+       i2c_write(reg, ICCR, 0x10);
+       mdelay(100);
+
+       iounmap(reg);
+}
+
 void __init r8a7740_add_standard_devices(void)
 {
+       /* I2C work-around */
+       r8a7740_i2c_workaround(&i2c0_device);
+       r8a7740_i2c_workaround(&i2c1_device);
+
        platform_add_devices(r8a7740_early_devices,
                            ARRAY_SIZE(r8a7740_early_devices));
+       platform_add_devices(r8a7740_late_devices,
+                            ARRAY_SIZE(r8a7740_late_devices));
 }
 
 void __init r8a7740_add_early_devices(void)