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

adp4000.c (10630B)


      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 ADP4000 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 
     18 #ifdef	COMPILER_HAS_DOUBLE
     19 #define I2C_DATA_T      double
     20 #define I2C_DATA_F      "f"
     21 #else
     22 #define I2C_DATA_T      int
     23 #define I2C_DATA_F      "d"
     24 #endif
     25 
     26 /* Calibration table in effect */
     27 static dac_calibrate_t* dac_params;
     28 static int dac_param_len;
     29 
     30 STATIC int
     31 adp4000_read(int unit, int devno,
     32 	  uint16 addr, uint8* data, uint32* len)
     33 {
     34     
     35     int rv = SOC_E_NONE;
     36     uint8 saddr = soc_i2c_addr(unit, devno);
     37 
     38     if (!*len) {
     39         return SOC_E_NONE;
     40     }
     41 
     42     /* reads a single byte from a device, from a designated register*/
     43     if (*len == 1) {
     44         rv = soc_i2c_read_byte_data(unit, saddr, addr,data);
     45         soc_i2c_device(unit, devno)->rbyte++;   
     46     } else if (*len == 2) {
     47         rv = soc_i2c_read_word_data(unit, saddr, addr,(uint16 *)data);
     48         soc_i2c_device(unit, devno)->rbyte +=2;   
     49     } else {
     50         /* not supported for now */
     51     }
     52 
     53     return rv;
     54 }
     55 
     56 STATIC int
     57 adp4000_write(int unit, int devno,
     58 	   uint16 addr, uint8* data, uint32 len)
     59 {
     60     int rv = SOC_E_NONE;
     61     uint8 saddr = soc_i2c_addr(unit, devno);
     62 
     63     if (len == 0) {
     64         /* simply writes command code to device */
     65         rv = soc_i2c_write_byte(unit, saddr, addr);
     66     } else if (len == 1) {
     67         rv = soc_i2c_write_byte_data(unit, saddr, addr,*data);
     68         soc_i2c_device(unit, devno)->tbyte++;   
     69     } else if (len == 2) {
     70         rv = soc_i2c_write_word_data(unit, saddr, addr,
     71              (data[1] << 8) | data[0]);
     72         soc_i2c_device(unit, devno)->tbyte += 2;   
     73     }
     74     return rv;
     75 }
     76 
     77 /*
     78  * NOTE NOTE NOTE:
     79  * All tables (dac_calibrate_t) passed to the ioctl() have size > 1
     80  * and the index is always within this range.
     81  */
     82 
     83 #define ADP4000_SET_SELECT_MIN  0
     84 #define ADP4000_SET_SELECT_MAX  1
     85 #define ADP4000_SET_SELECT_MID  2
     86 
     87 STATIC int
     88 adp4000_setmin_max(int unit, int devno, int set_sel, int idx)
     89 {
     90     uint8 data8;
     91     int rv;
     92 
     93     /* set the default voltage */
     94     switch (set_sel) {
     95     case ADP4000_SET_SELECT_MAX:
     96         data8 = (uint8)(dac_params[idx].dac_max_hwval);
     97         break;
     98     case ADP4000_SET_SELECT_MID:
     99         data8 = (uint8)(dac_params[idx].dac_mid_hwval);
    100         break;
    101     case ADP4000_SET_SELECT_MIN:
    102         data8 = (uint8)(dac_params[idx].dac_min_hwval);
    103         break;
    104     default:
    105         return SOC_E_INTERNAL;
    106     }
    107     rv = adp4000_write(unit, devno, I2C_ADP4000_CMD_VOUT_CMD,
    108                        &data8, 1);
    109     if (SOC_SUCCESS(rv)) {
    110 	/* Keep last value since DAC is write-only device */
    111         dac_params[idx].dac_last_val = data8;
    112     }
    113     return rv;
    114 }
    115 
    116 #define ADP4000_SETMAX(unit,devno, idx) \
    117    adp4000_setmin_max(unit, devno, ADP4000_SET_SELECT_MAX, idx)
    118 #define ADP4000_SETMIN(unit,devno, idx) \
    119    adp4000_setmin_max(unit, devno, ADP4000_SET_SELECT_MIN, idx)
    120 #define ADP4000_SETMID(unit,devno, idx) \
    121    adp4000_setmin_max(unit, devno, ADP4000_SET_SELECT_MID, idx)
    122 
    123 
    124 STATIC int
    125 adp4000_ioctl(int unit, int devno,
    126 	   int opcode, void* data, int len)
    127 {
    128     int rv = SOC_E_NONE;
    129     I2C_DATA_T fval,tmp;
    130     uint8 dac;
    131     dac_calibrate_t* params = NULL;
    132 
    133     /* length field is actually used as an index into the dac_params table*/
    134     if( !data || ( (dac_params != NULL) && (len > dac_param_len)))
    135 	return SOC_E_PARAM;
    136 
    137     switch ( opcode ){
    138 
    139 	/* Upload calibration table */
    140     case I2C_DAC_IOC_SET_CALTAB:
    141 	params = (dac_calibrate_t*)data;
    142 	dac_params = params;
    143 	dac_param_len = len;
    144 	break;
    145 
    146     case I2C_DAC_IOC_SETDAC_MIN:
    147 	/* Set MIN voltage */
    148 	rv = ADP4000_SETMIN(unit, devno, len);
    149 	break;
    150 
    151     case I2C_DAC_IOC_SETDAC_MAX:
    152 	/* Set MAX voltage */
    153 	rv = ADP4000_SETMAX(unit, devno, len);
    154 	break;
    155 
    156     case I2C_DAC_IOC_SETDAC_MID:
    157 	/* Set mid-range voltage */
    158 	rv = ADP4000_SETMID(unit, devno, len);
    159 	break;
    160 
    161     case I2C_DAC_IOC_CALIBRATE_MAX:
    162 	/* Set MAX output value (from ADC) */
    163 	fval = *((I2C_DATA_T*)data);
    164         if (dac_params) {
    165             dac_params[len].max = fval;
    166         }
    167 	break;
    168 
    169     case I2C_DAC_IOC_CALIBRATE_MIN:
    170 	/* Set MIN output value (from ADC) */
    171 	fval = *((I2C_DATA_T*)data);
    172         if (dac_params) {
    173             dac_params[len].min = fval;
    174         }
    175 	break;
    176 
    177     case I2C_DAC_IOC_CALIBRATE_STEP:
    178 	/* Calibrate stepsize */
    179     if (dac_params) {
    180         dac_params[len].step =
    181             (dac_params[len].use_max ? -1 : 1) *
    182             (dac_params[len].max - dac_params[len].min) / 
    183             (dac_params[len].dac_max_hwval - dac_params[len].dac_min_hwval);
    184         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    185                     (BSL_META_U(unit,
    186                                 "unit %d i2c %s: ADP4000 calibration on function %s:"
    187                                 "(max=%"I2C_DATA_F",min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    188                      unit, soc_i2c_devname(unit,devno),
    189                      dac_params[len].name,
    190                      dac_params[len].max,
    191                      dac_params[len].min,
    192                      dac_params[len].step));
    193     }
    194 	break;
    195 
    196     case I2C_DAC_IOC_SET_VOUT:
    197 	/* Set output voltage */
    198 	fval = *((I2C_DATA_T*)data);
    199     if (dac_params) {
    200         if ((fval < dac_params[len].min)||(fval > dac_params[len].max)){
    201             LOG_VERBOSE(BSL_LS_SOC_COMMON,
    202                         (BSL_META_U(unit,
    203                                     "unit %d i2c %s: calibration/range error :"
    204                                     "requested=%"I2C_DATA_F" (max=%"I2C_DATA_F","
    205                                     "min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    206                          unit, soc_i2c_devname(unit,devno),
    207                          fval, dac_params[len].max,
    208                          dac_params[len].min,
    209                          dac_params[len].step));
    210             return SOC_E_PARAM;
    211         }
    212         /*
    213          * Core (A,B,PHY) : DACVAL  = VMax - VReq / Step
    214          * TurboRef: DACVAL = VReq - VMin / Step
    215          */
    216         if(dac_params[len].use_max)  {
    217             tmp = ((dac_params[len].max - fval) / dac_params[len].step);
    218             tmp += dac_params[len].dac_max_hwval;
    219         } else {
    220             tmp = ((fval - dac_params[len].min) / dac_params[len].step);
    221             tmp += dac_params[len].dac_min_hwval;
    222         }
    223         dac = (uint8)tmp;
    224 
    225         /* Show what we are doing, for now ... */
    226         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    227                     (BSL_META_U(unit,
    228                                 "unit %d i2c %s: Set V_%s:"
    229                                 "request=%"I2C_DATA_F" dac=0x%x (max=%"I2C_DATA_F","
    230                                 "min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    231                      unit, soc_i2c_devname(unit, devno),
    232                      dac_params[len].name,
    233                      fval,
    234                      dac,
    235                      dac_params[len].max,
    236                      dac_params[len].min,
    237                      dac_params[len].step));
    238         rv = adp4000_write(unit, devno, I2C_ADP4000_CMD_VOUT_CMD, &dac, 1);
    239         /* Keep last value since DAC is write-only device */
    240         dac_params[len].dac_last_val = dac;
    241     }
    242 	break;
    243 
    244     default:
    245 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    246                     (BSL_META_U(unit,
    247                                 "unit %d i2c %s: adp4000_ioctl: invalid opcode (%d)\n"),
    248                      unit, soc_i2c_devname(unit, devno), opcode));
    249 	break;
    250     }
    251 
    252     return rv;
    253 }
    254 
    255 STATIC int
    256 adp4000_init(int unit, int devno,
    257 	  void* data, int len)
    258 {
    259     uint8 data8;
    260     uint32 datalen = 0;
    261     char *bbv_src = NULL;
    262     /* reset the device */
    263     data8 = 1 << 1;
    264     SOC_IF_ERROR_RETURN
    265         (adp4000_write(unit,devno,I2C_ADP4000_CMD_RESET,&data8, 1));
    266 
    267     /* clear all faults */
    268     /* coverity[callee_ptr_arith: FALSE] */
    269     SOC_IF_ERROR_RETURN
    270         (adp4000_write(unit,devno,I2C_ADP4000_CMD_CLEAR_FAULTS,&data8, 0));
    271 
    272     /* enable operation commands over the PMBus */
    273     datalen = 1;
    274     SOC_IF_ERROR_RETURN
    275         (adp4000_read(unit, devno, I2C_ADP4000_CMD_ON_OFF_CONFIG,&data8,
    276                       &datalen));
    277     data8 |= 0xf;
    278     SOC_IF_ERROR_RETURN
    279         (adp4000_write(unit,devno,I2C_ADP4000_CMD_ON_OFF_CONFIG,&data8, 1));
    280 
    281     /* set the default voltage */
    282     bbv_src = soc_property_get_str(unit, "bb_voltage_source");
    283     if (bbv_src && !sal_strcasecmp("core", bbv_src)) {
    284         data8 = (uint8)soc_property_get(unit, "bb_voltage_mid", ADP4000_MID_DACVAL);
    285     } else {
    286         data8 = ADP4000_MID_DACVAL;
    287     }
    288     SOC_IF_ERROR_RETURN
    289         (adp4000_write(unit,devno,I2C_ADP4000_CMD_VOUT_CMD,&data8, 1));
    290 
    291 
    292     /* bit3 1: control the ADP4000 output through VOUT command
    293     *      0: control the output via VID input pins which is controlled by
    294     *         a PCF8574 device
    295     */
    296 
    297     if (soc_property_get(unit, "voltage_control", 1)) {
    298         datalen = 1;
    299         SOC_IF_ERROR_RETURN
    300            (adp4000_read(unit,devno,I2C_ADP4000_CMD_CONFIG_1A,&data8,&datalen));
    301         data8 |= 1 << 3;
    302         SOC_IF_ERROR_RETURN
    303            (adp4000_write(unit,devno,I2C_ADP4000_CMD_CONFIG_1A,&data8, 1));
    304         datalen = 1;
    305         SOC_IF_ERROR_RETURN
    306            (adp4000_read(unit,devno,I2C_ADP4000_CMD_CONFIG_1B,&data8,&datalen));
    307         data8 |= 1 << 3;
    308         SOC_IF_ERROR_RETURN
    309            (adp4000_write(unit,devno,I2C_ADP4000_CMD_CONFIG_1B,&data8, 1));
    310     } else {
    311         datalen = 1;
    312         SOC_IF_ERROR_RETURN
    313            (adp4000_read(unit,devno,I2C_ADP4000_CMD_CONFIG_1A,&data8,&datalen));
    314         data8 &= ~(1 << 3);
    315         SOC_IF_ERROR_RETURN
    316            (adp4000_write(unit,devno,I2C_ADP4000_CMD_CONFIG_1A,&data8, 1));
    317         datalen = 1;
    318         SOC_IF_ERROR_RETURN
    319            (adp4000_read(unit,devno,I2C_ADP4000_CMD_CONFIG_1B,&data8,&datalen));
    320         data8 &= ~(1 << 3);
    321         SOC_IF_ERROR_RETURN
    322            (adp4000_write(unit,devno,I2C_ADP4000_CMD_CONFIG_1B,&data8, 1));
    323     }
    324 
    325     soc_i2c_devdesc_set(unit, devno, "ADP4000 Voltage Control");
    326 
    327     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    328                 (BSL_META_U(unit,
    329                             "adp4000_init: %s, devNo=0x%x\n"),
    330                  soc_i2c_devname(unit, devno), devno));
    331     return SOC_E_NONE;
    332 }
    333 
    334 
    335 /* adp4000 voltage control Chip Driver callout */
    336 i2c_driver_t _soc_i2c_adp4000_driver = {
    337     0x0, 0x0, /* System assigned bytes */
    338     ADP4000_DEVICE_TYPE,
    339     adp4000_read,
    340     adp4000_write,
    341     adp4000_ioctl,
    342     adp4000_init,
    343     NULL,
    344 };
    345