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

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, &reg_data)) != SOC_E_NONE)
     77     return rv;
     78   if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x05, &reg_data)) != SOC_E_NONE)
     79     return rv;
     80   if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x07, &reg_data)) != SOC_E_NONE)
     81     return rv;
     82   if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x09, &reg_data)) != SOC_E_NONE)
     83     return rv;
     84   if ((rv=soc_i2c_read_byte_data(unit, saddr, 0x0B, &reg_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, &regdata)) != 
    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