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

max669x.c (13020B)


      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  * BCM I2C Device Driver for MAXIM 669x
      8  */
      9 #include <sal/types.h>
     10 #include <soc/drv.h>
     11 #include <soc/error.h>
     12 #include <soc/i2c.h>
     13 #include <shared/bsl.h>
     14 /* The MAX669X registers */
     15 #define MAX669X_REG_LOCAL_TEMP_R	       0x00
     16 #define MAX669X_REG_REMOTE_TEMP_R    	       0x01 
     17 #define MAX669X_REG_STATUS_BYTE_R              0x02
     18 #define MAX669X_REG_CONFIG_BYTE_R              0x03
     19 #define MAX669X_REG_CONVERSION_RATE_BYTE_R     0x04
     20 #define MAX669X_REG_LOCAL_ALERT_HI_LIMIT_R     0x05
     21 #define MAX669X_REG_LOCAL_ALERT_LO_LIMIT_R     0x06
     22 #define MAX669X_REG_REMOTE_ALERT_HI_LIMIT_R    0x07
     23 #define MAX669X_REG_REMOTE_ALERT_LO_LIMIT_R    0x08
     24 #define MAX669X_REG_CONFIG_BYTE_W              0x09
     25 #define MAX669X_REG_CONVERSTION_RATE_BYTE_W    0x0a
     26 #define MAX669X_REG_LOCAL_ALERT_HI_LIMIT_W     0x0b
     27 #define MAX669X_REG_LOCAL_ALERT_LO_LIMIT_W     0x0c
     28 #define MAX669X_REG_REMOTE_ALERT_HI_LIMIT_W    0x0d
     29 #define MAX669X_REG_REMOTE_ALERT_LO_LIMIT_W    0x0e 
     30 #define MAX669X_REG_ONE_SHOT                   0x0f
     31 #define MAX669X_REG_REMOTE_EXTENDED_TEMP_R     0x10
     32 #define MAX669X_REG_LOCAL_EXTENDED_TEMP_R      0x11
     33 #define MAX669X_REG_REMOTE_OVERTEMP_LIMIT_RW   0x19
     34 #define MAX669X_REG_LOCAL_OVERTEMP_LIMIT_RW    0x20
     35 #define MAX669X_REG_OVERTEMP_HYSTERESIS        0x21
     36 #define MAX669X_REG_FAULT_QUEUE                0x22
     37 #define MAX669X_REG_MANUFACTURER_ID            0xFE
     38 #define MAX669X_REG_REVISION                   0xFF
     39 
     40 /* Initial values */
     41 #define MAX669X_OP_READ         0x1
     42 #define MAX669X_OP_WRITE        0x2
     43 
     44 /*
     45  * MAX669X Hardware information : registers and their human-readable
     46  * counterparts.
     47  */
     48 typedef struct max669x_reg_s {
     49     uint8	local_temp;
     50     uint8	remote_temp_1;
     51     uint8	remote_temp_2;
     52     uint8	config;
     53     uint8   status;
     54 } max669x_reg_t;
     55 
     56 /*
     57  * Function: max669x_ioctl
     58  *
     59  * Purpose: read temperature data from the MAX669X temperature probe
     60  *          chip.
     61  *
     62  * Parameters:
     63  *    unit - StrataSwitch device number or I2C bus number
     64  *    devno - chip device id
     65  *    opcode - CPU request (MAX669X_OP_READ)
     66  *    data - address of max669x_reg_t data
     67  *    len - size of test data (not used)
     68  *
     69  * Returns:
     70  *     SOC_E_NONE - no error
     71  *     SOC_E_TIMEOUT - chip temperature reading unavailable or IO error.
     72  */
     73 STATIC int
     74 max669x_ioctl(int unit, int devno, int opcode, void* data, int len)
     75 {
     76     int rv = SOC_E_NONE;
     77     max669x_reg_t* maxreg = (max669x_reg_t*)data;
     78     uint8 saddr = soc_i2c_addr(unit, devno);
     79 
     80     if (opcode == MAX669X_OP_READ) {
     81 
     82         rv = soc_i2c_read_byte_data(unit, saddr, MAX669X_REG_LOCAL_TEMP_R, &maxreg->local_temp);
     83         if (rv < 0) {
     84             return rv;
     85         }
     86 
     87         soc_i2c_device(unit, devno)->rbyte += 1;
     88         
     89         rv = soc_i2c_read_byte_data(unit, saddr, MAX669X_REG_REMOTE_TEMP_R, &maxreg->remote_temp_1);
     90         if (rv < 0) {
     91             return rv;
     92         }
     93         soc_i2c_device(unit, devno)->rbyte += 1;
     94         
     95         rv = soc_i2c_read_byte_data(unit, saddr,  MAX669X_REG_CONFIG_BYTE_R, &maxreg->config);
     96         if (rv < 0) {
     97             return rv;
     98         }
     99         soc_i2c_device(unit, devno)->rbyte += 1;
    100 
    101         rv = soc_i2c_write_byte_data(unit, saddr, MAX669X_REG_CONFIG_BYTE_W, (maxreg->config | (1<<3)));
    102         if (rv < 0) {
    103             return rv;
    104         }
    105 
    106         rv = soc_i2c_read_byte_data(unit, saddr, MAX669X_REG_REMOTE_TEMP_R, &maxreg->remote_temp_2);
    107         if (rv < 0) {
    108             return rv;
    109         }
    110         soc_i2c_device(unit, devno)->rbyte += 1;
    111 
    112         rv = soc_i2c_write_byte_data(unit, saddr, MAX669X_REG_CONFIG_BYTE_W, maxreg->config);
    113         if (rv < 0) {
    114             return rv;
    115         }
    116 
    117         rv = soc_i2c_read_byte_data(unit, saddr,  MAX669X_REG_STATUS_BYTE_R, &maxreg->status);
    118         if (rv < 0) {
    119             return rv;
    120         }
    121         soc_i2c_device(unit, devno)->rbyte += 1;
    122 
    123 
    124     } else if (opcode == MAX669X_OP_WRITE) {
    125         
    126         rv = soc_i2c_write_byte_data(unit, saddr, MAX669X_REG_CONFIG_BYTE_W, maxreg->config);
    127         if (rv < 0) {
    128             return rv;
    129         }
    130         
    131         soc_i2c_device(unit, devno)->tbyte += 1;
    132 
    133     } else {
    134         LOG_CLI((BSL_META_U(unit,
    135                             "invalid command for max6699 - must be read or write\n")));
    136         rv = SOC_E_UNAVAIL;
    137     }
    138 
    139     return rv;
    140 }
    141 
    142 /*
    143  * MAX669X control structure.
    144  */
    145 typedef struct {
    146     int	sleep;				/* Thread sleep time (0 to exit) */
    147     int	remote_temp_1[MAX_I2C_DEVICES];		/* last temp values */
    148     int	remote_temp_2[MAX_I2C_DEVICES];		/* last temp values */
    149     int	local_temp[MAX_I2C_DEVICES];		/* last temp values */
    150 } max669x_dev_info_t;
    151 
    152 static max669x_dev_info_t *max669x_info[SOC_MAX_NUM_DEVICES];
    153 
    154 #define	C2F(_d)		((9*(_d)/5) + 32)	/* celsius to farenheit */
    155 
    156 #define	MINDIFF		1			/* at least 1 degree change */
    157 
    158 /*
    159  * Function: max669x_temp_show
    160  *
    161  * Purpose:  Query MAX669X chip for temperature and report status in
    162  *           degrees Celcius and Degrees Fahrenheit.
    163  *
    164  * Parameters:
    165  *	unit	- switch unit
    166  *	dev	    - i2c device
    167  *	force	- if true, show temp even if it hasn't changed
    168  */
    169 STATIC void
    170 max669x_temp_show(int unit, int dev, int force)
    171 {
    172     max669x_reg_t       maxreg;
    173     max669x_dev_info_t	*max_info;
    174     int			        ctemp, ftemp, lasttemp;
    175     int			        difftemp;
    176     int                 cnt;
    177 
    178     max_info = max669x_info[unit];
    179     if (max_info == NULL) {
    180         return;
    181     }
    182 
    183     /* Read back stats */
    184     if (max669x_ioctl(unit, dev, MAX669X_OP_READ, &maxreg, sizeof(max669x_reg_t)) < 0) {
    185         LOG_CLI((BSL_META_U(unit,
    186                             "%s: ERROR: device not responding\n"),
    187                  soc_i2c_devname(unit, dev)));
    188 	max_info->sleep = 0;		/* exit thread */
    189 	return;
    190     }
    191 
    192     
    193     /* loop 3x for local and two remote temp */
    194     for (cnt=0; cnt<3; cnt++) {
    195         if (cnt==0) {
    196             ctemp = maxreg.local_temp;
    197             lasttemp = max_info->local_temp[dev];
    198         } else if (cnt==1) {
    199             ctemp = maxreg.remote_temp_1;
    200             lasttemp = max_info->remote_temp_1[dev];
    201         } else {
    202             ctemp = maxreg.remote_temp_2;
    203             lasttemp = max_info->remote_temp_2[dev];
    204         }
    205 
    206         if (lasttemp == 0) {	/* first time through */
    207             difftemp = MINDIFF;
    208         } else {
    209             difftemp = lasttemp - ctemp;
    210             if (difftemp < 0) {
    211                 difftemp = -difftemp;
    212             }
    213         }
    214 
    215         if (force || difftemp >= MINDIFF) {
    216 
    217             if (cnt==0) {
    218                 max_info->local_temp[dev] = ctemp;
    219             } else if (cnt==1) {
    220                 max_info->remote_temp_1[dev] = ctemp;
    221             } else {
    222                 max_info->remote_temp_2[dev] = ctemp;
    223 
    224             }
    225             
    226             /* 20 degree C change: something is wrong */
    227             if (difftemp > 20) {
    228                 if (force) {
    229                     LOG_CLI((BSL_META_U(unit,
    230                                         "%s: NOTICE: temperature unavailable\n"),
    231                              soc_i2c_devname(unit, dev)));
    232                     if (lasttemp > 0) {
    233                         ftemp = C2F(lasttemp);
    234                         LOG_CLI((BSL_META_U(unit,
    235                                             "%s: last temperature %d.%dC, %d.%dF\n"),
    236                                  soc_i2c_devname(unit, dev),
    237                                  lasttemp/10, lasttemp%10,
    238                                  ftemp/10, ftemp%10));
    239                     }
    240                 }
    241                 return;
    242             }
    243             
    244             ftemp = C2F(ctemp);
    245 
    246             if (cnt==0) {
    247                 LOG_CLI((BSL_META_U(unit,
    248                                     "%s: local temperature %dC, %dF\n"),
    249                          soc_i2c_devname(unit, dev),
    250                          ctemp,
    251                          ftemp));
    252             } else if (cnt==1) {
    253 
    254                 LOG_CLI((BSL_META_U(unit,
    255                                     "%s: remote temperature 1 %dC, %dF\n"),
    256                          soc_i2c_devname(unit, dev),
    257                          ctemp,
    258                          ftemp));
    259             } else {
    260 
    261                 LOG_CLI((BSL_META_U(unit,
    262                                     "%s: remote temperature 2 %dC, %dF\n\n"),
    263                          soc_i2c_devname(unit, dev),
    264                          ctemp,
    265                          ftemp));
    266             }
    267 
    268         }
    269     }
    270 }
    271 
    272 
    273 /*
    274  * Function: max669x_thread
    275  *
    276  * Purpose: Poll MAX669X devices and report stats every poll_delay seconds
    277  *
    278  * Parameters:
    279  *    unitp	- void * version of unit
    280  */
    281 STATIC void
    282 max669x_thread(void *unitp)
    283 {
    284     int			unit, dev, ndev;
    285     max669x_dev_info_t	*maxinfo;
    286     
    287     unit = PTR_TO_INT(unitp);
    288     maxinfo = max669x_info[unit];
    289     
    290     while (maxinfo && maxinfo->sleep) {
    291         ndev = soc_i2c_device_count(unit);
    292         for (dev = 0; dev < ndev; dev++) {
    293             if (soc_i2c_devtype(unit, dev) == MAX669X_DEVICE_TYPE) {
    294                 max669x_temp_show(unit, dev, FALSE);
    295             }
    296         }
    297         sal_usleep(maxinfo->sleep * SECOND_USEC);
    298     }
    299     LOG_CLI((BSL_META_U(unit,
    300                         "unit %d: thermal monitoring completed\n"), unit));
    301     sal_thread_exit(0);
    302 }
    303 
    304 /*
    305  * Function: max669x_init
    306  *
    307  * Purpose: Initialize the MAX669X temperature sensor chip.
    308  *
    309  * Parameters:
    310  *    unit - StrataSwitch device number or I2C bus number
    311  *    devno - chip device id
    312  *    data - not used
    313  *    len - not used
    314  *
    315  * Returns:
    316  *     SOC_E_NONE - no failure
    317  *     SOC_E_TIMEOUT - chip or device access failure.
    318  */
    319 STATIC int
    320 max669x_init(int unit, int devno,
    321 	  void* data, int len)
    322 {
    323     int	rv;
    324     max669x_reg_t maxreg;
    325 
    326     soc_i2c_devdesc_set(unit, devno, "MAX669X Temperature Sensor");
    327 
    328     /* Init chip */
    329     maxreg.config = 0x80; /* bit 7 - mask out alert interrupts, bit 6 RUN=0 enables temp sensor */
    330 
    331     rv = max669x_ioctl(unit, devno, MAX669X_OP_WRITE, &maxreg, sizeof(max669x_reg_t));
    332     if (rv < 0) {
    333         LOG_CLI((BSL_META_U(unit,
    334                             "%s: ERROR: device did not initialize: %s\n"),
    335                  soc_i2c_devname(unit, devno),
    336                  soc_errmsg(rv)));
    337     }
    338     LOG_VERBOSE(BSL_LS_SOC_I2C, (BSL_META_U(unit,
    339                 "MAX669X hardware status=0x%x\n"), maxreg.status));
    340 
    341     /* Init devinfo */
    342     if (max669x_info[unit] == NULL) {
    343         max669x_info[unit] = sal_alloc(sizeof(max669x_dev_info_t), "max669x_info");
    344         if (max669x_info[unit] == NULL) {
    345             return SOC_E_MEMORY;
    346         }
    347         sal_memset(max669x_info[unit], 0, sizeof(max669x_dev_info_t));
    348     }
    349     
    350     return SOC_E_NONE;
    351 }
    352 
    353 /*
    354  * Function: soc_i2c_max669x_monitor
    355  *
    356  * Purpose:
    357  *     Monitor configuration: start or stop a temperature probe
    358  *     task to monitor temperatures every nsecs.
    359  * Parameters:
    360  *    unit - StrataSwitch device number or I2C bus number
    361  *    enable - start or stop a temperature probe task
    362  *    nsecs - number of seconds delay, between succesive queries.
    363  *  Returns:
    364  *    None
    365  *  Notes:
    366  *    None
    367  */
    368 void
    369 soc_i2c_max669x_monitor(int unit, int enable, int nsecs)
    370 {
    371     if (!soc_i2c_is_attached(unit)) {
    372         soc_i2c_attach(unit, 0, 0);
    373     }
    374     if (max669x_info[unit] == NULL) {
    375         return;
    376     }
    377     if (!enable) {
    378         max669x_info[unit]->sleep = 0;
    379         return;
    380     }
    381     if (max669x_info[unit]->sleep) {
    382         return;
    383     }
    384     max669x_info[unit]->sleep = nsecs;
    385     
    386     sal_thread_create("bcmTEMP",
    387                       SAL_THREAD_STKSZ,
    388                       50,
    389                       (void (*)(void*))max669x_thread,
    390                       INT_TO_PTR(unit));
    391     LOG_CLI((BSL_META_U(unit,
    392                         "unit %d: thermal monitoring enabled\n"), unit));
    393 }
    394 
    395 
    396 /*
    397  * Function: soc_i2c_max669x_temperature_show
    398  *
    399  * Purpose: Show all temperature stats on all chips.
    400  *
    401  * Parameters:
    402  *   unit - StrataSwitch device number or I2C bus number
    403  *
    404  * Returns:
    405  *   None
    406  */
    407 void
    408 soc_i2c_max669x_temperature_show(int unit)
    409 {
    410     int		dev, ndev;
    411     
    412     if (!soc_i2c_is_attached(unit)) {
    413         soc_i2c_attach(unit, 0, 0);
    414     }
    415     if (max669x_info[unit] == NULL) {
    416         return;
    417     }
    418     ndev = soc_i2c_device_count(unit);
    419     for (dev = 0; dev < ndev; dev++) {
    420         if (soc_i2c_devtype(unit, dev) == MAX669X_DEVICE_TYPE) {
    421             max669x_temp_show(unit, dev, TRUE);
    422         }
    423     }
    424 }
    425 
    426 /* NOT USED */
    427 STATIC int
    428 max669x_read(int unit, int devno,
    429              uint16 addr, uint8* data, uint32* len)
    430 {
    431     return SOC_E_NONE;
    432 }
    433 
    434 /* NOT USED */
    435 STATIC int
    436 max669x_write(int unit, int devno,
    437               uint16 addr, uint8* data, uint32 len)
    438 {
    439     return SOC_E_NONE;
    440 }
    441 
    442 
    443 /* MAX669X Temperature Sensor Driver callout */
    444 i2c_driver_t _soc_i2c_max669x_driver = {
    445     0x0, 0x0, /* System assigned bytes */
    446     MAX669X_DEVICE_TYPE,
    447     max669x_read,
    448     max669x_write,
    449     max669x_ioctl,
    450     max669x_init,
    451     NULL,
    452 };
    453