-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Alberto Panizzo
authored and
Richard Purdie
committed
Mar 16, 2010
1 parent
a3d3203
commit e7fb9c4
Showing
4 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* l4f00242t03.h -- Platform glue for Epson L4F00242T03 LCD | ||
* | ||
* Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> | ||
* Based on Marek Vasut work in lms283gf05.h | ||
* | ||
* 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. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
*/ | ||
|
||
#ifndef _INCLUDE_LINUX_SPI_L4F00242T03_H_ | ||
#define _INCLUDE_LINUX_SPI_L4F00242T03_H_ | ||
|
||
struct l4f00242t03_pdata { | ||
unsigned int reset_gpio; | ||
unsigned int data_enable_gpio; | ||
const char *io_supply; /* will be set to 1.8 V */ | ||
const char *core_supply; /* will be set to 2.8 V */ | ||
}; | ||
|
||
#endif /* _INCLUDE_LINUX_SPI_L4F00242T03_H_ */ |