ltc4258.c (8719B)
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 * BCM56xx I2C Device Driver for Linear Technology LTC4258 Powered 8 * Ethernet Controller Chip. 9 * The LTC4258 is used to control DC power supplied over an ethernet 10 * link. 11 * 12 * See the LTC4258 datasheet for more details. 13 */ 14 15 #include <sal/types.h> 16 #include <soc/drv.h> 17 #include <soc/error.h> 18 #include <soc/i2c.h> 19 20 #define LTC4258 4258 21 #define LTC4259 4259 22 23 STATIC int PoeDeviceType = 0; 24 STATIC char *PoeDeviceName = NULL; 25 26 STATIC int 27 ltc4258_auto(int unit, uint8 saddr) 28 { 29 int rv; 30 /* Enable all ports' power on the POE controller (fully automatic) */ 31 /* Disable interrupts */ 32 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x01, 0x00)) != SOC_E_NONE) 33 return rv; 34 /* Full auto mode */ 35 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x12, 0xFF)) != SOC_E_NONE) 36 return rv; 37 /* Enable DC disconnect */ 38 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x13, 0x0F)) != 39 SOC_E_NONE) 40 return rv; 41 /* Enable classification and detection */ 42 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x14, 0xFF)) != SOC_E_NONE) 43 return rv; 44 return SOC_E_NONE; 45 } 46 47 STATIC int 48 ltc4258_enable_port(int unit, uint8 saddr, void *portmap) 49 { 50 /* Enable (fully automatic) power on the indicated port(s) */ 51 /* return soc_i2c_write_byte_data(unit, saddr, 0x12, 0xFF); */ 52 return SOC_E_NONE; 53 } 54 55 STATIC int 56 ltc4258_disable_port(int unit, uint8 saddr, void *portmap) 57 { 58 /* Shutdown power on the indicated port(s) */ 59 /* return soc_i2c_write_byte_data(unit, saddr, 0x12, 0x00); */ 60 return SOC_E_NONE; 61 } 62 63 STATIC int 64 ltc4258_shutdown(int unit, uint8 saddr) 65 { 66 /* Shutdown power on all ports */ 67 return soc_i2c_write_byte_data(unit, saddr, 0x12, 0x00); 68 } 69 70 STATIC int 71 ltc4258_clear_ints(int unit, uint8 saddr) 72 { 73 int rv; 74 uint8 reg_data; 75 /* Clear all event bits */ 76 if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x03, ®_data)) != SOC_E_NONE) 77 return rv; 78 if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x05, ®_data)) != SOC_E_NONE) 79 return rv; 80 if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x07, ®_data)) != SOC_E_NONE) 81 return rv; 82 if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x09, ®_data)) != SOC_E_NONE) 83 return rv; 84 if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x0B, ®_data)) != SOC_E_NONE) 85 return rv; 86 87 /* Clear all interrupt condition bits */ 88 if ((rv=soc_i2c_write_byte_data(unit, saddr, 0x1A, 0xC0)) != SOC_E_NONE) 89 return rv; 90 91 return SOC_E_NONE; 92 } 93 94 STATIC int 95 ltc4258_rescan(int unit, uint8 saddr) 96 { 97 /* Re-scan the ports for class and detection. */ 98 return soc_i2c_write_byte_data(unit, saddr, 0x18, 0xFF); 99 } 100 101 102 /* This routine writes a textual listing of the register values 103 * to the character buffer of length len pointed to by data. 104 */ 105 106 STATIC int 107 ltc4258_reg_dump_text(int unit, uint8 saddr, char *data, int len) 108 { 109 int buflen, regnum; 110 uint8 x; 111 int rv = SOC_E_NONE; 112 113 do { 114 115 buflen = sal_snprintf(data, len, "Read all %s registers...\n", 116 PoeDeviceName); 117 if (buflen >= len) 118 break; 119 data += buflen; 120 len -= buflen; 121 122 for (regnum = 0; regnum <= 0x17; regnum++) { 123 if ((regnum>=3) && (regnum<=0x0B) && (regnum&0x01)) 124 continue; 125 rv = soc_i2c_read_byte_data(unit, saddr, (uint8)regnum, &x); 126 if (rv != SOC_E_NONE) 127 break; 128 buflen = sal_snprintf(data, len, "register[0x%02x] = 0x%02X\n", regnum, x); 129 if (buflen >= len) 130 break; 131 data += buflen; 132 len -= buflen; 133 } 134 135 } while(0); 136 137 return rv; 138 } 139 140 STATIC int 141 ltc4258_chip_status_text(int unit, uint8 saddr, char *data, int len) 142 { 143 int buflen, port; 144 uint8 x, y; 145 char *class_text[8] = { 146 "Class_Unknown", "Class_1 ", "Class_2 ", "Class_3 ", 147 "Class_4 ", "Undef_Class_0", "Class_0 ", "Overcurrent " 148 }; 149 char *detect_text[8] = { 150 "Detect_Unknown", "Short_Circuit ", "????? ", "RLOW ", 151 "Detect_Good ", "RHIGH ", "Open_Circuit ", "????? " 152 }; 153 int rv = SOC_E_NONE; 154 155 rv = soc_i2c_read_byte_data(unit, saddr, 0x00, &x); 156 if (rv != SOC_E_NONE) 157 return rv; 158 buflen = sal_snprintf(data, len, "LTC4258 status:\n %s%s%s%s%s%s%s%s\n", 159 x&0x80?"Supply_Event ":"" , x&0x40?"TSTART_Fault ":"", 160 x&0x20?"TICUT_Fault ":"" , x&0x10?"Class_Complete ":"", 161 x&0x08?"Detect_Complete ":"", x&0x04?"Disconnect ":"", 162 x&0x02?"PwrGood_Event ":"" , x&0x01?"PwrEnable_Event ":""); 163 if (buflen >= len) 164 return rv; 165 166 do { 167 168 for (port=0; port<4; port++) { 169 rv = soc_i2c_read_byte_data(unit, saddr, (uint8)port + 0x0C, &x); 170 if (rv != SOC_E_NONE) 171 break; 172 rv = soc_i2c_read_byte_data(unit, saddr, 0x10, &y); 173 if (rv != SOC_E_NONE) 174 break; 175 176 buflen += sal_snprintf(&data[buflen], len-buflen, "Port #%d:\n %s %s %s%s\n", 177 port+1,class_text[(x>>4) & 0x7], 178 detect_text[x & 0x7], 179 (y & (0x10<<port))?"Power_Good ":"", 180 (y & (0x01<<port))?"Power_Enable ":""); 181 if (buflen >= len) 182 break; 183 } 184 185 } while(0); 186 187 188 return rv; 189 } 190 191 STATIC int 192 ltc4258_read(int unit, int devno, 193 uint16 addr, uint8* data, uint32* len) 194 { 195 *len = 1; /* Byte mode */ 196 return soc_i2c_read_byte_data(unit, 197 soc_i2c_addr(unit, devno), 198 (uint8)addr, data); 199 } 200 201 STATIC int 202 ltc4258_write(int unit, int devno, 203 uint16 addr, uint8* data, uint32 len) 204 { 205 /* len is ignored; write 1 byte only */ 206 return soc_i2c_write_byte_data(unit, 207 soc_i2c_addr(unit, devno), 208 (uint8)addr, *data); 209 } 210 211 212 213 /* 214 * Function: ltc4285_ioctl 215 * 216 * Purpose: perform various operations on the LTC4258 Powered Ethernet 217 * Controller chip. 218 * 219 * Parameters: 220 * unit - StrataSwitch device number or I2C bus number 221 * devno - chip device id 222 * opcode - CPU request (I2C_POE_IOC_XXX) 223 * data - address of optional data (opcode dependent) 224 * len - size of data 225 * 226 * Returns: 227 * SOC_E_NONE - no error 228 * SOC_E_TIMEOUT - I/O error. 229 * SOC_E_PARAM - chip operation unavailable. 230 */ 231 STATIC int 232 ltc4258_ioctl(int unit, int devno, 233 int opcode, void* data, int len) 234 { 235 int rv; 236 uint8 saddr = soc_i2c_addr(unit, devno); 237 switch (opcode) { 238 case I2C_POE_IOC_SHUTDOWN: 239 rv = ltc4258_shutdown(unit, saddr); 240 break; 241 case I2C_POE_IOC_AUTO: 242 rv = ltc4258_auto(unit, saddr); 243 break; 244 case I2C_POE_IOC_ENABLE_PORT: 245 rv = ltc4258_enable_port(unit, saddr, data); 246 break; 247 case I2C_POE_IOC_DISABLE_PORT: 248 rv = ltc4258_disable_port(unit, saddr, data); 249 break; 250 case I2C_POE_IOC_REG_DUMP: 251 if ((data == NULL) || (len <= 0)) 252 rv = SOC_E_PARAM; 253 else 254 rv = ltc4258_reg_dump_text(unit, saddr, (char *)data, len); 255 break; 256 case I2C_POE_IOC_STATUS: 257 if ((data == NULL) || (len <= 0)) 258 rv = SOC_E_PARAM; 259 else 260 rv = ltc4258_chip_status_text(unit, saddr, (char *)data, len); 261 break; 262 case I2C_POE_IOC_CLEAR: 263 rv = ltc4258_clear_ints(unit, saddr); 264 break; 265 case I2C_POE_IOC_RESCAN: 266 rv = ltc4258_rescan(unit, saddr); 267 break; 268 default: 269 rv = SOC_E_PARAM; 270 } 271 return rv; 272 } 273 274 STATIC int 275 ltc4258_init(int unit, int devno, 276 void* data, int len) 277 { 278 uint8 saddr = soc_i2c_addr(unit, devno); 279 uint8 orig_data, regdata = 0; 280 int rv; 281 282 /* Save register's original value, for later restoration. */ 283 if ((rv = soc_i2c_read_byte_data(unit, saddr, 0x13, &orig_data)) != 284 SOC_E_NONE) 285 return rv; 286 287 /* This register is tested to identify the installed POE chip. */ 288 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x13, 0xFF)) != SOC_E_NONE) 289 return rv; 290 if ((rv = soc_i2c_read_byte_data(unit, saddr, 0x13, ®data)) != 291 SOC_E_NONE) 292 return rv; 293 if (regdata == 0x0F) { 294 /* Upper bits are reserved, read as zeros */ 295 PoeDeviceType = LTC4258; 296 PoeDeviceName = "LTC4258"; 297 soc_i2c_devdesc_set(unit, devno, "LTC4258 Power over Ethernet"); 298 } 299 else { 300 /* Upper bits are implemented, retain values */ 301 PoeDeviceType = LTC4259; 302 PoeDeviceName = "LTC4259"; 303 soc_i2c_devdesc_set(unit, devno, "LTC4259 Power over Ethernet"); 304 } 305 306 /* Restore register's original data */ 307 if ((rv = soc_i2c_write_byte_data(unit, saddr, 0x13, orig_data)) != 308 SOC_E_NONE) 309 return rv; 310 311 /* ltc4258_shutdown(unit, saddr); */ 312 ltc4258_auto(unit, saddr); 313 return SOC_E_NONE; 314 } 315 316 /* LTC4258 POE Controller Chip Driver callout */ 317 i2c_driver_t _soc_i2c_ltc4258_driver = { 318 0x0, 0x0, /* System assigned bytes */ 319 LTC4258_DEVICE_TYPE, 320 ltc4258_read, 321 ltc4258_write, 322 ltc4258_ioctl, 323 ltc4258_init, 324 NULL, 325 }; 326