2019-05-30 02:57:44 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-03-24 02:02:10 +04:00
/*
* Copyright 2011 bct electronic GmbH
2013-08-15 01:23:47 +04:00
* Copyright 2013 Qtechnology / AS
2012-03-24 02:02:10 +04:00
*
* Author : Peter Meerwald < p . meerwald @ bct - electronic . com >
2020-04-30 16:52:24 +03:00
* Author : Ricardo Ribalda < ribalda @ kernel . org >
2012-03-24 02:02:10 +04:00
*
* Based on leds - pca955x . c
*
* LED driver for the PCA9633 I2C LED driver ( 7 - bit slave address 0x62 )
2014-07-03 09:50:34 +04:00
* LED driver for the PCA9634 / 5 I2C LED driver ( 7 - bit slave address set by hw . )
2012-03-24 02:02:10 +04:00
*
2013-07-25 21:16:41 +04:00
* Note that hardware blinking violates the leds infrastructure driver
* interface since the hardware only supports blinking all LEDs with the
* same delay_on / delay_off rates . That is , only the LEDs that are set to
* blink will actually blink but all LEDs that are set to blink will blink
* in identical fashion . The delay_on / delay_off values of the last LED
* that is set to blink will be used for all of the blinking LEDs .
* Hardware blinking is disabled by default but can be enabled by setting
2013-08-15 01:23:50 +04:00
* the ' blink_type ' member in the platform_data struct to ' PCA963X_HW_BLINK '
2013-07-25 21:16:41 +04:00
* or by adding the ' nxp , hw - blink ' property to the DTS .
2012-03-24 02:02:10 +04:00
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/ctype.h>
# include <linux/leds.h>
# include <linux/err.h>
# include <linux/i2c.h>
2019-03-25 17:02:07 +03:00
# include <linux/property.h>
2012-03-24 02:02:10 +04:00
# include <linux/slab.h>
2013-06-26 16:52:49 +04:00
# include <linux/of.h>
2013-08-15 01:23:50 +04:00
# include <linux/platform_data/leds-pca963x.h>
2012-03-24 02:02:10 +04:00
/* LED select registers determine the source that drives LED outputs */
2013-08-15 01:23:50 +04:00
# define PCA963X_LED_OFF 0x0 /* LED driver off */
# define PCA963X_LED_ON 0x1 /* LED driver on */
# define PCA963X_LED_PWM 0x2 /* Controlled through PWM */
# define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
2012-03-24 02:02:10 +04:00
2019-11-19 00:02:55 +03:00
# define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */
# define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */
2013-08-15 01:23:50 +04:00
# define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */
2013-07-25 21:16:41 +04:00
2013-08-15 01:23:50 +04:00
# define PCA963X_MODE1 0x00
# define PCA963X_MODE2 0x01
# define PCA963X_PWM_BASE 0x02
2013-08-15 01:23:47 +04:00
2013-08-15 01:23:50 +04:00
enum pca963x_type {
2013-08-15 01:23:47 +04:00
pca9633 ,
pca9634 ,
2014-07-03 09:50:34 +04:00
pca9635 ,
2013-08-15 01:23:47 +04:00
} ;
2013-08-15 01:23:50 +04:00
struct pca963x_chipdef {
2013-08-15 01:23:47 +04:00
u8 grppwm ;
u8 grpfreq ;
u8 ledout_base ;
int n_leds ;
2016-10-13 16:16:12 +03:00
unsigned int scaling ;
2013-08-15 01:23:47 +04:00
} ;
2013-08-15 01:23:50 +04:00
static struct pca963x_chipdef pca963x_chipdefs [ ] = {
2013-08-15 01:23:47 +04:00
[ pca9633 ] = {
. grppwm = 0x6 ,
. grpfreq = 0x7 ,
. ledout_base = 0x8 ,
. n_leds = 4 ,
} ,
[ pca9634 ] = {
. grppwm = 0xa ,
. grpfreq = 0xb ,
. ledout_base = 0xc ,
. n_leds = 8 ,
} ,
2014-07-03 09:50:34 +04:00
[ pca9635 ] = {
. grppwm = 0x12 ,
. grpfreq = 0x13 ,
. ledout_base = 0x14 ,
. n_leds = 16 ,
} ,
2013-08-15 01:23:47 +04:00
} ;
2012-03-24 02:02:10 +04:00
2013-07-25 21:16:41 +04:00
/* Total blink period in milliseconds */
2013-08-15 01:23:50 +04:00
# define PCA963X_BLINK_PERIOD_MIN 42
# define PCA963X_BLINK_PERIOD_MAX 10667
2013-07-25 21:16:41 +04:00
2013-08-15 01:23:50 +04:00
static const struct i2c_device_id pca963x_id [ ] = {
2013-08-15 01:23:47 +04:00
{ " pca9632 " , pca9633 } ,
{ " pca9633 " , pca9633 } ,
{ " pca9634 " , pca9634 } ,
2014-07-03 09:50:34 +04:00
{ " pca9635 " , pca9635 } ,
2012-03-24 02:02:10 +04:00
{ }
} ;
2013-08-15 01:23:50 +04:00
MODULE_DEVICE_TABLE ( i2c , pca963x_id ) ;
2012-03-24 02:02:10 +04:00
2013-08-15 01:23:50 +04:00
struct pca963x_led ;
2013-08-15 01:23:49 +04:00
2013-08-15 01:23:50 +04:00
struct pca963x {
struct pca963x_chipdef * chipdef ;
2013-08-15 01:23:49 +04:00
struct mutex mutex ;
struct i2c_client * client ;
2013-08-15 01:23:50 +04:00
struct pca963x_led * leds ;
2016-10-29 04:20:42 +03:00
unsigned long leds_on ;
2013-08-15 01:23:49 +04:00
} ;
2013-08-15 01:23:50 +04:00
struct pca963x_led {
struct pca963x * chip ;
2012-03-24 02:02:10 +04:00
struct led_classdev led_cdev ;
2014-07-03 09:50:34 +04:00
int led_num ; /* 0 .. 15 potentially */
2012-03-24 02:02:10 +04:00
char name [ 32 ] ;
2013-07-25 21:16:41 +04:00
u8 gdc ;
u8 gfrq ;
2012-03-24 02:02:10 +04:00
} ;
2020-09-20 03:24:57 +03:00
static int pca963x_brightness ( struct pca963x_led * led ,
2020-09-20 03:24:54 +03:00
enum led_brightness brightness )
2012-03-24 02:02:10 +04:00
{
2020-09-20 03:24:57 +03:00
struct i2c_client * client = led - > chip - > client ;
struct pca963x_chipdef * chipdef = led - > chip - > chipdef ;
2020-09-20 03:24:54 +03:00
u8 ledout_addr , ledout , mask , val ;
int shift ;
2015-08-20 13:38:44 +03:00
int ret ;
2012-03-24 02:02:10 +04:00
2020-09-20 03:24:57 +03:00
ledout_addr = chipdef - > ledout_base + ( led - > led_num / 4 ) ;
shift = 2 * ( led - > led_num % 4 ) ;
2020-09-20 03:24:54 +03:00
mask = 0x3 < < shift ;
ledout = i2c_smbus_read_byte_data ( client , ledout_addr ) ;
2015-08-20 13:38:44 +03:00
switch ( brightness ) {
2012-03-24 02:02:10 +04:00
case LED_FULL :
2020-09-20 03:24:54 +03:00
val = ( ledout & ~ mask ) | ( PCA963X_LED_ON < < shift ) ;
ret = i2c_smbus_write_byte_data ( client , ledout_addr , val ) ;
2012-03-24 02:02:10 +04:00
break ;
case LED_OFF :
2020-09-20 03:24:54 +03:00
val = ledout & ~ mask ;
ret = i2c_smbus_write_byte_data ( client , ledout_addr , val ) ;
2012-03-24 02:02:10 +04:00
break ;
default :
2020-09-20 03:24:54 +03:00
ret = i2c_smbus_write_byte_data ( client ,
PCA963X_PWM_BASE +
2020-09-20 03:24:57 +03:00
led - > led_num ,
2020-09-20 03:24:54 +03:00
brightness ) ;
2015-08-20 13:38:44 +03:00
if ( ret < 0 )
2016-10-29 04:20:42 +03:00
return ret ;
2020-09-20 03:24:54 +03:00
val = ( ledout & ~ mask ) | ( PCA963X_LED_PWM < < shift ) ;
ret = i2c_smbus_write_byte_data ( client , ledout_addr , val ) ;
2012-03-24 02:02:10 +04:00
break ;
}
2016-10-29 04:20:42 +03:00
2015-08-20 13:38:44 +03:00
return ret ;
2012-03-24 02:02:10 +04:00
}
2020-09-20 03:24:57 +03:00
static void pca963x_blink ( struct pca963x_led * led )
2013-07-25 21:16:41 +04:00
{
2020-09-20 03:24:57 +03:00
struct i2c_client * client = led - > chip - > client ;
struct pca963x_chipdef * chipdef = led - > chip - > chipdef ;
2020-09-20 03:24:54 +03:00
u8 ledout_addr , ledout , mask , val , mode2 ;
int shift ;
2020-09-20 03:24:57 +03:00
ledout_addr = chipdef - > ledout_base + ( led - > led_num / 4 ) ;
shift = 2 * ( led - > led_num % 4 ) ;
2020-09-20 03:24:54 +03:00
mask = 0x3 < < shift ;
mode2 = i2c_smbus_read_byte_data ( client , PCA963X_MODE2 ) ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:57 +03:00
i2c_smbus_write_byte_data ( client , chipdef - > grppwm , led - > gdc ) ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:57 +03:00
i2c_smbus_write_byte_data ( client , chipdef - > grpfreq , led - > gfrq ) ;
2013-07-25 21:16:41 +04:00
2013-08-15 01:23:50 +04:00
if ( ! ( mode2 & PCA963X_MODE2_DMBLNK ) )
2020-09-20 03:24:54 +03:00
i2c_smbus_write_byte_data ( client , PCA963X_MODE2 ,
mode2 | PCA963X_MODE2_DMBLNK ) ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:57 +03:00
mutex_lock ( & led - > chip - > mutex ) ;
2020-09-20 03:24:54 +03:00
ledout = i2c_smbus_read_byte_data ( client , ledout_addr ) ;
if ( ( ledout & mask ) ! = ( PCA963X_LED_GRP_PWM < < shift ) ) {
val = ( ledout & ~ mask ) | ( PCA963X_LED_GRP_PWM < < shift ) ;
i2c_smbus_write_byte_data ( client , ledout_addr , val ) ;
}
2020-09-20 03:24:57 +03:00
mutex_unlock ( & led - > chip - > mutex ) ;
2013-07-25 21:16:41 +04:00
}
2020-09-20 03:24:57 +03:00
static int pca963x_power_state ( struct pca963x_led * led )
2016-10-29 04:20:42 +03:00
{
2020-09-20 03:24:57 +03:00
struct i2c_client * client = led - > chip - > client ;
unsigned long * leds_on = & led - > chip - > leds_on ;
2020-09-20 03:24:54 +03:00
unsigned long cached_leds = * leds_on ;
2016-10-29 04:20:42 +03:00
2020-09-20 03:24:57 +03:00
if ( led - > led_cdev . brightness )
set_bit ( led - > led_num , leds_on ) ;
2016-10-29 04:20:42 +03:00
else
2020-09-20 03:24:57 +03:00
clear_bit ( led - > led_num , leds_on ) ;
2016-10-29 04:20:42 +03:00
if ( ! ( * leds_on ) ! = ! cached_leds )
2020-09-20 03:24:54 +03:00
return i2c_smbus_write_byte_data ( client , PCA963X_MODE1 ,
* leds_on ? 0 : BIT ( 4 ) ) ;
2016-10-29 04:20:42 +03:00
return 0 ;
}
2015-08-20 13:38:44 +03:00
static int pca963x_led_set ( struct led_classdev * led_cdev ,
2020-09-20 03:24:54 +03:00
enum led_brightness value )
2012-03-24 02:02:10 +04:00
{
2020-09-20 03:24:57 +03:00
struct pca963x_led * led ;
2016-10-29 04:20:42 +03:00
int ret ;
2012-03-24 02:02:10 +04:00
2020-09-20 03:24:57 +03:00
led = container_of ( led_cdev , struct pca963x_led , led_cdev ) ;
2012-03-24 02:02:10 +04:00
2020-09-20 03:24:57 +03:00
mutex_lock ( & led - > chip - > mutex ) ;
2016-10-29 04:20:42 +03:00
2020-09-20 03:24:57 +03:00
ret = pca963x_brightness ( led , value ) ;
2016-10-29 04:20:42 +03:00
if ( ret < 0 )
goto unlock ;
2020-09-20 03:24:57 +03:00
ret = pca963x_power_state ( led ) ;
2016-10-29 04:20:42 +03:00
unlock :
2020-09-20 03:24:57 +03:00
mutex_unlock ( & led - > chip - > mutex ) ;
2016-10-29 04:20:42 +03:00
return ret ;
2012-03-24 02:02:10 +04:00
}
2020-09-20 03:24:57 +03:00
static unsigned int pca963x_period_scale ( struct pca963x_led * led ,
2020-09-20 03:24:54 +03:00
unsigned int val )
2016-10-13 16:16:12 +03:00
{
2020-09-20 03:24:57 +03:00
unsigned int scaling = led - > chip - > chipdef - > scaling ;
2016-10-13 16:16:12 +03:00
return scaling ? DIV_ROUND_CLOSEST ( val * scaling , 1000 ) : val ;
}
2013-08-15 01:23:50 +04:00
static int pca963x_blink_set ( struct led_classdev * led_cdev ,
2020-09-20 03:24:54 +03:00
unsigned long * delay_on , unsigned long * delay_off )
2013-07-25 21:16:41 +04:00
{
unsigned long time_on , time_off , period ;
2020-09-20 03:24:57 +03:00
struct pca963x_led * led ;
2013-07-25 21:16:41 +04:00
u8 gdc , gfrq ;
2020-09-20 03:24:57 +03:00
led = container_of ( led_cdev , struct pca963x_led , led_cdev ) ;
2013-07-25 21:16:41 +04:00
time_on = * delay_on ;
time_off = * delay_off ;
/* If both zero, pick reasonable defaults of 500ms each */
if ( ! time_on & & ! time_off ) {
time_on = 500 ;
time_off = 500 ;
}
2020-09-20 03:24:57 +03:00
period = pca963x_period_scale ( led , time_on + time_off ) ;
2013-07-25 21:16:41 +04:00
/* If period not supported by hardware, default to someting sane. */
2013-08-15 01:23:50 +04:00
if ( ( period < PCA963X_BLINK_PERIOD_MIN ) | |
( period > PCA963X_BLINK_PERIOD_MAX ) ) {
2013-07-25 21:16:41 +04:00
time_on = 500 ;
time_off = 500 ;
2020-09-20 03:24:57 +03:00
period = pca963x_period_scale ( led , 1000 ) ;
2013-07-25 21:16:41 +04:00
}
/*
* From manual : duty cycle = ( GDC / 256 ) - >
* ( time_on / period ) = ( GDC / 256 ) - >
* GDC = ( ( time_on * 256 ) / period )
*/
2020-09-20 03:24:57 +03:00
gdc = ( pca963x_period_scale ( led , time_on ) * 256 ) / period ;
2013-07-25 21:16:41 +04:00
/*
* From manual : period = ( ( GFRQ + 1 ) / 24 ) in seconds .
* So , period ( in ms ) = ( ( ( GFRQ + 1 ) / 24 ) * 1000 ) - >
* GFRQ = ( ( period * 24 / 1000 ) - 1 )
*/
gfrq = ( period * 24 / 1000 ) - 1 ;
2020-09-20 03:24:57 +03:00
led - > gdc = gdc ;
led - > gfrq = gfrq ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:57 +03:00
pca963x_blink ( led ) ;
2013-07-25 21:16:41 +04:00
* delay_on = time_on ;
* delay_off = time_off ;
return 0 ;
}
2013-08-15 01:23:50 +04:00
static struct pca963x_platform_data *
2020-09-20 03:24:56 +03:00
pca963x_get_pdata ( struct device * dev , struct pca963x_chipdef * chipdef )
2013-06-26 16:52:49 +04:00
{
2013-08-15 01:23:50 +04:00
struct pca963x_platform_data * pdata ;
struct led_info * pca963x_leds ;
2019-03-25 17:02:07 +03:00
struct fwnode_handle * child ;
2013-06-26 16:52:49 +04:00
int count ;
2020-09-20 03:24:54 +03:00
count = device_get_child_node_count ( dev ) ;
2020-09-20 03:24:56 +03:00
if ( ! count | | count > chipdef - > n_leds )
2013-06-26 16:52:49 +04:00
return ERR_PTR ( - ENODEV ) ;
2020-09-20 03:24:56 +03:00
pca963x_leds = devm_kcalloc ( dev , chipdef - > n_leds ,
sizeof ( struct led_info ) , GFP_KERNEL ) ;
2013-08-15 01:23:50 +04:00
if ( ! pca963x_leds )
2013-06-26 16:52:49 +04:00
return ERR_PTR ( - ENOMEM ) ;
2020-09-20 03:24:54 +03:00
device_for_each_child_node ( dev , child ) {
2015-03-15 13:41:52 +03:00
struct led_info led = { } ;
2013-06-26 16:52:49 +04:00
u32 reg ;
int res ;
2019-03-25 17:02:07 +03:00
res = fwnode_property_read_u32 ( child , " reg " , & reg ) ;
2020-09-20 03:24:56 +03:00
if ( ( res ! = 0 ) | | ( reg > = chipdef - > n_leds ) )
2013-08-15 01:23:51 +04:00
continue ;
2019-03-25 17:02:07 +03:00
res = fwnode_property_read_string ( child , " label " , & led . name ) ;
if ( ( res ! = 0 ) & & is_of_node ( child ) )
led . name = to_of_node ( child ) - > name ;
fwnode_property_read_string ( child , " linux,default-trigger " ,
& led . default_trigger ) ;
2013-08-15 01:23:50 +04:00
pca963x_leds [ reg ] = led ;
2013-06-26 16:52:49 +04:00
}
2020-09-20 03:24:54 +03:00
pdata = devm_kzalloc ( dev , sizeof ( struct pca963x_platform_data ) ,
GFP_KERNEL ) ;
2013-06-26 16:52:49 +04:00
if ( ! pdata )
return ERR_PTR ( - ENOMEM ) ;
2013-08-15 01:23:50 +04:00
pdata - > leds . leds = pca963x_leds ;
2020-09-20 03:24:56 +03:00
pdata - > leds . num_leds = chipdef - > n_leds ;
2013-06-26 16:52:49 +04:00
/* default to open-drain unless totem pole (push-pull) is specified */
2020-09-20 03:24:54 +03:00
if ( device_property_read_bool ( dev , " nxp,totem-pole " ) )
2013-08-15 01:23:50 +04:00
pdata - > outdrv = PCA963X_TOTEM_POLE ;
2013-06-26 16:52:49 +04:00
else
2013-08-15 01:23:50 +04:00
pdata - > outdrv = PCA963X_OPEN_DRAIN ;
2013-06-26 16:52:49 +04:00
2013-07-25 21:16:41 +04:00
/* default to software blinking unless hardware blinking is specified */
2020-09-20 03:24:54 +03:00
if ( device_property_read_bool ( dev , " nxp,hw-blink " ) )
2013-08-15 01:23:50 +04:00
pdata - > blink_type = PCA963X_HW_BLINK ;
2013-07-25 21:16:41 +04:00
else
2013-08-15 01:23:50 +04:00
pdata - > blink_type = PCA963X_SW_BLINK ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:54 +03:00
if ( device_property_read_u32 ( dev , " nxp,period-scale " ,
2020-09-20 03:24:56 +03:00
& chipdef - > scaling ) )
chipdef - > scaling = 1000 ;
2016-10-13 16:16:12 +03:00
2017-04-27 09:37:33 +03:00
/* default to non-inverted output, unless inverted is specified */
2020-09-20 03:24:54 +03:00
if ( device_property_read_bool ( dev , " nxp,inverted-out " ) )
2017-04-27 09:37:33 +03:00
pdata - > dir = PCA963X_INVERTED ;
else
pdata - > dir = PCA963X_NORMAL ;
2013-06-26 16:52:49 +04:00
return pdata ;
}
2013-08-15 01:23:50 +04:00
static const struct of_device_id of_pca963x_match [ ] = {
2013-08-15 01:23:47 +04:00
{ . compatible = " nxp,pca9632 " , } ,
{ . compatible = " nxp,pca9633 " , } ,
{ . compatible = " nxp,pca9634 " , } ,
2014-07-03 09:50:34 +04:00
{ . compatible = " nxp,pca9635 " , } ,
2013-06-26 16:52:49 +04:00
{ } ,
} ;
2015-08-25 09:31:16 +03:00
MODULE_DEVICE_TABLE ( of , of_pca963x_match ) ;
2013-06-26 16:52:49 +04:00
2013-08-15 01:23:50 +04:00
static int pca963x_probe ( struct i2c_client * client ,
2020-09-20 03:24:54 +03:00
const struct i2c_device_id * id )
2012-03-24 02:02:10 +04:00
{
2020-09-20 03:24:54 +03:00
struct device * dev = & client - > dev ;
2020-09-20 03:24:56 +03:00
struct pca963x_chipdef * chipdef ;
2013-08-15 01:23:50 +04:00
struct pca963x_platform_data * pdata ;
2020-09-20 03:24:57 +03:00
struct pca963x_led * leds ;
2020-09-20 03:24:56 +03:00
struct pca963x * chip ;
2012-03-24 02:02:10 +04:00
int i , err ;
2020-09-20 03:24:56 +03:00
chipdef = & pca963x_chipdefs [ id - > driver_data ] ;
2020-09-20 03:24:54 +03:00
pdata = dev_get_platdata ( dev ) ;
2012-03-24 02:02:10 +04:00
2013-06-26 16:52:49 +04:00
if ( ! pdata ) {
2020-09-20 03:24:56 +03:00
pdata = pca963x_get_pdata ( dev , chipdef ) ;
2013-06-26 16:52:49 +04:00
if ( IS_ERR ( pdata ) ) {
2020-09-20 03:24:54 +03:00
dev_warn ( dev , " could not parse configuration \n " ) ;
2013-06-26 16:52:49 +04:00
pdata = NULL ;
}
}
2013-08-15 01:23:47 +04:00
if ( pdata & & ( pdata - > leds . num_leds < 1 | |
2020-09-20 03:24:56 +03:00
pdata - > leds . num_leds > chipdef - > n_leds ) ) {
dev_err ( dev , " board info must claim 1-%d LEDs " ,
chipdef - > n_leds ) ;
2013-08-15 01:23:47 +04:00
return - EINVAL ;
2012-03-24 02:02:10 +04:00
}
2020-09-20 03:24:56 +03:00
chip = devm_kzalloc ( dev , sizeof ( * chip ) , GFP_KERNEL ) ;
if ( ! chip )
2013-08-15 01:23:49 +04:00
return - ENOMEM ;
2020-09-20 03:24:57 +03:00
leds = devm_kcalloc ( dev , chipdef - > n_leds , sizeof ( * leds ) , GFP_KERNEL ) ;
if ( ! leds )
2012-03-24 02:02:10 +04:00
return - ENOMEM ;
2020-09-20 03:24:56 +03:00
i2c_set_clientdata ( client , chip ) ;
2013-08-15 01:23:49 +04:00
2020-09-20 03:24:56 +03:00
mutex_init ( & chip - > mutex ) ;
chip - > chipdef = chipdef ;
chip - > client = client ;
2020-09-20 03:24:57 +03:00
chip - > leds = leds ;
2013-08-15 01:23:49 +04:00
/* Turn off LEDs by default*/
2020-09-20 03:24:56 +03:00
for ( i = 0 ; i < chipdef - > n_leds / 4 ; i + + )
i2c_smbus_write_byte_data ( client , chipdef - > ledout_base + i , 0x00 ) ;
2012-03-24 02:02:10 +04:00
2020-09-20 03:24:56 +03:00
for ( i = 0 ; i < chipdef - > n_leds ; i + + ) {
2020-09-20 03:24:57 +03:00
struct pca963x_led * led = & leds [ i ] ;
led - > led_num = i ;
led - > chip = chip ;
2012-03-24 02:02:10 +04:00
/* Platform data can specify LED names and default triggers */
2012-09-24 10:53:49 +04:00
if ( pdata & & i < pdata - > leds . num_leds ) {
if ( pdata - > leds . leds [ i ] . name )
2020-09-20 03:24:57 +03:00
snprintf ( led - > name ,
sizeof ( led - > name ) , " pca963x:%s " ,
2012-09-24 10:53:49 +04:00
pdata - > leds . leds [ i ] . name ) ;
if ( pdata - > leds . leds [ i ] . default_trigger )
2020-09-20 03:24:57 +03:00
led - > led_cdev . default_trigger =
2012-09-24 10:53:49 +04:00
pdata - > leds . leds [ i ] . default_trigger ;
2012-03-24 02:02:10 +04:00
}
2013-08-15 01:23:48 +04:00
if ( ! pdata | | i > = pdata - > leds . num_leds | |
! pdata - > leds . leds [ i ] . name )
2020-09-20 03:24:57 +03:00
snprintf ( led - > name , sizeof ( led - > name ) ,
2013-08-15 01:23:50 +04:00
" pca963x:%d:%.2x:%d " , client - > adapter - > nr ,
2013-08-15 01:23:48 +04:00
client - > addr , i ) ;
2012-03-24 02:02:10 +04:00
2020-09-20 03:24:57 +03:00
led - > led_cdev . name = led - > name ;
led - > led_cdev . brightness_set_blocking = pca963x_led_set ;
2012-03-24 02:02:10 +04:00
2013-08-15 01:23:50 +04:00
if ( pdata & & pdata - > blink_type = = PCA963X_HW_BLINK )
2020-09-20 03:24:57 +03:00
led - > led_cdev . blink_set = pca963x_blink_set ;
2013-07-25 21:16:41 +04:00
2020-09-20 03:24:57 +03:00
err = devm_led_classdev_register ( dev , & led - > led_cdev ) ;
2012-03-24 02:02:10 +04:00
if ( err < 0 )
2020-09-20 03:24:55 +03:00
return err ;
2012-03-24 02:02:10 +04:00
}
2016-10-29 04:20:42 +03:00
/* Disable LED all-call address, and power down initially */
i2c_smbus_write_byte_data ( client , PCA963X_MODE1 , BIT ( 4 ) ) ;
2012-03-24 02:02:10 +04:00
2014-07-03 09:50:35 +04:00
if ( pdata ) {
2020-09-20 03:24:54 +03:00
u8 mode2 = i2c_smbus_read_byte_data ( client , PCA963X_MODE2 ) ;
2014-07-03 09:50:35 +04:00
/* Configure output: open-drain or totem pole (push-pull) */
if ( pdata - > outdrv = = PCA963X_OPEN_DRAIN )
2019-11-19 00:02:55 +03:00
mode2 & = ~ PCA963X_MODE2_OUTDRV ;
2014-07-03 09:50:35 +04:00
else
2019-11-19 00:02:55 +03:00
mode2 | = PCA963X_MODE2_OUTDRV ;
2017-04-27 09:37:33 +03:00
/* Configure direction: normal or inverted */
if ( pdata - > dir = = PCA963X_INVERTED )
2019-11-19 00:02:55 +03:00
mode2 | = PCA963X_MODE2_INVRT ;
2020-09-20 03:24:54 +03:00
i2c_smbus_write_byte_data ( client , PCA963X_MODE2 , mode2 ) ;
2014-07-03 09:50:35 +04:00
}
2012-09-24 10:53:49 +04:00
2012-03-24 02:02:10 +04:00
return 0 ;
}
2013-08-15 01:23:50 +04:00
static struct i2c_driver pca963x_driver = {
2012-03-24 02:02:10 +04:00
. driver = {
2013-08-15 01:23:50 +04:00
. name = " leds-pca963x " ,
2019-03-25 17:02:07 +03:00
. of_match_table = of_pca963x_match ,
2012-03-24 02:02:10 +04:00
} ,
2013-08-15 01:23:50 +04:00
. probe = pca963x_probe ,
. id_table = pca963x_id ,
2012-03-24 02:02:10 +04:00
} ;
2013-08-15 01:23:50 +04:00
module_i2c_driver ( pca963x_driver ) ;
2012-03-24 02:02:10 +04:00
MODULE_AUTHOR ( " Peter Meerwald <p.meerwald@bct-electronic.com> " ) ;
2013-08-15 01:23:50 +04:00
MODULE_DESCRIPTION ( " PCA963X LED driver " ) ;
2012-03-24 02:02:10 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;