11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
219f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
319f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck *	      monitoring
419f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
519f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
619f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
77c81c60f3789a082e141d7a013392af5f78db16aJean Delvare * the help of Jean Delvare <jdelvare@suse.de>
819f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck *
9cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * The DS1621 device is a digital temperature/thermometer with 9-bit
10cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * resolution, a thermal alarm output (Tout), and user-defined minimum
11cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * and maximum temperature thresholds (TH and TL).
12cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
13260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulson * The DS1625, DS1631, DS1721, and DS1731 are pin compatible with the DS1621
14260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulson * and similar in operation, with slight variations as noted in the device
15cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * datasheets (please refer to www.maximintegrated.com for specific
16cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * device information).
17cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
18cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * Since the DS1621 was the first chipset supported by this driver,
19cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * most comments will refer to this chipset, but are actually general
20cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * and concern all supported chipsets, unless mentioned otherwise.
21cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
2219f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * This program is free software; you can redistribute it and/or modify
2319f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * it under the terms of the GNU General Public License as published by
2419f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * the Free Software Foundation; either version 2 of the License, or
2519f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * (at your option) any later version.
2619f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck *
2719f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * This program is distributed in the hope that it will be useful,
2819f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of
2919f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3019f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * GNU General Public License for more details.
3119f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck *
3219f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * You should have received a copy of the GNU General Public License
3319f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * along with this program; if not, write to the Free Software
3419f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3519f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
42943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h>
4346a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare#include <linux/hwmon-sysfs.h>
44943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h>
459a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h>
46a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare#include <linux/sysfs.h>
47cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#include <linux/kernel.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
49cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson/* Supported devices */
50260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulsonenum chips { ds1621, ds1625, ds1631, ds1721, ds1731 };
51cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Insmod parameters */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int polarity = -1;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(polarity, int, 0);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson/*
58cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * The Configuration/Status register
59cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
60cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * - DS1621:
61cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *   7    6    5    4    3    2    1    0
62cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * |Done|THF |TLF |NVB | X  | X  |POL |1SHOT|
63cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
64cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * - DS1625:
65cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *   7    6    5    4    3    2    1    0
66cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * |Done|THF |TLF |NVB | 1  | 0  |POL |1SHOT|
67cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
68260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulson * - DS1631, DS1731:
6979c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson *   7    6    5    4    3    2    1    0
7079c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson * |Done|THF |TLF |NVB | R1 | R0 |POL |1SHOT|
7179c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson *
72cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * - DS1721:
73cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *   7    6    5    4    3    2    1    0
74cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * |Done| X  | X  | U  | R1 | R0 |POL |1SHOT|
75cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson *
76cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * Where:
77cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * - 'X' is Reserved
78cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * - 'U' is Undefined
79cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_REG_CONFIG_NVB		0x10
81cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1621_REG_CONFIG_RESOL		0x0C
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_REG_CONFIG_POLARITY	0x02
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_REG_CONFIG_1SHOT		0x01
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_REG_CONFIG_DONE		0x80
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
86cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1621_REG_CONFIG_RESOL_SHIFT	2
87cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
88cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson/* ds1721 conversion rates: {C/LSB, time(ms), resolution bit setting} */
89cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulsonstatic const unsigned short ds1721_convrates[] = {
90cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	94,	/*  9-bits (0.5,  93.75, RES[0..1] = 0 */
91cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	188,	/* 10-bits (0.25, 187.5, RES[0..1] = 1 */
92cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	375,	/* 11-bits (0.125,  375, RES[0..1] = 2 */
93cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	750,	/* 12-bits (0.0625, 750, RES[0..1] = 3 */
94cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson};
95cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
96cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1621_CONVERSION_MAX	750
97cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1625_CONVERSION_MAX	500
98cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
99cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1621_TEMP_MAX	125000
100cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1621_TEMP_MIN	(-55000)
101cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
102cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson/* The DS1621 temperature registers */
10346a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic const u8 DS1621_REG_TEMP[3] = {
10446a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	0xAA,		/* input, word, RO */
10546a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	0xA2,		/* min, word, RW */
10646a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	0xA1,		/* max, word, RW */
10746a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare};
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_REG_CONF			0xAC /* byte, RW */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_COM_START		0xEE /* no data */
110cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson#define DS1721_COM_START		0x51 /* no data */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_COM_STOP			0x22 /* no data */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The DS1621 configuration register */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_ALARM_TEMP_HIGH		0x40
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DS1621_ALARM_TEMP_LOW		0x20
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11775819f01af77d6d70abc7777e450a0848a9b898bJean Delvare/* Conversions */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALARMS_FROM_REG(val) ((val) & \
11919f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck			(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Each client has this additional data */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ds1621_data {
1238269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct i2c_client *client;
1249a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar	struct mutex update_lock;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char valid;			/* !=0 if following fields are valid */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long last_updated;	/* In jiffies */
127cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	enum chips kind;		/* device type */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12946a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	u16 temp[3];			/* Register values, word */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 conf;			/* Register encoding, combined */
131a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck	u8 zbits;			/* Resolution encoded as number of
132a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck					 * zero bits */
133cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	u16 update_interval;		/* Conversion rate in milliseconds */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
136cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulsonstatic inline int DS1621_TEMP_FROM_REG(u16 reg)
137cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson{
138cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	return DIV_ROUND_CLOSEST(((s16)reg / 16) * 625, 10);
139cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson}
140cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
141cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson/*
142cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * TEMP: 0.001C/bit (-55C to +125C)
143cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson * REG:
144a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck *  - 1621, 1625: 0.5C/bit, 7 zero-bits
145a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck *  - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits
146cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson */
147a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeckstatic inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits)
148cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson{
149a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck	temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX);
150a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck	temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
151a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck	return temp;
152cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson}
153cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
1548269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeckstatic void ds1621_init_client(struct ds1621_data *data,
1558269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck			       struct i2c_client *client)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
157cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	u8 conf, new_conf, sreg, resol;
158e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare
159e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare	new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
16044bbe87e9017efa050bb1b506c6822f1f3bb94d7Steven Cole	/* switch to continuous conversion mode */
161e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare	new_conf &= ~DS1621_REG_CONFIG_1SHOT;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* setup output polarity */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (polarity == 0)
165e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare		new_conf &= ~DS1621_REG_CONFIG_POLARITY;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (polarity == 1)
167e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare		new_conf |= DS1621_REG_CONFIG_POLARITY;
16819f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck
169e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare	if (conf != new_conf)
170e4879e28abd67b894fb9d2db0afd08f1945670baJean Delvare		i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
17119f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck
172cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	switch (data->kind) {
173cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	case ds1625:
174cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		data->update_interval = DS1625_CONVERSION_MAX;
175a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck		data->zbits = 7;
176cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		sreg = DS1621_COM_START;
177cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		break;
17879c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson	case ds1631:
179cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	case ds1721:
180260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulson	case ds1731:
181cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		resol = (new_conf & DS1621_REG_CONFIG_RESOL) >>
182cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson			 DS1621_REG_CONFIG_RESOL_SHIFT;
183cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		data->update_interval = ds1721_convrates[resol];
184a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck		data->zbits = 7 - resol;
185cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		sreg = DS1721_COM_START;
186cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		break;
187cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	default:
188cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		data->update_interval = DS1621_CONVERSION_MAX;
189a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck		data->zbits = 7;
190cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		sreg = DS1621_COM_START;
191cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		break;
192cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	}
193cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start conversion */
195cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	i2c_smbus_write_byte(client, sreg);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1989202add67454c6a6f9508f41e733edce705dc56eJean Delvarestatic struct ds1621_data *ds1621_update_client(struct device *dev)
1999202add67454c6a6f9508f41e733edce705dc56eJean Delvare{
2008269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct ds1621_data *data = dev_get_drvdata(dev);
2018269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct i2c_client *client = data->client;
2029202add67454c6a6f9508f41e733edce705dc56eJean Delvare	u8 new_conf;
2039202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2049202add67454c6a6f9508f41e733edce705dc56eJean Delvare	mutex_lock(&data->update_lock);
2059202add67454c6a6f9508f41e733edce705dc56eJean Delvare
206cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	if (time_after(jiffies, data->last_updated + data->update_interval) ||
207cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	    !data->valid) {
2089202add67454c6a6f9508f41e733edce705dc56eJean Delvare		int i;
2099202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2109202add67454c6a6f9508f41e733edce705dc56eJean Delvare		dev_dbg(&client->dev, "Starting ds1621 update\n");
2119202add67454c6a6f9508f41e733edce705dc56eJean Delvare
212594592dc6f68356a3b7278eb4d260a50a66f0a06Jean Delvare		data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
2139202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2149202add67454c6a6f9508f41e733edce705dc56eJean Delvare		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
21590f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare			data->temp[i] = i2c_smbus_read_word_swapped(client,
216594592dc6f68356a3b7278eb4d260a50a66f0a06Jean Delvare							 DS1621_REG_TEMP[i]);
2179202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2189202add67454c6a6f9508f41e733edce705dc56eJean Delvare		/* reset alarms if necessary */
2199202add67454c6a6f9508f41e733edce705dc56eJean Delvare		new_conf = data->conf;
2209202add67454c6a6f9508f41e733edce705dc56eJean Delvare		if (data->temp[0] > data->temp[1])	/* input > min */
2219202add67454c6a6f9508f41e733edce705dc56eJean Delvare			new_conf &= ~DS1621_ALARM_TEMP_LOW;
2229202add67454c6a6f9508f41e733edce705dc56eJean Delvare		if (data->temp[0] < data->temp[2])	/* input < max */
2239202add67454c6a6f9508f41e733edce705dc56eJean Delvare			new_conf &= ~DS1621_ALARM_TEMP_HIGH;
2249202add67454c6a6f9508f41e733edce705dc56eJean Delvare		if (data->conf != new_conf)
225594592dc6f68356a3b7278eb4d260a50a66f0a06Jean Delvare			i2c_smbus_write_byte_data(client, DS1621_REG_CONF,
226594592dc6f68356a3b7278eb4d260a50a66f0a06Jean Delvare						  new_conf);
2279202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2289202add67454c6a6f9508f41e733edce705dc56eJean Delvare		data->last_updated = jiffies;
2299202add67454c6a6f9508f41e733edce705dc56eJean Delvare		data->valid = 1;
2309202add67454c6a6f9508f41e733edce705dc56eJean Delvare	}
2319202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2329202add67454c6a6f9508f41e733edce705dc56eJean Delvare	mutex_unlock(&data->update_lock);
2339202add67454c6a6f9508f41e733edce705dc56eJean Delvare
2349202add67454c6a6f9508f41e733edce705dc56eJean Delvare	return data;
2359202add67454c6a6f9508f41e733edce705dc56eJean Delvare}
2369202add67454c6a6f9508f41e733edce705dc56eJean Delvare
23746a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic ssize_t show_temp(struct device *dev, struct device_attribute *da,
23846a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare			 char *buf)
23946a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare{
24046a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
24146a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	struct ds1621_data *data = ds1621_update_client(dev);
24246a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	return sprintf(buf, "%d\n",
243cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson		       DS1621_TEMP_FROM_REG(data->temp[attr->index]));
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24646a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic ssize_t set_temp(struct device *dev, struct device_attribute *da,
24746a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare			const char *buf, size_t count)
24846a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare{
24946a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
2508269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct ds1621_data *data = dev_get_drvdata(dev);
25119f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck	long val;
25219f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck	int err;
25319f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck
25419f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck	err = kstrtol(buf, 10, &val);
25519f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck	if (err)
25619f2c05964dc428ef639fcda1cce7c8c3075c9ccGuenter Roeck		return err;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25846a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	mutex_lock(&data->update_lock);
259a50d9a4d9ad3c71341788099d733e4151b8a511bGuenter Roeck	data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits);
2608269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	i2c_smbus_write_word_swapped(data->client, DS1621_REG_TEMP[attr->index],
26190f4102ce59226954edbe960b2434d8b3da5f086Jean Delvare				     data->temp[attr->index]);
26246a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	mutex_unlock(&data->update_lock);
26346a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	return count;
26446a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26646a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic ssize_t show_alarms(struct device *dev, struct device_attribute *da,
26746a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare			   char *buf)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ds1621_data *data = ds1621_update_client(dev);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27387f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvarestatic ssize_t show_alarm(struct device *dev, struct device_attribute *da,
27487f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare			  char *buf)
27587f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare{
27687f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
27787f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare	struct ds1621_data *data = ds1621_update_client(dev);
27887f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare	return sprintf(buf, "%d\n", !!(data->conf & attr->index));
27987f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare}
28087f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare
2813a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulsonstatic ssize_t show_convrate(struct device *dev, struct device_attribute *da,
2823a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson			  char *buf)
2833a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson{
2848269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct ds1621_data *data = dev_get_drvdata(dev);
2853a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval);
2863a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson}
2873a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
2883a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulsonstatic ssize_t set_convrate(struct device *dev, struct device_attribute *da,
2893a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson			    const char *buf, size_t count)
2903a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson{
2918269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct ds1621_data *data = dev_get_drvdata(dev);
2928269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct i2c_client *client = data->client;
2933a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	unsigned long convrate;
2943a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	s32 err;
2953a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	int resol = 0;
2963a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
2973a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	err = kstrtoul(buf, 10, &convrate);
2983a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	if (err)
2993a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson		return err;
3003a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
3013a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	/* Convert rate into resolution bits */
3023a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	while (resol < (ARRAY_SIZE(ds1721_convrates) - 1) &&
3033a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	       convrate > ds1721_convrates[resol])
3043a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson		resol++;
3053a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
3063a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	mutex_lock(&data->update_lock);
3073a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
3083a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	data->conf &= ~DS1621_REG_CONFIG_RESOL;
3093a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT);
3103a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf);
3113a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	data->update_interval = ds1721_convrates[resol];
31239c627a084475e8a690a4a9e7601410ca173ddd2Robert Coulson	data->zbits = 7 - resol;
3133a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	mutex_unlock(&data->update_lock);
3143a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
3153a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	return count;
3163a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson}
3173a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
3193a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulsonstatic DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_convrate,
3203a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson		   set_convrate);
3213a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
32246a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
32346a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
32446a2e71ced949ecf238f796c178f85f03501ce88Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
32587f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
32687f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare		DS1621_ALARM_TEMP_LOW);
32787f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
32887f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare		DS1621_ALARM_TEMP_HIGH);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
330a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic struct attribute *ds1621_attributes[] = {
33146a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	&sensor_dev_attr_temp1_input.dev_attr.attr,
33246a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	&sensor_dev_attr_temp1_min.dev_attr.attr,
33346a2e71ced949ecf238f796c178f85f03501ce88Jean Delvare	&sensor_dev_attr_temp1_max.dev_attr.attr,
33487f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
33587f0f31baf9ea2cb273d7fb56b3ebf9df5096884Jean Delvare	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
336a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	&dev_attr_alarms.attr,
3373a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	&dev_attr_update_interval.attr,
338a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	NULL
339a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
340a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare
3413a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulsonstatic umode_t ds1621_attribute_visible(struct kobject *kobj,
3423a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson					struct attribute *attr, int index)
3433a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson{
3443a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	struct device *dev = container_of(kobj, struct device, kobj);
3458269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct ds1621_data *data = dev_get_drvdata(dev);
3463a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
3473a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	if (attr == &dev_attr_update_interval.attr)
34879c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson		if (data->kind == ds1621 || data->kind == ds1625)
3493a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson			/* shhh, we're hiding update_interval */
3503a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson			return 0;
3513a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	return attr->mode;
3523a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson}
3533a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson
354a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvarestatic const struct attribute_group ds1621_group = {
355a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare	.attrs = ds1621_attributes,
3563a8fe3315571e896489d2e271ffe7f935bfc5ce8Robert Coulson	.is_visible = ds1621_attribute_visible
357a5ebe668add5f76ed8f01f752b37cfa164a26a30Jean Delvare};
3580d36dce0f1d15a9ca55f893b3aa5ce7c297e11c8Guenter Roeck__ATTRIBUTE_GROUPS(ds1621);
3598269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck
36070313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvarestatic int ds1621_probe(struct i2c_client *client,
36170313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare			const struct i2c_device_id *id)
36270313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare{
36370313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare	struct ds1621_data *data;
3648269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	struct device *hwmon_dev;
36570313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare
366e20b4b38cdf1622d1577ae5e402ded2bd63bf616Guenter Roeck	data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data),
367e20b4b38cdf1622d1577ae5e402ded2bd63bf616Guenter Roeck			    GFP_KERNEL);
368e20b4b38cdf1622d1577ae5e402ded2bd63bf616Guenter Roeck	if (!data)
369e20b4b38cdf1622d1577ae5e402ded2bd63bf616Guenter Roeck		return -ENOMEM;
37070313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare
37170313eabfc63ce6aa89b9fa3074129e5c521568aJean Delvare	mutex_init(&data->update_lock);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
373cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	data->kind = id->driver_data;
3748269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	data->client = client;
375cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize the DS1621 chip */
3778269b75ae72c4501df7caf93d053526cef7e8a8aGuenter Roeck	ds1621_init_client(data, client);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3790d36dce0f1d15a9ca55f893b3aa5ce7c297e11c8Guenter Roeck	hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
3800d36dce0f1d15a9ca55f893b3aa5ce7c297e11c8Guenter Roeck							   client->name, data,
3810d36dce0f1d15a9ca55f893b3aa5ce7c297e11c8Guenter Roeck							   ds1621_groups);
38231ab1ad70b25f4e19f6442e8f6d68025ba43b942Fengguang Wu	return PTR_ERR_OR_ZERO(hwmon_dev);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3859202add67454c6a6f9508f41e733edce705dc56eJean Delvarestatic const struct i2c_device_id ds1621_id[] = {
386cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	{ "ds1621", ds1621 },
387cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	{ "ds1625", ds1625 },
38879c1cc1c90c0ccaddd20965ea19205c54addd5f7Robert Coulson	{ "ds1631", ds1631 },
389cd6c8a4297ad036a155966db49982d6807e23ef8Robert Coulson	{ "ds1721", ds1721 },
390260f81ffc1b9f09dde355caa09e4b312756666f0Robert Coulson	{ "ds1731", ds1731 },
3919202add67454c6a6f9508f41e733edce705dc56eJean Delvare	{ }
3929202add67454c6a6f9508f41e733edce705dc56eJean Delvare};
3939202add67454c6a6f9508f41e733edce705dc56eJean DelvareMODULE_DEVICE_TABLE(i2c, ds1621_id);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3959202add67454c6a6f9508f41e733edce705dc56eJean Delvare/* This is the driver that will be inserted */
3969202add67454c6a6f9508f41e733edce705dc56eJean Delvarestatic struct i2c_driver ds1621_driver = {
3979202add67454c6a6f9508f41e733edce705dc56eJean Delvare	.class		= I2C_CLASS_HWMON,
3989202add67454c6a6f9508f41e733edce705dc56eJean Delvare	.driver = {
3999202add67454c6a6f9508f41e733edce705dc56eJean Delvare		.name	= "ds1621",
4009202add67454c6a6f9508f41e733edce705dc56eJean Delvare	},
4019202add67454c6a6f9508f41e733edce705dc56eJean Delvare	.probe		= ds1621_probe,
4029202add67454c6a6f9508f41e733edce705dc56eJean Delvare	.id_table	= ds1621_id,
4039202add67454c6a6f9508f41e733edce705dc56eJean Delvare};
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
405f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(ds1621_driver);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("DS1621 driver");
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
410