2008-04-14 12:35:08 +04:00
/*
* linux / drivers / video / backlight / pwm_bl . c
*
* simple PWM based backlight control , board code has to setup
* 1 ) pin configuration so PWM waveforms can output
* 2 ) platform_data casts to the PWM id ( 0 / 1 / 2 / 3 on PXA )
*
* 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/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/platform_device.h>
# include <linux/fb.h>
# include <linux/backlight.h>
# include <linux/err.h>
# include <linux/pwm.h>
# include <linux/pwm_backlight.h>
struct pwm_bl_data {
struct pwm_device * pwm ;
unsigned int period ;
2008-05-22 17:18:40 +04:00
int ( * notify ) ( int brightness ) ;
2008-04-14 12:35:08 +04:00
} ;
static int pwm_backlight_update_status ( struct backlight_device * bl )
{
struct pwm_bl_data * pb = dev_get_drvdata ( & bl - > dev ) ;
int brightness = bl - > props . brightness ;
int max = bl - > props . max_brightness ;
if ( bl - > props . power ! = FB_BLANK_UNBLANK )
brightness = 0 ;
if ( bl - > props . fb_blank ! = FB_BLANK_UNBLANK )
brightness = 0 ;
2008-05-22 17:18:40 +04:00
if ( pb - > notify )
brightness = pb - > notify ( brightness ) ;
2008-04-14 12:35:08 +04:00
if ( brightness = = 0 ) {
pwm_config ( pb - > pwm , 0 , pb - > period ) ;
pwm_disable ( pb - > pwm ) ;
} else {
pwm_config ( pb - > pwm , brightness * pb - > period / max , pb - > period ) ;
pwm_enable ( pb - > pwm ) ;
}
return 0 ;
}
static int pwm_backlight_get_brightness ( struct backlight_device * bl )
{
return bl - > props . brightness ;
}
static struct backlight_ops pwm_backlight_ops = {
. update_status = pwm_backlight_update_status ,
. get_brightness = pwm_backlight_get_brightness ,
} ;
static int pwm_backlight_probe ( struct platform_device * pdev )
{
struct platform_pwm_backlight_data * data = pdev - > dev . platform_data ;
struct backlight_device * bl ;
struct pwm_bl_data * pb ;
2008-05-22 17:18:40 +04:00
int ret ;
2008-04-14 12:35:08 +04:00
2008-08-06 00:01:22 +04:00
if ( ! data ) {
dev_err ( & pdev - > dev , " failed to find platform data \n " ) ;
2008-04-14 12:35:08 +04:00
return - EINVAL ;
2008-08-06 00:01:22 +04:00
}
2008-04-14 12:35:08 +04:00
2008-05-22 17:18:40 +04:00
if ( data - > init ) {
ret = data - > init ( & pdev - > dev ) ;
if ( ret < 0 )
return ret ;
}
2008-04-14 12:35:08 +04:00
pb = kzalloc ( sizeof ( * pb ) , GFP_KERNEL ) ;
2008-05-22 17:18:40 +04:00
if ( ! pb ) {
2008-08-06 00:01:22 +04:00
dev_err ( & pdev - > dev , " no memory for state \n " ) ;
2008-05-22 17:18:40 +04:00
ret = - ENOMEM ;
goto err_alloc ;
}
2008-04-14 12:35:08 +04:00
pb - > period = data - > pwm_period_ns ;
2008-05-22 17:18:40 +04:00
pb - > notify = data - > notify ;
2008-04-14 12:35:08 +04:00
pb - > pwm = pwm_request ( data - > pwm_id , " backlight " ) ;
2008-07-01 17:18:27 +04:00
if ( IS_ERR ( pb - > pwm ) ) {
2008-04-14 12:35:08 +04:00
dev_err ( & pdev - > dev , " unable to request PWM for backlight \n " ) ;
2008-07-01 17:18:27 +04:00
ret = PTR_ERR ( pb - > pwm ) ;
2008-05-22 17:18:40 +04:00
goto err_pwm ;
2008-08-06 00:01:22 +04:00
} else
dev_dbg ( & pdev - > dev , " got pwm for backlight \n " ) ;
2008-04-14 12:35:08 +04:00
bl = backlight_device_register ( pdev - > name , & pdev - > dev ,
pb , & pwm_backlight_ops ) ;
if ( IS_ERR ( bl ) ) {
dev_err ( & pdev - > dev , " failed to register backlight \n " ) ;
2008-05-22 17:18:40 +04:00
ret = PTR_ERR ( bl ) ;
goto err_bl ;
2008-04-14 12:35:08 +04:00
}
bl - > props . max_brightness = data - > max_brightness ;
bl - > props . brightness = data - > dft_brightness ;
backlight_update_status ( bl ) ;
platform_set_drvdata ( pdev , bl ) ;
return 0 ;
2008-05-22 17:18:40 +04:00
err_bl :
pwm_free ( pb - > pwm ) ;
err_pwm :
kfree ( pb ) ;
err_alloc :
if ( data - > exit )
data - > exit ( & pdev - > dev ) ;
return ret ;
2008-04-14 12:35:08 +04:00
}
static int pwm_backlight_remove ( struct platform_device * pdev )
{
2008-05-22 17:18:40 +04:00
struct platform_pwm_backlight_data * data = pdev - > dev . platform_data ;
2008-04-14 12:35:08 +04:00
struct backlight_device * bl = platform_get_drvdata ( pdev ) ;
struct pwm_bl_data * pb = dev_get_drvdata ( & bl - > dev ) ;
backlight_device_unregister ( bl ) ;
pwm_config ( pb - > pwm , 0 , pb - > period ) ;
pwm_disable ( pb - > pwm ) ;
pwm_free ( pb - > pwm ) ;
kfree ( pb ) ;
2008-05-22 17:18:40 +04:00
if ( data - > exit )
data - > exit ( & pdev - > dev ) ;
2008-04-14 12:35:08 +04:00
return 0 ;
}
# ifdef CONFIG_PM
static int pwm_backlight_suspend ( struct platform_device * pdev ,
pm_message_t state )
{
struct backlight_device * bl = platform_get_drvdata ( pdev ) ;
struct pwm_bl_data * pb = dev_get_drvdata ( & bl - > dev ) ;
pwm_config ( pb - > pwm , 0 , pb - > period ) ;
pwm_disable ( pb - > pwm ) ;
return 0 ;
}
static int pwm_backlight_resume ( struct platform_device * pdev )
{
struct backlight_device * bl = platform_get_drvdata ( pdev ) ;
backlight_update_status ( bl ) ;
return 0 ;
}
# else
# define pwm_backlight_suspend NULL
# define pwm_backlight_resume NULL
# endif
static struct platform_driver pwm_backlight_driver = {
. driver = {
. name = " pwm-backlight " ,
. owner = THIS_MODULE ,
} ,
. probe = pwm_backlight_probe ,
. remove = pwm_backlight_remove ,
. suspend = pwm_backlight_suspend ,
. resume = pwm_backlight_resume ,
} ;
static int __init pwm_backlight_init ( void )
{
return platform_driver_register ( & pwm_backlight_driver ) ;
}
module_init ( pwm_backlight_init ) ;
static void __exit pwm_backlight_exit ( void )
{
platform_driver_unregister ( & pwm_backlight_driver ) ;
}
module_exit ( pwm_backlight_exit ) ;
MODULE_DESCRIPTION ( " PWM based Backlight Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-08-06 00:01:24 +04:00
MODULE_ALIAS ( " platform:pwm-backlight " ) ;