diff options
Diffstat (limited to 'arch/arm/mach-shmobile/board-mackerel.c')
-rw-r--r-- | arch/arm/mach-shmobile/board-mackerel.c | 284 |
1 files changed, 224 insertions, 60 deletions
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 448ddbe4333..3802f2afabe 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -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> @@ -125,7 +126,7 @@ * ------+--------------------+--------------------+------- * 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 @@ -164,10 +165,10 @@ * 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, @@ -1136,6 +1289,7 @@ static struct platform_device *mackerel_devices[] __initdata = { &lcdc_device, &usb1_host_device, &usbhs1_device, + &usbhs0_device, &leds_device, &fsi_device, &fsi_ak4643_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); |