Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[~shefty/rdma-dev.git] / arch / arm / mach-shmobile / board-ap4evb.c
index 22a2b44ddb7bf14218d70db85ea732938fa09d54..46ca4d4abf910aad98652306a7d41bfa7ccdcfe8 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/usb/r8a66597.h>
 
+#include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+
 #include <sound/sh_fsi.h>
 
 #include <video/sh_mobile_hdmi.h>
@@ -250,7 +253,7 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 /* SH_MMCIF */
 static struct resource sh_mmcif_resources[] = {
        [0] = {
-               .name   = "SH_MMCIF",
+               .name   = "MMCIF",
                .start  = 0xE6BD0000,
                .end    = 0xE6BD00FF,
                .flags  = IORESOURCE_MEM,
@@ -390,10 +393,40 @@ static struct platform_device usb1_host_device = {
        .resource       = usb1_host_resources,
 };
 
+const static struct fb_videomode ap4evb_lcdc_modes[] = {
+       {
+#ifdef CONFIG_AP4EVB_QHD
+               .name           = "R63302(QHD)",
+               .xres           = 544,
+               .yres           = 961,
+               .left_margin    = 72,
+               .right_margin   = 600,
+               .hsync_len      = 16,
+               .upper_margin   = 8,
+               .lower_margin   = 8,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+#else
+               .name           = "WVGA Panel",
+               .xres           = 800,
+               .yres           = 480,
+               .left_margin    = 220,
+               .right_margin   = 110,
+               .hsync_len      = 70,
+               .upper_margin   = 20,
+               .lower_margin   = 5,
+               .vsync_len      = 5,
+               .sync           = 0,
+#endif
+       },
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
                .bpp = 16,
+               .lcd_cfg = ap4evb_lcdc_modes,
+               .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
        }
 };
 
@@ -532,27 +565,6 @@ static struct platform_device *qhd_devices[] __initdata = {
 
 /* FSI */
 #define IRQ_FSI                evt2irq(0x1840)
-#define FSIACKCR       0xE6150018
-static void fsiackcr_init(struct clk *clk)
-{
-       u32 status = __raw_readl(clk->enable_reg);
-
-       /* use external clock */
-       status &= ~0x000000ff;
-       status |= 0x00000080;
-       __raw_writel(status, clk->enable_reg);
-}
-
-static struct clk_ops fsiackcr_clk_ops = {
-       .init = fsiackcr_init,
-};
-
-static struct clk fsiackcr_clk = {
-       .ops            = &fsiackcr_clk_ops,
-       .enable_reg     = (void __iomem *)FSIACKCR,
-       .rate           = 0, /* unknown */
-};
-
 static struct sh_fsi_platform_info fsi_info = {
        .porta_flags = SH_FSI_BRS_INV |
                       SH_FSI_OUT_SLAVE_MODE |
@@ -592,26 +604,6 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
-               .lcd_cfg = {
-                       .name = "HDMI",
-                       /* So far only 720p is supported */
-                       .xres = 1280,
-                       .yres = 720,
-                       /*
-                        * If left and right margins are not multiples of 8,
-                        * LDHAJR will be adjusted accordingly by the LCDC
-                        * driver. Until we start using EDID, these values
-                        * might have to be adjusted for different monitors.
-                        */
-                       .left_margin = 200,
-                       .right_margin = 88,
-                       .hsync_len = 48,
-                       .upper_margin = 20,
-                       .lower_margin = 5,
-                       .vsync_len = 5,
-                       .pixclock = 13468,
-                       .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
-               },
        }
 };
 
@@ -623,7 +615,7 @@ static struct resource lcdc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = intcs_evt2irq(0x17a0),
+               .start  = intcs_evt2irq(0x1780),
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -704,6 +696,95 @@ static struct platform_device leds_device = {
        },
 };
 
+static struct i2c_board_info imx074_info = {
+       I2C_BOARD_INFO("imx074", 0x1a),
+};
+
+struct soc_camera_link imx074_link = {
+       .bus_id         = 0,
+       .board_info     = &imx074_info,
+       .i2c_adapter_id = 0,
+       .module_name    = "imx074",
+};
+
+static struct platform_device ap4evb_camera = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &imx074_link,
+       },
+};
+
+static struct sh_csi2_client_config csi2_clients[] = {
+       {
+               .phy            = SH_CSI2_PHY_MAIN,
+               .lanes          = 3,
+               .channel        = 0,
+               .pdev           = &ap4evb_camera,
+       },
+};
+
+static struct sh_csi2_pdata csi2_info = {
+       .type           = SH_CSI2C,
+       .clients        = csi2_clients,
+       .num_clients    = ARRAY_SIZE(csi2_clients),
+       .flags          = SH_CSI2_ECC | SH_CSI2_CRC,
+};
+
+static struct resource csi2_resources[] = {
+       [0] = {
+               .name   = "CSI2",
+               .start  = 0xffc90000,
+               .end    = 0xffc90fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x17a0),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device csi2_device = {
+       .name   = "sh-mobile-csi2",
+       .id     = 0,
+       .num_resources  = ARRAY_SIZE(csi2_resources),
+       .resource       = csi2_resources,
+       .dev    = {
+               .platform_data = &csi2_info,
+       },
+};
+
+static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+       .flags = SH_CEU_FLAG_USE_8BIT_BUS,
+       .csi2_dev = &csi2_device.dev,
+};
+
+static struct resource ceu_resources[] = {
+       [0] = {
+               .name   = "CEU",
+               .start  = 0xfe910000,
+               .end    = 0xfe91009f,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x880),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               /* place holder for contiguous memory */
+       },
+};
+
+static struct platform_device ceu_device = {
+       .name           = "sh_mobile_ceu",
+       .id             = 0, /* "ceu0" clock */
+       .num_resources  = ARRAY_SIZE(ceu_resources),
+       .resource       = ceu_resources,
+       .dev    = {
+               .platform_data  = &sh_mobile_ceu_info,
+       },
+};
+
 static struct platform_device *ap4evb_devices[] __initdata = {
        &leds_device,
        &nor_flash_device,
@@ -716,6 +797,9 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &lcdc1_device,
        &lcdc_device,
        &hdmi_device,
+       &csi2_device,
+       &ceu_device,
+       &ap4evb_camera,
 };
 
 static int __init hdmi_init_pm_clock(void)
@@ -730,22 +814,22 @@ static int __init hdmi_init_pm_clock(void)
                goto out;
        }
 
-       ret = clk_set_parent(&pllc2_clk, &dv_clki_div2_clk);
+       ret = clk_set_parent(&sh7372_pllc2_clk, &sh7372_dv_clki_div2_clk);
        if (ret < 0) {
-               pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, pllc2_clk.usecount);
+               pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, sh7372_pllc2_clk.usecount);
                goto out;
        }
 
-       pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&pllc2_clk));
+       pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&sh7372_pllc2_clk));
 
-       rate = clk_round_rate(&pllc2_clk, 594000000);
+       rate = clk_round_rate(&sh7372_pllc2_clk, 594000000);
        if (rate < 0) {
                pr_err("Cannot get suitable rate: %ld\n", rate);
                ret = rate;
                goto out;
        }
 
-       ret = clk_set_rate(&pllc2_clk, rate);
+       ret = clk_set_rate(&sh7372_pllc2_clk, rate);
        if (ret < 0) {
                pr_err("Cannot set rate %ld: %d\n", rate, ret);
                goto out;
@@ -753,7 +837,7 @@ static int __init hdmi_init_pm_clock(void)
 
        pr_debug("PLLC2 set frequency %lu\n", rate);
 
-       ret = clk_set_parent(hdmi_ick, &pllc2_clk);
+       ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
        if (ret < 0) {
                pr_err("Cannot set HDMI parent: %d\n", ret);
                goto out;
@@ -767,11 +851,51 @@ out:
 
 device_initcall(hdmi_init_pm_clock);
 
+#define FSIACK_DUMMY_RATE 48000
+static int __init fsi_init_pm_clock(void)
+{
+       struct clk *fsia_ick;
+       int ret;
+
+       /*
+        * FSIACK is connected to AK4642,
+        * and the rate is depend on playing sound rate.
+        * So, set dummy rate (= 48k) here
+        */
+       ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE);
+       if (ret < 0) {
+               pr_err("Cannot set FSIACK dummy rate: %d\n", ret);
+               return ret;
+       }
+
+       fsia_ick = clk_get(&fsi_device.dev, "icka");
+       if (IS_ERR(fsia_ick)) {
+               ret = PTR_ERR(fsia_ick);
+               pr_err("Cannot get FSI ICK: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk);
+       if (ret < 0) {
+               pr_err("Cannot set FSI-A parent: %d\n", ret);
+               goto out;
+       }
+
+       ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE);
+       if (ret < 0)
+               pr_err("Cannot set FSI-A rate: %d\n", ret);
+
+out:
+       clk_put(fsia_ick);
+
+       return ret;
+}
+device_initcall(fsi_init_pm_clock);
+
 /*
  * FIXME !!
  *
  * gpio_no_direction
- * gpio_pull_up
  * are quick_hack.
  *
  * current gpio frame work doesn't have
@@ -783,49 +907,37 @@ static void __init gpio_no_direction(u32 addr)
        __raw_writeb(0x00, addr);
 }
 
-static void __init gpio_pull_up(u32 addr)
-{
-       u8 data = __raw_readb(addr);
-
-       data &= 0x0F;
-       data |= 0xC0;
-       __raw_writeb(data, addr);
-}
-
 /* TouchScreen */
+#ifdef CONFIG_AP4EVB_QHD
+# define GPIO_TSC_IRQ  GPIO_FN_IRQ28_123
+# define GPIO_TSC_PORT GPIO_PORT123
+#else /* WVGA */
+# define GPIO_TSC_IRQ  GPIO_FN_IRQ7_40
+# define GPIO_TSC_PORT GPIO_PORT40
+#endif
+
 #define IRQ28  evt2irq(0x3380) /* IRQ28A */
 #define IRQ7   evt2irq(0x02e0) /* IRQ7A */
 static int ts_get_pendown_state(void)
 {
-       int val1, val2;
+       int val;
 
-       gpio_free(GPIO_FN_IRQ28_123);
-       gpio_free(GPIO_FN_IRQ7_40);
+       gpio_free(GPIO_TSC_IRQ);
 
-       gpio_request(GPIO_PORT123, NULL);
-       gpio_request(GPIO_PORT40, NULL);
+       gpio_request(GPIO_TSC_PORT, NULL);
 
-       gpio_direction_input(GPIO_PORT123);
-       gpio_direction_input(GPIO_PORT40);
+       gpio_direction_input(GPIO_TSC_PORT);
 
-       val1 = gpio_get_value(GPIO_PORT123);
-       val2 = gpio_get_value(GPIO_PORT40);
+       val = gpio_get_value(GPIO_TSC_PORT);
 
-       gpio_request(GPIO_FN_IRQ28_123, NULL);  /* for QHD */
-       gpio_request(GPIO_FN_IRQ7_40, NULL);    /* for WVGA */
+       gpio_request(GPIO_TSC_IRQ, NULL);
 
-       return val1 ^ val2;
+       return !val;
 }
 
-#define PORT40CR       0xE6051028
-#define PORT123CR      0xE605007B
 static int ts_init(void)
 {
-       gpio_request(GPIO_FN_IRQ28_123, NULL);  /* for QHD */
-       gpio_request(GPIO_FN_IRQ7_40, NULL);    /* for WVGA */
-
-       gpio_pull_up(PORT40CR);
-       gpio_pull_up(PORT123CR);
+       gpio_request(GPIO_TSC_IRQ, NULL);
 
        return 0;
 }
@@ -974,14 +1086,6 @@ static void __init ap4evb_init(void)
                clk_put(clk);
        }
 
-       /* change parent of FSI A */
-       clk = clk_get(NULL, "fsia_clk");
-       if (!IS_ERR(clk)) {
-               clk_register(&fsiackcr_clk);
-               clk_set_parent(clk, &fsiackcr_clk);
-               clk_put(clk);
-       }
-
        /*
         * set irq priority, to avoid sound chopping
         * when NFS rootfs is used
@@ -996,8 +1100,10 @@ static void __init ap4evb_init(void)
                                ARRAY_SIZE(i2c1_devices));
 
 #ifdef CONFIG_AP4EVB_QHD
+
        /*
-        * QHD
+        * For QHD Panel (MIPI-DSI, CONFIG_AP4EVB_QHD=y) and
+        * IRQ28 for Touch Panel, set dip switches S3, S43 as OFF, ON.
         */
 
        /* enable KEYSC */
@@ -1023,17 +1129,6 @@ static void __init ap4evb_init(void)
        lcdc_info.ch[0].interface_type          = RGB24;
        lcdc_info.ch[0].clock_divider           = 1;
        lcdc_info.ch[0].flags                   = LCDC_FLAGS_DWPOL;
-       lcdc_info.ch[0].lcd_cfg.name            = "R63302(QHD)";
-       lcdc_info.ch[0].lcd_cfg.xres            = 544;
-       lcdc_info.ch[0].lcd_cfg.yres            = 961;
-       lcdc_info.ch[0].lcd_cfg.left_margin     = 72;
-       lcdc_info.ch[0].lcd_cfg.right_margin    = 600;
-       lcdc_info.ch[0].lcd_cfg.hsync_len       = 16;
-       lcdc_info.ch[0].lcd_cfg.upper_margin    = 8;
-       lcdc_info.ch[0].lcd_cfg.lower_margin    = 8;
-       lcdc_info.ch[0].lcd_cfg.vsync_len       = 2;
-       lcdc_info.ch[0].lcd_cfg.sync            = FB_SYNC_VERT_HIGH_ACT |
-                                                 FB_SYNC_HOR_HIGH_ACT;
        lcdc_info.ch[0].lcd_size_cfg.width      = 44;
        lcdc_info.ch[0].lcd_size_cfg.height     = 79;
 
@@ -1041,8 +1136,10 @@ static void __init ap4evb_init(void)
 
 #else
        /*
-        * WVGA
+        * For WVGA Panel (18-bit RGB, CONFIG_AP4EVB_WVGA=y) and
+        * IRQ7 for Touch Panel, set dip switches S3, S43 to ON, OFF.
         */
+
        gpio_request(GPIO_FN_LCDD17,   NULL);
        gpio_request(GPIO_FN_LCDD16,   NULL);
        gpio_request(GPIO_FN_LCDD15,   NULL);
@@ -1074,16 +1171,6 @@ static void __init ap4evb_init(void)
        lcdc_info.ch[0].interface_type          = RGB18;
        lcdc_info.ch[0].clock_divider           = 2;
        lcdc_info.ch[0].flags                   = 0;
-       lcdc_info.ch[0].lcd_cfg.name            = "WVGA Panel";
-       lcdc_info.ch[0].lcd_cfg.xres            = 800;
-       lcdc_info.ch[0].lcd_cfg.yres            = 480;
-       lcdc_info.ch[0].lcd_cfg.left_margin     = 220;
-       lcdc_info.ch[0].lcd_cfg.right_margin    = 110;
-       lcdc_info.ch[0].lcd_cfg.hsync_len       = 70;
-       lcdc_info.ch[0].lcd_cfg.upper_margin    = 20;
-       lcdc_info.ch[0].lcd_cfg.lower_margin    = 5;
-       lcdc_info.ch[0].lcd_cfg.vsync_len       = 5;
-       lcdc_info.ch[0].lcd_cfg.sync            = 0;
        lcdc_info.ch[0].lcd_size_cfg.width      = 152;
        lcdc_info.ch[0].lcd_size_cfg.height     = 91;
 
@@ -1094,6 +1181,23 @@ static void __init ap4evb_init(void)
        i2c_register_board_info(0, &tsc_device, 1);
 #endif /* CONFIG_AP4EVB_QHD */
 
+       /* CEU */
+
+       /*
+        * TODO: reserve memory for V4L2 DMA buffers, when a suitable API
+        * becomes available
+        */
+
+       /* MIPI-CSI stuff */
+       gpio_request(GPIO_FN_VIO_CKO, NULL);
+
+       clk = clk_get(NULL, "vck1_clk");
+       if (!IS_ERR(clk)) {
+               clk_set_rate(clk, clk_round_rate(clk, 13000000));
+               clk_enable(clk);
+               clk_put(clk);
+       }
+
        sh7372_add_standard_devices();
 
        /* HDMI */
@@ -1116,7 +1220,7 @@ static void __init ap4evb_timer_init(void)
        shmobile_timer.init();
 
        /* External clock source */
-       clk_set_rate(&dv_clki_clk, 27000000);
+       clk_set_rate(&sh7372_dv_clki_clk, 27000000);
 }
 
 static struct sys_timer ap4evb_timer = {