diff options
Diffstat (limited to 'arch/arm/mach-shmobile/board-mackerel.c')
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 272 |
1 files changed, 238 insertions, 34 deletions
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 7da2ca24229..448ddbe4333 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -43,6 +43,7 @@ #include <linux/sh_intc.h> #include <linux/tca6416_keypad.h> #include <linux/usb/r8a66597.h> +#include <linux/usb/renesas_usbhs.h> #include <video/sh_mobile_hdmi.h> #include <video/sh_mobile_lcdc.h> @@ -143,7 +144,30 @@ * open | external VBUS | Function * * *1 - * CN31 is used as Host in Linux. + * CN31 is used as + * CONFIG_USB_R8A66597_HCD Host + * CONFIG_USB_RENESAS_USBHS Function + * + * CAUTION + * + * renesas_usbhs driver can use external interrupt mode + * (which come from USB-PHY) or autonomy mode (it use own interrupt) + * for detecting connection/disconnection when Function. + * USB will be power OFF while it has been disconnecting + * if external interrupt mode, and it is always power ON if autonomy mode, + * + * mackerel can not use external interrupt (IRQ7-PORT167) mode on "USB0", + * because Touchscreen is using IRQ7-PORT40. + * It is impossible to use IRQ7 demux on this board. + * + * We can use external interrupt mode USB-Function on "USB1". + * 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. + * + * Actually these are old/new version of USB driver. + * This mean its register will be broken if it supports SHARD IRQ, */ /* @@ -185,6 +209,7 @@ * FIXME !! * * gpio_no_direction + * gpio_pull_down * are quick_hack. * * current gpio frame work doesn't have @@ -196,6 +221,16 @@ static void __init gpio_no_direction(u32 addr) __raw_writeb(0x00, addr); } +static void __init gpio_pull_down(u32 addr) +{ + u8 data = __raw_readb(addr); + + data &= 0x0F; + data |= 0xA0; + + __raw_writeb(data, addr); +} + /* MTD */ static struct mtd_partition nor_flash_partitions[] = { { @@ -458,12 +493,6 @@ static void __init hdmi_init_pm_clock(void) goto out; } - ret = clk_enable(&sh7372_pllc2_clk); - if (ret < 0) { - pr_err("Cannot enable pllc2 clock\n"); - goto out; - } - pr_debug("PLLC2 set frequency %lu\n", rate); ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); @@ -515,6 +544,157 @@ static struct platform_device usb1_host_device = { .resource = usb1_host_resources, }; +/* USB1 (Function) */ +#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; + struct usbhs_private *priv = usbhs_get_priv(pdev); + + dev_dbg(&pdev->dev, "%s\n", __func__); + + renesas_usbhs_call_notify_hotplug(pdev); + + /* clear status */ + __raw_writew(__raw_readw(priv->usbphyaddr) | USB_PHY_INT_CLR, + priv->usbphyaddr); + + return IRQ_HANDLED; +} + +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, + dev_name(&pdev->dev), pdev); + if (ret) { + dev_err(&pdev->dev, "request_irq err\n"); + return ret; + } + + /* enable USB phy interrupt */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->usbphyaddr); + + return 0; +} + +static void usbhs1_hardware_exit(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + /* clear interrupt status */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr); + + free_irq(priv->irq, pdev); +} + +static void usbhs1_phy_reset(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + /* init phy */ + __raw_writew(0x8a0a, priv->usbcrcaddr); +} + +static u32 usbhs1_pipe_cfg[] = { + USB_ENDPOINT_XFER_CONTROL, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_ISOC, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_INT, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, + USB_ENDPOINT_XFER_BULK, +}; + +static struct usbhs_private usbhs1_private = { + .irq = evt2irq(0x0300), /* IRQ8 */ + .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, + }, + .driver_param = { + .buswait_bwait = 4, + .pipe_type = usbhs1_pipe_cfg, + .pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg), + }, + }, +}; + +static struct resource usbhs1_resources[] = { + [0] = { + .name = "USBHS", + .start = 0xE68B0000, + .end = 0xE68B00E6 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = evt2irq(0x1ce0) /* USB1_USB1I0 */, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usbhs1_device = { + .name = "renesas_usbhs", + .id = 1, + .dev = { + .platform_data = &usbhs1_private.info, + }, + .num_resources = ARRAY_SIZE(usbhs1_resources), + .resource = usbhs1_resources, +}; + + /* LED */ static struct gpio_led mackerel_leds[] = { { @@ -690,7 +870,15 @@ static struct resource sdhi0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = evt2irq(0x0e00) /* SDHI0 */, + .start = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */, .flags = IORESOURCE_IRQ, }, }; @@ -705,7 +893,7 @@ static struct platform_device sdhi0_device = { }, }; -#if !defined(CONFIG_MMC_SH_MMCIF) +#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) /* SDHI1 */ static struct sh_mobile_sdhi_info sdhi1_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, @@ -725,7 +913,15 @@ static struct resource sdhi1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = evt2irq(0x0e80), + .start = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */ + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */ + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */ .flags = IORESOURCE_IRQ, }, }; @@ -768,7 +964,15 @@ static struct resource sdhi2_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = evt2irq(0x1200), + .start = evt2irq(0x1200), /* SDHI2_SDHI2I0 */ + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = evt2irq(0x1220), /* SDHI2_SDHI2I1 */ + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = evt2irq(0x1240), /* SDHI2_SDHI2I2 */ .flags = IORESOURCE_IRQ, }, }; @@ -803,6 +1007,15 @@ static struct resource sh_mmcif_resources[] = { }, }; +static struct sh_mmcif_dma sh_mmcif_dma = { + .chan_priv_rx = { + .slave_id = SHDMA_SLAVE_MMCIF_RX, + }, + .chan_priv_tx = { + .slave_id = SHDMA_SLAVE_MMCIF_TX, + }, +}; + static struct sh_mmcif_plat_data sh_mmcif_plat = { .sup_pclk = 0, .ocr = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34, @@ -810,6 +1023,7 @@ static struct sh_mmcif_plat_data sh_mmcif_plat = { MMC_CAP_8_BIT_DATA | MMC_CAP_NEEDS_POLL, .get_cd = slot_cn7_get_cd, + .dma = &sh_mmcif_dma, }; static struct platform_device sh_mmcif_device = { @@ -858,37 +1072,23 @@ static struct soc_camera_link camera_link = { .priv = &camera_info, }; -static void dummy_release(struct device *dev) +static struct platform_device *camera_device; + +static void mackerel_camera_release(struct device *dev) { + soc_camera_platform_release(&camera_device); } -static struct platform_device camera_device = { - .name = "soc_camera_platform", - .dev = { - .platform_data = &camera_info, - .release = dummy_release, - }, -}; - static int mackerel_camera_add(struct soc_camera_link *icl, struct device *dev) { - if (icl != &camera_link) - return -ENODEV; - - camera_info.dev = dev; - - return platform_device_register(&camera_device); + return soc_camera_platform_add(icl, dev, &camera_device, &camera_link, + mackerel_camera_release, 0); } static void mackerel_camera_del(struct soc_camera_link *icl) { - if (icl != &camera_link) - return; - - platform_device_unregister(&camera_device); - memset(&camera_device.dev.kobj, 0, - sizeof(camera_device.dev.kobj)); + soc_camera_platform_del(icl, camera_device, &camera_link); } static struct sh_mobile_ceu_info sh_mobile_ceu_info = { @@ -935,12 +1135,13 @@ static struct platform_device *mackerel_devices[] __initdata = { &smc911x_device, &lcdc_device, &usb1_host_device, + &usbhs1_device, &leds_device, &fsi_device, &fsi_ak4643_device, &fsi_hdmi_device, &sdhi0_device, -#if !defined(CONFIG_MMC_SH_MMCIF) +#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) &sdhi1_device, #endif &sdhi2_device, @@ -1030,6 +1231,7 @@ static void __init mackerel_map_io(void) #define GPIO_PORT9CR 0xE6051009 #define GPIO_PORT10CR 0xE605100A +#define GPIO_PORT168CR 0xE60520A8 #define SRCR4 0xe61580bc #define USCCR1 0xE6058144 static void __init mackerel_init(void) @@ -1088,6 +1290,7 @@ static void __init mackerel_init(void) 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); /* setup USB phy */ __raw_writew(0x8a0a, 0xE6058130); /* USBCR4 */ @@ -1140,7 +1343,7 @@ static void __init mackerel_init(void) gpio_request(GPIO_FN_SDHID0_1, NULL); gpio_request(GPIO_FN_SDHID0_0, NULL); -#if !defined(CONFIG_MMC_SH_MMCIF) +#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) /* enable SDHI1 */ gpio_request(GPIO_FN_SDHICMD1, NULL); gpio_request(GPIO_FN_SDHICLK1, NULL); @@ -1216,6 +1419,7 @@ static void __init mackerel_init(void) platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices)); hdmi_init_pm_clock(); + sh7372_pm_init(); } static void __init mackerel_timer_init(void) |