| /* linux/arch/arm/mach-exynos4/mach-origen.c |
| * |
| * Copyright (c) 2011 Insignal Co., Ltd. |
| * http://www.insignal.co.kr/ |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <linux/serial_core.h> |
| #include <linux/gpio.h> |
| #include <linux/mmc/host.h> |
| #include <linux/platform_device.h> |
| #include <linux/io.h> |
| #include <linux/input.h> |
| #include <linux/pwm_backlight.h> |
| #include <linux/i2c.h> |
| #include <linux/delay.h> |
| #if defined(CONFIG_S5P_MEM_CMA) |
| #include <linux/cma.h> |
| #endif |
| #include <linux/regulator/machine.h> |
| #include <linux/regulator/fixed.h> |
| #include <asm/mach/arch.h> |
| #include <asm/mach-types.h> |
| |
| #include <plat/regs-serial.h> |
| #include <plat/exynos4.h> |
| #include <plat/cpu.h> |
| #include <plat/devs.h> |
| #include <plat/sdhci.h> |
| #include <plat/iic.h> |
| #include <plat/bootmem.h> |
| #include <plat/fb.h> |
| #include <plat/fimg2d.h> |
| #include <plat/fimc.h> |
| #include <plat/pd.h> |
| #include <plat/gpio-cfg.h> |
| #include <plat/backlight.h> |
| #include <plat/otg.h> |
| #include <plat/ohci.h> |
| #include <plat/ehci.h> |
| #include <plat/clock.h> |
| #include <plat/ts.h> |
| |
| #include <plat/tvout.h> |
| #include <mach/map.h> |
| #include <mach/bootmem.h> |
| |
| extern struct max8997_platform_data max8997_pdata; |
| |
| /* Following are default values for UCON, ULCON and UFCON UART registers */ |
| #define ORIGEN_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ |
| S3C2410_UCON_RXILEVEL | \ |
| S3C2410_UCON_TXIRQMODE | \ |
| S3C2410_UCON_RXIRQMODE | \ |
| S3C2410_UCON_RXFIFO_TOI | \ |
| S3C2443_UCON_RXERR_IRQEN) |
| |
| #define ORIGEN_ULCON_DEFAULT S3C2410_LCON_CS8 |
| |
| #define ORIGEN_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ |
| S5PV210_UFCON_TXTRIG4 | \ |
| S5PV210_UFCON_RXTRIG4) |
| |
| static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { |
| [0] = { |
| .hwport = 0, |
| .flags = 0, |
| .ucon = ORIGEN_UCON_DEFAULT, |
| .ulcon = ORIGEN_ULCON_DEFAULT, |
| .ufcon = ORIGEN_UFCON_DEFAULT, |
| }, |
| [1] = { |
| .hwport = 1, |
| .flags = 0, |
| .ucon = ORIGEN_UCON_DEFAULT, |
| .ulcon = ORIGEN_ULCON_DEFAULT, |
| .ufcon = ORIGEN_UFCON_DEFAULT, |
| }, |
| [2] = { |
| .hwport = 2, |
| .flags = 0, |
| .ucon = ORIGEN_UCON_DEFAULT, |
| .ulcon = ORIGEN_ULCON_DEFAULT, |
| .ufcon = ORIGEN_UFCON_DEFAULT, |
| }, |
| [3] = { |
| .hwport = 3, |
| .flags = 0, |
| .ucon = ORIGEN_UCON_DEFAULT, |
| .ulcon = ORIGEN_ULCON_DEFAULT, |
| .ufcon = ORIGEN_UFCON_DEFAULT, |
| }, |
| }; |
| |
| /* I2C0 */ |
| static struct i2c_board_info i2c_devs0[] __initdata = { |
| { |
| /* The address is 0xCC used since SRAD = 0 */ |
| I2C_BOARD_INFO("max8997", (0xCC >> 1)), |
| .platform_data = &max8997_pdata, |
| }, |
| #ifdef CONFIG_TOUCHSCREEN_UNIDISPLAY_TS |
| { |
| I2C_BOARD_INFO("unidisplay_ts", 0x41), |
| .irq = EINT_NUMBER(25), |
| }, |
| #endif |
| }; |
| |
| /* I2C1 */ |
| static struct i2c_board_info i2c_devs1[] __initdata = { |
| { |
| I2C_BOARD_INFO("rt5625", 0x1e), |
| }, |
| }; |
| static struct i2c_board_info i2c_devs6[] __initdata = { |
| { |
| I2C_BOARD_INFO("s5p_ddc", (0x74 >> 1)), |
| }, |
| }; |
| |
| static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = { |
| .cd_type = S3C_SDHCI_CD_INTERNAL, |
| .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, |
| #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT |
| .max_width = 8, |
| .host_caps = MMC_CAP_8_BIT_DATA, |
| #endif |
| }; |
| |
| static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { |
| .cd_type = S3C_SDHCI_CD_INTERNAL, |
| .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, |
| #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT |
| .max_width = 8, |
| .host_caps = MMC_CAP_8_BIT_DATA, |
| #endif |
| }; |
| |
| /* |
| * WLAN: SDIO Host will call this func at booting time |
| */ |
| static int origen_wifi_status_register(void (*notify_func) |
| (struct platform_device *, int state)); |
| |
| /* WLAN: MMC3-SDIO */ |
| static struct s3c_sdhci_platdata origen_hsmmc3_pdata __initdata = { |
| .max_width = 4, |
| .host_caps = MMC_CAP_4_BIT_DATA | |
| MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, |
| .cd_type = S3C_SDHCI_CD_EXTERNAL, |
| .ext_cd_init = origen_wifi_status_register, |
| }; |
| |
| /* |
| * WLAN: Save SDIO Card detect func into this pointer |
| */ |
| static void (*wifi_status_cb)(struct platform_device *, int state); |
| |
| static int origen_wifi_status_register(void (*notify_func) |
| (struct platform_device *, int state)) |
| { |
| if (!notify_func) |
| return -EAGAIN; |
| else |
| wifi_status_cb = notify_func; |
| |
| return 0; |
| } |
| |
| static struct gpio origen_wlan_bt_gpios[] __initdata = { |
| { EXYNOS4_GPX2(2), GPIOF_OUT_INIT_HIGH, "GPIO_BT_RESET"}, |
| { EXYNOS4_GPX2(3), GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_BT_WOW"}, |
| { EXYNOS4_GPX2(4), GPIOF_OUT_INIT_LOW, "GPIO_WIFI_RESET"}, |
| }; |
| |
| static void origen_wlan_setup_power(bool val) |
| { |
| int err; |
| |
| origen_wlan_bt_gpios[0].gpio = EXYNOS4_GPX2(2); |
| origen_wlan_bt_gpios[1].gpio = EXYNOS4_GPX2(3); |
| origen_wlan_bt_gpios[2].gpio = EXYNOS4_GPX2(4); |
| |
| if (val) { |
| err = gpio_request_array(origen_wlan_bt_gpios, |
| ARRAY_SIZE(origen_wlan_bt_gpios)); |
| if (err) { |
| pr_warning("ORIGEN: Not obtain WIFI/BT gpios\n"); |
| return; |
| } |
| s3c_gpio_cfgpin(origen_wlan_bt_gpios[2].gpio, S3C_GPIO_OUTPUT); |
| s3c_gpio_setpull(origen_wlan_bt_gpios[2].gpio, |
| S3C_GPIO_PULL_NONE); |
| /* VDD33,I/O Supply must be done */ |
| gpio_set_value(origen_wlan_bt_gpios[2].gpio, 0); |
| udelay(30); /*Tb */ |
| gpio_direction_output(origen_wlan_bt_gpios[2].gpio, 1); |
| } else { |
| gpio_direction_output(origen_wlan_bt_gpios[2].gpio, 0); |
| gpio_free_array(origen_wlan_bt_gpios, |
| ARRAY_SIZE(origen_wlan_bt_gpios)); |
| } |
| |
| return; |
| } |
| |
| /* |
| * This will be called at init time of WLAN driver |
| */ |
| int origen_wifi_set_detect(bool val) |
| { |
| if (!wifi_status_cb) { |
| printk(KERN_WARNING "WLAN: Nobody to notify\n"); |
| return -EAGAIN; |
| } |
| if (true == val) { |
| origen_wlan_setup_power(true); |
| wifi_status_cb(&s3c_device_hsmmc3, 1); |
| } else { |
| origen_wlan_setup_power(false); |
| wifi_status_cb(&s3c_device_hsmmc3, 0); |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Atheros driver can be module driver and then call |
| * this API before registering SDIO device driver |
| */ |
| EXPORT_SYMBOL(origen_wifi_set_detect); |
| |
| #ifdef CONFIG_VIDEO_FIMG2D |
| static struct fimg2d_platdata fimg2d_data __initdata = { |
| .hw_ver = 30, |
| .parent_clkname = "mout_mpll", |
| .clkname = "sclk_fimg2d", |
| .gate_clkname = "fimg2d", |
| .clkrate = 250 * 1000000, |
| }; |
| #endif |
| |
| #ifdef CONFIG_VIDEO_FIMC |
| static struct s3c_platform_fimc fimc_plat = { |
| #ifdef CONFIG_ITU_A |
| .default_cam = CAMERA_PAR_A, |
| #endif |
| .camera = { |
| }, |
| #ifdef CONFIG_CPU_S5PV310_EVT1 |
| .hw_ver = 0x52, |
| #else |
| .hw_ver = 0x51, |
| #endif |
| }; |
| #endif |
| static struct s5p_otg_platdata origen_otg_pdata; |
| static void __init origen_otg_init(void) |
| { |
| struct s5p_otg_platdata *pdata = &origen_otg_pdata; |
| |
| s5p_otg_set_platdata(pdata); |
| } |
| /*USB OHCI*/ |
| static struct s5p_ohci_platdata origen_ohci_pdata; |
| |
| static void __init origen_ohci_init(void) |
| { |
| struct s5p_ohci_platdata *pdata = &origen_ohci_pdata; |
| |
| s5p_ohci_set_platdata(pdata); |
| } |
| /* USB EHCI */ |
| static struct s5p_ehci_platdata origen_ehci_pdata; |
| |
| static void __init origen_ehci_init(void) |
| { |
| struct s5p_ehci_platdata *pdata = &origen_ehci_pdata; |
| |
| s5p_ehci_set_platdata(pdata); |
| } |
| |
| static struct platform_device *origen_devices[] __initdata = { |
| &s3c_device_fb, |
| &s3c_device_i2c0, |
| &s3c_device_i2c1, |
| &s3c_device_i2c6, |
| &s3c_device_hsmmc2, |
| &s3c_device_hsmmc0, |
| &s3c_device_hsmmc3, |
| &s3c_device_rtc, |
| &s3c_device_wdt, |
| &s5p_device_ohci, |
| &s5p_device_ehci, |
| &exynos4_device_i2s0, |
| &samsung_asoc_dma, |
| &exynos4_device_pd[PD_MFC], |
| &exynos4_device_pd[PD_G3D], |
| &exynos4_device_pd[PD_LCD0], |
| &exynos4_device_pd[PD_LCD1], |
| &exynos4_device_pd[PD_CAM], |
| &exynos4_device_pd[PD_TV], |
| &exynos4_device_pd[PD_GPS], |
| &exynos4_device_sysmmu, |
| #ifdef CONFIG_VIDEO_FIMG2D |
| &s5p_device_fimg2d, |
| #endif |
| #ifdef CONFIG_VIDEO_JPEG |
| &s5p_device_jpeg, |
| #endif |
| #ifdef CONFIG_VIDEO_FIMC |
| &s3c_device_fimc0, |
| &s3c_device_fimc1, |
| &s3c_device_fimc2, |
| #endif |
| #ifdef CONFIG_VIDEO_SAMSUNG_TVOUT |
| &s5p_device_tvout, |
| &s5p_device_cec, |
| &s5p_device_hpd, |
| #endif |
| &origen_device_button, |
| #ifdef CONFIG_USB_GADGET_S3C_OTGD |
| &s3c_device_usbgadget, |
| #endif |
| }; |
| |
| /* LCD Backlight data */ |
| static struct samsung_bl_gpio_info origen_bl_gpio_info = { |
| .no = EXYNOS4_GPD0(0), |
| .func = S3C_GPIO_SFN(2), |
| }; |
| |
| static struct platform_pwm_backlight_data origen_bl_data = { |
| .pwm_id = 0, |
| .pwm_period_ns = 1000, |
| }; |
| |
| static void __init origen_map_io(void) |
| { |
| s5p_init_io(NULL, 0, S5P_VA_CHIPID); |
| s3c24xx_init_clocks(24000000); |
| s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs)); |
| } |
| |
| #if defined(CONFIG_VIDEO_SAMSUNG_TVOUT) |
| static struct s5p_platform_hpd hdmi_hpd_data __initdata = { |
| |
| }; |
| static struct s5p_platform_cec hdmi_cec_data __initdata = { |
| |
| }; |
| #endif |
| |
| static void __init origen_machine_init(void) |
| { |
| s3c_i2c0_set_platdata(NULL); |
| s3c_i2c1_set_platdata(NULL); |
| s3c_i2c6_set_platdata(NULL); |
| i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); |
| i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); |
| i2c_register_board_info(2, i2c_devs6, ARRAY_SIZE(i2c_devs6)); |
| s3cfb_set_platdata(NULL); |
| s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); |
| s3c_sdhci0_set_platdata(&origen_hsmmc0_pdata); |
| s3c_sdhci3_set_platdata(&origen_hsmmc3_pdata); |
| #ifdef CONFIG_VIDEO_FIMG2D |
| s5p_fimg2d_set_platdata(&fimg2d_data); |
| #endif |
| #ifdef CONFIG_VIDEO_FIMC |
| /* fimc */ |
| s3c_fimc0_set_platdata(&fimc_plat); |
| s3c_fimc1_set_platdata(&fimc_plat); |
| s3c_fimc2_set_platdata(&fimc_plat); |
| #endif |
| #if defined(CONFIG_VIDEO_SAMSUNG_TVOUT) |
| s5p_hdmi_hpd_set_platdata(&hdmi_hpd_data); |
| s5p_hdmi_cec_set_platdata(&hdmi_cec_data); |
| #endif |
| platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); |
| #ifdef CONFIG_USB_GADGET_S3C_OTGD |
| origen_otg_init(); |
| #endif |
| origen_ohci_init(); |
| clk_xusbxti.rate = 24000000; |
| origen_ehci_init(); |
| |
| samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); |
| |
| } |
| #if defined(CONFIG_S5P_MEM_CMA) |
| static void __init exynos4_reserve_cma(void) |
| { |
| static struct cma_region regions[] = { |
| #if defined(CONFIG_VIDEO_SAMSUNG_MEMSIZE_JPEG) && !defined(CONFIG_VIDEO_UMP) |
| { |
| .name = "jpeg", |
| .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_JPEG * SZ_1K, |
| .start = 0 |
| }, |
| #endif |
| #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC0 |
| { |
| .name = "fimc0", |
| .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC0 * SZ_1K, |
| }, |
| #endif |
| #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC1 |
| { |
| .name = "fimc1", |
| .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC1 * SZ_1K, |
| }, |
| #endif |
| #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC2 |
| { |
| .name = "fimc2", |
| .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC2 * SZ_1K, |
| }, |
| #endif |
| #ifdef CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC3 |
| { |
| .name = "fimc3", |
| .size = CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC3 * SZ_1K, |
| }, |
| #endif |
| { |
| .name = "common", |
| .size = CONFIG_CMA_COMMON_MEMORY_SIZE * SZ_1K, |
| .start = 0 |
| }, |
| {} |
| }; |
| static const char map[] __initconst = |
| #if defined(CONFIG_VIDEO_JPEG) && !defined(CONFIG_VIDEO_UMP) |
| "s5p-jpeg=jpeg;" |
| #endif |
| #if defined(CONFIG_VIDEO_FIMC) |
| "s3c-fimc.0=fimc0;s3c-fimc.1=fimc1;" |
| "s3c-fimc.2=fimc2;s3c-fimc.3=fimc3;" |
| #endif |
| "*=common"; |
| int i = 0; |
| unsigned int bank0_end = meminfo.bank[0].start + |
| meminfo.bank[0].size; |
| unsigned int bank1_end = meminfo.bank[1].start + |
| meminfo.bank[1].size; |
| |
| for (; i < ARRAY_SIZE(regions) ; i++) { |
| if (regions[i].start == 0) { |
| regions[i].start = bank0_end - regions[i].size; |
| bank0_end = regions[i].start; |
| } else if (regions[i].start == 1) { |
| regions[i].start = bank1_end - regions[i].size; |
| bank1_end = regions[i].start; |
| } |
| printk(KERN_ERR "CMA reserve : %s, addr is 0x%x, size is 0x%x\n", |
| regions[i].name, regions[i].start, regions[i].size); |
| } |
| |
| cma_set_defaults(regions, map); |
| cma_early_regions_reserve(NULL); |
| } |
| #endif |
| |
| static void __init origen_fixup(struct machine_desc *desc, |
| struct tag *tags, char **cmdline, |
| struct meminfo *mi) |
| { |
| mi->bank[0].start = 0x40000000; |
| mi->bank[0].size = 512 * SZ_1M; |
| |
| mi->bank[1].start = 0x60000000; |
| mi->bank[1].size = 512 * SZ_1M; |
| |
| mi->nr_banks = 2; |
| } |
| |
| MACHINE_START(ORIGEN, "ORIGEN") |
| /* Maintainer: JeongHyeon Kim <jhkim@insignal.co.kr> */ |
| .boot_params = S5P_PA_SDRAM + 0x100, |
| .init_irq = exynos4_init_irq, |
| .fixup = origen_fixup, |
| .map_io = origen_map_io, |
| .init_machine = origen_machine_init, |
| .timer = &exynos4_timer, |
| #if defined(CONFIG_S5P_MEM_CMA) |
| .reserve = &exynos4_reserve_cma, |
| #else |
| .reserve = &s5p_reserve_bootmem, |
| #endif |
| MACHINE_END |