aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPer Dalén <per.dalen@appeartv.com>2011-04-06 14:29:44 -0400
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-05-19 11:19:32 -0400
commit83bffbce745795572d20f0109395cb61690c6dcf (patch)
tree1b57eaf9363e5dee1354c385372e50be3a11472a
parent61c4f2c81c61f73549928dfd9f3e8f26aa36a8cf (diff)
hwmon: Add support for MAX6642
MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor with Overtemperature Alarm from Maxim. Signed-off-by: Per Dalen <per.dalen@appeartv.com> Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
-rw-r--r--Documentation/hwmon/max664221
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/max6642.c356
4 files changed, 389 insertions, 0 deletions
diff --git a/Documentation/hwmon/max6642 b/Documentation/hwmon/max6642
new file mode 100644
index 000000000000..afbd3e4942e2
--- /dev/null
+++ b/Documentation/hwmon/max6642
@@ -0,0 +1,21 @@
1Kernel driver max6642
2=====================
3
4Supported chips:
5 * Maxim MAX6642
6 Prefix: 'max6642'
7 Addresses scanned: I2C 0x48-0x4f
8 Datasheet: Publicly available at the Maxim website
9 http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
10
11Authors:
12 Per Dalen <per.dalen@appeartv.com>
13
14Description
15-----------
16
17The MAX6642 is a digital temperature sensor. It senses its own temperature as
18well as the temperature on one external diode.
19
20All temperature values are given in degrees Celsius. Resolution
21is 0.25 degree for the local temperature and for the remote temperature.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 50e40dbd8bb6..f2d48777c508 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -727,6 +727,17 @@ config SENSORS_MAX6639
727 This driver can also be built as a module. If so, the module 727 This driver can also be built as a module. If so, the module
728 will be called max6639. 728 will be called max6639.
729 729
730config SENSORS_MAX6642
731 tristate "Maxim MAX6642 sensor chip"
732 depends on I2C && EXPERIMENTAL
733 help
734 If you say yes here you get support for MAX6642 sensor chip.
735 MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
736 with Overtemperature Alarm from Maxim.
737
738 This driver can also be built as a module. If so, the module
739 will be called max6642.
740
730config SENSORS_MAX6650 741config SENSORS_MAX6650
731 tristate "Maxim MAX6650 sensor chip" 742 tristate "Maxim MAX6650 sensor chip"
732 depends on I2C && EXPERIMENTAL 743 depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 967d0ea9447f..2211752d73b6 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
85obj-$(CONFIG_SENSORS_MAX1111) += max1111.o 85obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
86obj-$(CONFIG_SENSORS_MAX1619) += max1619.o 86obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
87obj-$(CONFIG_SENSORS_MAX6639) += max6639.o 87obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
88obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
88obj-$(CONFIG_SENSORS_MAX6650) += max6650.o 89obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
89obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o 90obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
90obj-$(CONFIG_SENSORS_PC87360) += pc87360.o 91obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
new file mode 100644
index 000000000000..0f9fc40379cd
--- /dev/null
+++ b/drivers/hwmon/max6642.c
@@ -0,0 +1,356 @@
1/*
2 * Driver for +/-1 degree C, SMBus-Compatible Remote/Local Temperature Sensor
3 * with Overtemperature Alarm
4 *
5 * Copyright (C) 2011 AppearTV AS
6 *
7 * Derived from:
8 *
9 * Based on the max1619 driver.
10 * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
11 * Jean Delvare <khali@linux-fr.org>
12 *
13 * The MAX6642 is a sensor chip made by Maxim.
14 * It reports up to two temperatures (its own plus up to
15 * one external one). Complete datasheet can be
16 * obtained from Maxim's website at:
17 * http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
34
35#include <linux/module.h>
36#include <linux/init.h>
37#include <linux/slab.h>
38#include <linux/jiffies.h>
39#include <linux/i2c.h>
40#include <linux/hwmon.h>
41#include <linux/hwmon-sysfs.h>
42#include <linux/err.h>
43#include <linux/mutex.h>
44#include <linux/sysfs.h>
45
46static const unsigned short normal_i2c[] = {
47 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
48
49/*
50 * The MAX6642 registers
51 */
52
53#define MAX6642_REG_R_MAN_ID 0xFE
54#define MAX6642_REG_R_CONFIG 0x03
55#define MAX6642_REG_W_CONFIG 0x09
56#define MAX6642_REG_R_STATUS 0x02
57#define MAX6642_REG_R_LOCAL_TEMP 0x00
58#define MAX6642_REG_R_LOCAL_TEMPL 0x11
59#define MAX6642_REG_R_LOCAL_HIGH 0x05
60#define MAX6642_REG_W_LOCAL_HIGH 0x0B
61#define MAX6642_REG_R_REMOTE_TEMP 0x01
62#define MAX6642_REG_R_REMOTE_TEMPL 0x10
63#define MAX6642_REG_R_REMOTE_HIGH 0x07
64#define MAX6642_REG_W_REMOTE_HIGH 0x0D
65
66/*
67 * Conversions
68 */
69
70static int temp_from_reg10(int val)
71{
72 return val * 250;
73}
74
75static int temp_from_reg(int val)
76{
77 return val * 1000;
78}
79
80static int temp_to_reg(int val)
81{
82 return val / 1000;
83}
84
85/*
86 * Client data (each client gets its own)
87 */
88
89struct max6642_data {
90 struct device *hwmon_dev;
91 struct mutex update_lock;
92 bool valid; /* zero until following fields are valid */
93 unsigned long last_updated; /* in jiffies */
94
95 /* registers values */
96 u16 temp_input[2]; /* local/remote */
97 u16 temp_high[2]; /* local/remote */
98 u8 alarms;
99};
100
101/*
102 * Real code
103 */
104
105static void max6642_init_client(struct i2c_client *client)
106{
107 u8 config;
108 struct max6642_data *data = i2c_get_clientdata(client);
109
110 /*
111 * Start the conversions.
112 */
113 config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
114 if (config & 0x40)
115 i2c_smbus_write_byte_data(client, MAX6642_REG_W_CONFIG,
116 config & 0xBF); /* run */
117
118 data->temp_high[0] = i2c_smbus_read_byte_data(client,
119 MAX6642_REG_R_LOCAL_HIGH);
120 data->temp_high[1] = i2c_smbus_read_byte_data(client,
121 MAX6642_REG_R_REMOTE_HIGH);
122}
123
124/* Return 0 if detection is successful, -ENODEV otherwise */
125static int max6642_detect(struct i2c_client *client,
126 struct i2c_board_info *info)
127{
128 struct i2c_adapter *adapter = client->adapter;
129 u8 reg_config, reg_status, man_id;
130
131 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
132 return -ENODEV;
133
134 /* identification */
135 man_id = i2c_smbus_read_byte_data(client, MAX6642_REG_R_MAN_ID);
136 if (man_id != 0x4D)
137 return -ENODEV;
138
139 /*
140 * We read the config and status register, the 4 lower bits in the
141 * config register should be zero and bit 5, 3, 1 and 0 should be
142 * zero in the status register.
143 */
144 reg_config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
145 reg_status = i2c_smbus_read_byte_data(client, MAX6642_REG_R_STATUS);
146 if (((reg_config & 0x0f) != 0x00) ||
147 ((reg_status & 0x2b) != 0x00))
148 return -ENODEV;
149
150 strlcpy(info->type, "max6642", I2C_NAME_SIZE);
151
152 return 0;
153}
154
155static struct max6642_data *max6642_update_device(struct device *dev)
156{
157 struct i2c_client *client = to_i2c_client(dev);
158 struct max6642_data *data = i2c_get_clientdata(client);
159 u16 val, tmp;
160
161 mutex_lock(&data->update_lock);
162
163 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
164 dev_dbg(&client->dev, "Updating max6642 data.\n");
165 val = i2c_smbus_read_byte_data(client,
166 MAX6642_REG_R_LOCAL_TEMPL);
167 tmp = (val >> 6) & 3;
168 val = i2c_smbus_read_byte_data(client,
169 MAX6642_REG_R_LOCAL_TEMP);
170 val = (val << 2) | tmp;
171 data->temp_input[0] = val;
172 val = i2c_smbus_read_byte_data(client,
173 MAX6642_REG_R_REMOTE_TEMPL);
174 tmp = (val >> 6) & 3;
175 val = i2c_smbus_read_byte_data(client,
176 MAX6642_REG_R_REMOTE_TEMP);
177 val = (val << 2) | tmp;
178 data->temp_input[1] = val;
179 data->alarms = i2c_smbus_read_byte_data(client,
180 MAX6642_REG_R_STATUS);
181
182 data->last_updated = jiffies;
183 data->valid = 1;
184 }
185
186 mutex_unlock(&data->update_lock);
187
188 return data;
189}
190
191/*
192 * Sysfs stuff
193 */
194
195static ssize_t show_temp_max10(struct device *dev,
196 struct device_attribute *dev_attr, char *buf)
197{
198 struct max6642_data *data = max6642_update_device(dev);
199 struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
200
201 return sprintf(buf, "%d\n",
202 temp_from_reg10(data->temp_input[attr->index]));
203}
204
205static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
206 char *buf)
207{
208 struct max6642_data *data = max6642_update_device(dev);
209 struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
210
211 return sprintf(buf, "%d\n", temp_from_reg(data->temp_high[attr2->nr]));
212}
213
214static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
215 const char *buf, size_t count)
216{
217 unsigned long val;
218 int err;
219 struct i2c_client *client = to_i2c_client(dev);
220 struct max6642_data *data = i2c_get_clientdata(client);
221 struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
222
223 err = strict_strtoul(buf, 10, &val);
224 if (err < 0)
225 return err;
226
227 mutex_lock(&data->update_lock);
228 data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
229 i2c_smbus_write_byte_data(client, attr2->index,
230 data->temp_high[attr2->nr]);
231 mutex_unlock(&data->update_lock);
232 return count;
233}
234
235static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
236 char *buf)
237{
238 int bitnr = to_sensor_dev_attr(attr)->index;
239 struct max6642_data *data = max6642_update_device(dev);
240 return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
241}
242
243static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_max10, NULL, 0);
244static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_max10, NULL, 1);
245static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
246 set_temp_max, 0, MAX6642_REG_W_LOCAL_HIGH);
247static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
248 set_temp_max, 1, MAX6642_REG_W_REMOTE_HIGH);
249static SENSOR_DEVICE_ATTR(temp_fault, S_IRUGO, show_alarm, NULL, 2);
250static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
251static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
252
253static struct attribute *max6642_attributes[] = {
254 &sensor_dev_attr_temp1_input.dev_attr.attr,
255 &sensor_dev_attr_temp2_input.dev_attr.attr,
256 &sensor_dev_attr_temp1_max.dev_attr.attr,
257 &sensor_dev_attr_temp2_max.dev_attr.attr,
258
259 &sensor_dev_attr_temp_fault.dev_attr.attr,
260 &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
261 &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
262 NULL
263};
264
265static const struct attribute_group max6642_group = {
266 .attrs = max6642_attributes,
267};
268
269static int max6642_probe(struct i2c_client *new_client,
270 const struct i2c_device_id *id)
271{
272 struct max6642_data *data;
273 int err;
274
275 data = kzalloc(sizeof(struct max6642_data), GFP_KERNEL);
276 if (!data) {
277 err = -ENOMEM;
278 goto exit;
279 }
280
281 i2c_set_clientdata(new_client, data);
282 mutex_init(&data->update_lock);
283
284 /* Initialize the MAX6642 chip */
285 max6642_init_client(new_client);
286
287 /* Register sysfs hooks */
288 err = sysfs_create_group(&new_client->dev.kobj, &max6642_group);
289 if (err)
290 goto exit_free;
291
292 data->hwmon_dev = hwmon_device_register(&new_client->dev);
293 if (IS_ERR(data->hwmon_dev)) {
294 err = PTR_ERR(data->hwmon_dev);
295 goto exit_remove_files;
296 }
297
298 return 0;
299
300exit_remove_files:
301 sysfs_remove_group(&new_client->dev.kobj, &max6642_group);
302exit_free:
303 kfree(data);
304exit:
305 return err;
306}
307
308static int max6642_remove(struct i2c_client *client)
309{
310 struct max6642_data *data = i2c_get_clientdata(client);
311
312 hwmon_device_unregister(data->hwmon_dev);
313 sysfs_remove_group(&client->dev.kobj, &max6642_group);
314
315 kfree(data);
316 return 0;
317}
318
319/*
320 * Driver data (common to all clients)
321 */
322
323static const struct i2c_device_id max6642_id[] = {
324 { "max6642", 0 },
325 { }
326};
327MODULE_DEVICE_TABLE(i2c, max6642_id);
328
329static struct i2c_driver max6642_driver = {
330 .class = I2C_CLASS_HWMON,
331 .driver = {
332 .name = "max6642",
333 },
334 .probe = max6642_probe,
335 .remove = max6642_remove,
336 .id_table = max6642_id,
337 .detect = max6642_detect,
338 .address_list = normal_i2c,
339};
340
341static int __init max6642_init(void)
342{
343 return i2c_add_driver(&max6642_driver);
344}
345
346static void __exit max6642_exit(void)
347{
348 i2c_del_driver(&max6642_driver);
349}
350
351MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
352MODULE_DESCRIPTION("MAX6642 sensor driver");
353MODULE_LICENSE("GPL");
354
355module_init(max6642_init);
356module_exit(max6642_exit);