2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2013-07-04 23:13:24 +04:00
/*
* gpio_backlight . c - Simple GPIO - controlled backlight
*/
# include <linux/backlight.h>
# include <linux/err.h>
# include <linux/fb.h>
2017-05-30 14:48:21 +03:00
# include <linux/gpio/consumer.h>
2013-07-04 23:13:24 +04:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
2014-02-27 18:28:33 +04:00
# include <linux/of.h>
2013-07-04 23:13:24 +04:00
# include <linux/platform_data/gpio_backlight.h>
# include <linux/platform_device.h>
2019-06-19 18:21:27 +03:00
# include <linux/property.h>
2013-07-04 23:13:24 +04:00
# include <linux/slab.h>
struct gpio_backlight {
struct device * fbdev ;
2017-05-30 14:48:21 +03:00
struct gpio_desc * gpiod ;
2013-07-04 23:13:24 +04:00
} ;
2019-10-22 11:36:24 +03:00
static int gpio_backlight_update_status ( struct backlight_device * bl )
{
struct gpio_backlight * gbl = bl_get_data ( bl ) ;
2020-07-19 11:07:39 +03:00
gpiod_set_value_cansleep ( gbl - > gpiod , backlight_get_brightness ( bl ) ) ;
2013-07-04 23:13:24 +04: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 ,
} ;
static int gpio_backlight_probe ( struct platform_device * pdev )
{
2019-10-22 11:36:29 +03:00
struct device * dev = & pdev - > dev ;
struct gpio_backlight_platform_data * pdata = dev_get_platdata ( dev ) ;
2019-10-22 11:36:30 +03:00
struct device_node * of_node = dev - > of_node ;
2013-07-04 23:13:24 +04:00
struct backlight_properties props ;
struct backlight_device * bl ;
struct gpio_backlight * gbl ;
2019-10-22 11:36:30 +03:00
int ret , init_brightness , def_value ;
2013-07-04 23:13:24 +04:00
2019-10-22 11:36:29 +03:00
gbl = devm_kzalloc ( dev , sizeof ( * gbl ) , GFP_KERNEL ) ;
2013-07-04 23:13:24 +04:00
if ( gbl = = NULL )
return - ENOMEM ;
2019-10-22 11:36:26 +03:00
if ( pdata )
2014-02-27 18:28:33 +04:00
gbl - > fbdev = pdata - > fbdev ;
2019-10-22 11:36:26 +03:00
2019-10-22 11:36:30 +03:00
def_value = device_property_read_bool ( dev , " default-on " ) ;
2019-10-22 11:36:26 +03:00
2019-10-22 11:36:29 +03:00
gbl - > gpiod = devm_gpiod_get ( dev , NULL , GPIOD_ASIS ) ;
2019-10-22 11:36:26 +03:00
if ( IS_ERR ( gbl - > gpiod ) ) {
ret = PTR_ERR ( gbl - > gpiod ) ;
if ( ret ! = - EPROBE_DEFER )
2019-10-22 11:36:29 +03:00
dev_err ( dev ,
2019-10-22 11:36:26 +03:00
" Error: The gpios parameter is missing or invalid. \n " ) ;
return ret ;
2013-07-04 23:13:24 +04:00
}
memset ( & props , 0 , sizeof ( props ) ) ;
props . type = BACKLIGHT_RAW ;
props . max_brightness = 1 ;
2019-10-22 11:36:29 +03:00
bl = devm_backlight_device_register ( dev , dev_name ( dev ) , dev , gbl ,
& gpio_backlight_ops , & props ) ;
2013-07-04 23:13:24 +04:00
if ( IS_ERR ( bl ) ) {
2019-10-22 11:36:29 +03:00
dev_err ( dev , " failed to register backlight \n " ) ;
2013-07-04 23:13:24 +04:00
return PTR_ERR ( bl ) ;
}
2019-10-22 11:36:30 +03:00
/* Set the initial power state */
if ( ! of_node | | ! of_node - > phandle )
/* Not booted with device tree or no phandle link to the node */
bl - > props . power = def_value ? FB_BLANK_UNBLANK
: FB_BLANK_POWERDOWN ;
else if ( gpiod_get_direction ( gbl - > gpiod ) = = 0 & &
gpiod_get_value_cansleep ( gbl - > gpiod ) = = 0 )
bl - > props . power = FB_BLANK_POWERDOWN ;
else
bl - > props . power = FB_BLANK_UNBLANK ;
2019-07-31 11:40:18 +03:00
bl - > props . brightness = 1 ;
2020-07-19 11:07:39 +03:00
init_brightness = backlight_get_brightness ( bl ) ;
2019-10-22 11:36:24 +03:00
ret = gpiod_direction_output ( gbl - > gpiod , init_brightness ) ;
if ( ret ) {
2019-10-22 11:36:29 +03:00
dev_err ( dev , " failed to set initial brightness \n " ) ;
2019-10-22 11:36:24 +03:00
return ret ;
}
2013-07-04 23:13:24 +04:00
platform_set_drvdata ( pdev , bl ) ;
return 0 ;
}
2014-02-27 18:28:33 +04:00
static struct of_device_id gpio_backlight_of_match [ ] = {
{ . compatible = " gpio-backlight " } ,
{ /* sentinel */ }
} ;
2015-04-16 03:21:24 +03:00
MODULE_DEVICE_TABLE ( of , gpio_backlight_of_match ) ;
2014-02-27 18:28:33 +04:00
2013-07-04 23:13:24 +04:00
static struct platform_driver gpio_backlight_driver = {
. driver = {
. name = " gpio-backlight " ,
2019-06-19 18:21:27 +03:00
. of_match_table = gpio_backlight_of_match ,
2013-07-04 23:13:24 +04: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 " ) ;