2011-09-02 09:58:37 -07:00
/*
2015-06-08 09:56:20 -07:00
* Hardware monitoring driver for LTC2978 and compatible chips .
2011-09-02 09:58:37 -07:00
*
* Copyright ( c ) 2011 Ericsson AB .
2015-06-08 09:56:20 -07:00
* Copyright ( c ) 2013 , 2014 , 2015 Guenter Roeck
2015-08-17 17:45:32 -07:00
* Copyright ( c ) 2015 Linear Technology
2011-09-02 09:58:37 -07:00
*
* 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 .
*/
2015-08-17 17:45:32 -07:00
# include <linux/delay.h>
# include <linux/jiffies.h>
2011-09-02 09:58:37 -07:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/i2c.h>
2014-10-15 13:55:10 -05:00
# include <linux/regulator/driver.h>
2011-09-02 09:58:37 -07:00
# include "pmbus.h"
2015-08-17 06:38:01 -07:00
enum chips { ltc2974 , ltc2975 , ltc2977 , ltc2978 , ltc2980 , ltc3880 , ltc3882 ,
2015-08-17 20:08:09 -07:00
ltc3883 , ltc3886 , ltc3887 , ltm2987 , ltm4675 , ltm4676 } ;
2011-09-02 09:58:37 -07:00
2013-01-27 09:24:28 -08:00
/* Common for all chips */
2011-09-02 09:58:37 -07:00
# define LTC2978_MFR_VOUT_PEAK 0xdd
# define LTC2978_MFR_VIN_PEAK 0xde
# define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
2015-08-17 06:27:56 -07:00
# define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */
2015-08-17 17:45:32 -07:00
# define LTC2978_MFR_COMMON 0xef
2011-09-02 09:58:37 -07:00
2015-08-17 06:38:01 -07:00
/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */
2011-09-02 09:58:37 -07:00
# define LTC2978_MFR_VOUT_MIN 0xfb
# define LTC2978_MFR_VIN_MIN 0xfc
# define LTC2978_MFR_TEMPERATURE_MIN 0xfd
2015-06-08 09:56:20 -07:00
/* LTC2974, LTC2975 */
2013-01-27 09:24:28 -08:00
# define LTC2974_MFR_IOUT_PEAK 0xd7
# define LTC2974_MFR_IOUT_MIN 0xd8
2015-08-17 20:08:09 -07:00
/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */
2011-09-11 20:31:09 -07:00
# define LTC3880_MFR_IOUT_PEAK 0xd7
# define LTC3880_MFR_CLEAR_PEAKS 0xe3
# define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
2015-08-17 07:21:43 -07:00
/* LTC3883 and LTC3886 only */
2013-01-27 09:24:28 -08:00
# define LTC3883_MFR_IIN_PEAK 0xe1
2015-06-08 09:56:20 -07:00
/* LTC2975 only */
# define LTC2975_MFR_IIN_PEAK 0xc4
# define LTC2975_MFR_IIN_MIN 0xc5
# define LTC2975_MFR_PIN_PEAK 0xc6
# define LTC2975_MFR_PIN_MIN 0xc7
2015-08-17 06:21:01 -07:00
# define LTC2978_ID_MASK 0xfff0
# define LTC2974_ID 0x0210
# define LTC2975_ID 0x0220
2013-09-23 10:56:48 -07:00
# define LTC2977_ID 0x0130
2015-08-17 06:27:56 -07:00
# define LTC2978_ID_REV1 0x0110 /* Early revision */
# define LTC2978_ID_REV2 0x0120
2015-08-17 06:38:01 -07:00
# define LTC2980_ID_A 0x8030 /* A/B for two die IDs */
# define LTC2980_ID_B 0x8040
2015-08-17 06:21:01 -07:00
# define LTC3880_ID 0x4020
2015-08-17 06:27:56 -07:00
# define LTC3882_ID 0x4200
# define LTC3882_ID_D1 0x4240 /* Dash 1 */
2013-01-27 09:24:28 -08:00
# define LTC3883_ID 0x4300
2015-08-17 07:21:43 -07:00
# define LTC3886_ID 0x4600
2015-08-07 09:06:37 -07:00
# define LTC3887_ID 0x4700
2015-08-17 06:38:01 -07:00
# define LTM2987_ID_A 0x8010 /* A/B for two die IDs */
# define LTM2987_ID_B 0x8020
2015-08-17 20:08:09 -07:00
# define LTM4675_ID 0x47a0
2015-08-17 06:21:01 -07:00
# define LTM4676_ID_REV1 0x4400
# define LTM4676_ID_REV2 0x4480
2015-08-07 09:06:37 -07:00
# define LTM4676A_ID 0x47e0
2011-09-02 09:58:37 -07:00
2013-01-27 09:24:28 -08:00
# define LTC2974_NUM_PAGES 4
2013-02-28 08:14:45 -08:00
# define LTC2978_NUM_PAGES 8
# define LTC3880_NUM_PAGES 2
2013-01-27 09:24:28 -08:00
# define LTC3883_NUM_PAGES 1
2013-02-28 08:14:45 -08:00
2015-08-17 17:45:32 -07:00
# define LTC_POLL_TIMEOUT 100 /* in milli-seconds */
# define LTC_NOT_BUSY BIT(5)
# define LTC_NOT_PENDING BIT(4)
2011-09-02 09:58:37 -07:00
/*
* LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed , which
* happens pretty much each time chip data is updated . Raw peak data therefore
* does not provide much value . To be able to provide useful peak data , keep an
* internal cache of measured peak data , which is only cleared if an explicit
* " clear peak " command is executed for the sensor in question .
*/
2013-02-28 08:14:45 -08:00
2011-09-02 09:58:37 -07:00
struct ltc2978_data {
enum chips id ;
2013-02-28 08:14:45 -08:00
u16 vin_min , vin_max ;
2013-01-27 09:24:28 -08:00
u16 temp_min [ LTC2974_NUM_PAGES ] , temp_max [ LTC2974_NUM_PAGES ] ;
2013-02-28 08:14:45 -08:00
u16 vout_min [ LTC2978_NUM_PAGES ] , vout_max [ LTC2978_NUM_PAGES ] ;
2013-01-27 09:24:28 -08:00
u16 iout_min [ LTC2974_NUM_PAGES ] , iout_max [ LTC2974_NUM_PAGES ] ;
2015-06-08 09:56:20 -07:00
u16 iin_min , iin_max ;
u16 pin_min , pin_max ;
2013-02-28 08:14:45 -08:00
u16 temp2_max ;
2011-09-02 09:58:37 -07:00
struct pmbus_driver_info info ;
2015-08-15 17:02:09 -07:00
u32 features ;
2011-09-02 09:58:37 -07:00
} ;
# define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info)
2015-08-15 17:02:09 -07:00
# define FEAT_CLEAR_PEAKS BIT(0)
2015-08-17 17:45:32 -07:00
# define FEAT_NEEDS_POLLING BIT(1)
2015-08-15 17:02:09 -07:00
# define has_clear_peaks(d) ((d)->features & FEAT_CLEAR_PEAKS)
2015-08-17 17:45:32 -07:00
# define needs_polling(d) ((d)->features & FEAT_NEEDS_POLLING)
static int ltc_wait_ready ( struct i2c_client * client )
{
unsigned long timeout = jiffies + msecs_to_jiffies ( LTC_POLL_TIMEOUT ) ;
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int status ;
u8 mask ;
if ( ! needs_polling ( data ) )
return 0 ;
/*
* LTC3883 does not support LTC_NOT_PENDING , even though
* the datasheet claims that it does .
*/
mask = LTC_NOT_BUSY ;
if ( data - > id ! = ltc3883 )
mask | = LTC_NOT_PENDING ;
do {
status = pmbus_read_byte_data ( client , 0 , LTC2978_MFR_COMMON ) ;
if ( status = = - EBADMSG | | status = = - ENXIO ) {
/* PEC error or NACK: chip may be busy, try again */
usleep_range ( 50 , 100 ) ;
continue ;
}
if ( status < 0 )
return status ;
if ( ( status & mask ) = = mask )
return 0 ;
usleep_range ( 50 , 100 ) ;
} while ( time_before ( jiffies , timeout ) ) ;
return - ETIMEDOUT ;
}
static int ltc_read_word_data ( struct i2c_client * client , int page , int reg )
{
int ret ;
ret = ltc_wait_ready ( client ) ;
if ( ret < 0 )
return ret ;
return pmbus_read_word_data ( client , page , reg ) ;
}
static int ltc_read_byte_data ( struct i2c_client * client , int page , int reg )
{
int ret ;
ret = ltc_wait_ready ( client ) ;
if ( ret < 0 )
return ret ;
return pmbus_read_byte_data ( client , page , reg ) ;
}
static int ltc_write_byte ( struct i2c_client * client , int page , u8 byte )
{
int ret ;
ret = ltc_wait_ready ( client ) ;
if ( ret < 0 )
return ret ;
return pmbus_write_byte ( client , page , byte ) ;
}
2015-08-15 17:02:09 -07:00
2011-09-02 09:58:37 -07:00
static inline int lin11_to_val ( int data )
{
s16 e = ( ( s16 ) data ) > > 11 ;
s32 m = ( ( ( s16 ) ( data < < 5 ) ) > > 5 ) ;
/*
* mantissa is 10 bit + sign , exponent adds up to 15 bit .
* Add 6 bit to exponent for maximum accuracy ( 10 + 15 + 6 = 31 ) .
*/
e + = 6 ;
return ( e < 0 ? m > > - e : m < < e ) ;
}
2015-08-15 17:17:53 -07:00
static int ltc_get_max ( struct ltc2978_data * data , struct i2c_client * client ,
int page , int reg , u16 * pmax )
{
int ret ;
2015-08-17 17:45:32 -07:00
ret = ltc_read_word_data ( client , page , reg ) ;
2015-08-15 17:17:53 -07:00
if ( ret > = 0 ) {
if ( lin11_to_val ( ret ) > lin11_to_val ( * pmax ) )
* pmax = ret ;
ret = * pmax ;
}
return ret ;
}
static int ltc_get_min ( struct ltc2978_data * data , struct i2c_client * client ,
int page , int reg , u16 * pmin )
{
int ret ;
2015-08-17 17:45:32 -07:00
ret = ltc_read_word_data ( client , page , reg ) ;
2015-08-15 17:17:53 -07:00
if ( ret > = 0 ) {
if ( lin11_to_val ( ret ) < lin11_to_val ( * pmin ) )
* pmin = ret ;
ret = * pmin ;
}
return ret ;
}
2011-09-11 20:31:09 -07:00
static int ltc2978_read_word_data_common ( struct i2c_client * client , int page ,
int reg )
2011-09-02 09:58:37 -07:00
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
case PMBUS_VIRT_READ_VIN_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC2978_MFR_VIN_PEAK ,
& data - > vin_max ) ;
2011-09-02 09:58:37 -07:00
break ;
case PMBUS_VIRT_READ_VOUT_MAX :
2015-08-17 17:45:32 -07:00
ret = ltc_read_word_data ( client , page , LTC2978_MFR_VOUT_PEAK ) ;
2011-09-02 09:58:37 -07:00
if ( ret > = 0 ) {
/*
* VOUT is 16 bit unsigned with fixed exponent ,
* so we can compare it directly
*/
if ( ret > data - > vout_max [ page ] )
data - > vout_max [ page ] = ret ;
ret = data - > vout_max [ page ] ;
}
break ;
case PMBUS_VIRT_READ_TEMP_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page ,
LTC2978_MFR_TEMPERATURE_PEAK ,
& data - > temp_max [ page ] ) ;
2011-09-02 09:58:37 -07:00
break ;
2011-09-11 20:31:09 -07:00
case PMBUS_VIRT_RESET_VOUT_HISTORY :
case PMBUS_VIRT_RESET_VIN_HISTORY :
case PMBUS_VIRT_RESET_TEMP_HISTORY :
ret = 0 ;
break ;
default :
2015-08-17 17:45:32 -07:00
ret = ltc_wait_ready ( client ) ;
if ( ret < 0 )
return ret ;
2011-09-11 20:31:09 -07:00
ret = - ENODATA ;
break ;
}
return ret ;
}
static int ltc2978_read_word_data ( struct i2c_client * client , int page , int reg )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
2011-09-02 09:58:37 -07:00
case PMBUS_VIRT_READ_VIN_MIN :
2015-08-15 17:17:53 -07:00
ret = ltc_get_min ( data , client , page , LTC2978_MFR_VIN_MIN ,
& data - > vin_min ) ;
2011-09-02 09:58:37 -07:00
break ;
case PMBUS_VIRT_READ_VOUT_MIN :
2015-08-17 17:45:32 -07:00
ret = ltc_read_word_data ( client , page , LTC2978_MFR_VOUT_MIN ) ;
2011-09-02 09:58:37 -07:00
if ( ret > = 0 ) {
/*
* VOUT_MIN is known to not be supported on some lots
* of LTC2978 revision 1 , and will return the maximum
* possible voltage if read . If VOUT_MAX is valid and
* lower than the reading of VOUT_MIN , use it instead .
*/
if ( data - > vout_max [ page ] & & ret > data - > vout_max [ page ] )
ret = data - > vout_max [ page ] ;
if ( ret < data - > vout_min [ page ] )
data - > vout_min [ page ] = ret ;
ret = data - > vout_min [ page ] ;
}
break ;
case PMBUS_VIRT_READ_TEMP_MIN :
2015-08-15 17:17:53 -07:00
ret = ltc_get_min ( data , client , page ,
LTC2978_MFR_TEMPERATURE_MIN ,
& data - > temp_min [ page ] ) ;
2011-09-02 09:58:37 -07:00
break ;
2011-09-11 20:31:09 -07:00
case PMBUS_VIRT_READ_IOUT_MAX :
case PMBUS_VIRT_RESET_IOUT_HISTORY :
case PMBUS_VIRT_READ_TEMP2_MAX :
case PMBUS_VIRT_RESET_TEMP2_HISTORY :
ret = - ENXIO ;
break ;
default :
ret = ltc2978_read_word_data_common ( client , page , reg ) ;
break ;
}
return ret ;
}
2013-01-27 09:24:28 -08:00
static int ltc2974_read_word_data ( struct i2c_client * client , int page , int reg )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
case PMBUS_VIRT_READ_IOUT_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC2974_MFR_IOUT_PEAK ,
& data - > iout_max [ page ] ) ;
2013-01-27 09:24:28 -08:00
break ;
case PMBUS_VIRT_READ_IOUT_MIN :
2015-08-15 17:17:53 -07:00
ret = ltc_get_min ( data , client , page , LTC2974_MFR_IOUT_MIN ,
& data - > iout_min [ page ] ) ;
2013-01-27 09:24:28 -08:00
break ;
case PMBUS_VIRT_RESET_IOUT_HISTORY :
ret = 0 ;
break ;
default :
ret = ltc2978_read_word_data ( client , page , reg ) ;
break ;
}
return ret ;
}
2015-06-08 09:56:20 -07:00
static int ltc2975_read_word_data ( struct i2c_client * client , int page , int reg )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
case PMBUS_VIRT_READ_IIN_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC2975_MFR_IIN_PEAK ,
& data - > iin_max ) ;
2015-06-08 09:56:20 -07:00
break ;
case PMBUS_VIRT_READ_IIN_MIN :
2015-08-15 17:17:53 -07:00
ret = ltc_get_min ( data , client , page , LTC2975_MFR_IIN_MIN ,
& data - > iin_min ) ;
2015-06-08 09:56:20 -07:00
break ;
case PMBUS_VIRT_READ_PIN_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC2975_MFR_PIN_PEAK ,
& data - > pin_max ) ;
2015-06-08 09:56:20 -07:00
break ;
case PMBUS_VIRT_READ_PIN_MIN :
2015-08-15 17:17:53 -07:00
ret = ltc_get_min ( data , client , page , LTC2975_MFR_PIN_MIN ,
& data - > pin_min ) ;
2015-06-08 09:56:20 -07:00
break ;
case PMBUS_VIRT_RESET_IIN_HISTORY :
case PMBUS_VIRT_RESET_PIN_HISTORY :
ret = 0 ;
break ;
default :
ret = ltc2978_read_word_data ( client , page , reg ) ;
break ;
}
return ret ;
}
2011-09-11 20:31:09 -07:00
static int ltc3880_read_word_data ( struct i2c_client * client , int page , int reg )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
case PMBUS_VIRT_READ_IOUT_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC3880_MFR_IOUT_PEAK ,
& data - > iout_max [ page ] ) ;
2011-09-11 20:31:09 -07:00
break ;
case PMBUS_VIRT_READ_TEMP2_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page ,
LTC3880_MFR_TEMPERATURE2_PEAK ,
& data - > temp2_max ) ;
2011-09-11 20:31:09 -07:00
break ;
case PMBUS_VIRT_READ_VIN_MIN :
case PMBUS_VIRT_READ_VOUT_MIN :
case PMBUS_VIRT_READ_TEMP_MIN :
ret = - ENXIO ;
break ;
case PMBUS_VIRT_RESET_IOUT_HISTORY :
case PMBUS_VIRT_RESET_TEMP2_HISTORY :
2011-09-02 09:58:37 -07:00
ret = 0 ;
break ;
default :
2011-09-11 20:31:09 -07:00
ret = ltc2978_read_word_data_common ( client , page , reg ) ;
2011-09-02 09:58:37 -07:00
break ;
}
return ret ;
}
2013-01-27 09:24:28 -08:00
static int ltc3883_read_word_data ( struct i2c_client * client , int page , int reg )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
case PMBUS_VIRT_READ_IIN_MAX :
2015-08-15 17:17:53 -07:00
ret = ltc_get_max ( data , client , page , LTC3883_MFR_IIN_PEAK ,
& data - > iin_max ) ;
2013-01-27 09:24:28 -08:00
break ;
case PMBUS_VIRT_RESET_IIN_HISTORY :
ret = 0 ;
break ;
default :
ret = ltc3880_read_word_data ( client , page , reg ) ;
break ;
}
return ret ;
}
2015-08-15 17:02:09 -07:00
static int ltc2978_clear_peaks ( struct ltc2978_data * data ,
struct i2c_client * client , int page )
2011-09-11 20:31:09 -07:00
{
int ret ;
2015-08-15 17:02:09 -07:00
if ( has_clear_peaks ( data ) )
2015-08-17 17:45:32 -07:00
ret = ltc_write_byte ( client , 0 , LTC3880_MFR_CLEAR_PEAKS ) ;
2013-01-27 09:24:28 -08:00
else
2015-08-17 17:45:32 -07:00
ret = ltc_write_byte ( client , page , PMBUS_CLEAR_FAULTS ) ;
2011-09-11 20:31:09 -07:00
return ret ;
}
2011-09-02 09:58:37 -07:00
static int ltc2978_write_word_data ( struct i2c_client * client , int page ,
int reg , u16 word )
{
const struct pmbus_driver_info * info = pmbus_get_driver_info ( client ) ;
struct ltc2978_data * data = to_ltc2978_data ( info ) ;
int ret ;
switch ( reg ) {
2013-01-27 09:24:28 -08:00
case PMBUS_VIRT_RESET_IIN_HISTORY :
data - > iin_max = 0x7c00 ;
2015-06-08 09:56:20 -07:00
data - > iin_min = 0x7bff ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , 0 ) ;
2015-06-08 09:56:20 -07:00
break ;
case PMBUS_VIRT_RESET_PIN_HISTORY :
data - > pin_max = 0x7c00 ;
data - > pin_min = 0x7bff ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , 0 ) ;
2013-01-27 09:24:28 -08:00
break ;
2011-09-11 20:31:09 -07:00
case PMBUS_VIRT_RESET_IOUT_HISTORY :
2013-02-21 09:33:25 -08:00
data - > iout_max [ page ] = 0x7c00 ;
2013-01-27 09:24:28 -08:00
data - > iout_min [ page ] = 0xfbff ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , page ) ;
2011-09-11 20:31:09 -07:00
break ;
case PMBUS_VIRT_RESET_TEMP2_HISTORY :
2013-02-21 09:33:25 -08:00
data - > temp2_max = 0x7c00 ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , page ) ;
2011-09-11 20:31:09 -07:00
break ;
2011-09-02 09:58:37 -07:00
case PMBUS_VIRT_RESET_VOUT_HISTORY :
data - > vout_min [ page ] = 0xffff ;
data - > vout_max [ page ] = 0 ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , page ) ;
2011-09-02 09:58:37 -07:00
break ;
case PMBUS_VIRT_RESET_VIN_HISTORY :
data - > vin_min = 0x7bff ;
2013-02-21 09:33:25 -08:00
data - > vin_max = 0x7c00 ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , page ) ;
2011-09-02 09:58:37 -07:00
break ;
case PMBUS_VIRT_RESET_TEMP_HISTORY :
2013-01-27 09:24:28 -08:00
data - > temp_min [ page ] = 0x7bff ;
2013-02-21 10:27:54 -08:00
data - > temp_max [ page ] = 0x7c00 ;
2015-08-15 17:02:09 -07:00
ret = ltc2978_clear_peaks ( data , client , page ) ;
2011-09-02 09:58:37 -07:00
break ;
default :
2015-08-17 17:45:32 -07:00
ret = ltc_wait_ready ( client ) ;
if ( ret < 0 )
return ret ;
2011-09-02 09:58:37 -07:00
ret = - ENODATA ;
break ;
}
return ret ;
}
static const struct i2c_device_id ltc2978_id [ ] = {
2013-01-27 09:24:28 -08:00
{ " ltc2974 " , ltc2974 } ,
2015-06-08 09:56:20 -07:00
{ " ltc2975 " , ltc2975 } ,
2013-09-23 10:56:48 -07:00
{ " ltc2977 " , ltc2977 } ,
2011-09-02 09:58:37 -07:00
{ " ltc2978 " , ltc2978 } ,
2015-08-17 06:38:01 -07:00
{ " ltc2980 " , ltc2980 } ,
2011-09-11 20:31:09 -07:00
{ " ltc3880 " , ltc3880 } ,
2015-06-08 10:29:45 -07:00
{ " ltc3882 " , ltc3882 } ,
2013-01-27 09:24:28 -08:00
{ " ltc3883 " , ltc3883 } ,
2015-08-17 07:21:43 -07:00
{ " ltc3886 " , ltc3886 } ,
2015-08-07 09:06:37 -07:00
{ " ltc3887 " , ltc3887 } ,
2015-08-17 06:38:01 -07:00
{ " ltm2987 " , ltm2987 } ,
2015-08-17 20:08:09 -07:00
{ " ltm4675 " , ltm4675 } ,
2014-03-05 21:23:01 -08:00
{ " ltm4676 " , ltm4676 } ,
2011-09-02 09:58:37 -07:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ltc2978_id ) ;
2014-10-15 13:55:10 -05:00
# if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
static const struct regulator_desc ltc2978_reg_desc [ ] = {
PMBUS_REGULATOR ( " vout " , 0 ) ,
PMBUS_REGULATOR ( " vout " , 1 ) ,
PMBUS_REGULATOR ( " vout " , 2 ) ,
PMBUS_REGULATOR ( " vout " , 3 ) ,
PMBUS_REGULATOR ( " vout " , 4 ) ,
PMBUS_REGULATOR ( " vout " , 5 ) ,
PMBUS_REGULATOR ( " vout " , 6 ) ,
PMBUS_REGULATOR ( " vout " , 7 ) ,
} ;
# endif /* CONFIG_SENSORS_LTC2978_REGULATOR */
2015-06-08 10:14:00 -07:00
static int ltc2978_get_id ( struct i2c_client * client )
{
int chip_id ;
chip_id = i2c_smbus_read_word_data ( client , LTC2978_MFR_SPECIAL_ID ) ;
2015-06-08 10:29:45 -07:00
if ( chip_id < 0 ) {
const struct i2c_device_id * id ;
u8 buf [ I2C_SMBUS_BLOCK_MAX ] ;
int ret ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_READ_BLOCK_DATA ) )
return - ENODEV ;
ret = i2c_smbus_read_block_data ( client , PMBUS_MFR_ID , buf ) ;
if ( ret < 0 )
return ret ;
if ( ret < 3 | | strncmp ( buf , " LTC " , 3 ) )
return - ENODEV ;
ret = i2c_smbus_read_block_data ( client , PMBUS_MFR_MODEL , buf ) ;
if ( ret < 0 )
return ret ;
for ( id = & ltc2978_id [ 0 ] ; strlen ( id - > name ) ; id + + ) {
if ( ! strncasecmp ( id - > name , buf , strlen ( id - > name ) ) )
return ( int ) id - > driver_data ;
}
return - ENODEV ;
}
2015-06-08 10:14:00 -07:00
2015-08-17 06:21:01 -07:00
chip_id & = LTC2978_ID_MASK ;
if ( chip_id = = LTC2974_ID )
2015-06-08 10:14:00 -07:00
return ltc2974 ;
2015-06-08 09:56:20 -07:00
else if ( chip_id = = LTC2975_ID )
return ltc2975 ;
2015-06-08 10:14:00 -07:00
else if ( chip_id = = LTC2977_ID )
return ltc2977 ;
2015-08-17 06:27:56 -07:00
else if ( chip_id = = LTC2978_ID_REV1 | | chip_id = = LTC2978_ID_REV2 )
2015-06-08 10:14:00 -07:00
return ltc2978 ;
2015-08-17 06:38:01 -07:00
else if ( chip_id = = LTC2980_ID_A | | chip_id = = LTC2980_ID_B )
return ltc2980 ;
2015-08-17 06:21:01 -07:00
else if ( chip_id = = LTC3880_ID )
2015-06-08 10:14:00 -07:00
return ltc3880 ;
2015-08-17 06:27:56 -07:00
else if ( chip_id = = LTC3882_ID | | chip_id = = LTC3882_ID_D1 )
return ltc3882 ;
2015-08-17 06:21:01 -07:00
else if ( chip_id = = LTC3883_ID )
2015-06-08 10:14:00 -07:00
return ltc3883 ;
2015-08-17 07:21:43 -07:00
else if ( chip_id = = LTC3886_ID )
return ltc3886 ;
2015-08-17 06:21:01 -07:00
else if ( chip_id = = LTC3887_ID )
2015-08-07 09:06:37 -07:00
return ltc3887 ;
2015-08-17 06:38:01 -07:00
else if ( chip_id = = LTM2987_ID_A | | chip_id = = LTM2987_ID_B )
return ltm2987 ;
2015-08-17 20:08:09 -07:00
else if ( chip_id = = LTM4675_ID )
return ltm4675 ;
2015-08-17 06:21:01 -07:00
else if ( chip_id = = LTM4676_ID_REV1 | | chip_id = = LTM4676_ID_REV2 | |
chip_id = = LTM4676A_ID )
2015-06-08 10:14:00 -07:00
return ltm4676 ;
dev_err ( & client - > dev , " Unsupported chip ID 0x%x \n " , chip_id ) ;
return - ENODEV ;
}
2011-09-02 09:58:37 -07:00
static int ltc2978_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
2015-06-08 10:14:00 -07:00
int i , chip_id ;
2011-09-02 09:58:37 -07:00
struct ltc2978_data * data ;
struct pmbus_driver_info * info ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_READ_WORD_DATA ) )
return - ENODEV ;
2012-02-22 08:56:43 -08:00
data = devm_kzalloc ( & client - > dev , sizeof ( struct ltc2978_data ) ,
GFP_KERNEL ) ;
2011-09-02 09:58:37 -07:00
if ( ! data )
return - ENOMEM ;
2015-06-08 10:14:00 -07:00
chip_id = ltc2978_get_id ( client ) ;
2012-02-22 08:56:43 -08:00
if ( chip_id < 0 )
return chip_id ;
2011-09-02 09:58:37 -07:00
2015-06-08 10:14:00 -07:00
data - > id = chip_id ;
2011-09-02 09:58:37 -07:00
if ( data - > id ! = id - > driver_data )
dev_warn ( & client - > dev ,
" Device mismatch: Configured %s, detected %s \n " ,
id - > name ,
ltc2978_id [ data - > id ] . name ) ;
info = & data - > info ;
info - > write_word_data = ltc2978_write_word_data ;
2015-08-17 17:45:32 -07:00
info - > write_byte = ltc_write_byte ;
info - > read_word_data = ltc_read_word_data ;
info - > read_byte_data = ltc_read_byte_data ;
2011-09-02 09:58:37 -07:00
data - > vin_min = 0x7bff ;
2013-02-21 09:33:25 -08:00
data - > vin_max = 0x7c00 ;
2013-02-28 08:14:45 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( data - > vout_min ) ; i + + )
data - > vout_min [ i ] = 0xffff ;
2013-01-27 09:24:28 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( data - > iout_min ) ; i + + )
data - > iout_min [ i ] = 0xfbff ;
for ( i = 0 ; i < ARRAY_SIZE ( data - > iout_max ) ; i + + )
data - > iout_max [ i ] = 0x7c00 ;
for ( i = 0 ; i < ARRAY_SIZE ( data - > temp_min ) ; i + + )
data - > temp_min [ i ] = 0x7bff ;
2013-02-21 10:27:54 -08:00
for ( i = 0 ; i < ARRAY_SIZE ( data - > temp_max ) ; i + + )
data - > temp_max [ i ] = 0x7c00 ;
2013-02-21 09:33:25 -08:00
data - > temp2_max = 0x7c00 ;
2011-09-02 09:58:37 -07:00
2013-02-21 10:49:40 -08:00
switch ( data - > id ) {
2013-01-27 09:24:28 -08:00
case ltc2974 :
info - > read_word_data = ltc2974_read_word_data ;
info - > pages = LTC2974_NUM_PAGES ;
info - > func [ 0 ] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_TEMP2 ;
for ( i = 0 ; i < info - > pages ; i + + ) {
info - > func [ i ] | = PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT ;
}
break ;
2015-06-08 09:56:20 -07:00
case ltc2975 :
info - > read_word_data = ltc2975_read_word_data ;
info - > pages = LTC2974_NUM_PAGES ;
info - > func [ 0 ] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
| PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_TEMP2 ;
for ( i = 0 ; i < info - > pages ; i + + ) {
info - > func [ i ] | = PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT ;
}
break ;
2013-09-23 10:56:48 -07:00
case ltc2977 :
2011-09-02 09:58:37 -07:00
case ltc2978 :
2015-08-17 06:38:01 -07:00
case ltc2980 :
case ltm2987 :
2011-09-11 20:31:09 -07:00
info - > read_word_data = ltc2978_read_word_data ;
2013-02-28 08:14:45 -08:00
info - > pages = LTC2978_NUM_PAGES ;
2011-09-02 09:58:37 -07:00
info - > func [ 0 ] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP ;
2013-02-28 08:14:45 -08:00
for ( i = 1 ; i < LTC2978_NUM_PAGES ; i + + ) {
2011-09-02 09:58:37 -07:00
info - > func [ i ] = PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT ;
}
break ;
2011-09-11 20:31:09 -07:00
case ltc3880 :
2015-08-07 09:06:37 -07:00
case ltc3887 :
2015-08-17 20:08:09 -07:00
case ltm4675 :
2014-03-05 21:23:01 -08:00
case ltm4676 :
2015-08-17 17:45:32 -07:00
data - > features | = FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING ;
2011-09-11 20:31:09 -07:00
info - > read_word_data = ltc3880_read_word_data ;
2013-02-28 08:14:45 -08:00
info - > pages = LTC3880_NUM_PAGES ;
2011-09-11 20:31:09 -07:00
info - > func [ 0 ] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP ;
info - > func [ 1 ] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP ;
2013-01-27 09:24:28 -08:00
break ;
2015-06-08 10:29:45 -07:00
case ltc3882 :
2015-08-17 17:45:32 -07:00
data - > features | = FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING ;
2015-06-08 10:29:45 -07:00
info - > read_word_data = ltc3880_read_word_data ;
info - > pages = LTC3880_NUM_PAGES ;
info - > func [ 0 ] = PMBUS_HAVE_VIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP ;
info - > func [ 1 ] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP ;
break ;
2013-01-27 09:24:28 -08:00
case ltc3883 :
2015-08-17 17:45:32 -07:00
data - > features | = FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING ;
2013-01-27 09:24:28 -08:00
info - > read_word_data = ltc3883_read_word_data ;
info - > pages = LTC3883_NUM_PAGES ;
info - > func [ 0 ] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP ;
2011-09-11 20:31:09 -07:00
break ;
2015-08-17 07:21:43 -07:00
case ltc3886 :
2015-08-17 17:45:32 -07:00
data - > features | = FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING ;
2015-08-17 07:21:43 -07:00
info - > read_word_data = ltc3883_read_word_data ;
info - > pages = LTC3880_NUM_PAGES ;
info - > func [ 0 ] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP ;
info - > func [ 1 ] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP ;
break ;
2011-09-02 09:58:37 -07:00
default :
2012-02-22 08:56:43 -08:00
return - ENODEV ;
2011-09-02 09:58:37 -07:00
}
2014-10-15 13:55:10 -05:00
# if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
info - > num_regulators = info - > pages ;
info - > reg_desc = ltc2978_reg_desc ;
if ( info - > num_regulators > ARRAY_SIZE ( ltc2978_reg_desc ) ) {
dev_err ( & client - > dev , " num_regulators too large! " ) ;
info - > num_regulators = ARRAY_SIZE ( ltc2978_reg_desc ) ;
}
# endif
2012-02-22 08:56:43 -08:00
return pmbus_do_probe ( client , id , info ) ;
2011-09-02 09:58:37 -07:00
}
2014-10-15 13:55:10 -05:00
# ifdef CONFIG_OF
static const struct of_device_id ltc2978_of_match [ ] = {
{ . compatible = " lltc,ltc2974 " } ,
2015-06-08 09:56:20 -07:00
{ . compatible = " lltc,ltc2975 " } ,
2014-10-15 13:55:10 -05:00
{ . compatible = " lltc,ltc2977 " } ,
{ . compatible = " lltc,ltc2978 " } ,
2015-08-17 06:38:01 -07:00
{ . compatible = " lltc,ltc2980 " } ,
2014-10-15 13:55:10 -05:00
{ . compatible = " lltc,ltc3880 " } ,
2015-06-08 10:29:45 -07:00
{ . compatible = " lltc,ltc3882 " } ,
2014-10-15 13:55:10 -05:00
{ . compatible = " lltc,ltc3883 " } ,
2015-08-17 07:21:43 -07:00
{ . compatible = " lltc,ltc3886 " } ,
2015-08-07 09:06:37 -07:00
{ . compatible = " lltc,ltc3887 " } ,
2015-08-17 06:38:01 -07:00
{ . compatible = " lltc,ltm2987 " } ,
2015-08-17 20:08:09 -07:00
{ . compatible = " lltc,ltm4675 " } ,
2014-10-15 13:55:10 -05:00
{ . compatible = " lltc,ltm4676 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ltc2978_of_match ) ;
# endif
2011-09-02 09:58:37 -07:00
static struct i2c_driver ltc2978_driver = {
. driver = {
. name = " ltc2978 " ,
2014-10-15 13:55:10 -05:00
. of_match_table = of_match_ptr ( ltc2978_of_match ) ,
2011-09-02 09:58:37 -07:00
} ,
. probe = ltc2978_probe ,
2012-02-22 08:56:44 -08:00
. remove = pmbus_do_remove ,
2011-09-02 09:58:37 -07:00
. id_table = ltc2978_id ,
} ;
2012-01-20 15:38:18 +08:00
module_i2c_driver ( ltc2978_driver ) ;
2011-09-02 09:58:37 -07:00
MODULE_AUTHOR ( " Guenter Roeck " ) ;
2015-06-08 09:56:20 -07:00
MODULE_DESCRIPTION ( " PMBus driver for LTC2978 and comppatible chips " ) ;
2011-09-02 09:58:37 -07:00
MODULE_LICENSE ( " GPL " ) ;