2011-03-08 22:01:39 -08:00
/*
* Hardware monitoring driver for UCD90xxx Sequencer and System Health
* Controller series
*
* Copyright ( C ) 2011 Ericsson AB .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2018-03-16 16:22:06 -05:00
# include <linux/debugfs.h>
2011-03-08 22:01:39 -08:00
# include <linux/kernel.h>
# include <linux/module.h>
2017-02-24 10:13:07 -03:00
# include <linux/of_device.h>
2011-03-08 22:01:39 -08:00
# include <linux/init.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/i2c.h>
2017-05-21 22:34:43 +02:00
# include <linux/pmbus.h>
2018-03-16 16:22:05 -05:00
# include <linux/gpio.h>
# include <linux/gpio/driver.h>
2011-03-08 22:01:39 -08:00
# include "pmbus.h"
2016-08-19 21:08:45 -05:00
enum chips { ucd9000 , ucd90120 , ucd90124 , ucd90160 , ucd9090 , ucd90910 } ;
2011-03-08 22:01:39 -08:00
# define UCD9000_MONITOR_CONFIG 0xd5
# define UCD9000_NUM_PAGES 0xd6
# define UCD9000_FAN_CONFIG_INDEX 0xe7
# define UCD9000_FAN_CONFIG 0xe8
2018-03-16 16:22:06 -05:00
# define UCD9000_MFR_STATUS 0xf3
2018-03-16 16:22:05 -05:00
# define UCD9000_GPIO_SELECT 0xfa
# define UCD9000_GPIO_CONFIG 0xfb
2011-03-08 22:01:39 -08:00
# define UCD9000_DEVICE_ID 0xfd
2018-03-16 16:22:05 -05:00
/* GPIO CONFIG bits */
# define UCD9000_GPIO_CONFIG_ENABLE BIT(0)
# define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1)
# define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2)
# define UCD9000_GPIO_CONFIG_STATUS BIT(3)
# define UCD9000_GPIO_INPUT 0
# define UCD9000_GPIO_OUTPUT 1
2011-03-08 22:01:39 -08:00
# define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07)
# define UCD9000_MON_PAGE(x) ((x) & 0x0f)
# define UCD9000_MON_VOLTAGE 1
# define UCD9000_MON_TEMPERATURE 2
# define UCD9000_MON_CURRENT 3
# define UCD9000_MON_VOLTAGE_HW 4
# define UCD9000_NUM_FAN 4
2018-03-16 16:22:05 -05:00
# define UCD9000_GPIO_NAME_LEN 16
# define UCD9090_NUM_GPIOS 23
# define UCD901XX_NUM_GPIOS 26
# define UCD90910_NUM_GPIOS 26
2018-03-16 16:22:06 -05:00
# define UCD9000_DEBUGFS_NAME_LEN 24
# define UCD9000_GPI_COUNT 8
2011-03-08 22:01:39 -08:00
struct ucd9000_data {
u8 fan_data [ UCD9000_NUM_FAN ] [ I2C_SMBUS_BLOCK_MAX ] ;
struct pmbus_driver_info info ;
2018-03-16 16:22:05 -05:00
# ifdef CONFIG_GPIOLIB
struct gpio_chip gpio ;
# endif
2018-03-16 16:22:06 -05:00
struct dentry * debugfs ;
2011-03-08 22:01:39 -08:00
} ;
# define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
2018-03-16 16:22:06 -05:00
struct ucd9000_debugfs_entry {
struct i2c_client * client ;
u8 index ;
} ;
2011-03-08 22:01:39 -08:00
static int ucd9000_get_fan_config ( struct i2c_client * client , int fan )
{
int fan_config = 0 ;
struct ucd9000_data * data
= to_ucd9000_data ( pmbus_get_driver_info ( client ) ) ;
if ( data - > fan_data [ fan ] [ 3 ] & 1 )
fan_config | = PB_FAN_2_INSTALLED ; /* Use lower bit position */
/* Pulses/revolution */
fan_config | = ( data - > fan_data [ fan ] [ 3 ] & 0x06 ) > > 1 ;
return fan_config ;
}
static int ucd9000_read_byte_data ( struct i2c_client * client , int page , int reg )
{
int ret = 0 ;
int fan_config ;
switch ( reg ) {
case PMBUS_FAN_CONFIG_12 :
2011-07-29 22:19:39 -07:00
if ( page > 0 )
2011-09-01 08:34:31 -07:00
return - ENXIO ;
2011-03-08 22:01:39 -08:00
ret = ucd9000_get_fan_config ( client , 0 ) ;
if ( ret < 0 )
return ret ;
fan_config = ret < < 4 ;
ret = ucd9000_get_fan_config ( client , 1 ) ;
if ( ret < 0 )
return ret ;
fan_config | = ret ;
ret = fan_config ;
break ;
case PMBUS_FAN_CONFIG_34 :
2011-07-29 22:19:39 -07:00
if ( page > 0 )
2011-09-01 08:34:31 -07:00
return - ENXIO ;
2011-03-08 22:01:39 -08:00
ret = ucd9000_get_fan_config ( client , 2 ) ;
if ( ret < 0 )
return ret ;
fan_config = ret < < 4 ;
ret = ucd9000_get_fan_config ( client , 3 ) ;
if ( ret < 0 )
return ret ;
fan_config | = ret ;
ret = fan_config ;
break ;
default :
ret = - ENODATA ;
break ;
}
return ret ;
}
static const struct i2c_device_id ucd9000_id [ ] = {
{ " ucd9000 " , ucd9000 } ,
{ " ucd90120 " , ucd90120 } ,
{ " ucd90124 " , ucd90124 } ,
2016-08-19 21:08:45 -05:00
{ " ucd90160 " , ucd90160 } ,
2011-03-08 22:01:39 -08:00
{ " ucd9090 " , ucd9090 } ,
{ " ucd90910 " , ucd90910 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ucd9000_id ) ;
2019-04-04 06:17:49 -07:00
static const struct of_device_id __maybe_unused ucd9000_of_match [ ] = {
2017-02-24 10:13:07 -03:00
{
. compatible = " ti,ucd9000 " ,
. data = ( void * ) ucd9000
} ,
{
. compatible = " ti,ucd90120 " ,
. data = ( void * ) ucd90120
} ,
{
. compatible = " ti,ucd90124 " ,
. data = ( void * ) ucd90124
} ,
{
. compatible = " ti,ucd90160 " ,
. data = ( void * ) ucd90160
} ,
{
. compatible = " ti,ucd9090 " ,
. data = ( void * ) ucd9090
} ,
{
. compatible = " ti,ucd90910 " ,
. data = ( void * ) ucd90910
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ucd9000_of_match ) ;
2018-03-16 16:22:05 -05:00
# ifdef CONFIG_GPIOLIB
static int ucd9000_gpio_read_config ( struct i2c_client * client ,
unsigned int offset )
{
int ret ;
/* No page set required */
ret = i2c_smbus_write_byte_data ( client , UCD9000_GPIO_SELECT , offset ) ;
if ( ret < 0 )
return ret ;
return i2c_smbus_read_byte_data ( client , UCD9000_GPIO_CONFIG ) ;
}
static int ucd9000_gpio_get ( struct gpio_chip * gc , unsigned int offset )
{
struct i2c_client * client = gpiochip_get_data ( gc ) ;
int ret ;
ret = ucd9000_gpio_read_config ( client , offset ) ;
if ( ret < 0 )
return ret ;
return ! ! ( ret & UCD9000_GPIO_CONFIG_STATUS ) ;
}
static void ucd9000_gpio_set ( struct gpio_chip * gc , unsigned int offset ,
int value )
{
struct i2c_client * client = gpiochip_get_data ( gc ) ;
int ret ;
ret = ucd9000_gpio_read_config ( client , offset ) ;
if ( ret < 0 ) {
dev_dbg ( & client - > dev , " failed to read GPIO %d config: %d \n " ,
offset , ret ) ;
return ;
}
if ( value ) {
if ( ret & UCD9000_GPIO_CONFIG_STATUS )
return ;
ret | = UCD9000_GPIO_CONFIG_STATUS ;
} else {
if ( ! ( ret & UCD9000_GPIO_CONFIG_STATUS ) )
return ;
ret & = ~ UCD9000_GPIO_CONFIG_STATUS ;
}
ret | = UCD9000_GPIO_CONFIG_ENABLE ;
/* Page set not required */
ret = i2c_smbus_write_byte_data ( client , UCD9000_GPIO_CONFIG , ret ) ;
if ( ret < 0 ) {
dev_dbg ( & client - > dev , " Failed to write GPIO %d config: %d \n " ,
offset , ret ) ;
return ;
}
ret & = ~ UCD9000_GPIO_CONFIG_ENABLE ;
ret = i2c_smbus_write_byte_data ( client , UCD9000_GPIO_CONFIG , ret ) ;
if ( ret < 0 )
dev_dbg ( & client - > dev , " Failed to write GPIO %d config: %d \n " ,
offset , ret ) ;
}
static int ucd9000_gpio_get_direction ( struct gpio_chip * gc ,
unsigned int offset )
{
struct i2c_client * client = gpiochip_get_data ( gc ) ;
int ret ;
ret = ucd9000_gpio_read_config ( client , offset ) ;
if ( ret < 0 )
return ret ;
return ! ( ret & UCD9000_GPIO_CONFIG_OUT_ENABLE ) ;
}
static int ucd9000_gpio_set_direction ( struct gpio_chip * gc ,
unsigned int offset , bool direction_out ,
int requested_out )
{
struct i2c_client * client = gpiochip_get_data ( gc ) ;
int ret , config , out_val ;
ret = ucd9000_gpio_read_config ( client , offset ) ;
if ( ret < 0 )
return ret ;
if ( direction_out ) {
out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0 ;
if ( ret & UCD9000_GPIO_CONFIG_OUT_ENABLE ) {
if ( ( ret & UCD9000_GPIO_CONFIG_OUT_VALUE ) = = out_val )
return 0 ;
} else {
ret | = UCD9000_GPIO_CONFIG_OUT_ENABLE ;
}
if ( out_val )
ret | = UCD9000_GPIO_CONFIG_OUT_VALUE ;
else
ret & = ~ UCD9000_GPIO_CONFIG_OUT_VALUE ;
} else {
if ( ! ( ret & UCD9000_GPIO_CONFIG_OUT_ENABLE ) )
return 0 ;
ret & = ~ UCD9000_GPIO_CONFIG_OUT_ENABLE ;
}
ret | = UCD9000_GPIO_CONFIG_ENABLE ;
config = ret ;
/* Page set not required */
ret = i2c_smbus_write_byte_data ( client , UCD9000_GPIO_CONFIG , config ) ;
if ( ret < 0 )
return ret ;
config & = ~ UCD9000_GPIO_CONFIG_ENABLE ;
return i2c_smbus_write_byte_data ( client , UCD9000_GPIO_CONFIG , config ) ;
}
static int ucd9000_gpio_direction_input ( struct gpio_chip * gc ,
unsigned int offset )
{
return ucd9000_gpio_set_direction ( gc , offset , UCD9000_GPIO_INPUT , 0 ) ;
}
static int ucd9000_gpio_direction_output ( struct gpio_chip * gc ,
unsigned int offset , int val )
{
return ucd9000_gpio_set_direction ( gc , offset , UCD9000_GPIO_OUTPUT ,
val ) ;
}
static void ucd9000_probe_gpio ( struct i2c_client * client ,
const struct i2c_device_id * mid ,
struct ucd9000_data * data )
{
int rc ;
switch ( mid - > driver_data ) {
case ucd9090 :
data - > gpio . ngpio = UCD9090_NUM_GPIOS ;
break ;
case ucd90120 :
case ucd90124 :
case ucd90160 :
data - > gpio . ngpio = UCD901XX_NUM_GPIOS ;
break ;
case ucd90910 :
data - > gpio . ngpio = UCD90910_NUM_GPIOS ;
break ;
default :
return ; /* GPIO support is optional. */
}
/*
* Pinmux support has not been added to the new gpio_chip .
* This support should be added when possible given the mux
* behavior of these IO devices .
*/
data - > gpio . label = client - > name ;
data - > gpio . get_direction = ucd9000_gpio_get_direction ;
data - > gpio . direction_input = ucd9000_gpio_direction_input ;
data - > gpio . direction_output = ucd9000_gpio_direction_output ;
data - > gpio . get = ucd9000_gpio_get ;
data - > gpio . set = ucd9000_gpio_set ;
data - > gpio . can_sleep = true ;
data - > gpio . base = - 1 ;
data - > gpio . parent = & client - > dev ;
rc = devm_gpiochip_add_data ( & client - > dev , & data - > gpio , client ) ;
if ( rc )
dev_warn ( & client - > dev , " Could not add gpiochip: %d \n " , rc ) ;
}
# else
static void ucd9000_probe_gpio ( struct i2c_client * client ,
const struct i2c_device_id * mid ,
struct ucd9000_data * data )
{
}
# endif /* CONFIG_GPIOLIB */
2018-03-16 16:22:06 -05:00
# ifdef CONFIG_DEBUG_FS
static int ucd9000_get_mfr_status ( struct i2c_client * client , u8 * buffer )
{
int ret = pmbus_set_page ( client , 0 ) ;
if ( ret < 0 )
return ret ;
return i2c_smbus_read_block_data ( client , UCD9000_MFR_STATUS , buffer ) ;
}
static int ucd9000_debugfs_show_mfr_status_bit ( void * data , u64 * val )
{
struct ucd9000_debugfs_entry * entry = data ;
struct i2c_client * client = entry - > client ;
u8 buffer [ I2C_SMBUS_BLOCK_MAX ] ;
int ret ;
ret = ucd9000_get_mfr_status ( client , buffer ) ;
if ( ret < 0 )
return ret ;
/*
* Attribute only created for devices with gpi fault bits at bits
* 16 - 23 , which is the second byte of the response .
*/
* val = ! ! ( buffer [ 1 ] & BIT ( entry - > index ) ) ;
return 0 ;
}
DEFINE_DEBUGFS_ATTRIBUTE ( ucd9000_debugfs_mfr_status_bit ,
ucd9000_debugfs_show_mfr_status_bit , NULL , " %1lld \n " ) ;
static ssize_t ucd9000_debugfs_read_mfr_status ( struct file * file ,
char __user * buf , size_t count ,
loff_t * ppos )
{
struct i2c_client * client = file - > private_data ;
u8 buffer [ I2C_SMBUS_BLOCK_MAX ] ;
char str [ ( I2C_SMBUS_BLOCK_MAX * 2 ) + 2 ] ;
char * res ;
int rc ;
rc = ucd9000_get_mfr_status ( client , buffer ) ;
if ( rc < 0 )
return rc ;
res = bin2hex ( str , buffer , min ( rc , I2C_SMBUS_BLOCK_MAX ) ) ;
* res + + = ' \n ' ;
* res = 0 ;
return simple_read_from_buffer ( buf , count , ppos , str , res - str ) ;
}
static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = {
. llseek = noop_llseek ,
. read = ucd9000_debugfs_read_mfr_status ,
. open = simple_open ,
} ;
static int ucd9000_init_debugfs ( struct i2c_client * client ,
const struct i2c_device_id * mid ,
struct ucd9000_data * data )
{
struct dentry * debugfs ;
struct ucd9000_debugfs_entry * entries ;
int i ;
char name [ UCD9000_DEBUGFS_NAME_LEN ] ;
debugfs = pmbus_get_debugfs_dir ( client ) ;
if ( ! debugfs )
return - ENOENT ;
data - > debugfs = debugfs_create_dir ( client - > name , debugfs ) ;
if ( ! data - > debugfs )
return - ENOENT ;
/*
* Of the chips this driver supports , only the UCD9090 , UCD90160 ,
* and UCD90910 report GPI faults in their MFR_STATUS register , so only
* create the GPI fault debugfs attributes for those chips .
*/
if ( mid - > driver_data = = ucd9090 | | mid - > driver_data = = ucd90160 | |
mid - > driver_data = = ucd90910 ) {
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
entries = devm_kcalloc ( & client - > dev ,
UCD9000_GPI_COUNT , sizeof ( * entries ) ,
2018-03-16 16:22:06 -05:00
GFP_KERNEL ) ;
if ( ! entries )
return - ENOMEM ;
for ( i = 0 ; i < UCD9000_GPI_COUNT ; i + + ) {
entries [ i ] . client = client ;
entries [ i ] . index = i ;
scnprintf ( name , UCD9000_DEBUGFS_NAME_LEN ,
" gpi%d_alarm " , i + 1 ) ;
debugfs_create_file ( name , 0444 , data - > debugfs ,
& entries [ i ] ,
& ucd9000_debugfs_mfr_status_bit ) ;
}
}
scnprintf ( name , UCD9000_DEBUGFS_NAME_LEN , " mfr_status " ) ;
debugfs_create_file ( name , 0444 , data - > debugfs , client ,
& ucd9000_debugfs_show_mfr_status_fops ) ;
return 0 ;
}
# else
static int ucd9000_init_debugfs ( struct i2c_client * client ,
const struct i2c_device_id * mid ,
struct ucd9000_data * data )
{
return 0 ;
}
# endif /* CONFIG_DEBUG_FS */
2011-03-08 22:01:39 -08:00
static int ucd9000_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
u8 block_buffer [ I2C_SMBUS_BLOCK_MAX + 1 ] ;
struct ucd9000_data * data ;
struct pmbus_driver_info * info ;
const struct i2c_device_id * mid ;
2017-02-24 10:13:07 -03:00
enum chips chip ;
2011-03-08 22:01:39 -08:00
int i , ret ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA ) )
return - ENODEV ;
ret = i2c_smbus_read_block_data ( client , UCD9000_DEVICE_ID ,
block_buffer ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to read device ID \n " ) ;
return ret ;
}
block_buffer [ ret ] = ' \0 ' ;
dev_info ( & client - > dev , " Device ID %s \n " , block_buffer ) ;
2011-08-31 11:53:41 -04:00
for ( mid = ucd9000_id ; mid - > name [ 0 ] ; mid + + ) {
2011-03-08 22:01:39 -08:00
if ( ! strncasecmp ( mid - > name , block_buffer , strlen ( mid - > name ) ) )
break ;
}
2011-08-31 11:53:41 -04:00
if ( ! mid - > name [ 0 ] ) {
2011-03-08 22:01:39 -08:00
dev_err ( & client - > dev , " Unsupported device \n " ) ;
return - ENODEV ;
}
2017-02-24 10:13:07 -03:00
if ( client - > dev . of_node )
chip = ( enum chips ) of_device_get_match_data ( & client - > dev ) ;
else
chip = id - > driver_data ;
if ( chip ! = ucd9000 & & chip ! = mid - > driver_data )
2011-03-08 22:01:39 -08:00
dev_notice ( & client - > dev ,
" Device mismatch: Configured %s, detected %s \n " ,
id - > name , mid - > name ) ;
2012-02-22 08:56:43 -08:00
data = devm_kzalloc ( & client - > dev , sizeof ( struct ucd9000_data ) ,
GFP_KERNEL ) ;
2011-03-08 22:01:39 -08:00
if ( ! data )
return - ENOMEM ;
info = & data - > info ;
ret = i2c_smbus_read_byte_data ( client , UCD9000_NUM_PAGES ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev ,
" Failed to read number of active pages \n " ) ;
2012-02-22 08:56:43 -08:00
return ret ;
2011-03-08 22:01:39 -08:00
}
info - > pages = ret ;
if ( ! info - > pages ) {
dev_err ( & client - > dev , " No pages configured \n " ) ;
2012-02-22 08:56:43 -08:00
return - ENODEV ;
2011-03-08 22:01:39 -08:00
}
/* The internal temperature sensor is always active */
info - > func [ 0 ] = PMBUS_HAVE_TEMP ;
/* Everything else is configurable */
ret = i2c_smbus_read_block_data ( client , UCD9000_MONITOR_CONFIG ,
block_buffer ) ;
if ( ret < = 0 ) {
dev_err ( & client - > dev , " Failed to read configuration data \n " ) ;
2012-02-22 08:56:43 -08:00
return - ENODEV ;
2011-03-08 22:01:39 -08:00
}
for ( i = 0 ; i < ret ; i + + ) {
int page = UCD9000_MON_PAGE ( block_buffer [ i ] ) ;
if ( page > = info - > pages )
continue ;
switch ( UCD9000_MON_TYPE ( block_buffer [ i ] ) ) {
case UCD9000_MON_VOLTAGE :
case UCD9000_MON_VOLTAGE_HW :
info - > func [ page ] | = PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT ;
break ;
case UCD9000_MON_TEMPERATURE :
info - > func [ page ] | = PMBUS_HAVE_TEMP2
| PMBUS_HAVE_STATUS_TEMP ;
break ;
case UCD9000_MON_CURRENT :
info - > func [ page ] | = PMBUS_HAVE_IOUT
| PMBUS_HAVE_STATUS_IOUT ;
break ;
default :
break ;
}
}
/* Fan configuration */
if ( mid - > driver_data = = ucd90124 ) {
for ( i = 0 ; i < UCD9000_NUM_FAN ; i + + ) {
i2c_smbus_write_byte_data ( client ,
UCD9000_FAN_CONFIG_INDEX , i ) ;
ret = i2c_smbus_read_block_data ( client ,
UCD9000_FAN_CONFIG ,
data - > fan_data [ i ] ) ;
if ( ret < 0 )
2012-02-22 08:56:43 -08:00
return ret ;
2011-03-08 22:01:39 -08:00
}
i2c_smbus_write_byte_data ( client , UCD9000_FAN_CONFIG_INDEX , 0 ) ;
info - > read_byte_data = ucd9000_read_byte_data ;
info - > func [ 0 ] | = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
| PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34 ;
}
2018-03-16 16:22:05 -05:00
ucd9000_probe_gpio ( client , mid , data ) ;
2018-03-16 16:22:06 -05:00
ret = pmbus_do_probe ( client , mid , info ) ;
if ( ret )
return ret ;
ret = ucd9000_init_debugfs ( client , mid , data ) ;
if ( ret )
dev_warn ( & client - > dev , " Failed to register debugfs: %d \n " ,
ret ) ;
return 0 ;
2011-03-08 22:01:39 -08:00
}
/* This is the driver that will be inserted */
static struct i2c_driver ucd9000_driver = {
. driver = {
. name = " ucd9000 " ,
2017-02-24 10:13:07 -03:00
. of_match_table = of_match_ptr ( ucd9000_of_match ) ,
2011-03-08 22:01:39 -08:00
} ,
. probe = ucd9000_probe ,
2012-02-22 08:56:44 -08:00
. remove = pmbus_do_remove ,
2011-03-08 22:01:39 -08:00
. id_table = ucd9000_id ,
} ;
2012-01-20 15:38:18 +08:00
module_i2c_driver ( ucd9000_driver ) ;
2011-03-08 22:01:39 -08:00
MODULE_AUTHOR ( " Guenter Roeck " ) ;
MODULE_DESCRIPTION ( " PMBus driver for TI UCD90xxx " ) ;
MODULE_LICENSE ( " GPL " ) ;