tmp102.c 7.8 KB
Newer Older
J
Jean Delvare 已提交
1
/* Texas Instruments TMP102 SMBus temperature sensor driver
2
 *
J
Jean Delvare 已提交
3
 * Copyright (C) 2010 Steven King <sfking@fdwdc.com>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
J
Jean Delvare 已提交
28
#include <linux/device.h>
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

#define	DRIVER_NAME "tmp102"

#define	TMP102_TEMP_REG			0x00
#define	TMP102_CONF_REG			0x01
/* note: these bit definitions are byte swapped */
#define		TMP102_CONF_SD		0x0100
#define		TMP102_CONF_TM		0x0200
#define		TMP102_CONF_POL		0x0400
#define		TMP102_CONF_F0		0x0800
#define		TMP102_CONF_F1		0x1000
#define		TMP102_CONF_R0		0x2000
#define		TMP102_CONF_R1		0x4000
#define		TMP102_CONF_OS		0x8000
#define		TMP102_CONF_EM		0x0010
#define		TMP102_CONF_AL		0x0020
#define		TMP102_CONF_CR0		0x0040
#define		TMP102_CONF_CR1		0x0080
#define	TMP102_TLOW_REG			0x02
#define	TMP102_THIGH_REG		0x03

struct tmp102 {
	struct device *hwmon_dev;
	struct mutex lock;
	unsigned long last_update;
	int temp[3];
};

J
Jean Delvare 已提交
57 58 59
/* SMBus specifies low byte first, but the TMP102 returns high byte first,
 * so we have to swab16 the values */
static inline int tmp102_read_reg(struct i2c_client *client, u8 reg)
60 61 62 63 64
{
	int result = i2c_smbus_read_word_data(client, reg);
	return result < 0 ? result : swab16(result);
}

J
Jean Delvare 已提交
65
static inline int tmp102_write_reg(struct i2c_client *client, u8 reg, u16 val)
66 67 68 69
{
	return i2c_smbus_write_word_data(client, reg, swab16(val));
}

J
Jean Delvare 已提交
70 71
/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
static inline int tmp102_reg_to_mC(s16 val)
72
{
J
Jean Delvare 已提交
73
	return ((val & ~0x01) * 1000) / 128;
74 75
}

J
Jean Delvare 已提交
76 77
/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
static inline u16 tmp102_mC_to_reg(int val)
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
	return (val * 128) / 1000;
}

static const u8 tmp102_reg[] = {
	TMP102_TEMP_REG,
	TMP102_TLOW_REG,
	TMP102_THIGH_REG,
};

static struct tmp102 *tmp102_update_device(struct i2c_client *client)
{
	struct tmp102 *tmp102 = i2c_get_clientdata(client);

	mutex_lock(&tmp102->lock);
J
Jean Delvare 已提交
93
	if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
		int i;
		for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
			int status = tmp102_read_reg(client, tmp102_reg[i]);
			if (status > -1)
				tmp102->temp[i] = tmp102_reg_to_mC(status);
		}
		tmp102->last_update = jiffies;
	}
	mutex_unlock(&tmp102->lock);
	return tmp102;
}

static ssize_t tmp102_show_temp(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
	struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));

	return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
}

static ssize_t tmp102_set_temp(struct device *dev,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
{
	struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
	struct i2c_client *client = to_i2c_client(dev);
	struct tmp102 *tmp102 = i2c_get_clientdata(client);
	long val;
J
Jean Delvare 已提交
124
	int status;
125

J
Jean Delvare 已提交
126
	if (strict_strtol(buf, 10, &val) < 0)
127
		return -EINVAL;
J
Jean Delvare 已提交
128 129
	val = SENSORS_LIMIT(val, -256000, 255000);

130
	mutex_lock(&tmp102->lock);
J
Jean Delvare 已提交
131 132 133
	tmp102->temp[sda->index] = val;
	status = tmp102_write_reg(client, tmp102_reg[sda->index],
				  tmp102_mC_to_reg(val));
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	mutex_unlock(&tmp102->lock);
	return status ? : count;
}

static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0);

static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp,
			  tmp102_set_temp, 1);

static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp,
			  tmp102_set_temp, 2);

static struct attribute *tmp102_attributes[] = {
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
	&sensor_dev_attr_temp1_max.dev_attr.attr,
	NULL
};

static const struct attribute_group tmp102_attr_group = {
	.attrs = tmp102_attributes,
};

#define TMP102_CONFIG  (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1)
#define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL)

static int __devinit tmp102_probe(struct i2c_client *client,
				  const struct i2c_device_id *id)
{
	struct tmp102 *tmp102;
	int status;

J
Jean Delvare 已提交
166
	if (!i2c_check_functionality(client->adapter,
167
				     I2C_FUNC_SMBUS_WORD_DATA)) {
J
Jean Delvare 已提交
168 169
		dev_err(&client->dev, "adapter doesnt support SMBus word "
			"transactions\n");
170 171 172 173 174 175 176 177 178 179
		return -ENODEV;
	}

	tmp102 = kzalloc(sizeof(*tmp102), GFP_KERNEL);
	if (!tmp102) {
		dev_dbg(&client->dev, "kzalloc failed\n");
		return -ENOMEM;
	}
	i2c_set_clientdata(client, tmp102);

J
Jean Delvare 已提交
180 181 182 183 184
	status = tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);
	if (status < 0) {
		dev_err(&client->dev, "error writing config register\n");
		goto fail0;
	}
185 186
	status = tmp102_read_reg(client, TMP102_CONF_REG);
	if (status < 0) {
J
Jean Delvare 已提交
187
		dev_err(&client->dev, "error reading config register\n");
188 189 190 191
		goto fail0;
	}
	status &= ~TMP102_CONFIG_RD_ONLY;
	if (status != TMP102_CONFIG) {
J
Jean Delvare 已提交
192 193
		dev_err(&client->dev, "config settings did not stick\n");
		status = -ENODEV;
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
		goto fail0;
	}
	tmp102->last_update = jiffies - HZ;
	mutex_init(&tmp102->lock);

	status = sysfs_create_group(&client->dev.kobj, &tmp102_attr_group);
	if (status) {
		dev_dbg(&client->dev, "could not create sysfs files\n");
		goto fail0;
	}
	tmp102->hwmon_dev = hwmon_device_register(&client->dev);
	if (IS_ERR(tmp102->hwmon_dev)) {
		dev_dbg(&client->dev, "unable to register hwmon device\n");
		status = PTR_ERR(tmp102->hwmon_dev);
		goto fail1;
	}

	dev_info(&client->dev, "initialized\n");

	return 0;
fail1:
	sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
fail0:
	i2c_set_clientdata(client, NULL);
	kfree(tmp102);

J
Jean Delvare 已提交
220
	return status;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
}

static int __devexit tmp102_remove(struct i2c_client *client)
{
	struct tmp102 *tmp102 = i2c_get_clientdata(client);

	/* shutdown the chip */
	tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONF_SD);

	hwmon_device_unregister(tmp102->hwmon_dev);
	sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
	i2c_set_clientdata(client, NULL);
	kfree(tmp102);

	return 0;
}

#ifdef CONFIG_PM
static int tmp102_suspend(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);

	tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONF_SD);

	return 0;
}

static int tmp102_resume(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);

	tmp102_write_reg(client, TMP102_CONF_REG, TMP102_CONFIG);

	return 0;
}

static const struct dev_pm_ops tmp102_dev_pm_ops = {
	.suspend	= tmp102_suspend,
	.resume		= tmp102_resume,
};

#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
#else
#define	TMP102_DEV_PM_OPS NULL
#endif /* CONFIG_PM */

static const struct i2c_device_id tmp102_id[] = {
J
Jean Delvare 已提交
268
	{ "tmp102", 0 },
269 270
	{ }
};
J
Jean Delvare 已提交
271
MODULE_DEVICE_TABLE(i2c, tmp102_id);
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

static struct i2c_driver tmp102_driver = {
	.driver.name	= DRIVER_NAME,
	.driver.pm	= TMP102_DEV_PM_OPS,
	.probe		= tmp102_probe,
	.remove		= __devexit_p(tmp102_remove),
	.id_table	= tmp102_id,
};

static int __init tmp102_init(void)
{
	return i2c_add_driver(&tmp102_driver);
}
module_init(tmp102_init);

static void __exit tmp102_exit(void)
{
	i2c_del_driver(&tmp102_driver);
}
module_exit(tmp102_exit);

MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
MODULE_DESCRIPTION("Texas Instruments TMP102 temperature sensor driver");
MODULE_LICENSE("GPL");