summaryrefslogtreecommitdiff
path: root/drivers/video/backlight/l4f00242t03.c
diff options
context:
space:
mode:
authorAlberto Panizzo <maramaopercheseimorto@gmail.com>2009-12-18 16:42:11 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-03-16 19:47:53 +0000
commite7fb9c4ad351a8da7c09e182bd2e7ccd043daf08 (patch)
treedc3dc3f491e01d987d7edd82f37fac994cd8ac7c /drivers/video/backlight/l4f00242t03.c
parenta3d3203e4bb40f253b1541e310dc0f9305be7c84 (diff)
downloadlwn-e7fb9c4ad351a8da7c09e182bd2e7ccd043daf08.tar.gz
lwn-e7fb9c4ad351a8da7c09e182bd2e7ccd043daf08.zip
backlight: Add Epson L4F00242T03 LCD driver
The Epson LCD L4F00242T03 is mounted on the Freescale i.MX31 PDK board. Based upon Marek Vasut work in l4f00242t03.c, this driver provides basic init and power on/off functionality for this device through the sysfs lcd interface. Unfortunately Datasheet for this device are not available and all the control sequences sent to the display were copied from the freescale driver that in the i.MX31 Linux BSP. As in the i.MX31PDK board the core and io suppliers are voltage regulators, that functionality is embedded here, but not strict. Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com> Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'drivers/video/backlight/l4f00242t03.c')
-rw-r--r--drivers/video/backlight/l4f00242t03.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
new file mode 100644
index 000000000000..42d061e1403b
--- /dev/null
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -0,0 +1,256 @@
+/*
+ * l4f00242t03.c -- support for Epson L4F00242T03 LCD
+ *
+ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ * Inspired by Marek Vasut work in l4f00242t03.c
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/lcd.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/l4f00242t03.h>
+
+struct l4f00242t03_priv {
+ struct spi_device *spi;
+ struct lcd_device *ld;
+ int lcd_on:1;
+ struct regulator *io_reg;
+ struct regulator *core_reg;
+};
+
+
+static void l4f00242t03_reset(unsigned int gpio)
+{
+ pr_debug("l4f00242t03_reset.\n");
+ gpio_set_value(gpio, 1);
+ mdelay(100);
+ gpio_set_value(gpio, 0);
+ mdelay(10); /* tRES >= 100us */
+ gpio_set_value(gpio, 1);
+ mdelay(20);
+}
+
+#define param(x) ((x) | 0x100)
+
+static void l4f00242t03_lcd_init(struct spi_device *spi)
+{
+ struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
+ struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+ const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
+
+ dev_dbg(&spi->dev, "initializing LCD\n");
+
+ if (priv->io_reg) {
+ regulator_set_voltage(priv->io_reg, 1800000, 1800000);
+ regulator_enable(priv->io_reg);
+ }
+
+ if (priv->core_reg) {
+ regulator_set_voltage(priv->core_reg, 2800000, 2800000);
+ regulator_enable(priv->core_reg);
+ }
+
+ gpio_set_value(pdata->data_enable_gpio, 1);
+ msleep(60);
+ spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16));
+}
+
+static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
+{
+ struct l4f00242t03_priv *priv = lcd_get_data(ld);
+ struct spi_device *spi = priv->spi;
+
+ const u16 slpout = 0x11;
+ const u16 dison = 0x29;
+
+ const u16 slpin = 0x10;
+ const u16 disoff = 0x28;
+
+ if (power) {
+ if (priv->lcd_on)
+ return 0;
+
+ dev_dbg(&spi->dev, "turning on LCD\n");
+
+ spi_write(spi, (const u8 *)&slpout, sizeof(u16));
+ msleep(60);
+ spi_write(spi, (const u8 *)&dison, sizeof(u16));
+
+ priv->lcd_on = 1;
+ } else {
+ if (!priv->lcd_on)
+ return 0;
+
+ dev_dbg(&spi->dev, "turning off LCD\n");
+
+ spi_write(spi, (const u8 *)&disoff, sizeof(u16));
+ msleep(60);
+ spi_write(spi, (const u8 *)&slpin, sizeof(u16));
+
+ priv->lcd_on = 0;
+ }
+
+ return 0;
+}
+
+static struct lcd_ops l4f_ops = {
+ .set_power = l4f00242t03_lcd_power_set,
+ .get_power = NULL,
+};
+
+static int __devinit l4f00242t03_probe(struct spi_device *spi)
+{
+ struct l4f00242t03_priv *priv;
+ struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
+ int ret;
+
+ if (pdata == NULL) {
+ dev_err(&spi->dev, "Uninitialized platform data.\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct l4f00242t03_priv), GFP_KERNEL);
+
+ if (priv == NULL) {
+ dev_err(&spi->dev, "No memory for this device.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev_set_drvdata(&spi->dev, priv);
+ spi->bits_per_word = 9;
+ spi_setup(spi);
+
+ priv->spi = spi;
+
+ ret = gpio_request(pdata->reset_gpio, "lcd l4f00242t03 reset");
+ if (ret) {
+ dev_err(&spi->dev,
+ "Unable to get the lcd l4f00242t03 reset gpio.\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(pdata->reset_gpio, 1);
+ if (ret)
+ goto err2;
+
+ ret = gpio_request(pdata->data_enable_gpio,
+ "lcd l4f00242t03 data enable");
+ if (ret) {
+ dev_err(&spi->dev,
+ "Unable to get the lcd l4f00242t03 data en gpio.\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(pdata->data_enable_gpio, 0);
+ if (ret)
+ goto err3;
+
+ if (pdata->io_supply) {
+ priv->io_reg = regulator_get(NULL, pdata->io_supply);
+
+ if (IS_ERR(priv->io_reg)) {
+ pr_err("%s: Unable to get the IO regulator\n",
+ __func__);
+ goto err3;
+ }
+ }
+
+ if (pdata->core_supply) {
+ priv->core_reg = regulator_get(NULL, pdata->core_supply);
+
+ if (IS_ERR(priv->core_reg)) {
+ pr_err("%s: Unable to get the core regulator\n",
+ __func__);
+ goto err4;
+ }
+ }
+
+ priv->ld = lcd_device_register("l4f00242t03",
+ &spi->dev, priv, &l4f_ops);
+ if (IS_ERR(priv->ld)) {
+ ret = PTR_ERR(priv->ld);
+ goto err5;
+ }
+
+ /* Init the LCD */
+ l4f00242t03_reset(pdata->reset_gpio);
+ l4f00242t03_lcd_init(spi);
+ l4f00242t03_lcd_power_set(priv->ld, 1);
+
+ dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
+
+ return 0;
+
+err5:
+ if (priv->core_reg)
+ regulator_put(priv->core_reg);
+err4:
+ if (priv->io_reg)
+ regulator_put(priv->io_reg);
+err3:
+ gpio_free(pdata->data_enable_gpio);
+err2:
+ gpio_free(pdata->reset_gpio);
+err:
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit l4f00242t03_remove(struct spi_device *spi)
+{
+ struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+ struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data;
+
+ l4f00242t03_lcd_power_set(priv->ld, 0);
+ lcd_device_unregister(priv->ld);
+
+ gpio_free(pdata->data_enable_gpio);
+ gpio_free(pdata->reset_gpio);
+
+ if (priv->io_reg)
+ regulator_put(priv->core_reg);
+ if (priv->core_reg)
+ regulator_put(priv->io_reg);
+
+ kfree(priv);
+
+ return 0;
+}
+
+static struct spi_driver l4f00242t03_driver = {
+ .driver = {
+ .name = "l4f00242t03",
+ .owner = THIS_MODULE,
+ },
+ .probe = l4f00242t03_probe,
+ .remove = __devexit_p(l4f00242t03_remove),
+};
+
+static __init int l4f00242t03_init(void)
+{
+ return spi_register_driver(&l4f00242t03_driver);
+}
+
+static __exit void l4f00242t03_exit(void)
+{
+ spi_unregister_driver(&l4f00242t03_driver);
+}
+
+module_init(l4f00242t03_init);
+module_exit(l4f00242t03_exit);
+
+MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
+MODULE_DESCRIPTION("EPSON L4F00242T03 LCD");