2012-09-25 00:25:28 +04:00
/*
* tps65217_bl . c
*
* TPS65217 backlight driver
*
* Copyright ( C ) 2012 Matthias Kaehlcke
* Author : Matthias Kaehlcke < matthias @ kaehlcke . net >
*
* 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 version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/backlight.h>
# include <linux/err.h>
# include <linux/fb.h>
# include <linux/mfd/tps65217.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
struct tps65217_bl {
struct tps65217 * tps ;
struct device * dev ;
struct backlight_device * bl ;
bool is_enabled ;
} ;
static int tps65217_bl_enable ( struct tps65217_bl * tps65217_bl )
{
int rc ;
rc = tps65217_set_bits ( tps65217_bl - > tps , TPS65217_REG_WLEDCTRL1 ,
TPS65217_WLEDCTRL1_ISINK_ENABLE ,
TPS65217_WLEDCTRL1_ISINK_ENABLE , TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to enable backlight: %d \n " , rc ) ;
return rc ;
}
tps65217_bl - > is_enabled = true ;
dev_dbg ( tps65217_bl - > dev , " backlight enabled \n " ) ;
return 0 ;
}
static int tps65217_bl_disable ( struct tps65217_bl * tps65217_bl )
{
int rc ;
rc = tps65217_clear_bits ( tps65217_bl - > tps ,
TPS65217_REG_WLEDCTRL1 ,
TPS65217_WLEDCTRL1_ISINK_ENABLE ,
TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to disable backlight: %d \n " , rc ) ;
return rc ;
}
tps65217_bl - > is_enabled = false ;
dev_dbg ( tps65217_bl - > dev , " backlight disabled \n " ) ;
return 0 ;
}
static int tps65217_bl_update_status ( struct backlight_device * bl )
{
struct tps65217_bl * tps65217_bl = bl_get_data ( bl ) ;
int rc ;
int brightness = bl - > props . brightness ;
if ( bl - > props . state & BL_CORE_SUSPENDED )
brightness = 0 ;
if ( ( bl - > props . power ! = FB_BLANK_UNBLANK ) | |
( bl - > props . fb_blank ! = FB_BLANK_UNBLANK ) )
/* framebuffer in low power mode or blanking active */
brightness = 0 ;
if ( brightness > 0 ) {
rc = tps65217_reg_write ( tps65217_bl - > tps ,
TPS65217_REG_WLEDCTRL2 ,
brightness - 1 ,
TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to set brightness level: %d \n " , rc ) ;
return rc ;
}
dev_dbg ( tps65217_bl - > dev , " brightness set to %d \n " , brightness ) ;
if ( ! tps65217_bl - > is_enabled )
rc = tps65217_bl_enable ( tps65217_bl ) ;
} else {
rc = tps65217_bl_disable ( tps65217_bl ) ;
}
return rc ;
}
static const struct backlight_ops tps65217_bl_ops = {
. options = BL_CORE_SUSPENDRESUME ,
. update_status = tps65217_bl_update_status ,
} ;
static int tps65217_bl_hw_init ( struct tps65217_bl * tps65217_bl ,
struct tps65217_bl_pdata * pdata )
{
int rc ;
rc = tps65217_bl_disable ( tps65217_bl ) ;
if ( rc )
return rc ;
switch ( pdata - > isel ) {
case TPS65217_BL_ISET1 :
/* select ISET_1 current level */
rc = tps65217_clear_bits ( tps65217_bl - > tps ,
TPS65217_REG_WLEDCTRL1 ,
TPS65217_WLEDCTRL1_ISEL ,
TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to select ISET1 current level: %d) \n " ,
rc ) ;
return rc ;
}
dev_dbg ( tps65217_bl - > dev , " selected ISET1 current level \n " ) ;
break ;
case TPS65217_BL_ISET2 :
/* select ISET2 current level */
rc = tps65217_set_bits ( tps65217_bl - > tps , TPS65217_REG_WLEDCTRL1 ,
TPS65217_WLEDCTRL1_ISEL ,
TPS65217_WLEDCTRL1_ISEL , TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to select ISET2 current level: %d \n " ,
rc ) ;
return rc ;
}
dev_dbg ( tps65217_bl - > dev , " selected ISET2 current level \n " ) ;
break ;
default :
dev_err ( tps65217_bl - > dev ,
" invalid value for current level: %d \n " , pdata - > isel ) ;
return - EINVAL ;
}
/* set PWM frequency */
rc = tps65217_set_bits ( tps65217_bl - > tps ,
TPS65217_REG_WLEDCTRL1 ,
TPS65217_WLEDCTRL1_FDIM_MASK ,
pdata - > fdim ,
TPS65217_PROTECT_NONE ) ;
if ( rc ) {
dev_err ( tps65217_bl - > dev ,
" failed to select PWM dimming frequency: %d \n " ,
rc ) ;
return rc ;
}
return 0 ;
}
# ifdef CONFIG_OF
static struct tps65217_bl_pdata *
tps65217_bl_parse_dt ( struct platform_device * pdev )
{
struct tps65217 * tps = dev_get_drvdata ( pdev - > dev . parent ) ;
2017-11-20 13:45:46 +03:00
struct device_node * node ;
2012-09-25 00:25:28 +04:00
struct tps65217_bl_pdata * pdata , * err ;
u32 val ;
2017-11-20 13:45:46 +03:00
node = of_get_child_by_name ( tps - > dev - > of_node , " backlight " ) ;
2012-09-25 00:25:28 +04:00
if ( ! node )
return ERR_PTR ( - ENODEV ) ;
pdata = devm_kzalloc ( & pdev - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata ) {
err = ERR_PTR ( - ENOMEM ) ;
goto err ;
}
pdata - > isel = TPS65217_BL_ISET1 ;
if ( ! of_property_read_u32 ( node , " isel " , & val ) ) {
if ( val < TPS65217_BL_ISET1 | |
val > TPS65217_BL_ISET2 ) {
dev_err ( & pdev - > dev ,
" invalid 'isel' value in the device tree \n " ) ;
err = ERR_PTR ( - EINVAL ) ;
goto err ;
}
pdata - > isel = val ;
}
pdata - > fdim = TPS65217_BL_FDIM_200HZ ;
if ( ! of_property_read_u32 ( node , " fdim " , & val ) ) {
switch ( val ) {
case 100 :
pdata - > fdim = TPS65217_BL_FDIM_100HZ ;
break ;
case 200 :
pdata - > fdim = TPS65217_BL_FDIM_200HZ ;
break ;
case 500 :
pdata - > fdim = TPS65217_BL_FDIM_500HZ ;
break ;
case 1000 :
pdata - > fdim = TPS65217_BL_FDIM_1000HZ ;
break ;
default :
dev_err ( & pdev - > dev ,
" invalid 'fdim' value in the device tree \n " ) ;
err = ERR_PTR ( - EINVAL ) ;
goto err ;
}
}
2013-04-30 03:18:08 +04:00
if ( ! of_property_read_u32 ( node , " default-brightness " , & val ) ) {
2017-10-09 00:56:48 +03:00
if ( val > 100 ) {
2013-04-30 03:18:08 +04:00
dev_err ( & pdev - > dev ,
" invalid 'default-brightness' value in the device tree \n " ) ;
err = ERR_PTR ( - EINVAL ) ;
goto err ;
}
pdata - > dft_brightness = val ;
}
2012-09-25 00:25:28 +04:00
of_node_put ( node ) ;
return pdata ;
err :
of_node_put ( node ) ;
return err ;
}
# else
static struct tps65217_bl_pdata *
tps65217_bl_parse_dt ( struct platform_device * pdev )
{
return NULL ;
}
# endif
static int tps65217_bl_probe ( struct platform_device * pdev )
{
int rc ;
struct tps65217 * tps = dev_get_drvdata ( pdev - > dev . parent ) ;
struct tps65217_bl * tps65217_bl ;
struct tps65217_bl_pdata * pdata ;
struct backlight_properties bl_props ;
2017-08-30 12:29:10 +03:00
pdata = tps65217_bl_parse_dt ( pdev ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
2012-09-25 00:25:28 +04:00
tps65217_bl = devm_kzalloc ( & pdev - > dev , sizeof ( * tps65217_bl ) ,
GFP_KERNEL ) ;
2014-04-04 01:49:06 +04:00
if ( tps65217_bl = = NULL )
2012-09-25 00:25:28 +04:00
return - ENOMEM ;
tps65217_bl - > tps = tps ;
tps65217_bl - > dev = & pdev - > dev ;
tps65217_bl - > is_enabled = false ;
rc = tps65217_bl_hw_init ( tps65217_bl , pdata ) ;
if ( rc )
return rc ;
memset ( & bl_props , 0 , sizeof ( struct backlight_properties ) ) ;
bl_props . type = BACKLIGHT_RAW ;
bl_props . max_brightness = 100 ;
2013-11-13 03:09:24 +04:00
tps65217_bl - > bl = devm_backlight_device_register ( & pdev - > dev , pdev - > name ,
2012-09-25 00:25:28 +04:00
tps65217_bl - > dev , tps65217_bl ,
& tps65217_bl_ops , & bl_props ) ;
if ( IS_ERR ( tps65217_bl - > bl ) ) {
dev_err ( tps65217_bl - > dev ,
" registration of backlight device failed: %d \n " , rc ) ;
return PTR_ERR ( tps65217_bl - > bl ) ;
}
2013-04-30 03:18:08 +04:00
tps65217_bl - > bl - > props . brightness = pdata - > dft_brightness ;
backlight_update_status ( tps65217_bl - > bl ) ;
2012-09-30 14:28:26 +04:00
platform_set_drvdata ( pdev , tps65217_bl ) ;
2012-09-25 00:25:28 +04:00
return 0 ;
}
2015-11-29 19:29:46 +03:00
# ifdef CONFIG_OF
static const struct of_device_id tps65217_bl_of_match [ ] = {
{ . compatible = " ti,tps65217-bl " , } ,
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , tps65217_bl_of_match ) ;
# endif
2012-09-25 00:25:28 +04:00
static struct platform_driver tps65217_bl_driver = {
. probe = tps65217_bl_probe ,
. driver = {
. name = " tps65217-bl " ,
2015-11-29 19:29:46 +03:00
. of_match_table = of_match_ptr ( tps65217_bl_of_match ) ,
2012-09-25 00:25:28 +04:00
} ,
} ;
2012-09-30 14:28:26 +04:00
module_platform_driver ( tps65217_bl_driver ) ;
2012-09-25 00:25:28 +04:00
MODULE_DESCRIPTION ( " TPS65217 Backlight driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Matthias Kaehlcke <matthias@kaehlcke.net> " ) ;