summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Lorentzon <marcus.xm.lorentzon@stericsson.com>2011-10-10 13:09:48 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:11 +0200
commit349241bbf7131f4d9e7edcdd872b1e9b6e273393 (patch)
treed168c68d3806162b3bae3fffb23b0f7b69dbfee8
parente3507717b6584baffaa72d38c3d676a6bd15c671 (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
-rw-r--r--drivers/video/mcde/Kconfig5
-rw-r--r--drivers/video/mcde/Makefile1
-rw-r--r--drivers/video/mcde/display-samsung_s6d16d0.c217
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");