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

pcf8574.c (5969B)


      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 PCF8574 Parallel port.
      8  *
      9  * On P48 systems, the parallel port is typically connected to two
     10  * MUX's used to control I2C slave addressing on the common I2C bus.
     11  *
     12  *
     13  *       o-------[MUX1]--[MUX2]
     14  *       |         |       |
     15  *       |         |       |
     16  *       |         |       |
     17  *   [PCF8574]   (SxA)   (SyB)
     18  *       |         |       |
     19  *       0=========O=======0================I2C
     20  *
     21  *
     22  * SxA = Slave X with Address Bits A
     23  * SxB = Slave Y with Address Bits B
     24  */
     25 
     26 #include <shared/bsl.h>
     27 
     28 #include <sal/types.h>
     29 #include <soc/debug.h>
     30 #include <soc/drv.h>
     31 #include <soc/error.h>
     32 #include <soc/i2c.h>
     33 #include <shared/bsl.h>
     34 
     35 STATIC int
     36 pcf8574_read(int unit, int devno,
     37 	  uint16 addr, uint8* data, uint32* len)
     38 {
     39     
     40     int rv;
     41     uint8 saddr = soc_i2c_addr(unit, devno);
     42 
     43     rv = soc_i2c_read_byte(unit, saddr, data);
     44     *len = 1; /* Byte device */
     45     /* LOG_CLI((BSL_META_U(unit,
     46                            "lpt0: read 0x%x from HW\n"),*data)); */
     47     soc_i2c_device(unit, devno)->rbyte++;   
     48     return rv;
     49 }
     50 
     51 STATIC int
     52 pcf8574_write(int unit, int devno,
     53 	   uint16 addr, uint8* data, uint32 len)
     54 {
     55     int rv;
     56     uint8 saddr = soc_i2c_addr(unit, devno);
     57 
     58     rv = soc_i2c_write_byte(unit, saddr, *data);
     59     /* LOG_CLI((BSL_META_U(unit,
     60                            "lpt0: wrote 0x%x to HW\n"),*data)); */
     61     soc_i2c_device(unit, devno)->tbyte++;   
     62     return rv;
     63 }
     64 
     65 
     66 
     67 STATIC int
     68 pcf8574_ioctl(int unit, int devno,
     69 	   int opcode, void* data, int len)
     70 {
     71     return SOC_E_NONE;
     72 }
     73 
     74 STATIC int
     75 pcf8574_init(int unit, int devno,
     76 	  void* data, int len)
     77 {
     78     uint32 bytes;
     79     uint8 lpt_val = 0;
     80     uint8 saddr = soc_i2c_addr(unit, devno);        
     81 
     82     if (saddr == I2C_LPT_SADDR0) {
     83         pcf8574_read(unit, devno, 0, &lpt_val, &bytes);
     84 	if (lpt_val == 0xFF) {
     85 	    /* This is probably immediately after power-on; reset to zero. */
     86 	    lpt_val = 0;
     87 	    pcf8574_write(unit, devno, 0, &lpt_val, 1);
     88 	}
     89 	soc_i2c_devdesc_set(unit, devno, "PCF8574 MUX control");
     90 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
     91                     (BSL_META_U(unit,
     92                                 "%s: mux control 0x%x\n"),
     93                      soc_i2c_devname(unit, devno), lpt_val));
     94     } else if (saddr == I2C_LPT_SADDR1) {
     95         /* This device used as input; write 0xFF to disable quasi-outputs */
     96         lpt_val = 0xFF;
     97         pcf8574_write(unit, devno, 0, &lpt_val, 1);
     98 
     99         /* Now read what is being driven onto the quasi-inputs */
    100         /* coverity[callee_ptr_arith: FALSE] */
    101         pcf8574_read(unit, devno, 0, &lpt_val, &bytes);
    102 
    103         /* Try to read from the PCA9554 device */
    104         if (lpt_val == 0xFF || lpt_val == 0x0) {
    105             lpt_val = 0; /* Write 0x00 to command register first */
    106             pcf8574_write(unit, devno, 0, &lpt_val, 1);
    107             pcf8574_read(unit, devno, 0, &lpt_val, &bytes);
    108         }
    109 
    110         soc_i2c_devdesc_set(unit, devno, "PCF8574 or PCA9554 Baseboard ID");
    111         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    112                     (BSL_META_U(unit,
    113                                 "%s: baseboard id 0x%x\n"),
    114                      soc_i2c_devname(unit, devno), lpt_val));
    115         SOC_CONTROL(unit)->board_type = lpt_val;
    116     } else if (saddr == I2C_LPT_SADDR2) {
    117         /* 
    118 	 * The power-up state is the appropriate default; 
    119 	 * no need to manually initialize the HCLK PCF8574.
    120 	 */
    121 	soc_i2c_devdesc_set(unit, devno, "PCF8574 HCLK control");
    122 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    123                     (BSL_META_U(unit,
    124                                 "%s: hclk control 0x%x\n"),
    125                      soc_i2c_devname(unit, devno), lpt_val));
    126     } else if (saddr == I2C_LPT_SADDR3) {
    127         pcf8574_read(unit, devno, 0, &lpt_val, &bytes);
    128 	if (lpt_val == 0xFF) {
    129 	    /* This is probably immediately after power-on; reset to zero. */
    130 	    lpt_val = 0x0;
    131 	    pcf8574_write(unit, devno, 0, &lpt_val, 1);
    132 	}
    133 	pcf8574_write(unit, devno, 0, &lpt_val, 1);
    134 	soc_i2c_devdesc_set(unit, devno, "PCF8574 POE control");
    135 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    136                     (BSL_META_U(unit,
    137                                 "%s: poe control 0x%x\n"),
    138                      soc_i2c_devname(unit, devno), lpt_val));
    139     } else if (saddr == I2C_LPT_SADDR4) {
    140 	soc_i2c_devdesc_set(unit, devno, "PCF8574 synthesizer frequency selector M");
    141 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    142                     (BSL_META_U(unit,
    143                                 "%s: synth freq select B 0x%x\n"),
    144                      soc_i2c_devname(unit, devno), lpt_val));
    145     } else if (saddr == I2C_LPT_SADDR5) {
    146 	soc_i2c_devdesc_set(unit, devno, "PCF8574 synthesizer frequency selector N");
    147 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    148                     (BSL_META_U(unit,
    149                                 "%s: synth freq select A 0x%x\n"),
    150                      soc_i2c_devname(unit, devno), lpt_val));
    151     } else if (saddr == I2C_LPT_SADDR6) {
    152 	soc_i2c_devdesc_set(unit, devno, "PCF8574 PPD clock delay");
    153 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    154                     (BSL_META_U(unit,
    155                                 "%s: clock selector 0x%x\n"),
    156                      soc_i2c_devname(unit, devno), lpt_val));
    157     } else if (saddr == I2C_LPT_SADDR7) {
    158 	soc_i2c_devdesc_set(unit, devno, "PCF8574 PPD clock divider");
    159 	LOG_VERBOSE(BSL_LS_SOC_COMMON,
    160                     (BSL_META_U(unit,
    161                                 "%s: clock selector 0x%x\n"),
    162                      soc_i2c_devname(unit, devno), lpt_val));
    163     } else {
    164 	soc_i2c_devdesc_set(unit, devno, "PCF8574 Parallel Port");
    165     }
    166     return SOC_E_NONE;
    167 }
    168 
    169 
    170 /* PCF8574 Clock Chip Driver callout */
    171 i2c_driver_t _soc_i2c_pcf8574_driver = {
    172     0x0, 0x0, /* System assigned bytes */
    173     PCF8574_DEVICE_TYPE,
    174     pcf8574_read,
    175     pcf8574_write,
    176     pcf8574_ioctl,
    177     pcf8574_init,
    178     NULL,
    179 };
    180