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

pca9505.c (8395B)


      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 Phillips PCA9505 i2c switch
      8  */
      9 
     10 #include <shared/bsl.h>
     11 
     12 #include <sal/types.h>
     13 #include <soc/debug.h>
     14 #include <soc/drv.h>
     15 #include <soc/error.h>
     16 #include <soc/i2c.h>
     17 #include <shared/bsl.h>
     18 #if  defined(SHADOW_SVK)
     19 
     20 #ifdef SHADOW_SVK
     21 #define PCA9505_DEV_MAX         3
     22 #define PCA9505_PORT_MAX        5
     23 #endif
     24 
     25 #define PCA9505_IOP_BASE        0x08
     26 #define PCA9505_POL_BASE        0x10
     27 #define PCA9505_IOC_BASE        0x18
     28 #define PCA9505_MSK_BASE        0x20
     29 
     30 
     31 int
     32 pio_devname(int dev, char **name)
     33 {
     34     switch (dev) {
     35     case 0:
     36         *name = I2C_IOP_0;
     37         break;
     38     case 1:
     39         *name = I2C_IOP_1;
     40         break;
     41     default:
     42         *name = I2C_IOP_0;
     43         break;
     44     }
     45     return SOC_E_NONE;
     46 }
     47 
     48 
     49 /* Port configuration */
     50 static struct pca9505_port_config {
     51     uint8 io_config;         /* port pin: 0=ouput, 1==input */
     52     uint8 mask_intr;         /* mask : 0=interrupt, 1==no interrupt*/
     53     uint8 defaults;          /* default value in case of output*/
     54     uint8 op_config;         /* used only if output, 1=toggle output, 0=directly set the default*/
     55 } pca9505_port_config[][PCA9505_PORT_MAX] = {
     56 
     57 #ifdef SHADOW_SVK
     58     {   /* device @ SADDR0 */
     59         { 0xff, 0xff, 0x00, 0x00 },  /* port 0: SFP_ABS[0..7]    */
     60         { 0x00, 0xff, 0x00, 0x00 },  /* port 1: SFP_TXDIS[0..7]  */
     61         { 0xff, 0xff, 0x00, 0x00 },  /* port 2: SFP_TXFLT[0..7]  */
     62         { 0xff, 0xff, 0x00, 0x00 },  /* port 3: QSFP_PRS[0..3], QSFP_INT[4..7] */
     63         { 0xff, 0xff, 0x00, 0x00 },  /* port 4: UNUSED */
     64     },
     65     {   /* device @ SADDR1 */
     66         { 0xff, 0xff, 0x00, 0x00 },  /* port 0: XON_XOFF[0..7]  */ /* changed this
     67         to input as per Doug's request as these are overloaded for EB3 address
     68         */
     69         { 0xff, 0xff, 0x00, 0x00 },  /* port 1: BRD_ID[0..7]    */
     70         { 0x00, 0xff, 0x00, 0x00 },  /* port 2: SHAD_GPIO[0..7] */
     71         { 0xff, 0xff, 0x00, 0x00 },  /* port 3: UNUSED          */
     72         { 0xff, 0xff, 0x00, 0x00 },  /* port 4: JTAG_TCE[0]     */
     73     },
     74     {   /* device @ SADDR0 */
     75         { 0xe0, 0xff, 0x0e, 0x00 },  /* port 0: MOD_ABS, LO-PWR, PRG[3:1], TXDIS */
     76         { 0xe0, 0xff, 0x0e, 0x00 },  /* port 1: MOD_ABS, LO-PWR, PRG[3:1], TXDIS */
     77         { 0xff, 0xff, 0x00, 0x00 },  /* port 2: SFP_TXFLT[0..7]  */
     78         { 0xff, 0xff, 0x00, 0x00 },  /* port 3: QSFP_PRS[0..3], QSFP_INT[4..7] */
     79         { 0xff, 0xff, 0x00, 0x00 },  /* port 4: UNUSED */
     80     }
     81 #endif
     82 };
     83 
     84 
     85 STATIC int
     86 pca9505_read(int unit, int devno, uint16 addr, uint8 *data, uint32 *len)
     87 {
     88 
     89     int rv;
     90     uint8 saddr;
     91 
     92     saddr = soc_i2c_addr(unit, devno);
     93 
     94     rv = soc_i2c_read_byte_data(unit, saddr, addr, data);
     95     *len = 1; /* Byte device */
     96     LOG_INFO(BSL_LS_SOC_I2C,
     97              (BSL_META_U(unit,
     98                          "iop@0x%x: read 0x%x from addr 0x%x\n"), saddr, *data, addr));
     99     soc_i2c_device(unit, devno)->rbyte++;   
    100     return rv;
    101 }
    102 
    103 
    104 
    105 STATIC int
    106 pca9505_write(int unit, int devno, uint16 addr, uint8 *data, uint32 len)
    107 {
    108     int rv;
    109     uint8 saddr;
    110 
    111     saddr = soc_i2c_addr(unit, devno);
    112 
    113     rv = soc_i2c_write_byte_data(unit, saddr, addr, *data);
    114     LOG_INFO(BSL_LS_SOC_I2C,
    115              (BSL_META_U(unit,
    116                          "iop@0x%x: wrote 0x%x to addr 0x%x\n"), saddr, *data, addr));
    117     soc_i2c_device(unit, devno)->tbyte++;   
    118     return rv;
    119 }
    120 
    121 
    122 
    123 STATIC int
    124 pca9505_ioctl(int unit, int devno, int opcode, void* data, int len)
    125 {
    126     return SOC_E_NONE;
    127 }
    128 
    129 STATIC int
    130 pca9505_saddr_to_devid(int unit, uint8 saddr) {
    131 
    132     int dev_idx = -1;
    133 
    134 #ifdef SHADOW_SVK
    135     if (saddr == I2C_IOP_SADDR0) {
    136         dev_idx = 0;
    137     } else if (saddr == I2C_IOP_SADDR1) {
    138         dev_idx = 1;
    139     } else {
    140         dev_idx = -1;
    141     }
    142 
    143     if ((saddr == I2C_IOP_SADDR0) &&
    144         (soc_property_get(unit, "cfp_enable", 0))) {
    145         dev_idx = 2;
    146     }
    147 #endif
    148     return dev_idx;
    149 
    150 }
    151 
    152 STATIC int
    153 pca9505_init(int unit, int devno, void* data, int len)
    154 {
    155     int port;
    156     int dev_idx;
    157     int rv;
    158     uint8 value = 0;
    159     uint8 saddr;
    160 
    161     saddr = soc_i2c_addr(unit, devno);        
    162 
    163     soc_i2c_devdesc_set(unit, devno, "PCA9505 IO Port");
    164 
    165     dev_idx = pca9505_saddr_to_devid(unit, saddr);
    166     if (dev_idx < 0) {
    167         LOG_CLI((BSL_META_U(unit,
    168                             "%s: invalid address 0x%x\n"),
    169                  soc_i2c_devname(unit, devno), saddr));
    170         return SOC_E_CONFIG;
    171     }
    172 
    173     /* Configure port IO pin direction and mask */
    174     for (port = 0; port < PCA9505_PORT_MAX; port++) {
    175 
    176         LOG_INFO(BSL_LS_SOC_I2C,
    177                  (BSL_META_U(unit,
    178                              "iop: Initializing port %d \n"), port));
    179         /* Disable polarity inversion */
    180         rv = pca9505_write(unit, devno, PCA9505_POL_BASE + port, 
    181                                &value, 1);
    182 
    183         /* Configure reasonable value for output */
    184         LOG_INFO(BSL_LS_SOC_I2C,
    185                  (BSL_META_U(unit,
    186                              "iop: Setting known output on %d : 0x%x \n"), 
    187                   port, pca9505_port_config[dev_idx][port].defaults));
    188         if (pca9505_port_config[dev_idx][port].op_config) {
    189             /* Support for toggling any resets */
    190             uint8 idata = 0;
    191             idata = pca9505_port_config[dev_idx][port].defaults &
    192                      ~(pca9505_port_config[dev_idx][port].op_config);
    193             idata |= ~(pca9505_port_config[dev_idx][port].defaults & 
    194                        pca9505_port_config[dev_idx][port].op_config);
    195             rv = pca9505_write(unit, devno, PCA9505_IOP_BASE + port, &idata, 1); 
    196         }
    197         rv = pca9505_write(unit, devno, PCA9505_IOP_BASE + port, 
    198                            &pca9505_port_config[dev_idx][port].defaults, 1);
    199         LOG_INFO(BSL_LS_SOC_I2C,
    200                  (BSL_META_U(unit,
    201                              "iop: Setting interrupt mask on %d : 0x%x \n"), 
    202                   port, pca9505_port_config[dev_idx][port].mask_intr));
    203         rv = pca9505_write(unit, devno, PCA9505_MSK_BASE + port, 
    204                            &pca9505_port_config[dev_idx][port].mask_intr, 1);
    205         if (rv != SOC_E_NONE) {
    206             LOG_CLI((BSL_META_U(unit,
    207                                 "Failed initializing PCA9505 interrupt mask "
    208                                 "addr=0x%x, port=%d\n"), saddr, port));
    209         }
    210 
    211         /* Setup IO config only after loading correct values */
    212         rv = pca9505_write(unit, devno, PCA9505_IOC_BASE + port, 
    213                            &pca9505_port_config[dev_idx][port].io_config, 1);
    214         if (rv != SOC_E_NONE) {
    215             LOG_CLI((BSL_META_U(unit,
    216                                 "Failed initializing PCA9505 pin direction "
    217                                 "addr=0x%x, port=%d\n"), saddr, port));
    218             return SOC_E_FAIL;
    219         }
    220     }        
    221     return SOC_E_NONE;
    222 }
    223 
    224 void
    225 pca9505_dump(int dev, int startp, int endp)
    226 {
    227     uint8 val_0;
    228     uint8 val_8;
    229     uint8 val_10;
    230     uint8 val_18;
    231     uint8 val_20;
    232     int i;
    233     uint8 saddr;
    234 
    235     switch (dev) {
    236     case 0:
    237         saddr = I2C_IOP_SADDR0; break;
    238     case 1:
    239         saddr = I2C_IOP_SADDR1; break;
    240     case 2:
    241 #ifdef SHADOW_SVK
    242         saddr = I2C_IOP_SADDR0; break;
    243 #endif
    244     default:
    245         return;
    246     }
    247     for(i = startp; i < endp; i++) {
    248         soc_i2c_read_byte_data(0,saddr, 0x00 + i, &val_0);
    249         soc_i2c_read_byte_data(0,saddr, 0x08 + i, &val_8);
    250         soc_i2c_read_byte_data(0,saddr, 0x10 + i, &val_10);
    251         soc_i2c_read_byte_data(0,saddr, 0x18 + i, &val_18);
    252         soc_i2c_read_byte_data(0,saddr, 0x20 + i, &val_20);
    253         LOG_CLI((BSL_META("R[0x%02x] = 0x%02x\n"), 0x00 + i, (uint32)val_0));
    254         LOG_CLI((BSL_META("R[0x%02x] = 0x%02x\n"), 0x08 + i, (uint32)val_8));
    255         LOG_CLI((BSL_META("R[0x%02x] = 0x%02x\n"), 0x10 + i, (uint32)val_10));
    256         LOG_CLI((BSL_META("R[0x%02x] = 0x%02x\n"), 0x18 + i, (uint32)val_18));
    257         LOG_CLI((BSL_META("R[0x%02x] = 0x%02x\n"), 0x20 + i, (uint32)val_20));
    258    }
    259 }
    260 
    261 
    262 /* PCA9505 Clock Chip Driver callout */
    263 i2c_driver_t _soc_i2c_pca9505_driver = {
    264     0x0, 0x0, /* System assigned bytes */
    265     PCA9505_DEVICE_TYPE,
    266     pca9505_read,
    267     pca9505_write,
    268     pca9505_ioctl,
    269     pca9505_init,
    270     NULL,
    271 };
    272 
    273 #endif /* SHADOW_SVK */