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

cpu.c (9957B)


      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 access from the CPU
      8  */
      9 
     10 #include <sal/types.h>
     11 #include <shared/bsl.h>
     12 #include <soc/drv.h>
     13 #include <soc/i2c.h>
     14 
     15 #if defined(__DUNE_GTO_BCM_CPU__) || defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_SLK_BCM_CPU__) || defined(INCLUDE_CPU_I2C)
     16 
     17 #include <sal/appl/i2c.h>
     18 
     19 
     20 #define CPU_I2C_MAX_ADDRESS_SIZE 4 /* Maximum number of bytes of an address in an I2C device (register address) */
     21 
     22 uint8 cpu_i2c_bus_num_default = CPU_I2C_BUS_NUM_DEFAULT;
     23 
     24 int cpu_i2c_write(int chip, int addr, CPU_I2C_BUS_LEN alen, int val)
     25 {
     26     int ret, bus_num = CPU_I2C_BUS_NUM_DEFAULT;
     27     uint32 value;
     28     uint8 data_len = alen & 0xf, addr_len = (alen >> 4) & 0xf, i, data[CPU_I2C_MAX_ADDRESS_SIZE] = {0};
     29 
     30     LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META(
     31       "cpu_i2c_write: bus:%d dev:@%02x reg:%0x data:%x\n"), bus_num, chip, addr, val));
     32 
     33     switch (alen)
     34     {
     35         /* No internal/register address */
     36         case CPU_I2C_ALEN_NONE_DLEN_BYTE:
     37         case CPU_I2C_ALEN_NONE_DLEN_WORD:
     38         case CPU_I2C_ALEN_NONE_DLEN_LONG:
     39         case CPU_I2C_ALEN_BYTE_DLEN_BYTE: /* address is 1 byte long */
     40         case CPU_I2C_ALEN_WORD_DLEN_WORD: /* address is word (2 bytes) long */
     41         case CPU_I2C_ALEN_BYTE_DLEN_LONG: /* address is 1 bytes long, data is 4 byte long*/
     42         case CPU_I2C_ALEN_WORD_DLEN_LONG: /* address is 1 bytes long, data is 4 byte long*/
     43         case CPU_I2C_ALEN_LONG_DLEN_LONG: /* address is 4 bytes long */
     44         case CPU_I2C_ALEN_BYTE_DLEN_WORD: /* address is 1 bytes long, data is 2 bytes long */
     45             break;
     46         default:
     47             LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META(
     48               "error - unsupported address and data length given = 0x%x"), (unsigned)alen));
     49             return SOC_E_PARAM;
     50     }
     51 
     52     /* build data as big endian */
     53     value = val;
     54     for (i = data_len ; i > 0 ;) {
     55         data[--i] = value & 0xff;
     56         value >>= 8;
     57     }
     58 
     59     /* Perform an I2C write operation */
     60     ret = sal_i2c_write(CPU_I2C_BUS_NUM_DEFAULT, chip, (uint32)addr, addr_len, data, data_len);
     61 
     62     if (ret != SOC_E_NONE)
     63     {
     64         LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META(
     65           "Error in %s: cpu_i2c_write() returned with error.\n"), FUNCTION_NAME()));
     66     }
     67 
     68     return ret;
     69 }
     70 
     71 /* perform an I2C read operation by the CPU card */
     72 int cpu_i2c_read_extended(int chip, int addr, CPU_I2C_BUS_LEN alen, int* p_val, int donot_print_errors)
     73 {
     74     int ret = 0;
     75     int bus_num = CPU_I2C_BUS_NUM_DEFAULT;
     76     uint32 value;
     77     uint8 data_len = alen & 0xf, addr_len = (alen >> 4) & 0xf, i, result[CPU_I2C_MAX_ADDRESS_SIZE] = {0};
     78 
     79     LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META(
     80       "cpu_i2c_read: bus:%d dev:@%02x reg:%0x\n"), bus_num, chip, addr));
     81 
     82     switch (alen)
     83     {
     84         /* No internal/register address */
     85         case CPU_I2C_ALEN_NONE_DLEN_BYTE:
     86         case CPU_I2C_ALEN_NONE_DLEN_WORD:
     87         case CPU_I2C_ALEN_NONE_DLEN_LONG:
     88 
     89         case CPU_I2C_ALEN_BYTE_DLEN_BYTE: /* address is 1 byte long */
     90         case CPU_I2C_ALEN_WORD_DLEN_WORD: /* address is word (2 bytes) long */
     91         case CPU_I2C_ALEN_BYTE_DLEN_LONG: /* address is 1 bytes long, data is 4 byte long*/
     92         case CPU_I2C_ALEN_WORD_DLEN_LONG: /* address is 1 bytes long, data is 4 byte long*/
     93         case CPU_I2C_ALEN_LONG_DLEN_LONG: /* address is 4 bytes long */
     94         case CPU_I2C_ALEN_BYTE_DLEN_WORD: /* address is 1 bytes long, data is 2 bytes long */
     95             break;
     96         default:
     97             LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META(
     98               "error - unsupported address and data length given = 0x%x"), (unsigned)alen));
     99             return SOC_E_PARAM;
    100     } /* switch*/
    101 
    102     /* Perform an I2C read operation */
    103     ret = sal_i2c_read(CPU_I2C_BUS_NUM_DEFAULT, chip, (uint32)addr, addr_len, result, data_len);
    104 
    105     /* build results value according received as big endian */
    106     value = 0;
    107     if (ret == SOC_E_NONE) {
    108         for (i = 0 ; i < data_len; ++i) {
    109             value = (value << 8) | result[i];
    110         }
    111         LOG_INFO(BSL_LS_SOC_I2C, (BSL_META(
    112           "cpu_i2c_read: bus:%d dev:@%02x reg:%0x data:%x\n"), bus_num, chip, addr, value));
    113     } else if (!donot_print_errors) {
    114         LOG_ERROR(BSL_LS_SOC_I2C, (BSL_META("cpu_i2c_read() returned with error.\n")));
    115     }
    116     *p_val = value;
    117     return ret;
    118 }
    119 
    120 int cpu_i2c_read(int chip, int addr, CPU_I2C_BUS_LEN alen, int* p_val)
    121 {
    122   return cpu_i2c_read_extended(chip, addr, alen, p_val, 0);
    123 }
    124 
    125 /* perform an I2C read operation on an I2C device connected to the CPU */
    126 soc_error_t cpu_i2c_read_generic(
    127   uint8 i2c_bus, /* The number of the I2C bus to access on */
    128   uint16 i2c_dev,/* the device on the I2C bus (slave address) to be accessed */
    129   uint8 alen,    /* the length of the address in bytes, should be between 0 and 4. */
    130   uint8 dlen,    /* the length of the data to read. */
    131   uint32 addr,   /* The address in the device to be accessed (register address). Used if alen>0 */
    132   uint8 *data)   /* the buffer for the data to be read. */
    133 {
    134     return sal_i2c_read(i2c_bus, i2c_dev, addr, alen, data, dlen);
    135 }
    136 
    137 /* perform an I2C write operation on an I2C device connected to the CPU */
    138 soc_error_t cpu_i2c_write_generic(
    139   uint8 i2c_bus, /* The number of the I2C bus to access on */
    140   uint16 i2c_dev,/* the device on the I2C bus (slave address) to be accessed */
    141   uint8 alen,    /* the length of the address in bytes, should be between 0 and 4. */
    142   uint8 dlen,    /* the length of the data to read. */
    143   uint32 addr,   /* The address in the device to be accessed (register address). Used if alen>0 */
    144   uint8 *data)   /* the buffer for the data to be read. */
    145 {
    146     return sal_i2c_write(i2c_bus, i2c_dev, addr, alen, data, dlen);
    147 }
    148 
    149 
    150 
    151 /*
    152  * Function: cpu_i2c_device_present
    153  * Purpose: Probe the I2C bus using saddr, report if a device responds.
    154  *          The I2C bus is released upon return.
    155  *          No further action is taken.
    156  *
    157  * Parameters:
    158  *    saddr - I2C slave address
    159  *
    160  * Return:
    161  *     SOC_E_NONE - An I2C device responds at the indicated saddr.
    162  *     otherwise  - No I2C response at the indicated saddr, or I/O error.
    163  */
    164 int
    165 cpu_i2c_device_present(int bus, i2c_saddr_t saddr) {
    166     return sal_i2c_device_present(bus, saddr);
    167 }
    168 
    169 /*
    170  * Function: cpu_i2c_block_read
    171  * Purpose: Read a block of data from I2c device
    172  *
    173  * Parameters:
    174  *    bus  - cpu controller to use
    175  *    saddr  - slave address
    176  *    addr -  interal starting address, only 8bit addressing as of now
    177  *    data  - pointer to buffer
    178  *    len   - len of data to be read
    179  * Return:
    180  *     SOC_E_NONE - An I2C device responds at the indicated saddr.
    181  *     otherwise  - No I2C response at the indicated saddr, or I/O error.
    182  */
    183 int
    184 cpu_i2c_block_read(int bus, i2c_saddr_t saddr, 
    185                    uint8 reg, uint8 *data, uint8 *len)
    186 {
    187 
    188     int rv;
    189 
    190     if (*len == 0) {
    191         LOG_ERROR(BSL_LS_SOC_I2C,
    192                  (BSL_META("ERROR in cpu_i2c_block_read: invalid len specified (%d)"),
    193                   *len));
    194         return SOC_E_PARAM;
    195     }
    196     rv = sal_i2c_read(bus, saddr, reg, 1, data, *len);
    197   
    198     if (rv != SOC_E_NONE) {
    199         LOG_ERROR(BSL_LS_SOC_I2C,
    200                  (BSL_META("\nFailed reading %d bytes data from %x at device saddr %x"),
    201                   *len, reg, saddr));
    202         return rv;
    203     }
    204     return SOC_E_NONE;
    205 }
    206 
    207 /*
    208  * Function: cpu_i2c_block_write
    209  * Purpose: Write a block of data from I2c device
    210  *
    211  * Parameters:
    212  *    bus  - cpu controller to use
    213  *    saddr  - slave address
    214  *    addr -  interal starting address, only 8bit addressing as of now
    215  *    data  - pointer to buffer
    216  *    len   - len of data to be read
    217  * Return:
    218  *     SOC_E_NONE - An I2C device responds at the indicated saddr.
    219  *     otherwise  - No I2C response at the indicated saddr, or I/O error.
    220  */
    221 int
    222 cpu_i2c_block_write(int bus, i2c_saddr_t saddr, 
    223                    uint8 reg, uint8 *data, uint8 len)
    224 {
    225     int rv = sal_i2c_write_split(bus, saddr, reg, 1, data, len);
    226 
    227     if (rv != SOC_E_NONE) {
    228         LOG_ERROR(BSL_LS_SOC_I2C,
    229                  (BSL_META("\nFailed reading %d bytes data from %x at device saddr %x"),
    230                   len, reg, saddr));
    231         return rv;
    232     }
    233     return SOC_E_NONE;
    234 }
    235 
    236 
    237 /* Write to the internal device Address space using I2C */
    238 soc_error_t cpu_i2c_device_read(
    239   uint8 i2c_bus, /* The number of the I2C bus to access on */
    240   uint8 i2c_dev, /* the device on the I2C bus (slave address) to be accessed */
    241   uint32 addr,   /* The address to access in the internal device address space */
    242   uint32 *value) /* the value to be read. */
    243 {
    244     unsigned i;
    245     uint8 data[sizeof(*value)];
    246 
    247     soc_error_t ret = sal_i2c_read(i2c_bus, i2c_dev, addr, sizeof(addr), data, sizeof(*value));
    248     /* build value according received as big endian */
    249     *value = 0;
    250     for (i = 0 ; i < sizeof(*value); ++i) {
    251         *value = (*value << 8) | data[i];
    252     }
    253     return ret;
    254 }
    255 
    256 /* Write to the internal device Address space using I2C */
    257 soc_error_t cpu_i2c_device_write(
    258   uint8 i2c_bus, /* The number of the I2C bus to access on */
    259   uint8 i2c_dev, /* the device on the I2C bus (slave address) to be accessed */
    260   uint32 addr,   /* The address to access in the internal device address space */
    261   uint32 value)  /* the value to be written. */
    262 {
    263     unsigned i;
    264     uint8 data[sizeof(value)];
    265 
    266     /* copy the address to data as big endian */
    267     for (i = sizeof(value) ; i > 0 ; ) {
    268         data[--i] = value & 0xff;
    269         value >>= 8;
    270     }
    271     /* The device returns an error on writes, even though they are performed */
    272     sal_i2c_write(i2c_bus, i2c_dev, addr, sizeof(addr), data, sizeof(value));
    273     return SOC_E_NONE; /* ignore errors */
    274 }
    275 
    276 
    277 #else
    278 int _src_soc_i2c_cpu_c_not_empty;
    279 #endif  /* defined(__DUNE_GTO_BCM_CPU__) || defined(__DUNE_WRX_BCM_CPU__) || defined(__DUNE_SLK_BCM_CPU__) || defined(INCLUDE_CPU_I2C) */