2019-05-28 19:57:06 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-04-05 10:46:19 +03:00
/*
* AD5592R Digital < - > Analog converters driver
*
* Copyright 2014 - 2016 Analog Devices Inc .
* Author : Paul Cercueil < paul . cercueil @ analog . com >
*/
# include <linux/bitops.h>
# include <linux/delay.h>
# include <linux/iio/iio.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/of.h>
# include <linux/regulator/consumer.h>
# include <linux/gpio/consumer.h>
# include <linux/gpio/driver.h>
# include <linux/property.h>
# include <dt-bindings/iio/adi,ad5592r.h>
# include "ad5592r-base.h"
static int ad5592r_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
struct ad5592r_state * st = gpiochip_get_data ( chip ) ;
int ret = 0 ;
u8 val ;
mutex_lock ( & st - > gpio_lock ) ;
if ( st - > gpio_out & BIT ( offset ) )
val = st - > gpio_val ;
else
ret = st - > ops - > gpio_read ( st , & val ) ;
mutex_unlock ( & st - > gpio_lock ) ;
if ( ret < 0 )
return ret ;
return ! ! ( val & BIT ( offset ) ) ;
}
static void ad5592r_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
{
struct ad5592r_state * st = gpiochip_get_data ( chip ) ;
mutex_lock ( & st - > gpio_lock ) ;
if ( value )
st - > gpio_val | = BIT ( offset ) ;
else
st - > gpio_val & = ~ BIT ( offset ) ;
st - > ops - > reg_write ( st , AD5592R_REG_GPIO_SET , st - > gpio_val ) ;
mutex_unlock ( & st - > gpio_lock ) ;
}
static int ad5592r_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
{
struct ad5592r_state * st = gpiochip_get_data ( chip ) ;
int ret ;
mutex_lock ( & st - > gpio_lock ) ;
st - > gpio_out & = ~ BIT ( offset ) ;
st - > gpio_in | = BIT ( offset ) ;
ret = st - > ops - > reg_write ( st , AD5592R_REG_GPIO_OUT_EN , st - > gpio_out ) ;
if ( ret < 0 )
goto err_unlock ;
ret = st - > ops - > reg_write ( st , AD5592R_REG_GPIO_IN_EN , st - > gpio_in ) ;
err_unlock :
mutex_unlock ( & st - > gpio_lock ) ;
return ret ;
}
static int ad5592r_gpio_direction_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
struct ad5592r_state * st = gpiochip_get_data ( chip ) ;
int ret ;
mutex_lock ( & st - > gpio_lock ) ;
if ( value )
st - > gpio_val | = BIT ( offset ) ;
else
st - > gpio_val & = ~ BIT ( offset ) ;
st - > gpio_in & = ~ BIT ( offset ) ;
st - > gpio_out | = BIT ( offset ) ;
ret = st - > ops - > reg_write ( st , AD5592R_REG_GPIO_SET , st - > gpio_val ) ;
if ( ret < 0 )
goto err_unlock ;
ret = st - > ops - > reg_write ( st , AD5592R_REG_GPIO_OUT_EN , st - > gpio_out ) ;
if ( ret < 0 )
goto err_unlock ;
ret = st - > ops - > reg_write ( st , AD5592R_REG_GPIO_IN_EN , st - > gpio_in ) ;
err_unlock :
mutex_unlock ( & st - > gpio_lock ) ;
return ret ;
}
static int ad5592r_gpio_request ( struct gpio_chip * chip , unsigned offset )
{
struct ad5592r_state * st = gpiochip_get_data ( chip ) ;
if ( ! ( st - > gpio_map & BIT ( offset ) ) ) {
dev_err ( st - > dev , " GPIO %d is reserved by alternate function \n " ,
offset ) ;
return - ENODEV ;
}
return 0 ;
}
static int ad5592r_gpio_init ( struct ad5592r_state * st )
{
if ( ! st - > gpio_map )
return 0 ;
st - > gpiochip . label = dev_name ( st - > dev ) ;
st - > gpiochip . base = - 1 ;
st - > gpiochip . ngpio = 8 ;
st - > gpiochip . parent = st - > dev ;
st - > gpiochip . can_sleep = true ;
st - > gpiochip . direction_input = ad5592r_gpio_direction_input ;
st - > gpiochip . direction_output = ad5592r_gpio_direction_output ;
st - > gpiochip . get = ad5592r_gpio_get ;
st - > gpiochip . set = ad5592r_gpio_set ;
st - > gpiochip . request = ad5592r_gpio_request ;
st - > gpiochip . owner = THIS_MODULE ;
mutex_init ( & st - > gpio_lock ) ;
return gpiochip_add_data ( & st - > gpiochip , st ) ;
}
static void ad5592r_gpio_cleanup ( struct ad5592r_state * st )
{
if ( st - > gpio_map )
gpiochip_remove ( & st - > gpiochip ) ;
}
static int ad5592r_reset ( struct ad5592r_state * st )
{
struct gpio_desc * gpio ;
gpio = devm_gpiod_get_optional ( st - > dev , " reset " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( gpio ) )
return PTR_ERR ( gpio ) ;
if ( gpio ) {
udelay ( 1 ) ;
gpiod_set_value ( gpio , 1 ) ;
} else {
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
/* Writing this magic value resets the device */
st - > ops - > reg_write ( st , AD5592R_REG_RESET , 0xdac ) ;
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
}
udelay ( 250 ) ;
return 0 ;
}
static int ad5592r_get_vref ( struct ad5592r_state * st )
{
int ret ;
if ( st - > reg ) {
ret = regulator_get_voltage ( st - > reg ) ;
if ( ret < 0 )
return ret ;
return ret / 1000 ;
} else {
return 2500 ;
}
}
static int ad5592r_set_channel_modes ( struct ad5592r_state * st )
{
const struct ad5592r_rw_ops * ops = st - > ops ;
int ret ;
unsigned i ;
u8 pulldown = 0 , tristate = 0 , dac = 0 , adc = 0 ;
u16 read_back ;
for ( i = 0 ; i < st - > num_channels ; i + + ) {
switch ( st - > channel_modes [ i ] ) {
case CH_MODE_DAC :
dac | = BIT ( i ) ;
break ;
case CH_MODE_ADC :
adc | = BIT ( i ) ;
break ;
case CH_MODE_DAC_AND_ADC :
dac | = BIT ( i ) ;
adc | = BIT ( i ) ;
break ;
case CH_MODE_GPIO :
st - > gpio_map | = BIT ( i ) ;
st - > gpio_in | = BIT ( i ) ; /* Default to input */
break ;
case CH_MODE_UNUSED :
/* fall-through */
default :
switch ( st - > channel_offstate [ i ] ) {
case CH_OFFSTATE_OUT_TRISTATE :
tristate | = BIT ( i ) ;
break ;
case CH_OFFSTATE_OUT_LOW :
st - > gpio_out | = BIT ( i ) ;
break ;
case CH_OFFSTATE_OUT_HIGH :
st - > gpio_out | = BIT ( i ) ;
st - > gpio_val | = BIT ( i ) ;
break ;
case CH_OFFSTATE_PULLDOWN :
/* fall-through */
default :
pulldown | = BIT ( i ) ;
break ;
}
}
}
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
/* Pull down unused pins to GND */
ret = ops - > reg_write ( st , AD5592R_REG_PULLDOWN , pulldown ) ;
if ( ret )
goto err_unlock ;
ret = ops - > reg_write ( st , AD5592R_REG_TRISTATE , tristate ) ;
if ( ret )
goto err_unlock ;
/* Configure pins that we use */
ret = ops - > reg_write ( st , AD5592R_REG_DAC_EN , dac ) ;
if ( ret )
goto err_unlock ;
ret = ops - > reg_write ( st , AD5592R_REG_ADC_EN , adc ) ;
if ( ret )
goto err_unlock ;
ret = ops - > reg_write ( st , AD5592R_REG_GPIO_SET , st - > gpio_val ) ;
if ( ret )
goto err_unlock ;
ret = ops - > reg_write ( st , AD5592R_REG_GPIO_OUT_EN , st - > gpio_out ) ;
if ( ret )
goto err_unlock ;
ret = ops - > reg_write ( st , AD5592R_REG_GPIO_IN_EN , st - > gpio_in ) ;
if ( ret )
goto err_unlock ;
/* Verify that we can read back at least one register */
ret = ops - > reg_read ( st , AD5592R_REG_ADC_EN , & read_back ) ;
if ( ! ret & & ( read_back & 0xff ) ! = adc )
ret = - EIO ;
err_unlock :
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
return ret ;
}
static int ad5592r_reset_channel_modes ( struct ad5592r_state * st )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( st - > channel_modes ) ; i + + )
st - > channel_modes [ i ] = CH_MODE_UNUSED ;
return ad5592r_set_channel_modes ( st ) ;
}
static int ad5592r_write_raw ( struct iio_dev * iio_dev ,
struct iio_chan_spec const * chan , int val , int val2 , long mask )
{
struct ad5592r_state * st = iio_priv ( iio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
if ( val > = ( 1 < < chan - > scan_type . realbits ) | | val < 0 )
return - EINVAL ;
if ( ! chan - > output )
return - EINVAL ;
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
ret = st - > ops - > write_dac ( st , chan - > channel , val ) ;
if ( ! ret )
st - > cached_dac [ chan - > channel ] = val ;
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
return ret ;
case IIO_CHAN_INFO_SCALE :
if ( chan - > type = = IIO_VOLTAGE ) {
bool gain ;
if ( val = = st - > scale_avail [ 0 ] [ 0 ] & &
val2 = = st - > scale_avail [ 0 ] [ 1 ] )
gain = false ;
else if ( val = = st - > scale_avail [ 1 ] [ 0 ] & &
val2 = = st - > scale_avail [ 1 ] [ 1 ] )
gain = true ;
else
return - EINVAL ;
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
ret = st - > ops - > reg_read ( st , AD5592R_REG_CTRL ,
& st - > cached_gp_ctrl ) ;
if ( ret < 0 ) {
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
return ret ;
}
if ( chan - > output ) {
if ( gain )
st - > cached_gp_ctrl | =
AD5592R_REG_CTRL_DAC_RANGE ;
else
st - > cached_gp_ctrl & =
~ AD5592R_REG_CTRL_DAC_RANGE ;
} else {
if ( gain )
st - > cached_gp_ctrl | =
AD5592R_REG_CTRL_ADC_RANGE ;
else
st - > cached_gp_ctrl & =
~ AD5592R_REG_CTRL_ADC_RANGE ;
}
ret = st - > ops - > reg_write ( st , AD5592R_REG_CTRL ,
st - > cached_gp_ctrl ) ;
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
return ret ;
}
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int ad5592r_read_raw ( struct iio_dev * iio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long m )
{
struct ad5592r_state * st = iio_priv ( iio_dev ) ;
u16 read_val ;
int ret ;
switch ( m ) {
case IIO_CHAN_INFO_RAW :
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
if ( ! chan - > output ) {
ret = st - > ops - > read_adc ( st , chan - > channel , & read_val ) ;
if ( ret )
goto unlock ;
if ( ( read_val > > 12 & 0x7 ) ! = ( chan - > channel & 0x7 ) ) {
dev_err ( st - > dev , " Error while reading channel %u \n " ,
chan - > channel ) ;
ret = - EIO ;
goto unlock ;
}
read_val & = GENMASK ( 11 , 0 ) ;
} else {
read_val = st - > cached_dac [ chan - > channel ] ;
}
dev_dbg ( st - > dev , " Channel %u read: 0x%04hX \n " ,
chan - > channel , read_val ) ;
* val = ( int ) read_val ;
ret = IIO_VAL_INT ;
break ;
case IIO_CHAN_INFO_SCALE :
* val = ad5592r_get_vref ( st ) ;
if ( chan - > type = = IIO_TEMP ) {
s64 tmp = * val * ( 3767897513LL / 25LL ) ;
* val = div_s64_rem ( tmp , 1000000000LL , val2 ) ;
ret = IIO_VAL_INT_PLUS_MICRO ;
} else {
int mult ;
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
if ( chan - > output )
mult = ! ! ( st - > cached_gp_ctrl &
AD5592R_REG_CTRL_DAC_RANGE ) ;
else
mult = ! ! ( st - > cached_gp_ctrl &
AD5592R_REG_CTRL_ADC_RANGE ) ;
* val * = + + mult ;
* val2 = chan - > scan_type . realbits ;
ret = IIO_VAL_FRACTIONAL_LOG2 ;
}
break ;
case IIO_CHAN_INFO_OFFSET :
ret = ad5592r_get_vref ( st ) ;
2020-05-20 15:02:01 +03:00
mutex_lock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
if ( st - > cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE )
* val = ( - 34365 * 25 ) / ret ;
else
* val = ( - 75365 * 25 ) / ret ;
ret = IIO_VAL_INT ;
break ;
default :
ret = - EINVAL ;
}
unlock :
2020-05-20 15:02:01 +03:00
mutex_unlock ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
return ret ;
}
static int ad5592r_write_raw_get_fmt ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , long mask )
{
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
return IIO_VAL_INT_PLUS_NANO ;
default :
return IIO_VAL_INT_PLUS_MICRO ;
}
return - EINVAL ;
}
static const struct iio_info ad5592r_info = {
. read_raw = ad5592r_read_raw ,
. write_raw = ad5592r_write_raw ,
. write_raw_get_fmt = ad5592r_write_raw_get_fmt ,
} ;
static ssize_t ad5592r_show_scale_available ( struct iio_dev * iio_dev ,
uintptr_t private ,
const struct iio_chan_spec * chan ,
char * buf )
{
struct ad5592r_state * st = iio_priv ( iio_dev ) ;
return sprintf ( buf , " %d.%09u %d.%09u \n " ,
st - > scale_avail [ 0 ] [ 0 ] , st - > scale_avail [ 0 ] [ 1 ] ,
st - > scale_avail [ 1 ] [ 0 ] , st - > scale_avail [ 1 ] [ 1 ] ) ;
}
2020-05-27 00:02:20 +03:00
static const struct iio_chan_spec_ext_info ad5592r_ext_info [ ] = {
2016-04-05 10:46:19 +03:00
{
. name = " scale_available " ,
. read = ad5592r_show_scale_available ,
. shared = true ,
} ,
{ } ,
} ;
static void ad5592r_setup_channel ( struct iio_dev * iio_dev ,
struct iio_chan_spec * chan , bool output , unsigned id )
{
chan - > type = IIO_VOLTAGE ;
chan - > indexed = 1 ;
chan - > output = output ;
chan - > channel = id ;
chan - > info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ;
chan - > info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) ;
chan - > scan_type . sign = ' u ' ;
chan - > scan_type . realbits = 12 ;
chan - > scan_type . storagebits = 16 ;
chan - > ext_info = ad5592r_ext_info ;
}
2020-05-25 16:10:34 +03:00
static int ad5592r_alloc_channels ( struct iio_dev * iio_dev )
2016-04-05 10:46:19 +03:00
{
2020-05-25 16:10:34 +03:00
struct ad5592r_state * st = iio_priv ( iio_dev ) ;
2016-04-05 10:46:19 +03:00
unsigned i , curr_channel = 0 ,
num_channels = st - > num_channels ;
struct iio_chan_spec * channels ;
struct fwnode_handle * child ;
u32 reg , tmp ;
int ret ;
device_for_each_child_node ( st - > dev , child ) {
ret = fwnode_property_read_u32 ( child , " reg " , & reg ) ;
2016-04-29 12:03:31 +03:00
if ( ret | | reg > = ARRAY_SIZE ( st - > channel_modes ) )
2016-04-05 10:46:19 +03:00
continue ;
ret = fwnode_property_read_u32 ( child , " adi,mode " , & tmp ) ;
if ( ! ret )
st - > channel_modes [ reg ] = tmp ;
fwnode_property_read_u32 ( child , " adi,off-state " , & tmp ) ;
if ( ! ret )
st - > channel_offstate [ reg ] = tmp ;
}
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-13 00:07:58 +03:00
channels = devm_kcalloc ( st - > dev ,
1 + 2 * num_channels , sizeof ( * channels ) ,
GFP_KERNEL ) ;
2016-04-05 10:46:19 +03:00
if ( ! channels )
return - ENOMEM ;
for ( i = 0 ; i < num_channels ; i + + ) {
switch ( st - > channel_modes [ i ] ) {
case CH_MODE_DAC :
ad5592r_setup_channel ( iio_dev , & channels [ curr_channel ] ,
true , i ) ;
curr_channel + + ;
break ;
case CH_MODE_ADC :
ad5592r_setup_channel ( iio_dev , & channels [ curr_channel ] ,
false , i ) ;
curr_channel + + ;
break ;
case CH_MODE_DAC_AND_ADC :
ad5592r_setup_channel ( iio_dev , & channels [ curr_channel ] ,
true , i ) ;
curr_channel + + ;
ad5592r_setup_channel ( iio_dev , & channels [ curr_channel ] ,
false , i ) ;
curr_channel + + ;
break ;
default :
continue ;
}
}
channels [ curr_channel ] . type = IIO_TEMP ;
channels [ curr_channel ] . channel = 8 ;
channels [ curr_channel ] . info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_OFFSET ) ;
curr_channel + + ;
iio_dev - > num_channels = curr_channel ;
iio_dev - > channels = channels ;
return 0 ;
}
static void ad5592r_init_scales ( struct ad5592r_state * st , int vref_mV )
{
s64 tmp = ( s64 ) vref_mV * 1000000000LL > > 12 ;
st - > scale_avail [ 0 ] [ 0 ] =
div_s64_rem ( tmp , 1000000000LL , & st - > scale_avail [ 0 ] [ 1 ] ) ;
st - > scale_avail [ 1 ] [ 0 ] =
div_s64_rem ( tmp * 2 , 1000000000LL , & st - > scale_avail [ 1 ] [ 1 ] ) ;
}
int ad5592r_probe ( struct device * dev , const char * name ,
const struct ad5592r_rw_ops * ops )
{
struct iio_dev * iio_dev ;
struct ad5592r_state * st ;
int ret ;
iio_dev = devm_iio_device_alloc ( dev , sizeof ( * st ) ) ;
if ( ! iio_dev )
return - ENOMEM ;
st = iio_priv ( iio_dev ) ;
st - > dev = dev ;
st - > ops = ops ;
st - > num_channels = 8 ;
dev_set_drvdata ( dev , iio_dev ) ;
st - > reg = devm_regulator_get_optional ( dev , " vref " ) ;
if ( IS_ERR ( st - > reg ) ) {
if ( ( PTR_ERR ( st - > reg ) ! = - ENODEV ) & & dev - > of_node )
return PTR_ERR ( st - > reg ) ;
st - > reg = NULL ;
} else {
ret = regulator_enable ( st - > reg ) ;
if ( ret )
return ret ;
}
iio_dev - > name = name ;
iio_dev - > info = & ad5592r_info ;
iio_dev - > modes = INDIO_DIRECT_MODE ;
2020-05-20 15:02:01 +03:00
mutex_init ( & st - > lock ) ;
2016-04-05 10:46:19 +03:00
ad5592r_init_scales ( st , ad5592r_get_vref ( st ) ) ;
ret = ad5592r_reset ( st ) ;
if ( ret )
goto error_disable_reg ;
ret = ops - > reg_write ( st , AD5592R_REG_PD ,
( st - > reg = = NULL ) ? AD5592R_REG_PD_EN_REF : 0 ) ;
if ( ret )
goto error_disable_reg ;
2020-05-25 16:10:34 +03:00
ret = ad5592r_alloc_channels ( iio_dev ) ;
2016-04-05 10:46:19 +03:00
if ( ret )
goto error_disable_reg ;
ret = ad5592r_set_channel_modes ( st ) ;
if ( ret )
goto error_reset_ch_modes ;
ret = iio_device_register ( iio_dev ) ;
if ( ret )
goto error_reset_ch_modes ;
ret = ad5592r_gpio_init ( st ) ;
if ( ret )
goto error_dev_unregister ;
return 0 ;
error_dev_unregister :
iio_device_unregister ( iio_dev ) ;
error_reset_ch_modes :
ad5592r_reset_channel_modes ( st ) ;
error_disable_reg :
if ( st - > reg )
regulator_disable ( st - > reg ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( ad5592r_probe ) ;
int ad5592r_remove ( struct device * dev )
{
struct iio_dev * iio_dev = dev_get_drvdata ( dev ) ;
struct ad5592r_state * st = iio_priv ( iio_dev ) ;
iio_device_unregister ( iio_dev ) ;
ad5592r_reset_channel_modes ( st ) ;
ad5592r_gpio_cleanup ( st ) ;
if ( st - > reg )
regulator_disable ( st - > reg ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ad5592r_remove ) ;
MODULE_AUTHOR ( " Paul Cercueil <paul.cercueil@analog.com> " ) ;
MODULE_DESCRIPTION ( " Analog Devices AD5592R multi-channel converters " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;