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