openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

ltc388x.c (75159B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * I2C Device Driver for LTC388X an integrated power control IC.
      8  *
      9  * For new chip with Resistor configurations add new resistor
     10  * configuration array [ for ex sense_resistor_config_56960k
     11  * for Tomahawk chip] and initalise with the appropriate index
     12  * (chip number-G42) in IOCTL opcodes I2C_LTC_IOC_SET_CONFIG and
     13  * I2C_LTC_IOC_SET_RCONFIG.
     14 */
     15 
     16 #include <sal/types.h>
     17 #include <soc/debug.h>
     18 #include <soc/drv.h>
     19 #include <soc/error.h>
     20 #include <soc/i2c.h>
     21 #include <shared/bsl.h>
     22 #include <sal/appl/sal.h>
     23 
     24 typedef struct device_data_s {
     25     sal_mutex_t lock;   /* mutex lock for device operation */
     26     dac_calibrate_t *dac_params;  /*dac params for each device channel*/
     27     int dac_param_len;
     28 } device_data_t;
     29 
     30 #define DEV_MUTEX(dev) \
     31     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->lock)
     32 #define DEV_DAC_PARAMS(dev) \
     33     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_params)
     34 #define DEV_DAC_PARAM_LEN(dev) \
     35     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_param_len)   
     36 #define DEV_CHECK_RETURN(dev) \
     37 { \
     38     if ((dev) == NULL) { \
     39         return SOC_E_INTERNAL; \
     40     } \
     41 }
     42 #define DEV_PRIVDATA_CHECK_RETURN(dev) \
     43 { \
     44     DEV_CHECK_RETURN(dev) \
     45     if ((dev)->priv_data == NULL) { \
     46         return SOC_E_INTERNAL; \
     47     } \
     48 }
     49 
     50 /* L16 format conversions */
     51 #define L16_TO_V(val) ((val)*100000/4096/100000)
     52 #define V_TO_L16(val) ((val)*4096)
     53 #define L16_TO_UV(val) ((val)*100000/4096*10)
     54 #define UV_TO_L16(val) ((val)/10*4096/100000)
     55 
     56 /* The ranges are defined in unit of one part per 100000 */
     57 #define FAULT_LIMIT_RANGE    10000
     58 #define WARN_LIMIT_RANGE      7500
     59 #define MARGIN_RANGE          5000
     60 #define POWER_GOOD_ON_RANGE   7000
     61 #define POWER_GOOD_OFF_RANGE  8000
     62 
     63 #define MAX_VS_CONFIG         15
     64 #define SB2_MAX_VS_CONFIG     6
     65 #define AP_MAX_VS_CONFIG      4
     66 #define FB5_MAX_VS_CONFIG     5
     67 #define HR3_MAX_VS_CONFIG     6
     68 #define GH2_MAX_VS_CONFIG     6
     69 #define MN_MAX_VS_CONFIG      3  
     70 #define WH2_MAX_VS_CONFIG     5
     71 #define FB5_MAX_VS_CONFIG     5
     72 #define HX5_MAX_VS_CONFIG     9
     73 
     74 
     75 #define L16_RANGE_UPPER(L16, range) ((L16) + (int)(range)*L16/100000)
     76 #define L16_RANGE_LOWER(L16, range)  ((L16) - (int)(range)*L16/100000)
     77 
     78 
     79 #define POWER(exponent, input_val)  exponent < 0 ? \
     80                     (int)((int) (input_val) << (exponent*(-1))): \
     81                     (int)((int) (input_val*1000000) >> exponent)/1000000
     82 
     83 static i2c_ltc_t* sense_resistor_config;
     84 
     85 /* Sense Resistors Configuration Table for Tomahawk 56960k */
     86 static i2c_ltc_t sense_resistor_config_56960k[MAX_VS_CONFIG]={
     87     { 0, "1.25",   "ltc3880",   I2C_LTC3880_CH0, LTC3880_1_25V_RES_CONFIG, 0 },
     88     { 1, "1.8",    "ltc3880",   I2C_LTC3880_CH1, LTC3880_1_8V_RES_CONFIG,  0 },
     89     { 2, "Analog", "ltc3882-1", I2C_BOTH_CH,     LTC3882_ANLG_RES_CONFIG,  0 },
     90     { 3, "3.3",    "ltc3882-0", I2C_BOTH_CH,     LTC3882_3_3V_RES_CONFIG,  0 },
     91     { 4, "Core",   I2C_LTC3882_55, I2C_BOTH_CH,     1,  0 },
     92     { 5, "ANA1",   I2C_LTC3880_41, I2C_BOTH_CH,     2,  0 },
     93     { 6, "ANA2",   I2C_LTC3880_42, I2C_LTC3880_CH0, 2,  0 },
     94     { 7, "3.3V",    I2C_LTC3880_42, I2C_LTC3880_CH1, 4,  0 },
     95     { 8, "DDR_15", I2C_LTC3880_43, I2C_BOTH_CH,     2, 0 },
     96     { 9, "SP1",    I2C_LTC3880_47, I2C_LTC3880_CH0, 8,  0 },
     97     { 10, "SP2",    I2C_LTC3880_47, I2C_LTC3880_CH1, 4,  0 },
     98     { 11, "DDR_Core",   I2C_LTC3880_45, I2C_LTC3880_CH0, 8,  0 },
     99     { 12, "SP3",    I2C_LTC3880_45, I2C_LTC3880_CH1, 4,  0 },
    100     { 13,  "Core",   I2C_LTC3882_66, I2C_BOTH_CH,     1,  0 },
    101     { 14, "Core",   I2C_LTC3882_77, I2C_BOTH_CH,     1,  0 }
    102 };
    103 
    104 static i2c_ltc_t sense_resistor_config_56260[SB2_MAX_VS_CONFIG]={
    105     { 0, "Core",   I2C_LTC3880_41, I2C_LTC3880_CH0, LTC3880_CORE_RES_CONFIG,  0 },
    106     { 1, "DDR",    I2C_LTC3880_41, I2C_LTC3880_CH1, LTC3880_DDR_RES_CONFIG,   0 },
    107     { 2, "IPROC_CORE", I2C_LTC3880_42, I2C_LTC3880_CH0, LTC3880_IPROC_CORE_RES_CONFIG,  0 },
    108     { 3, "Analog", I2C_LTC3880_42, I2C_LTC3880_CH1, LTC3880_ANLG_RES_CONFIG,  0 },
    109     { 4, "1.8",    I2C_LTM4676_43, I2C_LTC3880_CH1, LTC3880_1_8V_RES_CONFIG,  0 },
    110     { 5, "3.3",    I2C_LTM4676_43, I2C_LTC3880_CH0, LTC3880_3_3V_RES_CONFIG,  0 },
    111 };
    112 #ifdef BCM_APACHE_SUPPORT
    113 /* Sense Resistors Configuration Table for Apache 56560K and Maverick 56760K*/
    114 static i2c_ltc_t sense_resistor_config_56760[AP_MAX_VS_CONFIG]={
    115     { 0, "Core",     I2C_LTC3884_42, I2C_BOTH_CH,     1,  0 },
    116     { 1, "Core",     I2C_LTC3884_43, I2C_LTC3880_CH0, 1,  0 },
    117     { 2, "Analog",   I2C_LTC3884_43, I2C_LTC3880_CH1, 2,  0 },
    118     { 3, "3.3V",     I2C_LTC3880_45, I2C_BOTH_CH,     2,  0 },
    119 };
    120 /* Sense Resistors Configuration Table for FireBolt5 56565K */
    121 static i2c_ltc_t sense_resistor_config_56565[FB5_MAX_VS_CONFIG]={
    122     { 0, "Core",     I2C_LTC3884_42, I2C_BOTH_CH,     1,  0 },
    123     { 1, "Core",     I2C_LTC3884_43, I2C_LTC3880_CH0, 1,  0 },
    124     { 2, "Analog",   I2C_LTC3884_43, I2C_LTC3880_CH1, 2,  0 },
    125     { 3, "1.0V_PHY", I2C_LTC3884_46, I2C_BOTH_CH,     1,  0 },
    126     { 4, "3.3V",     I2C_LTM4676_47, I2C_BOTH_CH,     0,  1 },
    127 };
    128 #endif
    129 
    130 #ifdef BCM_MONTEREY_SUPPORT
    131 /* Sense Resistors Configuration Table for MONTEREY 56670*/
    132 static i2c_ltc_t sense_resistor_config_56670[MN_MAX_VS_CONFIG]={
    133     { 0, "Core",     I2C_LTC3884_42, I2C_BOTH_CH,     1,  0 },
    134     { 2, "Analog",   I2C_LTC3884_43, I2C_LTC3880_CH1, 2,  0 },
    135     { 3, "3.3V",     I2C_LTC3884_43, I2C_LTC3880_CH0,  1,  0 },
    136 };
    137 #endif 
    138 
    139 #ifdef BCM_HELIX5_SUPPORT
    140 /* Sense Resistors Configuration Table for FireBolt5 56565K */
    141 static i2c_ltc_t sense_resistor_config_56370[HX5_MAX_VS_CONFIG]={
    142     { 0, "Core",     I2C_LTC3884_42, I2C_BOTH_CH,     1,  0 },
    143     { 1, "Core",     I2C_LTC3884_43, I2C_LTC3880_CH0, 1,  0 },
    144     { 2, "Analog",   I2C_LTC3884_43, I2C_LTC3880_CH1, 2,  0 },
    145 };
    146 #endif
    147 
    148 static i2c_ltc_t sense_resistor_config_56160[HR3_MAX_VS_CONFIG]={
    149      {0, "3.3V", I2C_LTC3880_60, I2C_LTC3880_CH0, 2, 0},
    150      {1, "1.0V", I2C_LTC3880_60, I2C_LTC3880_CH1, 2, 0},
    151      {2, "1.8V", I2C_LTC3880_61, I2C_LTC3880_CH0, 2, 0},
    152      {3, "1.2V", I2C_LTC3880_61, I2C_LTC3880_CH1, 2, 0},
    153      {4, "Core", I2C_LTC3880_62, I2C_LTC3880_CH0, 2, 0},
    154      {5, "Analog", I2C_LTC3880_62, I2C_LTC3880_CH1, 2, 0},
    155 };
    156 
    157 static i2c_ltc_t sense_resistor_config_53570[GH2_MAX_VS_CONFIG]={
    158      {0, "3.3V", I2C_LTC3880_60, I2C_LTC3880_CH0, 2, 0},
    159      {1, "1.25V", I2C_LTC3880_60, I2C_LTC3880_CH1, 2, 0},
    160      {2, "1.8V", I2C_LTC3880_61, I2C_LTC3880_CH0, 2, 0},
    161      {3, "1.2V", I2C_LTC3880_61, I2C_LTC3880_CH1, 2, 0},
    162      {4, "Core", I2C_LTC3880_62, I2C_LTC3880_CH0, 2, 0},
    163      {5, "Analog", I2C_LTC3880_62, I2C_LTC3880_CH1, 2, 0},
    164 };
    165 
    166 static i2c_ltc_t sense_resistor_config_53570S[GH2_MAX_VS_CONFIG]={
    167      {0, "3.3V", I2C_LTC3880_60, I2C_LTC3880_CH0, 2, 0},
    168      {1, "1.25V", I2C_LTC3880_60, I2C_LTC3880_CH1, 2, 0},
    169      {2, "1.8V", I2C_LTC3880_61, I2C_LTC3880_CH0, 2, 0},
    170      {3, "1.5V", I2C_LTC3880_61, I2C_LTC3880_CH1, 2, 0},
    171      {4, "Core", I2C_LTC3880_62, I2C_LTC3880_CH0, 2, 0},
    172      {5, "Analog", I2C_LTC3880_62, I2C_LTC3880_CH1, 2, 0},
    173 };
    174 
    175 static i2c_ltc_t sense_resistor_config_53547[WH2_MAX_VS_CONFIG]={
    176      {0, "3.3V", I2C_LTC3880_60, I2C_LTC3880_CH0, 2, 0},
    177      {1, "1.8V", I2C_LTC3880_61, I2C_LTC3880_CH0, 2, 0},
    178      {2, "1.2V", I2C_LTC3880_61, I2C_LTC3880_CH1, 2, 0},
    179      {3, "Core", I2C_LTC3880_62, I2C_LTC3880_CH0, 2, 0},
    180      {4, "Analog", I2C_LTC3880_62, I2C_LTC3880_CH1, 2, 0},
    181 };
    182 
    183 static i2c_ltc_t sense_resistor_config_53549[WH2_MAX_VS_CONFIG]={
    184      {0, "3.3V", I2C_LTC3880_60, I2C_LTC3880_CH0, 2, 0},
    185      {1, "1.8V", I2C_LTC3880_61, I2C_LTC3880_CH0, 2, 0},
    186      {2, "1.5V", I2C_LTC3880_61, I2C_LTC3880_CH1, 2, 0},
    187      {3, "Core", I2C_LTC3880_62, I2C_LTC3880_CH0, 2, 0},
    188      {4, "Analog", I2C_LTC3880_62, I2C_LTC3880_CH1, 2, 0},
    189 };
    190 
    191 typedef struct _ltc_board_resistor_map_s {
    192     int offset;
    193     i2c_ltc_t* sense_resistor_config;
    194 } _ltc_board_resistor_map_t;
    195 
    196 /* 
    197  * This table is used to reflect the mapping between board type offset and 
    198  *  sens_register_config table. The board type offset is used since the IN 
    199  *  parameter on I2C_LTC_IOC_{SET_CONFIG,SET_RCONFIG,READ_IOUT} takes TH SVK 
    200  *  board(G42) as basis to identify different board.
    201  *
    202  * Information for the board type offset :
    203  *  1. This is the delta value of board_type index and TH is the index basis.
    204  *     [Examples] :
    205  *      - Tomahawk(board_type=G42), offset=0
    206  *      - HR3 (board_type=G52~G55, offset=10 (G42-G52)
    207  *  2. The board_type definition can be found in i2c_cmds.c
    208  */
    209 static _ltc_board_resistor_map_t board_resistor_map[] = {
    210     {0, sense_resistor_config_56960k},  /* TH(G42) */
    211     {7, sense_resistor_config_56960k},  /* TH(G49) */
    212     {6, sense_resistor_config_56260},   /* SB2(G48) */
    213     {10, sense_resistor_config_56160},  /* HR3(G52) */
    214     {11, sense_resistor_config_56160},  /* HR3(G53) */
    215     {12, sense_resistor_config_56160},  /* HR3(G54) */
    216     {13, sense_resistor_config_56160},  /* HR3(G55) */
    217     {16, sense_resistor_config_53570},  /* GH2(G58) */
    218     {17, sense_resistor_config_53570S},  /* GH2(G59) */
    219     {20, sense_resistor_config_53547},  /* WH2(G62) */
    220     {21, sense_resistor_config_53549},  /* WH2(G63) */
    221 };
    222 
    223 /* 
    224  * This function is used to match the comming offset (delta_index) with a 
    225  * predefined sense_resistor_configuration table.
    226  */
    227 STATIC int 
    228 ltc388x_board_resistor_match(int unit, int in_offset)
    229 {
    230     int i, map_size;
    231 
    232 #ifdef BCM_APACHE_SUPPORT
    233     if ((SOC_CONTROL(unit)->board_type == 0x94) ||
    234         (SOC_CONTROL(unit)->board_type == 0x96)) {
    235         return SOC_E_NONE;
    236     }
    237 #endif
    238 
    239 #ifdef BCM_MONTEREY_SUPPORT
    240     if ((SOC_CONTROL(unit)->board_type == 0xAA)) { 
    241         return SOC_E_NONE;
    242     }
    243 #endif
    244 
    245 #ifdef BCM_HELIX5_SUPPORT
    246     if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    247         (SOC_CONTROL(unit)->board_type == 0xB6)) {
    248         return SOC_E_NONE;
    249     }
    250 #endif
    251 
    252     map_size = sizeof(board_resistor_map) / sizeof(_ltc_board_resistor_map_t);
    253 
    254     for (i = 0; i < map_size; i++) {
    255         if (board_resistor_map[i].offset == in_offset) {
    256             sense_resistor_config = board_resistor_map[i].sense_resistor_config;
    257             return SOC_E_NONE;
    258         }
    259     }
    260     return SOC_E_NOT_FOUND;
    261 }
    262 
    263 /*
    264  * Convert a floating point value into a
    265  * LinearFloat5_11 formatted word
    266  */
    267 
    268 STATIC int
    269 #ifdef  COMPILER_HAS_DOUBLE
    270 ltc388x_float_to_L11(double input_val, uint16* data)
    271 #else
    272 ltc388x_float_to_L11(int input_val, uint16* data)
    273 #endif
    274 {
    275     uint16 uExponent, uMantissa;
    276     /* set exponent to -16 */
    277     int16 exponent = -16;
    278     /* extract mantissa from input value */
    279     int mantissa = POWER(exponent, input_val);
    280     
    281     /* Search for an exponent that produces
    282      * a valid 11-bit mantissa */
    283     do
    284     {
    285         if((mantissa >= -1024) &&
    286                 (mantissa <= +1023))
    287         {
    288             break; /* stop if mantissa valid */
    289         }
    290         exponent++;
    291         mantissa= POWER(exponent, input_val);
    292     } while (exponent < +15);
    293 
    294     /* Format the exponent of the L11 */
    295     uExponent = exponent << 11;
    296     /* Format the mantissa of the L11 */
    297     uMantissa = mantissa & 0x07FF;
    298     /* Compute value as exponent | mantissa */
    299     *(data) = uExponent | uMantissa;
    300     return SOC_E_NONE;
    301 }
    302 
    303 /*
    304  * Convert a LinearFloat5_11 formatted word
    305  * into a floating point value
    306  */
    307 STATIC int
    308 ltc388x_L11_to_float(uint16 input_val, void *data)
    309 {
    310     /* extract exponent as MS 5 bits */
    311     int8 exponent = input_val >> 11;
    312     /* extract mantissa as LS 11 bits */
    313     int16 mantissa = input_val & 0x7ff;
    314     /* sign extend exponent from 5 to 8 bits */
    315     if( exponent > 0x0F ) exponent |= 0xE0;
    316     /* sign extend mantissa from 11 to 16 bits */
    317     if( mantissa > 0x03FF ) mantissa |= 0xF800;
    318 #ifdef  COMPILER_HAS_DOUBLE
    319     /* compute value as mantissa * 2^(exponent) */
    320     *(double *)data= exponent < 0 ?
    321                       (double) ((mantissa*1000000) >>
    322                                  (exponent* (-1)))/1000000:
    323                       (double) (mantissa << exponent);
    324 #else
    325     *(int *)data= exponent < 0 ?
    326                    (((mantissa)*1000000) >> (exponent*(-1))):
    327                    ((mantissa) << exponent)*100000;
    328 #endif
    329     return SOC_E_NONE;
    330 }
    331 
    332 STATIC int
    333 ltc388x_wait_for_not_busy(int unit, int devno)
    334 {
    335     int rv = SOC_E_NONE;
    336     uint8 mfr_status, saddr;
    337     uint32 usec, wait_usec;
    338     i2c_device_t *dev = soc_i2c_device(unit, devno);
    339 
    340     DEV_CHECK_RETURN(dev);
    341 
    342     wait_usec = 0;
    343     usec = 10;
    344 
    345     saddr = soc_i2c_addr(unit, devno);
    346 
    347     while(wait_usec < 1000000) {
    348         SOC_IF_ERROR_RETURN(soc_i2c_read_byte_data(unit, saddr, 
    349                     PMBUS_CMD_MFR_COMMON, &mfr_status));
    350         dev->rbyte++;
    351         if ((mfr_status & 0x70) == 0x70) {
    352             /* Bit 6 : Chip not busy */
    353             /* Bit 5 : calculations not pending */
    354             /* Bit 4 : OUTPUT not in transition */
    355             break;
    356         } else {
    357             sal_udelay(usec);
    358             wait_usec += usec;
    359         }
    360     }
    361 
    362     if ((mfr_status & 0x70) != 0x70) {
    363          LOG_WARN(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "unit %d i2c %s :"
    364                  "ltc388x is busy !\n"),
    365                  unit, soc_i2c_devname(unit, devno)));
    366         rv = SOC_E_TIMEOUT;
    367     }
    368 
    369     return rv;
    370 }
    371 
    372 STATIC int
    373 ltc388x_read(int unit, int devno, uint16 addr, uint8* data, uint32* len)
    374 {
    375     int rv = SOC_E_NONE;
    376     uint8 saddr;
    377     i2c_device_t *dev = soc_i2c_device(unit, devno);
    378 
    379     DEV_CHECK_RETURN(dev);
    380 
    381     saddr = soc_i2c_addr(unit, devno);
    382 
    383     if (*len == 0) {
    384         return SOC_E_NONE;
    385     }
    386 
    387     if (*len == 1) {
    388         /* reads a single byte from a device, from a designated register*/
    389         rv = soc_i2c_read_byte_data(unit, saddr, addr, data);
    390         dev->rbyte++;
    391         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    392                     "unit %d i2c %s: LTC388X_read: "
    393                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    394                     "rv = %d\n"),
    395                     unit, soc_i2c_devname(unit,devno),
    396                     saddr, addr, *data, *len, rv));
    397     } else if (*len == 2) {
    398         /* reads a single word from a device, from a designated register*/
    399         rv = soc_i2c_read_word_data(unit, saddr, addr,(uint16 *)data);
    400         dev->rbyte +=2;
    401         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    402                     "unit %d i2c %s: LTC388X_read: "
    403                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    404                     "rv = %d\n"),
    405                     unit, soc_i2c_devname(unit,devno),
    406                     saddr, addr, *(uint16 *)data, *len, rv));
    407     } else {
    408         /* not supported for now */
    409         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    410                     "unit %d i2c %s: LTC388X_read fail: "
    411                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    412                     unit, soc_i2c_devname(unit,devno),
    413                     saddr, addr, *data, *len));
    414     }
    415 
    416     return rv;
    417 }
    418 
    419 STATIC int
    420 ltc388x_write(int unit, int devno, uint16 addr, uint8* data, uint32 len)
    421 {
    422     int rv = SOC_E_NONE;
    423     uint8 saddr;
    424     unsigned short val;
    425     i2c_device_t *dev = soc_i2c_device(unit, devno);
    426 
    427     DEV_CHECK_RETURN(dev);
    428 
    429     saddr = soc_i2c_addr(unit, devno);
    430 
    431     if (len == 0) {
    432         /* simply writes command code to device */
    433         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, "i2c %s: LTC388X write: "
    434                     "saddr = 0x%x, addr = 0x%x, len = %d\n"),
    435                     soc_i2c_devname(unit, devno), saddr, addr, len));
    436         rv = soc_i2c_write_byte(unit, saddr, addr);
    437     } else if (len == 1) {
    438         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, "i2c %s: LTC388X write: "
    439                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    440                     soc_i2c_devname(unit, devno), saddr, addr, *data, len));
    441         rv = soc_i2c_write_byte_data(unit, saddr, addr,*data);
    442         dev->tbyte++;
    443     } else if (len == 2) {
    444         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, "i2c %s: LTC388X write: "
    445                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    446                     soc_i2c_devname(unit, devno),
    447                     saddr, addr, *(uint16 *)data, len));
    448         val = *(unsigned short *)data;
    449         rv = soc_i2c_write_word_data(unit, saddr, addr, val);
    450         dev->tbyte += 2;
    451     }
    452 
    453     if (addr == PMBUS_CMD_VOUT_COMMAND) {
    454         /* Make sure the set voltage command is completed internally */
    455         rv = ltc388x_wait_for_not_busy(unit, devno);
    456         if (rv == SOC_E_NONE) {
    457             sal_usleep(120000);
    458         }
    459     }
    460     return rv;
    461 }
    462 
    463 
    464 STATIC int
    465 ltc388x_check_page(int unit, int devno, int ch)
    466 {
    467     int rv;
    468     uint8 page;
    469     uint32 len;
    470 
    471     len = sizeof(char);
    472     rv = ltc388x_read(unit, devno, PMBUS_CMD_PAGE, &page, &len);
    473     if (rv != SOC_E_NONE) {
    474         return rv;
    475     }
    476 
    477     if (page != ch) {
    478         page = ch;
    479         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
    480                     "LTC388X %d set page to %d\n"),
    481                     soc_i2c_addr(unit, devno), page));
    482         rv = ltc388x_write(unit, devno, PMBUS_CMD_PAGE, &page, sizeof(char));
    483     }
    484 
    485     return rv;
    486 }
    487 
    488 
    489 
    490 STATIC int
    491 ltc388x_setmin_max(int unit, int devno, int len)
    492 {
    493     int rv=SOC_E_NONE;
    494     int data,i,ch;
    495     uint16 dac;
    496     i2c_device_t *dev = soc_i2c_device(unit, devno);
    497     int max_vs_config = MAX_VS_CONFIG;
    498 
    499     DEV_PRIVDATA_CHECK_RETURN(dev);
    500 #if defined(BCM_SABER2_SUPPORT)
    501     if(SOC_IS_SABER2(unit)) {
    502         max_vs_config = sizeof(sense_resistor_config_56260)/sizeof(i2c_ltc_t);
    503     }
    504 #endif
    505 #if defined(BCM_APACHE_SUPPORT)
    506     if (SOC_CONTROL(unit)->board_type == 0x94) {
    507         max_vs_config = sizeof(sense_resistor_config_56760)/sizeof(i2c_ltc_t);
    508     } else if (SOC_CONTROL(unit)->board_type == 0x96) {
    509         max_vs_config = sizeof(sense_resistor_config_56565)/sizeof(i2c_ltc_t);
    510     }
    511 #endif
    512 
    513 #if defined(BCM_MONTEREY_SUPPORT)
    514     if (SOC_CONTROL(unit)->board_type == 0xAA) {
    515         max_vs_config = sizeof(sense_resistor_config_56670)/sizeof(i2c_ltc_t);
    516     } 
    517 #endif
    518 
    519 #if defined(BCM_HELIX5_SUPPORT)
    520     if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    521         (SOC_CONTROL(unit)->board_type == 0xB6)) {
    522         max_vs_config = sizeof(sense_resistor_config_56370)/sizeof(i2c_ltc_t);
    523     }
    524 #endif 
    525     /* for HR3 boards */
    526     if ((SOC_CONTROL(unit)->board_type == 0x8F) || 
    527             (SOC_CONTROL(unit)->board_type == 0x90) || 
    528             (SOC_CONTROL(unit)->board_type == 0x91)) {
    529         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
    530     }
    531 
    532     /* for GH2 boards */
    533     if ((SOC_CONTROL(unit)->board_type == 0xA0) ||
    534         (SOC_CONTROL(unit)->board_type == 0xA1)) {
    535         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
    536     }
    537 
    538     /* for WH2 boards */
    539     if ((SOC_CONTROL(unit)->board_type == 0xA8) ||
    540         (SOC_CONTROL(unit)->board_type == 0xA9)) {
    541         max_vs_config = sizeof(sense_resistor_config_53547)/sizeof(i2c_ltc_t);
    542     }
    543 
    544     for(i=0;i<max_vs_config;i++) {
    545          if (sal_strcmp(DEV_DAC_PARAMS(dev)[len].name, 
    546                         sense_resistor_config[i].function) == 0) {
    547              break;
    548          }
    549     }
    550     if (i == max_vs_config) {
    551         LOG_CLI((BSL_META_U(unit, "Error: failed to find sense resistor "
    552                     "for VDD_%s in  LTC 3880 device.\n"), 
    553                     DEV_DAC_PARAMS(dev)[len].name));
    554          return SOC_E_NOT_FOUND;
    555     }
    556     if (sense_resistor_config[i].flag == 0) {
    557         ch=sense_resistor_config[i].ch;
    558         SOC_IF_ERROR_RETURN
    559             (ltc388x_check_page(unit, devno, ch));
    560         data = DEV_DAC_PARAMS(dev)[len].dac_max_hwval;
    561         dac=(uint16) L16_RANGE_UPPER(data, 10000);
    562         SOC_IF_ERROR_RETURN
    563             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_MAX, (void *)&dac, 2));
    564         dac=(uint16) L16_RANGE_UPPER(data, 7000);
    565         SOC_IF_ERROR_RETURN
    566             (ltc388x_wait_for_not_busy(unit, devno));
    567         SOC_IF_ERROR_RETURN
    568             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_OV_FAULT_LIMIT, 
    569                             (void *)&dac, 2));
    570         dac=(uint16) L16_RANGE_UPPER(data, 5000);
    571         SOC_IF_ERROR_RETURN
    572             (ltc388x_wait_for_not_busy(unit, devno));
    573         SOC_IF_ERROR_RETURN
    574             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_OV_WARN_LIMIT, 
    575                             (void *)&dac, 2));
    576         dac=(uint16) L16_RANGE_UPPER(data, 2000);
    577         SOC_IF_ERROR_RETURN
    578             (ltc388x_wait_for_not_busy(unit, devno));
    579         SOC_IF_ERROR_RETURN
    580             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_MARGIN_HIGH, 
    581                             (void *)&dac, 2));
    582 
    583         data=DEV_DAC_PARAMS(dev)[len].dac_min_hwval;
    584         SOC_IF_ERROR_RETURN
    585             (ltc388x_wait_for_not_busy(unit, devno));
    586 
    587         dac=(uint16) L16_RANGE_LOWER(data, 5000);
    588         SOC_IF_ERROR_RETURN
    589             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_UV_FAULT_LIMIT, 
    590                             (void *)&dac, 2));
    591 
    592         if((sal_strcmp("ltc3880", sense_resistor_config[i].devname) == 0) || 
    593                 (sal_strcmp(I2C_LTM4676_43, sense_resistor_config[i].devname) == 0)){
    594             SOC_IF_ERROR_RETURN
    595                 (ltc388x_write(unit, devno, PMBUS_CMD_POWER_GOOD_ON, 
    596                                 (void *)&dac, 2));
    597 
    598             dac=(uint16) L16_RANGE_LOWER(data, 7000);
    599             SOC_IF_ERROR_RETURN
    600                 (ltc388x_write(unit, devno, PMBUS_CMD_POWER_GOOD_OFF, 
    601                                 (void *)&dac, 2));
    602         }
    603         dac=(uint16) L16_RANGE_LOWER(data, 2000);
    604         SOC_IF_ERROR_RETURN
    605             (ltc388x_wait_for_not_busy(unit, devno));
    606         SOC_IF_ERROR_RETURN
    607             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_UV_WARN_LIMIT, 
    608                             (void *)&dac, 2));
    609 
    610         dac=(uint16) L16_RANGE_LOWER(data, 1000);
    611         SOC_IF_ERROR_RETURN
    612             ( ltc388x_wait_for_not_busy(unit, devno));
    613         SOC_IF_ERROR_RETURN
    614             (ltc388x_write(unit, devno, PMBUS_CMD_VOUT_MARGIN_LOW, 
    615                             (void *)&dac, 2));
    616 
    617 #if defined(BCM_SABER2_SUPPORT)
    618         if(!SOC_IS_SABER2(unit)) {
    619 #endif
    620             rv=ltc388x_float_to_L11(sense_resistor_config[i].res_value, &dac);
    621             SOC_IF_ERROR_RETURN
    622                 (ltc388x_write(unit, devno,
    623                                 PMBUS_CMD_IOUT_CAL_GAIN, (void *)&dac, 2));
    624             sal_udelay(500);
    625 #if defined(BCM_SABER2_SUPPORT)
    626         }
    627 #endif
    628 
    629        /* Device Configured */
    630         sense_resistor_config[i].flag=1;
    631 
    632     }
    633     return rv;
    634 }
    635 
    636 STATIC int
    637 ltc388x_get_ch_voltage(int unit, int devno, int ch, unsigned short *voltage)
    638 {
    639     int rv;
    640     uint32 len;
    641 
    642     SOC_IF_ERROR_RETURN(ltc388x_check_page(unit, devno, ch));
    643 
    644     len = sizeof(short);
    645     rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_VOUT, (uint8*)voltage,
    646                         &len);
    647 
    648     return rv;
    649 }
    650 
    651 STATIC int
    652 ltc388x_set_ch_voltage_upper_with_supervision(int unit, int devno, int ch,
    653                                                         unsigned short voltage)
    654 {
    655     unsigned short val;
    656 
    657     val = L16_RANGE_UPPER(voltage, FAULT_LIMIT_RANGE);
    658     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    659                                         PMBUS_CMD_VOUT_OV_FAULT_LIMIT,
    660                                         (uint8*)&val, sizeof(short)));
    661 
    662     val = L16_RANGE_UPPER(voltage, WARN_LIMIT_RANGE);
    663     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    664                                         PMBUS_CMD_VOUT_OV_WARN_LIMIT,
    665                                         (uint8*)&val, sizeof(short)));
    666 
    667     val = L16_RANGE_UPPER(voltage, MARGIN_RANGE);
    668     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    669                                         PMBUS_CMD_VOUT_MARGIN_HIGH,
    670                                         (uint8*)&val, sizeof(short)));
    671 
    672 
    673     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,
    674                                         (uint8*)&voltage, sizeof(short)));
    675 
    676     val = L16_RANGE_LOWER(voltage, MARGIN_RANGE);
    677     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    678                                         PMBUS_CMD_VOUT_MARGIN_LOW,
    679                                         (uint8*)&val, sizeof(short)));
    680 
    681 
    682     val = L16_RANGE_LOWER(voltage, WARN_LIMIT_RANGE);
    683     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    684                                         PMBUS_CMD_VOUT_UV_WARN_LIMIT,
    685                                         (uint8*)&val, sizeof(short)));
    686 
    687     val = L16_RANGE_LOWER(voltage, FAULT_LIMIT_RANGE);
    688     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    689                                         PMBUS_CMD_VOUT_UV_FAULT_LIMIT,
    690                                         (uint8*)&val, sizeof(short)));
    691 
    692     if (soc_i2c_devtype(unit, devno) != LTC3884_DEVICE_TYPE) {
    693         val = L16_RANGE_LOWER(voltage, POWER_GOOD_ON_RANGE);
    694         SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    695                                         PMBUS_CMD_POWER_GOOD_ON,
    696                                         (uint8*)&val, sizeof(short)));
    697 
    698         val = L16_RANGE_LOWER(voltage, POWER_GOOD_OFF_RANGE);
    699         SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    700                                         PMBUS_CMD_POWER_GOOD_OFF,
    701                                         (uint8*)&val, sizeof(short)));
    702     }
    703 
    704     return SOC_E_NONE;
    705 }
    706 
    707 STATIC int
    708 ltc388x_set_ch_voltage_lower_with_supervision(int unit, int devno, int ch,
    709                                                         unsigned short voltage)
    710 {
    711     unsigned short val;
    712 
    713     val = L16_RANGE_LOWER(voltage, FAULT_LIMIT_RANGE);
    714     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    715                                         PMBUS_CMD_VOUT_UV_FAULT_LIMIT,
    716                                         (uint8*)&val, sizeof(short)));
    717 
    718     val = L16_RANGE_LOWER(voltage, WARN_LIMIT_RANGE);
    719     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    720                                         PMBUS_CMD_VOUT_UV_WARN_LIMIT,
    721                                         (uint8*)&val, sizeof(short)));
    722 
    723     val = L16_RANGE_LOWER(voltage, MARGIN_RANGE);
    724     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    725                                         PMBUS_CMD_VOUT_MARGIN_LOW,
    726                                         (uint8*)&val, sizeof(short)));
    727 
    728     if (soc_i2c_devtype(unit, devno) != LTC3884_DEVICE_TYPE) {
    729         val = L16_RANGE_LOWER(voltage, POWER_GOOD_ON_RANGE);
    730         SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    731                                         PMBUS_CMD_POWER_GOOD_ON,
    732                                         (uint8*)&val, sizeof(short)));
    733 
    734         val = L16_RANGE_LOWER(voltage, POWER_GOOD_OFF_RANGE);
    735         SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    736                                         PMBUS_CMD_POWER_GOOD_OFF,
    737                                         (uint8*)&val, sizeof(short)));
    738 
    739     }
    740 
    741     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,
    742                                         (uint8*)&voltage, sizeof(short)));
    743 
    744 
    745     val = L16_RANGE_UPPER(voltage, MARGIN_RANGE);
    746     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    747                                         PMBUS_CMD_VOUT_MARGIN_HIGH,
    748                                         (uint8*)&val, sizeof(short)));
    749 
    750     val = L16_RANGE_UPPER(voltage, WARN_LIMIT_RANGE);
    751     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    752                                         PMBUS_CMD_VOUT_OV_WARN_LIMIT,
    753                                         (uint8*)&val, sizeof(short)));
    754 
    755     val = L16_RANGE_UPPER(voltage, FAULT_LIMIT_RANGE);
    756     SOC_IF_ERROR_RETURN(ltc388x_write(unit, devno,
    757                                         PMBUS_CMD_VOUT_OV_FAULT_LIMIT,
    758                                         (uint8*)&val, sizeof(short)));
    759 
    760     return SOC_E_NONE;
    761 }
    762 
    763 STATIC int
    764 ltc388x_set_ch_voltage(int unit, int devno, int ch, unsigned short voltage)
    765 {
    766     int rv = SOC_E_NONE;
    767     unsigned short old_vout;
    768 
    769     SOC_IF_ERROR_RETURN(ltc388x_get_ch_voltage(unit, devno, ch, &old_vout));
    770 
    771     if (voltage >= old_vout) {
    772         SOC_IF_ERROR_RETURN(ltc388x_set_ch_voltage_upper_with_supervision(unit,
    773                                                     devno, ch, voltage));
    774     } else {
    775         SOC_IF_ERROR_RETURN(ltc388x_set_ch_voltage_lower_with_supervision(unit,
    776                                                     devno, ch, voltage));
    777     }
    778 
    779 
    780 /*
    781     if (SOC_SUCCESS(rv)) {
    782         sal_udelay(100000);
    783     }
    784 */
    785 
    786     return rv;
    787 }
    788 
    789 STATIC int
    790 ltc388x_dac_set_ch_voltage(int unit, int devno, int ch, unsigned short voltage)
    791 {
    792     int rv;
    793     i2c_device_t *dev = soc_i2c_device(unit, devno);
    794 
    795     DEV_PRIVDATA_CHECK_RETURN(dev);
    796 
    797     rv = ltc388x_set_ch_voltage(unit, devno, ch, voltage);
    798 
    799 #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT)
    800     if ((SOC_CONTROL(unit)->board_type == 0x94) ||
    801         (SOC_CONTROL(unit)->board_type == 0x96) ||
    802         (SOC_CONTROL(unit)->board_type == 0xB0) || 
    803         (SOC_CONTROL(unit)->board_type == 0xB3) ||
    804         (SOC_CONTROL(unit)->board_type == 0xB6)) {
    805         /* For Apache/Maverick/FB5 Core voltage is on 3 phase so old voltage
    806          * needs to be saved only for the device connected on first two phases
    807          * which is done in ioctl()
    808          */
    809        return rv;
    810 	}
    811 #endif /* #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT) */
    812 
    813     if (SOC_SUCCESS(rv)) {
    814         /* Keep last value since DAC is write-only device */
    815         DEV_DAC_PARAMS(dev)[ch].dac_last_val = voltage;
    816     }
    817 
    818     return rv;
    819 }
    820 
    821 STATIC int
    822 ltc388x_read_current(int unit, int devno, void* data, int ch)
    823 {
    824     int rv = SOC_E_NONE;
    825 #ifdef  COMPILER_HAS_DOUBLE
    826     double fval,fval1,fval0;
    827 #else
    828     int fval,fval1,fval0;
    829 #endif
    830     uint16 dac,dac0,dac1;
    831     uint32 datalen;
    832     soc_i2c_bus_t *i2cbus;
    833     int i;
    834     int max_vs_config = MAX_VS_CONFIG;
    835 
    836 #if defined(BCM_SABER2_SUPPORT)
    837     if(SOC_IS_SABER2(unit)) {
    838         max_vs_config = sizeof(sense_resistor_config_56260)/sizeof(i2c_ltc_t);
    839     }
    840 #endif
    841 #if defined(BCM_APACHE_SUPPORT)
    842     if (SOC_CONTROL(unit)->board_type == 0x94) {
    843         max_vs_config = sizeof(sense_resistor_config_56760)/sizeof(i2c_ltc_t);
    844     } else if (SOC_CONTROL(unit)->board_type == 0x96) {
    845         max_vs_config = sizeof(sense_resistor_config_56565)/sizeof(i2c_ltc_t);
    846     }
    847 #endif
    848 
    849 #if defined(BCM_MONTEREY_SUPPORT)
    850     if (SOC_CONTROL(unit)->board_type == 0xAA) {
    851         max_vs_config = sizeof(sense_resistor_config_56670)/sizeof(i2c_ltc_t);
    852     }
    853 #endif
    854 
    855 #if defined(BCM_HELIX5_SUPPORT)
    856     if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    857         (SOC_CONTROL(unit)->board_type == 0xB6)) {
    858         max_vs_config = sizeof(sense_resistor_config_56370)/sizeof(i2c_ltc_t);
    859 	}
    860 #endif
    861 
    862     /* for HR3 boards */
    863     if ((SOC_CONTROL(unit)->board_type == 0x8F) || 
    864             (SOC_CONTROL(unit)->board_type == 0x90) || 
    865             (SOC_CONTROL(unit)->board_type == 0x91)) {
    866         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
    867     }
    868 
    869     /* for GH2 boards */
    870     if ((SOC_CONTROL(unit)->board_type == 0xA0) ||
    871         (SOC_CONTROL(unit)->board_type == 0xA1)) {
    872         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
    873     }
    874 
    875     /* for WH2 boards */
    876     if ((SOC_CONTROL(unit)->board_type == 0xA8) ||
    877         (SOC_CONTROL(unit)->board_type == 0xA9)) {
    878         max_vs_config = sizeof(sense_resistor_config_53547)/sizeof(i2c_ltc_t);
    879     }
    880 
    881     i2cbus = I2CBUS(unit);
    882     for( i=0; i < max_vs_config; i++ ) {
    883         if (sal_strcmp(i2cbus->devs[devno]->devname,
    884                             sense_resistor_config[i].devname) == 0) {
    885              if (sense_resistor_config[i].ch == ch ) {
    886                  if (sense_resistor_config[i].flag == 0) {
    887                      if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
    888                          LOG_CLI((BSL_META_U(unit, "Error: failed to set page"
    889                                 " %d in unit:%d LTC388X device name: %s.\n"),
    890                                 ch, unit, soc_i2c_devname(unit, devno)));
    891                          return rv;
    892                      }
    893 
    894 #if defined(BCM_SABER2_SUPPORT)
    895                     if(!SOC_IS_SABER2(unit)) {
    896 #endif
    897                          rv = ltc388x_float_to_L11(
    898                                 sense_resistor_config[i].res_value, &dac);
    899                          if ((rv = ltc388x_write(unit, devno,
    900                                 PMBUS_CMD_IOUT_CAL_GAIN, (void *)&dac, 2)) < 0) {
    901                              LOG_CLI((BSL_META_U(unit, "Error: failed to set "
    902                                      "sense resistor in unit:%d"
    903                                      " LTC388X device name: %s.\n"),
    904                                      unit, soc_i2c_devname(unit, devno)));
    905                              return rv;
    906                          }
    907                          sal_udelay(500);
    908 #if defined(BCM_SABER2_SUPPORT)
    909                     }
    910 #endif
    911                  }
    912                  break;
    913              }
    914         }
    915     }
    916     if (i == max_vs_config) {
    917         LOG_CLI((BSL_META_U(unit, "Error: failed to find sense resistor value "
    918                 "for %s device .\n"), soc_i2c_devname(unit, devno)));
    919         return SOC_E_NOT_FOUND;
    920     }
    921 
    922     if( ch == 0xFF ) {
    923         /* LTC3882/LTC3884 in dual mode hence current at both channels
    924          * are added up to measure total output current.......*/
    925         ch = 0x00;
    926         datalen = 2;
    927         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
    928             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
    929                     "unit: %d LTC388X device name: %s.\n"),
    930                     ch, unit, soc_i2c_devname(unit, devno)));
    931             return rv;
    932         }
    933         if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_IOUT, 
    934                     (void *)&dac0, &datalen)) < 0) {
    935             LOG_CLI((BSL_META_U(unit, "Error: failed to read current in "
    936                     "LTC3882 device.\n")));
    937         }
    938         ch = 0x01;
    939         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
    940             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
    941                     "unit: %d LTC388X device name: %s.\n"),
    942                     ch, unit, soc_i2c_devname(unit, devno)));
    943             return rv;
    944         }
    945         if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_IOUT, 
    946                     (void *)&dac1, &datalen)) < 0) {
    947             LOG_CLI((BSL_META_U(unit, "Error: failed to read current in "
    948                     "unit: %d LTC3882 device name: %s.\n"),
    949                     unit, soc_i2c_devname(unit, devno)));
    950             return rv;
    951         }
    952         rv = ltc388x_L11_to_float(dac1, &fval1);
    953         rv = ltc388x_L11_to_float(dac0, &fval0);
    954         fval = fval0 + fval1;
    955     } else {
    956         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
    957             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
    958                     "unit: %d LTC388X device name: %s.\n"),
    959                     ch, unit, soc_i2c_devname(unit, devno)));
    960             return rv;
    961         }
    962         datalen = 2;
    963         if ((rv = ltc388x_read(unit, devno,
    964                         PMBUS_CMD_READ_IOUT, (void *)&dac, &datalen)) < 0) {
    965             LOG_CLI((BSL_META_U(unit, "Error: failed to read current in "
    966                     "unit: %d LTC3882 device name: %s.\n"),
    967                     unit, soc_i2c_devname(unit, devno)));
    968             return rv;
    969         }
    970         rv = ltc388x_L11_to_float(dac, &fval);
    971     }
    972 #ifdef COMPILER_HAS_DOUBLE
    973     *(double *)data = fval * 1000;
    974 #else
    975     *(int *)data = fval;
    976 #endif
    977     return rv;
    978 }
    979 
    980 STATIC int
    981 ltc388x_read_power(int unit, int devno, void* data, int ch)
    982 {
    983     int rv = SOC_E_NONE;
    984 #ifdef  COMPILER_HAS_DOUBLE
    985     double fval,fval1,fval0;
    986 #else
    987     int fval,fval1,fval0;
    988 #endif
    989     uint16 dac,dac0,dac1;
    990     uint32 datalen;
    991     if( ch == 0xFF) {
    992         /* LTC3882/LTC3884 in dual mode hence current at both channels
    993            are added up to measure totl output current...........*/
    994         ch = 0x00;
    995         datalen = 2;
    996         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
    997             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
    998                     "unit: %d LTC388X device name: %s.\n"),
    999                     ch, unit, soc_i2c_devname(unit, devno)));
   1000             return rv;
   1001         }
   1002         if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_POUT, 
   1003                     (void *)&dac0, &datalen)) < 0) {
   1004             LOG_CLI((BSL_META_U(unit, "Error: failed to read current in "
   1005                     "LTC3882 device.\n")));
   1006         }
   1007         ch = 0x01;
   1008         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
   1009             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1010                     "unit: %d LTC388X device name: %s.\n"),
   1011                     ch, unit, soc_i2c_devname(unit, devno)));
   1012             return rv;
   1013         }
   1014         if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_POUT, 
   1015                     (void *)&dac1, &datalen)) < 0) {
   1016             LOG_CLI((BSL_META_U(unit, "Error: failed to read power in "
   1017                     "unit: %d LTC3882 device name: %s.\n"),
   1018                     unit, soc_i2c_devname(unit, devno)));
   1019             return rv;
   1020         }
   1021         rv = ltc388x_L11_to_float(dac1,&fval1);
   1022         rv = ltc388x_L11_to_float(dac0,&fval0);
   1023         fval = fval0+fval1;
   1024     } else {
   1025         if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
   1026             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1027                     "unit: %d LTC388X device name: %s.\n"),
   1028                     ch, unit, soc_i2c_devname(unit, devno)));
   1029             return rv;
   1030         }
   1031         datalen = 2;
   1032         if ((rv = ltc388x_read(unit, devno,
   1033                     PMBUS_CMD_READ_POUT, (void *)&dac, &datalen)) < 0) {
   1034             LOG_CLI((BSL_META_U(unit, "Error: failed to read power in "
   1035                     "unit: %d LTC3882 device name: %s.\n"),
   1036                     unit, soc_i2c_devname(unit, devno)));
   1037             return rv;
   1038         }
   1039         rv = ltc388x_L11_to_float(dac,&fval);
   1040     }
   1041 #ifdef COMPILER_HAS_DOUBLE
   1042         *(double *)data = fval * 1000;
   1043 #else
   1044         *(int *)data = fval;
   1045 #endif
   1046         return rv;
   1047 }
   1048 
   1049 /*
   1050  * NOTE NOTE NOTE:
   1051  * All tables (dac_calibrate_t) passed to the ioctl() have size > 1
   1052  * and the index is always within this range.
   1053  */
   1054 STATIC int
   1055 ltc388x_ioctl(int unit, int devno, int opcode, void* data, int len)
   1056 {
   1057     int rv = SOC_E_NONE;
   1058 #ifdef COMPILER_HAS_DOUBLE
   1059     double fval=0, fval1=0;
   1060 #else
   1061     int fval=0, fval1=0;
   1062 #endif
   1063     int uV,ch,i;
   1064     int iter;
   1065     uint16 dac,time_ms;
   1066     unsigned short voltage;
   1067     uint32 datalen;
   1068     dac_calibrate_t* params = NULL;
   1069     i2c_device_t *dev = soc_i2c_device(unit, devno);
   1070     int max_vs_config = MAX_VS_CONFIG;
   1071 
   1072 #if defined(BCM_SABER2_SUPPORT)
   1073     if(SOC_IS_SABER2(unit)) {
   1074         max_vs_config = sizeof(sense_resistor_config_56260)/sizeof(i2c_ltc_t);
   1075     }
   1076 #endif
   1077 #if defined(BCM_APACHE_SUPPORT)
   1078     if (SOC_CONTROL(unit)->board_type == 0x94) {
   1079         max_vs_config = sizeof(sense_resistor_config_56760)/sizeof(i2c_ltc_t);
   1080     } else if (SOC_CONTROL(unit)->board_type == 0x96) {
   1081         max_vs_config = sizeof(sense_resistor_config_56565)/sizeof(i2c_ltc_t);
   1082     }
   1083 #endif
   1084     
   1085 #if defined(BCM_MONTEREY_SUPPORT)
   1086     if (SOC_CONTROL(unit)->board_type == 0xAA) {
   1087         max_vs_config = sizeof(sense_resistor_config_56670)/sizeof(i2c_ltc_t);
   1088    } 
   1089 #endif  
   1090 #if defined(BCM_HELIX5_SUPPORT)
   1091     if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1092         (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1093         max_vs_config = sizeof(sense_resistor_config_56370)/sizeof(i2c_ltc_t);
   1094    }
   1095 #endif
   1096     /* for HR3 boards */
   1097     if ((SOC_CONTROL(unit)->board_type == 0x8F) || 
   1098             (SOC_CONTROL(unit)->board_type == 0x90) || 
   1099             (SOC_CONTROL(unit)->board_type == 0x91)) {
   1100         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
   1101     }
   1102 
   1103     /* for GH2 boards */
   1104     if ((SOC_CONTROL(unit)->board_type == 0xA0) ||
   1105         (SOC_CONTROL(unit)->board_type == 0xA1)) {
   1106         max_vs_config = sizeof(sense_resistor_config_56160)/sizeof(i2c_ltc_t);
   1107     }
   1108 
   1109     /* for WH2 boards */
   1110     if ((SOC_CONTROL(unit)->board_type == 0xA8) ||
   1111         (SOC_CONTROL(unit)->board_type == 0xA9)) {
   1112         max_vs_config = sizeof(sense_resistor_config_53547)/sizeof(i2c_ltc_t);
   1113     }
   1114 
   1115     DEV_PRIVDATA_CHECK_RETURN(dev);
   1116 
   1117     /* length field is actually used as an index into the dac_params table*/
   1118     if( !data || ( (DEV_DAC_PARAMS(dev) != NULL) && 
   1119         ((len > DEV_DAC_PARAM_LEN(dev)) && (len != I2C_BOTH_CH)))) {
   1120         /* 
   1121          * len for op = I2C_LTC_IOC_SET_RCONFIG is used as table offset 
   1122          * instead of dac_param's length.
   1123          */
   1124         if (opcode != I2C_LTC_IOC_SET_RCONFIG) {
   1125             return SOC_E_PARAM;
   1126         }
   1127     }
   1128 
   1129     /* Using mutex lock to ensure thread-safe for ioctl operations */
   1130     sal_mutex_take(DEV_MUTEX(dev), sal_mutex_FOREVER);
   1131 
   1132     switch ( opcode ){
   1133     case I2C_ADC_QUERY_CHANNEL:
   1134         ch = len;
   1135         rv = ltc388x_get_ch_voltage(unit, devno, ch, &voltage);
   1136         fval = voltage;
   1137 #ifdef COMPILER_HAS_DOUBLE
   1138         fval = L16_TO_V(fval);
   1139 #else
   1140         fval = L16_TO_UV(fval);
   1141 #endif
   1142         ((i2c_adc_t*)data)->max =
   1143         ((i2c_adc_t*)data)->min =
   1144         ((i2c_adc_t*)data)->val = fval;
   1145         ((i2c_adc_t*)data)->delta = 0;
   1146         ((i2c_adc_t*)data)->nsamples = 1;
   1147         break;
   1148 
   1149     /* Upload calibration table */
   1150     case I2C_DAC_IOC_SET_CALTAB:
   1151         params = (dac_calibrate_t*)data;
   1152         /* dac_params  initialised */
   1153         DEV_DAC_PARAMS(dev) = params;
   1154         DEV_DAC_PARAM_LEN(dev) = len;
   1155         break;
   1156 
   1157     case I2C_DAC_IOC_SETDAC_MIN:
   1158         /* Set MIN voltage */
   1159         if (DEV_DAC_PARAMS(dev)) {
   1160             rv = ltc388x_dac_set_ch_voltage(unit, devno, len,
   1161                     DEV_DAC_PARAMS(dev)[len].dac_min_hwval);
   1162         }
   1163         break;
   1164 
   1165     case I2C_DAC_IOC_SETDAC_MAX:
   1166         /* Set MAX voltage */
   1167         if (DEV_DAC_PARAMS(dev)) {
   1168             rv = ltc388x_dac_set_ch_voltage(unit, devno, len,
   1169                     DEV_DAC_PARAMS(dev)[len].dac_max_hwval);
   1170         }
   1171         break;
   1172     
   1173     case I2C_DAC_IOC_SETDAC_MID:
   1174         /* Set mid-range voltage */
   1175         if (DEV_DAC_PARAMS(dev)) {
   1176             rv = ltc388x_dac_set_ch_voltage(unit, devno, len,
   1177                     DEV_DAC_PARAMS(dev)[len].dac_mid_hwval);
   1178         }
   1179         break;
   1180 
   1181     case I2C_DAC_IOC_CALIBRATE_MAX:
   1182         /* Set MAX output value (from ADC) */
   1183         if (DEV_DAC_PARAMS(dev)) {
   1184 #ifdef COMPILER_HAS_DOUBLE
   1185             fval = *((double*)data);
   1186             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1187                             "CALIBRATE_MAX setting %f\n"), fval));
   1188 #else
   1189             fval = *((int *)data);
   1190             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1191                             "CALIBRATE_MAX setting %d\n"), fval));
   1192 #endif
   1193             DEV_DAC_PARAMS(dev)[len].max = fval;
   1194         }
   1195         break;
   1196 
   1197     case I2C_DAC_IOC_CALIBRATE_MIN:
   1198         /* Set MIN output value (from ADC) */
   1199         if (DEV_DAC_PARAMS(dev)) {
   1200 #ifdef COMPILER_HAS_DOUBLE
   1201             fval = *((double*)data);
   1202             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1203                             "CALIBRATE_MIN setting %f\n"), fval));
   1204 #else
   1205             fval = *((int *)data);
   1206             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1207                             "CALIBRATE_MIN setting %d\n"), fval));
   1208 #endif
   1209             DEV_DAC_PARAMS(dev)[len].min = fval;
   1210         }
   1211         break;
   1212 
   1213     case I2C_DAC_IOC_CALIBRATE_STEP:
   1214         /* Calibrate stepsize */
   1215         if (DEV_DAC_PARAMS(dev)) {
   1216             DEV_DAC_PARAMS(dev)[len].step =
   1217                 (DEV_DAC_PARAMS(dev)[len].use_max ? -1 : 1) *
   1218                 (DEV_DAC_PARAMS(dev)[len].max - DEV_DAC_PARAMS(dev)[len].min) /
   1219                 (DEV_DAC_PARAMS(dev)[len].dac_max_hwval - 
   1220                     DEV_DAC_PARAMS(dev)[len].dac_min_hwval);
   1221 #ifdef COMPILER_HAS_DOUBLE
   1222             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1223                         "unit %d i2c %s: LTC388X calibration on function %s:"
   1224                         "(max=%f,min=%f,step=%f)\n"),
   1225                         unit, soc_i2c_devname(unit,devno),
   1226                         DEV_DAC_PARAMS(dev)[len].name,
   1227                         DEV_DAC_PARAMS(dev)[len].max,
   1228                         DEV_DAC_PARAMS(dev)[len].min,
   1229                         DEV_DAC_PARAMS(dev)[len].step));
   1230 #else
   1231             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1232                         "unit %d i2c %s: LTC388X calibration on function %s:"
   1233                         "(max=%d,min=%d,step=%d)\n"),
   1234                         unit, soc_i2c_devname(unit,devno),
   1235                         DEV_DAC_PARAMS(dev)[len].name,
   1236                         DEV_DAC_PARAMS(dev)[len].max,
   1237                         DEV_DAC_PARAMS(dev)[len].min,
   1238                         DEV_DAC_PARAMS(dev)[len].step));
   1239 #endif
   1240         }
   1241         break;
   1242     case I2C_DAC_IOC_SET_VOUT:
   1243         /* Set output voltage */
   1244         if (DEV_DAC_PARAMS(dev)) {
   1245 #ifdef COMPILER_HAS_DOUBLE
   1246             fval = *((double*)data); /* in V */
   1247             voltage = V_TO_L16(fval);
   1248             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1249                         "unit %d i2c %s: LTC388x ioctl I2C_DAC_IOC_SET_VOUT: "
   1250                         "voltage = %d, len = %d\n"),
   1251                         unit, soc_i2c_devname(unit,devno), voltage, len));
   1252 #else
   1253             fval = *((int *)data); /* in uV */
   1254             voltage = UV_TO_L16(fval);
   1255             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1256                         "unit %d i2c %s: LTC388X ioctl I2C_DAC_IOC_SET_VOUT: "
   1257                         "voltage = %d, len = %d\n"),
   1258                         unit, soc_i2c_devname(unit,devno), voltage, len));
   1259 #endif
   1260             if ((voltage > DEV_DAC_PARAMS(dev)[len].dac_max_hwval)  ||
   1261                     (voltage < DEV_DAC_PARAMS(dev)[len].dac_min_hwval)) {
   1262                 LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1263                                 "unit %d i2c %d: LTC388X given voltage %d "
   1264                                 "beyond range for ch %d, %d, %d\n"),
   1265                             unit, devno, voltage, len,
   1266                             DEV_DAC_PARAMS(dev)[len].dac_max_hwval,
   1267                             DEV_DAC_PARAMS(dev)[len].dac_min_hwval));
   1268                 rv=SOC_E_PARAM;
   1269                 break;
   1270             }
   1271             if ((rv=ltc388x_check_page(unit, devno, len)) < 0) {
   1272                 LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1273                         "unit: %d LTC388X device name: %s.\n"),
   1274                         len, unit, soc_i2c_devname(unit, devno)));
   1275             }
   1276             rv = ltc388x_dac_set_ch_voltage(unit, devno, len, voltage);
   1277         }
   1278        break;
   1279 
   1280     case I2C_REGULATOR_IOC_VOLT_GET:
   1281         rv = ltc388x_get_ch_voltage(unit, devno, len, &voltage);
   1282         if (rv == SOC_E_NONE) {
   1283             *((int *)data) = L16_TO_UV(voltage);
   1284         }
   1285         break;
   1286 
   1287     case I2C_REGULATOR_IOC_VOLT_SET:
   1288         uV = *(int *)data;
   1289         voltage = UV_TO_L16(uV);
   1290         rv = ltc388x_set_ch_voltage(unit, devno, len, voltage);
   1291         break;
   1292 
   1293     case I2C_LTC_IOC_SET_CONFIG:
   1294         /* Initialising sense resistor */
   1295 #ifdef COMPILER_HAS_DOUBLE
   1296         i = *(double *)data;
   1297 #else
   1298         i = *(int *)data;
   1299 #endif
   1300 #ifdef BCM_APACHE_SUPPORT
   1301         if (SOC_CONTROL(unit)->board_type == 0x94) {
   1302             /* Initializing with Apache/Maverick chip resistor configuration */
   1303             sense_resistor_config = sense_resistor_config_56760;
   1304             rv = ltc388x_setmin_max(unit, devno, len);
   1305             break;
   1306         } else if (SOC_CONTROL(unit)->board_type == 0x96) {
   1307             /* Initializing with FB5 chip resistor configuration */
   1308             sense_resistor_config = sense_resistor_config_56565;
   1309             rv = ltc388x_setmin_max(unit, devno, len);
   1310             break;
   1311         }
   1312 #endif
   1313 
   1314 #ifdef BCM_MONTEREY_SUPPORT
   1315         if (SOC_CONTROL(unit)->board_type == 0xAA) {
   1316             /* Initializing with MONTEREY chip resistor configuration */
   1317             sense_resistor_config = sense_resistor_config_56670;
   1318             rv = ltc388x_setmin_max(unit, devno, len);
   1319             break;
   1320         }
   1321 #endif 
   1322 
   1323 #ifdef BCM_HELIX5_SUPPORT
   1324         if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1325             (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1326             /* Initializing with MONTEREY chip resistor configuration */
   1327             sense_resistor_config = sense_resistor_config_56370;
   1328             rv = ltc388x_setmin_max(unit, devno, len);
   1329             break;
   1330         }
   1331 #endif
   1332         /* 
   1333          * Initializing with Tomahawk chip resistor configuration
   1334          *
   1335          * "i" is retrieved from incoming parameter and it is referenced as 
   1336          * board_type offset index. (offset from TH's board type) 
   1337          * 
   1338          * ltc388x_board_resistor_match() as the general matching process
   1339          * uses this offset index to retreive the board 
   1340          * based sense_resistor_configuration.
   1341          */
   1342         if (ltc388x_board_resistor_match(unit, i) == SOC_E_NOT_FOUND) {
   1343             if (i != 4) {
   1344                 LOG_CLI((BSL_META_U(unit, "Error: Invalid chip: %d for "
   1345                         "LTC388X device %s .\n"),
   1346                         i, soc_i2c_devname(unit, devno)));
   1347                 rv=SOC_E_NOT_FOUND;
   1348                 break;
   1349             }
   1350         }
   1351         if (DEV_DAC_PARAMS(dev)) {
   1352             /* Setting max and min values for dac */
   1353             rv= ltc388x_setmin_max(unit, devno, len);
   1354         }
   1355         break;
   1356    case I2C_LTC_IOC_SET_RCONFIG:
   1357         i = len;
   1358 
   1359         /* 
   1360          * Initializing with Tomahawk chip resistor configuration
   1361          *
   1362          * "i" is retrieved from incoming parameter and it is referenced as 
   1363          * board_type offset index. (offset from TH's board type) 
   1364          * 
   1365          * ltc388x_board_resistor_match() as the general matching process
   1366          * uses this offset index to retreive the board 
   1367          * based sense_resistor_configuration.
   1368          */
   1369         if (ltc388x_board_resistor_match(unit, i) == SOC_E_NOT_FOUND) {
   1370             if (i != 4) {
   1371                 LOG_CLI((BSL_META_U(unit, "Error: Invalid chip: %d for "
   1372                         "LTC388X device %s .\n"),
   1373                         i, soc_i2c_devname(unit, devno)));
   1374                 rv=SOC_E_NOT_FOUND;
   1375                 break;
   1376             }
   1377         }
   1378         break;
   1379    case I2C_LTC_IOC_NOMINAL:
   1380         if ((rv=ltc388x_wait_for_not_busy(unit, devno)) < 0) {
   1381             LOG_CLI((BSL_META_U(unit, "Error: unit: %d  LTC388X device name"
   1382                     " %s Device is busy.\n"), 
   1383                     unit, soc_i2c_devname(unit, devno)));
   1384             break;
   1385         }
   1386         ch=*((int *)data);
   1387         if ((rv=ltc388x_check_page(unit, devno, ch)) < 0) {
   1388             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1389                         "unit: %d LTC388X device name: %s.\n"),
   1390                         ch, unit, soc_i2c_devname(unit, devno)));
   1391             break;
   1392         }
   1393         if (DEV_DAC_PARAMS(dev)) {
   1394             dac= (uint16) DEV_DAC_PARAMS(dev)[len].dac_mid_hwval;
   1395             rv = ltc388x_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,(
   1396                                     void *)&dac, 2);
   1397             /* Keep last value since DAC is write-only device */
   1398             DEV_DAC_PARAMS(dev)[len].dac_last_val = dac;
   1399         }
   1400         break;
   1401 
   1402     case I2C_LTC_IOC_READ_VOUT:
   1403         ch = len;
   1404         ((i2c_adc_t*)data)->max =
   1405         ((i2c_adc_t*)data)->min =
   1406         ((i2c_adc_t*)data)->val =
   1407         ((i2c_adc_t*)data)->delta = 0;
   1408 
   1409 #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT)
   1410         if ((SOC_CONTROL(unit)->board_type == 0x94) ||
   1411             (SOC_CONTROL(unit)->board_type == 0x96) ||
   1412             (SOC_CONTROL(unit)->board_type == 0xB0) ||
   1413             (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1414             (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1415             ((i2c_adc_t*)data)->nsamples = 100;
   1416         } else
   1417 #endif /* #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT) */
   1418         {
   1419             ((i2c_adc_t*)data)->nsamples = 1;
   1420         }
   1421 
   1422         /* Taking Samples */
   1423         for (iter = 0; iter < ((i2c_adc_t*)data)->nsamples; iter++) {
   1424             if ((rv = ltc388x_check_page(unit, devno, ch)) < 0) {
   1425                 LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1426                         "unit: %d LTC388X Device name: %s.\n"),
   1427                         ch, unit, soc_i2c_devname(unit, devno)));
   1428                 break;
   1429             }
   1430             datalen = 2;
   1431             if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_READ_VOUT,
   1432                                    (void *)&voltage, &datalen)) < 0) {
   1433                 LOG_CLI((BSL_META_U(unit, "Error: Failed to read voltage in "
   1434                          "unit:%d LTC388x Device name:%s.\n"),
   1435                          unit, soc_i2c_devname(unit, devno)));
   1436                 break;
   1437             }
   1438             fval = voltage;
   1439 #ifdef COMPILER_HAS_DOUBLE
   1440             fval = L16_TO_V(fval);
   1441 #else
   1442             fval = L16_TO_UV(fval);
   1443 #endif
   1444             if (((i2c_adc_t*)data)->min == 0) {
   1445                 ((i2c_adc_t*)data)->min = fval;
   1446             }
   1447             if (fval > ((i2c_adc_t*)data)->max) {
   1448                 ((i2c_adc_t*)data)->max = fval;
   1449             } else if (fval < ((i2c_adc_t*)data)->min) {
   1450                 ((i2c_adc_t*)data)->min = fval;
   1451             }
   1452         }
   1453         ((i2c_adc_t*)data)->val =
   1454             (((i2c_adc_t*)data)->max + ((i2c_adc_t*)data)->min) / 2;
   1455         ((i2c_adc_t*)data)->delta =
   1456             (((i2c_adc_t*)data)->max - ((i2c_adc_t*)data)->min);
   1457         break;
   1458 
   1459     case I2C_LTC_IOC_READ_IOUT:
   1460 #ifdef COMPILER_HAS_DOUBLE
   1461         i = *(double *)data;
   1462 #else
   1463         i = *(int *)data;
   1464 #endif
   1465 #if defined BCM_APACHE_SUPPORT || defined BCM_HELIX5_SUPPORT
   1466         ((i2c_adc_t*)data)->max =
   1467         ((i2c_adc_t*)data)->min =
   1468         ((i2c_adc_t*)data)->val =
   1469         ((i2c_adc_t*)data)->delta = 0;
   1470         /* For Apache/Maverick/FB5/HX5 Three phase support */
   1471         if ((SOC_CONTROL(unit)->board_type == 0x94) ||
   1472             (SOC_CONTROL(unit)->board_type == 0x96) || 
   1473             (SOC_CONTROL(unit)->board_type == 0xAA) ||
   1474             (SOC_CONTROL(unit)->board_type == 0xB0) ||
   1475             (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1476             (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1477 #if defined BCM_APACHE_SUPPORT
   1478             if (SOC_CONTROL(unit)->board_type == 0x94) {
   1479                 /* Initializing with Apache/Maverick sense resistor configuration */
   1480                 sense_resistor_config = sense_resistor_config_56760;
   1481             } else if (SOC_CONTROL(unit)->board_type == 0x96) {
   1482                 /* Initializing with FB5 sense resistor configuration */
   1483                 sense_resistor_config = sense_resistor_config_56565;
   1484             }
   1485 #endif
   1486 #ifdef BCM_MONTEREY_SUPPORT
   1487            if (SOC_CONTROL(unit)->board_type == 0xAA) {
   1488             /* Initializing with MONTEREY chip resistor configuration */
   1489             sense_resistor_config = sense_resistor_config_56670;
   1490             }
   1491 #endif 
   1492 #ifdef BCM_HELIX5_SUPPORT
   1493            if ((SOC_CONTROL(unit)->board_type == 0xB0) ||
   1494                (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1495                (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1496                 /* Initializing with MONTEREY chip resistor configuration */
   1497                 sense_resistor_config = sense_resistor_config_56370;
   1498             }
   1499 #endif
   1500             /* Taking 100 Samples */
   1501             for (iter = 0; iter < 100; iter++) {
   1502                 if (soc_i2c_addr(unit, devno) == I2C_LTC3884_SADDR42  && 
   1503                                     (SOC_CONTROL(unit)->board_type != 0xAA)) {
   1504                     SOC_IF_ERROR_RETURN
   1505                         (ltc388x_read_current(unit, devno, &fval, len));
   1506                     rv = ltc388x_read_current(unit, devno + 1, &fval1, I2C_LTC3880_CH0);
   1507                     fval += fval1;
   1508                 } else {
   1509                     rv = ltc388x_read_current(unit, devno, &fval, len);
   1510                 }
   1511                 if (((i2c_adc_t*)data)->min == 0) {
   1512                     ((i2c_adc_t*)data)->min = fval;
   1513                 }
   1514                 if (fval > ((i2c_adc_t*)data)->max) {
   1515                     ((i2c_adc_t*)data)->max = fval;
   1516                 } else if (fval < ((i2c_adc_t*)data)->min) {
   1517                     ((i2c_adc_t*)data)->min = fval;
   1518                 }
   1519             }
   1520             ((i2c_adc_t*)data)->val =
   1521                 (((i2c_adc_t*)data)->max + ((i2c_adc_t*)data)->min) / 2;
   1522             ((i2c_adc_t*)data)->delta =
   1523                 (((i2c_adc_t*)data)->max - ((i2c_adc_t*)data)->min);
   1524             ((i2c_adc_t*)data)->nsamples = 100;
   1525             break;
   1526         }
   1527 #endif /* #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT) */
   1528 
   1529         if (ltc388x_board_resistor_match(unit, i) == SOC_E_NOT_FOUND) {
   1530             if (i != 4) {
   1531                 LOG_CLI((BSL_META_U(unit, "Error: Invalid chip: %d for "
   1532                         "LTC388X device %s .\n"),
   1533                         i, soc_i2c_devname(unit, devno)));
   1534                 rv=SOC_E_NOT_FOUND;
   1535                 break;
   1536             }
   1537         }
   1538 
   1539         rv=ltc388x_read_current(unit, devno, &fval, len);
   1540 
   1541         /* For Tomahawk PVT Six phase support */
   1542         if ((SOC_CONTROL(unit)->board_type == 0x88)
   1543              && (soc_i2c_devtype(unit, devno) == LTC3882_DEVICE_TYPE)) {
   1544             rv=ltc388x_read_current(unit, devno+1, &fval1, I2C_BOTH_CH);
   1545             fval += fval1;
   1546             fval1 = 0;
   1547             rv=ltc388x_read_current(unit, devno+2, &fval1, I2C_BOTH_CH);
   1548             fval += fval1;
   1549         }
   1550 
   1551 #ifdef COMPILER_HAS_DOUBLE
   1552         *(double *)data=fval;
   1553 #else
   1554         *(int *)data=fval;
   1555 #endif
   1556         break;
   1557 
   1558     case I2C_LTC_IOC_READ_POUT:
   1559 #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT)
   1560         ((i2c_adc_t*)data)->max =
   1561         ((i2c_adc_t*)data)->min =
   1562         ((i2c_adc_t*)data)->val =
   1563         ((i2c_adc_t*)data)->delta = 0;
   1564         /* For Apache/Maverick/FB5/HX5 Three phase support */
   1565         if ((SOC_CONTROL(unit)->board_type == 0x94) ||
   1566             (SOC_CONTROL(unit)->board_type == 0x96) ||
   1567             (SOC_CONTROL(unit)->board_type == 0xAA) ||
   1568             (SOC_CONTROL(unit)->board_type == 0xB0) ||
   1569             (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1570             (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1571             /* Taking 100 Samples */
   1572             for (iter = 0; iter < 100; iter++) {
   1573                 if (soc_i2c_addr(unit, devno) == I2C_LTC3884_SADDR42 && 
   1574                     (SOC_CONTROL(unit)->board_type != 0xAA)) {
   1575                     SOC_IF_ERROR_RETURN
   1576                         (ltc388x_read_power(unit, devno, &fval, len));
   1577                     rv = ltc388x_read_power(unit, devno + 1, &fval1, I2C_LTC3880_CH0);
   1578                     fval += fval1;
   1579                 } else {
   1580                     rv = ltc388x_read_power(unit, devno, &fval, len);
   1581                 }
   1582                 if (((i2c_adc_t*)data)->min == 0) {
   1583                     ((i2c_adc_t*)data)->min = fval;
   1584                 }
   1585                 if (fval > ((i2c_adc_t*)data)->max) {
   1586                     ((i2c_adc_t*)data)->max = fval;
   1587                 } else if (fval < ((i2c_adc_t*)data)->min) {
   1588                     ((i2c_adc_t*)data)->min = fval;
   1589                 }
   1590             }
   1591             ((i2c_adc_t*)data)->val =
   1592                 (((i2c_adc_t*)data)->max + ((i2c_adc_t*)data)->min) / 2;
   1593             ((i2c_adc_t*)data)->delta =
   1594                 (((i2c_adc_t*)data)->max - ((i2c_adc_t*)data)->min);
   1595             ((i2c_adc_t*)data)->nsamples = 100;
   1596             break;
   1597         }
   1598 #endif /* #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT) */
   1599 
   1600         rv=ltc388x_read_power(unit, devno, &fval, len);
   1601 
   1602         /* For Tomahawk PVT Six phase support */
   1603         if ((SOC_CONTROL(unit)->board_type == 0x88)
   1604             && (soc_i2c_devtype(unit, devno) == LTC3882_DEVICE_TYPE)) {
   1605             rv=ltc388x_read_power(unit, devno+1, &fval1, I2C_BOTH_CH);
   1606             fval += fval1;
   1607             fval1 = 0;
   1608             rv=ltc388x_read_power(unit, devno+2, &fval1, I2C_BOTH_CH);
   1609             fval += fval1;
   1610         }
   1611 #ifdef COMPILER_HAS_DOUBLE
   1612         *(double *)data=fval;
   1613 #else
   1614         *(int *)data=fval;
   1615 #endif
   1616         break;
   1617 
   1618     case I2C_LTC_IOC_SET_VOUT:
   1619         /* Finding and  setting page numbers */
   1620         if (DEV_DAC_PARAMS(dev)) {
   1621             for(i=0;i<max_vs_config;i++) {
   1622                 if(sal_strcmp(DEV_DAC_PARAMS(dev)[len].name, 
   1623                             sense_resistor_config[i].function) == 0 ) {
   1624                     break;
   1625                 }
   1626             }
   1627             if (i == max_vs_config) {
   1628                 LOG_CLI((BSL_META_U(unit, "Error: failed to find page number"
   1629                         " for VDD_%s in sense resistor table.\n"), 
   1630                         DEV_DAC_PARAMS(dev)[len].name));
   1631                 rv=SOC_E_NOT_FOUND;
   1632                 break;
   1633             }
   1634             ch = sense_resistor_config[i].ch;
   1635             if ((rv=ltc388x_check_page(unit, devno, ch)) < 0) {
   1636                 LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1637                         "LTC388X device.\n"), ch));
   1638                 break;
   1639             }
   1640             /* Conversion of output voltage */
   1641 #ifdef COMPILER_HAS_DOUBLE
   1642             fval = *((double*)data);
   1643             voltage = (fval*4096);
   1644 #else
   1645             fval = *((int*)data);
   1646             /*2^12 conversion and changing from uVolt */
   1647             voltage = (fval*4096)/1000000;
   1648 #endif
   1649             if ((voltage < DEV_DAC_PARAMS(dev)[len].dac_min_hwval)||
   1650                     (voltage > DEV_DAC_PARAMS(dev)[len].dac_max_hwval)) {
   1651 #ifdef  COMPILER_HAS_DOUBLE
   1652                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1653                           "unit %d i2c %d: LTC388X given voltage %2.3f V "
   1654                           "beyond range( max=%2.3f V, min=%2.3f V) for "
   1655                           "voltage VDD_%s \n"), unit, devno, 
   1656                           (double)voltage/4096, 
   1657                           (double) DEV_DAC_PARAMS(dev)[len].dac_max_hwval/4096,
   1658                           (double) DEV_DAC_PARAMS(dev)[len].dac_min_hwval/4096, 
   1659                           DEV_DAC_PARAMS(dev)[len].name));
   1660 #else
   1661                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1662                           "unit %d i2c %d: LTC388X given voltage %d mV "
   1663                           "beyond range( max=%d mV, min=%d mV ) for " 
   1664                           "voltage  VDD_%s \n"), unit, devno, 
   1665                           voltage*1000/4096, 
   1666                           DEV_DAC_PARAMS(dev)[len].dac_max_hwval*1000/4096,
   1667                           DEV_DAC_PARAMS(dev)[len].dac_min_hwval*1000/4096,
   1668                           DEV_DAC_PARAMS(dev)[len].name));
   1669 
   1670 #endif
   1671                 rv = SOC_E_PARAM;
   1672                 break;
   1673             }
   1674             dac = voltage;
   1675             /* Show what we are doing, for now ... */
   1676             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1677                         "unit %d i2c %s: LTC388X ioctl "
   1678                         "I2C_DAC_IOC_SET_VOUT : voltage = %d, len = %d\n"),
   1679                         unit, soc_i2c_devname(unit,devno), voltage, len));
   1680 #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT)
   1681             /* For Apache/Maverick/FB5/HX5 Three Phase Support
   1682              * LTC3884 at 0x42 : Channel 0,1 = VDD_Core
   1683              * LTC3884 at 0x43 : Channel 0 = VDD_Core
   1684              *                   Channel 1 = VDD_Analog
   1685              */
   1686             if ((SOC_CONTROL(unit)->board_type == 0x94) ||
   1687                 (SOC_CONTROL(unit)->board_type == 0x96) ||
   1688                 (SOC_CONTROL(unit)->board_type == 0xB0) ||
   1689                 (SOC_CONTROL(unit)->board_type == 0xB3) ||
   1690                 (SOC_CONTROL(unit)->board_type == 0xB6)) {
   1691                 if (soc_i2c_addr(unit, devno) == I2C_LTC3884_SADDR42) {
   1692                     SOC_IF_ERROR_RETURN
   1693                         (ltc388x_dac_set_ch_voltage(unit, devno, ch, voltage));
   1694                     /* Set VDD_Core on Channel 0 of I2C_LTC3884_SADDR43 */
   1695                     SOC_IF_ERROR_RETURN
   1696                         (ltc388x_dac_set_ch_voltage(unit, devno + 1, I2C_LTC3880_CH0, voltage));
   1697                 } else {
   1698                     SOC_IF_ERROR_RETURN
   1699                         (ltc388x_dac_set_ch_voltage(unit, devno, ch, voltage));
   1700                 }
   1701                 /* Store voltage setting in NV memory to retain them after power cycling */
   1702                 rv = ltc388x_write(unit, devno, PMBUS_CMD_STORE_USER_ALL, (void *)&dac, 0);
   1703             } else
   1704 #endif /* #if defined (BCM_APACHE_SUPPORT) || defined (BCM_HELIX5_SUPPORT) */
   1705             {
   1706                 rv = ltc388x_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,(void *) &dac, 2);
   1707             }
   1708             /* Keep last value since DAC is write-only device */
   1709             DEV_DAC_PARAMS(dev)[len].dac_last_val = dac;
   1710         }
   1711         break;
   1712 
   1713     case I2C_SET_SEQ:
   1714         if ((rv = ltc388x_check_page(unit, devno, len)) < 0) {
   1715             LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1716                         "unit: %d LTC388X device name: %s.\n"),
   1717                         len, unit, soc_i2c_devname(unit, devno)));
   1718             break;
   1719         }
   1720 #ifdef  COMPILER_HAS_DOUBLE
   1721         fval = *((double*)data);
   1722         rv = ltc388x_float_to_L11(fval, &time_ms);
   1723 #else
   1724         fval = *((int*)data);
   1725         rv = ltc388x_float_to_L11(fval/1000000, &time_ms);
   1726 #endif
   1727         if ((rv = ltc388x_write(unit, devno, PMBUS_CMD_POWER_ON_DELAY,
   1728                     (void *) &time_ms, 2)) < 0) {
   1729              LOG_CLI((BSL_META_U(unit, "Error: failed to set TON_DELAY for"
   1730                      " %s.\n"), soc_i2c_devname(unit, devno)));
   1731              break;
   1732         }
   1733         if ((rv = ltc388x_wait_for_not_busy(unit, devno)) < 0) {
   1734              LOG_CLI((BSL_META_U(unit, "Error: unit: %d  LTC388X device name"
   1735                      " %s Device is busy.\n"),
   1736                      unit, soc_i2c_devname(unit, devno)));
   1737              break;
   1738         }
   1739         dac = 0;
   1740         if ((rv = ltc388x_write(unit, devno, PMBUS_CMD_STORE_USER_ALL, 
   1741                     (void *)&dac, 0)) < 0) {
   1742             LOG_CLI((BSL_META_U(unit, "Error: Failed to store the TON_DELAY"
   1743                     " value to NVRAM in device: %s.\n"),
   1744                     soc_i2c_devname(unit, devno)));
   1745             break;
   1746         }
   1747         if ((rv = ltc388x_wait_for_not_busy(unit, devno)) < 0) {
   1748              LOG_CLI((BSL_META_U(unit, "Error: unit: %d  LTC388X device name"
   1749                     " %s Device is busy.\n"),
   1750                     unit, soc_i2c_devname(unit, devno)));
   1751              break;
   1752         }
   1753         break;
   1754 
   1755     case I2C_READ_SEQ:
   1756          if ((rv = ltc388x_check_page(unit, devno, len)) < 0) {
   1757              LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1758                     "unit: %d LTC388X device name: %s.\n"),
   1759                     len, unit, soc_i2c_devname(unit, devno)));
   1760              break;
   1761          }
   1762          datalen = 2;
   1763          if ((rv = ltc388x_read(unit, devno, PMBUS_CMD_POWER_ON_DELAY,
   1764                     (void *) &time_ms, &datalen)) < 0) {
   1765              LOG_CLI((BSL_META_U(unit, "Error: failed to read TON_DELAY "
   1766                     "for %s.\n"), soc_i2c_devname(unit, devno)));
   1767              break;
   1768          }
   1769          rv = ltc388x_L11_to_float(time_ms, &fval);
   1770 #ifdef  COMPILER_HAS_DOUBLE
   1771         *(double *)data = fval;
   1772 #else
   1773         *(int *)data = (fval);
   1774 #endif
   1775         break;
   1776 
   1777     default:
   1778         LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1779                     "unit %d i2c %s: LTC388X_ioctl: invalid opcode (%d)\n"),
   1780                     unit, soc_i2c_devname(unit,devno), opcode));
   1781         break;
   1782     }
   1783     sal_mutex_give(DEV_MUTEX(dev));
   1784     return rv;
   1785 }
   1786 
   1787 STATIC int
   1788 ltc388x_init(int unit, int devno, void* data, int len)
   1789 {
   1790     int rv = SOC_E_NONE;
   1791     uint16 dac;
   1792     i2c_device_t *dev = soc_i2c_device(unit, devno);
   1793     char *devname;
   1794     int devtype;
   1795 
   1796     if (dev == NULL) {
   1797         rv = SOC_E_INTERNAL;
   1798         goto err_return;
   1799     }
   1800 
   1801     devname = (char *)soc_i2c_devname(unit, devno);
   1802     if (dev->priv_data == NULL) {
   1803         dev->priv_data = sal_alloc(sizeof(device_data_t), devname);
   1804         if (dev->priv_data == NULL) {
   1805             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 
   1806                         "Fail to allocate private data fo dev %s\n"), 
   1807                         soc_i2c_devname(unit, devno)));
   1808             rv = SOC_E_MEMORY;
   1809             goto err_return;    
   1810         }
   1811         DEV_MUTEX(dev) = sal_mutex_create(devname);
   1812         if (DEV_MUTEX(dev) == NULL) {
   1813             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 
   1814                         "Fail to create %s mutex lock\n"), 
   1815                         soc_i2c_devname(unit, devno)));
   1816             rv = SOC_E_MEMORY;
   1817             goto err_free_mem;
   1818         }
   1819         DEV_DAC_PARAMS(dev) = NULL;
   1820         DEV_DAC_PARAM_LEN(dev) = 0;
   1821     }
   1822 
   1823     sal_mutex_take(DEV_MUTEX(dev), sal_mutex_FOREVER);
   1824     if ((rv=ltc388x_write(unit, devno, PMBUS_CMD_CLEAR_FAULTS, 
   1825             (void *)&dac, 0)) < 0) {
   1826         LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 
   1827             "Error: Failed to clear fault for LTC388X Device name:%s.\n"),
   1828             soc_i2c_devname(unit, devno)));
   1829         goto err_unlock;
   1830     }
   1831     if ((rv=ltc388x_wait_for_not_busy(unit, devno)) < 0) {
   1832         LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, 
   1833             "Error: LTC388X device name %s Device is busy.\n"),
   1834             soc_i2c_devname(unit, devno)));
   1835         goto err_unlock;
   1836     }
   1837     sal_mutex_give(DEV_MUTEX(dev));
   1838 
   1839     devtype = soc_i2c_devtype(unit, devno);
   1840     if (devtype == LTC3880_DEVICE_TYPE) {
   1841         soc_i2c_devdesc_set(unit, devno, "Linear Tech LTC3880 Step_Down DC/DC "
   1842             "Controller");
   1843     } else if (devtype == LTC3882_DEVICE_TYPE) {
   1844         soc_i2c_devdesc_set(unit, devno, "Linear Tech LTC3882 Step_Down DC/DC "
   1845             "Controller");
   1846     } else if (devtype == LTC3884_DEVICE_TYPE) {
   1847         soc_i2c_devdesc_set(unit, devno, "Linear Tech LTC3884 Step_Down DC/DC "
   1848             "Controller");
   1849     } else if (devtype == LTM4676_DEVICE_TYPE) {
   1850         soc_i2c_devdesc_set(unit, devno, "Linear Tech LTM4676 Step_Down DC/DC "
   1851             "Controller");
   1852     } else {
   1853         soc_i2c_devdesc_set(unit, devno, devname);
   1854     }
   1855     
   1856     LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
   1857             "ltc388x_init: %s, devNo=0x%x\n"), 
   1858             soc_i2c_devname(unit,devno), devno));
   1859     
   1860     return rv;
   1861 
   1862 err_unlock:
   1863     sal_mutex_give(DEV_MUTEX(dev));
   1864     sal_mutex_destroy(DEV_MUTEX(dev));
   1865 err_free_mem:
   1866     sal_free(dev->priv_data);
   1867     dev->priv_data = NULL;
   1868 err_return:
   1869     return rv;
   1870 }
   1871 
   1872 STATIC int 
   1873 ltc388x_deinit(int unit, int devno)
   1874 {
   1875     int rv = SOC_E_NONE;
   1876     i2c_device_t *dev = soc_i2c_device(unit, devno);
   1877 
   1878     if (dev != NULL) {
   1879         if (dev->priv_data != NULL) {
   1880             if (DEV_MUTEX(dev) != NULL) {
   1881                 sal_mutex_destroy(DEV_MUTEX(dev));
   1882             }
   1883             sal_free(dev->priv_data);
   1884             dev->priv_data = NULL;
   1885         }
   1886     } else {
   1887         rv = SOC_E_INTERNAL;
   1888     }
   1889 
   1890     return rv;
   1891 }
   1892 
   1893 STATIC int
   1894 ltc388x_check_device_id(int unit, int devno, char *id, char *model)
   1895 {
   1896     int rv = SOC_E_NONE;
   1897     i2c_saddr_t saddr;
   1898     uint8 block_size = 0;
   1899     uint8 block_data[256+1];
   1900 
   1901     saddr = soc_i2c_addr(unit, devno);
   1902     if (id != NULL) {
   1903         rv = soc_i2c_block_read(unit, saddr, PMBUS_CMD_MFR_ID, 
   1904                                 &block_size, block_data);
   1905         if (rv == SOC_E_NONE) {
   1906             block_data[block_size] = '\0';
   1907             if (sal_strcmp((char *)block_data, id) != 0) {
   1908                 LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
   1909                     "I2C %s(0x%02x) MFR_ID(%d) is read "
   1910                     "as [%s], not the expected value [%s]\n"), 
   1911                                     soc_i2c_devname(unit, devno), saddr, 
   1912                                     block_size, block_data, id));
   1913                 goto match_fail;
   1914             }
   1915         }
   1916         else {
   1917             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
   1918                 "Fail to get MFR_ID for I2C device addr 0x%02x\n"), saddr));
   1919             goto match_fail; 
   1920         }
   1921     }
   1922     
   1923     if (model != NULL) {
   1924         rv = soc_i2c_block_read(unit, saddr, PMBUS_CMD_MFR_MODEL, 
   1925                                 &block_size, block_data);
   1926         if (rv == SOC_E_NONE) {
   1927             block_data[block_size] = '\0';
   1928             if (sal_strcmp((char *)block_data, model) != 0) {
   1929                 LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
   1930                                     "I2C %s(0x%02x) MFR_MODEL(%d) read "
   1931                                     "as [%s], not the expected value [%s]\n"), 
   1932                                     soc_i2c_devname(unit, devno), saddr, 
   1933                                     block_size, block_data, model));
   1934                 goto match_fail;
   1935             }
   1936         }
   1937         else {
   1938             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit, 
   1939                 "Fail to get MFR_MODEL for I2C device addr 0x%02x\n"), saddr));
   1940             goto match_fail;
   1941         }
   1942     }
   1943 
   1944     return rv;
   1945     
   1946 match_fail:
   1947     return SOC_E_NOT_FOUND;
   1948 }
   1949 
   1950 STATIC int
   1951 ltc3880_init(int unit, int devno, void* data, int len)
   1952 {
   1953     SOC_IF_ERROR_RETURN(
   1954         ltc388x_check_device_id(unit, devno, LTC_MFR_ID, LTC_3880_MFR_MODEL));
   1955 
   1956     return ltc388x_init(unit, devno, data, len);
   1957 }
   1958 
   1959 STATIC int
   1960 ltc3882_init(int unit, int devno, void* data, int len)
   1961 {
   1962     SOC_IF_ERROR_RETURN(
   1963         ltc388x_check_device_id(unit, devno, LTC_MFR_ID, LTC_3882_MFR_MODEL));
   1964 
   1965     return ltc388x_init(unit, devno, data, len);
   1966 }
   1967 
   1968 STATIC int
   1969 ltc3884_init(int unit, int devno, void* data, int len)
   1970 {
   1971     SOC_IF_ERROR_RETURN(
   1972         ltc388x_check_device_id(unit, devno, LTC_MFR_ID, LTC_3884_MFR_MODEL));
   1973 
   1974     return ltc388x_init(unit, devno, data, len);
   1975 }
   1976 
   1977 STATIC int
   1978 ltm4676_init(int unit, int devno, void* data, int len)
   1979 {
   1980     SOC_IF_ERROR_RETURN(
   1981         ltc388x_check_device_id(unit, devno, LTC_MFR_ID, LTM_4676_MFR_MODEL));
   1982 
   1983     return ltc388x_init(unit, devno, data, len);
   1984 }
   1985 
   1986 
   1987 /* ltc 3880 voltage control Chip Driver callout */
   1988 i2c_driver_t _soc_i2c_ltc3880_driver = {
   1989     0x0, 0x0, /* System assigned bytes */
   1990     LTC3880_DEVICE_TYPE,
   1991     ltc388x_read,
   1992     ltc388x_write,
   1993     ltc388x_ioctl,
   1994     ltc3880_init,
   1995     ltc388x_deinit,
   1996 };
   1997 
   1998 /* ltc 3882 voltage control Chip Driver callout */
   1999 i2c_driver_t _soc_i2c_ltc3882_driver = {
   2000     0x0, 0x0, /* System assigned bytes */
   2001     LTC3882_DEVICE_TYPE,
   2002     ltc388x_read,
   2003     ltc388x_write,
   2004     ltc388x_ioctl,
   2005     ltc3882_init,
   2006     ltc388x_deinit,
   2007 };
   2008 
   2009 /* ltc 3884 voltage control Chip Driver callout */
   2010 i2c_driver_t _soc_i2c_ltc3884_driver = {
   2011     0x0, 0x0, /* System assigned bytes */
   2012     LTC3884_DEVICE_TYPE,
   2013     ltc388x_read,
   2014     ltc388x_write,
   2015     ltc388x_ioctl,
   2016     ltc3884_init,
   2017     ltc388x_deinit,
   2018 };
   2019 
   2020 /* ltm 4676 voltage control Chip Driver callout */
   2021 i2c_driver_t _soc_i2c_ltm4676_driver = {
   2022     0x0, 0x0, /* System assigned bytes */
   2023     LTM4676_DEVICE_TYPE,
   2024     ltc388x_read,
   2025     ltc388x_write,
   2026     ltc388x_ioctl,
   2027     ltm4676_init,
   2028     ltc388x_deinit,
   2029 };