2011-03-23 02:30:18 +03:00
/*
* ld9040 AMOLED LCD panel driver .
*
* Copyright ( c ) 2011 Samsung Electronics
* Author : Donghwa Lee < dh09 . lee @ samsung . com >
* 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 .
*/
2013-02-22 04:43:19 +04:00
# include <linux/backlight.h>
2011-03-23 02:30:18 +03:00
# include <linux/delay.h>
2013-02-22 04:43:19 +04:00
# include <linux/fb.h>
2011-03-23 02:30:18 +03:00
# include <linux/gpio.h>
# include <linux/interrupt.h>
2013-02-22 04:43:19 +04:00
# include <linux/irq.h>
2011-03-23 02:30:18 +03:00
# include <linux/kernel.h>
# include <linux/lcd.h>
2011-07-04 00:17:28 +04:00
# include <linux/module.h>
2012-01-11 03:09:15 +04:00
# include <linux/regulator/consumer.h>
2013-02-22 04:43:19 +04:00
# include <linux/spi/spi.h>
# include <linux/wait.h>
2011-03-23 02:30:18 +03:00
# 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
struct ld9040 {
struct device * dev ;
struct spi_device * spi ;
unsigned int power ;
unsigned int current_brightness ;
struct lcd_device * ld ;
struct backlight_device * bd ;
struct lcd_platform_data * lcd_pd ;
2012-01-11 03:09:15 +04:00
struct mutex lock ;
bool enabled ;
} ;
static struct regulator_bulk_data supplies [ ] = {
{ . supply = " vdd3 " , } ,
{ . supply = " vci " , } ,
2011-03-23 02:30:18 +03:00
} ;
2012-01-11 03:09:15 +04:00
static void ld9040_regulator_enable ( struct ld9040 * lcd )
{
int ret = 0 ;
struct lcd_platform_data * pd = NULL ;
pd = lcd - > lcd_pd ;
mutex_lock ( & lcd - > lock ) ;
if ( ! lcd - > enabled ) {
ret = regulator_bulk_enable ( ARRAY_SIZE ( supplies ) , supplies ) ;
if ( ret )
goto out ;
lcd - > enabled = true ;
}
2013-02-22 04:43:15 +04:00
msleep ( pd - > power_on_delay ) ;
2012-01-11 03:09:15 +04:00
out :
mutex_unlock ( & lcd - > lock ) ;
}
static void ld9040_regulator_disable ( struct ld9040 * lcd )
{
int ret = 0 ;
mutex_lock ( & lcd - > lock ) ;
if ( lcd - > enabled ) {
ret = regulator_bulk_disable ( ARRAY_SIZE ( supplies ) , supplies ) ;
if ( ret )
goto out ;
lcd - > enabled = false ;
}
out :
mutex_unlock ( & lcd - > lock ) ;
}
2011-03-23 02:30:18 +03:00
static const unsigned short seq_swreset [ ] = {
0x01 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_user_setting [ ] = {
0xF0 , 0x5A ,
DATA_ONLY , 0x5A ,
ENDDEF , 0x00
} ;
static const unsigned short seq_elvss_on [ ] = {
0xB1 , 0x0D ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x16 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_gtcon [ ] = {
0xF7 , 0x09 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_panel_condition [ ] = {
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 [ ] = {
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 [ ] = {
0xFB , 0x02 ,
DATA_ONLY , 0x5A ,
ENDDEF , 0x00
} ;
static const unsigned short seq_gamma_start [ ] = {
0xF9 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_apon [ ] = {
0xF3 , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x0A ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_display_ctrl [ ] = {
0xF2 , 0x02 ,
DATA_ONLY , 0x08 ,
DATA_ONLY , 0x08 ,
DATA_ONLY , 0x10 ,
DATA_ONLY , 0x10 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_manual_pwr [ ] = {
0xB0 , 0x04 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_pwr_ctrl [ ] = {
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_sleep_out [ ] = {
0x11 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_sleep_in [ ] = {
0x10 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_display_on [ ] = {
0x29 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_display_off [ ] = {
0x28 , COMMAND_ONLY ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vci1_1st_en [ ] = {
0xF3 , 0x10 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vl1_en [ ] = {
0xF3 , 0x11 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vl2_en [ ] = {
0xF3 , 0x13 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vci1_2nd_en [ ] = {
0xF3 , 0x33 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vl3_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vreg1_amp_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0x01 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vgh_amp_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0x11 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vgl_amp_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0x31 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x02 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vmos_amp_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0xB1 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x03 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vint_amp_en [ ] = {
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 [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0xF9 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x03 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_vbl_amp_en [ ] = {
0xF3 , 0x37 ,
DATA_ONLY , 0xFD ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x00 ,
DATA_ONLY , 0x03 ,
ENDDEF , 0x00
} ;
static const unsigned short seq_gam_amp_en [ ] = {
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 [ ] = {
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 [ ] = {
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 [ ] = {
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 [ ] = {
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 = {
. len = 2 ,
. tx_buf = buf ,
} ;
buf [ 0 ] = ( 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 = 0 ;
if ( address ! = DATA_ONLY )
ret = ld9040_spi_write_byte ( lcd , 0x0 , address ) ;
if ( command ! = COMMAND_ONLY )
ret = ld9040_spi_write_byte ( lcd , 0x1 , command ) ;
return ret ;
}
static int ld9040_panel_send_sequence ( struct ld9040 * lcd ,
const unsigned short * wbuf )
{
int ret = 0 , i = 0 ;
while ( ( wbuf [ i ] & DEFMASK ) ! = ENDDEF ) {
if ( ( wbuf [ i ] & DEFMASK ) ! = SLEEPMSEC ) {
ret = ld9040_spi_write ( lcd , wbuf [ i ] , wbuf [ i + 1 ] ) ;
if ( ret )
break ;
2013-02-22 04:43:15 +04:00
} else {
msleep ( wbuf [ i + 1 ] ) ;
}
2011-03-23 02:30:18 +03:00
i + = 2 ;
}
return ret ;
}
static int _ld9040_gamma_ctl ( struct ld9040 * lcd , const unsigned int * gamma )
{
unsigned int i = 0 ;
int ret = 0 ;
/* start gamma table updating. */
ret = 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 = 0 ; i < GAMMA_TABLE_COUNT ; i + + ) {
ret = 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 = 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 )
{
2013-02-22 04:43:18 +04:00
return _ld9040_gamma_ctl ( lcd , gamma_table . gamma_22_table [ gamma ] ) ;
2011-03-23 02:30:18 +03:00
}
static int ld9040_ldi_init ( struct ld9040 * lcd )
{
int ret , i ;
static const unsigned short * init_seq [ ] = {
seq_user_setting ,
seq_panel_condition ,
seq_display_ctrl ,
seq_manual_pwr ,
seq_elvss_on ,
seq_gtcon ,
seq_gamma_set1 ,
seq_gamma_ctrl ,
seq_sleep_out ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( init_seq ) ; i + + ) {
ret = ld9040_panel_send_sequence ( lcd , init_seq [ i ] ) ;
/* workaround: minimum delay time for transferring CMD */
2013-02-22 04:43:15 +04:00
usleep_range ( 300 , 310 ) ;
2011-03-23 02:30:18 +03:00
if ( ret )
break ;
}
return ret ;
}
static int ld9040_ldi_enable ( struct ld9040 * lcd )
{
2013-02-22 04:43:18 +04:00
return ld9040_panel_send_sequence ( lcd , seq_display_on ) ;
2011-03-23 02:30:18 +03:00
}
static int ld9040_ldi_disable ( struct ld9040 * lcd )
{
int ret ;
ret = ld9040_panel_send_sequence ( lcd , seq_display_off ) ;
ret = ld9040_panel_send_sequence ( lcd , seq_sleep_in ) ;
return ret ;
}
2013-02-22 04:43:16 +04:00
static int ld9040_power_is_on ( int power )
{
return power < = FB_BLANK_NORMAL ;
}
2011-03-23 02:30:18 +03:00
static int ld9040_power_on ( struct ld9040 * lcd )
{
int ret = 0 ;
2013-02-22 04:43:16 +04:00
struct lcd_platform_data * pd ;
2011-03-23 02:30:18 +03:00
pd = lcd - > lcd_pd ;
2012-01-11 03:09:15 +04:00
/* lcd power on */
ld9040_regulator_enable ( lcd ) ;
2011-03-23 02:30:18 +03:00
if ( ! pd - > reset ) {
dev_err ( lcd - > dev , " reset is NULL. \n " ) ;
2013-02-22 04:43:17 +04:00
return - EINVAL ;
2011-03-23 02:30:18 +03:00
}
2014-08-27 05:11:52 +04:00
pd - > reset ( lcd - > ld ) ;
msleep ( pd - > reset_delay ) ;
2011-03-23 02:30:18 +03:00
ret = ld9040_ldi_init ( lcd ) ;
if ( ret ) {
dev_err ( lcd - > dev , " failed to initialize ldi. \n " ) ;
return ret ;
}
ret = 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 )
{
2013-02-22 04:43:16 +04:00
int ret ;
struct lcd_platform_data * pd ;
2011-03-23 02:30:18 +03:00
pd = lcd - > lcd_pd ;
ret = ld9040_ldi_disable ( lcd ) ;
if ( ret ) {
dev_err ( lcd - > dev , " lcd setting failed. \n " ) ;
return - EIO ;
}
2013-02-22 04:43:15 +04:00
msleep ( pd - > power_off_delay ) ;
2011-03-23 02:30:18 +03:00
2012-01-11 03:09:15 +04:00
/* lcd power off */
ld9040_regulator_disable ( lcd ) ;
2011-03-23 02:30:18 +03:00
return 0 ;
}
static int ld9040_power ( struct ld9040 * lcd , int power )
{
int ret = 0 ;
2013-02-22 04:43:16 +04:00
if ( ld9040_power_is_on ( power ) & & ! ld9040_power_is_on ( lcd - > power ) )
2011-03-23 02:30:18 +03:00
ret = ld9040_power_on ( lcd ) ;
2013-02-22 04:43:16 +04:00
else if ( ! ld9040_power_is_on ( power ) & & ld9040_power_is_on ( lcd - > power ) )
2011-03-23 02:30:18 +03:00
ret = ld9040_power_off ( lcd ) ;
if ( ! ret )
lcd - > power = power ;
return ret ;
}
static int ld9040_set_power ( struct lcd_device * ld , int power )
{
struct ld9040 * lcd = lcd_get_data ( ld ) ;
if ( power ! = FB_BLANK_UNBLANK & & power ! = FB_BLANK_POWERDOWN & &
power ! = 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 = lcd_get_data ( ld ) ;
return lcd - > power ;
}
static int ld9040_set_brightness ( struct backlight_device * bd )
{
int ret = 0 , brightness = bd - > props . brightness ;
struct ld9040 * lcd = 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 = 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 = {
. set_power = ld9040_set_power ,
. get_power = ld9040_get_power ,
} ;
static const struct backlight_ops ld9040_backlight_ops = {
. update_status = ld9040_set_brightness ,
} ;
static int ld9040_probe ( struct spi_device * spi )
{
int ret = 0 ;
struct ld9040 * lcd = NULL ;
struct lcd_device * ld = NULL ;
struct backlight_device * bd = NULL ;
2011-07-26 04:12:01 +04:00
struct backlight_properties props ;
2011-03-23 02:30:18 +03:00
2012-05-30 02:07:23 +04:00
lcd = devm_kzalloc ( & spi - > dev , sizeof ( struct ld9040 ) , GFP_KERNEL ) ;
2011-03-23 02:30:18 +03:00
if ( ! lcd )
return - ENOMEM ;
/* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
spi - > bits_per_word = 9 ;
ret = spi_setup ( spi ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " spi setup failed. \n " ) ;
2012-05-30 02:07:23 +04:00
return ret ;
2011-03-23 02:30:18 +03:00
}
lcd - > spi = spi ;
lcd - > dev = & spi - > dev ;
2013-11-13 03:09:04 +04:00
lcd - > lcd_pd = dev_get_platdata ( & spi - > dev ) ;
2011-03-23 02:30:18 +03:00
if ( ! lcd - > lcd_pd ) {
dev_err ( & spi - > dev , " platform data is NULL. \n " ) ;
2013-02-22 04:43:17 +04:00
return - EINVAL ;
2011-03-23 02:30:18 +03:00
}
2012-01-11 03:09:15 +04:00
mutex_init ( & lcd - > lock ) ;
2013-02-22 04:43:55 +04:00
ret = devm_regulator_bulk_get ( lcd - > dev , ARRAY_SIZE ( supplies ) , supplies ) ;
2012-01-11 03:09:15 +04:00
if ( ret ) {
dev_err ( lcd - > dev , " Failed to get regulators: %d \n " , ret ) ;
2012-05-30 02:07:23 +04:00
return ret ;
2012-01-11 03:09:15 +04:00
}
2013-11-13 03:09:33 +04:00
ld = devm_lcd_device_register ( & spi - > dev , " ld9040 " , & spi - > dev , lcd ,
& ld9040_lcd_ops ) ;
2013-02-22 04:43:55 +04:00
if ( IS_ERR ( ld ) )
return PTR_ERR ( ld ) ;
2011-03-23 02:30:18 +03:00
lcd - > ld = ld ;
2011-07-26 04:12:01 +04:00
memset ( & props , 0 , sizeof ( struct backlight_properties ) ) ;
props . type = BACKLIGHT_RAW ;
props . max_brightness = MAX_BRIGHTNESS ;
2013-11-13 03:09:33 +04:00
bd = devm_backlight_device_register ( & spi - > dev , " ld9040-bl " , & spi - > dev ,
lcd , & ld9040_backlight_ops , & props ) ;
if ( IS_ERR ( bd ) )
return PTR_ERR ( bd ) ;
2011-03-23 02:30:18 +03:00
bd - > props . brightness = MAX_BRIGHTNESS ;
lcd - > bd = bd ;
/*
* 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 = FB_BLANK_POWERDOWN ;
ld9040_power ( lcd , FB_BLANK_UNBLANK ) ;
2013-02-22 04:43:16 +04:00
} else {
2011-03-23 02:30:18 +03:00
lcd - > power = FB_BLANK_UNBLANK ;
2013-02-22 04:43:16 +04:00
}
2011-03-23 02:30:18 +03:00
2013-02-22 04:43:33 +04:00
spi_set_drvdata ( spi , lcd ) ;
2011-03-23 02:30:18 +03:00
dev_info ( & spi - > dev , " ld9040 panel driver has been probed. \n " ) ;
return 0 ;
}
2012-11-19 22:26:34 +04:00
static int ld9040_remove ( struct spi_device * spi )
2011-03-23 02:30:18 +03:00
{
2013-02-22 04:43:33 +04:00
struct ld9040 * lcd = spi_get_drvdata ( spi ) ;
2011-03-23 02:30:18 +03:00
ld9040_power ( lcd , FB_BLANK_POWERDOWN ) ;
return 0 ;
}
2013-04-30 03:17:35 +04:00
# ifdef CONFIG_PM_SLEEP
static int ld9040_suspend ( struct device * dev )
2011-03-23 02:30:18 +03:00
{
2013-04-30 03:17:35 +04:00
struct ld9040 * lcd = dev_get_drvdata ( dev ) ;
2011-03-23 02:30:18 +03:00
2013-04-30 03:17:35 +04:00
dev_dbg ( dev , " lcd->power = %d \n " , lcd - > power ) ;
2011-03-23 02:30:18 +03:00
/*
* when lcd panel is suspend , lcd panel becomes off
* regardless of status .
*/
2013-02-22 04:43:18 +04:00
return ld9040_power ( lcd , FB_BLANK_POWERDOWN ) ;
2011-03-23 02:30:18 +03:00
}
2013-04-30 03:17:35 +04:00
static int ld9040_resume ( struct device * dev )
2011-03-23 02:30:18 +03:00
{
2013-04-30 03:17:35 +04:00
struct ld9040 * lcd = dev_get_drvdata ( dev ) ;
2011-03-23 02:30:18 +03:00
lcd - > power = FB_BLANK_POWERDOWN ;
2013-02-22 04:43:18 +04:00
return ld9040_power ( lcd , FB_BLANK_UNBLANK ) ;
2011-03-23 02:30:18 +03:00
}
# endif
2013-04-30 03:17:35 +04:00
static SIMPLE_DEV_PM_OPS ( ld9040_pm_ops , ld9040_suspend , ld9040_resume ) ;
2011-03-23 02:30:18 +03:00
/* Power down all displays on reboot, poweroff or halt. */
static void ld9040_shutdown ( struct spi_device * spi )
{
2013-02-22 04:43:33 +04:00
struct ld9040 * lcd = spi_get_drvdata ( spi ) ;
2011-03-23 02:30:18 +03:00
ld9040_power ( lcd , FB_BLANK_POWERDOWN ) ;
}
static struct spi_driver ld9040_driver = {
. driver = {
. name = " ld9040 " ,
. owner = THIS_MODULE ,
2013-04-30 03:17:35 +04:00
. pm = & ld9040_pm_ops ,
2011-03-23 02:30:18 +03:00
} ,
. probe = ld9040_probe ,
2012-11-19 22:21:09 +04:00
. remove = ld9040_remove ,
2011-03-23 02:30:18 +03:00
. shutdown = ld9040_shutdown ,
} ;
2012-03-24 02:01:59 +04:00
module_spi_driver ( ld9040_driver ) ;
2011-03-23 02:30:18 +03:00
MODULE_AUTHOR ( " Donghwa Lee <dh09.lee@samsung.com> " ) ;
MODULE_DESCRIPTION ( " ld9040 LCD Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;