2020-11-23 21:56:57 +03:00
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for MAX127 .
*
* Copyright ( c ) 2020 Facebook Inc .
*/
# include <linux/err.h>
# include <linux/hwmon.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/module.h>
/*
* MAX127 Control Byte . Refer to MAX127 datasheet , Table 1 " Control-Byte
* Format " for details.
*/
# define MAX127_CTRL_START BIT(7)
# define MAX127_CTRL_SEL_SHIFT 4
# define MAX127_CTRL_RNG BIT(3)
# define MAX127_CTRL_BIP BIT(2)
# define MAX127_CTRL_PD1 BIT(1)
# define MAX127_CTRL_PD0 BIT(0)
# define MAX127_NUM_CHANNELS 8
# define MAX127_SET_CHANNEL(ch) (((ch) & 7) << MAX127_CTRL_SEL_SHIFT)
/*
* MAX127 channel input ranges . Refer to MAX127 datasheet , Table 3 " Range
* and Polarity Selection " for details.
*/
# define MAX127_FULL_RANGE 10000 /* 10V */
# define MAX127_HALF_RANGE 5000 /* 5V */
/*
* MAX127 returns 2 bytes at read :
* - the first byte contains data [ 11 : 4 ] .
* - the second byte contains data [ 3 : 0 ] ( MSB ) and 4 dummy 0 s ( LSB ) .
* Refer to MAX127 datasheet , " Read a Conversion (Read Cycle) " section
* for details .
*/
# define MAX127_DATA_LEN 2
# define MAX127_DATA_SHIFT 4
# define MAX127_SIGN_BIT BIT(11)
struct max127_data {
struct mutex lock ;
struct i2c_client * client ;
u8 ctrl_byte [ MAX127_NUM_CHANNELS ] ;
} ;
static int max127_select_channel ( struct i2c_client * client , u8 ctrl_byte )
{
int status ;
struct i2c_msg msg = {
. addr = client - > addr ,
. flags = 0 ,
. len = sizeof ( ctrl_byte ) ,
. buf = & ctrl_byte ,
} ;
status = i2c_transfer ( client - > adapter , & msg , 1 ) ;
if ( status < 0 )
return status ;
if ( status ! = 1 )
return - EIO ;
return 0 ;
}
static int max127_read_channel ( struct i2c_client * client , long * val )
{
int status ;
u8 i2c_data [ MAX127_DATA_LEN ] ;
struct i2c_msg msg = {
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = sizeof ( i2c_data ) ,
. buf = i2c_data ,
} ;
status = i2c_transfer ( client - > adapter , & msg , 1 ) ;
if ( status < 0 )
return status ;
if ( status ! = 1 )
return - EIO ;
* val = ( i2c_data [ 1 ] > > MAX127_DATA_SHIFT ) |
( ( u16 ) i2c_data [ 0 ] < < MAX127_DATA_SHIFT ) ;
return 0 ;
}
static long max127_process_raw ( u8 ctrl_byte , long raw )
{
long scale , weight ;
/*
* MAX127 ' s data coding is binary in unipolar mode with 1 LSB =
* ( Full - Scale / 4096 ) and two ’ s complement binary in bipolar mode
* with 1 LSB = [ ( 2 x | FS | ) / 4096 ] .
* Refer to MAX127 datasheet , " Transfer Function " section for
* details .
*/
scale = ( ctrl_byte & MAX127_CTRL_RNG ) ? MAX127_FULL_RANGE :
MAX127_HALF_RANGE ;
if ( ctrl_byte & MAX127_CTRL_BIP ) {
weight = ( raw & MAX127_SIGN_BIT ) ;
raw & = ~ MAX127_SIGN_BIT ;
raw - = weight ;
raw * = 2 ;
}
return raw * scale / 4096 ;
}
static int max127_read_input ( struct max127_data * data , int channel , long * val )
{
long raw ;
int status ;
struct i2c_client * client = data - > client ;
u8 ctrl_byte = data - > ctrl_byte [ channel ] ;
mutex_lock ( & data - > lock ) ;
status = max127_select_channel ( client , ctrl_byte ) ;
if ( status )
goto exit ;
status = max127_read_channel ( client , & raw ) ;
if ( status )
goto exit ;
* val = max127_process_raw ( ctrl_byte , raw ) ;
exit :
mutex_unlock ( & data - > lock ) ;
return status ;
}
static int max127_read_min ( struct max127_data * data , int channel , long * val )
{
u8 rng_bip = ( data - > ctrl_byte [ channel ] > > 2 ) & 3 ;
static const int min_input_map [ 4 ] = {
0 , /* RNG=0, BIP=0 */
- MAX127_HALF_RANGE , /* RNG=0, BIP=1 */
0 , /* RNG=1, BIP=0 */
- MAX127_FULL_RANGE , /* RNG=1, BIP=1 */
} ;
* val = min_input_map [ rng_bip ] ;
return 0 ;
}
static int max127_read_max ( struct max127_data * data , int channel , long * val )
{
u8 rng_bip = ( data - > ctrl_byte [ channel ] > > 2 ) & 3 ;
static const int max_input_map [ 4 ] = {
MAX127_HALF_RANGE , /* RNG=0, BIP=0 */
MAX127_HALF_RANGE , /* RNG=0, BIP=1 */
MAX127_FULL_RANGE , /* RNG=1, BIP=0 */
MAX127_FULL_RANGE , /* RNG=1, BIP=1 */
} ;
* val = max_input_map [ rng_bip ] ;
return 0 ;
}
static int max127_write_min ( struct max127_data * data , int channel , long val )
{
u8 ctrl ;
mutex_lock ( & data - > lock ) ;
ctrl = data - > ctrl_byte [ channel ] ;
if ( val < = - MAX127_FULL_RANGE ) {
ctrl | = ( MAX127_CTRL_RNG | MAX127_CTRL_BIP ) ;
} else if ( val < 0 ) {
ctrl | = MAX127_CTRL_BIP ;
ctrl & = ~ MAX127_CTRL_RNG ;
} else {
ctrl & = ~ MAX127_CTRL_BIP ;
}
data - > ctrl_byte [ channel ] = ctrl ;
mutex_unlock ( & data - > lock ) ;
return 0 ;
}
static int max127_write_max ( struct max127_data * data , int channel , long val )
{
mutex_lock ( & data - > lock ) ;
if ( val > = MAX127_FULL_RANGE )
data - > ctrl_byte [ channel ] | = MAX127_CTRL_RNG ;
else
data - > ctrl_byte [ channel ] & = ~ MAX127_CTRL_RNG ;
mutex_unlock ( & data - > lock ) ;
return 0 ;
}
static umode_t max127_is_visible ( const void * _data ,
enum hwmon_sensor_types type ,
u32 attr , int channel )
{
if ( type = = hwmon_in ) {
switch ( attr ) {
case hwmon_in_input :
return 0444 ;
case hwmon_in_min :
case hwmon_in_max :
return 0644 ;
default :
break ;
}
}
return 0 ;
}
static int max127_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * val )
{
int status ;
struct max127_data * data = dev_get_drvdata ( dev ) ;
if ( type ! = hwmon_in )
return - EOPNOTSUPP ;
switch ( attr ) {
case hwmon_in_input :
status = max127_read_input ( data , channel , val ) ;
break ;
case hwmon_in_min :
status = max127_read_min ( data , channel , val ) ;
break ;
case hwmon_in_max :
status = max127_read_max ( data , channel , val ) ;
break ;
default :
status = - EOPNOTSUPP ;
break ;
}
return status ;
}
static int max127_write ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long val )
{
int status ;
struct max127_data * data = dev_get_drvdata ( dev ) ;
if ( type ! = hwmon_in )
return - EOPNOTSUPP ;
switch ( attr ) {
case hwmon_in_min :
status = max127_write_min ( data , channel , val ) ;
break ;
case hwmon_in_max :
status = max127_write_max ( data , channel , val ) ;
break ;
default :
status = - EOPNOTSUPP ;
break ;
}
return status ;
}
static const struct hwmon_ops max127_hwmon_ops = {
. is_visible = max127_is_visible ,
. read = max127_read ,
. write = max127_write ,
} ;
static const struct hwmon_channel_info * max127_info [ ] = {
HWMON_CHANNEL_INFO ( in ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX ) ,
NULL ,
} ;
static const struct hwmon_chip_info max127_chip_info = {
. ops = & max127_hwmon_ops ,
. info = max127_info ,
} ;
hwmon: use simple i2c probe
All these drivers have an i2c probe function which doesn't use the
"struct i2c_device_id *id" parameter, so they can trivially be
converted to the "probe_new" style of probe with a single argument.
This is part of an ongoing transition to single-argument i2c probe
functions. Old-style probe functions involve a call to i2c_match_id:
in drivers/i2c/i2c-core-base.c,
/*
* When there are no more users of probe(),
* rename probe_new to probe.
*/
if (driver->probe_new)
status = driver->probe_new(client);
else if (driver->probe)
status = driver->probe(client,
i2c_match_id(driver->id_table, client));
else
status = -EINVAL;
Drivers which don't need the second parameter can be declared using
probe_new instead, avoiding the call to i2c_match_id. Drivers which do
can still be converted to probe_new-style, calling i2c_match_id
themselves (as is done currently for of_match_id).
This change was done using the following Coccinelle script, and fixed
up for whitespace changes:
@ rule1 @
identifier fn;
identifier client, id;
@@
- static int fn(struct i2c_client *client, const struct i2c_device_id *id)
+ static int fn(struct i2c_client *client)
{
...when != id
}
@ rule2 depends on rule1 @
identifier rule1.fn;
identifier driver;
@@
struct i2c_driver driver = {
- .probe
+ .probe_new
=
(
fn
|
- &fn
+ fn
)
,
};
Signed-off-by: Stephen Kitt <steve@sk2.org>
Link: https://lore.kernel.org/r/20221011143309.3141267-1-steve@sk2.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2022-10-11 17:33:08 +03:00
static int max127_probe ( struct i2c_client * client )
2020-11-23 21:56:57 +03:00
{
int i ;
struct device * hwmon_dev ;
struct max127_data * data ;
struct device * dev = & client - > dev ;
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
for ( i = 0 ; i < ARRAY_SIZE ( data - > ctrl_byte ) ; i + + )
data - > ctrl_byte [ i ] = ( MAX127_CTRL_START |
MAX127_SET_CHANNEL ( i ) ) ;
hwmon_dev = devm_hwmon_device_register_with_info ( dev , client - > name ,
data ,
& max127_chip_info ,
NULL ) ;
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
}
static const struct i2c_device_id max127_id [ ] = {
{ " max127 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , max127_id ) ;
static struct i2c_driver max127_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " max127 " ,
} ,
hwmon: use simple i2c probe
All these drivers have an i2c probe function which doesn't use the
"struct i2c_device_id *id" parameter, so they can trivially be
converted to the "probe_new" style of probe with a single argument.
This is part of an ongoing transition to single-argument i2c probe
functions. Old-style probe functions involve a call to i2c_match_id:
in drivers/i2c/i2c-core-base.c,
/*
* When there are no more users of probe(),
* rename probe_new to probe.
*/
if (driver->probe_new)
status = driver->probe_new(client);
else if (driver->probe)
status = driver->probe(client,
i2c_match_id(driver->id_table, client));
else
status = -EINVAL;
Drivers which don't need the second parameter can be declared using
probe_new instead, avoiding the call to i2c_match_id. Drivers which do
can still be converted to probe_new-style, calling i2c_match_id
themselves (as is done currently for of_match_id).
This change was done using the following Coccinelle script, and fixed
up for whitespace changes:
@ rule1 @
identifier fn;
identifier client, id;
@@
- static int fn(struct i2c_client *client, const struct i2c_device_id *id)
+ static int fn(struct i2c_client *client)
{
...when != id
}
@ rule2 depends on rule1 @
identifier rule1.fn;
identifier driver;
@@
struct i2c_driver driver = {
- .probe
+ .probe_new
=
(
fn
|
- &fn
+ fn
)
,
};
Signed-off-by: Stephen Kitt <steve@sk2.org>
Link: https://lore.kernel.org/r/20221011143309.3141267-1-steve@sk2.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2022-10-11 17:33:08 +03:00
. probe_new = max127_probe ,
2020-11-23 21:56:57 +03:00
. id_table = max127_id ,
} ;
module_i2c_driver ( max127_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Mike Choi <mikechoi@fb.com> " ) ;
MODULE_AUTHOR ( " Tao Ren <rentao.bupt@gmail.com> " ) ;
MODULE_DESCRIPTION ( " MAX127 Hardware Monitoring driver " ) ;