1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Digital temperature sensor with integrated Non-volatile memory 4 * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com> 5 * 6 * Driver for the Texas Instruments TMP117 Temperature Sensor 7 * (7-bit I2C slave address (0x48 - 0x4B), changeable via ADD pins) 8 * 9 * Note: This driver assumes that the sensor has been calibrated beforehand. 10 */ 11 12 #include <linux/array_size.h> 13 #include <linux/delay.h> 14 #include <linux/err.h> 15 #include <linux/i2c.h> 16 #include <linux/module.h> 17 #include <linux/bitops.h> 18 #include <linux/types.h> 19 #include <linux/kernel.h> 20 #include <linux/limits.h> 21 #include <linux/property.h> 22 #include <linux/regulator/consumer.h> 23 24 #include <linux/iio/iio.h> 25 26 #define TMP117_REG_TEMP 0x0 27 #define TMP117_REG_CFGR 0x1 28 #define TMP117_REG_HIGH_LIM 0x2 29 #define TMP117_REG_LOW_LIM 0x3 30 #define TMP117_REG_EEPROM_UL 0x4 31 #define TMP117_REG_EEPROM1 0x5 32 #define TMP117_REG_EEPROM2 0x6 33 #define TMP117_REG_TEMP_OFFSET 0x7 34 #define TMP117_REG_EEPROM3 0x8 35 #define TMP117_REG_DEVICE_ID 0xF 36 37 #define TMP117_RESOLUTION_10UC 78125 38 #define MICRODEGREE_PER_10MILLIDEGREE 10000 39 40 #define TMP116_DEVICE_ID 0x1116 41 #define TMP117_DEVICE_ID 0x0117 42 #define TMP119_DEVICE_ID 0x2117 43 44 struct tmp117_data { 45 struct i2c_client *client; 46 s16 calibbias; 47 }; 48 49 struct tmp11x_info { 50 const char *name; 51 struct iio_chan_spec const *channels; 52 int num_channels; 53 }; 54 55 static int tmp117_read_raw(struct iio_dev *indio_dev, 56 struct iio_chan_spec const *channel, int *val, 57 int *val2, long mask) 58 { 59 struct tmp117_data *data = iio_priv(indio_dev); 60 s32 ret; 61 62 switch (mask) { 63 case IIO_CHAN_INFO_RAW: 64 ret = i2c_smbus_read_word_swapped(data->client, 65 TMP117_REG_TEMP); 66 if (ret < 0) 67 return ret; 68 *val = sign_extend32(ret, 15); 69 return IIO_VAL_INT; 70 71 case IIO_CHAN_INFO_CALIBBIAS: 72 ret = i2c_smbus_read_word_swapped(data->client, 73 TMP117_REG_TEMP_OFFSET); 74 if (ret < 0) 75 return ret; 76 *val = sign_extend32(ret, 15); 77 return IIO_VAL_INT; 78 79 case IIO_CHAN_INFO_SCALE: 80 /* 81 * Conversion from 10s of uC to mC 82 * as IIO reports temperature in mC 83 */ 84 *val = TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE; 85 *val2 = (TMP117_RESOLUTION_10UC % 86 MICRODEGREE_PER_10MILLIDEGREE) * 100; 87 88 return IIO_VAL_INT_PLUS_MICRO; 89 90 default: 91 return -EINVAL; 92 } 93 } 94 95 static int tmp117_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec 96 const *channel, int val, int val2, long mask) 97 { 98 struct tmp117_data *data = iio_priv(indio_dev); 99 s16 off; 100 101 switch (mask) { 102 case IIO_CHAN_INFO_CALIBBIAS: 103 off = clamp_t(int, val, S16_MIN, S16_MAX); 104 if (off == data->calibbias) 105 return 0; 106 data->calibbias = off; 107 return i2c_smbus_write_word_swapped(data->client, 108 TMP117_REG_TEMP_OFFSET, off); 109 110 default: 111 return -EINVAL; 112 } 113 } 114 115 static const struct iio_chan_spec tmp117_channels[] = { 116 { 117 .type = IIO_TEMP, 118 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 119 BIT(IIO_CHAN_INFO_CALIBBIAS) | 120 BIT(IIO_CHAN_INFO_SCALE), 121 }, 122 }; 123 124 static const struct iio_chan_spec tmp116_channels[] = { 125 { 126 .type = IIO_TEMP, 127 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 128 BIT(IIO_CHAN_INFO_SCALE), 129 }, 130 }; 131 132 static const struct tmp11x_info tmp116_channels_info = { 133 .name = "tmp116", 134 .channels = tmp116_channels, 135 .num_channels = ARRAY_SIZE(tmp116_channels) 136 }; 137 138 static const struct tmp11x_info tmp117_channels_info = { 139 .name = "tmp117", 140 .channels = tmp117_channels, 141 .num_channels = ARRAY_SIZE(tmp117_channels) 142 }; 143 144 static const struct tmp11x_info tmp119_channels_info = { 145 .name = "tmp119", 146 .channels = tmp117_channels, 147 .num_channels = ARRAY_SIZE(tmp117_channels) 148 }; 149 150 static const struct iio_info tmp117_info = { 151 .read_raw = tmp117_read_raw, 152 .write_raw = tmp117_write_raw, 153 }; 154 155 static int tmp117_probe(struct i2c_client *client) 156 { 157 const struct tmp11x_info *match_data; 158 struct tmp117_data *data; 159 struct iio_dev *indio_dev; 160 int dev_id; 161 int ret; 162 163 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 164 return -EOPNOTSUPP; 165 166 ret = devm_regulator_get_enable(&client->dev, "vcc"); 167 if (ret) 168 return ret; 169 170 fsleep(1500); 171 172 dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID); 173 if (dev_id < 0) 174 return dev_id; 175 176 switch (dev_id) { 177 case TMP116_DEVICE_ID: 178 match_data = &tmp116_channels_info; 179 break; 180 case TMP117_DEVICE_ID: 181 match_data = &tmp117_channels_info; 182 break; 183 case TMP119_DEVICE_ID: 184 match_data = &tmp119_channels_info; 185 break; 186 default: 187 dev_info(&client->dev, 188 "Unknown device id (0x%x), use fallback compatible\n", 189 dev_id); 190 match_data = i2c_get_match_data(client); 191 } 192 193 if (!match_data) 194 return dev_err_probe(&client->dev, -ENODEV, 195 "Failed to identify unsupported device\n"); 196 197 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 198 if (!indio_dev) 199 return -ENOMEM; 200 201 data = iio_priv(indio_dev); 202 data->client = client; 203 data->calibbias = 0; 204 205 indio_dev->modes = INDIO_DIRECT_MODE; 206 indio_dev->info = &tmp117_info; 207 indio_dev->channels = match_data->channels; 208 indio_dev->num_channels = match_data->num_channels; 209 indio_dev->name = match_data->name; 210 211 212 return devm_iio_device_register(&client->dev, indio_dev); 213 } 214 215 static const struct of_device_id tmp117_of_match[] = { 216 { .compatible = "ti,tmp116", .data = &tmp116_channels_info }, 217 { .compatible = "ti,tmp117", .data = &tmp117_channels_info }, 218 { .compatible = "ti,tmp119", .data = &tmp119_channels_info }, 219 { } 220 }; 221 MODULE_DEVICE_TABLE(of, tmp117_of_match); 222 223 static const struct i2c_device_id tmp117_id[] = { 224 { .name = "tmp116", .driver_data = (kernel_ulong_t)&tmp116_channels_info }, 225 { .name = "tmp117", .driver_data = (kernel_ulong_t)&tmp117_channels_info }, 226 { .name = "tmp119", .driver_data = (kernel_ulong_t)&tmp119_channels_info }, 227 { } 228 }; 229 MODULE_DEVICE_TABLE(i2c, tmp117_id); 230 231 static struct i2c_driver tmp117_driver = { 232 .driver = { 233 .name = "tmp117", 234 .of_match_table = tmp117_of_match, 235 }, 236 .probe = tmp117_probe, 237 .id_table = tmp117_id, 238 }; 239 module_i2c_driver(tmp117_driver); 240 241 MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>"); 242 MODULE_DESCRIPTION("TI TMP117 Temperature sensor driver"); 243 MODULE_LICENSE("GPL"); 244