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

max664x.c (12114B)


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