diff options
Diffstat (limited to 'arch/arm/mach-shmobile/board-kzm9g.c')
-rw-r--r-- | arch/arm/mach-shmobile/board-kzm9g.c | 325 |
1 files changed, 323 insertions, 2 deletions
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index d8e33b68283..3b8a0171c3c 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -30,9 +30,14 @@ #include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mfd/tmio.h> #include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> #include <linux/smsc911x.h> #include <linux/usb/r8a66597.h> +#include <linux/usb/renesas_usbhs.h> #include <linux/videodev2.h> +#include <sound/sh_fsi.h> +#include <sound/simple_card.h> #include <mach/irqs.h> #include <mach/sh73a0.h> #include <mach/common.h> @@ -54,6 +59,20 @@ #define GPIO_PCF8575_PORT15 (GPIO_NR + 13) #define GPIO_PCF8575_PORT16 (GPIO_NR + 14) +/* Dummy supplies, where voltage doesn't matter */ +static struct regulator_consumer_supply dummy_supplies[] = { + REGULATOR_SUPPLY("vddvario", "smsc911x"), + REGULATOR_SUPPLY("vdd33a", "smsc911x"), +}; + +/* + * FSI-AK4648 + * + * this command is required when playback. + * + * # amixer set "LINEOUT Mixer DACL" on + */ + /* SMSC 9221 */ static struct resource smsc9221_resources[] = { [0] = { @@ -112,6 +131,151 @@ static struct platform_device usb_host_device = { .resource = usb_resources, }; +/* USB Func CN17 */ +struct usbhs_private { + unsigned int phy; + unsigned int cr2; + struct renesas_usbhs_platform_info info; +}; + +#define IRQ15 intcs_evt2irq(0x03e0) +#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) + +#define usbhs_get_priv(pdev) \ + container_of(renesas_usbhs_get_info(pdev), struct usbhs_private, info) + +static int usbhs_get_vbus(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + return !((1 << 7) & __raw_readw(priv->cr2)); +} + +static void usbhs_phy_reset(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + + /* init phy */ + __raw_writew(0x8a0a, priv->cr2); +} + +static int usbhs_get_id(struct platform_device *pdev) +{ + return USBHS_GADGET; +} + +static irqreturn_t usbhs_interrupt(int irq, void *data) +{ + struct platform_device *pdev = data; + struct usbhs_private *priv = usbhs_get_priv(pdev); + + renesas_usbhs_call_notify_hotplug(pdev); + + /* clear status */ + __raw_writew(__raw_readw(priv->phy) | USB_PHY_INT_CLR, priv->phy); + + return IRQ_HANDLED; +} + +static int usbhs_hardware_init(struct platform_device *pdev) +{ + struct usbhs_private *priv = usbhs_get_priv(pdev); + int ret; + + /* clear interrupt status */ + __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy); + + ret = request_irq(IRQ15, usbhs_interrupt, IRQF_TRIGGER_HIGH, + 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->phy); + + return 0; +} + +static void usbhs_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->phy); + + free_irq(IRQ15, pdev); +} + +static u32 usbhs_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 usbhs_private = { + .phy = 0xe60781e0, /* USBPHYINT */ + .cr2 = 0xe605810c, /* USBCR2 */ + .info = { + .platform_callback = { + .hardware_init = usbhs_hardware_init, + .hardware_exit = usbhs_hardware_exit, + .get_id = usbhs_get_id, + .phy_reset = usbhs_phy_reset, + .get_vbus = usbhs_get_vbus, + }, + .driver_param = { + .buswait_bwait = 4, + .has_otg = 1, + .pipe_type = usbhs_pipe_cfg, + .pipe_size = ARRAY_SIZE(usbhs_pipe_cfg), + }, + }, +}; + +static struct resource usbhs_resources[] = { + [0] = { + .start = 0xE6890000, + .end = 0xE68900e6 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(62), + .end = gic_spi(62), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device usbhs_device = { + .name = "renesas_usbhs", + .id = -1, + .dev = { + .dma_mask = NULL, + .coherent_dma_mask = 0xffffffff, + .platform_data = &usbhs_private.info, + }, + .num_resources = ARRAY_SIZE(usbhs_resources), + .resource = usbhs_resources, +}; + /* LCDC */ static struct fb_videomode kzm_lcdc_mode = { .name = "WVGA Panel", @@ -166,6 +330,13 @@ static struct platform_device lcdc_device = { }, }; +/* Fixed 1.8V regulator to be used by MMCIF */ +static struct regulator_consumer_supply fixed1v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"), +}; + /* MMCIF */ static struct resource sh_mmcif_resources[] = { [0] = { @@ -175,11 +346,11 @@ static struct resource sh_mmcif_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(141), + .start = gic_spi(140), .flags = IORESOURCE_IRQ, }, [2] = { - .start = gic_spi(140), + .start = gic_spi(141), .flags = IORESOURCE_IRQ, }, }; @@ -187,6 +358,8 @@ static struct resource sh_mmcif_resources[] = { static struct sh_mmcif_plat_data sh_mmcif_platdata = { .ocr = MMC_VDD_165_195, .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, + .slave_id_tx = SHDMA_SLAVE_MMCIF_TX, + .slave_id_rx = SHDMA_SLAVE_MMCIF_RX, }; static struct platform_device mmc_device = { @@ -200,6 +373,15 @@ static struct platform_device mmc_device = { .resource = sh_mmcif_resources, }; +/* Fixed 2.8V regulators to be used by SDHI0 and SDHI2 */ +static struct regulator_consumer_supply fixed2v8_power_consumers[] = +{ + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"), + REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.2"), + REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.2"), +}; + /* SDHI */ static struct sh_mobile_sdhi_info sdhi0_info = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, @@ -240,6 +422,50 @@ static struct platform_device sdhi0_device = { }, }; +/* Micro SD */ +static struct sh_mobile_sdhi_info sdhi2_info = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | + TMIO_MMC_USE_GPIO_CD | + TMIO_MMC_WRPROTECT_DISABLE, + .tmio_caps = MMC_CAP_SD_HIGHSPEED, + .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, + .cd_gpio = GPIO_PORT13, +}; + +static struct resource sdhi2_resources[] = { + [0] = { + .name = "SDHI2", + .start = 0xee140000, + .end = 0xee1400ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT, + .start = gic_spi(103), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .name = SH_MOBILE_SDHI_IRQ_SDCARD, + .start = gic_spi(104), + .flags = IORESOURCE_IRQ, + }, + [3] = { + .name = SH_MOBILE_SDHI_IRQ_SDIO, + .start = gic_spi(105), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sdhi2_device = { + .name = "sh_mobile_sdhi", + .id = 2, + .num_resources = ARRAY_SIZE(sdhi2_resources), + .resource = sdhi2_resources, + .dev = { + .platform_data = &sdhi2_info, + }, +}; + /* KEY */ #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } @@ -267,11 +493,74 @@ static struct platform_device gpio_keys_device = { }, }; +/* FSI-AK4648 */ +static struct sh_fsi_platform_info fsi_info = { + .port_a = { + .tx_id = SHDMA_SLAVE_FSI2A_TX, + }, +}; + +static struct resource fsi_resources[] = { + [0] = { + .name = "FSI", + .start = 0xEC230000, + .end = 0xEC230400 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(146), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device fsi_device = { + .name = "sh_fsi2", + .id = -1, + .num_resources = ARRAY_SIZE(fsi_resources), + .resource = fsi_resources, + .dev = { + .platform_data = &fsi_info, + }, +}; + +static struct asoc_simple_dai_init_info fsi2_ak4648_init_info = { + .fmt = SND_SOC_DAIFMT_LEFT_J, + .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM, + .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS, + .sysclk = 11289600, +}; + +static struct asoc_simple_card_info fsi2_ak4648_info = { + .name = "AK4648", + .card = "FSI2A-AK4648", + .cpu_dai = "fsia-dai", + .codec = "ak4642-codec.0-0012", + .platform = "sh_fsi2", + .codec_dai = "ak4642-hifi", + .init = &fsi2_ak4648_init_info, +}; + +static struct platform_device fsi_ak4648_device = { + .name = "asoc-simple-card", + .dev = { + .platform_data = &fsi2_ak4648_info, + }, +}; + /* I2C */ static struct pcf857x_platform_data pcf8575_pdata = { .gpio_base = GPIO_PCF8575_BASE, }; +static struct i2c_board_info i2c0_devices[] = { + { + I2C_BOARD_INFO("ak4648", 0x12), + }, + { + I2C_BOARD_INFO("r2025sd", 0x32), + } +}; + static struct i2c_board_info i2c1_devices[] = { { I2C_BOARD_INFO("st1232-ts", 0x55), @@ -289,10 +578,14 @@ static struct i2c_board_info i2c3_devices[] = { static struct platform_device *kzm_devices[] __initdata = { &smsc_device, &usb_host_device, + &usbhs_device, &lcdc_device, &mmc_device, &sdhi0_device, + &sdhi2_device, &gpio_keys_device, + &fsi_device, + &fsi_ak4648_device, }; /* @@ -350,6 +643,12 @@ device_initcall(as3711_enable_lcdc_backlight); static void __init kzm_init(void) { + regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers, + ARRAY_SIZE(fixed1v8_power_consumers), 1800000); + regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers, + ARRAY_SIZE(fixed2v8_power_consumers), 2800000); + regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies)); + sh73a0_pinmux_init(); /* enable SCIFA4 */ @@ -427,15 +726,36 @@ static void __init kzm_init(void) gpio_request(GPIO_PORT15, NULL); gpio_direction_output(GPIO_PORT15, 1); /* power */ + /* enable Micro SD */ + gpio_request(GPIO_FN_SDHID2_0, NULL); + gpio_request(GPIO_FN_SDHID2_1, NULL); + gpio_request(GPIO_FN_SDHID2_2, NULL); + gpio_request(GPIO_FN_SDHID2_3, NULL); + gpio_request(GPIO_FN_SDHICMD2, NULL); + gpio_request(GPIO_FN_SDHICLK2, NULL); + gpio_request(GPIO_PORT14, NULL); + gpio_direction_output(GPIO_PORT14, 1); /* power */ + /* I2C 3 */ gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL); gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL); + /* enable FSI2 port A (ak4648) */ + gpio_request(GPIO_FN_FSIACK, NULL); + gpio_request(GPIO_FN_FSIAILR, NULL); + gpio_request(GPIO_FN_FSIAIBT, NULL); + gpio_request(GPIO_FN_FSIAISLD, NULL); + gpio_request(GPIO_FN_FSIAOSLD, NULL); + + /* enable USB */ + gpio_request(GPIO_FN_VBUS_0, NULL); + #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 64K*8way */ l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); #endif + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices)); i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices)); @@ -455,6 +775,7 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g") .init_irq = sh73a0_init_irq, .handle_irq = gic_handle_irq, .init_machine = kzm_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, .dt_compat = kzm9g_boards_compat_dt, MACHINE_END |