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

isl68127.c (14482B)


      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 ISL68127 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 /* Divided by 1000 for voltage conversion */
     19 #define L16_TO_V(val)  ((val)*100000/1000/100000)
     20 #define V_TO_L16(val)  ((val)*1000)
     21 #define L16_TO_UV(val) ((val)*100000/1000*10)
     22 #define UV_TO_L16(val) ((val)/10*1000/100000)
     23 
     24 #define L16_RANGE_UPPER(L16, range) ((L16) + (int)(range)*L16/100000)
     25 #define L16_RANGE_LOWER(L16, range) ((L16) - (int)(range)*L16/100000)
     26 
     27 #define MAX_VS_CONFIG    2
     28 
     29 typedef struct device_data_s {
     30     sal_mutex_t lock;   /* mutex lock for device operation */
     31     dac_calibrate_t *dac_params;  /*dac params for each device channel*/
     32     int dac_param_len;
     33     int flags;
     34     i2c_saddr_t rail_saddr;
     35 } device_data_t;
     36 
     37 #define DEV_DAC_PARAMS(dev) \
     38     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_params)
     39 #define DEV_DAC_PARAM_LEN(dev) \
     40     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->dac_param_len)   
     41 #define DEV_FLAGS(dev) \
     42     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->flags)   
     43 #define DEV_RAIL_SADDR(dev) \
     44     (((device_data_t *)(((i2c_device_t *)(dev))->priv_data))->rail_saddr)   
     45 
     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 static sal_mutex_t ioctl_lock = NULL;
     64 
     65 STATIC int
     66 Write1(uint8 saddr, uint8 comm, uint8 arg0)
     67 {
     68 
     69     return soc_i2c_write_byte_data(0, saddr, comm, arg0);
     70 
     71 }
     72 
     73 STATIC int
     74 Write2(uint8 saddr, uint8 comm, uint8 arg0, uint8 arg1)
     75 {
     76     uint16 value = (arg1 << 8) | arg0;
     77 
     78     return soc_i2c_write_word_data(0, saddr, comm, value);
     79 
     80 }
     81 
     82 STATIC int
     83 Write4(uint8 saddr, uint8 comm, uint8 arg0, uint8 arg1, uint8 arg2, uint8 arg3)
     84 {
     85     uint8 buf[4];
     86 
     87     buf[0] = arg0;
     88     buf[1] = arg1;
     89     buf[2] = arg2;
     90     buf[3] = arg3;
     91 
     92     return soc_i2c_multi_write(0, saddr, comm, 4, buf);
     93 
     94 }
     95 
     96 STATIC int
     97 disable_load_line (int unit, int devno) {
     98     int rv;
     99     uint8 saddr;
    100 
    101     saddr = soc_i2c_addr(unit, devno);
    102 
    103     /* Disables load line */
    104     rv = Write2(saddr, 0xf7,0x9b,0xe6);
    105     if (rv < 0) {
    106         return rv;
    107     }
    108     rv = Write4(saddr, 0xf5,0x05,0x86,0,0);
    109     if (rv < 0) {
    110         return rv;
    111     }
    112     rv = Write2(saddr, 0xf7,0x85,0xe6);
    113     if (rv < 0) {
    114         return rv;
    115     }
    116     rv = Write4(saddr, 0xf5,0,0,0,0);
    117     if (rv < 0) {
    118         return rv;
    119     }
    120     rv = Write2(saddr, 0xf7,0xb4,0xe6);
    121     if (rv < 0) {
    122         return rv;
    123     }
    124     rv = Write4(saddr, 0xf5,0,0,0,0);
    125     if (rv < 0) {
    126         return rv;
    127     }
    128     rv = Write2(saddr, 0xf7,0xb2,0xe6);
    129     if (rv < 0) {
    130         return rv;
    131     }
    132     rv = Write4(saddr, 0xf5,0,0,0,0);
    133     if (rv < 0) {
    134         return rv;
    135     }
    136     rv = Write1(saddr, 0x00,0x01);
    137     if (rv < 0) {
    138         return rv;
    139     }
    140     rv = Write2(saddr, 0x28,0,0);
    141     if (rv < 0) {
    142         return rv;
    143     }
    144     rv = Write2(saddr, 0xf7,0xa3,0xe3);
    145     if (rv < 0) {
    146         return rv;
    147     }
    148     rv = Write4(saddr, 0xf5,0,0,0,0);
    149     if (rv < 0) {
    150         return rv;
    151     }
    152     rv = Write2(saddr, 0xe7,0x01,0x0);
    153 
    154     return rv;
    155 }
    156 
    157 
    158 STATIC int
    159 isl68127_read(int unit, int devno, uint16 addr, uint8* data, uint32* len)
    160 {
    161     int rv = SOC_E_NONE;
    162     uint8 saddr;
    163 
    164     saddr = soc_i2c_addr(unit, devno);
    165 
    166     if (*len == 0) {
    167         return SOC_E_NONE;
    168     }
    169     if (*len == 1) {
    170         /* reads a single byte from a device, from a designated register*/
    171         rv = soc_i2c_read_byte_data(unit, saddr, addr,data);
    172         soc_i2c_device(unit, devno)->rbyte++;
    173          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    174                     "unit %d i2c %s: ISL68127_read: "
    175                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    176                     "rv = %d\n"),
    177                     unit, soc_i2c_devname(unit,devno),
    178                     saddr, addr, *data, *len, rv));
    179     } else if (*len == 2) {
    180         /* reads a single word from a device, from a designated register*/
    181         rv = soc_i2c_read_word_data(unit, saddr, addr,(uint16 *)data);
    182         soc_i2c_device(unit, devno)->rbyte +=2;
    183         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    184                     "unit %d i2c %s: ISL68127_read: "
    185                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d, "
    186                     "rv = %d\n"),
    187                     unit, soc_i2c_devname(unit,devno),
    188                     saddr, addr, *(uint16 *)data, *len, rv));
    189     } else {
    190         /* not supported for now */
    191          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    192                     "unit %d i2c %s: ISL68127_read fail: "
    193                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    194                     unit, soc_i2c_devname(unit,devno),
    195                     saddr, addr, *data, *len));
    196     }
    197     return rv;
    198 }
    199 
    200 STATIC int
    201 _isl68127_write(int unit, int devno, uint8 saddr, uint16 addr, uint8* data, uint32 len)
    202 {
    203     int rv = SOC_E_NONE;
    204     unsigned short val;
    205 
    206     if (len == 0) {
    207         /* simply writes command code to device */
    208         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: ISL68127 write: "
    209                     "saddr = 0x%x, addr = 0x%x, len = %d\n"),
    210                     soc_i2c_devname(unit, devno), saddr, addr, len));
    211         rv = soc_i2c_write_byte(unit, saddr, addr);
    212     } else if (len == 1) {
    213         LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: ISL68127 write: "
    214                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    215                     soc_i2c_devname(unit, devno), saddr, addr, *data, len));
    216         rv = soc_i2c_write_byte_data(unit, saddr, addr, *data);
    217         soc_i2c_device(unit, devno)->tbyte++;
    218     } else if (len == 2) {
    219          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "i2c %s: ISL68127 write: "
    220                     "saddr = 0x%x, addr = 0x%x, data = 0x%x, len = %d\n"),
    221                     soc_i2c_devname(unit, devno),
    222                     saddr, addr, *(uint16 *)data, len));
    223         val = *(unsigned short *)data;
    224         rv = soc_i2c_write_word_data(unit, saddr, addr, val);
    225         soc_i2c_device(unit, devno)->tbyte += 2;
    226     }
    227     return rv;
    228 }
    229 
    230 STATIC int
    231 isl68127_write(int unit, int devno, uint16 addr, uint8* data, uint32 len)
    232 {
    233     uint8 saddr;
    234 
    235     saddr = soc_i2c_addr(unit, devno);
    236 
    237     return (_isl68127_write(unit, devno, saddr, addr, data, len));
    238 
    239 }
    240 
    241 STATIC int
    242 isl68127_check_page(int unit, int devno, int ch)
    243 {
    244      int rv;
    245      uint8 page;
    246      uint32 len;
    247 
    248      len = sizeof(char);
    249      rv = isl68127_read(unit, devno, PMBUS_CMD_PAGE, &page, &len);
    250      if (rv != SOC_E_NONE) {
    251          return rv;
    252      }
    253 
    254      if (page != ch) {
    255          page = ch;
    256          LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "ISL68127 %d set page to %d\n"),
    257                      soc_i2c_addr(unit, devno), page));
    258          rv = isl68127_write(unit, devno, PMBUS_CMD_PAGE, &page, sizeof(char));
    259      }
    260      return rv;
    261 }
    262 
    263 /*
    264  * NOTE NOTE NOTE:
    265  * All tables (dac_calibrate_t) passed to the ioctl() have size > 1
    266  * and the index is always within this range.
    267  */
    268 STATIC int
    269 isl68127_ioctl(int unit, int devno, int opcode,
    270               void* data, int len)
    271 {
    272     int rv = SOC_E_NONE;
    273 #ifdef COMPILER_HAS_DOUBLE
    274     double fval;
    275 #else
    276     int fval;
    277 #endif
    278     uint16 dac;
    279     uint32 datalen = 2;
    280     unsigned short voltage;
    281     /* Using mutex lock to ensure thread-safe for ioctl operations */
    282     sal_mutex_take(ioctl_lock, sal_mutex_FOREVER);
    283 
    284      /* length field is actually used as an index into the dac_params table*/
    285      switch (opcode) {
    286          case PMBUS_IOC_READ_VOUT:
    287              if ((rv=isl68127_check_page(unit, devno, len)) < 0) {
    288                  cli_out("Error: failed to set page %d in ISL68127 device.\n", len);
    289                  break;
    290              }
    291              datalen=2;
    292              if ((rv=isl68127_read(unit,devno, PMBUS_CMD_READ_VOUT, (void *)&dac, &datalen)) < 0) {
    293                  cli_out("Error: Failed to read VOUT of ISL68127 Device.\n");
    294                  break;
    295              }
    296              fval=dac;
    297 #ifdef COMPILER_HAS_DOUBLE
    298              if (len == 0) {
    299                  fval=((fval)*120000/1000/100000);
    300              } else {
    301                  fval=L16_TO_V(fval );
    302              }
    303              *(double *)data=fval;
    304 #else
    305              fval=L16_TO_UV(fval);
    306              *(int *)data=(fval);
    307 #endif
    308              break;
    309 
    310          case PMBUS_IOC_READ_IOUT:
    311              if ((rv=isl68127_check_page(unit, devno, len)) < 0) {
    312                  cli_out("Error: failed to set page %d in ISL68127 device.\n", len);
    313                  break;
    314              }
    315              if ((rv=isl68127_read(unit, devno,PMBUS_CMD_READ_IOUT, (void *)&dac, &datalen)) < 0) {
    316                  cli_out("Error:Failed to read current in ISL68127 Device.\n");
    317                  break;
    318              }
    319 #ifdef COMPILER_HAS_DOUBLE
    320              *(double *)data=dac*100; /* (dac/10)*1000 */
    321 #else
    322              *(int *)data=dac;
    323 #endif
    324              break;
    325 
    326          case PMBUS_IOC_READ_POUT:
    327             datalen=2;
    328             if ((rv=isl68127_check_page(unit, devno, len)) < 0) {
    329                 cli_out("Error: failed to set page %d in ISL68127 device.\n", len);
    330                 break;
    331             }
    332 
    333             if ((rv=isl68127_read(unit,devno, PMBUS_CMD_READ_POUT, (void *)&dac, &datalen)) < 0) {
    334                 cli_out("Error: failed to read power in ISL68127 device.\n");
    335                 break;
    336             }
    337 #ifdef COMPILER_HAS_DOUBLE
    338             if (len == 0) {
    339                 *(double *)data=dac*1200;
    340             } else {
    341                 *(double *)data=dac*1000;
    342             }
    343 #else
    344              *(int *)data=dac;
    345 #endif
    346              break;
    347 
    348     case PMBUS_IOC_SET_VOUT:
    349             /* Conversion of output voltage */
    350 #ifdef COMPILER_HAS_DOUBLE
    351             fval = *((double*)data);
    352             voltage = (fval*1000);
    353 #else
    354             fval = *((int*)data);
    355             /*2^12 conversion and changing from uVolt */
    356             voltage = (fval*1000)/1000000;
    357 #endif
    358             dac = voltage;
    359 
    360             /* Show what we are doing, for now ... */
    361             LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    362                         "unit %d i2c %s: ISL68127 ioctl "
    363                         "I2C_DAC_IOC_SET_VOUT : voltage = %d, len = %d\n"),
    364                         unit, soc_i2c_devname(unit,devno), voltage, len));
    365 
    366 	        rv = isl68127_write(unit, devno, PMBUS_CMD_VOUT_COMMAND,(void *) &dac, 2);
    367              break;
    368 
    369          default:
    370               LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    371                  "unit %d i2c %s: isl68127_ioctl: invalid opcode (%d)\n"),
    372                  unit, soc_i2c_devname(unit,devno), opcode));
    373              break;
    374     }
    375     sal_mutex_give(ioctl_lock);
    376     return rv;
    377 }
    378 
    379 STATIC int
    380 isl68127_init(int unit, int devno, void* data, int len)
    381 {
    382     int rv = SOC_E_NONE;
    383     i2c_device_t *dev = soc_i2c_device(unit, devno);
    384     char *devname;
    385     uint8 data8;
    386 
    387     if (dev == NULL) {
    388         return SOC_E_INTERNAL;
    389     }
    390     devname = (char *)soc_i2c_devname(unit, devno);
    391     if (dev->priv_data == NULL) {
    392         dev->priv_data = sal_alloc(sizeof(device_data_t), devname);
    393         if (dev->priv_data == NULL) {
    394             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    395                         "Fail to allocate private data fo dev %s\n"),
    396                         soc_i2c_devname(unit, devno)));
    397             return SOC_E_MEMORY;
    398         }
    399         sal_memset(dev->priv_data, 0, sizeof(device_data_t));
    400     }
    401 
    402     if (ioctl_lock == NULL) {
    403         ioctl_lock = sal_mutex_create("isl68127_ioctl_lock");
    404         if (ioctl_lock == NULL) {
    405             LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit,
    406                     "Fail to create isl68127_ioctl_lock\n")));
    407             rv = SOC_E_MEMORY;
    408         }
    409     }
    410 
    411     /* Using mutex lock to ensure thread-safe for ioctl operations */
    412     sal_mutex_take(ioctl_lock, sal_mutex_FOREVER);
    413     /* bit3 1: control the ISL68127 output through VOUT command
    414      *      0: control the output via VID input pins which is controlled by
    415      *         a PCF8574 device
    416      */
    417     if ((rv=isl68127_write(unit, devno,
    418                     PMBUS_CMD_CLEAR_FAULTS,(void *) &len, 0)) < 0) {
    419         cli_out("Error: Failed to clear the faults of ISL68127 device.\n");
    420         sal_mutex_give(ioctl_lock);
    421         return rv;
    422     }
    423 
    424     len = 1;
    425     if ((rv=isl68127_read(unit, devno, 0xFA, (uint8 *)&DEV_RAIL_SADDR(dev), (void *)&len)) < 0) {
    426         cli_out("Error: Failed to read 0xFA of ISL68127 device.\n");
    427         sal_mutex_give(ioctl_lock);
    428         return rv;
    429     }
    430 
    431     soc_i2c_devdesc_set(unit, devno, "ISL68127 Voltage Control");
    432      LOG_VERBOSE(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "isl68127_init: %s, devNo=0x%x\n"),
    433              soc_i2c_devname(unit,devno), devno));
    434 
    435     /* Setting Fault response to zero to prevent shut-down of device */
    436     data8 =0x00;
    437     if ((rv=isl68127_write(unit, devno,
    438                     PMBUS_CMD_VOUT_OV_FAULT_RES, &data8, 1)) < 0) {
    439         cli_out("Error: failed to set OV fault response of ISL68127.\n");
    440         sal_mutex_give(ioctl_lock);
    441         return rv;
    442     }
    443 
    444     data8 =0x0A;
    445     if ((rv=isl68127_write(unit, devno, PMBUS_CMD_ON_OFF_CONFIG, &data8, 1)) < 0) {
    446         cli_out("Error: failed to set CONFIG register of ISL68127 device.\n");
    447         sal_mutex_give(ioctl_lock);
    448         return rv;
    449     }
    450     if ((rv=disable_load_line(unit, devno)) < 0) {
    451         cli_out("Error: Failed to disable ISL68127 load line.\n");
    452         sal_mutex_give(ioctl_lock);
    453         return rv;
    454     }
    455     /* Switching on ISL68127 device */
    456     data8 =0x80;
    457     if ((rv=isl68127_write(unit, devno, PMBUS_CMD_OPERATION, &data8, 1)) < 0) {
    458         cli_out("Error: failed to set operation register of ISL68127 device.\n");
    459         sal_mutex_give(ioctl_lock);
    460         return rv;
    461     }
    462 
    463     sal_mutex_give(ioctl_lock);
    464     return rv;
    465 }
    466 
    467 /* isl68127 voltage control Chip Driver callout */
    468 i2c_driver_t _soc_i2c_isl68127_driver = {
    469     0x0, 0x0, /* System assigned bytes */
    470     ISL68127_DEVICE_TYPE,
    471     isl68127_read,
    472     isl68127_write,
    473     isl68127_ioctl,
    474     isl68127_init,
    475     NULL,
    476 };