2014-01-25 10:25:33 +04:00
/*
* Driver for TI ADC128D818 System Monitor with Temperature Sensor
*
* Copyright ( c ) 2014 Guenter Roeck
*
* Derived from lm80 . c
* Copyright ( C ) 1998 , 1999 Frodo Looijaard < frodol @ dds . nl >
* and Philip Edelbrock < phil @ netroedge . com >
*
* 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 .
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/i2c.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/err.h>
# include <linux/regulator/consumer.h>
# include <linux/mutex.h>
2015-01-23 01:44:14 +03:00
# include <linux/bitops.h>
2017-01-06 13:38:15 +03:00
# include <linux/of.h>
2014-01-25 10:25:33 +04:00
/* Addresses to scan
* The chip also supports addresses 0x35 . .0 x37 . Don ' t scan those addresses
* since they are also used by some EEPROMs , which may result in false
* positives .
*/
static const unsigned short normal_i2c [ ] = {
0x1d , 0x1e , 0x1f , 0x2d , 0x2e , 0x2f , I2C_CLIENT_END } ;
/* registers */
# define ADC128_REG_IN_MAX(nr) (0x2a + (nr) * 2)
# define ADC128_REG_IN_MIN(nr) (0x2b + (nr) * 2)
# define ADC128_REG_IN(nr) (0x20 + (nr))
# define ADC128_REG_TEMP 0x27
# define ADC128_REG_TEMP_MAX 0x38
# define ADC128_REG_TEMP_HYST 0x39
# define ADC128_REG_CONFIG 0x00
# define ADC128_REG_ALARM 0x01
# define ADC128_REG_MASK 0x03
# define ADC128_REG_CONV_RATE 0x07
# define ADC128_REG_ONESHOT 0x09
# define ADC128_REG_SHUTDOWN 0x0a
# define ADC128_REG_CONFIG_ADV 0x0b
# define ADC128_REG_BUSY_STATUS 0x0c
# define ADC128_REG_MAN_ID 0x3e
# define ADC128_REG_DEV_ID 0x3f
2017-01-06 13:38:16 +03:00
/* No. of voltage entries in adc128_attrs */
# define ADC128_ATTR_NUM_VOLT (8 * 4)
/* Voltage inputs visible per operation mode */
static const u8 num_inputs [ ] = { 7 , 8 , 4 , 6 } ;
2014-01-25 10:25:33 +04:00
struct adc128_data {
struct i2c_client * client ;
struct regulator * regulator ;
int vref ; /* Reference voltage in mV */
struct mutex update_lock ;
2017-01-06 13:38:15 +03:00
u8 mode ; /* Operation mode */
2014-01-25 10:25:33 +04:00
bool valid ; /* true if following fields are valid */
unsigned long last_updated ; /* In jiffies */
2017-01-06 13:38:16 +03:00
u16 in [ 3 ] [ 8 ] ; /* Register value, normalized to 12 bit
2014-01-25 10:25:33 +04:00
* 0 : input voltage
* 1 : min limit
* 2 : max limit
*/
s16 temp [ 3 ] ; /* Register value, normalized to 9 bit
* 0 : sensor 1 : limit 2 : hyst
*/
u8 alarms ; /* alarm register value */
} ;
static struct adc128_data * adc128_update_device ( struct device * dev )
{
struct adc128_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
struct adc128_data * ret = data ;
int i , rv ;
mutex_lock ( & data - > update_lock ) ;
if ( time_after ( jiffies , data - > last_updated + HZ ) | | ! data - > valid ) {
2017-01-06 13:38:16 +03:00
for ( i = 0 ; i < num_inputs [ data - > mode ] ; i + + ) {
2014-01-25 10:25:33 +04:00
rv = i2c_smbus_read_word_swapped ( client ,
ADC128_REG_IN ( i ) ) ;
if ( rv < 0 )
goto abort ;
data - > in [ 0 ] [ i ] = rv > > 4 ;
rv = i2c_smbus_read_byte_data ( client ,
ADC128_REG_IN_MIN ( i ) ) ;
if ( rv < 0 )
goto abort ;
data - > in [ 1 ] [ i ] = rv < < 4 ;
rv = i2c_smbus_read_byte_data ( client ,
ADC128_REG_IN_MAX ( i ) ) ;
if ( rv < 0 )
goto abort ;
data - > in [ 2 ] [ i ] = rv < < 4 ;
}
2017-01-06 13:38:16 +03:00
if ( data - > mode ! = 1 ) {
rv = i2c_smbus_read_word_swapped ( client ,
ADC128_REG_TEMP ) ;
if ( rv < 0 )
goto abort ;
data - > temp [ 0 ] = rv > > 7 ;
2014-01-25 10:25:33 +04:00
2017-01-06 13:38:16 +03:00
rv = i2c_smbus_read_byte_data ( client ,
ADC128_REG_TEMP_MAX ) ;
if ( rv < 0 )
goto abort ;
data - > temp [ 1 ] = rv < < 1 ;
2014-01-25 10:25:33 +04:00
2017-01-06 13:38:16 +03:00
rv = i2c_smbus_read_byte_data ( client ,
ADC128_REG_TEMP_HYST ) ;
if ( rv < 0 )
goto abort ;
data - > temp [ 2 ] = rv < < 1 ;
}
2014-01-25 10:25:33 +04:00
rv = i2c_smbus_read_byte_data ( client , ADC128_REG_ALARM ) ;
if ( rv < 0 )
goto abort ;
data - > alarms | = rv ;
data - > last_updated = jiffies ;
data - > valid = true ;
}
goto done ;
abort :
ret = ERR_PTR ( rv ) ;
data - > valid = false ;
done :
mutex_unlock ( & data - > update_lock ) ;
return ret ;
}
2018-12-11 01:02:00 +03:00
static ssize_t adc128_in_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2014-01-25 10:25:33 +04:00
{
struct adc128_data * data = adc128_update_device ( dev ) ;
int index = to_sensor_dev_attr_2 ( attr ) - > index ;
int nr = to_sensor_dev_attr_2 ( attr ) - > nr ;
int val ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
val = DIV_ROUND_CLOSEST ( data - > in [ index ] [ nr ] * data - > vref , 4095 ) ;
return sprintf ( buf , " %d \n " , val ) ;
}
2018-12-11 01:02:00 +03:00
static ssize_t adc128_in_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2014-01-25 10:25:33 +04:00
{
struct adc128_data * data = dev_get_drvdata ( dev ) ;
int index = to_sensor_dev_attr_2 ( attr ) - > index ;
int nr = to_sensor_dev_attr_2 ( attr ) - > nr ;
u8 reg , regval ;
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err < 0 )
return err ;
mutex_lock ( & data - > update_lock ) ;
/* 10 mV LSB on limit registers */
regval = clamp_val ( DIV_ROUND_CLOSEST ( val , 10 ) , 0 , 255 ) ;
data - > in [ index ] [ nr ] = regval < < 4 ;
reg = index = = 1 ? ADC128_REG_IN_MIN ( nr ) : ADC128_REG_IN_MAX ( nr ) ;
i2c_smbus_write_byte_data ( data - > client , reg , regval ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2018-12-11 01:02:00 +03:00
static ssize_t adc128_temp_show ( struct device * dev ,
2014-01-25 10:25:33 +04:00
struct device_attribute * attr , char * buf )
{
struct adc128_data * data = adc128_update_device ( dev ) ;
int index = to_sensor_dev_attr ( attr ) - > index ;
int temp ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2015-01-23 01:44:14 +03:00
temp = sign_extend32 ( data - > temp [ index ] , 8 ) ;
2014-01-25 10:25:33 +04:00
return sprintf ( buf , " %d \n " , temp * 500 ) ; /* 0.5 degrees C resolution */
}
2018-12-11 01:02:00 +03:00
static ssize_t adc128_temp_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
2014-01-25 10:25:33 +04:00
{
struct adc128_data * data = dev_get_drvdata ( dev ) ;
int index = to_sensor_dev_attr ( attr ) - > index ;
long val ;
int err ;
s8 regval ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err < 0 )
return err ;
mutex_lock ( & data - > update_lock ) ;
regval = clamp_val ( DIV_ROUND_CLOSEST ( val , 1000 ) , - 128 , 127 ) ;
data - > temp [ index ] = regval < < 1 ;
i2c_smbus_write_byte_data ( data - > client ,
index = = 1 ? ADC128_REG_TEMP_MAX
: ADC128_REG_TEMP_HYST ,
regval ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2018-12-11 01:02:00 +03:00
static ssize_t adc128_alarm_show ( struct device * dev ,
2014-01-25 10:25:33 +04:00
struct device_attribute * attr , char * buf )
{
struct adc128_data * data = adc128_update_device ( dev ) ;
int mask = 1 < < to_sensor_dev_attr ( attr ) - > index ;
u8 alarms ;
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
/*
* Clear an alarm after reporting it to user space . If it is still
* active , the next update sequence will set the alarm bit again .
*/
alarms = data - > alarms ;
data - > alarms & = ~ mask ;
return sprintf ( buf , " %u \n " , ! ! ( alarms & mask ) ) ;
}
2017-01-06 13:38:16 +03:00
static umode_t adc128_is_visible ( struct kobject * kobj ,
struct attribute * attr , int index )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct adc128_data * data = dev_get_drvdata ( dev ) ;
if ( index < ADC128_ATTR_NUM_VOLT ) {
/* Voltage, visible according to num_inputs[] */
if ( index > = num_inputs [ data - > mode ] * 4 )
return 0 ;
} else {
/* Temperature, visible if not in mode 1 */
if ( data - > mode = = 1 )
return 0 ;
}
return attr - > mode ;
}
2018-12-11 01:02:00 +03:00
static SENSOR_DEVICE_ATTR_2_RO ( in0_input , adc128_in , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in0_min , adc128_in , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in0_max , adc128_in , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in1_input , adc128_in , 1 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_min , adc128_in , 1 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_max , adc128_in , 1 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in2_input , adc128_in , 2 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_min , adc128_in , 2 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_max , adc128_in , 2 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in3_input , adc128_in , 3 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_min , adc128_in , 3 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_max , adc128_in , 3 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in4_input , adc128_in , 4 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_min , adc128_in , 4 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_max , adc128_in , 4 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in5_input , adc128_in , 5 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_min , adc128_in , 5 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_max , adc128_in , 5 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in6_input , adc128_in , 6 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_min , adc128_in , 6 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_max , adc128_in , 6 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in7_input , adc128_in , 7 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_min , adc128_in , 7 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_max , adc128_in , 7 , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_input , adc128_temp , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_max , adc128_temp , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_max_hyst , adc128_temp , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in0_alarm , adc128_alarm , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_alarm , adc128_alarm , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_alarm , adc128_alarm , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_alarm , adc128_alarm , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in4_alarm , adc128_alarm , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( in5_alarm , adc128_alarm , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( in6_alarm , adc128_alarm , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( in7_alarm , adc128_alarm , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_max_alarm , adc128_alarm , 7 ) ;
2014-01-25 10:25:33 +04:00
static struct attribute * adc128_attrs [ ] = {
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in0_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in0_max . dev_attr . attr ,
& sensor_dev_attr_in0_min . dev_attr . attr ,
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in1_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in1_max . dev_attr . attr ,
& sensor_dev_attr_in1_min . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in2_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in2_max . dev_attr . attr ,
& sensor_dev_attr_in2_min . dev_attr . attr ,
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in3_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in3_max . dev_attr . attr ,
& sensor_dev_attr_in3_min . dev_attr . attr ,
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in4_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in4_max . dev_attr . attr ,
& sensor_dev_attr_in4_min . dev_attr . attr ,
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in5_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in5_max . dev_attr . attr ,
& sensor_dev_attr_in5_min . dev_attr . attr ,
& sensor_dev_attr_in6_alarm . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_in6_input . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_in6_max . dev_attr . attr ,
& sensor_dev_attr_in6_min . dev_attr . attr ,
& sensor_dev_attr_in7_alarm . dev_attr . attr ,
& sensor_dev_attr_in7_input . dev_attr . attr ,
& sensor_dev_attr_in7_max . dev_attr . attr ,
& sensor_dev_attr_in7_min . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp1_max_alarm . dev_attr . attr ,
2017-01-06 13:38:16 +03:00
& sensor_dev_attr_temp1_max_hyst . dev_attr . attr ,
2014-01-25 10:25:33 +04:00
NULL
} ;
2017-01-06 13:38:16 +03:00
2017-07-05 08:22:13 +03:00
static const struct attribute_group adc128_group = {
2017-01-06 13:38:16 +03:00
. attrs = adc128_attrs ,
. is_visible = adc128_is_visible ,
} ;
__ATTRIBUTE_GROUPS ( adc128 ) ;
2014-01-25 10:25:33 +04:00
static int adc128_detect ( struct i2c_client * client , struct i2c_board_info * info )
{
int man_id , dev_id ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA ) )
return - ENODEV ;
man_id = i2c_smbus_read_byte_data ( client , ADC128_REG_MAN_ID ) ;
dev_id = i2c_smbus_read_byte_data ( client , ADC128_REG_DEV_ID ) ;
if ( man_id ! = 0x01 | | dev_id ! = 0x09 )
return - ENODEV ;
/* Check unused bits for confirmation */
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_CONFIG ) & 0xf4 )
return - ENODEV ;
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_CONV_RATE ) & 0xfe )
return - ENODEV ;
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_ONESHOT ) & 0xfe )
return - ENODEV ;
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_SHUTDOWN ) & 0xfe )
return - ENODEV ;
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_CONFIG_ADV ) & 0xf8 )
return - ENODEV ;
if ( i2c_smbus_read_byte_data ( client , ADC128_REG_BUSY_STATUS ) & 0xfc )
return - ENODEV ;
strlcpy ( info - > type , " adc128d818 " , I2C_NAME_SIZE ) ;
return 0 ;
}
static int adc128_init_client ( struct adc128_data * data )
{
struct i2c_client * client = data - > client ;
int err ;
/*
* Reset chip to defaults .
* This makes most other initializations unnecessary .
*/
err = i2c_smbus_write_byte_data ( client , ADC128_REG_CONFIG , 0x80 ) ;
if ( err )
return err ;
2017-01-06 13:38:15 +03:00
/* Set operation mode, if non-default */
if ( data - > mode ! = 0 ) {
err = i2c_smbus_write_byte_data ( client ,
ADC128_REG_CONFIG_ADV ,
data - > mode < < 1 ) ;
if ( err )
return err ;
}
2014-01-25 10:25:33 +04:00
/* Start monitoring */
err = i2c_smbus_write_byte_data ( client , ADC128_REG_CONFIG , 0x01 ) ;
if ( err )
return err ;
/* If external vref is selected, configure the chip to use it */
if ( data - > regulator ) {
err = i2c_smbus_write_byte_data ( client ,
ADC128_REG_CONFIG_ADV , 0x01 ) ;
if ( err )
return err ;
}
return 0 ;
}
static int adc128_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct device * dev = & client - > dev ;
struct regulator * regulator ;
struct device * hwmon_dev ;
struct adc128_data * data ;
int err , vref ;
data = devm_kzalloc ( dev , sizeof ( struct adc128_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
/* vref is optional. If specified, is used as chip reference voltage */
regulator = devm_regulator_get_optional ( dev , " vref " ) ;
if ( ! IS_ERR ( regulator ) ) {
data - > regulator = regulator ;
err = regulator_enable ( regulator ) ;
if ( err < 0 )
return err ;
vref = regulator_get_voltage ( regulator ) ;
if ( vref < 0 ) {
err = vref ;
goto error ;
}
data - > vref = DIV_ROUND_CLOSEST ( vref , 1000 ) ;
} else {
data - > vref = 2560 ; /* 2.56V, in mV */
}
2017-01-06 13:38:17 +03:00
/* Operation mode is optional. If unspecified, keep current mode */
2017-01-06 13:38:15 +03:00
if ( of_property_read_u8 ( dev - > of_node , " ti,mode " , & data - > mode ) = = 0 ) {
2017-01-06 13:38:16 +03:00
if ( data - > mode > 3 ) {
dev_err ( dev , " invalid operation mode %d \n " ,
2017-01-06 13:38:15 +03:00
data - > mode ) ;
err = - EINVAL ;
goto error ;
}
} else {
2017-01-06 13:38:17 +03:00
err = i2c_smbus_read_byte_data ( client , ADC128_REG_CONFIG_ADV ) ;
if ( err < 0 )
goto error ;
data - > mode = ( err > > 1 ) & ADC128_REG_MASK ;
2017-01-06 13:38:15 +03:00
}
2014-01-25 10:25:33 +04:00
data - > client = client ;
i2c_set_clientdata ( client , data ) ;
mutex_init ( & data - > update_lock ) ;
/* Initialize the chip */
err = adc128_init_client ( data ) ;
if ( err < 0 )
goto error ;
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
data , adc128_groups ) ;
if ( IS_ERR ( hwmon_dev ) ) {
err = PTR_ERR ( hwmon_dev ) ;
goto error ;
}
return 0 ;
error :
if ( data - > regulator )
regulator_disable ( data - > regulator ) ;
return err ;
}
static int adc128_remove ( struct i2c_client * client )
{
struct adc128_data * data = i2c_get_clientdata ( client ) ;
if ( data - > regulator )
regulator_disable ( data - > regulator ) ;
return 0 ;
}
static const struct i2c_device_id adc128_id [ ] = {
{ " adc128d818 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adc128_id ) ;
2019-04-04 16:23:59 +03:00
static const struct of_device_id __maybe_unused adc128_of_match [ ] = {
2017-02-24 16:12:55 +03:00
{ . compatible = " ti,adc128d818 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , adc128_of_match ) ;
2014-01-25 10:25:33 +04:00
static struct i2c_driver adc128_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " adc128d818 " ,
2017-02-24 16:12:55 +03:00
. of_match_table = of_match_ptr ( adc128_of_match ) ,
2014-01-25 10:25:33 +04:00
} ,
. probe = adc128_probe ,
. remove = adc128_remove ,
. id_table = adc128_id ,
. detect = adc128_detect ,
. address_list = normal_i2c ,
} ;
module_i2c_driver ( adc128_driver ) ;
MODULE_AUTHOR ( " Guenter Roeck " ) ;
MODULE_DESCRIPTION ( " Driver for ADC128D818 " ) ;
MODULE_LICENSE ( " GPL " ) ;