root/drivers/iio/humidity/si7020.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. si7020_read_raw
  2. si7020_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
   4  * Copyright (c) 2013,2014  Uplogix, Inc.
   5  * David Barksdale <dbarksdale@uplogix.com>
   6  */
   7 
   8 /*
   9  * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
  10  * are i2c devices which have an identical programming interface for
  11  * measuring relative humidity and temperature. The Si7013 has an additional
  12  * temperature input which this driver does not support.
  13  *
  14  * Data Sheets:
  15  *   Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
  16  *   Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
  17  *   Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
  18  */
  19 
  20 #include <linux/delay.h>
  21 #include <linux/i2c.h>
  22 #include <linux/module.h>
  23 #include <linux/slab.h>
  24 #include <linux/sysfs.h>
  25 
  26 #include <linux/iio/iio.h>
  27 #include <linux/iio/sysfs.h>
  28 
  29 /* Measure Relative Humidity, Hold Master Mode */
  30 #define SI7020CMD_RH_HOLD       0xE5
  31 /* Measure Temperature, Hold Master Mode */
  32 #define SI7020CMD_TEMP_HOLD     0xE3
  33 /* Software Reset */
  34 #define SI7020CMD_RESET         0xFE
  35 
  36 static int si7020_read_raw(struct iio_dev *indio_dev,
  37                            struct iio_chan_spec const *chan, int *val,
  38                            int *val2, long mask)
  39 {
  40         struct i2c_client **client = iio_priv(indio_dev);
  41         int ret;
  42 
  43         switch (mask) {
  44         case IIO_CHAN_INFO_RAW:
  45                 ret = i2c_smbus_read_word_swapped(*client,
  46                                                   chan->type == IIO_TEMP ?
  47                                                   SI7020CMD_TEMP_HOLD :
  48                                                   SI7020CMD_RH_HOLD);
  49                 if (ret < 0)
  50                         return ret;
  51                 *val = ret >> 2;
  52                 /*
  53                  * Humidity values can slightly exceed the 0-100%RH
  54                  * range and should be corrected by software
  55                  */
  56                 if (chan->type == IIO_HUMIDITYRELATIVE)
  57                         *val = clamp_val(*val, 786, 13893);
  58                 return IIO_VAL_INT;
  59         case IIO_CHAN_INFO_SCALE:
  60                 if (chan->type == IIO_TEMP)
  61                         *val = 175720; /* = 175.72 * 1000 */
  62                 else
  63                         *val = 125 * 1000;
  64                 *val2 = 65536 >> 2;
  65                 return IIO_VAL_FRACTIONAL;
  66         case IIO_CHAN_INFO_OFFSET:
  67                 /*
  68                  * Since iio_convert_raw_to_processed_unlocked assumes offset
  69                  * is an integer we have to round these values and lose
  70                  * accuracy.
  71                  * Relative humidity will be 0.0032959% too high and
  72                  * temperature will be 0.00277344 degrees too high.
  73                  * This is no big deal because it's within the accuracy of the
  74                  * sensor.
  75                  */
  76                 if (chan->type == IIO_TEMP)
  77                         *val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
  78                 else
  79                         *val = -786; /* = -6 * (65536 >> 2) / 125 */
  80                 return IIO_VAL_INT;
  81         default:
  82                 break;
  83         }
  84 
  85         return -EINVAL;
  86 }
  87 
  88 static const struct iio_chan_spec si7020_channels[] = {
  89         {
  90                 .type = IIO_HUMIDITYRELATIVE,
  91                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  92                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  93         },
  94         {
  95                 .type = IIO_TEMP,
  96                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  97                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
  98         }
  99 };
 100 
 101 static const struct iio_info si7020_info = {
 102         .read_raw = si7020_read_raw,
 103 };
 104 
 105 static int si7020_probe(struct i2c_client *client,
 106                         const struct i2c_device_id *id)
 107 {
 108         struct iio_dev *indio_dev;
 109         struct i2c_client **data;
 110         int ret;
 111 
 112         if (!i2c_check_functionality(client->adapter,
 113                                      I2C_FUNC_SMBUS_WRITE_BYTE |
 114                                      I2C_FUNC_SMBUS_READ_WORD_DATA))
 115                 return -EOPNOTSUPP;
 116 
 117         /* Reset device, loads default settings. */
 118         ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
 119         if (ret < 0)
 120                 return ret;
 121         /* Wait the maximum power-up time after software reset. */
 122         msleep(15);
 123 
 124         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 125         if (!indio_dev)
 126                 return -ENOMEM;
 127 
 128         data = iio_priv(indio_dev);
 129         *data = client;
 130 
 131         indio_dev->dev.parent = &client->dev;
 132         indio_dev->name = dev_name(&client->dev);
 133         indio_dev->modes = INDIO_DIRECT_MODE;
 134         indio_dev->info = &si7020_info;
 135         indio_dev->channels = si7020_channels;
 136         indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
 137 
 138         return devm_iio_device_register(&client->dev, indio_dev);
 139 }
 140 
 141 static const struct i2c_device_id si7020_id[] = {
 142         { "si7020", 0 },
 143         { "th06", 0 },
 144         { }
 145 };
 146 MODULE_DEVICE_TABLE(i2c, si7020_id);
 147 
 148 static const struct of_device_id si7020_dt_ids[] = {
 149         { .compatible = "silabs,si7020" },
 150         { }
 151 };
 152 MODULE_DEVICE_TABLE(of, si7020_dt_ids);
 153 
 154 static struct i2c_driver si7020_driver = {
 155         .driver = {
 156                 .name = "si7020",
 157                 .of_match_table = of_match_ptr(si7020_dt_ids),
 158         },
 159         .probe          = si7020_probe,
 160         .id_table       = si7020_id,
 161 };
 162 
 163 module_i2c_driver(si7020_driver);
 164 MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
 165 MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
 166 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */