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

ltc2974.c (43631B)


      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 LTC2974 an integrated power control IC.
      8  */
      9 
     10 #include <sal/types.h>
     11 #include <soc/debug.h>
     12 #include <soc/drv.h>
     13 #include <soc/error.h>
     14 #include <soc/i2c.h>
     15 #include <shared/bsl.h>
     16 #include <sal/appl/sal.h>
     17  /* Divided by 2^13 for voltage conversion */
     18 #define L16_TO_V(val)  ((val)*100000/8192/100000)
     19 #define V_TO_L16(val)  ((val)*8192)
     20 #define L16_TO_UV(val) ((val)*100000/8192*10)
     21 #define UV_TO_L16(val) ((val)/10*8192/100000)
     22 
     23 #define L16_RANGE_UPPER(L16, range) ((L16) + (int)(range)*L16/100000)
     24 #define L16_RANGE_LOWER(L16, range) ((L16) - (int)(range)*L16/100000)
     25 
     26 #define MAX_VS_CONFIG    2
     27 
     28 #define POWER(exponent, input_val)  exponent < 0 ? \
     29                             (int)((int) (input_val) << (exponent*(-1))): \
     30                             (int)((int) (input_val*1000000) >> \
     31 			    exponent)/1000000
     32 
     33 typedef struct device_data_s {
     34     sal_mutex_t lock;   /* mutex lock for device operation */
     35     dac_calibrate_t *dac_params;  /*dac params for each device channel*/
     36     int dac_param_len;
     37 } device_data_t;
     38 
     39 #define DEV_DAC_PARAMS(dev) \
     40     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_params)
     41 #define DEV_DAC_PARAM_LEN(dev) \
     42     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_param_len)   
     43 
     44 #define DEV_CHECK_RETURN(dev) \
     45 { \
     46     if ((dev) == NULL) { \
     47         return SOC_E_INTERNAL; \
     48     } \
     49 }
     50 
     51 #define DEV_PRIVDATA_CHECK_RETURN(dev) \
     52 { \
     53     DEV_CHECK_RETURN(dev) \
     54     if ((dev)->priv_data == NULL) { \
     55         return SOC_E_INTERNAL; \
     56     } \
     57 }
     58 
     59 static i2c_ltc_t* sense_resistor_config;
     60 typedef struct _ltc_board_resistor_map_s {
     61     int offset;
     62     i2c_ltc_t* sense_resistor_config;
     63 } _ltc_board_resistor_map_t;
     64 
     65 #define ML_MAX_VS_CONFIG     4
     66 #define MONTEREY_MAX_VS_CONFIG     4
     67 #if 0
     68 static i2c_ltc_t sense_resistor_config_56270[ML_MAX_VS_CONFIG]={
     69     { 0, "Core",   I2C_LTC3880_41, I2C_LTC3880_CH0, LTC3880_CORE_RES_CONFIG,  0 },
     70     { 1, "Analog", I2C_LTC3880_42, I2C_LTC3880_CH1, LTC3880_ANLG_RES_CONFIG,  0 },
     71     { 2, "1.8",    I2C_LTM4676_43, I2C_LTC3880_CH1, LTC3880_1_8V_RES_CONFIG,  0 },
     72     { 3, "3.3",    I2C_LTM4676_43, I2C_LTC3880_CH0, LTC3880_3_3V_RES_CONFIG,  0 },
     73 };
     74 #endif
     75 
     76 static i2c_ltc_t sense_resistor_config_56270[ML_MAX_VS_CONFIG]={
     77     { 0, "Core",   I2C_LTC2974_0, I2C_LTC2974_CH0, 0x1,  0 },
     78     { 1, "Analog", I2C_LTC2974_0, I2C_LTC2974_CH1, 0x2,  0 },
     79     { 2, "3.3",    I2C_LTC2974_0, I2C_LTC2974_CH2, 0x2,  0 },
     80     { 3, "1.8",    I2C_LTC2974_0, I2C_LTC2974_CH3, 0x2,  0 },
     81 };
     82 static i2c_ltc_t sense_resistor_config_56670[MONTEREY_MAX_VS_CONFIG]={
     83     { 0, "1.2V",   I2C_LTC2974_64, I2C_LTC2974_CH0, 0x4,  0 },
     84     { 1, "3.3dut", I2C_LTC2974_64, I2C_LTC2974_CH1, 0x44,  0 },
     85     { 2, "1.8V",    I2C_LTC2974_64, I2C_LTC2974_CH2, 0x14,  0 },
     86     { 3, "1.2mdio",    I2C_LTC2974_64, I2C_LTC2974_CH3, 0xC8,  0 },
     87  
     88 };
     89 #define TH2_MAX_VS_CONFIG     4
     90 static i2c_ltc_t sense_resistor_config_56970[TH2_MAX_VS_CONFIG]={
     91     { 0, "Analog", I2C_LTC2974_5C, I2C_LTC2974_CH0, 0xF801/*0.5*/,  0 },
     92     { 1, "1.2",    I2C_LTC2974_5C, I2C_LTC2974_CH1, 0x4 /*4*/  ,  0 },
     93     { 2, "1.8",    I2C_LTC2974_5C, I2C_LTC2974_CH2, 0xC8/*200*/,  0 },
     94     { 3, "3.3",    I2C_LTC2974_5C, I2C_LTC2974_CH3, 0xC8/*200*/,  0 },
     95 };
     96 
     97 #define TD3_MAX_VS_CONFIG     4
     98 static i2c_ltc_t sense_resistor_config_56870[TD3_MAX_VS_CONFIG]={
     99     { 0, "Analog", I2C_LTC2974_5C, I2C_LTC2974_CH0, 0xF801/*0.5*/,  0 },
    100     { 1, "1.2",    I2C_LTC2974_5C, I2C_LTC2974_CH1, 0x4 /*4*/  ,  0 },
    101     { 2, "1.8",    I2C_LTC2974_5C, I2C_LTC2974_CH2, 0xC8/*200*/,  0 },
    102     { 3, "3.3",    I2C_LTC2974_5C, I2C_LTC2974_CH3, 0xC8/*200*/,  0 },
    103 };
    104 
    105 #define TH3_MAX_VS_CONFIG     4
    106 static i2c_ltc_t sense_resistor_config_56980[TH3_MAX_VS_CONFIG]={
    107     { 0, "MDIO",   I2C_LTC2974_5C, I2C_LTC2974_CH0, 0xF801/*0.5*/,  0 },
    108     { 1, "1.2",    I2C_LTC2974_5C, I2C_LTC2974_CH1, 0x4 /*4*/  ,  0 },
    109     { 2, "1.8",    I2C_LTC2974_5C, I2C_LTC2974_CH2, 0xC8/*200*/,  0 },
    110     { 3, "3.3",    I2C_LTC2974_5C, I2C_LTC2974_CH3, 0xC8/*200*/,  0 },
    111 };
    112 
    113 
    114 #define HX5_MAX_VS_CONFIG     8
    115 static i2c_ltc_t sense_resistor_config_56370[HX5_MAX_VS_CONFIG]={
    116     { 0, "0.88V",    I2C_LTC2974_63, I2C_LTC2974_CH0, 0xEA20,  0 },
    117     { 1, "3.3V_Dut", I2C_LTC2974_63, I2C_LTC2974_CH1, 0xEA20,  0 },
    118     { 2, "2.5V",     I2C_LTC2974_63, I2C_LTC2974_CH2, 0xEA20,  0 },
    119     { 3, "VDD_MDIO", I2C_LTC2974_63, I2C_LTC2974_CH3, 0xF320,  0 },
    120     { 4, "1.8V",     I2C_LTC2974_64, I2C_LTC2974_CH0, 0xDA80,  0 },
    121     { 5, "1.2V",     I2C_LTC2974_64, I2C_LTC2974_CH1, 0xD280,  0 },
    122     { 6, "3.3V",     I2C_LTC2974_64, I2C_LTC2974_CH2, 0xBA00,  0 },    
    123     { 7, "5.0V",     I2C_LTC2974_64, I2C_LTC2974_CH3, 0xEA20,  0 }
    124 };
    125 
    126 /* 
    127  * This table is used to reflect the mapping between board type offset and 
    128  *  sens_register_config table. The board type offset is used since the IN 
    129  *  parameter on I2C_LTC_IOC_{SET_CONFIG,SET_RCONFIG,READ_IOUT} takes Metrolite SVK 
    130  *  board(G56) as basis to identify different board.
    131  *
    132  * Information for the board type offset :
    133  *  1. This is the delta value of board_type index and TH is the index basis.
    134  *     [Examples] :
    135  *      - Metrolite(board_type=G56), offset=14
    136  *  2. The board_type definition can be found in i2c_cmds.c
    137  */
    138 static _ltc_board_resistor_map_t board_resistor_map[] = {
    139     {14, sense_resistor_config_56270},   /* Metrolite(G56) */
    140     {15, sense_resistor_config_56970},   /* TOMAHAWK2(G57) */
    141     {18, sense_resistor_config_56870},   /* TRIDENT3(G60) */
    142     {19, sense_resistor_config_56670},   /* MONTEREY(G61) */
    143     {22, sense_resistor_config_56980},   /* TOMAHAWK3(G64) */
    144     {23, sense_resistor_config_56370},   /* HELIX5(G65) */
    145 };
    146 
    147 static sal_mutex_t ioctl_lock = NULL;
    148 
    149 /*
    150  * Convert a floating point value into a
    151  * LinearFloat5_11 formatted word
    152  */
    153 STATIC int
    154 #ifdef  COMPILER_HAS_DOUBLE
    155 ltc2974_float_to_L11(double input_val, uint16* data)
    156 #else
    157 ltc2974_float_to_L11(int input_val, uint16* data)
    158 #endif
    159 {
    160     uint16 uExponent, uMantissa;
    161     /* set exponent to -16 */
    162     int16 exponent = -16;
    163     /* extract mantissa from input value */
    164     int mantissa = POWER(exponent, input_val); 
    165 
    166     /* Search for an exponent that produces
    167      * a valid 11-bit mantissa */
    168     do
    169     {
    170         if((mantissa >= -1024) &&
    171                 (mantissa <= +1023))
    172         {
    173             break; /* stop if mantissa valid */
    174         }
    175         exponent++;
    176         mantissa = POWER(exponent, input_val);
    177     } while (exponent < +15);
    178 
    179     /* Format the exponent of the L11 */
    180     uExponent = exponent << 11;
    181     /* Format the mantissa of the L11 */
    182     uMantissa = mantissa & 0x07FF;
    183     /* Compute value as exponent | mantissa */
    184     *(data) = uExponent | uMantissa;
    185     return SOC_E_NONE;
    186 }
    187 
    188 /*
    189  * Convert a LinearFloat5_11 formatted word
    190  * into a floating point value
    191  */
    192 STATIC int
    193 ltc2974_L11_to_float(uint16 input_val, void *data)
    194 {
    195     /* extract exponent as MS 5 bits */
    196     int8 exponent = input_val >> 11;
    197     /* extract mantissa as LS 11 bits */
    198     int16 mantissa = input_val & 0x7ff;
    199     /* sign extend exponent from 5 to 8 bits */
    200     if( exponent > 0x0F ) exponent |= 0xE0;
    201     /* sign extend mantissa from 11 to 16 bits */
    202     if( mantissa > 0x03FF ) mantissa |= 0xF800;
    203 #ifdef  COMPILER_HAS_DOUBLE
    204     /* compute value as mantissa * 2^(exponent) */
    205     *(double *)data= exponent < 0 ?
    206                       (double) ((mantissa*1000000) >>
    207                                 (exponent*(-1)))/1000000:
    208                       (double) (mantissa << exponent);
    209 #else
    210     *(int *)data= exponent < 0 ?
    211                    (((mantissa)*1000000) >> (exponent*(-1))):
    212                    ((mantissa) << exponent)*100000;
    213 #endif
    214     return SOC_E_NONE;
    215 }
    216 
    217 STATIC int
    218 ltc2974_wait_for_not_busy(int unit, int devno)
    219 {
    220     int rv = SOC_E_NONE;
    221     uint8 mfr_status, saddr;
    222     uint32 usec, wait_usec;
    223 
    224     wait_usec = 0;
    225     usec = 10;
    226 
    227     saddr = soc_i2c_addr(unit, devno);
    228 
    229     while(wait_usec < 1000000) {
    230         SOC_IF_ERROR_RETURN
    231             (soc_i2c_read_byte_data(unit, saddr,PMBUS_CMD_MFR_COMMON,
    232                                     &mfr_status));
    233         soc_i2c_device(unit, devno)->rbyte++;
    234         if ((mfr_status & 0x70) == 0x70) {
    235             /* Bit 6 : Chip not busy */
    236             /* Bit 5 : calculations not pending */
    237             /* Bit 4 : OUTPUT not in transition */
    238             break;
    239         } else {
    240             sal_udelay(usec);
    241             wait_usec += usec;
    242         }
    243     }
    244 
    245     if ((mfr_status & 0x70) != 0x70) {
    246         LOG_WARN(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "unit %d i2c %s :ltc2974 is busy !\n"),
    247                  unit, soc_i2c_devname(unit, devno)));
    248         rv = SOC_E_TIMEOUT;
    249     }
    250     return rv;
    251 }
    252 
    253 
    254 STATIC int
    255 ltc2974_read(int unit, int devno, uint16 addr, uint8* data, uint32* len)
    256 {
    257     int rv = SOC_E_NONE;
    258     uint8 saddr;
    259 
    260     saddr = soc_i2c_addr(unit, devno);
    261 
    262     if (*len == 0) {
    263         return SOC_E_NONE;
    264     }
    265     if (*len == 1) {
    266         /* reads a single byte from a device, from a designated register*/
    267         rv = soc_i2c_read_byte_data(unit, saddr, addr,data);
    268         soc_i2c_device(unit, devno)->rbyte++;
    269          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    270                     "unit %d i2c %s: LTC2974_read: "
    271                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    272                     "rv = %d\n"),
    273                     unit, soc_i2c_devname(unit,devno),
    274                     saddr, addr, *data, *len, rv));
    275     } else if (*len == 2) {
    276         /* reads a single word from a device, from a designated register*/
    277         rv = soc_i2c_read_word_data(unit, saddr, addr,(uint16 *)data);
    278         soc_i2c_device(unit, devno)->rbyte +=2;
    279         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    280                     "unit %d i2c %s: LTC2974_read: "
    281                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    282                     "rv = %d\n"),
    283                     unit, soc_i2c_devname(unit,devno),
    284                     saddr, addr, *(uint16 *)data, *len, rv));
    285     } else {
    286         /* not supported for now */
    287          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    288                     "unit %d i2c %s: LTC2974_read fail: "
    289                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    290                     unit, soc_i2c_devname(unit,devno),
    291                     saddr, addr, *data, *len));
    292     }
    293     return rv;
    294 }
    295 
    296 STATIC int
    297 ltc2974_write(int unit, int devno, uint16 addr, uint8* data, uint32 len)
    298 {
    299     int rv = SOC_E_NONE;
    300     uint8 saddr;
    301     unsigned short val;
    302 
    303     saddr = soc_i2c_addr(unit, devno);
    304 
    305     if (len == 0) {
    306         /* simply writes command code to device */
    307         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: LTC2974 write: "
    308                     "saddr = 0x%x, addr = 0x%x, len = %d\n"),
    309                     soc_i2c_devname(unit, devno), saddr, addr, len));
    310         rv = soc_i2c_write_byte(unit, saddr, addr);
    311     } else if (len == 1) {
    312         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: LTC2974 write: "
    313                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    314                     soc_i2c_devname(unit, devno), saddr, addr, *data, len));
    315         rv = soc_i2c_write_byte_data(unit, saddr, addr, *data);
    316         soc_i2c_device(unit, devno)->tbyte++;
    317     } else if (len == 2) {
    318          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: LTC2974 write: "
    319                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    320                     soc_i2c_devname(unit, devno),
    321                     saddr, addr, *(uint16 *)data, len));
    322         val = *(unsigned short *)data;
    323         rv = soc_i2c_write_word_data(unit, saddr, addr, val);
    324         soc_i2c_device(unit, devno)->tbyte += 2;
    325     }
    326     return rv;
    327 }
    328 
    329 STATIC int
    330 ltc2974_check_page(int unit, int devno, int ch)
    331 {
    332      int rv;
    333      uint8 page;
    334      uint32 len;
    335 
    336      len = sizeof(char);
    337      rv = ltc2974_read(unit, devno, PMBUS_CMD_PAGE, &page, &len);
    338      if (rv != SOC_E_NONE) {
    339          return rv;
    340      }
    341 
    342      if (page != ch) {
    343          page = ch;
    344          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "LTC2974 %d set page to %d\n"),
    345                      soc_i2c_addr(unit, devno), page));
    346          rv = ltc2974_write(unit, devno, PMBUS_CMD_PAGE, &page, sizeof(char));
    347      }
    348      return rv;
    349  }
    350 
    351 STATIC int
    352 ltc2974_get_ch_voltage(int unit, int devno, int ch, unsigned short *voltage)
    353 {
    354     int rv;
    355     uint32 len;
    356 
    357     SOC_IF_ERROR_RETURN(ltc2974_check_page(unit, devno, ch));
    358 
    359     len = sizeof(short);
    360     rv = ltc2974_read(unit, devno, PMBUS_CMD_READ_VOUT, (uint8*)voltage,
    361                         &len);
    362 
    363     return rv;
    364 }
    365 
    366 STATIC int
    367 ltc2974_set_ch_voltage_upper_with_supervision(int unit, int devno, int ch,
    368                                                         unsigned short voltage)
    369 {
    370 
    371     SOC_IF_ERROR_RETURN(ltc2974_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,
    372                                         (uint8*)&voltage, sizeof(short)));
    373     return SOC_E_NONE;
    374 }
    375 
    376 STATIC int
    377 ltc2974_set_ch_voltage_lower_with_supervision(int unit, int devno, int ch,
    378                                                         unsigned short voltage)
    379 {
    380     SOC_IF_ERROR_RETURN(ltc2974_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,
    381                                         (uint8*)&voltage, sizeof(short)));
    382 
    383     return SOC_E_NONE;
    384 }
    385 STATIC int
    386 ltc2974_set_ch_voltage(int unit, int devno, int ch, unsigned short voltage)
    387 {
    388     int rv = SOC_E_NONE;
    389     unsigned short old_vout;
    390 
    391     SOC_IF_ERROR_RETURN(ltc2974_get_ch_voltage(unit, devno, ch, &old_vout));
    392 
    393     if (voltage >= old_vout) {
    394         SOC_IF_ERROR_RETURN(ltc2974_set_ch_voltage_upper_with_supervision(unit,
    395                                                     devno, ch, voltage));
    396     } else {
    397         SOC_IF_ERROR_RETURN(ltc2974_set_ch_voltage_lower_with_supervision(unit,
    398                                                     devno, ch, voltage));
    399     }
    400 
    401 
    402 /*
    403     if (SOC_SUCCESS(rv)) {
    404         sal_udelay(100000);
    405     }
    406 */
    407 
    408     return rv;
    409 }
    410 STATIC int
    411 ltc2974_dac_set_ch_voltage(int unit, int devno, int ch, unsigned short voltage)
    412 {
    413     int rv;
    414     i2c_device_t *dev = soc_i2c_device(unit, devno);
    415 
    416     DEV_PRIVDATA_CHECK_RETURN(dev);
    417 
    418     rv = ltc2974_set_ch_voltage(unit, devno, ch, voltage);
    419 
    420     if (SOC_SUCCESS(rv)) {
    421         /* Keep last value since DAC is write-only device */
    422         DEV_DAC_PARAMS(dev)[ch].dac_last_val = voltage;
    423     }
    424 
    425     return rv;
    426 }
    427 
    428 /* 
    429  * This function is used to match the comming offset (delta_index) with a 
    430  * predefined sense_resistor_configuration table.
    431  */
    432 STATIC int 
    433 ltc2974_board_resistor_match(int in_offset) 
    434 {
    435     int i, map_size;
    436 
    437     map_size = sizeof(board_resistor_map) / sizeof(_ltc_board_resistor_map_t);
    438 
    439     for (i = 0; i < map_size; i++) {
    440         if (board_resistor_map[i].offset == in_offset) {
    441             sense_resistor_config = board_resistor_map[i].sense_resistor_config;
    442             return SOC_E_NONE;
    443         }
    444     }
    445     
    446     return SOC_E_NOT_FOUND;
    447 }
    448 
    449 STATIC int
    450 ltc2974_setmin_max(int unit, int devno, int len)
    451 {
    452     int rv=SOC_E_NONE;
    453     int data,i,ch;
    454     uint16 dac;
    455     i2c_device_t *dev = soc_i2c_device(unit, devno);
    456     int max_vs_config = 1;
    457 
    458     DEV_PRIVDATA_CHECK_RETURN(dev);
    459 
    460 #ifdef BCM_METROLITE_SUPPORT
    461     if (SOC_CONTROL(unit)->board_type == 0x98) {
    462         max_vs_config = sizeof(sense_resistor_config_56270)/sizeof(i2c_ltc_t);
    463     }
    464 #endif
    465 
    466 #ifdef BCM_MONTEREY_SUPPORT
    467     if (SOC_CONTROL(unit)->board_type == 0xAA) {
    468         sense_resistor_config  = sense_resistor_config_56670 ;
    469         max_vs_config = sizeof(sense_resistor_config_56670)/sizeof(i2c_ltc_t);
    470     }
    471 #endif
    472 #if defined(BCM_TOMAHAWK2_SUPPORT)
    473     if ((SOC_CONTROL(unit)->board_type == 0x9D) ||
    474         (SOC_CONTROL(unit)->board_type == 0xA3) ||
    475         (SOC_CONTROL(unit)->board_type == 0x9F) ||
    476         (SOC_CONTROL(unit)->board_type == 0x9E)) {
    477         max_vs_config = sizeof(sense_resistor_config_56970)/sizeof(i2c_ltc_t);
    478     }
    479 #endif
    480 
    481 #if defined(BCM_TRIDENT3_SUPPORT)
    482     if ((SOC_CONTROL(unit)->board_type == 0xA4) ||
    483         (SOC_CONTROL(unit)->board_type == 0xA5) ||
    484         (SOC_CONTROL(unit)->board_type == 0xA6) ||
    485         (SOC_CONTROL(unit)->board_type == 0xA7)) {
    486         max_vs_config = sizeof(sense_resistor_config_56870)/sizeof(i2c_ltc_t);
    487     }
    488 #endif
    489 
    490 #if defined(BCM_MAVERICK2_SUPPORT)
    491     if ((SOC_CONTROL(unit)->board_type == 0xA6) ||
    492         (SOC_CONTROL(unit)->board_type == 0xB5)) {
    493         max_vs_config = sizeof(sense_resistor_config_56870)/sizeof(i2c_ltc_t);
    494     }
    495 #endif
    496 
    497 #if defined(BCM_TOMAHAWK3_SUPPORT)
    498     if ((SOC_CONTROL(unit)->board_type == 0xAC) || (SOC_CONTROL(unit)->board_type == 0xDE) || 
    499         (SOC_CONTROL(unit)->board_type == 0xB1) || (SOC_CONTROL(unit)->board_type == 0xAD) || 
    500         (SOC_CONTROL(unit)->board_type == 0xAF)) {
    501         max_vs_config = sizeof(sense_resistor_config_56980)/sizeof(i2c_ltc_t);
    502     }
    503 #endif
    504 
    505 #if defined(BCM_HELIX5_SUPPORT)
    506     if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    507         (SOC_CONTROL(unit)->board_type == 0xB6)) {
    508         sense_resistor_config  = sense_resistor_config_56370 ;
    509         max_vs_config = sizeof(sense_resistor_config_56370)/sizeof(i2c_ltc_t);
    510     }
    511 #endif
    512     
    513 
    514     for(i=0;i<max_vs_config;i++) {
    515          /*
    516           * COVERITY
    517           *
    518           * The sense_resistor_config is never overrun. It is guarded by a
    519           * device specific board-id and device type.
    520           */
    521          /* coverity[overrun-local : FALSE] */
    522          if (sal_strcmp(DEV_DAC_PARAMS(dev)[len].name, 
    523                         sense_resistor_config[i].function) == 0) {
    524              break;
    525          }
    526     }
    527     if (i == max_vs_config) {
    528         LOG_CLI((BSL_META_U(unit, "Error: failed to find sense resistor "
    529                     "for VDD_%s in  LTC 2974 device.\n"), 
    530                     DEV_DAC_PARAMS(dev)[len].name));
    531          return SOC_E_NOT_FOUND;
    532     }
    533     if (sense_resistor_config[i].flag == 0) {
    534         ch=sense_resistor_config[i].ch;
    535         SOC_IF_ERROR_RETURN
    536             (ltc2974_check_page(unit, devno, ch));
    537         data = DEV_DAC_PARAMS(dev)[len].dac_max_hwval;
    538         dac=(uint16) L16_RANGE_UPPER(data, 10000);
    539         SOC_IF_ERROR_RETURN
    540             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_MAX, (void *)&dac, 2));
    541         dac=(uint16) L16_RANGE_UPPER(data, 7000);
    542         SOC_IF_ERROR_RETURN
    543             (ltc2974_wait_for_not_busy(unit, devno));
    544         SOC_IF_ERROR_RETURN
    545             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_OV_FAULT_LIMIT, 
    546                             (void *)&dac, 2));
    547         dac=(uint16) L16_RANGE_UPPER(data, 5000);
    548         SOC_IF_ERROR_RETURN
    549             (ltc2974_wait_for_not_busy(unit, devno));
    550         SOC_IF_ERROR_RETURN
    551             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_OV_WARN_LIMIT, 
    552                             (void *)&dac, 2));
    553         dac=(uint16) L16_RANGE_UPPER(data, 2000);
    554         SOC_IF_ERROR_RETURN
    555             (ltc2974_wait_for_not_busy(unit, devno));
    556         SOC_IF_ERROR_RETURN
    557             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_MARGIN_HIGH, 
    558                             (void *)&dac, 2));
    559 
    560         data=DEV_DAC_PARAMS(dev)[len].dac_min_hwval;
    561         SOC_IF_ERROR_RETURN
    562             (ltc2974_wait_for_not_busy(unit, devno));
    563 
    564         dac=(uint16) L16_RANGE_LOWER(data, 5000);
    565         SOC_IF_ERROR_RETURN
    566             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_UV_FAULT_LIMIT, 
    567                             (void *)&dac, 2));
    568 
    569         if((sal_strcmp("ltc2974", sense_resistor_config[i].devname) == 0) || 
    570                 (sal_strcmp(I2C_LTM4676_43, sense_resistor_config[i].devname) == 0)){
    571             SOC_IF_ERROR_RETURN
    572                 (ltc2974_write(unit, devno, PMBUS_CMD_POWER_GOOD_ON, 
    573                                 (void *)&dac, 2));
    574 
    575             dac=(uint16) L16_RANGE_LOWER(data, 7000);
    576             SOC_IF_ERROR_RETURN
    577                 (ltc2974_write(unit, devno, PMBUS_CMD_POWER_GOOD_OFF, 
    578                                 (void *)&dac, 2));
    579         }
    580         dac=(uint16) L16_RANGE_LOWER(data, 2000);
    581         SOC_IF_ERROR_RETURN
    582             (ltc2974_wait_for_not_busy(unit, devno));
    583         SOC_IF_ERROR_RETURN
    584             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_UV_WARN_LIMIT, 
    585                             (void *)&dac, 2));
    586 
    587         dac=(uint16) L16_RANGE_LOWER(data, 1000);
    588         SOC_IF_ERROR_RETURN
    589             ( ltc2974_wait_for_not_busy(unit, devno));
    590         SOC_IF_ERROR_RETURN
    591             (ltc2974_write(unit, devno, PMBUS_CMD_VOUT_MARGIN_LOW, 
    592                             (void *)&dac, 2));
    593 
    594 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) \
    595            || defined(BCM_MONTEREY_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    596         if ((SOC_CONTROL(unit)->board_type == 0x9D) ||
    597             (SOC_CONTROL(unit)->board_type == 0xA3) ||
    598             (SOC_CONTROL(unit)->board_type == 0x9F) ||
    599             (SOC_CONTROL(unit)->board_type == 0x9E) ||
    600             (SOC_CONTROL(unit)->board_type == 0xA4) ||
    601             (SOC_CONTROL(unit)->board_type == 0xA5) ||
    602             (SOC_CONTROL(unit)->board_type == 0xA6) ||
    603             (SOC_CONTROL(unit)->board_type == 0xAA) ||
    604             (SOC_CONTROL(unit)->board_type == 0xA7) ||
    605             (SOC_CONTROL(unit)->board_type == 0xB1) ||
    606             (SOC_CONTROL(unit)->board_type == 0xAD) ||
    607             (SOC_CONTROL(unit)->board_type == 0xAF) ||
    608             (SOC_CONTROL(unit)->board_type == 0xDE) ||
    609             (SOC_CONTROL(unit)->board_type == 0xAC) ||
    610             (SOC_CONTROL(unit)->board_type == 0xB0) ||
    611             (SOC_CONTROL(unit)->board_type == 0xB3) ||
    612             (SOC_CONTROL(unit)->board_type == 0xB6)) {
    613             dac = sense_resistor_config[i].res_value;
    614         } else
    615 #endif
    616         {
    617             rv=ltc2974_float_to_L11(sense_resistor_config[i].res_value, &dac);
    618         }
    619             SOC_IF_ERROR_RETURN
    620                 (ltc2974_write(unit, devno,
    621                                 PMBUS_CMD_IOUT_CAL_GAIN, (void *)&dac, 2));
    622             sal_udelay(500);
    623 
    624        /* Device Configured */
    625         sense_resistor_config[i].flag=1;
    626 
    627     }
    628     return rv;
    629 }
    630 
    631 /*
    632  * NOTE NOTE NOTE:
    633  * All tables (dac_calibrate_t) passed to the ioctl() have size > 1
    634  * and the index is always within this range.
    635  */
    636 STATIC int
    637 ltc2974_ioctl(int unit, int devno, int opcode,
    638               void* data, int len)
    639 {
    640     int rv = SOC_E_NONE;
    641 #ifdef COMPILER_HAS_DOUBLE
    642     double fval;
    643 #else
    644     int fval;
    645 #endif
    646     uint16 dac;
    647     uint32 datalen = 2;
    648     uint8 data8;
    649     unsigned short voltage;
    650     dac_calibrate_t* params = NULL;
    651     int i, ch;
    652     int max_vs_config = MAX_VS_CONFIG;
    653     i2c_device_t *dev = soc_i2c_device(unit, devno);
    654     /* Using mutex lock to ensure thread-safe for ioctl operations */
    655     sal_mutex_take(ioctl_lock, sal_mutex_FOREVER);
    656 
    657      /* length field is actually used as an index into the dac_params table*/
    658      switch (opcode) {
    659          case I2C_LTC_IOC_READ_VOUT:
    660              if ((rv=ltc2974_check_page(unit, devno, len)) < 0) {
    661                  cli_out("Error: failed to set page %d in LTC2974 device.\n", len);
    662                  break;
    663              }
    664              if ((rv=ltc2974_write(unit, devno,
    665                              PMBUS_CMD_CLEAR_FAULTS,(void *) &data8, 0)) < 0) {
    666                  cli_out("Error: Failed to clear the faults of LTC2974 device.\n");
    667                  break;
    668              }
    669              if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    670                  cli_out("Error: LTC2974 device is busy.\n");
    671                  break;
    672              }
    673 
    674             /* Setting Fault response to zero to prevent shut-down of device */
    675              data8 =0x00;
    676              if ((rv=ltc2974_write(unit, devno,
    677                              PMBUS_CMD_VOUT_OV_FAULT_RES, &data8, 1)) < 0) {
    678                  cli_out("Error: failed to set OV fault response of LTC2974.\n");
    679                  break;
    680              }
    681              if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    682                  cli_out("Error: LTC2974 device is busy.\n");
    683                  break;
    684              }
    685 
    686 	     if ((SOC_CONTROL(unit)->board_type != 0x98) && (SOC_CONTROL(unit)->board_type != 0xAA) &&
    687                  (SOC_CONTROL(unit)->board_type != 0xAC) && (SOC_CONTROL(unit)->board_type != 0xDE) && 
    688                  (SOC_CONTROL(unit)->board_type != 0xB1) && (SOC_CONTROL(unit)->board_type != 0xAD) && 
    689                  (SOC_CONTROL(unit)->board_type != 0xAF) && (SOC_CONTROL(unit)->board_type != 0xB0) &&
    690                  (SOC_CONTROL(unit)->board_type != 0xB3) && (SOC_CONTROL(unit)->board_type != 0xB6)) {
    691                  /* Switching on LTC2974 device */
    692                  data8 =0x40;
    693                  if ((rv=ltc2974_write(unit, devno, PMBUS_CMD_OPERATION, &data8, 1)) < 0) {
    694                      cli_out("Error: failed to set operation register of LTC2974 device.\n");
    695                      break;
    696                  }
    697                  if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    698                      cli_out("Error: LTC2974 Device is busy.\n");
    699                      break;
    700                  }
    701 	     }
    702              data8 =0x0A;
    703 #if  defined(BCM_METROLITE_SUPPORT) || defined(BCM_MONTEREY_SUPPORT) || defined(BCM_HELIX5_SUPPORT)
    704              if ((SOC_CONTROL(unit)->board_type == 0x98)  || (SOC_CONTROL(unit)->board_type == 0xAA) ||
    705                   (SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    706                   (SOC_CONTROL(unit)->board_type == 0xB6)) {
    707                  data8 =0x1E;
    708              }
    709 #endif
    710              if ((rv=ltc2974_write(unit, devno, PMBUS_CMD_ON_OFF_CONFIG, &data8, 1)) < 0) {
    711                  cli_out("Error: failed to set CONFIG register of LTC2974 device.\n");
    712                  break;
    713              }
    714              if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    715                  cli_out("Error: Device LTC2974 is busy.\n");
    716                  break;
    717              }
    718              datalen=2;
    719              if ((rv=ltc2974_read(unit,devno, PMBUS_CMD_READ_VOUT, (void *)&dac, &datalen)) < 0) {
    720                  cli_out("Error: Failed to read VOUT of LTC2974 Device.\n");
    721                  break;
    722              }
    723              fval=dac;
    724 #ifdef COMPILER_HAS_DOUBLE
    725              fval=L16_TO_V(fval );
    726              *(double *)data=fval;
    727 #else
    728              fval=L16_TO_UV(fval);
    729              *(int *)data=(fval);
    730 #endif
    731              ((i2c_adc_t*)data)->nsamples = 1;
    732              ((i2c_adc_t*)data)->max = fval;
    733              ((i2c_adc_t*)data)->min = fval;
    734              ((i2c_adc_t*)data)->delta = 0;
    735              break;
    736 
    737          case I2C_LTC_IOC_READ_IOUT:
    738              if ((rv=ltc2974_check_page(unit, devno, len)) < 0) {
    739                  cli_out("Error: failed to set page %d in LTC2974 device.\n", len);
    740                  break;
    741              }
    742              rv=ltc2974_float_to_L11(LTC2974_RES_CONFIG, &dac);
    743 #if defined(BCM_METROLITE_SUPPORT) 
    744              if (SOC_CONTROL(unit)->board_type == 0x98 ) {
    745                  rv=ltc2974_float_to_L11(sense_resistor_config[len].res_value, &dac);
    746              }
    747 #endif
    748 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 
    749              if ((SOC_CONTROL(unit)->board_type == 0x9D) ||
    750                  (SOC_CONTROL(unit)->board_type == 0xA3) ||
    751                  (SOC_CONTROL(unit)->board_type == 0x9F) ||
    752                  (SOC_CONTROL(unit)->board_type == 0x9E) ||
    753                  (SOC_CONTROL(unit)->board_type == 0xA4) ||
    754                  (SOC_CONTROL(unit)->board_type == 0xA5) ||
    755                  (SOC_CONTROL(unit)->board_type == 0xA6) ||
    756                  (SOC_CONTROL(unit)->board_type == 0xA7) ||
    757                  (SOC_CONTROL(unit)->board_type == 0xAA) ||
    758                  (SOC_CONTROL(unit)->board_type == 0xB1) ||
    759                  (SOC_CONTROL(unit)->board_type == 0xAD) ||
    760                  (SOC_CONTROL(unit)->board_type == 0xAF) ||
    761                  (SOC_CONTROL(unit)->board_type == 0xDE) ||
    762                  (SOC_CONTROL(unit)->board_type == 0xAC) ||
    763                  (SOC_CONTROL(unit)->board_type == 0xB0) ||
    764                  (SOC_CONTROL(unit)->board_type == 0xB3) ||
    765                  (SOC_CONTROL(unit)->board_type == 0xB6))
    766              {
    767                  i = len;
    768                  /* For HX5 boards since there are two 2974 devices, adjust the offset
    769                     based on the address */
    770                  if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    771                      (SOC_CONTROL(unit)->board_type == 0xB6)) {
    772                      i = ((dev->saddr == I2C_LTC2974_SADDR63) ? len: (len + 4));
    773                  }
    774                  dac = sense_resistor_config[i].res_value;
    775              }
    776 #endif
    777              if ((rv=ltc2974_write(unit, devno,
    778                              PMBUS_CMD_IOUT_CAL_GAIN, (void *)&dac, 2)) < 0) {
    779                  cli_out("Error: failed to set IOUT_CAL_GAIN of LTC2974 device.\n");
    780                  break;
    781              }
    782              sal_udelay(500);
    783              if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    784                  cli_out("Error: LTC2974 Device is busy.\n");
    785                  break;
    786              }
    787              if ((rv=ltc2974_read(unit, devno,PMBUS_CMD_READ_IOUT, (void *)&dac, &datalen)) < 0) {
    788                  cli_out("Error:Failed to read current in LTC2974 Device.\n");
    789                  break;
    790              }
    791              rv=ltc2974_L11_to_float(dac, &fval);
    792 #ifdef COMPILER_HAS_DOUBLE
    793              *(double *)data=fval*1000;
    794              ((i2c_adc_t*)data)->max = fval*1000;
    795              ((i2c_adc_t*)data)->min = fval*1000;
    796 #else
    797              *(int *)data=fval;
    798              ((i2c_adc_t*)data)->max = fval;
    799              ((i2c_adc_t*)data)->min = fval;
    800 
    801 #endif
    802              ((i2c_adc_t*)data)->nsamples = 1;
    803              ((i2c_adc_t*)data)->delta = 0;
    804 
    805              break;
    806 
    807          case I2C_LTC_IOC_SET_RCONFIG:
    808              /* For future use in different RCONFIGs */
    809 	     /* Initialising sense resistor */
    810              i = len;
    811 
    812 	     /* 
    813 	      * ltc2974_board_resistor_match() as the general matching process
    814 	      * uses this offset index to retreive the board 
    815 	      * based sense_resistor_configuration.
    816 	      */
    817 	     if (ltc2974_board_resistor_match(i) != SOC_E_NOT_FOUND) {
    818 		     if ((i != 14) && (i != 15) && (i != 18) && (i != 22) && (i != 23)) {
    819 			     LOG_CLI((BSL_META_U(unit, "Error: Invalid chip: %d for "
    820 	                                         "LTC2974 device %s .\n"),
    821 					         i, soc_i2c_devname(unit, devno)));
    822 			     rv=SOC_E_NOT_FOUND;
    823 			     break;
    824 		     }
    825 	     }
    826 	     break;
    827 
    828          case I2C_LTC_IOC_READ_POUT:
    829              datalen=2;
    830              if ((rv=ltc2974_check_page(unit, devno, len)) < 0) {
    831                  cli_out("Error: failed to set page %d in LTC2974 device.\n", len);
    832                  break;
    833              }
    834              if ((rv=ltc2974_read(unit,devno, PMBUS_CMD_READ_POUT, (void *)&dac, &datalen)) < 0) {
    835                  cli_out("Error: failed to read power in LTC2974 device.\n");
    836                  break;
    837              }
    838              /* Switching off LTC2974  */
    839 	     if ((SOC_CONTROL(unit)->board_type != 0x98) && (SOC_CONTROL(unit)->board_type != 0xAA) &&
    840                  (SOC_CONTROL(unit)->board_type != 0xAC) && (SOC_CONTROL(unit)->board_type != 0xDE) && 
    841                  (SOC_CONTROL(unit)->board_type != 0xB1) && (SOC_CONTROL(unit)->board_type != 0xAD) && 
    842                  (SOC_CONTROL(unit)->board_type != 0xAF) && (SOC_CONTROL(unit)->board_type != 0xB0) &&
    843                  (SOC_CONTROL(unit)->board_type != 0xB3) && (SOC_CONTROL(unit)->board_type != 0xB6)) {
    844                  data8 = 0x00;
    845                  if ((rv=ltc2974_write(unit, devno, PMBUS_CMD_OPERATION, &data8, 1)) < 0) {
    846                      cli_out("Error: failed to set operation register of LTC2974 device.\n");
    847                      break;
    848                  }
    849                  if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
    850                      cli_out("Error: LTC2974 Device is busy.\n");
    851                      break;
    852                  }
    853              }
    854              rv=ltc2974_L11_to_float(dac, &fval);
    855 #ifdef COMPILER_HAS_DOUBLE
    856              *(double *)data=fval*1000;
    857              ((i2c_adc_t*)data)->max = fval*1000;
    858              ((i2c_adc_t*)data)->min = fval*1000;
    859 #else
    860              *(int *)data=fval;
    861              ((i2c_adc_t*)data)->max = fval;
    862              ((i2c_adc_t*)data)->min = fval;
    863 #endif
    864              ((i2c_adc_t*)data)->nsamples = 1;
    865              ((i2c_adc_t*)data)->delta = 0;
    866              break;
    867 
    868     /* Upload calibration table */
    869     case I2C_DAC_IOC_SET_CALTAB:
    870         params = (dac_calibrate_t*)data;
    871         /* dac_params  initialised */
    872         DEV_DAC_PARAMS(dev) = params;
    873         DEV_DAC_PARAM_LEN(dev) = len;
    874         break;
    875 
    876     case I2C_LTC_IOC_SET_CONFIG:
    877         /* Initialising sense resistor */
    878 #ifdef COMPILER_HAS_DOUBLE
    879         i = *(double *)data;
    880 #else
    881         i = *(int *)data;
    882 #endif
    883         /* 
    884          * ltc2974_board_resistor_match() as the general matching process
    885          * uses this offset index to retreive the board 
    886          * based sense_resistor_configuration.
    887          */
    888         if (ltc2974_board_resistor_match(i) != SOC_E_NOT_FOUND) {
    889             if ((i != 14) && (i != 15) && (i != 18) && (i != 22)) {
    890                 LOG_CLI((BSL_META_U(unit, "Error: Invalid chip: %d for "
    891                         "LTC2974 device %s .\n"),
    892                         i, soc_i2c_devname(unit, devno)));
    893                 rv=SOC_E_NOT_FOUND;
    894                 break;
    895             }
    896         }
    897         if (DEV_DAC_PARAMS(dev)) {
    898             /* Setting max and min values for dac */
    899             rv= ltc2974_setmin_max(unit, devno, len);
    900         }
    901         break;
    902 
    903     case I2C_DAC_IOC_SET_VOUT:
    904         /* Set output voltage */
    905         if (DEV_DAC_PARAMS(dev)) {
    906 #ifdef COMPILER_HAS_DOUBLE
    907             fval = *((double*)data); /* in V */
    908             voltage = V_TO_L16(fval);
    909             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    910                         "unit %d i2c %s: LTC2974 ioctl I2C_DAC_IOC_SET_VOUT: "
    911                         "voltage = %d, len = %d\n"),
    912                         unit, soc_i2c_devname(unit,devno), voltage, len));
    913 #else
    914             fval = *((int *)data); /* in uV */
    915             voltage = UV_TO_L16(fval);
    916             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    917                         "unit %d i2c %s: LTC2974 ioctl I2C_DAC_IOC_SET_VOUT: "
    918                         "voltage = %d, len = %d\n"),
    919                         unit, soc_i2c_devname(unit,devno), voltage, len));
    920 #endif
    921             if ((voltage > DEV_DAC_PARAMS(dev)[len].dac_max_hwval)  ||
    922                     (voltage < DEV_DAC_PARAMS(dev)[len].dac_min_hwval)) {
    923                 LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    924                                 "unit %d i2c %d: LTC2974 given voltage %d "
    925                                 "beyond range for ch %d, %d, %d\n"),
    926                             unit, devno, voltage, len,
    927                             DEV_DAC_PARAMS(dev)[len].dac_max_hwval,
    928                             DEV_DAC_PARAMS(dev)[len].dac_min_hwval));
    929                 rv=SOC_E_PARAM;
    930                 break;
    931             }
    932             if ((rv=ltc2974_check_page(unit, devno, len)) < 0) {
    933                 LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
    934                         "unit: %d LTC2974 device name: %s.\n"),
    935                         len, unit, soc_i2c_devname(unit, devno)));
    936             }
    937             rv = ltc2974_dac_set_ch_voltage(unit, devno, len, voltage);
    938         }
    939        break;
    940 
    941     case I2C_LTC_IOC_SET_VOUT:
    942         /* Finding and  setting page numbers */
    943         if (DEV_DAC_PARAMS(dev)) {
    944 
    945 #ifdef BCM_METROLITE_SUPPORT
    946             if (SOC_CONTROL(unit)->board_type == 0x98) {
    947                 max_vs_config = ML_MAX_VS_CONFIG;
    948             }
    949 #endif
    950 #ifdef BCM_MONTEREY_SUPPORT
    951             if (SOC_CONTROL(unit)->board_type == 0xAA) {
    952                 max_vs_config = MONTEREY_MAX_VS_CONFIG;
    953             }
    954 #endif
    955 
    956 #if defined(BCM_TOMAHAWK2_SUPPORT)
    957             if ((SOC_CONTROL(unit)->board_type == 0x9D) ||
    958                 (SOC_CONTROL(unit)->board_type == 0xA3) ||
    959                 (SOC_CONTROL(unit)->board_type == 0x9F) ||
    960                 (SOC_CONTROL(unit)->board_type == 0x9E)) {
    961                 max_vs_config = TH2_MAX_VS_CONFIG;
    962             }
    963 #endif
    964 
    965 #if defined(BCM_TRIDENT3_SUPPORT)
    966             if ((SOC_CONTROL(unit)->board_type == 0xA4) ||
    967                 (SOC_CONTROL(unit)->board_type == 0xA5) ||
    968                 (SOC_CONTROL(unit)->board_type == 0xA6) ||
    969                 (SOC_CONTROL(unit)->board_type == 0xA7)) {
    970                 max_vs_config = TD3_MAX_VS_CONFIG;
    971             }
    972 #endif
    973 
    974 #if defined(BCM_MAVERICK2_SUPPORT)
    975             if ((SOC_CONTROL(unit)->board_type == 0xA6) ||
    976                 (SOC_CONTROL(unit)->board_type == 0xB5)) {
    977                 max_vs_config = TD3_MAX_VS_CONFIG;
    978             }
    979 #endif
    980 
    981 #if defined(BCM_TOMAHAWK3_SUPPORT)
    982             if ((SOC_CONTROL(unit)->board_type == 0xAC) || (SOC_CONTROL(unit)->board_type == 0xDE) ||
    983                 (SOC_CONTROL(unit)->board_type == 0xB1) || (SOC_CONTROL(unit)->board_type == 0xAD) ||
    984                 (SOC_CONTROL(unit)->board_type == 0xAF)) {
    985                 max_vs_config = TH3_MAX_VS_CONFIG;
    986             }
    987 #endif
    988 
    989 #if defined(BCM_HELIX5_SUPPORT)
    990             if ((SOC_CONTROL(unit)->board_type == 0xB0) || (SOC_CONTROL(unit)->board_type == 0xB3) ||
    991                 (SOC_CONTROL(unit)->board_type == 0xB6)) {
    992                 max_vs_config = HX5_MAX_VS_CONFIG;
    993             }
    994 #endif            
    995             for(i=0;i<max_vs_config;i++) {
    996                 if(sal_strcmp(DEV_DAC_PARAMS(dev)[len].name, 
    997                             sense_resistor_config[i].function) == 0 ) {
    998                     break;
    999                 }
   1000             }
   1001             if (i == max_vs_config) {
   1002                 LOG_CLI((BSL_META_U(unit, "Error: failed to find page number"
   1003                         " for VDD_%s in sense resistor table.\n"), 
   1004                         DEV_DAC_PARAMS(dev)[len].name));
   1005                 rv=SOC_E_NOT_FOUND;
   1006                 break;
   1007             }
   1008             ch = sense_resistor_config[i].ch;
   1009             if ((rv=ltc2974_check_page(unit, devno, ch)) < 0) {
   1010                 LOG_CLI((BSL_META_U(unit, "Error: failed to set page %d in "
   1011                         "LTC2974 device.\n"), ch));
   1012                 break;
   1013             }
   1014             /* Conversion of output voltage */
   1015 #ifdef COMPILER_HAS_DOUBLE
   1016             fval = *((double*)data);
   1017             voltage = (fval*8192);
   1018 #else
   1019             fval = *((int*)data);
   1020             /*2^12 conversion and changing from uVolt */
   1021             voltage = (fval*8192)/1000000;
   1022 #endif
   1023             if ((voltage < DEV_DAC_PARAMS(dev)[len].dac_min_hwval)||
   1024                     (voltage > DEV_DAC_PARAMS(dev)[len].dac_max_hwval)) {
   1025 #ifdef  COMPILER_HAS_DOUBLE
   1026                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1027                           "unit %d i2c %d: LTC2974 given voltage %2.3f V "
   1028                           "beyond range( max=%2.3f V, min=%2.3f V) for "
   1029                           "voltage VDD_%s \n"), unit, devno, 
   1030                           (double)voltage/8192, 
   1031                           (double) DEV_DAC_PARAMS(dev)[len].dac_max_hwval/8192,
   1032                           (double) DEV_DAC_PARAMS(dev)[len].dac_min_hwval/8192, 
   1033                           DEV_DAC_PARAMS(dev)[len].name));
   1034 #else
   1035                 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1036                           "unit %d i2c %d: LTC2974 given voltage %d mV "
   1037                           "beyond range( max=%d mV, min=%d mV ) for " 
   1038                           "voltage  VDD_%s \n"), unit, devno, 
   1039                           voltage*1000/8192, 
   1040                           DEV_DAC_PARAMS(dev)[len].dac_max_hwval*1000/8192,
   1041                           DEV_DAC_PARAMS(dev)[len].dac_min_hwval*1000/8192,
   1042                           DEV_DAC_PARAMS(dev)[len].name));
   1043 
   1044 #endif
   1045                 rv = SOC_E_PARAM;
   1046                 break;
   1047             }
   1048             dac = voltage;
   1049             /* Show what we are doing, for now ... */
   1050             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
   1051                         "unit %d i2c %s: LTC2974 ioctl "
   1052                         "I2C_DAC_IOC_SET_VOUT : voltage = %d, len = %d\n"),
   1053                         unit, soc_i2c_devname(unit,devno), voltage, len));
   1054 #ifdef BCM_METROLITE_SUPPORT
   1055 	    if (SOC_CONTROL(unit)->board_type == 0x98) {
   1056                 rv = ltc2974_dac_set_ch_voltage(unit, devno, len, voltage);
   1057                 /* Store voltage setting in NV memory to retain them after power cycling */
   1058                 rv = ltc2974_write(unit, devno, PMBUS_CMD_STORE_USER_ALL, (void *)&dac, 0);
   1059                 if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
   1060                     cli_out("Error: LTC2974 device is busy.\n");
   1061                     break;
   1062 		}
   1063 	    }else
   1064 #endif
   1065 	    {
   1066 	        rv = ltc2974_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,(void *) &dac, 2);
   1067             }
   1068             /* Keep last value since DAC is write-only device */
   1069             DEV_DAC_PARAMS(dev)[len].dac_last_val = dac;
   1070         }
   1071         break;
   1072 
   1073          default:
   1074               LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1075                  "unit %d i2c %s: ltc2974_ioctl: invalid opcode (%d)\n"),
   1076                  unit, soc_i2c_devname(unit,devno), opcode));
   1077              break;
   1078      }
   1079     sal_mutex_give(ioctl_lock);
   1080     return rv;
   1081 }
   1082 
   1083 STATIC int
   1084 ltc2974_init(int unit, int devno, void* data, int len)
   1085 {
   1086     int rv = SOC_E_NONE;
   1087     i2c_device_t *dev = soc_i2c_device(unit, devno);
   1088     char *devname;
   1089 
   1090     if (dev == NULL) {
   1091         return SOC_E_INTERNAL;
   1092     }
   1093     devname = (char *)soc_i2c_devname(unit, devno);
   1094     if (dev->priv_data == NULL) {
   1095         dev->priv_data = sal_alloc(sizeof(device_data_t), devname);
   1096         if (dev->priv_data == NULL) {
   1097             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1098                         "Fail to allocate private data fo dev %s\n"),
   1099                         soc_i2c_devname(unit, devno)));
   1100             return SOC_E_MEMORY;
   1101         }
   1102     }
   1103 
   1104     if (ioctl_lock == NULL) {
   1105         ioctl_lock = sal_mutex_create("ltc2974_ioctl_lock");
   1106         if (ioctl_lock == NULL) {
   1107             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
   1108                     "Fail to create ltc2974_ioctl_lock\n")));
   1109             rv = SOC_E_MEMORY;
   1110         }
   1111     }
   1112 
   1113     /* Using mutex lock to ensure thread-safe for ioctl operations */
   1114     sal_mutex_take(ioctl_lock, sal_mutex_FOREVER);
   1115     /* bit3 1: control the LTC2974 output through VOUT command
   1116      *      0: control the output via VID input pins which is controlled by
   1117      *         a PCF8574 device
   1118      */
   1119     if ((rv=ltc2974_write(unit, devno,
   1120                     PMBUS_CMD_CLEAR_FAULTS,(void *) &len, 0)) < 0) {
   1121         cli_out("Error: Failed to clear the faults of LTC2974 device.\n");
   1122         sal_mutex_give(ioctl_lock);
   1123         return rv;
   1124     }
   1125     if ((rv=ltc2974_wait_for_not_busy(unit, devno)) < 0) {
   1126         cli_out("Error: LTC2974 Device is busy.\n");
   1127         sal_mutex_give(ioctl_lock);
   1128         return rv;
   1129     }
   1130     soc_i2c_devdesc_set(unit, devno, "LTC2974 Voltage Control");
   1131      LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "ltc2974_init: %s, devNo=0x%x\n"),
   1132              soc_i2c_devname(unit,devno), devno));
   1133 
   1134     sal_mutex_give(ioctl_lock);
   1135     return rv;
   1136 }
   1137 
   1138 /* ltc2974 voltage control Chip Driver callout */
   1139 i2c_driver_t _soc_i2c_ltc2974_driver = {
   1140     0x0, 0x0, /* System assigned bytes */
   1141     LTC2974_DEVICE_TYPE,
   1142     ltc2974_read,
   1143     ltc2974_write,
   1144     ltc2974_ioctl,
   1145     ltc2974_init,
   1146     NULL,
   1147 };