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 };