Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * t5403.c - Support for EPCOS T5403 pressure/temperature sensor
0004  *
0005  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
0006  *
0007  * (7-bit I2C slave address 0x77)
0008  *
0009  * TODO: end-of-conversion irq
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/i2c.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/sysfs.h>
0016 #include <linux/delay.h>
0017 
0018 #define T5403_DATA 0xf5 /* data, LSB first, 16 bit */
0019 #define T5403_CALIB_DATA 0x8e /* 10 calibration coeff., LSB first, 16 bit */
0020 #define T5403_SLAVE_ADDR 0x88 /* I2C slave address, 0x77 */
0021 #define T5403_COMMAND 0xf1
0022 
0023 /* command bits */
0024 #define T5403_MODE_SHIFT 3 /* conversion time: 2, 8, 16, 66 ms */
0025 #define T5403_PT BIT(1) /* 0 .. pressure, 1 .. temperature measurement */
0026 #define T5403_SCO BIT(0) /* start conversion */
0027 
0028 #define T5403_MODE_LOW 0
0029 #define T5403_MODE_STANDARD 1
0030 #define T5403_MODE_HIGH 2
0031 #define T5403_MODE_ULTRA_HIGH 3
0032 
0033 #define T5403_I2C_MASK (~BIT(7))
0034 #define T5403_I2C_ADDR 0x77
0035 
0036 static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66};
0037 
0038 struct t5403_data {
0039     struct i2c_client *client;
0040     struct mutex lock;
0041     int mode;
0042     __le16 c[10];
0043 };
0044 
0045 #define T5403_C_U16(i) le16_to_cpu(data->c[(i) - 1])
0046 #define T5403_C(i) sign_extend32(T5403_C_U16(i), 15)
0047 
0048 static int t5403_read(struct t5403_data *data, bool pressure)
0049 {
0050     int wait_time = 3;  /* wakeup time in ms */
0051 
0052     int ret = i2c_smbus_write_byte_data(data->client, T5403_COMMAND,
0053         (pressure ? (data->mode << T5403_MODE_SHIFT) : T5403_PT) |
0054         T5403_SCO);
0055     if (ret < 0)
0056         return ret;
0057 
0058     wait_time += pressure ? t5403_pressure_conv_ms[data->mode] : 2;
0059 
0060     msleep(wait_time);
0061 
0062     return i2c_smbus_read_word_data(data->client, T5403_DATA);
0063 }
0064 
0065 static int t5403_comp_pressure(struct t5403_data *data, int *val, int *val2)
0066 {
0067     int ret;
0068     s16 t_r;
0069     u16 p_r;
0070     s32 S, O, X;
0071 
0072     mutex_lock(&data->lock);
0073 
0074     ret = t5403_read(data, false);
0075     if (ret < 0)
0076         goto done;
0077     t_r = ret;
0078 
0079     ret = t5403_read(data, true);
0080     if (ret < 0)
0081         goto done;
0082     p_r = ret;
0083 
0084     /* see EPCOS application note */
0085     S = T5403_C_U16(3) + (s32) T5403_C_U16(4) * t_r / 0x20000 +
0086         T5403_C(5) * t_r / 0x8000 * t_r / 0x80000 +
0087         T5403_C(9) * t_r / 0x8000 * t_r / 0x8000 * t_r / 0x10000;
0088 
0089     O = T5403_C(6) * 0x4000 + T5403_C(7) * t_r / 8 +
0090         T5403_C(8) * t_r / 0x8000 * t_r / 16 +
0091         T5403_C(9) * t_r / 0x8000 * t_r / 0x10000 * t_r;
0092 
0093     X = (S * p_r + O) / 0x4000;
0094 
0095     X += ((X - 75000) * (X - 75000) / 0x10000 - 9537) *
0096         T5403_C(10) / 0x10000;
0097 
0098     *val = X / 1000;
0099     *val2 = (X % 1000) * 1000;
0100 
0101 done:
0102     mutex_unlock(&data->lock);
0103     return ret;
0104 }
0105 
0106 static int t5403_comp_temp(struct t5403_data *data, int *val)
0107 {
0108     int ret;
0109     s16 t_r;
0110 
0111     mutex_lock(&data->lock);
0112     ret = t5403_read(data, false);
0113     if (ret < 0)
0114         goto done;
0115     t_r = ret;
0116 
0117     /* see EPCOS application note */
0118     *val = ((s32) T5403_C_U16(1) * t_r / 0x100 +
0119         (s32) T5403_C_U16(2) * 0x40) * 1000 / 0x10000;
0120 
0121 done:
0122     mutex_unlock(&data->lock);
0123     return ret;
0124 }
0125 
0126 static int t5403_read_raw(struct iio_dev *indio_dev,
0127               struct iio_chan_spec const *chan,
0128               int *val, int *val2, long mask)
0129 {
0130     struct t5403_data *data = iio_priv(indio_dev);
0131     int ret;
0132 
0133     switch (mask) {
0134     case IIO_CHAN_INFO_PROCESSED:
0135         switch (chan->type) {
0136         case IIO_PRESSURE:
0137             ret = t5403_comp_pressure(data, val, val2);
0138             if (ret < 0)
0139                 return ret;
0140             return IIO_VAL_INT_PLUS_MICRO;
0141         case IIO_TEMP:
0142             ret = t5403_comp_temp(data, val);
0143             if (ret < 0)
0144                 return ret;
0145             return IIO_VAL_INT;
0146         default:
0147             return -EINVAL;
0148         }
0149     case IIO_CHAN_INFO_INT_TIME:
0150         *val = 0;
0151         *val2 = t5403_pressure_conv_ms[data->mode] * 1000;
0152         return IIO_VAL_INT_PLUS_MICRO;
0153     default:
0154         return -EINVAL;
0155     }
0156 }
0157 
0158 static int t5403_write_raw(struct iio_dev *indio_dev,
0159                struct iio_chan_spec const *chan,
0160                int val, int val2, long mask)
0161 {
0162     struct t5403_data *data = iio_priv(indio_dev);
0163     int i;
0164 
0165     switch (mask) {
0166     case IIO_CHAN_INFO_INT_TIME:
0167         if (val != 0)
0168             return -EINVAL;
0169         for (i = 0; i < ARRAY_SIZE(t5403_pressure_conv_ms); i++)
0170             if (val2 == t5403_pressure_conv_ms[i] * 1000) {
0171                 mutex_lock(&data->lock);
0172                 data->mode = i;
0173                 mutex_unlock(&data->lock);
0174                 return 0;
0175             }
0176         return -EINVAL;
0177     default:
0178         return -EINVAL;
0179     }
0180 }
0181 
0182 static const struct iio_chan_spec t5403_channels[] = {
0183     {
0184         .type = IIO_PRESSURE,
0185         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
0186             BIT(IIO_CHAN_INFO_INT_TIME),
0187     },
0188     {
0189         .type = IIO_TEMP,
0190         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
0191     },
0192 };
0193 
0194 static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066");
0195 
0196 static struct attribute *t5403_attributes[] = {
0197     &iio_const_attr_integration_time_available.dev_attr.attr,
0198     NULL
0199 };
0200 
0201 static const struct attribute_group t5403_attribute_group = {
0202     .attrs = t5403_attributes,
0203 };
0204 
0205 static const struct iio_info t5403_info = {
0206     .read_raw = &t5403_read_raw,
0207     .write_raw = &t5403_write_raw,
0208     .attrs = &t5403_attribute_group,
0209 };
0210 
0211 static int t5403_probe(struct i2c_client *client,
0212              const struct i2c_device_id *id)
0213 {
0214     struct t5403_data *data;
0215     struct iio_dev *indio_dev;
0216     int ret;
0217 
0218     if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
0219         I2C_FUNC_SMBUS_I2C_BLOCK))
0220         return -EOPNOTSUPP;
0221 
0222     ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR);
0223     if (ret < 0)
0224         return ret;
0225     if ((ret & T5403_I2C_MASK) != T5403_I2C_ADDR)
0226         return -ENODEV;
0227 
0228     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0229     if (!indio_dev)
0230         return -ENOMEM;
0231 
0232     data = iio_priv(indio_dev);
0233     data->client = client;
0234     mutex_init(&data->lock);
0235 
0236     i2c_set_clientdata(client, indio_dev);
0237     indio_dev->info = &t5403_info;
0238     indio_dev->name = id->name;
0239     indio_dev->modes = INDIO_DIRECT_MODE;
0240     indio_dev->channels = t5403_channels;
0241     indio_dev->num_channels = ARRAY_SIZE(t5403_channels);
0242 
0243     data->mode = T5403_MODE_STANDARD;
0244 
0245     ret = i2c_smbus_read_i2c_block_data(data->client, T5403_CALIB_DATA,
0246         sizeof(data->c), (u8 *) data->c);
0247     if (ret < 0)
0248         return ret;
0249 
0250     return devm_iio_device_register(&client->dev, indio_dev);
0251 }
0252 
0253 static const struct i2c_device_id t5403_id[] = {
0254     { "t5403", 0 },
0255     { }
0256 };
0257 MODULE_DEVICE_TABLE(i2c, t5403_id);
0258 
0259 static struct i2c_driver t5403_driver = {
0260     .driver = {
0261         .name   = "t5403",
0262     },
0263     .probe = t5403_probe,
0264     .id_table = t5403_id,
0265 };
0266 module_i2c_driver(t5403_driver);
0267 
0268 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
0269 MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver");
0270 MODULE_LICENSE("GPL");