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

pmbus.c (17854B)


      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 pmbus 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 #define POWER(exponent, input_val)                          \
     27     exponent < 0 ?                                          \
     28     (int)((int) (input_val) << (exponent*(-1))):            \
     29     (int)((int) (input_val*1000000) >> exponent)/1000000
     30 
     31 typedef struct device_data_s {
     32     sal_mutex_t lock;               /* mutex lock for device operation */
     33     int pmbus_io_flags;             /* pmbus io ctrl support flag */
     34 #define PMBUS_VID    0x20
     35     int dac_vout_mode;              /* vout_command mode */
     36     dac_calibrate_t *dac_params;    /* dac params for each device channel */
     37     int dac_param_len;              /* number of dac params, for multi-channel device */
     38 } device_data_t;
     39 
     40 #define DEV_DAC_VOUTMODE(dev) \
     41     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_vout_mode)
     42 #define DEV_DAC_PARAMS(dev) \
     43     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_params)
     44 #define DEV_DAC_PARAM_LEN(dev) \
     45     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_param_len)
     46 
     47 #define DEV_CHECK_RETURN(dev) \
     48 { \
     49     if ((dev) == NULL) { \
     50         return SOC_E_INTERNAL; \
     51     } \
     52 }
     53 
     54 #define DEV_PRIVDATA_CHECK_RETURN(dev) \
     55 { \
     56     DEV_CHECK_RETURN(dev) \
     57     if ((dev)->priv_data == NULL) { \
     58         return SOC_E_INTERNAL; \
     59     } \
     60 }
     61 
     62 /*
     63  * Convert a floating point value into a
     64  * LinearFloat5_11 formatted word
     65  */
     66 STATIC int
     67 #ifdef  COMPILER_HAS_DOUBLE
     68 pmbus_float_to_L11(double input_val, uint16* data)
     69 #else
     70 pmbus_float_to_L11(int input_val, uint16* data)
     71 #endif
     72 {
     73     uint16 uExponent, uMantissa;
     74     /* set exponent to -16 */
     75     int16 exponent = -16;
     76     /* extract mantissa from input value */
     77     int mantissa = POWER(exponent, input_val);
     78 
     79     /* Search for an exponent that produces
     80      * a valid 11-bit mantissa */
     81     do
     82     {
     83         if((mantissa >= -1024) && (mantissa <= +1023))
     84         {
     85             break; /* stop if mantissa valid */
     86         }
     87         exponent++;
     88         mantissa = POWER(exponent, input_val);
     89     } while (exponent < +15);
     90 
     91     /* Format the exponent of the L11 */
     92     uExponent = exponent << 11;
     93     /* Format the mantissa of the L11 */
     94     uMantissa = mantissa & 0x07FF;
     95     /* Compute value as exponent | mantissa */
     96     *(data) = uExponent | uMantissa;
     97     return SOC_E_NONE;
     98 }
     99 
    100 /*
    101  * Convert a LinearFloat5_11 formatted word
    102  * into a floating point value
    103  */
    104 STATIC int
    105 pmbus_L11_to_float(uint16 input_val, void *data)
    106 {
    107     /* extract exponent as MS 5 bits */
    108     int8 exponent = input_val >> 11;
    109     /* extract mantissa as LS 11 bits */
    110     int16 mantissa = input_val & 0x7ff;
    111     /* sign extend exponent from 5 to 8 bits */
    112     if( exponent > 0x0F ) exponent |= 0xE0;
    113     /* sign extend mantissa from 11 to 16 bits */
    114     if( mantissa > 0x03FF ) mantissa |= 0xF800;
    115 #ifdef  COMPILER_HAS_DOUBLE
    116     /* compute value as mantissa * 2^(exponent) */
    117     *(double *)data= exponent < 0 ?
    118                       (double) ((mantissa*1000000) >>
    119                                 (exponent*(-1)))/1000000:
    120                       (double) (mantissa << exponent);
    121 #else
    122     *(int *)data= exponent < 0 ?
    123                    (((mantissa)*1000000) >> (exponent*(-1))):
    124                    ((mantissa) << exponent)*100000;
    125 #endif
    126     return SOC_E_NONE;
    127 }
    128 
    129 STATIC int
    130 pmbus_read(int unit, int devno, uint16 addr, uint8* data, uint32* len)
    131 {
    132 
    133     int rv = SOC_E_NONE;
    134     uint8 saddr = soc_i2c_addr(unit, devno);
    135 
    136     if (!*len) {
    137         return SOC_E_NONE;
    138     }
    139 
    140     /* reads a single byte from a device, from a designated register*/
    141     if (*len == 1) {
    142         rv = soc_i2c_read_byte_data(unit, saddr, addr,data);
    143         soc_i2c_device(unit, devno)->rbyte++;
    144     } else if (*len == 2) {
    145         rv = soc_i2c_read_word_data(unit, saddr, addr,(uint16 *)data);
    146         soc_i2c_device(unit, devno)->rbyte +=2;
    147     } else {
    148         /* not supported for now */
    149     }
    150 
    151     return rv;
    152 }
    153 
    154 STATIC int
    155 pmbus_write(int unit, int devno, uint16 addr, uint8* data, uint32 len)
    156 {
    157     int rv = SOC_E_NONE;
    158     uint8 saddr = soc_i2c_addr(unit, devno);
    159 
    160     if (len == 0) {
    161         /* simply writes command code to device */
    162         rv = soc_i2c_write_byte(unit, saddr, addr);
    163     } else if (len == 1) {
    164         rv = soc_i2c_write_byte_data(unit, saddr, addr,*data);
    165         soc_i2c_device(unit, devno)->tbyte++;
    166     } else if (len == 2) {
    167         rv = soc_i2c_write_word_data(unit, saddr, addr, *(uint16 *)data);
    168         soc_i2c_device(unit, devno)->tbyte += 2;
    169     }
    170     return rv;
    171 }
    172 
    173 STATIC int
    174 pmbus_ioctl(int unit, int devno, int opcode, void* data, int len)
    175 {
    176     int rv = SOC_E_NONE;
    177     I2C_DATA_T fval = 0,tmp;
    178     uint8  data8;
    179     uint16 dac;
    180     uint16 time_ms;
    181     uint32 datalen = 0;
    182     dac_calibrate_t* dac_params = NULL;
    183     i2c_device_t *dev = soc_i2c_device(unit, devno);
    184 
    185     DEV_PRIVDATA_CHECK_RETURN(dev);
    186 
    187     dac_params = DEV_DAC_PARAMS(dev);
    188     /* length field is actually used as an index into the dac_params table*/
    189     if((!data) || ((dac_params != NULL) && (len > DEV_DAC_PARAM_LEN(dev)))) {
    190         return SOC_E_PARAM;
    191     }
    192 
    193     switch (opcode){
    194     case PMBUS_IOC_SET_DAC:
    195     /* Set special dac table */
    196     dac_params = (dac_calibrate_t*)data;
    197     DEV_DAC_PARAMS(dev) = dac_params;
    198     DEV_DAC_PARAM_LEN(dev) = len;
    199 
    200     /* Set vout command mode*/
    201     datalen = 1;
    202     if ((rv = pmbus_read(unit, devno, PMBUS_CMD_VOUT_MODE,
    203                          &data8, &datalen)) < 0) {
    204         LOG_ERROR(BSL_LS_SOC_COMMON,
    205                   (BSL_META_U(unit, "Error: failed to read VOUT MODE for %s.\n"),
    206                   soc_i2c_devname(unit, devno)));
    207         break;
    208     }
    209     DEV_DAC_VOUTMODE(dev) = data8;
    210     break;
    211 
    212     case PMBUS_IOC_SET_VOUT:
    213     /* Set output voltage */
    214     fval = *((I2C_DATA_T*)data);
    215     if (dac_params) {
    216         if ((fval < dac_params[len].min)||(fval > dac_params[len].max)){
    217             LOG_VERBOSE(BSL_LS_SOC_COMMON,
    218                         (BSL_META_U(unit,
    219                                     "unit %d i2c %s: calibration/range error :"
    220                                     "requested=%"I2C_DATA_F" (max=%"I2C_DATA_F","
    221                                     "min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    222                          unit, soc_i2c_devname(unit,devno),
    223                          fval, dac_params[len].max,
    224                          dac_params[len].min,
    225                          dac_params[len].step));
    226             return SOC_E_PARAM;
    227         }
    228 
    229         if (DEV_DAC_VOUTMODE(dev) & PMBUS_VID) {
    230             /* VID mode */
    231             if(dac_params[len].use_max)  {
    232                 tmp = ((dac_params[len].max - fval) / dac_params[len].step);
    233                 tmp = dac_params[len].dac_max_hwval - tmp;
    234             } else {
    235                 tmp = ((dac_params[len].max - fval) / dac_params[len].step);
    236                 tmp = dac_params[len].dac_max_hwval + tmp;
    237             }
    238             dac = (uint8)tmp;
    239         } else {
    240             /* Linear mode */
    241             rv = pmbus_float_to_L11(fval, &dac);
    242         }
    243 
    244         /* Show what we are doing, for now ... */
    245         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    246                     (BSL_META_U(unit,
    247                                 "unit %d i2c %s: Set V_%s:"
    248                                 "request=%"I2C_DATA_F" dac=0x%x (max=%"I2C_DATA_F","
    249                                 "min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    250                      unit, soc_i2c_devname(unit, devno),
    251                      dac_params[len].name,
    252                      fval,
    253                      dac,
    254                      dac_params[len].max,
    255                      dac_params[len].min,
    256                      dac_params[len].step));
    257         if ((rv = pmbus_write(unit, devno,
    258                               PMBUS_CMD_VOUT_COMMAND, (uint8 *)&dac, 2)) < 0) {
    259             LOG_ERROR(BSL_LS_SOC_COMMON,
    260                       (BSL_META_U(unit, "Error: failed to set VOUT for %s.\n"),
    261                       soc_i2c_devname(unit, devno)));
    262             break;
    263         }
    264         /* Keep last value since DAC is write-only device */
    265         dac_params[len].dac_last_val = dac;
    266     }
    267     break;
    268 
    269     case PMBUS_IOC_READ_VOUT:
    270     /* Set output voltage */
    271     if (dac_params) {
    272         datalen = 2;
    273         if ((rv = pmbus_read(unit, devno, PMBUS_CMD_READ_VOUT,
    274                              (uint8 *)&dac, &datalen)) < 0) {
    275             LOG_ERROR(BSL_LS_SOC_COMMON,
    276                       (BSL_META_U(unit, "Error: failed to read VOUT for %s.\n"),
    277                       soc_i2c_devname(unit, devno)));
    278             break;
    279         }
    280 
    281         /* Show what we are doing, for now ... */
    282         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    283                     (BSL_META_U(unit,
    284                                 "unit %d i2c %s: Get V_%s:"
    285                                 " dac=0x%x (max=%"I2C_DATA_F","
    286                                 "min=%"I2C_DATA_F",step=%"I2C_DATA_F")\n"),
    287                      unit, soc_i2c_devname(unit, devno),
    288                      dac_params[len].name,
    289                      dac,
    290                      dac_params[len].max,
    291                      dac_params[len].min,
    292                      dac_params[len].step));
    293 
    294         if (DEV_DAC_VOUTMODE(dev) & PMBUS_VID) {
    295             if(dac_params[len].use_max)  {
    296                 tmp = dac_params[len].dac_max_hwval - dac;
    297                 fval = dac_params[len].max - tmp * dac_params[len].step;
    298             } else {
    299                 tmp = dac - dac_params[len].dac_max_hwval;
    300                 fval = dac_params[len].max - tmp * dac_params[len].step;
    301             }
    302         } else {
    303             /* Linear mode */
    304             rv = pmbus_L11_to_float(dac, &fval);
    305         }
    306     }
    307     *((I2C_DATA_T*)data) = fval;
    308     break;
    309 
    310     case PMBUS_IOC_SET_SEQ:
    311     time_ms = *((uint16 *)data);
    312     time_ms &= ((1 << 4) - 1);
    313     if ((rv = pmbus_write(unit, devno, PMBUS_CMD_POWER_ON_DELAY,
    314                           (uint8 *)&time_ms, 2)) < 0) {
    315         LOG_ERROR(BSL_LS_SOC_COMMON,
    316                   (BSL_META_U(unit, "Error: failed to set TON_DELAY for %s.\n"),
    317                   soc_i2c_devname(unit, devno)));
    318         break;
    319     }
    320     break;
    321 
    322     case PMBUS_IOC_READ_SEQ:
    323     datalen = 2;
    324     if ((rv = pmbus_read(unit, devno, PMBUS_CMD_POWER_ON_DELAY,
    325                          (uint8 *)&time_ms, &datalen)) < 0) {
    326         LOG_ERROR(BSL_LS_SOC_COMMON,
    327                   (BSL_META_U(unit, "Error: failed to read TON_DELAY for %s.\n"),
    328                   soc_i2c_devname(unit, devno)));
    329         break;
    330     }
    331     *((uint16 *)data) = time_ms;
    332     break;
    333 
    334     case PMBUS_IOC_READ_IOUT:
    335     datalen = 2;
    336     if ((rv = pmbus_read(unit, devno, PMBUS_CMD_READ_IOUT,
    337                          (uint8 *)&dac, &datalen)) < 0) {
    338         LOG_ERROR(BSL_LS_SOC_COMMON,
    339                   (BSL_META_U(unit, "Error: failed to read current for %s.\n"),
    340                   soc_i2c_devname(unit, devno)));
    341         break;
    342     }
    343     rv = pmbus_L11_to_float(dac, &fval);
    344 #ifdef COMPILER_HAS_DOUBLE
    345      *(double *)data=fval*1000;
    346 #else
    347      *(int *)data=fval;
    348 #endif
    349     break;
    350 
    351     default:
    352     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    353                 (BSL_META_U(unit,
    354                             "unit %d i2c %s: pmbus_ioctl: invalid opcode (%d)\n"),
    355                  unit, soc_i2c_devname(unit, devno), opcode));
    356     break;
    357     }
    358 
    359     return rv;
    360 }
    361 
    362 /* Calibration table in effect */
    363 static dac_calibrate_t
    364 ncp4200_dac_params = {0, "core",
    365                       NCP4200_MAX_VOL, NCP4200_MIN_VOL, NCP4200_DAC_STEP, 0,
    366                       NCP4200_MIN_DACVAL, NCP4200_MAX_DACVAL, NCP4200_MID_DACVAL, 0x0};
    367 
    368 static dac_calibrate_t
    369 ncp81233_dac_params = {0, "core",
    370                        NCP81233_MAX_VOL, NCP81233_MIN_VOL, NCP81233_DAC_STEP, 0,
    371                        NCP81233_MAX_DACVAL, NCP81233_MIN_DACVAL, NCP81233_MID_DACVAL, 0x1};
    372 
    373 STATIC int
    374 pmbus_init(int unit, int devno, void* data, int len)
    375 {
    376     uint8 data8, mfr_id;
    377     uint16 mfr_model;
    378     uint32 datalen = 0;
    379     int rv = SOC_E_NONE, line = __LINE__;
    380     i2c_device_t *dev = soc_i2c_device(unit, devno);
    381     char *devname;
    382 
    383     if (dev == NULL) {
    384         return SOC_E_INTERNAL;
    385     }
    386     devname = (char *)soc_i2c_devname(unit, devno);
    387     if (dev->priv_data == NULL) {
    388         dev->priv_data = sal_alloc(sizeof(device_data_t), devname);
    389         if (dev->priv_data == NULL) {
    390             LOG_ERROR(BSL_LS_SOC_COMMON,
    391                       (BSL_META_U(unit,
    392                                   "Fail to allocate private data fo dev %s\n"),
    393                       soc_i2c_devname(unit, devno)));
    394             rv = SOC_E_MEMORY;
    395             return rv;
    396         }
    397         DEV_DAC_PARAMS(dev) = NULL;
    398         DEV_DAC_PARAM_LEN(dev) = 0;
    399     }
    400 
    401     /* clear all faults */
    402     /* coverity[callee_ptr_arith: FALSE] */
    403     rv = pmbus_write(unit, devno, PMBUS_CMD_CLEAR_FAULTS, &data8, 0);
    404     if (SOC_FAILURE(rv)) {
    405         line = __LINE__;
    406         goto err_return;
    407     }
    408 
    409     /* enable operation commands over the PMBus */
    410     datalen = 1;
    411     rv =pmbus_read(unit, devno, PMBUS_CMD_ON_OFF_CONFIG, &data8, &datalen);
    412     if (SOC_FAILURE(rv)) {
    413         line = __LINE__;
    414         goto err_return;
    415     }
    416 
    417     data8 |= 0xf;
    418     rv = pmbus_write(unit, devno, PMBUS_CMD_ON_OFF_CONFIG, &data8, 1);
    419     if (SOC_FAILURE(rv)) {
    420         line = __LINE__;
    421         goto err_return;
    422     }
    423 
    424     /* get MFR ID and MFR MODEL */
    425     rv = pmbus_read(unit, devno, PMBUS_CMD_MFR_ID, &mfr_id, &datalen);
    426     if (SOC_FAILURE(rv)) {
    427         line = __LINE__;
    428         goto err_return;
    429     }
    430 
    431     datalen = 2;
    432     rv = pmbus_read(unit, devno, PMBUS_CMD_MFR_MODEL, (uint8*)&mfr_model, &datalen);
    433     if (SOC_FAILURE(rv)) {
    434         line = __LINE__;
    435         goto err_return;
    436     }
    437 
    438     /* MFR special init */
    439     if((mfr_id == 0x1) && (mfr_model == 0x2)) {
    440         /* NCP4200 device */
    441         data8 = NCP4200_MID_DACVAL;
    442         rv = pmbus_write(unit, devno, PMBUS_CMD_VOUT_COMMAND, &data8, 1);
    443         if (SOC_FAILURE(rv)) {
    444             line = __LINE__;
    445             goto err_return;
    446         }
    447         if (soc_property_get(unit, "voltage_control", 1)) {
    448             datalen = 1;
    449             rv = pmbus_read(unit, devno, I2C_ADP4000_CMD_CONFIG_1A, &data8, &datalen);
    450             if (SOC_FAILURE(rv)) {
    451                 line = __LINE__;
    452                 goto err_return;
    453             }
    454             data8 |= 1 << 3;
    455             rv = pmbus_write(unit, devno, I2C_ADP4000_CMD_CONFIG_1A, &data8, 1);
    456             if (SOC_FAILURE(rv)) {
    457                 line = __LINE__;
    458                 goto err_return;
    459             }
    460             datalen = 1;
    461             rv = pmbus_read(unit, devno, I2C_ADP4000_CMD_CONFIG_1B, &data8, &datalen);
    462             if (SOC_FAILURE(rv)) {
    463                 line = __LINE__;
    464                 goto err_return;
    465             }
    466             data8 |= 1 << 3;
    467             rv = pmbus_write(unit, devno, I2C_ADP4000_CMD_CONFIG_1B, &data8, 1);
    468             if (SOC_FAILURE(rv)) {
    469                 line = __LINE__;
    470                 goto err_return;
    471             }
    472         } else {
    473             datalen = 1;
    474             rv = pmbus_read(unit, devno, I2C_ADP4000_CMD_CONFIG_1A, &data8, &datalen);
    475             if (SOC_FAILURE(rv)) {
    476                 line = __LINE__;
    477                 goto err_return;
    478             }
    479             data8 &= ~(1 << 3);
    480             rv = pmbus_write(unit, devno, I2C_ADP4000_CMD_CONFIG_1A, &data8, 1);
    481             if (SOC_FAILURE(rv)) {
    482                 line = __LINE__;
    483                 goto err_return;
    484             }
    485             datalen = 1;
    486             rv = pmbus_read(unit, devno, I2C_ADP4000_CMD_CONFIG_1B, &data8, &datalen);
    487             if (SOC_FAILURE(rv)) {
    488                 line = __LINE__;
    489                 goto err_return;
    490             }
    491             data8 &= ~(1 << 3);
    492             rv = pmbus_write(unit, devno, I2C_ADP4000_CMD_CONFIG_1B, &data8, 1);
    493             if (SOC_FAILURE(rv)) {
    494                 line = __LINE__;
    495                 goto err_return;
    496             }
    497         }
    498         rv = pmbus_ioctl(unit, devno, PMBUS_IOC_SET_DAC, &ncp4200_dac_params, 1);
    499         if (SOC_FAILURE(rv)) {
    500             line = __LINE__;
    501             goto err_return;
    502         }
    503     } else if ((mfr_id == 0x1A) && (mfr_model == 0x1233)) {
    504         /* NCP81233 device */
    505         rv = pmbus_ioctl(unit, devno, PMBUS_IOC_SET_DAC, &ncp81233_dac_params, 1);
    506         if (SOC_FAILURE(rv)) {
    507             line = __LINE__;
    508             goto err_return;
    509         }
    510     }
    511 
    512     soc_i2c_devdesc_set(unit, devno, "Pmbus Voltage Control");
    513 
    514     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    515                 (BSL_META_U(unit,
    516                             "pmbus_init: %s, devNo=0x%x\n"),
    517                  soc_i2c_devname(unit, devno), devno));
    518     return rv;
    519 
    520 err_return:
    521     LOG_ERROR(BSL_LS_SOC_COMMON,
    522               (BSL_META_U(unit, "pmbus init error: %s, line = %d\n"),
    523               soc_i2c_devname(unit, devno), line));
    524     sal_free(dev->priv_data);
    525     dev->priv_data = NULL;
    526     return rv;
    527 }
    528 
    529 STATIC int
    530 pmbus_deinit(int unit, int devno)
    531 {
    532     int rv = SOC_E_NONE;
    533     i2c_device_t *dev = soc_i2c_device(unit, devno);
    534 
    535     if (dev != NULL) {
    536         if (dev->priv_data != NULL) {
    537             sal_free(dev->priv_data);
    538             dev->priv_data = NULL;
    539         }
    540     } else {
    541         rv = SOC_E_INTERNAL;
    542     }
    543 
    544     return rv;
    545 }
    546 
    547 /* pmbus voltage control Chip Driver callout */
    548 i2c_driver_t _soc_i2c_pmbus_driver = {
    549     0x0, 0x0, /* System assigned bytes */
    550     PMBUS_DEVICE_TYPE,
    551     pmbus_read,
    552     pmbus_write,
    553     pmbus_ioctl,
    554     pmbus_init,
    555     pmbus_deinit,
    556 };