2023-11-23 13:28:02 +00:00
// SPDX-License-Identifier: GPL-2.0
/*
* Device driver for leds in MAX5970 and MAX5978 IC
*
* Copyright ( c ) 2022 9 elements GmbH
*
* Author : Patrick Rudolph < patrick . rudolph @ 9 elements . com >
*/
2023-12-14 20:40:11 +02:00
# include <linux/bits.h>
# include <linux/container_of.h>
# include <linux/device.h>
2023-11-23 13:28:02 +00:00
# include <linux/leds.h>
# include <linux/mfd/max5970.h>
2023-12-14 20:40:09 +02:00
# include <linux/mod_devicetable.h>
2023-12-14 20:40:11 +02:00
# include <linux/module.h>
2023-11-23 13:28:02 +00:00
# include <linux/platform_device.h>
2023-12-14 20:40:09 +02:00
# include <linux/property.h>
2023-11-23 13:28:02 +00:00
# include <linux/regmap.h>
# define ldev_to_maxled(c) container_of(c, struct max5970_led, cdev)
struct max5970_led {
struct device * dev ;
struct regmap * regmap ;
struct led_classdev cdev ;
unsigned int index ;
} ;
static int max5970_led_set_brightness ( struct led_classdev * cdev ,
enum led_brightness brightness )
{
struct max5970_led * ddata = ldev_to_maxled ( cdev ) ;
int ret , val ;
/* Set/clear corresponding bit for given led index */
val = ! brightness ? BIT ( ddata - > index ) : 0 ;
ret = regmap_update_bits ( ddata - > regmap , MAX5970_REG_LED_FLASH , BIT ( ddata - > index ) , val ) ;
if ( ret < 0 )
dev_err ( cdev - > dev , " failed to set brightness %d " , ret ) ;
return ret ;
}
static int max5970_led_probe ( struct platform_device * pdev )
{
2023-12-14 20:40:09 +02:00
struct fwnode_handle * led_node , * child ;
2023-11-23 13:28:02 +00:00
struct device * dev = & pdev - > dev ;
struct regmap * regmap ;
struct max5970_led * ddata ;
2023-12-14 20:40:08 +02:00
int ret = - ENODEV ;
2023-11-23 13:28:02 +00:00
2023-12-14 20:40:09 +02:00
regmap = dev_get_regmap ( dev - > parent , NULL ) ;
2023-11-23 13:28:02 +00:00
if ( ! regmap )
return - ENODEV ;
2023-12-14 20:40:09 +02:00
led_node = device_get_named_child_node ( dev - > parent , " leds " ) ;
2023-11-23 13:28:02 +00:00
if ( ! led_node )
return - ENODEV ;
2023-12-14 20:40:09 +02:00
fwnode_for_each_available_child_node ( led_node , child ) {
2023-11-23 13:28:02 +00:00
u32 reg ;
2023-12-14 20:40:09 +02:00
if ( fwnode_property_read_u32 ( child , " reg " , & reg ) )
2023-11-23 13:28:02 +00:00
continue ;
if ( reg > = MAX5970_NUM_LEDS ) {
2023-12-14 20:40:10 +02:00
dev_err_probe ( dev , - EINVAL , " invalid LED (%u >= %d) \n " , reg , MAX5970_NUM_LEDS ) ;
2023-11-23 13:28:02 +00:00
continue ;
}
ddata = devm_kzalloc ( dev , sizeof ( * ddata ) , GFP_KERNEL ) ;
if ( ! ddata ) {
2023-12-14 20:40:09 +02:00
fwnode_handle_put ( child ) ;
2023-11-23 13:28:02 +00:00
return - ENOMEM ;
}
ddata - > index = reg ;
ddata - > regmap = regmap ;
ddata - > dev = dev ;
2023-12-14 20:40:09 +02:00
if ( fwnode_property_read_string ( child , " label " , & ddata - > cdev . name ) )
ddata - > cdev . name = fwnode_get_name ( child ) ;
2023-11-23 13:28:02 +00:00
ddata - > cdev . max_brightness = 1 ;
ddata - > cdev . brightness_set_blocking = max5970_led_set_brightness ;
ddata - > cdev . default_trigger = " none " ;
ret = devm_led_classdev_register ( dev , & ddata - > cdev ) ;
if ( ret < 0 ) {
2023-12-14 20:40:09 +02:00
fwnode_handle_put ( child ) ;
2023-12-14 20:40:10 +02:00
return dev_err_probe ( dev , ret , " Failed to initialize LED %u \n " , reg ) ;
2023-11-23 13:28:02 +00:00
}
}
return ret ;
}
static struct platform_driver max5970_led_driver = {
. driver = {
. name = " max5970-led " ,
} ,
. probe = max5970_led_probe ,
} ;
module_platform_driver ( max5970_led_driver ) ;
2023-12-14 20:40:09 +02:00
2023-11-23 13:28:02 +00:00
MODULE_AUTHOR ( " Patrick Rudolph <patrick.rudolph@9elements.com> " ) ;
MODULE_AUTHOR ( " Naresh Solanki <Naresh.Solanki@9elements.com> " ) ;
MODULE_DESCRIPTION ( " MAX5970_hot-swap controller LED driver " ) ;
MODULE_LICENSE ( " GPL " ) ;