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