tmp102.c 8.0 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
#include <linux/jiffies.h>
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

#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;
54
	u16 config_orig;
55 56 57 58
	unsigned long last_update;
	int temp[3];
};

J
Jean Delvare 已提交
59 60
/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
static inline int tmp102_reg_to_mC(s16 val)
61
{
J
Jean Delvare 已提交
62
	return ((val & ~0x01) * 1000) / 128;
63 64
}

J
Jean Delvare 已提交
65 66
/* convert milliCelsius to left adjusted 13-bit TMP102 register value */
static inline u16 tmp102_mC_to_reg(int val)
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
{
	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 已提交
82
	if (time_after(jiffies, tmp102->last_update + HZ / 3)) {
83 84
		int i;
		for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) {
85 86
			int status = i2c_smbus_read_word_swapped(client,
								 tmp102_reg[i]);
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
			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 已提交
114
	int status;
115

116
	if (kstrtol(buf, 10, &val) < 0)
117
		return -EINVAL;
J
Jean Delvare 已提交
118 119
	val = SENSORS_LIMIT(val, -256000, 255000);

120
	mutex_lock(&tmp102->lock);
J
Jean Delvare 已提交
121
	tmp102->temp[sda->index] = val;
122 123
	status = i2c_smbus_write_word_swapped(client, tmp102_reg[sda->index],
					      tmp102_mC_to_reg(val));
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	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 已提交
156
	if (!i2c_check_functionality(client->adapter,
157
				     I2C_FUNC_SMBUS_WORD_DATA)) {
L
Lucas De Marchi 已提交
158
		dev_err(&client->dev, "adapter doesn't support SMBus word "
J
Jean Delvare 已提交
159
			"transactions\n");
160 161 162
		return -ENODEV;
	}

163 164
	tmp102 = devm_kzalloc(&client->dev, sizeof(*tmp102), GFP_KERNEL);
	if (!tmp102)
165
		return -ENOMEM;
166

167 168
	i2c_set_clientdata(client, tmp102);

169
	status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
170 171
	if (status < 0) {
		dev_err(&client->dev, "error reading config register\n");
172
		return status;
173 174
	}
	tmp102->config_orig = status;
175 176
	status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
					      TMP102_CONFIG);
J
Jean Delvare 已提交
177 178
	if (status < 0) {
		dev_err(&client->dev, "error writing config register\n");
179
		goto fail_restore_config;
J
Jean Delvare 已提交
180
	}
181
	status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
182
	if (status < 0) {
J
Jean Delvare 已提交
183
		dev_err(&client->dev, "error reading config register\n");
184
		goto fail_restore_config;
185 186 187
	}
	status &= ~TMP102_CONFIG_RD_ONLY;
	if (status != TMP102_CONFIG) {
J
Jean Delvare 已提交
188 189
		dev_err(&client->dev, "config settings did not stick\n");
		status = -ENODEV;
190
		goto fail_restore_config;
191 192 193 194 195 196 197
	}
	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");
198
		goto fail_restore_config;
199 200 201 202 203
	}
	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);
204
		goto fail_remove_sysfs;
205 206 207 208 209
	}

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

	return 0;
210 211

fail_remove_sysfs:
212
	sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
213
fail_restore_config:
214 215
	i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
				     tmp102->config_orig);
J
Jean Delvare 已提交
216
	return status;
217 218 219 220 221 222 223 224
}

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

	hwmon_device_unregister(tmp102->hwmon_dev);
	sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
225 226 227 228 229

	/* Stop monitoring if device was stopped originally */
	if (tmp102->config_orig & TMP102_CONF_SD) {
		int config;

230
		config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
231
		if (config >= 0)
232 233
			i2c_smbus_write_word_swapped(client, TMP102_CONF_REG,
						     config | TMP102_CONF_SD);
234 235
	}

236 237 238 239 240 241 242
	return 0;
}

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

245
	config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
246 247
	if (config < 0)
		return config;
248

249
	config |= TMP102_CONF_SD;
250
	return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config);
251 252 253 254 255
}

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

258
	config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG);
259 260
	if (config < 0)
		return config;
261

262
	config &= ~TMP102_CONF_SD;
263
	return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config);
264 265 266 267 268 269 270 271 272 273 274 275 276
}

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 已提交
277
	{ "tmp102", 0 },
278 279
	{ }
};
J
Jean Delvare 已提交
280
MODULE_DEVICE_TABLE(i2c, tmp102_id);
281 282 283 284 285

static struct i2c_driver tmp102_driver = {
	.driver.name	= DRIVER_NAME,
	.driver.pm	= TMP102_DEV_PM_OPS,
	.probe		= tmp102_probe,
B
Bill Pemberton 已提交
286
	.remove		= tmp102_remove,
287 288 289
	.id_table	= tmp102_id,
};

290
module_i2c_driver(tmp102_driver);
291 292 293 294

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