1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor 4 * 5 * Copyright (c) 2015 Measurement-Specialties 6 * 7 * Datasheet: 8 * http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf 9 */ 10 11 #include <linux/iio/iio.h> 12 #include <linux/iio/sysfs.h> 13 #include <linux/device.h> 14 #include <linux/mutex.h> 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/kernel.h> 18 #include <linux/stat.h> 19 #include "../common/ms_sensors/ms_sensors_i2c.h" 20 21 /* TSYS01 Commands */ 22 #define TSYS01_RESET 0x1E 23 #define TSYS01_CONVERSION_START 0x48 24 #define TSYS01_ADC_READ 0x00 25 #define TSYS01_PROM_READ 0xA0 26 27 #define TSYS01_PROM_WORDS_NB 8 28 29 struct tsys01_dev { 30 void *client; 31 struct mutex lock; /* lock during conversion */ 32 33 int (*reset)(void *cli, u8 cmd, unsigned int delay); 34 int (*convert_and_read)(void *cli, u8 conv, u8 rd, 35 unsigned int delay, u32 *adc); 36 int (*read_prom_word)(void *cli, int cmd, u16 *word); 37 38 u16 prom[TSYS01_PROM_WORDS_NB]; 39 }; 40 41 /* Multiplication coefficients for temperature computation */ 42 static const int coeff_mul[] = { -1500000, 1000000, -2000000, 43 4000000, -2000000 }; 44 45 static int tsys01_read_temperature(struct iio_dev *indio_dev, 46 s32 *temperature) 47 { 48 int ret, i; 49 u32 adc; 50 s64 temp = 0; 51 struct tsys01_dev *dev_data = iio_priv(indio_dev); 52 53 mutex_lock(&dev_data->lock); 54 ret = dev_data->convert_and_read(dev_data->client, 55 TSYS01_CONVERSION_START, 56 TSYS01_ADC_READ, 9000, &adc); 57 mutex_unlock(&dev_data->lock); 58 if (ret) 59 return ret; 60 61 adc >>= 8; 62 63 /* Temperature algorithm */ 64 for (i = 4; i > 0; i--) { 65 temp += coeff_mul[i] * 66 (s64)dev_data->prom[5 - i]; 67 temp *= (s64)adc; 68 temp = div64_s64(temp, 100000); 69 } 70 temp *= 10; 71 temp += coeff_mul[0] * (s64)dev_data->prom[5]; 72 temp = div64_s64(temp, 100000); 73 74 *temperature = temp; 75 76 return 0; 77 } 78 79 static int tsys01_read_raw(struct iio_dev *indio_dev, 80 struct iio_chan_spec const *channel, int *val, 81 int *val2, long mask) 82 { 83 int ret; 84 s32 temperature; 85 86 switch (mask) { 87 case IIO_CHAN_INFO_PROCESSED: 88 switch (channel->type) { 89 case IIO_TEMP: /* in milli °C */ 90 ret = tsys01_read_temperature(indio_dev, &temperature); 91 if (ret) 92 return ret; 93 *val = temperature; 94 95 return IIO_VAL_INT; 96 default: 97 return -EINVAL; 98 } 99 default: 100 return -EINVAL; 101 } 102 } 103 104 static const struct iio_chan_spec tsys01_channels[] = { 105 { 106 .type = IIO_TEMP, 107 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), 108 } 109 }; 110 111 static const struct iio_info tsys01_info = { 112 .read_raw = tsys01_read_raw, 113 }; 114 115 static bool tsys01_crc_valid(u16 *n_prom) 116 { 117 u8 cnt; 118 u8 sum = 0; 119 120 for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++) 121 sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF)); 122 123 return (sum == 0); 124 } 125 126 static int tsys01_read_prom(struct iio_dev *indio_dev) 127 { 128 int i, ret; 129 struct tsys01_dev *dev_data = iio_priv(indio_dev); 130 char buf[7 * TSYS01_PROM_WORDS_NB + 1]; 131 char *ptr = buf; 132 133 for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) { 134 ret = dev_data->read_prom_word(dev_data->client, 135 TSYS01_PROM_READ + (i << 1), 136 &dev_data->prom[i]); 137 if (ret) 138 return ret; 139 140 ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]); 141 ptr += ret; 142 } 143 144 if (!tsys01_crc_valid(dev_data->prom)) { 145 dev_err(&indio_dev->dev, "prom crc check error\n"); 146 return -ENODEV; 147 } 148 *ptr = 0; 149 dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf); 150 151 return 0; 152 } 153 154 static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev) 155 { 156 int ret; 157 struct tsys01_dev *dev_data = iio_priv(indio_dev); 158 159 mutex_init(&dev_data->lock); 160 161 indio_dev->info = &tsys01_info; 162 indio_dev->name = dev->driver->name; 163 indio_dev->dev.parent = dev; 164 indio_dev->modes = INDIO_DIRECT_MODE; 165 indio_dev->channels = tsys01_channels; 166 indio_dev->num_channels = ARRAY_SIZE(tsys01_channels); 167 168 ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000); 169 if (ret) 170 return ret; 171 172 ret = tsys01_read_prom(indio_dev); 173 if (ret) 174 return ret; 175 176 return devm_iio_device_register(dev, indio_dev); 177 } 178 179 static int tsys01_i2c_probe(struct i2c_client *client, 180 const struct i2c_device_id *id) 181 { 182 struct tsys01_dev *dev_data; 183 struct iio_dev *indio_dev; 184 185 if (!i2c_check_functionality(client->adapter, 186 I2C_FUNC_SMBUS_WORD_DATA | 187 I2C_FUNC_SMBUS_WRITE_BYTE | 188 I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { 189 dev_err(&client->dev, 190 "Adapter does not support some i2c transaction\n"); 191 return -EOPNOTSUPP; 192 } 193 194 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); 195 if (!indio_dev) 196 return -ENOMEM; 197 198 dev_data = iio_priv(indio_dev); 199 dev_data->client = client; 200 dev_data->reset = ms_sensors_reset; 201 dev_data->read_prom_word = ms_sensors_read_prom_word; 202 dev_data->convert_and_read = ms_sensors_convert_and_read; 203 204 i2c_set_clientdata(client, indio_dev); 205 206 return tsys01_probe(indio_dev, &client->dev); 207 } 208 209 static const struct i2c_device_id tsys01_id[] = { 210 {"tsys01", 0}, 211 {} 212 }; 213 MODULE_DEVICE_TABLE(i2c, tsys01_id); 214 215 static const struct of_device_id tsys01_of_match[] = { 216 { .compatible = "meas,tsys01", }, 217 { }, 218 }; 219 MODULE_DEVICE_TABLE(of, tsys01_of_match); 220 221 static struct i2c_driver tsys01_driver = { 222 .probe = tsys01_i2c_probe, 223 .id_table = tsys01_id, 224 .driver = { 225 .name = "tsys01", 226 .of_match_table = of_match_ptr(tsys01_of_match), 227 }, 228 }; 229 230 module_i2c_driver(tsys01_driver); 231 232 MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver"); 233 MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); 234 MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); 235 MODULE_LICENSE("GPL v2"); 236