diff options
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r-- | drivers/video/backlight/Kconfig | 7 | ||||
-rw-r--r-- | drivers/video/backlight/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/backlight/l4f00242t03.c | 256 |
3 files changed, 264 insertions, 0 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0c77fc610212..c025c84601b0 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -31,6 +31,13 @@ config LCD_CORGI Say y here to support the LCD panels usually found on SHARP corgi (C7x0) and spitz (Cxx00) models. +config LCD_L4F00242T03 + tristate "Epson L4F00242T03 LCD" + depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO + help + SPI driver for Epson L4F00242T03. This provides basic support + for init and powering the LCD up/down through a sysfs interface. + config LCD_LMS283GF05 tristate "Samsung LMS283GF05 LCD" depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 6c704d41462d..09d1f14d6257 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o +obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o obj-$(CONFIG_LCD_ILI9320) += ili9320.o 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"); |