2013-07-04 21:13:24 +02:00
/*
* gpio_backlight . c - Simple GPIO - controlled backlight
*
* 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/backlight.h>
# include <linux/err.h>
# include <linux/fb.h>
# include <linux/gpio.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
2014-02-27 15:28:33 +01:00
# include <linux/of.h>
# include <linux/of_gpio.h>
2013-07-04 21:13:24 +02:00
# include <linux/platform_data/gpio_backlight.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
struct gpio_backlight {
struct device * dev ;
struct device * fbdev ;
int gpio ;
int active ;
2014-02-27 15:28:33 +01:00
int def_value ;
2013-07-04 21:13:24 +02:00
} ;
static int gpio_backlight_update_status ( struct backlight_device * bl )
{
struct gpio_backlight * gbl = bl_get_data ( bl ) ;
int brightness = bl - > props . brightness ;
if ( bl - > props . power ! = FB_BLANK_UNBLANK | |
bl - > props . fb_blank ! = FB_BLANK_UNBLANK | |
bl - > props . state & ( BL_CORE_SUSPENDED | BL_CORE_FBBLANK ) )
brightness = 0 ;
2014-05-08 18:24:55 -07:00
gpio_set_value_cansleep ( gbl - > gpio ,
brightness ? gbl - > active : ! gbl - > active ) ;
2013-07-04 21:13:24 +02:00
return 0 ;
}
static int gpio_backlight_check_fb ( struct backlight_device * bl ,
struct fb_info * info )
{
struct gpio_backlight * gbl = bl_get_data ( bl ) ;
return gbl - > fbdev = = NULL | | gbl - > fbdev = = info - > dev ;
}
static const struct backlight_ops gpio_backlight_ops = {
. options = BL_CORE_SUSPENDRESUME ,
. update_status = gpio_backlight_update_status ,
. check_fb = gpio_backlight_check_fb ,
} ;
2014-02-27 15:28:33 +01:00
static int gpio_backlight_probe_dt ( struct platform_device * pdev ,
struct gpio_backlight * gbl )
{
struct device_node * np = pdev - > dev . of_node ;
enum of_gpio_flags gpio_flags ;
gbl - > gpio = of_get_gpio_flags ( np , 0 , & gpio_flags ) ;
if ( ! gpio_is_valid ( gbl - > gpio ) ) {
if ( gbl - > gpio ! = - EPROBE_DEFER ) {
dev_err ( & pdev - > dev ,
" Error: The gpios parameter is missing or invalid. \n " ) ;
}
return gbl - > gpio ;
}
gbl - > active = ( gpio_flags & OF_GPIO_ACTIVE_LOW ) ? 0 : 1 ;
gbl - > def_value = of_property_read_bool ( np , " default-on " ) ;
return 0 ;
}
2013-07-04 21:13:24 +02:00
static int gpio_backlight_probe ( struct platform_device * pdev )
{
2013-11-12 15:09:04 -08:00
struct gpio_backlight_platform_data * pdata =
dev_get_platdata ( & pdev - > dev ) ;
2013-07-04 21:13:24 +02:00
struct backlight_properties props ;
struct backlight_device * bl ;
struct gpio_backlight * gbl ;
2014-02-27 15:28:33 +01:00
struct device_node * np = pdev - > dev . of_node ;
2015-10-23 16:44:43 -07:00
unsigned long flags = GPIOF_DIR_OUT ;
2013-07-04 21:13:24 +02:00
int ret ;
2014-02-27 15:28:33 +01:00
if ( ! pdata & & ! np ) {
dev_err ( & pdev - > dev ,
" failed to find platform data or device tree node. \n " ) ;
2013-07-04 21:13:24 +02:00
return - ENODEV ;
}
gbl = devm_kzalloc ( & pdev - > dev , sizeof ( * gbl ) , GFP_KERNEL ) ;
if ( gbl = = NULL )
return - ENOMEM ;
gbl - > dev = & pdev - > dev ;
2014-02-27 15:28:33 +01:00
if ( np ) {
ret = gpio_backlight_probe_dt ( pdev , gbl ) ;
if ( ret )
return ret ;
} else {
gbl - > fbdev = pdata - > fbdev ;
gbl - > gpio = pdata - > gpio ;
gbl - > active = pdata - > active_low ? 0 : 1 ;
gbl - > def_value = pdata - > def_value ;
}
2013-07-04 21:13:24 +02:00
2015-10-23 16:44:43 -07:00
if ( gbl - > active )
flags | = gbl - > def_value ? GPIOF_INIT_HIGH : GPIOF_INIT_LOW ;
else
flags | = gbl - > def_value ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH ;
ret = devm_gpio_request_one ( gbl - > dev , gbl - > gpio , flags ,
2014-02-27 15:28:33 +01:00
pdata ? pdata - > name : " backlight " ) ;
2013-07-04 21:13:24 +02:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " unable to request GPIO \n " ) ;
return ret ;
}
memset ( & props , 0 , sizeof ( props ) ) ;
props . type = BACKLIGHT_RAW ;
props . max_brightness = 1 ;
2013-11-12 15:09:16 -08:00
bl = devm_backlight_device_register ( & pdev - > dev , dev_name ( & pdev - > dev ) ,
& pdev - > dev , gbl , & gpio_backlight_ops ,
& props ) ;
2013-07-04 21:13:24 +02:00
if ( IS_ERR ( bl ) ) {
dev_err ( & pdev - > dev , " failed to register backlight \n " ) ;
return PTR_ERR ( bl ) ;
}
2014-02-27 15:28:33 +01:00
bl - > props . brightness = gbl - > def_value ;
2013-07-04 21:13:24 +02:00
backlight_update_status ( bl ) ;
platform_set_drvdata ( pdev , bl ) ;
return 0 ;
}
2014-02-27 15:28:33 +01:00
# ifdef CONFIG_OF
static struct of_device_id gpio_backlight_of_match [ ] = {
{ . compatible = " gpio-backlight " } ,
{ /* sentinel */ }
} ;
2015-04-15 17:21:24 -07:00
MODULE_DEVICE_TABLE ( of , gpio_backlight_of_match ) ;
2014-02-27 15:28:33 +01:00
# endif
2013-07-04 21:13:24 +02:00
static struct platform_driver gpio_backlight_driver = {
. driver = {
. name = " gpio-backlight " ,
2014-02-27 15:28:33 +01:00
. of_match_table = of_match_ptr ( gpio_backlight_of_match ) ,
2013-07-04 21:13:24 +02:00
} ,
. probe = gpio_backlight_probe ,
} ;
module_platform_driver ( gpio_backlight_driver ) ;
MODULE_AUTHOR ( " Laurent Pinchart <laurent.pinchart@ideasonboard.com> " ) ;
MODULE_DESCRIPTION ( " GPIO-based Backlight Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:gpio-backlight " ) ;