2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2012-03-23 15:02:01 -07:00
/*
* TI LP855x Backlight Driver
*
* Copyright ( C ) 2011 Texas Instruments
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/backlight.h>
2016-06-10 12:39:57 -07:00
# include <linux/delay.h>
2012-03-23 15:02:01 -07:00
# include <linux/err.h>
2013-04-29 16:18:06 -07:00
# include <linux/of.h>
2012-07-30 14:40:53 -07:00
# include <linux/platform_data/lp855x.h>
2012-12-17 16:00:43 -08:00
# include <linux/pwm.h>
2014-12-02 17:39:12 -08:00
# include <linux/regulator/consumer.h>
2012-03-23 15:02:01 -07:00
2013-02-21 16:44:06 -08:00
/* LP8550/1/2/3/6 Registers */
# define LP855X_BRIGHTNESS_CTRL 0x00
# define LP855X_DEVICE_CTRL 0x01
# define LP855X_EEPROM_START 0xA0
# define LP855X_EEPROM_END 0xA7
# define LP8556_EPROM_START 0xA0
# define LP8556_EPROM_END 0xAF
2013-11-12 15:08:57 -08:00
/* LP8555/7 Registers */
2013-02-21 16:44:06 -08:00
# define LP8557_BL_CMD 0x00
# define LP8557_BL_MASK 0x01
# define LP8557_BL_ON 0x01
# define LP8557_BL_OFF 0x00
# define LP8557_BRIGHTNESS_CTRL 0x04
# define LP8557_CONFIG 0x10
2013-11-12 15:08:57 -08:00
# define LP8555_EPROM_START 0x10
# define LP8555_EPROM_END 0x7A
2013-02-21 16:44:06 -08:00
# define LP8557_EPROM_START 0x10
# define LP8557_EPROM_END 0x1E
2012-03-23 15:02:01 -07:00
# define DEFAULT_BL_NAME "lcd-backlight"
# define MAX_BRIGHTNESS 255
2013-04-29 16:18:03 -07:00
enum lp855x_brightness_ctrl_mode {
PWM_BASED = 1 ,
REGISTER_BASED ,
} ;
2013-02-21 16:44:05 -08:00
struct lp855x ;
/*
* struct lp855x_device_config
* @ pre_init_device : init device function call before updating the brightness
* @ reg_brightness : register address for brigthenss control
* @ reg_devicectrl : register address for device control
* @ post_init_device : late init device function call
*/
struct lp855x_device_config {
int ( * pre_init_device ) ( struct lp855x * ) ;
u8 reg_brightness ;
u8 reg_devicectrl ;
int ( * post_init_device ) ( struct lp855x * ) ;
} ;
2012-03-23 15:02:01 -07:00
struct lp855x {
const char * chipname ;
enum lp855x_chip_id chip_id ;
2013-04-29 16:18:03 -07:00
enum lp855x_brightness_ctrl_mode mode ;
2013-02-21 16:44:05 -08:00
struct lp855x_device_config * cfg ;
2012-03-23 15:02:01 -07:00
struct i2c_client * client ;
struct backlight_device * bl ;
struct device * dev ;
struct lp855x_platform_data * pdata ;
2012-12-17 16:00:43 -08:00
struct pwm_device * pwm ;
2015-07-20 15:45:38 +09:00
struct regulator * supply ; /* regulator for VDD input */
2016-06-10 12:39:57 -07:00
struct regulator * enable ; /* regulator for EN/VDDIO input */
2012-03-23 15:02:01 -07:00
} ;
static int lp855x_write_byte ( struct lp855x * lp , u8 reg , u8 data )
{
2012-12-17 16:00:45 -08:00
return i2c_smbus_write_byte_data ( lp - > client , reg , data ) ;
2012-03-23 15:02:01 -07:00
}
2013-02-21 16:44:06 -08:00
static int lp855x_update_bit ( struct lp855x * lp , u8 reg , u8 mask , u8 data )
{
int ret ;
u8 tmp ;
ret = i2c_smbus_read_byte_data ( lp - > client , reg ) ;
if ( ret < 0 ) {
dev_err ( lp - > dev , " failed to read 0x%.2x \n " , reg ) ;
return ret ;
}
tmp = ( u8 ) ret ;
tmp & = ~ mask ;
tmp | = data & mask ;
return lp855x_write_byte ( lp , reg , tmp ) ;
}
2012-03-23 15:02:01 -07:00
static bool lp855x_is_valid_rom_area ( struct lp855x * lp , u8 addr )
{
u8 start , end ;
switch ( lp - > chip_id ) {
case LP8550 :
case LP8551 :
case LP8552 :
case LP8553 :
2013-02-21 16:44:06 -08:00
start = LP855X_EEPROM_START ;
end = LP855X_EEPROM_END ;
2012-03-23 15:02:01 -07:00
break ;
case LP8556 :
2013-02-21 16:44:06 -08:00
start = LP8556_EPROM_START ;
end = LP8556_EPROM_END ;
break ;
2013-11-12 15:08:57 -08:00
case LP8555 :
start = LP8555_EPROM_START ;
end = LP8555_EPROM_END ;
break ;
2013-02-21 16:44:06 -08:00
case LP8557 :
start = LP8557_EPROM_START ;
end = LP8557_EPROM_END ;
2012-03-23 15:02:01 -07:00
break ;
default :
return false ;
}
2014-01-23 15:54:32 -08:00
return addr > = start & & addr < = end ;
2012-03-23 15:02:01 -07:00
}
2013-02-21 16:44:06 -08:00
static int lp8557_bl_off ( struct lp855x * lp )
{
/* BL_ON = 0 before updating EPROM settings */
return lp855x_update_bit ( lp , LP8557_BL_CMD , LP8557_BL_MASK ,
LP8557_BL_OFF ) ;
}
static int lp8557_bl_on ( struct lp855x * lp )
{
/* BL_ON = 1 after updating EPROM settings */
return lp855x_update_bit ( lp , LP8557_BL_CMD , LP8557_BL_MASK ,
LP8557_BL_ON ) ;
}
2013-02-21 16:44:05 -08:00
static struct lp855x_device_config lp855x_dev_cfg = {
2013-02-21 16:44:06 -08:00
. reg_brightness = LP855X_BRIGHTNESS_CTRL ,
. reg_devicectrl = LP855X_DEVICE_CTRL ,
} ;
static struct lp855x_device_config lp8557_dev_cfg = {
. reg_brightness = LP8557_BRIGHTNESS_CTRL ,
. reg_devicectrl = LP8557_CONFIG ,
. pre_init_device = lp8557_bl_off ,
. post_init_device = lp8557_bl_on ,
2013-02-21 16:44:05 -08:00
} ;
/*
* Device specific configuration flow
*
* a ) pre_init_device ( optional )
* b ) update the brightness register
* c ) update device control register
* d ) update ROM area ( optional )
* e ) post_init_device ( optional )
*
*/
static int lp855x_configure ( struct lp855x * lp )
2012-03-23 15:02:01 -07:00
{
u8 val , addr ;
int i , ret ;
struct lp855x_platform_data * pd = lp - > pdata ;
2013-02-21 16:44:05 -08:00
switch ( lp - > chip_id ) {
2013-11-12 15:08:57 -08:00
case LP8550 :
case LP8551 :
case LP8552 :
case LP8553 :
case LP8556 :
2013-02-21 16:44:05 -08:00
lp - > cfg = & lp855x_dev_cfg ;
break ;
2013-11-12 15:08:57 -08:00
case LP8555 :
2013-02-21 16:44:06 -08:00
case LP8557 :
lp - > cfg = & lp8557_dev_cfg ;
break ;
2013-02-21 16:44:05 -08:00
default :
return - EINVAL ;
}
if ( lp - > cfg - > pre_init_device ) {
ret = lp - > cfg - > pre_init_device ( lp ) ;
if ( ret ) {
dev_err ( lp - > dev , " pre init device err: %d \n " , ret ) ;
goto err ;
}
}
2012-03-23 15:02:01 -07:00
val = pd - > initial_brightness ;
2013-02-21 16:44:05 -08:00
ret = lp855x_write_byte ( lp , lp - > cfg - > reg_brightness , val ) ;
2012-03-23 15:02:01 -07:00
if ( ret )
2013-02-21 16:44:05 -08:00
goto err ;
2012-03-23 15:02:01 -07:00
val = pd - > device_control ;
2013-02-21 16:44:05 -08:00
ret = lp855x_write_byte ( lp , lp - > cfg - > reg_devicectrl , val ) ;
2012-03-23 15:02:01 -07:00
if ( ret )
2013-02-21 16:44:05 -08:00
goto err ;
2012-03-23 15:02:01 -07:00
2013-04-29 16:18:05 -07:00
if ( pd - > size_program > 0 ) {
2012-03-23 15:02:01 -07:00
for ( i = 0 ; i < pd - > size_program ; i + + ) {
addr = pd - > rom_data [ i ] . addr ;
val = pd - > rom_data [ i ] . val ;
if ( ! lp855x_is_valid_rom_area ( lp , addr ) )
continue ;
ret = lp855x_write_byte ( lp , addr , val ) ;
if ( ret )
2013-02-21 16:44:05 -08:00
goto err ;
}
}
if ( lp - > cfg - > post_init_device ) {
ret = lp - > cfg - > post_init_device ( lp ) ;
if ( ret ) {
dev_err ( lp - > dev , " post init device err: %d \n " , ret ) ;
goto err ;
2012-03-23 15:02:01 -07:00
}
}
2013-02-21 16:44:05 -08:00
return 0 ;
err :
2012-03-23 15:02:01 -07:00
return ret ;
}
2012-12-17 16:00:43 -08:00
static void lp855x_pwm_ctrl ( struct lp855x * lp , int br , int max_br )
{
unsigned int period = lp - > pdata - > period_ns ;
unsigned int duty = br * period / max_br ;
struct pwm_device * pwm ;
/* request pwm device with the consumer name */
if ( ! lp - > pwm ) {
pwm = devm_pwm_get ( lp - > dev , lp - > chipname ) ;
if ( IS_ERR ( pwm ) )
return ;
lp - > pwm = pwm ;
2016-04-14 21:17:31 +02:00
/*
* FIXME : pwm_apply_args ( ) should be removed when switching to
* the atomic PWM API .
*/
pwm_apply_args ( pwm ) ;
2012-12-17 16:00:43 -08:00
}
pwm_config ( lp - > pwm , duty , period ) ;
if ( duty )
pwm_enable ( lp - > pwm ) ;
else
pwm_disable ( lp - > pwm ) ;
}
2012-03-23 15:02:01 -07:00
static int lp855x_bl_update_status ( struct backlight_device * bl )
{
struct lp855x * lp = bl_get_data ( bl ) ;
2015-05-11 13:32:05 -07:00
int brightness = bl - > props . brightness ;
2012-03-23 15:02:01 -07:00
2013-07-02 14:15:54 +02:00
if ( bl - > props . state & ( BL_CORE_SUSPENDED | BL_CORE_FBBLANK ) )
2015-05-11 13:32:05 -07:00
brightness = 0 ;
2012-03-23 15:02:01 -07:00
2015-05-11 13:32:05 -07:00
if ( lp - > mode = = PWM_BASED )
lp855x_pwm_ctrl ( lp , brightness , bl - > props . max_brightness ) ;
else if ( lp - > mode = = REGISTER_BASED )
lp855x_write_byte ( lp , lp - > cfg - > reg_brightness , ( u8 ) brightness ) ;
2012-03-23 15:02:01 -07:00
return 0 ;
}
static const struct backlight_ops lp855x_bl_ops = {
. options = BL_CORE_SUSPENDRESUME ,
. update_status = lp855x_bl_update_status ,
} ;
static int lp855x_backlight_register ( struct lp855x * lp )
{
struct backlight_device * bl ;
struct backlight_properties props ;
struct lp855x_platform_data * pdata = lp - > pdata ;
2013-04-29 16:18:02 -07:00
const char * name = pdata - > name ? : DEFAULT_BL_NAME ;
2012-03-23 15:02:01 -07:00
2015-08-27 10:41:15 -07:00
memset ( & props , 0 , sizeof ( props ) ) ;
2012-03-23 15:02:01 -07:00
props . type = BACKLIGHT_PLATFORM ;
props . max_brightness = MAX_BRIGHTNESS ;
if ( pdata - > initial_brightness > props . max_brightness )
pdata - > initial_brightness = props . max_brightness ;
props . brightness = pdata - > initial_brightness ;
2013-11-12 15:09:19 -08:00
bl = devm_backlight_device_register ( lp - > dev , name , lp - > dev , lp ,
2012-03-23 15:02:01 -07:00
& lp855x_bl_ops , & props ) ;
if ( IS_ERR ( bl ) )
return PTR_ERR ( bl ) ;
lp - > bl = bl ;
return 0 ;
}
static ssize_t lp855x_get_chip_id ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct lp855x * lp = dev_get_drvdata ( dev ) ;
2014-08-27 10:12:53 +09:00
2013-04-29 16:17:52 -07:00
return scnprintf ( buf , PAGE_SIZE , " %s \n " , lp - > chipname ) ;
2012-03-23 15:02:01 -07:00
}
static ssize_t lp855x_get_bl_ctl_mode ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct lp855x * lp = dev_get_drvdata ( dev ) ;
char * strmode = NULL ;
2013-04-29 16:18:03 -07:00
if ( lp - > mode = = PWM_BASED )
2012-03-23 15:02:01 -07:00
strmode = " pwm based " ;
2013-04-29 16:18:03 -07:00
else if ( lp - > mode = = REGISTER_BASED )
2012-03-23 15:02:01 -07:00
strmode = " register based " ;
2013-04-29 16:17:52 -07:00
return scnprintf ( buf , PAGE_SIZE , " %s \n " , strmode ) ;
2012-03-23 15:02:01 -07:00
}
static DEVICE_ATTR ( chip_id , S_IRUGO , lp855x_get_chip_id , NULL ) ;
static DEVICE_ATTR ( bl_ctl_mode , S_IRUGO , lp855x_get_bl_ctl_mode , NULL ) ;
static struct attribute * lp855x_attributes [ ] = {
& dev_attr_chip_id . attr ,
& dev_attr_bl_ctl_mode . attr ,
NULL ,
} ;
static const struct attribute_group lp855x_attr_group = {
. attrs = lp855x_attributes ,
} ;
2013-04-29 16:18:06 -07:00
# ifdef CONFIG_OF
2014-12-02 17:39:11 -08:00
static int lp855x_parse_dt ( struct lp855x * lp )
2013-04-29 16:18:06 -07:00
{
2014-12-02 17:39:11 -08:00
struct device * dev = lp - > dev ;
struct device_node * node = dev - > of_node ;
2013-04-29 16:18:06 -07:00
struct lp855x_platform_data * pdata ;
int rom_length ;
if ( ! node ) {
dev_err ( dev , " no platform data \n " ) ;
return - EINVAL ;
}
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
of_property_read_string ( node , " bl-name " , & pdata - > name ) ;
of_property_read_u8 ( node , " dev-ctrl " , & pdata - > device_control ) ;
of_property_read_u8 ( node , " init-brt " , & pdata - > initial_brightness ) ;
of_property_read_u32 ( node , " pwm-period " , & pdata - > period_ns ) ;
/* Fill ROM platform data if defined */
rom_length = of_get_child_count ( node ) ;
if ( rom_length > 0 ) {
struct lp855x_rom_data * rom ;
struct device_node * child ;
int i = 0 ;
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:07:58 -07:00
rom = devm_kcalloc ( dev , rom_length , sizeof ( * rom ) , GFP_KERNEL ) ;
2013-04-29 16:18:06 -07:00
if ( ! rom )
return - ENOMEM ;
for_each_child_of_node ( node , child ) {
of_property_read_u8 ( child , " rom-addr " , & rom [ i ] . addr ) ;
of_property_read_u8 ( child , " rom-val " , & rom [ i ] . val ) ;
i + + ;
}
pdata - > size_program = rom_length ;
pdata - > rom_data = & rom [ 0 ] ;
}
2014-12-02 17:39:11 -08:00
lp - > pdata = pdata ;
2013-04-29 16:18:06 -07:00
return 0 ;
}
# else
2014-12-02 17:39:11 -08:00
static int lp855x_parse_dt ( struct lp855x * lp )
2013-04-29 16:18:06 -07:00
{
return - EINVAL ;
}
# endif
2012-03-23 15:02:01 -07:00
static int lp855x_probe ( struct i2c_client * cl , const struct i2c_device_id * id )
{
struct lp855x * lp ;
int ret ;
if ( ! i2c_check_functionality ( cl - > adapter , I2C_FUNC_SMBUS_I2C_BLOCK ) )
return - EIO ;
lp = devm_kzalloc ( & cl - > dev , sizeof ( struct lp855x ) , GFP_KERNEL ) ;
if ( ! lp )
return - ENOMEM ;
lp - > client = cl ;
lp - > dev = & cl - > dev ;
lp - > chipname = id - > name ;
lp - > chip_id = id - > driver_data ;
2014-12-02 17:39:11 -08:00
lp - > pdata = dev_get_platdata ( & cl - > dev ) ;
if ( ! lp - > pdata ) {
ret = lp855x_parse_dt ( lp ) ;
if ( ret < 0 )
return ret ;
}
if ( lp - > pdata - > period_ns > 0 )
lp - > mode = PWM_BASED ;
else
lp - > mode = REGISTER_BASED ;
2015-07-20 15:45:38 +09:00
lp - > supply = devm_regulator_get ( lp - > dev , " power " ) ;
if ( IS_ERR ( lp - > supply ) ) {
if ( PTR_ERR ( lp - > supply ) = = - EPROBE_DEFER )
return - EPROBE_DEFER ;
lp - > supply = NULL ;
}
2016-06-10 12:39:57 -07:00
lp - > enable = devm_regulator_get_optional ( lp - > dev , " enable " ) ;
if ( IS_ERR ( lp - > enable ) ) {
ret = PTR_ERR ( lp - > enable ) ;
if ( ret = = - ENODEV ) {
lp - > enable = NULL ;
} else {
if ( ret ! = - EPROBE_DEFER )
dev_err ( lp - > dev , " error getting enable regulator: %d \n " ,
ret ) ;
return ret ;
}
}
2015-07-20 15:45:38 +09:00
if ( lp - > supply ) {
ret = regulator_enable ( lp - > supply ) ;
2014-12-02 17:39:12 -08:00
if ( ret < 0 ) {
dev_err ( & cl - > dev , " failed to enable supply: %d \n " , ret ) ;
return ret ;
}
}
2016-06-10 12:39:57 -07:00
if ( lp - > enable ) {
ret = regulator_enable ( lp - > enable ) ;
if ( ret < 0 ) {
dev_err ( lp - > dev , " failed to enable vddio: %d \n " , ret ) ;
2020-02-24 14:07:48 +00:00
goto disable_supply ;
2016-06-10 12:39:57 -07:00
}
/*
* LP8555 datasheet says t_RESPONSE ( time between VDDIO and
* I2C ) is 1 ms .
*/
usleep_range ( 1000 , 2000 ) ;
}
2012-03-23 15:02:01 -07:00
i2c_set_clientdata ( cl , lp ) ;
2013-02-21 16:44:05 -08:00
ret = lp855x_configure ( lp ) ;
2012-03-23 15:02:01 -07:00
if ( ret ) {
2013-02-21 16:44:05 -08:00
dev_err ( lp - > dev , " device config err: %d " , ret ) ;
2020-02-24 14:07:48 +00:00
goto disable_vddio ;
2012-03-23 15:02:01 -07:00
}
ret = lp855x_backlight_register ( lp ) ;
if ( ret ) {
dev_err ( lp - > dev ,
" failed to register backlight. err: %d \n " , ret ) ;
2020-02-24 14:07:48 +00:00
goto disable_vddio ;
2012-03-23 15:02:01 -07:00
}
ret = sysfs_create_group ( & lp - > dev - > kobj , & lp855x_attr_group ) ;
if ( ret ) {
dev_err ( lp - > dev , " failed to register sysfs. err: %d \n " , ret ) ;
2020-02-24 14:07:48 +00:00
goto disable_vddio ;
2012-03-23 15:02:01 -07:00
}
backlight_update_status ( lp - > bl ) ;
2020-02-24 14:07:48 +00:00
2012-03-23 15:02:01 -07:00
return 0 ;
2020-02-24 14:07:48 +00:00
disable_vddio :
if ( lp - > enable )
regulator_disable ( lp - > enable ) ;
disable_supply :
if ( lp - > supply )
regulator_disable ( lp - > supply ) ;
return ret ;
2012-03-23 15:02:01 -07:00
}
2012-11-19 13:26:34 -05:00
static int lp855x_remove ( struct i2c_client * cl )
2012-03-23 15:02:01 -07:00
{
struct lp855x * lp = i2c_get_clientdata ( cl ) ;
lp - > bl - > props . brightness = 0 ;
backlight_update_status ( lp - > bl ) ;
2020-02-24 14:07:48 +00:00
if ( lp - > enable )
regulator_disable ( lp - > enable ) ;
2015-07-20 15:45:38 +09:00
if ( lp - > supply )
regulator_disable ( lp - > supply ) ;
2012-03-23 15:02:01 -07:00
sysfs_remove_group ( & lp - > dev - > kobj , & lp855x_attr_group ) ;
return 0 ;
}
2013-04-29 16:18:06 -07:00
static const struct of_device_id lp855x_dt_ids [ ] = {
{ . compatible = " ti,lp8550 " , } ,
{ . compatible = " ti,lp8551 " , } ,
{ . compatible = " ti,lp8552 " , } ,
{ . compatible = " ti,lp8553 " , } ,
2013-11-12 15:08:57 -08:00
{ . compatible = " ti,lp8555 " , } ,
2013-04-29 16:18:06 -07:00
{ . compatible = " ti,lp8556 " , } ,
{ . compatible = " ti,lp8557 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , lp855x_dt_ids ) ;
2012-03-23 15:02:01 -07:00
static const struct i2c_device_id lp855x_ids [ ] = {
{ " lp8550 " , LP8550 } ,
{ " lp8551 " , LP8551 } ,
{ " lp8552 " , LP8552 } ,
{ " lp8553 " , LP8553 } ,
2013-11-12 15:08:57 -08:00
{ " lp8555 " , LP8555 } ,
2012-03-23 15:02:01 -07:00
{ " lp8556 " , LP8556 } ,
2013-02-21 16:44:06 -08:00
{ " lp8557 " , LP8557 } ,
2012-03-23 15:02:01 -07:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , lp855x_ids ) ;
static struct i2c_driver lp855x_driver = {
. driver = {
. name = " lp855x " ,
2013-04-29 16:18:06 -07:00
. of_match_table = of_match_ptr ( lp855x_dt_ids ) ,
2012-03-23 15:02:01 -07:00
} ,
. probe = lp855x_probe ,
2012-11-19 13:21:09 -05:00
. remove = lp855x_remove ,
2012-03-23 15:02:01 -07:00
. id_table = lp855x_ids ,
} ;
module_i2c_driver ( lp855x_driver ) ;
MODULE_DESCRIPTION ( " Texas Instruments LP855x Backlight driver " ) ;
MODULE_AUTHOR ( " Milo Kim <milo.kim@ti.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;