Merge branch 'driver-core-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / arm / mach-shmobile / board-mackerel.c
index 448ddbe..7e1d375 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/pm_runtime.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
  * ------+--------------------+--------------------+-------
  * IRQ0  | ICR1A.IRQ0SA=0010  | SDHI2 card detect  | Low
  * IRQ6  | ICR1A.IRQ6SA=0011  | Ether(LAN9220)     | High
- * IRQ7  | ICR1A.IRQ7SA=0010  | LCD Tuch Panel     | Low
+ * IRQ7  | ICR1A.IRQ7SA=0010  | LCD Touch Panel    | Low
  * IRQ8  | ICR2A.IRQ8SA=0010  | MMC/SD card detect | Low
  * IRQ9  | ICR2A.IRQ9SA=0010  | KEY(TCA6408)       | Low
  * IRQ21 | ICR4A.IRQ21SA=0011 | Sensor(ADXL345)    | High
  * USB1 can become Host by r8a66597, and become Function by renesas_usbhs.
  * But don't select both drivers in same time.
  * These uses same IRQ number for request_irq(), and aren't supporting
- * IRQF_SHARD / IORESOURCE_IRQ_SHAREABLE.
+ * IRQF_SHARED / IORESOURCE_IRQ_SHAREABLE.
  *
  * Actually these are old/new version of USB driver.
- * This mean its register will be broken if it supports SHARD IRQ,
+ * This mean its register will be broken if it supports shared IRQ,
  */
 
 /*
@@ -314,6 +315,30 @@ static struct platform_device smc911x_device = {
        },
 };
 
+/* MERAM */
+static struct sh_mobile_meram_info mackerel_meram_info = {
+       .addr_mode      = SH_MOBILE_MERAM_MODE1,
+};
+
+static struct resource meram_resources[] = {
+       [0] = {
+               .name   = "MERAM",
+               .start  = 0xe8000000,
+               .end    = 0xe81fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device meram_device = {
+       .name           = "sh_mobile_meram",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(meram_resources),
+       .resource       = meram_resources,
+       .dev            = {
+               .platform_data = &mackerel_meram_info,
+       },
+};
+
 /* LCDC */
 static struct fb_videomode mackerel_lcdc_modes[] = {
        {
@@ -342,7 +367,23 @@ static int mackerel_get_brightness(void *board_data)
        return gpio_get_value(GPIO_PORT31);
 }
 
+static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 28,
+               .cache_icb      = 24,
+               .meram_offset   = 0x0,
+               .meram_size     = 0x40,
+       },
+       .icb[1] = {
+               .marker_icb     = 29,
+               .cache_icb      = 25,
+               .meram_offset   = 0x40,
+               .meram_size     = 0x40,
+       },
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -362,6 +403,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                        .name = "sh_mobile_lcdc_bl",
                        .max_brightness = 1,
                },
+               .meram_cfg = &lcd_meram_cfg,
        }
 };
 
@@ -388,8 +430,23 @@ static struct platform_device lcdc_device = {
        },
 };
 
+static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 30,
+               .cache_icb      = 26,
+               .meram_offset   = 0x80,
+               .meram_size     = 0x100,
+       },
+       .icb[1] = {
+               .marker_icb     = 31,
+               .cache_icb      = 27,
+               .meram_offset   = 0x180,
+               .meram_size     = 0x100,
+       },
+};
 /* HDMI */
 static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -397,6 +454,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
+               .meram_cfg = &hdmi_meram_cfg,
        }
 };
 
@@ -504,7 +562,121 @@ out:
                clk_put(hdmi_ick);
 }
 
-/* USB1 (Host) */
+/* USBHS0 is connected to CN22 which takes a USB Mini-B plug
+ *
+ * The sh7372 SoC has IRQ7 set aside for USBHS0 hotplug,
+ * but on this particular board IRQ7 is already used by
+ * the touch screen. This leaves us with software polling.
+ */
+#define USBHS0_POLL_INTERVAL (HZ * 5)
+
+struct usbhs_private {
+       unsigned int usbphyaddr;
+       unsigned int usbcrcaddr;
+       struct renesas_usbhs_platform_info info;
+       struct delayed_work work;
+       struct platform_device *pdev;
+};
+
+#define usbhs_get_priv(pdev)                           \
+       container_of(renesas_usbhs_get_info(pdev),      \
+                    struct usbhs_private, info)
+
+#define usbhs_is_connected(priv)                       \
+       (!((1 << 7) & __raw_readw(priv->usbcrcaddr)))
+
+static int usbhs_get_vbus(struct platform_device *pdev)
+{
+       return usbhs_is_connected(usbhs_get_priv(pdev));
+}
+
+static void usbhs_phy_reset(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* init phy */
+       __raw_writew(0x8a0a, priv->usbcrcaddr);
+}
+
+static int usbhs0_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static void usbhs0_work_function(struct work_struct *work)
+{
+       struct usbhs_private *priv = container_of(work, struct usbhs_private,
+                                                 work.work);
+
+       renesas_usbhs_call_notify_hotplug(priv->pdev);
+       schedule_delayed_work(&priv->work, USBHS0_POLL_INTERVAL);
+}
+
+static int usbhs0_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       priv->pdev = pdev;
+       INIT_DELAYED_WORK(&priv->work, usbhs0_work_function);
+       schedule_delayed_work(&priv->work, USBHS0_POLL_INTERVAL);
+       return 0;
+}
+
+static void usbhs0_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       cancel_delayed_work_sync(&priv->work);
+}
+
+static struct usbhs_private usbhs0_private = {
+       .usbcrcaddr     = 0xe605810c,           /* USBCR2 */
+       .info = {
+               .platform_callback = {
+                       .hardware_init  = usbhs0_hardware_init,
+                       .hardware_exit  = usbhs0_hardware_exit,
+                       .phy_reset      = usbhs_phy_reset,
+                       .get_id         = usbhs0_get_id,
+                       .get_vbus       = usbhs_get_vbus,
+               },
+               .driver_param = {
+                       .buswait_bwait  = 4,
+               },
+       },
+};
+
+static struct resource usbhs0_resources[] = {
+       [0] = {
+               .name   = "USBHS0",
+               .start  = 0xe6890000,
+               .end    = 0xe68900e6 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1ca0) /* USB0_USB0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs0_device = {
+       .name   = "renesas_usbhs",
+       .id     = 0,
+       .dev = {
+               .platform_data          = &usbhs0_private.info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs0_resources),
+       .resource       = usbhs0_resources,
+};
+
+/* USBHS1 is connected to CN31 which takes a USB Mini-AB plug
+ *
+ * Use J30 to select between Host and Function. This setting
+ * can however not be detected by software. Hotplug of USBHS1
+ * is provided via IRQ8.
+ */
+#define IRQ8 evt2irq(0x0300)
+
+/* USBHS1 USB Host support via r8a66597_hcd */
 static void usb1_host_port_power(int port, int power)
 {
        if (!power) /* only power-on is supported for now */
@@ -521,9 +693,9 @@ static struct r8a66597_platdata usb1_host_data = {
 
 static struct resource usb1_host_resources[] = {
        [0] = {
-               .name   = "USBHS",
-               .start  = 0xE68B0000,
-               .end    = 0xE68B00E6 - 1,
+               .name   = "USBHS1",
+               .start  = 0xe68b0000,
+               .end    = 0xe68b00e6 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -544,37 +716,14 @@ static struct platform_device usb1_host_device = {
        .resource       = usb1_host_resources,
 };
 
-/* USB1 (Function) */
+/* USBHS1 USB Function support via renesas_usbhs */
+
 #define USB_PHY_MODE           (1 << 4)
 #define USB_PHY_INT_EN         ((1 << 3) | (1 << 2))
 #define USB_PHY_ON             (1 << 1)
 #define USB_PHY_OFF            (1 << 0)
 #define USB_PHY_INT_CLR                (USB_PHY_ON | USB_PHY_OFF)
 
-struct usbhs_private {
-       unsigned int irq;
-       unsigned int usbphyaddr;
-       unsigned int usbcrcaddr;
-       struct renesas_usbhs_platform_info info;
-};
-
-#define usbhs_get_priv(pdev)                           \
-       container_of(renesas_usbhs_get_info(pdev),      \
-                    struct usbhs_private, info)
-
-#define usbhs_is_connected(priv)                       \
-       (!((1 << 7) & __raw_readw(priv->usbcrcaddr)))
-
-static int usbhs1_get_id(struct platform_device *pdev)
-{
-       return USBHS_GADGET;
-}
-
-static int usbhs1_get_vbus(struct platform_device *pdev)
-{
-       return usbhs_is_connected(usbhs_get_priv(pdev));
-}
-
 static irqreturn_t usbhs1_interrupt(int irq, void *data)
 {
        struct platform_device *pdev = data;
@@ -596,12 +745,10 @@ static int usbhs1_hardware_init(struct platform_device *pdev)
        struct usbhs_private *priv = usbhs_get_priv(pdev);
        int ret;
 
-       irq_set_irq_type(priv->irq, IRQ_TYPE_LEVEL_HIGH);
-
        /* clear interrupt status */
        __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
 
-       ret = request_irq(priv->irq, usbhs1_interrupt, 0,
+       ret = request_irq(IRQ8, usbhs1_interrupt, IRQF_TRIGGER_HIGH,
                          dev_name(&pdev->dev), pdev);
        if (ret) {
                dev_err(&pdev->dev, "request_irq err\n");
@@ -621,15 +768,12 @@ static void usbhs1_hardware_exit(struct platform_device *pdev)
        /* clear interrupt status */
        __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
 
-       free_irq(priv->irq, pdev);
+       free_irq(IRQ8, pdev);
 }
 
-static void usbhs1_phy_reset(struct platform_device *pdev)
+static int usbhs1_get_id(struct platform_device *pdev)
 {
-       struct usbhs_private *priv = usbhs_get_priv(pdev);
-
-       /* init phy */
-       __raw_writew(0x8a0a, priv->usbcrcaddr);
+       return USBHS_GADGET;
 }
 
 static u32 usbhs1_pipe_cfg[] = {
@@ -652,16 +796,15 @@ static u32 usbhs1_pipe_cfg[] = {
 };
 
 static struct usbhs_private usbhs1_private = {
-       .irq            = evt2irq(0x0300),      /* IRQ8 */
-       .usbphyaddr     = 0xE60581E2,           /* USBPHY1INTAP */
-       .usbcrcaddr     = 0xE6058130,           /* USBCR4 */
+       .usbphyaddr     = 0xe60581e2,           /* USBPHY1INTAP */
+       .usbcrcaddr     = 0xe6058130,           /* USBCR4 */
        .info = {
                .platform_callback = {
                        .hardware_init  = usbhs1_hardware_init,
                        .hardware_exit  = usbhs1_hardware_exit,
-                       .phy_reset      = usbhs1_phy_reset,
                        .get_id         = usbhs1_get_id,
-                       .get_vbus       = usbhs1_get_vbus,
+                       .phy_reset      = usbhs_phy_reset,
+                       .get_vbus       = usbhs_get_vbus,
                },
                .driver_param = {
                        .buswait_bwait  = 4,
@@ -673,9 +816,9 @@ static struct usbhs_private usbhs1_private = {
 
 static struct resource usbhs1_resources[] = {
        [0] = {
-               .name   = "USBHS",
-               .start  = 0xE68B0000,
-               .end    = 0xE68B00E6 - 1,
+               .name   = "USBHS1",
+               .start  = 0xe68b0000,
+               .end    = 0xe68b00e6 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -694,7 +837,6 @@ static struct platform_device usbhs1_device = {
        .resource       = usbhs1_resources,
 };
 
-
 /* LED */
 static struct gpio_led mackerel_leds[] = {
        {
@@ -856,6 +998,17 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 }
 
 /* SDHI0 */
+static irqreturn_t mackerel_sdhi0_gpio_cd(int irq, void *arg)
+{
+       struct device *dev = arg;
+       struct sh_mobile_sdhi_info *info = dev->platform_data;
+       struct tmio_mmc_data *pdata = info->pdata;
+
+       tmio_mmc_cd_wakeup(pdata);
+
+       return IRQ_HANDLED;
+}
+
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
        .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
@@ -1134,6 +1287,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &nor_flash_device,
        &smc911x_device,
        &lcdc_device,
+       &usbhs0_device,
        &usb1_host_device,
        &usbhs1_device,
        &leds_device,
@@ -1150,6 +1304,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &mackerel_camera,
        &hdmi_lcdc_device,
        &hdmi_device,
+       &meram_device,
 };
 
 /* Keypad Initialization */
@@ -1231,6 +1386,7 @@ static void __init mackerel_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define GPIO_PORT167CR 0xE60520A7
 #define GPIO_PORT168CR 0xE60520A8
 #define SRCR4          0xe61580bc
 #define USCCR1         0xE6058144
@@ -1238,6 +1394,7 @@ static void __init mackerel_init(void)
 {
        u32 srcr4;
        struct clk *clk;
+       int ret;
 
        sh7372_pinmux_init();
 
@@ -1283,17 +1440,17 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_PORT151, NULL); /* LCDDON */
        gpio_direction_output(GPIO_PORT151, 1);
 
-       /* USB enable */
-       gpio_request(GPIO_FN_VBUS0_1,    NULL);
-       gpio_request(GPIO_FN_IDIN_1_18,  NULL);
-       gpio_request(GPIO_FN_PWEN_1_115, NULL);
-       gpio_request(GPIO_FN_OVCN_1_114, NULL);
-       gpio_request(GPIO_FN_EXTLP_1,    NULL);
-       gpio_request(GPIO_FN_OVCN2_1,    NULL);
-       gpio_pull_down(GPIO_PORT168CR);
+       /* USBHS0 */
+       gpio_request(GPIO_FN_VBUS0_0, NULL);
+       gpio_pull_down(GPIO_PORT168CR); /* VBUS0_0 pull down */
 
-       /* setup USB phy */
-       __raw_writew(0x8a0a, 0xE6058130);       /* USBCR4 */
+       /* USBHS1 */
+       gpio_request(GPIO_FN_VBUS0_1, NULL);
+       gpio_pull_down(GPIO_PORT167CR); /* VBUS0_1 pull down */
+       gpio_request(GPIO_FN_IDIN_1_113, NULL);
+
+       /* USB phy tweak to make the r8a66597_hcd host driver work */
+       __raw_writew(0x8a0a, 0xe6058130);       /* USBCR4 */
 
        /* enable FSI2 port A (ak4643) */
        gpio_request(GPIO_FN_FSIAIBT,   NULL);
@@ -1343,6 +1500,13 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_SDHID0_1, NULL);
        gpio_request(GPIO_FN_SDHID0_0, NULL);
 
+       ret = request_irq(evt2irq(0x3340), mackerel_sdhi0_gpio_cd,
+                         IRQF_TRIGGER_FALLING, "sdhi0 cd", &sdhi0_device.dev);
+       if (!ret)
+               sdhi0_info.tmio_flags |= TMIO_MMC_HAS_COLD_CD;
+       else
+               pr_err("Cannot get IRQ #%d: %d\n", evt2irq(0x3340), ret);
+
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        /* enable SDHI1 */
        gpio_request(GPIO_FN_SDHICMD1, NULL);