2019-04-23 12:04:49 +03:00
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (C) 2018 BayLibre SAS
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
//
// LED driver for MAXIM 77650/77651 charger/power-supply.
# include <linux/i2c.h>
# include <linux/leds.h>
# include <linux/mfd/max77650.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# define MAX77650_LED_NUM_LEDS 3
# define MAX77650_LED_A_BASE 0x40
# define MAX77650_LED_B_BASE 0x43
# define MAX77650_LED_BR_MASK GENMASK(4, 0)
# define MAX77650_LED_EN_MASK GENMASK(7, 6)
# define MAX77650_LED_MAX_BRIGHTNESS MAX77650_LED_BR_MASK
/* Enable EN_LED_MSTR. */
# define MAX77650_LED_TOP_DEFAULT BIT(0)
# define MAX77650_LED_ENABLE GENMASK(7, 6)
# define MAX77650_LED_DISABLE 0x00
# define MAX77650_LED_A_DEFAULT MAX77650_LED_DISABLE
/* 100% on duty */
# define MAX77650_LED_B_DEFAULT GENMASK(3, 0)
struct max77650_led {
struct led_classdev cdev ;
struct regmap * map ;
unsigned int regA ;
unsigned int regB ;
} ;
static struct max77650_led * max77650_to_led ( struct led_classdev * cdev )
{
return container_of ( cdev , struct max77650_led , cdev ) ;
}
static int max77650_led_brightness_set ( struct led_classdev * cdev ,
enum led_brightness brightness )
{
struct max77650_led * led = max77650_to_led ( cdev ) ;
int val , mask ;
mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK ;
if ( brightness = = LED_OFF )
val = MAX77650_LED_DISABLE ;
else
val = MAX77650_LED_ENABLE | brightness ;
return regmap_update_bits ( led - > map , led - > regA , mask , val ) ;
}
static int max77650_led_probe ( struct platform_device * pdev )
{
2019-08-22 18:19:27 +03:00
struct fwnode_handle * child ;
2019-04-23 12:04:49 +03:00
struct max77650_led * leds , * led ;
struct device * dev ;
struct regmap * map ;
int rv , num_leds ;
u32 reg ;
dev = & pdev - > dev ;
leds = devm_kcalloc ( dev , sizeof ( * leds ) ,
MAX77650_LED_NUM_LEDS , GFP_KERNEL ) ;
if ( ! leds )
return - ENOMEM ;
map = dev_get_regmap ( dev - > parent , NULL ) ;
if ( ! map )
return - ENODEV ;
2019-08-22 18:19:27 +03:00
num_leds = device_get_child_node_count ( dev ) ;
2019-04-23 12:04:49 +03:00
if ( ! num_leds | | num_leds > MAX77650_LED_NUM_LEDS )
return - ENODEV ;
2019-08-22 18:19:27 +03:00
device_for_each_child_node ( dev , child ) {
2020-09-18 01:33:04 +03:00
struct led_init_data init_data = { } ;
2019-08-22 18:19:27 +03:00
rv = fwnode_property_read_u32 ( child , " reg " , & reg ) ;
2019-07-11 10:54:05 +03:00
if ( rv | | reg > = MAX77650_LED_NUM_LEDS ) {
rv = - EINVAL ;
goto err_node_put ;
}
2019-04-23 12:04:49 +03:00
led = & leds [ reg ] ;
led - > map = map ;
led - > regA = MAX77650_LED_A_BASE + reg ;
led - > regB = MAX77650_LED_B_BASE + reg ;
led - > cdev . brightness_set_blocking = max77650_led_brightness_set ;
led - > cdev . max_brightness = MAX77650_LED_MAX_BRIGHTNESS ;
2020-09-18 01:33:04 +03:00
init_data . fwnode = child ;
init_data . devicename = " max77650 " ;
/* for backwards compatibility if `label` is not present */
init_data . default_label = " : " ;
rv = devm_led_classdev_register_ext ( dev , & led - > cdev ,
& init_data ) ;
2019-04-23 12:04:49 +03:00
if ( rv )
2019-07-11 10:54:05 +03:00
goto err_node_put ;
2019-04-23 12:04:49 +03:00
rv = regmap_write ( map , led - > regA , MAX77650_LED_A_DEFAULT ) ;
if ( rv )
2019-07-11 10:54:05 +03:00
goto err_node_put ;
2019-04-23 12:04:49 +03:00
rv = regmap_write ( map , led - > regB , MAX77650_LED_B_DEFAULT ) ;
if ( rv )
2019-07-11 10:54:05 +03:00
goto err_node_put ;
2019-04-23 12:04:49 +03:00
}
return regmap_write ( map ,
MAX77650_REG_CNFG_LED_TOP ,
MAX77650_LED_TOP_DEFAULT ) ;
2019-07-11 10:54:05 +03:00
err_node_put :
2019-08-22 18:19:27 +03:00
fwnode_handle_put ( child ) ;
2019-07-11 10:54:05 +03:00
return rv ;
2019-04-23 12:04:49 +03:00
}
2019-12-10 13:08:32 +03:00
static const struct of_device_id max77650_led_of_match [ ] = {
{ . compatible = " maxim,max77650-led " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , max77650_led_of_match ) ;
2019-04-23 12:04:49 +03:00
static struct platform_driver max77650_led_driver = {
. driver = {
. name = " max77650-led " ,
2019-12-10 13:08:32 +03:00
. of_match_table = max77650_led_of_match ,
2019-04-23 12:04:49 +03:00
} ,
. probe = max77650_led_probe ,
} ;
module_platform_driver ( max77650_led_driver ) ;
MODULE_DESCRIPTION ( " MAXIM 77650/77651 LED driver " ) ;
MODULE_AUTHOR ( " Bartosz Golaszewski <bgolaszewski@baylibre.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2019-07-03 11:47:38 +03:00
MODULE_ALIAS ( " platform:max77650-led " ) ;