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