diff options
author | Vikas Sajjan <vikas.sajjan@linaro.org> | 2013-01-11 18:50:04 +0530 |
---|---|---|
committer | Vikas Sajjan <vikas.sajjan@linaro.org> | 2013-02-14 11:28:07 +0530 |
commit | 11d809eabdffa2ac98562898dc2c7fb67baac874 (patch) | |
tree | 0e144b8c31dbfd373a5c1b7f85857ce4aa5f1e7b | |
parent | e2365ae0b1b6b7331dc4d1244e9e51a05b45493d (diff) |
exynos: mipi : add platform data for tc358764 driver for smdk 5250
adds platform data to tc358764 driver to get tc358764 panel working on
smdk 5250
Signed-off-by: Vikas Sajjan <vikas.sajjan@linaro.org>
-rw-r--r-- | arch/arm/boot/dts/exynos5250-smdk5250.dts | 6 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mach-exynos5-dt.c | 322 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_mipi_dsi.c | 41 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_mipi_dsi_common.c | 2 | ||||
-rw-r--r-- | drivers/video/exynos/tc358764.c | 20 |
5 files changed, 386 insertions, 5 deletions
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index bc35d622660..e4833689355 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -27,6 +27,12 @@ bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; }; + mipi { + compatible = "samsung,exynos5-mipi"; + reg = <0x14500000 0x10000>; + interrupts = <0 82 0>; + }; + i2c@12C60000 { samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <20000>; diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index cad40aa50f4..17eda14c90b 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -9,6 +9,10 @@ * published by the Free Software Foundation. */ +#define EXYNOS_MIPI_DRIVER +#define TC358764_DRIVER 1 +#define SE68ax0_DRIVER !TC358764_DRIVER + #include <linux/of_platform.h> #include <linux/of_fdt.h> #include <linux/serial_core.h> @@ -23,6 +27,11 @@ #include <mach/map.h> #include <mach/regs-pmu.h> +#ifdef EXYNOS_MIPI_DRIVER +#include <video/exynos_mipi_dsim.h> +#else +#include <plat/dsim.h> +#endif #include <plat/cpu.h> #include <plat/regs-serial.h> #include <plat/mfc.h> @@ -30,8 +39,303 @@ #include <plat/gpio-cfg.h> #include <plat/fb.h> +#ifdef EXYNOS_MIPI_DRIVER +#include <linux/lcd.h> +#else + #include <video/platform_lcd.h> +#endif + #include "common.h" +static struct mipi_dsim_config dsim_info = { + .e_interface = DSIM_VIDEO, + .e_pixel_format = DSIM_24BPP_888, + /* main frame fifo auto flush at VSYNC pulse */ + .auto_flush = false, + .eot_disable = false, + .auto_vertical_cnt = false, + .hse = false, + .hfp = false, + .hbp = false, + .hsa = false, + + .e_no_data_lane = DSIM_DATA_LANE_4, + .e_byte_clk = DSIM_PLL_OUT_DIV8, + .e_burst_mode = DSIM_BURST, + + .p = 3, + .m = 115, + .s = 1, + + /* D-PHY PLL stable time spec :min = 200usec ~ max 400usec */ + .pll_stable_time = 500, + + .esc_clk = 0.4 * 1000000, /* escape clk : 10MHz */ + + /* stop state holding counter after bta change count 0 ~ 0xfff */ + .stop_holding_cnt = 0x0f, + .bta_timeout = 0xff, /* bta timeout 0 ~ 0xff */ + .rx_timeout = 0xffff, /* lp rx timeout 0 ~ 0xffff */ +#ifdef EXYNOS_MIPI_DRIVER + .e_virtual_ch = DSIM_VIRTUAL_CH_0, /* :SAB */ + .cmd_allow = 0xf, /* :SAB */ +#else + .dsim_ddi_pd = &tc358764_mipi_lcd_driver, +#endif +}; + +#if TC358764_DRIVER +static struct fb_videomode tc358764_lcd_panel_info = { + .left_margin = 0x4, + .right_margin = 0x4, + .upper_margin = 0x4, + .lower_margin = 0x4, + .hsync_len = 0x4, + .vsync_len = 0x4, + .xres = 1280, + .yres = 800, +}; +#else +static struct fb_videomode se68ax0_lcd_panel_info = { + .left_margin = 0x4, + .right_margin = 0x4, + .upper_margin = 0x4, + .lower_margin = 0x4, + .hsync_len = 0x4, + .vsync_len = 0x4, + .xres = 1280, + .yres = 800, +}; +#endif + +static int s5p_dsim_enable_d_phy(struct platform_device *pdev, bool enable) +{ + unsigned int reg; +#if defined(CONFIG_ARCH_EXYNOS5) + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + reg = readl(S5P_MIPI_DPHY_CONTROL(1)) & ~(1 << 0); + reg |= (enable << 0); + writel(reg, S5P_MIPI_DPHY_CONTROL(1)); +#else + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + reg = readl(S5P_MIPI_DPHY_CONTROL(0)) & ~(1 << 0); + reg |= (enable << 0); + writel(reg, S5P_MIPI_DPHY_CONTROL(0)); +#endif + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + return 0; +} + +static int s5p_dsim_enable_dsi_master(struct platform_device *pdev, bool enable) +{ + unsigned int reg; +#if defined(CONFIG_ARCH_EXYNOS5) + reg = readl(S5P_MIPI_DPHY_CONTROL(1)) & ~(1 << 2); + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + reg |= (enable << 2); + writel(reg, S5P_MIPI_DPHY_CONTROL(1)); +#else + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + reg = readl(S5P_MIPI_DPHY_CONTROL(0)) & ~(1 << 2); + reg |= (enable << 2); + writel(reg, S5P_MIPI_DPHY_CONTROL(0)); +#endif + return 0; +} + +int s5p_dsim_init_d_phy(struct platform_device *pdev, bool enable) +{ + /** + * DPHY and aster block must be enabled at the system initialization + * step before data access from/to DPHY begins. + */ + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + s5p_dsim_enable_d_phy(pdev, enable); + s5p_dsim_enable_dsi_master(pdev, enable); + + return 0; +} + +#ifdef EXYNOS_MIPI_DRIVER +static int __lcd_set_power(struct lcd_device *ld, int power) +#else +static void __lcd_set_power(struct plat_lcd_data *pd, + unsigned int power) +#endif +{ + static int bPowerOn; + + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + + if (power == bPowerOn) + return 0; + + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + bPowerOn = power; + + /* reset */ + gpio_request_one(EXYNOS5_GPX1(5), GPIOF_OUT_INIT_HIGH, "GPX1"); + mdelay(20); + gpio_set_value(EXYNOS5_GPX1(5), 0); + mdelay(20); + gpio_set_value(EXYNOS5_GPX1(5), 1); + mdelay(20); + gpio_free(EXYNOS5_GPX1(5)); + mdelay(20); + + return 0; + +} + +static struct mipi_dsim_platform_data tc358764_mipi_dsim_platform_data = { + .lcd_panel_name = "tc358764", + .dsim_config = &dsim_info, + .enabled = 0, + .lcd_panel_info = &tc358764_lcd_panel_info, + .phy_enable = s5p_dsim_init_d_phy, +}; + +static int tc358764_lcd_reset(struct lcd_device *ld) +{ + return 1; +} + +/* toshiba LVDS-MIPI */ +#if TC358764_DRIVER +static struct lcd_platform_data tc358764_lcd_platform_data = { + .reset = tc358764_lcd_reset, + .power_on = __lcd_set_power, + .lcd_enabled = 1, + .reset_delay = 120, /* 120ms */ + .power_on_delay = 25, /* 25ms */ + .power_off_delay = 200, /* 200ms */ +}; + +static struct mipi_dsim_lcd_device tc358764_mipi_dsim_lcd_device = { + .name = "tc358764", + .id = -1, + .bus_id = 0, + .platform_data = (void *)&tc358764_lcd_platform_data, +}; + +#else +static void mipi_lcd_set_power(struct lcd_device *ld, + unsigned int power) +{ + if (samsung_rev() >= EXYNOS5250_REV_1_0) { + if (!gpio_request(EXYNOS5_GPD1(5), "GPD1")) { + s3c_gpio_cfgpin(EXYNOS5_GPD1(5), S3C_GPIO_SFN(1)); + gpio_direction_output(EXYNOS5_GPD1(5), 0); + gpio_direction_output(EXYNOS5_GPD1(5), 1); + gpio_free(EXYNOS5_GPD1(5)); + } + } + /* reset */ + gpio_request_one(EXYNOS5_GPX1(5), GPIOF_OUT_INIT_HIGH, "GPX1"); + + msleep(20); + if (power) { + /* fire nRESET on power up */ + gpio_set_value(EXYNOS5_GPX1(5), 0); + msleep(20); + gpio_set_value(EXYNOS5_GPX1(5), 1); + msleep(20); + gpio_free(EXYNOS5_GPX1(5)); + } else { + /* fire nRESET on power off */ + gpio_set_value(EXYNOS5_GPX1(5), 0); + msleep(20); + gpio_set_value(EXYNOS5_GPX1(5), 1); + msleep(20); + gpio_free(EXYNOS5_GPX1(5)); + } + msleep(20); + /* power */ + gpio_request_one(EXYNOS5_GPX3(0), GPIOF_OUT_INIT_LOW, "GPX3"); + if (power) { + /* fire nRESET on power up */ + gpio_set_value(EXYNOS5_GPX3(0), 1); + gpio_free(EXYNOS5_GPX3(0)); + } else { + /* fire nRESET on power off */ + gpio_set_value(EXYNOS5_GPX3(0), 0); + gpio_free(EXYNOS5_GPX3(0)); + } + +#ifndef CONFIG_BACKLIGHT_PWM + /* backlight */ + gpio_request_one(EXYNOS5_GPB2(0), GPIOF_OUT_INIT_LOW, "GPB2"); + if (power) { + /* fire nRESET on power up */ + gpio_set_value(EXYNOS5_GPB2(0), 1); + gpio_free(EXYNOS5_GPB2(0)); + } else { + /* fire nRESET on power off */ + gpio_set_value(EXYNOS5_GPB2(0), 0); + gpio_free(EXYNOS5_GPB2(0)); + } +#endif /* CONFIG_BACKLIGHT_PWM */ +} + +static struct lcd_platform_data s6e8ax0_lcd_platform_data = { + .reset = tc358764_lcd_reset, + .power_on = mipi_lcd_set_power, + .lcd_enabled = 1, + .reset_delay = 120, /* 120ms */ + .power_on_delay = 25, /* 25ms */ + .power_off_delay = 200, /* 200ms */ +}; + +static struct mipi_dsim_lcd_device s6e8ax0_mipi_dsim_lcd_device = { + .name = "s6e8ax0", + .id = -1, + .bus_id = 0, + .platform_data = (void *)&s6e8ax0_lcd_platform_data, +}; + +#endif + + +#if 0 +static int smdk5250_match_fb(struct plat_lcd_data *pd, struct fb_info *info) +{ + /* Don't call .set_power callback while unblanking */ + return 0; +} +static struct plat_lcd_data smdk5250_lcd_data = { + .set_power = __lcd_set_power, + .match_fb = smdk5250_match_fb, +}; + +static struct platform_device smdk5250_lcd = { + .name = "platform-lcd", + .dev.platform_data = &smdk5250_lcd_data, +}; +#endif +static struct resource exynos_dsim_resource[] = { + [0] = { + .start = 0x14500000, + .end = 0x14500000 + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 82, + .end = 82, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device exynos_device_mipi_dsim = { + .name = "exynos-mipi-dsim", + .id = 0, + .num_resources = ARRAY_SIZE(exynos_dsim_resource), + .resource = exynos_dsim_resource, + .dev = { + .platform_data = &tc358764_mipi_dsim_platform_data, + }, +}; + + static int smdk5250_bl_notify(struct device *unused, int brightness) { /* manage lcd_bl_en signal */ @@ -130,6 +434,10 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { "exynos5-mixer", NULL), OF_DEV_AUXDATA("samsung,exynos5-fimd", EXYNOS5_PA_FIMD1, "exynos5-fb.1", NULL), + + OF_DEV_AUXDATA("samsung,exynos5-mipi", 0x14500000, + "exynos-mipi-dsim", &tc358764_mipi_dsim_platform_data), + OF_DEV_AUXDATA("samsung,exynos5-dp", EXYNOS5_PA_DP, "exynos-dp", NULL), OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL), OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000, @@ -214,6 +522,7 @@ static void __init exynos5_dt_machine_init(void) } if (of_machine_is_compatible("samsung,exynos5250")) { + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); gpio_request_one(EXYNOS5_GPX3(0), GPIOF_OUT_INIT_HIGH, "lcd_bl_en"); samsung_bl_set(&smdk5250_bl_gpio_info, &smdk5250_bl_data); @@ -224,6 +533,19 @@ static void __init exynos5_dt_machine_init(void) else if (of_machine_is_compatible("samsung,exynos5440")) of_platform_populate(NULL, of_default_bus_match_table, exynos5440_auxdata_lookup, NULL); + + +#ifdef EXYNOS_MIPI_DRIVER +#if TC358764_DRIVER + pr_err("v MIPI:SAB exynos_mipi_dsi_register_lcd_device from exynos5_dt.c file "); + pr_err("v MIPI:SAB register_ldc_device_name: %s", tc358764_mipi_dsim_lcd_device.name); + exynos_mipi_dsi_register_lcd_device(&tc358764_mipi_dsim_lcd_device); +#else + pr_err("v MIPI:SAB exynos_mipi_dsi_register_lcd_device from exynos5_dt.c file "); + pr_err("v MIPI:SAB register_ldc_device_name: %s", s6e8ax0_mipi_dsim_lcd_device.name); + exynos_mipi_dsi_register_lcd_device(&s6e8ax0_mipi_dsim_lcd_device); +#endif +#endif } static char const *exynos5_dt_compat[] __initdata = { diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 07d70a3a628..d34d59592c6 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -253,13 +253,13 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); if (!dsim_ddi) { - pr_err("mipi_dsim_ddi object not found.\n"); + pr_err("v mipi_dsim_ddi object not found.\n"); return -EFAULT; } dsim_ddi->dsim_lcd_drv = lcd_drv; - pr_info("registered panel driver(%s) to mipi-dsi driver.\n", + pr_info("v registered panel driver(%s) to mipi-dsi driver.\n", lcd_drv->name); return 0; @@ -277,13 +277,23 @@ static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi( mutex_lock(&dsim->lock); + pr_err("\n $$$$$ PANEL : %s\n", name); + list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) { lcd_drv = dsim_ddi->dsim_lcd_drv; lcd_dev = dsim_ddi->dsim_lcd_dev; + + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); +#if 0 if (!lcd_drv || !lcd_dev || (dsim->id != dsim_ddi->bus_id)) continue; +#else + if (!lcd_drv || !lcd_dev) + continue; +#endif + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n", lcd_drv->id, lcd_dev->id); dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n", @@ -338,6 +348,8 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) struct mipi_dsim_ddi *dsim_ddi; int ret = -EINVAL; + pr_err("\n <<<<<< %s >>>>>> \n", __func__); + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); if (!dsim) { dev_err(&pdev->dev, "failed to allocate dsim object.\n"); @@ -405,10 +417,12 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) mutex_init(&dsim->lock); + pr_err("\n $$$$$ PANEL : %s\n", dsim_pd->lcd_panel_name); + /* bind lcd ddi matched with panel name. */ dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); if (!dsim_ddi) { - dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); + dev_err(&pdev->dev, " >>> probe: mipi_dsim_ddi object not found.\n"); ret = -EINVAL; goto err_bind; } @@ -569,6 +583,7 @@ static int exynos_mipi_dsi_resume(struct device *dev) if (client_drv && client_drv->power_on) client_drv->power_on(client_dev, 1); + exynos_mipi_regulator_enable(dsim); /* enable MIPI-DSI PHY. */ @@ -593,13 +608,33 @@ static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume) }; +static struct platform_device_id exynos_mipi_driver_ids[] = { + { + .name = "exynos-mipi", + .driver_data = NULL, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, exynos_mipi_driver_ids); + +static const struct of_device_id exynos_mipi_match[] = { + { + .compatible = "samsung,exynos5-mipi", + .data = NULL, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_mipi_match); + static struct platform_driver exynos_mipi_dsi_driver = { .probe = exynos_mipi_dsi_probe, .remove = __devexit_p(exynos_mipi_dsi_remove), + //.id_table = exynos_mipi_driver_ids, .driver = { .name = "exynos-mipi-dsim", .owner = THIS_MODULE, .pm = &exynos_mipi_dsi_pm_ops, + .of_match_table = exynos_mipi_match, }, }; diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 3cd29a4fc10..8888dc74e84 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -813,7 +813,7 @@ int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim) /* set LCDC and CPU transfer mode to HS. */ exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); - exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); + exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 1); exynos_mipi_dsi_enable_hs_clock(dsim, 1); return 0; diff --git a/drivers/video/exynos/tc358764.c b/drivers/video/exynos/tc358764.c index ce50b1c723b..3b359709ffb 100644 --- a/drivers/video/exynos/tc358764.c +++ b/drivers/video/exynos/tc358764.c @@ -56,6 +56,7 @@ static int tc358764_lcd_init(struct mipi_dsim_device *dsim) { 0x9c, 0x04, 0x0d, 0x00, 0x00, 0x00}, /* "initcode_049c" */ }; + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); max_init_codes = sizeof(arr_init_codes)/sizeof(char [6]); for (indx_code = 0; indx_code < max_init_codes; indx_code++) { @@ -66,6 +67,7 @@ static int tc358764_lcd_init(struct mipi_dsim_device *dsim) return -EINVAL; } + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); return 0; } @@ -113,6 +115,7 @@ static int tc358764_mipi_lcd_probe(struct mipi_dsim_lcd_device *dsim_dev) { struct mipi_dsim_device *dsim_drv; struct tc358764 *lcd_tc358764; + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); lcd_tc358764 = kzalloc(sizeof(struct tc358764), GFP_KERNEL); if (!lcd_tc358764) @@ -123,10 +126,15 @@ static int tc358764_mipi_lcd_probe(struct mipi_dsim_lcd_device *dsim_dev) dsim_dev->platform_data; lcd_tc358764->dev = &dsim_dev->dev; + + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); /* get platform data information, if lcd device node is present */ - if (lcd_tc358764->ddi_pd->pdata) + if (lcd_tc358764->ddi_pd->pdata) { + + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); if (tc358764_update_platform_lcd_data(lcd_tc358764)) return -EINVAL; + } dsim_drv = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); if (!dsim_drv) @@ -142,8 +150,11 @@ static void tc358764_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) { struct tc358764 *lcd_tc358764 = dev_get_drvdata(&dsim_dev->dev); + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); + msleep(lcd_tc358764->ddi_pd->power_on_delay); +#if 0 gpio_request_one(lcd_tc358764->gpio_poweron, GPIOF_OUT_INIT_HIGH, 0); mdelay(20); gpio_set_value(lcd_tc358764->gpio_poweron, 0); @@ -152,10 +163,16 @@ static void tc358764_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power) mdelay(20); gpio_free(lcd_tc358764->gpio_poweron); mdelay(20); +#else + + pr_err("mipi: func: %s, line: %d\n", __func__, __LINE__); + lcd_tc358764->ddi_pd->power_on(NULL, 1); +#endif } static void tc358764_set_sequence(struct mipi_dsim_lcd_device *dsim_dev) { + pr_err("mipi: func: %s line: %d\n", __func__, __LINE__); tc358764_lcd_init(dsim_dev->master); } @@ -170,6 +187,7 @@ static struct mipi_dsim_lcd_driver tc358764_dsim_ddi_driver = { static int tc358764_init(void) { + pr_err("mipi: tc358764_init is called\n"); exynos_mipi_dsi_register_lcd_driver(&tc358764_dsim_ddi_driver); return 0; } |