diff options
author | Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> | 2011-10-10 13:09:48 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:00:12 +0100 |
commit | 8eeef4b0e2aa726f151d605885ac259b7807fe54 (patch) | |
tree | b9bc880f60cecf98d4dd51eafecd4a58ea76c7ce /drivers/video | |
parent | 79222dece0adcb57e567dc02eb0f9e0181a12d19 (diff) |
video: mcde: Add Samsung S6D16D0 driver
ST-Ericsson ID: 365249
ST-Ericsson Linux next: NA
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: Icb611dd8a6a73fca23f56841f587db97f3400f4c
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33263
Reviewed-by: Marcus LORENTZON <marcus.xm.lorentzon@stericsson.com>
Tested-by: Marcus LORENTZON <marcus.xm.lorentzon@stericsson.com>
Reviewed-by: Jimmy RUBIN <jimmy.rubin@stericsson.com>
Reviewed-by: Per PERSSON <per.xb.persson@stericsson.com>
Reviewed-by: QABUILD
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/mcde/Kconfig | 5 | ||||
-rw-r--r-- | drivers/video/mcde/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/mcde/display-samsung_s6d16d0.c | 217 |
3 files changed, 223 insertions, 0 deletions
diff --git a/drivers/video/mcde/Kconfig b/drivers/video/mcde/Kconfig index 94ce470c504..cb88a66d370 100644 --- a/drivers/video/mcde/Kconfig +++ b/drivers/video/mcde/Kconfig @@ -45,6 +45,11 @@ menu "MCDE DSI displays" config MCDE_DISPLAY_GENERIC_DSI tristate "Generic DSI display driver" +config MCDE_DISPLAY_SAMSUNG_S6D16D0 + bool "Samsung S6D16D0 DSI display driver" + ---help--- + Say Y if you have a TPO Taal or Blackpearl display panel. + config MCDE_DISPLAY_SONY_ACX424AKP_DSI tristate "Sony acx424akp DSI display driver" diff --git a/drivers/video/mcde/Makefile b/drivers/video/mcde/Makefile index ab86a074005..82a78c2542a 100644 --- a/drivers/video/mcde/Makefile +++ b/drivers/video/mcde/Makefile @@ -8,6 +8,7 @@ mcde-objs += mcde_debugfs.o obj-$(CONFIG_FB_MCDE) += mcde.o obj-$(CONFIG_MCDE_DISPLAY_GENERIC_DSI) += display-generic_dsi.o +obj-$(CONFIG_MCDE_DISPLAY_SAMSUNG_S6D16D0) += display-samsung_s6d16d0.o obj-$(CONFIG_MCDE_DISPLAY_SONY_ACX424AKP_DSI) += display-sony_acx424akp_dsi.o obj-$(CONFIG_MCDE_DISPLAY_VUIB500_DPI) += display-vuib500-dpi.o obj-$(CONFIG_MCDE_DISPLAY_AB8500_DENC) += display-ab8500.o diff --git a/drivers/video/mcde/display-samsung_s6d16d0.c b/drivers/video/mcde/display-samsung_s6d16d0.c new file mode 100644 index 00000000000..60be4e022f9 --- /dev/null +++ b/drivers/video/mcde/display-samsung_s6d16d0.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE Samsung S6D16D0 display driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/err.h> + +#include <video/mcde_display.h> + +#define RESET_DURATION_US 10 +#define RESET_DELAY_MS 120 +#define SLEEP_OUT_DELAY_MS 120 +#define IO_REGU "vdd1" +#define IO_REGU_MIN 1650000 +#define IO_REGU_MAX 3300000 + +struct device_info { + int reset_gpio; + struct mcde_port port; + struct regulator *regulator; +}; + +static inline struct device_info *get_drvdata(struct mcde_display_device *ddev) +{ + return (struct device_info *)dev_get_drvdata(&ddev->dev); +} + +static int power_on(struct mcde_display_device *ddev) +{ + struct device_info *di = get_drvdata(ddev); + + dev_dbg(&ddev->dev, "Reset & power on s6d16d0 display\n"); + + regulator_enable(di->regulator); + gpio_set_value_cansleep(di->reset_gpio, 0); + udelay(RESET_DURATION_US); + gpio_set_value_cansleep(di->reset_gpio, 1); + msleep(RESET_DELAY_MS); + + return 0; +} + +static int power_off(struct mcde_display_device *ddev) +{ + struct device_info *di = get_drvdata(ddev); + + dev_dbg(&ddev->dev, "Power off s6d16d0 display\n"); + + regulator_disable(di->regulator); + + return 0; +} + +static int display_on(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display on s6d16d0\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_EXIT_SLEEP_MODE, + NULL, 0); + if (ret) + return ret; + msleep(SLEEP_OUT_DELAY_MS); + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_ON, + NULL, 0); +} + +static int display_off(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display off s6d16d0\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_OFF, + NULL, 0); + if (ret) + return ret; + + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_ENTER_SLEEP_MODE, + NULL, 0); +} + +static int set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + + dev_dbg(&ddev->dev, "Set power mode %d\n", power_mode); + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + ret = power_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + + ret = display_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_ON; + } + /* ON -> STANDBY */ + else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + + ret = display_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + ret = power_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + + return mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); +} + +static int __devinit samsung_s6d16d0_probe(struct mcde_display_device *ddev) +{ + int ret = 0; + struct mcde_display_dsi_platform_data *pdata = ddev->dev.platform_data; + struct device_info *di; + + if (pdata == NULL || !pdata->reset_gpio) { + dev_err(&ddev->dev, "Invalid platform data\n"); + return -EINVAL; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; + di->reset_gpio = pdata->reset_gpio; + di->port.link = pdata->link; + di->port.type = MCDE_PORTTYPE_DSI; + di->port.mode = MCDE_PORTMODE_CMD; + di->port.pixel_format = MCDE_PORTPIXFMT_DSI_24BPP; + di->port.sync_src = MCDE_SYNCSRC_BTA; + di->port.phy.dsi.num_data_lanes = 2; + /* TODO: Move UI to mcde_hw.c when clk_get_rate(dsi) is done */ + di->port.phy.dsi.ui = 9; + + ret = gpio_request(di->reset_gpio, NULL); + if (ret) + goto gpio_request_failed; + gpio_direction_output(di->reset_gpio, 1); + di->regulator = regulator_get(&ddev->dev, IO_REGU); + if (IS_ERR(di->regulator)) { + di->regulator = NULL; + goto regulator_get_failed; + } + ret = regulator_set_voltage(di->regulator, IO_REGU_MIN, IO_REGU_MAX); + if (WARN_ON(ret)) + goto regulator_voltage_failed; + + /* Get in sync with u-boot */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY) + (void)regulator_enable(di->regulator); + + ddev->set_power_mode = set_power_mode; + ddev->port = &di->port; + ddev->native_x_res = 864; + ddev->native_y_res = 480; + dev_set_drvdata(&ddev->dev, di); + + dev_info(&ddev->dev, "Samsung s6d16d0 display probed\n"); + + return 0; +regulator_voltage_failed: + regulator_put(di->regulator); +regulator_get_failed: + gpio_free(di->reset_gpio); +gpio_request_failed: + kfree(di); + return ret; +} + +static struct mcde_display_driver samsung_s6d16d0_driver = { + .probe = samsung_s6d16d0_probe, + .driver = { + .name = "samsung_s6d16d0", + }, +}; + +static int __init samsung_s6d16d0_init(void) +{ + return mcde_display_driver_register(&samsung_s6d16d0_driver); +} +module_init(samsung_s6d16d0_init); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE Samsung S6D16D0 display driver"); |