From mboxrd@z Thu Jan 1 00:00:00 1970 From: Donghwa Lee Date: Wed, 19 Jan 2011 02:39:59 +0000 Subject: Re: [PATCH] drivers: ld9040 amoled driver support Message-Id: <4D364EFF.6080401@samsung.com> List-Id: References: <1294893628-16998-1-git-send-email-dh09.lee@samsung.com> In-Reply-To: <1294893628-16998-1-git-send-email-dh09.lee@samsung.com> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable To: linux-arm-kernel@lists.infradead.org Dear Richard Purdie, I had sent ld9040 amoled driver patch file for several times with expectati= on for your comment. But, there was no comment about that. I was somewhat disappointed. That patch is working well on my board and it is very smilar framework as s= 6e63m0 that already included mainline. Please reply with any comment. I'm looking forward to your reply. Thanks, Donghwa Lee On 2011-01-13 =BF=C0=C8=C4 1:40 , Donghwa Lee wrote: > This patch is ld9040 amoled panel driver. > I resend because there was no comment. > > It is similar to s6e63m0 panel driver and use spi gpio to send panel > information. > > Signed-off-by: Donghwa Lee > Signed-off-by: Kyungmin Park > Signed-off-by: Inki Dae > > --- > drivers/video/backlight/Kconfig | 8 + > drivers/video/backlight/Makefile | 1 + > drivers/video/backlight/ld9040.c | 927 ++++++++++++++++++++++++++= ++++++ > drivers/video/backlight/ld9040_gamma.h | 203 +++++++ > 4 files changed, 1139 insertions(+), 0 deletions(-) > create mode 100644 drivers/video/backlight/ld9040.c > create mode 100644 drivers/video/backlight/ld9040_gamma.h > > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kc= onfig > index e54a337..db3d123 100644 > --- a/drivers/video/backlight/Kconfig > +++ b/drivers/video/backlight/Kconfig > @@ -109,6 +109,14 @@ config LCD_S6E63M0 > If you have an S6E63M0 LCD Panel, say Y to enable its > LCD control driver. > =20 > +config LCD_LD9040 > + tristate "LD9040 AMOLED LCD Driver" > + depends on SPI && BACKLIGHT_CLASS_DEVICE > + default n > + help > + If you have an LD9040 Panel, say Y to enable its > + control driver. > + > endif # LCD_CLASS_DEVICE > =20 > # > diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/M= akefile > index 44c0f81..457996c 100644 > --- a/drivers/video/backlight/Makefile > +++ b/drivers/video/backlight/Makefile > @@ -12,6 +12,7 @@ obj-$(CONFIG_LCD_VGG2432A4) +=3D vgg2432a4.o > obj-$(CONFIG_LCD_TDO24M) +=3D tdo24m.o > obj-$(CONFIG_LCD_TOSA) +=3D tosa_lcd.o > obj-$(CONFIG_LCD_S6E63M0) +=3D s6e63m0.o > +obj-$(CONFIG_LCD_LD9040) +=3D ld9040.o > =20 > obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) +=3D backlight.o > obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) +=3D atmel-pwm-bl.o > diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/l= d9040.c > new file mode 100644 > index 0000000..248f42f > --- /dev/null > +++ b/drivers/video/backlight/ld9040.c > @@ -0,0 +1,927 @@ > +/* > + * ld9040 AMOLED LCD panel driver. > + * > + * Author: Donghwa Lee > + * > + * Derived from drivers/video/backlight/s6e63m0.c > + * > + * This program is free software; you can redistribute it and/or modify = it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + * > + * 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 alo= ng > + * with this program; if not, write to the Free Software Foundation, Inc= ., > + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "ld9040_gamma.h" > + > +#define SLEEPMSEC 0x1000 > +#define ENDDEF 0x2000 > +#define DEFMASK 0xFF00 > +#define COMMAND_ONLY 0xFE > +#define DATA_ONLY 0xFF > + > +#define MIN_BRIGHTNESS 0 > +#define MAX_BRIGHTNESS 24 > +#define POWER_IS_ON(pwr) ((pwr) <=3D FB_BLANK_NORMAL) > + > +struct ld9040 { > + struct device *dev; > + struct spi_device *spi; > + unsigned int power; > + unsigned int gamma_mode; > + unsigned int current_brightness; > + unsigned int gamma_table_count; > + > + struct lcd_device *ld; > + struct backlight_device *bd; > + struct lcd_platform_data *lcd_pd; > +}; > + > +static const unsigned short SEQ_SWRESET[] =3D { > + 0x01, COMMAND_ONLY, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_USER_SETTING[] =3D { > + 0xF0, 0x5A, > + > + DATA_ONLY, 0x5A, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_ELVSS_ON[] =3D { > + 0xB1, 0x0D, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x16, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GTCON[] =3D { > + 0xF7, 0x09, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_PANEL_CONDITION[] =3D { > + 0xF8, 0x05, > + > + DATA_ONLY, 0x65, > + DATA_ONLY, 0x96, > + DATA_ONLY, 0x71, > + DATA_ONLY, 0x7D, > + DATA_ONLY, 0x19, > + DATA_ONLY, 0x3B, > + DATA_ONLY, 0x0D, > + DATA_ONLY, 0x19, > + DATA_ONLY, 0x7E, > + DATA_ONLY, 0x0D, > + DATA_ONLY, 0xE2, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x7E, > + DATA_ONLY, 0x7D, > + DATA_ONLY, 0x07, > + DATA_ONLY, 0x07, > + DATA_ONLY, 0x20, > + DATA_ONLY, 0x20, > + DATA_ONLY, 0x20, > + DATA_ONLY, 0x02, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GAMMA_SET1[] =3D { > + 0xF9, 0x00, > + > + DATA_ONLY, 0xA7, > + DATA_ONLY, 0xB4, > + DATA_ONLY, 0xAE, > + DATA_ONLY, 0xBF, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x91, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0xB2, > + DATA_ONLY, 0xB4, > + DATA_ONLY, 0xAA, > + DATA_ONLY, 0xBB, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0xAC, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0xB3, > + DATA_ONLY, 0xB1, > + DATA_ONLY, 0xAA, > + DATA_ONLY, 0xBC, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0xB3, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GAMMA_CTRL[] =3D { > + 0xFB, 0x02, > + > + DATA_ONLY, 0x5A, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GAMMA_START[] =3D { > + 0xF9, COMMAND_ONLY, > + > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_APON[] =3D { > + 0xF3, 0x00, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x0A, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_DISPCTL[] =3D { > + 0xF2, 0x02, > + > + DATA_ONLY, 0x08, > + DATA_ONLY, 0x08, > + DATA_ONLY, 0x10, > + DATA_ONLY, 0x10, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_MANPWR[] =3D { > + 0xB0, 0x04, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_PWR_CTRL[] =3D { > + 0xF4, 0x0A, > + > + DATA_ONLY, 0x87, > + DATA_ONLY, 0x25, > + DATA_ONLY, 0x6A, > + DATA_ONLY, 0x44, > + DATA_ONLY, 0x02, > + DATA_ONLY, 0x88, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_SLPOUT[] =3D { > + 0x11, COMMAND_ONLY, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_SLPIN[] =3D { > + 0x10, COMMAND_ONLY, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_DISPON[] =3D { > + 0x29, COMMAND_ONLY, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_DISPOFF[] =3D { > + 0x28, COMMAND_ONLY, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VCI1_1ST_EN[] =3D { > + 0xF3, 0x10, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VL1_EN[] =3D { > + 0xF3, 0x11, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VL2_EN[] =3D { > + 0xF3, 0x13, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VCI1_2ND_EN[] =3D { > + 0xF3, 0x33, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VL3_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VREG1_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0x01, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VGH_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0x11, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VGL_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0x31, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x02, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VMOS_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xB1, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VINT_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xF1, > + /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VBH_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xF9, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_VBL_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFD, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GAM_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFF, > + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_SD_AMP_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFF, > + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x80, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_GLS_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFF, > + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x81, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_ELS_EN[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFF, > + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x83, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static const unsigned short SEQ_EL_ON[] =3D { > + 0xF3, 0x37, > + > + DATA_ONLY, 0xFF, > + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ > + DATA_ONLY, 0x87, > + DATA_ONLY, 0x00, > + DATA_ONLY, 0x03, > + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ > + ENDDEF, 0x00 > +}; > + > +static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data) > +{ > + u16 buf[1]; > + struct spi_message msg; > + > + struct spi_transfer xfer =3D { > + .len =3D 2, > + .tx_buf =3D buf, > + }; > + > + buf[0] =3D (addr << 8) | data; > + > + spi_message_init(&msg); > + spi_message_add_tail(&xfer, &msg); > + > + return spi_sync(lcd->spi, &msg); > +} > + > +static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address, > + unsigned char command) > +{ > + int ret =3D 0; > + > + if (address !=3D DATA_ONLY) > + ret =3D ld9040_spi_write_byte(lcd, 0x0, address); > + if (command !=3D COMMAND_ONLY) > + ret =3D ld9040_spi_write_byte(lcd, 0x1, command); > + > + return ret; > +} > + > +static int ld9040_panel_send_sequence(struct ld9040 *lcd, > + const unsigned short *wbuf) > +{ > + int ret =3D 0, i =3D 0; > + > + while ((wbuf[i] & DEFMASK) !=3D ENDDEF) { > + if ((wbuf[i] & DEFMASK) !=3D SLEEPMSEC) { > + ret =3D ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); > + if (ret) > + break; > + } else > + udelay(wbuf[i+1]*1000); > + i +=3D 2; > + } > + > + return ret; > +} > + > +static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gam= ma) > +{ > + unsigned int i =3D 0; > + int ret =3D 0; > + > + /* start gamma table updating. */ > + ret =3D ld9040_panel_send_sequence(lcd, SEQ_GAMMA_START); > + if (ret) { > + dev_err(lcd->dev, "failed to disable gamma table updating.\n"); > + goto gamma_err; > + } > + > + for (i =3D 0 ; i < GAMMA_TABLE_COUNT; i++) { > + ret =3D ld9040_spi_write(lcd, DATA_ONLY, gamma[i]); > + if (ret) { > + dev_err(lcd->dev, "failed to set gamma table.\n"); > + goto gamma_err; > + } > + } > + > + /* update gamma table. */ > + ret =3D ld9040_panel_send_sequence(lcd, SEQ_GAMMA_CTRL); > + if (ret) > + dev_err(lcd->dev, "failed to update gamma table.\n"); > + > +gamma_err: > + return ret; > +} > + > +static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) > +{ > + int ret =3D 0; > + > + ret =3D _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); > + > + return ret; > +} > + > + > +static int ld9040_ldi_init(struct ld9040 *lcd) > +{ > + int ret, i; > + const unsigned short *init_seq[] =3D { > + SEQ_USER_SETTING, > + SEQ_PANEL_CONDITION, > + SEQ_DISPCTL, > + SEQ_MANPWR, > + SEQ_PWR_CTRL, > + SEQ_ELVSS_ON, > + SEQ_GTCON, > + SEQ_GAMMA_SET1, > + SEQ_GAMMA_CTRL, > + SEQ_SLPOUT, > + }; > + > + for (i =3D 0; i < ARRAY_SIZE(init_seq); i++) { > + ret =3D ld9040_panel_send_sequence(lcd, init_seq[i]); > + /* workaround: minimum delay time for transferring CMD */ > + udelay(300); > + if (ret) > + break; > + } > + > + return ret; > +} > + > +static int ld9040_ldi_enable(struct ld9040 *lcd) > +{ > + int ret =3D 0; > + > + ret =3D ld9040_panel_send_sequence(lcd, SEQ_DISPON); > + > + return ret; > +} > + > +static int ld9040_ldi_disable(struct ld9040 *lcd) > +{ > + int ret; > + > + ret =3D ld9040_panel_send_sequence(lcd, SEQ_DISPOFF); > + ret =3D ld9040_panel_send_sequence(lcd, SEQ_SLPIN); > + > + return ret; > +} > + > +static int ld9040_power_on(struct ld9040 *lcd) > +{ > + int ret =3D 0; > + struct lcd_platform_data *pd =3D NULL; > + pd =3D lcd->lcd_pd; > + if (!pd) { > + dev_err(lcd->dev, "platform data is NULL.\n"); > + return -EFAULT; > + } > + > + if (!pd->power_on) { > + dev_err(lcd->dev, "power_on is NULL.\n"); > + return -EFAULT; > + } else { > + pd->power_on(lcd->ld, 1); > + mdelay(pd->power_on_delay); > + } > + > + if (!pd->reset) { > + dev_err(lcd->dev, "reset is NULL.\n"); > + return -EFAULT; > + } else { > + pd->reset(lcd->ld); > + mdelay(pd->reset_delay); > + } > + > + ret =3D ld9040_ldi_init(lcd); > + if (ret) { > + dev_err(lcd->dev, "failed to initialize ldi.\n"); > + return ret; > + } > + > + ret =3D ld9040_ldi_enable(lcd); > + if (ret) { > + dev_err(lcd->dev, "failed to enable ldi.\n"); > + return ret; > + } > + > + return 0; > +} > + > +static int ld9040_power_off(struct ld9040 *lcd) > +{ > + int ret =3D 0; > + struct lcd_platform_data *pd =3D NULL; > + > + pd =3D lcd->lcd_pd; > + if (!pd) { > + dev_err(lcd->dev, "platform data is NULL.\n"); > + return -EFAULT; > + } > + > + ret =3D ld9040_ldi_disable(lcd); > + if (ret) { > + dev_err(lcd->dev, "lcd setting failed.\n"); > + return -EIO; > + } > + > + mdelay(pd->power_off_delay); > + > + if (!pd->power_on) { > + dev_err(lcd->dev, "power_on is NULL.\n"); > + return -EFAULT; > + } else > + pd->power_on(lcd->ld, 0); > + > + return 0; > +} > + > +static int ld9040_power(struct ld9040 *lcd, int power) > +{ > + int ret =3D 0; > + > + if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) > + ret =3D ld9040_power_on(lcd); > + else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) > + ret =3D ld9040_power_off(lcd); > + > + if (!ret) > + lcd->power =3D power; > + > + return ret; > +} > + > +static int ld9040_set_power(struct lcd_device *ld, int power) > +{ > + struct ld9040 *lcd =3D lcd_get_data(ld); > + > + if (power !=3D FB_BLANK_UNBLANK && power !=3D FB_BLANK_POWERDOWN && > + power !=3D FB_BLANK_NORMAL) { > + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); > + return -EINVAL; > + } > + > + return ld9040_power(lcd, power); > +} > + > +static int ld9040_get_power(struct lcd_device *ld) > +{ > + struct ld9040 *lcd =3D lcd_get_data(ld); > + > + return lcd->power; > +} > + > +static int ld9040_get_brightness(struct backlight_device *bd) > +{ > + return bd->props.brightness; > +} > + > +static int ld9040_set_brightness(struct backlight_device *bd) > +{ > + int ret =3D 0, brightness =3D bd->props.brightness; > + struct ld9040 *lcd =3D bl_get_data(bd); > + > + if (brightness < MIN_BRIGHTNESS || > + brightness > bd->props.max_brightness) { > + dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", > + MIN_BRIGHTNESS, MAX_BRIGHTNESS); > + return -EINVAL; > + } > + > + ret =3D ld9040_gamma_ctl(lcd, bd->props.brightness); > + if (ret) { > + dev_err(&bd->dev, "lcd brightness setting failed.\n"); > + return -EIO; > + } > + > + return ret; > +} > + > +static struct lcd_ops ld9040_lcd_ops =3D { > + .set_power =3D ld9040_set_power, > + .get_power =3D ld9040_get_power, > +}; > + > +static const struct backlight_ops ld9040_backlight_ops =3D { > + .get_brightness =3D ld9040_get_brightness, > + .update_status =3D ld9040_set_brightness, > +}; > + > +static ssize_t ld9040_sysfs_show_gamma_mode(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct ld9040 *lcd =3D dev_get_drvdata(dev); > + char temp[10]; > + > + switch (lcd->gamma_mode) { > + case 0: > + sprintf(temp, "2.2 mode\n"); > + strcat(buf, temp); > + break; > + default: > + dev_info(dev, "gamma mode could be 0:2.2\n"); > + break; > + } > + > + return strlen(buf); > +} > + > +static ssize_t ld9040_sysfs_store_gamma_mode(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct ld9040 *lcd =3D dev_get_drvdata(dev); > + struct backlight_device *bd =3D NULL; > + int brightness, rc; > + > + rc =3D strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode); > + if (rc < 0) > + return rc; > + > + bd =3D lcd->bd; > + > + brightness =3D bd->props.brightness; > + > + switch (lcd->gamma_mode) { > + case 0: > + _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); > + break; > + default: > + dev_info(dev, "gamma mode could be 0:2.2\n"); > + _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); > + break; > + } > + return len; > +} > + > +static DEVICE_ATTR(gamma_mode, 0644, > + ld9040_sysfs_show_gamma_mode, ld9040_sysfs_store_gamma_mode); > + > +static ssize_t ld9040_sysfs_show_gamma_table(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct ld9040 *lcd =3D dev_get_drvdata(dev); > + char temp[3]; > + > + sprintf(temp, "%d\n", lcd->gamma_table_count); > + strcpy(buf, temp); > + > + return strlen(buf); > +} > + > +static DEVICE_ATTR(gamma_table, 0644, > + ld9040_sysfs_show_gamma_table, NULL); > + > +static int ld9040_probe(struct spi_device *spi) > +{ > + int ret =3D 0; > + struct ld9040 *lcd =3D NULL; > + struct lcd_device *ld =3D NULL; > + struct backlight_device *bd =3D NULL; > + > + lcd =3D kzalloc(sizeof(struct ld9040), GFP_KERNEL); > + if (!lcd) > + return -ENOMEM; > + > + /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */ > + spi->bits_per_word =3D 9; > + > + ret =3D spi_setup(spi); > + if (ret < 0) { > + dev_err(&spi->dev, "spi setup failed.\n"); > + goto out_free_lcd; > + } > + > + lcd->spi =3D spi; > + lcd->dev =3D &spi->dev; > + > + lcd->lcd_pd =3D (struct lcd_platform_data *)spi->dev.platform_data; > + if (!lcd->lcd_pd) { > + dev_err(&spi->dev, "platform data is NULL.\n"); > + goto out_free_lcd; > + } > + > + ld =3D lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); > + if (IS_ERR(ld)) { > + ret =3D PTR_ERR(ld); > + goto out_free_lcd; > + } > + > + lcd->ld =3D ld; > + > + bd =3D backlight_device_register("ld9040-bl", &spi->dev, > + lcd, &ld9040_backlight_ops, NULL); > + if (IS_ERR(ld)) { > + ret =3D PTR_ERR(ld); > + goto out_free_lcd; > + } > + > + bd->props.max_brightness =3D MAX_BRIGHTNESS; > + bd->props.brightness =3D MAX_BRIGHTNESS; > + lcd->bd =3D bd; > + > + /* > + * it gets gamma table count available so it gets user > + * know that. > + */ > + lcd->gamma_table_count > + sizeof(gamma_table) / (MAX_GAMMA_LEVEL *= sizeof(int)); > + > + ret =3D device_create_file(&(spi->dev), &dev_attr_gamma_mode); > + if (ret < 0) > + dev_err(&(spi->dev), "failed to add sysfs entries\n"); > + > + ret =3D device_create_file(&(spi->dev), &dev_attr_gamma_table); > + if (ret < 0) > + dev_err(&(spi->dev), "failed to add sysfs entries\n"); > + > + /* > + * if lcd panel was on from bootloader like u-boot then > + * do not lcd on. > + */ > + if (!lcd->lcd_pd->lcd_enabled) { > + /* > + * if lcd panel was off from bootloader then > + * current lcd status is powerdown and then > + * it enables lcd panel. > + */ > + lcd->power =3D FB_BLANK_POWERDOWN; > + > + ld9040_power(lcd, FB_BLANK_UNBLANK); > + } else > + lcd->power =3D FB_BLANK_UNBLANK; > + > + dev_set_drvdata(&spi->dev, lcd); > + > + dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); > + return 0; > + > +out_free_lcd: > + kfree(lcd); > + return ret; > +} > + > +static int __devexit ld9040_remove(struct spi_device *spi) > +{ > + struct ld9040 *lcd =3D dev_get_drvdata(&spi->dev); > + > + ld9040_power(lcd, FB_BLANK_POWERDOWN); > + lcd_device_unregister(lcd->ld); > + kfree(lcd); > + > + return 0; > +} > + > +#if defined(CONFIG_PM) > +unsigned int beforepower; > + > +static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) > +{ > + int ret =3D 0; > + struct ld9040 *lcd =3D dev_get_drvdata(&spi->dev); > + > + dev_dbg(&spi->dev, "lcd->power =3D %d\n", lcd->power); > + > + beforepower =3D lcd->power; > + > + /* > + * when lcd panel is suspend, lcd panel becomes off > + * regardless of status. > + */ > + ret =3D ld9040_power(lcd, FB_BLANK_POWERDOWN); > + > + return ret; > +} > + > +static int ld9040_resume(struct spi_device *spi) > +{ > + int ret =3D 0; > + struct ld9040 *lcd =3D dev_get_drvdata(&spi->dev); > + > + /* > + * after suspended, if lcd panel status is FB_BLANK_UNBLANK > + * (at that time, power is FB_BLANK_UNBLANK) then > + * it changes that status to FB_BLANK_POWERDOWN to get lcd on. > + */ > + if (beforepower =3D FB_BLANK_UNBLANK) > + lcd->power =3D FB_BLANK_POWERDOWN; > + > + dev_dbg(&spi->dev, "power =3D %d\n", beforepower); > + > + ret =3D ld9040_power(lcd, beforepower); > + > + return ret; > +} > +#else > +#define ld9040_suspend NULL > +#define ld9040_resume NULL > +#endif > + > +/* Power down all displays on reboot, poweroff or halt. */ > +static void ld9040_shutdown(struct spi_device *spi) > +{ > + struct ld9040 *lcd =3D dev_get_drvdata(&spi->dev); > + > + ld9040_power(lcd, FB_BLANK_POWERDOWN); > +} > + > +static struct spi_driver ld9040_driver =3D { > + .driver =3D { > + .name =3D "ld9040", > + .bus =3D &spi_bus_type, > + .owner =3D THIS_MODULE, > + }, > + .probe =3D ld9040_probe, > + .remove =3D __devexit_p(ld9040_remove), > + .shutdown =3D ld9040_shutdown, > + .suspend =3D ld9040_suspend, > + .resume =3D ld9040_resume, > +}; > + > +static int __init ld9040_init(void) > +{ > + return spi_register_driver(&ld9040_driver); > +} > + > +static void __exit ld9040_exit(void) > +{ > + spi_unregister_driver(&ld9040_driver); > +} > + > +module_init(ld9040_init); > +module_exit(ld9040_exit); > + > +MODULE_AUTHOR("Donghwa Lee "); > +MODULE_DESCRIPTION("ld9040 LCD Driver"); > +MODULE_LICENSE("GPL"); > + > diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backl= ight/ld9040_gamma.h > new file mode 100644 > index 0000000..f199133 > --- /dev/null > +++ b/drivers/video/backlight/ld9040_gamma.h > @@ -0,0 +1,203 @@ > +/* linux/drivers/video/samsung/ld9040_brightness.h > + * > + * Gamma level definitions. > + * > + * Copyright (c) 2009 Samsung Electronics > + * InKi Dae > + * > + * 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. > +*/ > + > +#ifndef _ld9040_BRIGHTNESS_H > +#define _ld9040_BRIGHTNESS_H > + > +#define MAX_GAMMA_LEVEL 25 > +#define GAMMA_TABLE_COUNT 21 > + > +/* gamma value: 2.2 */ > +static const unsigned int ld9040_22_300[] =3D { > + 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, > + 0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac, > + 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 > +}; > + > +static const unsigned int ld9040_22_290[] =3D { > + 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, > + 0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4, > + 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa > +}; > + > +static const unsigned int ld9040_22_280[] =3D { > + 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, > + 0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0, > + 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 > +}; > + > +static const unsigned int ld9040_22_270[] =3D { > + 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, > + 0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d, > + 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 > + > +}; > +static const unsigned int ld9040_22_260[] =3D { > + 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, > + 0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a, > + 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 > +}; > + > +static const unsigned int ld9040_22_250[] =3D { > + 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, > + 0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97, > + 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d > +}; > + > +static const unsigned int ld9040_22_240[] =3D { > + 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, > + 0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94, > + 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a > +}; > + > +static const unsigned int ld9040_22_230[] =3D { > + 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, > + 0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90, > + 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 > +}; > + > +static const unsigned int ld9040_22_220[] =3D { > + 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, > + 0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e, > + 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 > +}; > + > +static const unsigned int ld9040_22_210[] =3D { > + 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, > + 0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a, > + 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 > +}; > + > +static const unsigned int ld9040_22_200[] =3D { > + 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, > + 0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86, > + 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d > +}; > + > +static const unsigned int ld9040_22_190[] =3D { > + 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, > + 0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82, > + 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 > +}; > + > +static const unsigned int ld9040_22_180[] =3D { > + 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, > + 0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f, > + 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 > +}; > + > +static const unsigned int ld9040_22_170[] =3D { > + 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, > + 0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a, > + 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 > +}; > + > +static const unsigned int ld9040_22_160[] =3D { > + 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, > + 0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76, > + 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e > +}; > + > +static const unsigned int ld9040_22_150[] =3D { > + 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, > + 0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72, > + 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a > +}; > + > +static const unsigned int ld9040_22_140[] =3D { > + 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, > + 0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e, > + 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 > +}; > + > +static const unsigned int ld9040_22_130[] =3D { > + 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, > + 0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a, > + 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 > +}; > + > +static const unsigned int ld9040_22_120[] =3D { > + 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, > + 0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65, > + 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c > +}; > + > +static const unsigned int ld9040_22_110[] =3D { > + 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, > + 0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60, > + 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 > +}; > + > +static const unsigned int ld9040_22_100[] =3D { > + 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, > + 0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c, > + 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 > +}; > + > +static const unsigned int ld9040_22_90[] =3D { > + 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, > + 0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56, > + 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d > +}; > + > +static const unsigned int ld9040_22_80[] =3D { > + 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, > + 0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51, > + 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 > +}; > + > +static const unsigned int ld9040_22_70[] =3D { > + 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, > + 0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b, > + 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 > +}; > + > +static const unsigned int ld9040_22_50[] =3D { > + 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, > + 0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d, > + 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 > +}; > + > +struct ld9040_gamma { > + unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; > +}; > + > +static struct ld9040_gamma gamma_table =3D { > + .gamma_22_table[0] =3D (unsigned int *)&ld9040_22_50, > + .gamma_22_table[1] =3D (unsigned int *)&ld9040_22_70, > + .gamma_22_table[2] =3D (unsigned int *)&ld9040_22_80, > + .gamma_22_table[3] =3D (unsigned int *)&ld9040_22_90, > + .gamma_22_table[4] =3D (unsigned int *)&ld9040_22_100, > + .gamma_22_table[5] =3D (unsigned int *)&ld9040_22_110, > + .gamma_22_table[6] =3D (unsigned int *)&ld9040_22_120, > + .gamma_22_table[7] =3D (unsigned int *)&ld9040_22_130, > + .gamma_22_table[8] =3D (unsigned int *)&ld9040_22_140, > + .gamma_22_table[9] =3D (unsigned int *)&ld9040_22_150, > + .gamma_22_table[10] =3D (unsigned int *)&ld9040_22_160, > + .gamma_22_table[11] =3D (unsigned int *)&ld9040_22_170, > + .gamma_22_table[12] =3D (unsigned int *)&ld9040_22_180, > + .gamma_22_table[13] =3D (unsigned int *)&ld9040_22_190, > + .gamma_22_table[14] =3D (unsigned int *)&ld9040_22_200, > + .gamma_22_table[15] =3D (unsigned int *)&ld9040_22_210, > + .gamma_22_table[16] =3D (unsigned int *)&ld9040_22_220, > + .gamma_22_table[17] =3D (unsigned int *)&ld9040_22_230, > + .gamma_22_table[18] =3D (unsigned int *)&ld9040_22_240, > + .gamma_22_table[19] =3D (unsigned int *)&ld9040_22_250, > + .gamma_22_table[20] =3D (unsigned int *)&ld9040_22_260, > + .gamma_22_table[21] =3D (unsigned int *)&ld9040_22_270, > + .gamma_22_table[22] =3D (unsigned int *)&ld9040_22_280, > + .gamma_22_table[23] =3D (unsigned int *)&ld9040_22_290, > + .gamma_22_table[24] =3D (unsigned int *)&ld9040_22_300, > +}; > + > +#endif > +