xref: /openbmc/linux/drivers/hwmon/sht15.c (revision 9e5e9b7a)
1251eb40fSJonathan Cameron /*
2251eb40fSJonathan Cameron  * sht15.c - support for the SHT15 Temperature and Humidity Sensor
3251eb40fSJonathan Cameron  *
4edec5af7SVivien Didelot  * Portions Copyright (c) 2010-2012 Savoir-faire Linux Inc.
582c7465bSJerome Oufella  *          Jerome Oufella <jerome.oufella@savoirfairelinux.com>
6cc15c7ebSVivien Didelot  *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7cc15c7ebSVivien Didelot  *
8251eb40fSJonathan Cameron  * Copyright (c) 2009 Jonathan Cameron
9251eb40fSJonathan Cameron  *
10251eb40fSJonathan Cameron  * Copyright (c) 2007 Wouter Horre
11251eb40fSJonathan Cameron  *
12251eb40fSJonathan Cameron  * This program is free software; you can redistribute it and/or modify
13251eb40fSJonathan Cameron  * it under the terms of the GNU General Public License version 2 as
14251eb40fSJonathan Cameron  * published by the Free Software Foundation.
15251eb40fSJonathan Cameron  *
1699a0378dSVivien Didelot  * For further information, see the Documentation/hwmon/sht15 file.
17251eb40fSJonathan Cameron  */
18251eb40fSJonathan Cameron 
19251eb40fSJonathan Cameron #include <linux/interrupt.h>
20251eb40fSJonathan Cameron #include <linux/irq.h>
21251eb40fSJonathan Cameron #include <linux/gpio.h>
22251eb40fSJonathan Cameron #include <linux/module.h>
23251eb40fSJonathan Cameron #include <linux/init.h>
24251eb40fSJonathan Cameron #include <linux/hwmon.h>
25251eb40fSJonathan Cameron #include <linux/hwmon-sysfs.h>
26251eb40fSJonathan Cameron #include <linux/mutex.h>
27f9b693ebSVivien Didelot #include <linux/platform_data/sht15.h>
28251eb40fSJonathan Cameron #include <linux/platform_device.h>
29d43c36dcSAlexey Dobriyan #include <linux/sched.h>
30251eb40fSJonathan Cameron #include <linux/delay.h>
31251eb40fSJonathan Cameron #include <linux/jiffies.h>
32251eb40fSJonathan Cameron #include <linux/err.h>
33251eb40fSJonathan Cameron #include <linux/regulator/consumer.h>
345a0e3ad6STejun Heo #include <linux/slab.h>
3560063497SArun Sharma #include <linux/atomic.h>
36251eb40fSJonathan Cameron 
3799a0378dSVivien Didelot /* Commands */
3899a0378dSVivien Didelot #define SHT15_MEASURE_TEMP		0x03
3999a0378dSVivien Didelot #define SHT15_MEASURE_RH		0x05
40cc15c7ebSVivien Didelot #define SHT15_WRITE_STATUS		0x06
41cc15c7ebSVivien Didelot #define SHT15_READ_STATUS		0x07
42181148aeSVivien Didelot #define SHT15_SOFT_RESET		0x1E
43251eb40fSJonathan Cameron 
4499a0378dSVivien Didelot /* Min timings */
4599a0378dSVivien Didelot #define SHT15_TSCKL			100	/* (nsecs) clock low */
4699a0378dSVivien Didelot #define SHT15_TSCKH			100	/* (nsecs) clock high */
4799a0378dSVivien Didelot #define SHT15_TSU			150	/* (nsecs) data setup time */
48181148aeSVivien Didelot #define SHT15_TSRST			11	/* (msecs) soft reset time */
49251eb40fSJonathan Cameron 
50cc15c7ebSVivien Didelot /* Status Register Bits */
51cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_RESOLUTION	0x01
52cc15c7ebSVivien Didelot #define SHT15_STATUS_NO_OTP_RELOAD	0x02
53cc15c7ebSVivien Didelot #define SHT15_STATUS_HEATER		0x04
54cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_BATTERY	0x40
55cc15c7ebSVivien Didelot 
56edec5af7SVivien Didelot /* List of supported chips */
57edec5af7SVivien Didelot enum sht15_chips { sht10, sht11, sht15, sht71, sht75 };
58edec5af7SVivien Didelot 
5999a0378dSVivien Didelot /* Actions the driver may be doing */
6099a0378dSVivien Didelot enum sht15_state {
6199a0378dSVivien Didelot 	SHT15_READING_NOTHING,
6299a0378dSVivien Didelot 	SHT15_READING_TEMP,
6399a0378dSVivien Didelot 	SHT15_READING_HUMID
6499a0378dSVivien Didelot };
65251eb40fSJonathan Cameron 
66251eb40fSJonathan Cameron /**
6725985edcSLucas De Marchi  * struct sht15_temppair - elements of voltage dependent temp calc
68251eb40fSJonathan Cameron  * @vdd:	supply voltage in microvolts
69251eb40fSJonathan Cameron  * @d1:		see data sheet
70251eb40fSJonathan Cameron  */
71251eb40fSJonathan Cameron struct sht15_temppair {
72251eb40fSJonathan Cameron 	int vdd; /* microvolts */
73251eb40fSJonathan Cameron 	int d1;
74251eb40fSJonathan Cameron };
75251eb40fSJonathan Cameron 
7699a0378dSVivien Didelot /* Table 9 from datasheet - relates temperature calculation to supply voltage */
77251eb40fSJonathan Cameron static const struct sht15_temppair temppoints[] = {
78251eb40fSJonathan Cameron 	{ 2500000, -39400 },
79251eb40fSJonathan Cameron 	{ 3000000, -39600 },
80251eb40fSJonathan Cameron 	{ 3500000, -39700 },
81251eb40fSJonathan Cameron 	{ 4000000, -39800 },
82251eb40fSJonathan Cameron 	{ 5000000, -40100 },
83251eb40fSJonathan Cameron };
84251eb40fSJonathan Cameron 
8582c7465bSJerome Oufella /* Table from CRC datasheet, section 2.4 */
8682c7465bSJerome Oufella static const u8 sht15_crc8_table[] = {
8782c7465bSJerome Oufella 	0,	49,	98,	83,	196,	245,	166,	151,
8882c7465bSJerome Oufella 	185,	136,	219,	234,	125,	76,	31,	46,
8982c7465bSJerome Oufella 	67,	114,	33,	16,	135,	182,	229,	212,
9082c7465bSJerome Oufella 	250,	203,	152,	169,	62,	15,	92,	109,
9182c7465bSJerome Oufella 	134,	183,	228,	213,	66,	115,	32,	17,
9282c7465bSJerome Oufella 	63,	14,	93,	108,	251,	202,	153,	168,
9382c7465bSJerome Oufella 	197,	244,	167,	150,	1,	48,	99,	82,
9482c7465bSJerome Oufella 	124,	77,	30,	47,	184,	137,	218,	235,
9582c7465bSJerome Oufella 	61,	12,	95,	110,	249,	200,	155,	170,
9682c7465bSJerome Oufella 	132,	181,	230,	215,	64,	113,	34,	19,
9782c7465bSJerome Oufella 	126,	79,	28,	45,	186,	139,	216,	233,
9882c7465bSJerome Oufella 	199,	246,	165,	148,	3,	50,	97,	80,
9982c7465bSJerome Oufella 	187,	138,	217,	232,	127,	78,	29,	44,
10082c7465bSJerome Oufella 	2,	51,	96,	81,	198,	247,	164,	149,
10182c7465bSJerome Oufella 	248,	201,	154,	171,	60,	13,	94,	111,
10282c7465bSJerome Oufella 	65,	112,	35,	18,	133,	180,	231,	214,
10382c7465bSJerome Oufella 	122,	75,	24,	41,	190,	143,	220,	237,
10482c7465bSJerome Oufella 	195,	242,	161,	144,	7,	54,	101,	84,
10582c7465bSJerome Oufella 	57,	8,	91,	106,	253,	204,	159,	174,
10682c7465bSJerome Oufella 	128,	177,	226,	211,	68,	117,	38,	23,
10782c7465bSJerome Oufella 	252,	205,	158,	175,	56,	9,	90,	107,
10882c7465bSJerome Oufella 	69,	116,	39,	22,	129,	176,	227,	210,
10982c7465bSJerome Oufella 	191,	142,	221,	236,	123,	74,	25,	40,
11082c7465bSJerome Oufella 	6,	55,	100,	85,	194,	243,	160,	145,
11182c7465bSJerome Oufella 	71,	118,	37,	20,	131,	178,	225,	208,
11282c7465bSJerome Oufella 	254,	207,	156,	173,	58,	11,	88,	105,
11382c7465bSJerome Oufella 	4,	53,	102,	87,	192,	241,	162,	147,
11482c7465bSJerome Oufella 	189,	140,	223,	238,	121,	72,	27,	42,
11582c7465bSJerome Oufella 	193,	240,	163,	146,	5,	52,	103,	86,
11682c7465bSJerome Oufella 	120,	73,	26,	43,	188,	141,	222,	239,
11782c7465bSJerome Oufella 	130,	179,	224,	209,	70,	119,	36,	21,
11882c7465bSJerome Oufella 	59,	10,	89,	104,	255,	206,	157,	172
11982c7465bSJerome Oufella };
12082c7465bSJerome Oufella 
121251eb40fSJonathan Cameron /**
122251eb40fSJonathan Cameron  * struct sht15_data - device instance specific data
12399a0378dSVivien Didelot  * @pdata:		platform data (gpio's etc).
12499a0378dSVivien Didelot  * @read_work:		bh of interrupt handler.
12599a0378dSVivien Didelot  * @wait_queue:		wait queue for getting values from device.
12699a0378dSVivien Didelot  * @val_temp:		last temperature value read from device.
12799a0378dSVivien Didelot  * @val_humid:		last humidity value read from device.
128cc15c7ebSVivien Didelot  * @val_status:		last status register value read from device.
12982c7465bSJerome Oufella  * @checksum_ok:	last value read from the device passed CRC validation.
13082c7465bSJerome Oufella  * @checksumming:	flag used to enable the data validation with CRC.
13199a0378dSVivien Didelot  * @state:		state identifying the action the driver is doing.
13299a0378dSVivien Didelot  * @measurements_valid:	are the current stored measures valid (start condition).
133cc15c7ebSVivien Didelot  * @status_valid:	is the current stored status valid (start condition).
13499a0378dSVivien Didelot  * @last_measurement:	time of last measure.
135cc15c7ebSVivien Didelot  * @last_status:	time of last status reading.
13699a0378dSVivien Didelot  * @read_lock:		mutex to ensure only one read in progress at a time.
13799a0378dSVivien Didelot  * @dev:		associate device structure.
13899a0378dSVivien Didelot  * @hwmon_dev:		device associated with hwmon subsystem.
13999a0378dSVivien Didelot  * @reg:		associated regulator (if specified).
14099a0378dSVivien Didelot  * @nb:			notifier block to handle notifications of voltage
14199a0378dSVivien Didelot  *                      changes.
14299a0378dSVivien Didelot  * @supply_uV:		local copy of supply voltage used to allow use of
14399a0378dSVivien Didelot  *                      regulator consumer if available.
14499a0378dSVivien Didelot  * @supply_uV_valid:	indicates that an updated value has not yet been
14599a0378dSVivien Didelot  *			obtained from the regulator and so any calculations
146251eb40fSJonathan Cameron  *			based upon it will be invalid.
14799a0378dSVivien Didelot  * @update_supply_work:	work struct that is used to update the supply_uV.
14899a0378dSVivien Didelot  * @interrupt_handled:	flag used to indicate a handler has been scheduled.
149251eb40fSJonathan Cameron  */
150251eb40fSJonathan Cameron struct sht15_data {
151251eb40fSJonathan Cameron 	struct sht15_platform_data	*pdata;
152251eb40fSJonathan Cameron 	struct work_struct		read_work;
153251eb40fSJonathan Cameron 	wait_queue_head_t		wait_queue;
154251eb40fSJonathan Cameron 	uint16_t			val_temp;
155251eb40fSJonathan Cameron 	uint16_t			val_humid;
156cc15c7ebSVivien Didelot 	u8				val_status;
15782c7465bSJerome Oufella 	bool				checksum_ok;
15882c7465bSJerome Oufella 	bool				checksumming;
15999a0378dSVivien Didelot 	enum sht15_state		state;
16099a0378dSVivien Didelot 	bool				measurements_valid;
161cc15c7ebSVivien Didelot 	bool				status_valid;
16299a0378dSVivien Didelot 	unsigned long			last_measurement;
163cc15c7ebSVivien Didelot 	unsigned long			last_status;
164251eb40fSJonathan Cameron 	struct mutex			read_lock;
165251eb40fSJonathan Cameron 	struct device			*dev;
166251eb40fSJonathan Cameron 	struct device			*hwmon_dev;
167251eb40fSJonathan Cameron 	struct regulator		*reg;
168251eb40fSJonathan Cameron 	struct notifier_block		nb;
169251eb40fSJonathan Cameron 	int				supply_uV;
17099a0378dSVivien Didelot 	bool				supply_uV_valid;
171251eb40fSJonathan Cameron 	struct work_struct		update_supply_work;
172251eb40fSJonathan Cameron 	atomic_t			interrupt_handled;
173251eb40fSJonathan Cameron };
174251eb40fSJonathan Cameron 
175251eb40fSJonathan Cameron /**
17682c7465bSJerome Oufella  * sht15_reverse() - reverse a byte
17782c7465bSJerome Oufella  * @byte:    byte to reverse.
17882c7465bSJerome Oufella  */
17982c7465bSJerome Oufella static u8 sht15_reverse(u8 byte)
18082c7465bSJerome Oufella {
18182c7465bSJerome Oufella 	u8 i, c;
18282c7465bSJerome Oufella 
18382c7465bSJerome Oufella 	for (c = 0, i = 0; i < 8; i++)
18482c7465bSJerome Oufella 		c |= (!!(byte & (1 << i))) << (7 - i);
18582c7465bSJerome Oufella 	return c;
18682c7465bSJerome Oufella }
18782c7465bSJerome Oufella 
18882c7465bSJerome Oufella /**
18982c7465bSJerome Oufella  * sht15_crc8() - compute crc8
19082c7465bSJerome Oufella  * @data:	sht15 specific data.
19182c7465bSJerome Oufella  * @value:	sht15 retrieved data.
19282c7465bSJerome Oufella  *
19382c7465bSJerome Oufella  * This implements section 2 of the CRC datasheet.
19482c7465bSJerome Oufella  */
19582c7465bSJerome Oufella static u8 sht15_crc8(struct sht15_data *data,
19682c7465bSJerome Oufella 		const u8 *value,
19782c7465bSJerome Oufella 		int len)
19882c7465bSJerome Oufella {
19982c7465bSJerome Oufella 	u8 crc = sht15_reverse(data->val_status & 0x0F);
20082c7465bSJerome Oufella 
20182c7465bSJerome Oufella 	while (len--) {
20282c7465bSJerome Oufella 		crc = sht15_crc8_table[*value ^ crc];
20382c7465bSJerome Oufella 		value++;
20482c7465bSJerome Oufella 	}
20582c7465bSJerome Oufella 
20682c7465bSJerome Oufella 	return crc;
20782c7465bSJerome Oufella }
20882c7465bSJerome Oufella 
20982c7465bSJerome Oufella /**
210251eb40fSJonathan Cameron  * sht15_connection_reset() - reset the comms interface
211251eb40fSJonathan Cameron  * @data:	sht15 specific data
212251eb40fSJonathan Cameron  *
213251eb40fSJonathan Cameron  * This implements section 3.4 of the data sheet
214251eb40fSJonathan Cameron  */
215251eb40fSJonathan Cameron static void sht15_connection_reset(struct sht15_data *data)
216251eb40fSJonathan Cameron {
217251eb40fSJonathan Cameron 	int i;
21899a0378dSVivien Didelot 
219251eb40fSJonathan Cameron 	gpio_direction_output(data->pdata->gpio_data, 1);
220251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
221251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
222251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
223251eb40fSJonathan Cameron 	for (i = 0; i < 9; ++i) {
224251eb40fSJonathan Cameron 		gpio_set_value(data->pdata->gpio_sck, 1);
225251eb40fSJonathan Cameron 		ndelay(SHT15_TSCKH);
226251eb40fSJonathan Cameron 		gpio_set_value(data->pdata->gpio_sck, 0);
227251eb40fSJonathan Cameron 		ndelay(SHT15_TSCKL);
228251eb40fSJonathan Cameron 	}
229251eb40fSJonathan Cameron }
23099a0378dSVivien Didelot 
231251eb40fSJonathan Cameron /**
232251eb40fSJonathan Cameron  * sht15_send_bit() - send an individual bit to the device
233251eb40fSJonathan Cameron  * @data:	device state data
234251eb40fSJonathan Cameron  * @val:	value of bit to be sent
23599a0378dSVivien Didelot  */
236251eb40fSJonathan Cameron static inline void sht15_send_bit(struct sht15_data *data, int val)
237251eb40fSJonathan Cameron {
238251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_data, val);
239251eb40fSJonathan Cameron 	ndelay(SHT15_TSU);
240251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 1);
241251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKH);
242251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
243251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL); /* clock low time */
244251eb40fSJonathan Cameron }
245251eb40fSJonathan Cameron 
246251eb40fSJonathan Cameron /**
247251eb40fSJonathan Cameron  * sht15_transmission_start() - specific sequence for new transmission
248251eb40fSJonathan Cameron  * @data:	device state data
24999a0378dSVivien Didelot  *
250251eb40fSJonathan Cameron  * Timings for this are not documented on the data sheet, so very
251251eb40fSJonathan Cameron  * conservative ones used in implementation. This implements
252251eb40fSJonathan Cameron  * figure 12 on the data sheet.
25399a0378dSVivien Didelot  */
254251eb40fSJonathan Cameron static void sht15_transmission_start(struct sht15_data *data)
255251eb40fSJonathan Cameron {
256251eb40fSJonathan Cameron 	/* ensure data is high and output */
257251eb40fSJonathan Cameron 	gpio_direction_output(data->pdata->gpio_data, 1);
258251eb40fSJonathan Cameron 	ndelay(SHT15_TSU);
259251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
260251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
261251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 1);
262251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKH);
263251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_data, 0);
264251eb40fSJonathan Cameron 	ndelay(SHT15_TSU);
265251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
266251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
267251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 1);
268251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKH);
269251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_data, 1);
270251eb40fSJonathan Cameron 	ndelay(SHT15_TSU);
271251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
272251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
273251eb40fSJonathan Cameron }
27499a0378dSVivien Didelot 
275251eb40fSJonathan Cameron /**
276251eb40fSJonathan Cameron  * sht15_send_byte() - send a single byte to the device
277251eb40fSJonathan Cameron  * @data:	device state
278251eb40fSJonathan Cameron  * @byte:	value to be sent
27999a0378dSVivien Didelot  */
280251eb40fSJonathan Cameron static void sht15_send_byte(struct sht15_data *data, u8 byte)
281251eb40fSJonathan Cameron {
282251eb40fSJonathan Cameron 	int i;
28399a0378dSVivien Didelot 
284251eb40fSJonathan Cameron 	for (i = 0; i < 8; i++) {
285251eb40fSJonathan Cameron 		sht15_send_bit(data, !!(byte & 0x80));
286251eb40fSJonathan Cameron 		byte <<= 1;
287251eb40fSJonathan Cameron 	}
288251eb40fSJonathan Cameron }
28999a0378dSVivien Didelot 
290251eb40fSJonathan Cameron /**
291251eb40fSJonathan Cameron  * sht15_wait_for_response() - checks for ack from device
292251eb40fSJonathan Cameron  * @data:	device state
29399a0378dSVivien Didelot  */
294251eb40fSJonathan Cameron static int sht15_wait_for_response(struct sht15_data *data)
295251eb40fSJonathan Cameron {
296251eb40fSJonathan Cameron 	gpio_direction_input(data->pdata->gpio_data);
297251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 1);
298251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKH);
299251eb40fSJonathan Cameron 	if (gpio_get_value(data->pdata->gpio_data)) {
300251eb40fSJonathan Cameron 		gpio_set_value(data->pdata->gpio_sck, 0);
301251eb40fSJonathan Cameron 		dev_err(data->dev, "Command not acknowledged\n");
302251eb40fSJonathan Cameron 		sht15_connection_reset(data);
303251eb40fSJonathan Cameron 		return -EIO;
304251eb40fSJonathan Cameron 	}
305251eb40fSJonathan Cameron 	gpio_set_value(data->pdata->gpio_sck, 0);
306251eb40fSJonathan Cameron 	ndelay(SHT15_TSCKL);
307251eb40fSJonathan Cameron 	return 0;
308251eb40fSJonathan Cameron }
309251eb40fSJonathan Cameron 
310251eb40fSJonathan Cameron /**
311251eb40fSJonathan Cameron  * sht15_send_cmd() - Sends a command to the device.
312251eb40fSJonathan Cameron  * @data:	device state
313251eb40fSJonathan Cameron  * @cmd:	command byte to be sent
314251eb40fSJonathan Cameron  *
315251eb40fSJonathan Cameron  * On entry, sck is output low, data is output pull high
316251eb40fSJonathan Cameron  * and the interrupt disabled.
31799a0378dSVivien Didelot  */
318251eb40fSJonathan Cameron static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
319251eb40fSJonathan Cameron {
320251eb40fSJonathan Cameron 	int ret = 0;
32199a0378dSVivien Didelot 
322251eb40fSJonathan Cameron 	sht15_transmission_start(data);
323251eb40fSJonathan Cameron 	sht15_send_byte(data, cmd);
324251eb40fSJonathan Cameron 	ret = sht15_wait_for_response(data);
325251eb40fSJonathan Cameron 	return ret;
326251eb40fSJonathan Cameron }
32799a0378dSVivien Didelot 
328251eb40fSJonathan Cameron /**
329181148aeSVivien Didelot  * sht15_soft_reset() - send a soft reset command
330181148aeSVivien Didelot  * @data:	sht15 specific data.
331181148aeSVivien Didelot  *
332181148aeSVivien Didelot  * As described in section 3.2 of the datasheet.
333181148aeSVivien Didelot  */
334181148aeSVivien Didelot static int sht15_soft_reset(struct sht15_data *data)
335181148aeSVivien Didelot {
336181148aeSVivien Didelot 	int ret;
337181148aeSVivien Didelot 
338181148aeSVivien Didelot 	ret = sht15_send_cmd(data, SHT15_SOFT_RESET);
339181148aeSVivien Didelot 	if (ret)
340181148aeSVivien Didelot 		return ret;
341181148aeSVivien Didelot 	msleep(SHT15_TSRST);
342cc15c7ebSVivien Didelot 	/* device resets default hardware status register value */
343cc15c7ebSVivien Didelot 	data->val_status = 0;
344181148aeSVivien Didelot 
345cc15c7ebSVivien Didelot 	return ret;
346cc15c7ebSVivien Didelot }
347cc15c7ebSVivien Didelot 
348cc15c7ebSVivien Didelot /**
34982c7465bSJerome Oufella  * sht15_ack() - send a ack
35082c7465bSJerome Oufella  * @data:	sht15 specific data.
35182c7465bSJerome Oufella  *
35282c7465bSJerome Oufella  * Each byte of data is acknowledged by pulling the data line
35382c7465bSJerome Oufella  * low for one clock pulse.
35482c7465bSJerome Oufella  */
35582c7465bSJerome Oufella static void sht15_ack(struct sht15_data *data)
35682c7465bSJerome Oufella {
35782c7465bSJerome Oufella 	gpio_direction_output(data->pdata->gpio_data, 0);
35882c7465bSJerome Oufella 	ndelay(SHT15_TSU);
35982c7465bSJerome Oufella 	gpio_set_value(data->pdata->gpio_sck, 1);
36082c7465bSJerome Oufella 	ndelay(SHT15_TSU);
36182c7465bSJerome Oufella 	gpio_set_value(data->pdata->gpio_sck, 0);
36282c7465bSJerome Oufella 	ndelay(SHT15_TSU);
36382c7465bSJerome Oufella 	gpio_set_value(data->pdata->gpio_data, 1);
36482c7465bSJerome Oufella 
36582c7465bSJerome Oufella 	gpio_direction_input(data->pdata->gpio_data);
36682c7465bSJerome Oufella }
36782c7465bSJerome Oufella 
36882c7465bSJerome Oufella /**
369cc15c7ebSVivien Didelot  * sht15_end_transmission() - notify device of end of transmission
370cc15c7ebSVivien Didelot  * @data:	device state.
371cc15c7ebSVivien Didelot  *
372cc15c7ebSVivien Didelot  * This is basically a NAK (single clock pulse, data high).
373cc15c7ebSVivien Didelot  */
374cc15c7ebSVivien Didelot static void sht15_end_transmission(struct sht15_data *data)
375cc15c7ebSVivien Didelot {
376cc15c7ebSVivien Didelot 	gpio_direction_output(data->pdata->gpio_data, 1);
377cc15c7ebSVivien Didelot 	ndelay(SHT15_TSU);
378cc15c7ebSVivien Didelot 	gpio_set_value(data->pdata->gpio_sck, 1);
379cc15c7ebSVivien Didelot 	ndelay(SHT15_TSCKH);
380cc15c7ebSVivien Didelot 	gpio_set_value(data->pdata->gpio_sck, 0);
381cc15c7ebSVivien Didelot 	ndelay(SHT15_TSCKL);
382cc15c7ebSVivien Didelot }
383cc15c7ebSVivien Didelot 
384cc15c7ebSVivien Didelot /**
385cc15c7ebSVivien Didelot  * sht15_read_byte() - Read a byte back from the device
386cc15c7ebSVivien Didelot  * @data:	device state.
387cc15c7ebSVivien Didelot  */
388cc15c7ebSVivien Didelot static u8 sht15_read_byte(struct sht15_data *data)
389cc15c7ebSVivien Didelot {
390cc15c7ebSVivien Didelot 	int i;
391cc15c7ebSVivien Didelot 	u8 byte = 0;
392cc15c7ebSVivien Didelot 
393cc15c7ebSVivien Didelot 	for (i = 0; i < 8; ++i) {
394cc15c7ebSVivien Didelot 		byte <<= 1;
395cc15c7ebSVivien Didelot 		gpio_set_value(data->pdata->gpio_sck, 1);
396cc15c7ebSVivien Didelot 		ndelay(SHT15_TSCKH);
397cc15c7ebSVivien Didelot 		byte |= !!gpio_get_value(data->pdata->gpio_data);
398cc15c7ebSVivien Didelot 		gpio_set_value(data->pdata->gpio_sck, 0);
399cc15c7ebSVivien Didelot 		ndelay(SHT15_TSCKL);
400cc15c7ebSVivien Didelot 	}
401cc15c7ebSVivien Didelot 	return byte;
402cc15c7ebSVivien Didelot }
403cc15c7ebSVivien Didelot 
404cc15c7ebSVivien Didelot /**
405cc15c7ebSVivien Didelot  * sht15_send_status() - write the status register byte
406cc15c7ebSVivien Didelot  * @data:	sht15 specific data.
407cc15c7ebSVivien Didelot  * @status:	the byte to set the status register with.
408cc15c7ebSVivien Didelot  *
409cc15c7ebSVivien Didelot  * As described in figure 14 and table 5 of the datasheet.
410cc15c7ebSVivien Didelot  */
411cc15c7ebSVivien Didelot static int sht15_send_status(struct sht15_data *data, u8 status)
412cc15c7ebSVivien Didelot {
413cc15c7ebSVivien Didelot 	int ret;
414cc15c7ebSVivien Didelot 
415cc15c7ebSVivien Didelot 	ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
416cc15c7ebSVivien Didelot 	if (ret)
417cc15c7ebSVivien Didelot 		return ret;
418cc15c7ebSVivien Didelot 	gpio_direction_output(data->pdata->gpio_data, 1);
419cc15c7ebSVivien Didelot 	ndelay(SHT15_TSU);
420cc15c7ebSVivien Didelot 	sht15_send_byte(data, status);
421cc15c7ebSVivien Didelot 	ret = sht15_wait_for_response(data);
422cc15c7ebSVivien Didelot 	if (ret)
423cc15c7ebSVivien Didelot 		return ret;
424cc15c7ebSVivien Didelot 
425cc15c7ebSVivien Didelot 	data->val_status = status;
426181148aeSVivien Didelot 	return 0;
427181148aeSVivien Didelot }
428181148aeSVivien Didelot 
429181148aeSVivien Didelot /**
430cc15c7ebSVivien Didelot  * sht15_update_status() - get updated status register from device if too old
431cc15c7ebSVivien Didelot  * @data:	device instance specific data.
432cc15c7ebSVivien Didelot  *
433cc15c7ebSVivien Didelot  * As described in figure 15 and table 5 of the datasheet.
434cc15c7ebSVivien Didelot  */
435cc15c7ebSVivien Didelot static int sht15_update_status(struct sht15_data *data)
436cc15c7ebSVivien Didelot {
437cc15c7ebSVivien Didelot 	int ret = 0;
438cc15c7ebSVivien Didelot 	u8 status;
43982c7465bSJerome Oufella 	u8 previous_config;
44082c7465bSJerome Oufella 	u8 dev_checksum = 0;
44182c7465bSJerome Oufella 	u8 checksum_vals[2];
442cc15c7ebSVivien Didelot 	int timeout = HZ;
443cc15c7ebSVivien Didelot 
444cc15c7ebSVivien Didelot 	mutex_lock(&data->read_lock);
445cc15c7ebSVivien Didelot 	if (time_after(jiffies, data->last_status + timeout)
446cc15c7ebSVivien Didelot 			|| !data->status_valid) {
447cc15c7ebSVivien Didelot 		ret = sht15_send_cmd(data, SHT15_READ_STATUS);
448cc15c7ebSVivien Didelot 		if (ret)
449cc15c7ebSVivien Didelot 			goto error_ret;
450cc15c7ebSVivien Didelot 		status = sht15_read_byte(data);
451cc15c7ebSVivien Didelot 
45282c7465bSJerome Oufella 		if (data->checksumming) {
45382c7465bSJerome Oufella 			sht15_ack(data);
45482c7465bSJerome Oufella 			dev_checksum = sht15_reverse(sht15_read_byte(data));
45582c7465bSJerome Oufella 			checksum_vals[0] = SHT15_READ_STATUS;
45682c7465bSJerome Oufella 			checksum_vals[1] = status;
45782c7465bSJerome Oufella 			data->checksum_ok = (sht15_crc8(data, checksum_vals, 2)
45882c7465bSJerome Oufella 					== dev_checksum);
45982c7465bSJerome Oufella 		}
46082c7465bSJerome Oufella 
461cc15c7ebSVivien Didelot 		sht15_end_transmission(data);
462cc15c7ebSVivien Didelot 
46382c7465bSJerome Oufella 		/*
46482c7465bSJerome Oufella 		 * Perform checksum validation on the received data.
46582c7465bSJerome Oufella 		 * Specification mentions that in case a checksum verification
46682c7465bSJerome Oufella 		 * fails, a soft reset command must be sent to the device.
46782c7465bSJerome Oufella 		 */
46882c7465bSJerome Oufella 		if (data->checksumming && !data->checksum_ok) {
46982c7465bSJerome Oufella 			previous_config = data->val_status & 0x07;
47082c7465bSJerome Oufella 			ret = sht15_soft_reset(data);
47182c7465bSJerome Oufella 			if (ret)
47282c7465bSJerome Oufella 				goto error_ret;
47382c7465bSJerome Oufella 			if (previous_config) {
47482c7465bSJerome Oufella 				ret = sht15_send_status(data, previous_config);
47582c7465bSJerome Oufella 				if (ret) {
47682c7465bSJerome Oufella 					dev_err(data->dev,
47782c7465bSJerome Oufella 						"CRC validation failed, unable "
47882c7465bSJerome Oufella 						"to restore device settings\n");
47982c7465bSJerome Oufella 					goto error_ret;
48082c7465bSJerome Oufella 				}
48182c7465bSJerome Oufella 			}
48282c7465bSJerome Oufella 			ret = -EAGAIN;
48382c7465bSJerome Oufella 			goto error_ret;
48482c7465bSJerome Oufella 		}
48582c7465bSJerome Oufella 
486cc15c7ebSVivien Didelot 		data->val_status = status;
487cc15c7ebSVivien Didelot 		data->status_valid = true;
488cc15c7ebSVivien Didelot 		data->last_status = jiffies;
489cc15c7ebSVivien Didelot 	}
490cc15c7ebSVivien Didelot error_ret:
491cc15c7ebSVivien Didelot 	mutex_unlock(&data->read_lock);
492cc15c7ebSVivien Didelot 
493cc15c7ebSVivien Didelot 	return ret;
494cc15c7ebSVivien Didelot }
495cc15c7ebSVivien Didelot 
496cc15c7ebSVivien Didelot /**
49799a0378dSVivien Didelot  * sht15_measurement() - get a new value from device
498251eb40fSJonathan Cameron  * @data:		device instance specific data
499251eb40fSJonathan Cameron  * @command:		command sent to request value
500251eb40fSJonathan Cameron  * @timeout_msecs:	timeout after which comms are assumed
501251eb40fSJonathan Cameron  *			to have failed are reset.
50299a0378dSVivien Didelot  */
50399a0378dSVivien Didelot static int sht15_measurement(struct sht15_data *data,
504251eb40fSJonathan Cameron 			     int command,
505251eb40fSJonathan Cameron 			     int timeout_msecs)
506251eb40fSJonathan Cameron {
507251eb40fSJonathan Cameron 	int ret;
50882c7465bSJerome Oufella 	u8 previous_config;
50999a0378dSVivien Didelot 
510251eb40fSJonathan Cameron 	ret = sht15_send_cmd(data, command);
511251eb40fSJonathan Cameron 	if (ret)
512251eb40fSJonathan Cameron 		return ret;
513251eb40fSJonathan Cameron 
514251eb40fSJonathan Cameron 	gpio_direction_input(data->pdata->gpio_data);
515251eb40fSJonathan Cameron 	atomic_set(&data->interrupt_handled, 0);
516251eb40fSJonathan Cameron 
517251eb40fSJonathan Cameron 	enable_irq(gpio_to_irq(data->pdata->gpio_data));
518251eb40fSJonathan Cameron 	if (gpio_get_value(data->pdata->gpio_data) == 0) {
519251eb40fSJonathan Cameron 		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
52025985edcSLucas De Marchi 		/* Only relevant if the interrupt hasn't occurred. */
521251eb40fSJonathan Cameron 		if (!atomic_read(&data->interrupt_handled))
522251eb40fSJonathan Cameron 			schedule_work(&data->read_work);
523251eb40fSJonathan Cameron 	}
524251eb40fSJonathan Cameron 	ret = wait_event_timeout(data->wait_queue,
52599a0378dSVivien Didelot 				 (data->state == SHT15_READING_NOTHING),
526251eb40fSJonathan Cameron 				 msecs_to_jiffies(timeout_msecs));
527251eb40fSJonathan Cameron 	if (ret == 0) {/* timeout occurred */
52824205e08SJoe Perches 		disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
529251eb40fSJonathan Cameron 		sht15_connection_reset(data);
530251eb40fSJonathan Cameron 		return -ETIME;
531251eb40fSJonathan Cameron 	}
53282c7465bSJerome Oufella 
53382c7465bSJerome Oufella 	/*
53482c7465bSJerome Oufella 	 *  Perform checksum validation on the received data.
53582c7465bSJerome Oufella 	 *  Specification mentions that in case a checksum verification fails,
53682c7465bSJerome Oufella 	 *  a soft reset command must be sent to the device.
53782c7465bSJerome Oufella 	 */
53882c7465bSJerome Oufella 	if (data->checksumming && !data->checksum_ok) {
53982c7465bSJerome Oufella 		previous_config = data->val_status & 0x07;
54082c7465bSJerome Oufella 		ret = sht15_soft_reset(data);
54182c7465bSJerome Oufella 		if (ret)
54282c7465bSJerome Oufella 			return ret;
54382c7465bSJerome Oufella 		if (previous_config) {
54482c7465bSJerome Oufella 			ret = sht15_send_status(data, previous_config);
54582c7465bSJerome Oufella 			if (ret) {
54682c7465bSJerome Oufella 				dev_err(data->dev,
54782c7465bSJerome Oufella 					"CRC validation failed, unable "
54882c7465bSJerome Oufella 					"to restore device settings\n");
54982c7465bSJerome Oufella 				return ret;
55082c7465bSJerome Oufella 			}
55182c7465bSJerome Oufella 		}
55282c7465bSJerome Oufella 		return -EAGAIN;
55382c7465bSJerome Oufella 	}
55482c7465bSJerome Oufella 
555251eb40fSJonathan Cameron 	return 0;
556251eb40fSJonathan Cameron }
557251eb40fSJonathan Cameron 
558251eb40fSJonathan Cameron /**
55999a0378dSVivien Didelot  * sht15_update_measurements() - get updated measures from device if too old
560251eb40fSJonathan Cameron  * @data:	device state
56199a0378dSVivien Didelot  */
56299a0378dSVivien Didelot static int sht15_update_measurements(struct sht15_data *data)
563251eb40fSJonathan Cameron {
564251eb40fSJonathan Cameron 	int ret = 0;
565251eb40fSJonathan Cameron 	int timeout = HZ;
566251eb40fSJonathan Cameron 
567251eb40fSJonathan Cameron 	mutex_lock(&data->read_lock);
56899a0378dSVivien Didelot 	if (time_after(jiffies, data->last_measurement + timeout)
56999a0378dSVivien Didelot 	    || !data->measurements_valid) {
57099a0378dSVivien Didelot 		data->state = SHT15_READING_HUMID;
57199a0378dSVivien Didelot 		ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
572251eb40fSJonathan Cameron 		if (ret)
573251eb40fSJonathan Cameron 			goto error_ret;
57499a0378dSVivien Didelot 		data->state = SHT15_READING_TEMP;
57599a0378dSVivien Didelot 		ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
576251eb40fSJonathan Cameron 		if (ret)
577251eb40fSJonathan Cameron 			goto error_ret;
57899a0378dSVivien Didelot 		data->measurements_valid = true;
57999a0378dSVivien Didelot 		data->last_measurement = jiffies;
580251eb40fSJonathan Cameron 	}
581251eb40fSJonathan Cameron error_ret:
582251eb40fSJonathan Cameron 	mutex_unlock(&data->read_lock);
583251eb40fSJonathan Cameron 
584251eb40fSJonathan Cameron 	return ret;
585251eb40fSJonathan Cameron }
586251eb40fSJonathan Cameron 
587251eb40fSJonathan Cameron /**
588251eb40fSJonathan Cameron  * sht15_calc_temp() - convert the raw reading to a temperature
589251eb40fSJonathan Cameron  * @data:	device state
590251eb40fSJonathan Cameron  *
591251eb40fSJonathan Cameron  * As per section 4.3 of the data sheet.
59299a0378dSVivien Didelot  */
593251eb40fSJonathan Cameron static inline int sht15_calc_temp(struct sht15_data *data)
594251eb40fSJonathan Cameron {
595328a2c22SJerome Oufella 	int d1 = temppoints[0].d1;
596cc15c7ebSVivien Didelot 	int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
597251eb40fSJonathan Cameron 	int i;
598251eb40fSJonathan Cameron 
599328a2c22SJerome Oufella 	for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
600251eb40fSJonathan Cameron 		/* Find pointer to interpolate */
601251eb40fSJonathan Cameron 		if (data->supply_uV > temppoints[i - 1].vdd) {
602328a2c22SJerome Oufella 			d1 = (data->supply_uV - temppoints[i - 1].vdd)
603251eb40fSJonathan Cameron 				* (temppoints[i].d1 - temppoints[i - 1].d1)
604251eb40fSJonathan Cameron 				/ (temppoints[i].vdd - temppoints[i - 1].vdd)
605251eb40fSJonathan Cameron 				+ temppoints[i - 1].d1;
606251eb40fSJonathan Cameron 			break;
607251eb40fSJonathan Cameron 		}
608251eb40fSJonathan Cameron 
609cc15c7ebSVivien Didelot 	return data->val_temp * d2 + d1;
610251eb40fSJonathan Cameron }
611251eb40fSJonathan Cameron 
612251eb40fSJonathan Cameron /**
613251eb40fSJonathan Cameron  * sht15_calc_humid() - using last temperature convert raw to humid
614251eb40fSJonathan Cameron  * @data:	device state
615251eb40fSJonathan Cameron  *
616251eb40fSJonathan Cameron  * This is the temperature compensated version as per section 4.2 of
617251eb40fSJonathan Cameron  * the data sheet.
61899a0378dSVivien Didelot  *
61999a0378dSVivien Didelot  * The sensor is assumed to be V3, which is compatible with V4.
62099a0378dSVivien Didelot  * Humidity conversion coefficients are shown in table 7 of the datasheet.
62199a0378dSVivien Didelot  */
622251eb40fSJonathan Cameron static inline int sht15_calc_humid(struct sht15_data *data)
623251eb40fSJonathan Cameron {
62499a0378dSVivien Didelot 	int rh_linear; /* milli percent */
625251eb40fSJonathan Cameron 	int temp = sht15_calc_temp(data);
626cc15c7ebSVivien Didelot 	int c2, c3;
627cc15c7ebSVivien Didelot 	int t2;
628251eb40fSJonathan Cameron 	const int c1 = -4;
629cc15c7ebSVivien Didelot 
630cc15c7ebSVivien Didelot 	if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
631cc15c7ebSVivien Didelot 		c2 = 648000; /* x 10 ^ -6 */
632cc15c7ebSVivien Didelot 		c3 = -7200;  /* x 10 ^ -7 */
633cc15c7ebSVivien Didelot 		t2 = 1280;
634cc15c7ebSVivien Didelot 	} else {
635cc15c7ebSVivien Didelot 		c2 = 40500;  /* x 10 ^ -6 */
636cc15c7ebSVivien Didelot 		c3 = -28;    /* x 10 ^ -7 */
637cc15c7ebSVivien Didelot 		t2 = 80;
638cc15c7ebSVivien Didelot 	}
639251eb40fSJonathan Cameron 
64099a0378dSVivien Didelot 	rh_linear = c1 * 1000
641251eb40fSJonathan Cameron 		+ c2 * data->val_humid / 1000
642ccd32e73SVivien Didelot 		+ (data->val_humid * data->val_humid * c3) / 10000;
643cc15c7ebSVivien Didelot 	return (temp - 25000) * (10000 + t2 * data->val_humid)
64499a0378dSVivien Didelot 		/ 1000000 + rh_linear;
645251eb40fSJonathan Cameron }
646251eb40fSJonathan Cameron 
64799a0378dSVivien Didelot /**
648cc15c7ebSVivien Didelot  * sht15_show_status() - show status information in sysfs
649cc15c7ebSVivien Didelot  * @dev:	device.
650cc15c7ebSVivien Didelot  * @attr:	device attribute.
651cc15c7ebSVivien Didelot  * @buf:	sysfs buffer where information is written to.
652cc15c7ebSVivien Didelot  *
653cc15c7ebSVivien Didelot  * Will be called on read access to temp1_fault, humidity1_fault
654cc15c7ebSVivien Didelot  * and heater_enable sysfs attributes.
655cc15c7ebSVivien Didelot  * Returns number of bytes written into buffer, negative errno on error.
656cc15c7ebSVivien Didelot  */
657cc15c7ebSVivien Didelot static ssize_t sht15_show_status(struct device *dev,
658cc15c7ebSVivien Didelot 				 struct device_attribute *attr,
659cc15c7ebSVivien Didelot 				 char *buf)
660cc15c7ebSVivien Didelot {
661cc15c7ebSVivien Didelot 	int ret;
662cc15c7ebSVivien Didelot 	struct sht15_data *data = dev_get_drvdata(dev);
663cc15c7ebSVivien Didelot 	u8 bit = to_sensor_dev_attr(attr)->index;
664cc15c7ebSVivien Didelot 
665cc15c7ebSVivien Didelot 	ret = sht15_update_status(data);
666cc15c7ebSVivien Didelot 
667cc15c7ebSVivien Didelot 	return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
668cc15c7ebSVivien Didelot }
669cc15c7ebSVivien Didelot 
670cc15c7ebSVivien Didelot /**
671cc15c7ebSVivien Didelot  * sht15_store_heater() - change heater state via sysfs
672cc15c7ebSVivien Didelot  * @dev:	device.
673cc15c7ebSVivien Didelot  * @attr:	device attribute.
674cc15c7ebSVivien Didelot  * @buf:	sysfs buffer to read the new heater state from.
675cc15c7ebSVivien Didelot  * @count:	length of the data.
676cc15c7ebSVivien Didelot  *
677e9b6e9f3SVivien Didelot  * Will be called on write access to heater_enable sysfs attribute.
678cc15c7ebSVivien Didelot  * Returns number of bytes actually decoded, negative errno on error.
679cc15c7ebSVivien Didelot  */
680cc15c7ebSVivien Didelot static ssize_t sht15_store_heater(struct device *dev,
681cc15c7ebSVivien Didelot 				  struct device_attribute *attr,
682cc15c7ebSVivien Didelot 				  const char *buf, size_t count)
683cc15c7ebSVivien Didelot {
684cc15c7ebSVivien Didelot 	int ret;
685cc15c7ebSVivien Didelot 	struct sht15_data *data = dev_get_drvdata(dev);
686cc15c7ebSVivien Didelot 	long value;
687cc15c7ebSVivien Didelot 	u8 status;
688cc15c7ebSVivien Didelot 
689179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &value))
690cc15c7ebSVivien Didelot 		return -EINVAL;
691cc15c7ebSVivien Didelot 
692cc15c7ebSVivien Didelot 	mutex_lock(&data->read_lock);
693cc15c7ebSVivien Didelot 	status = data->val_status & 0x07;
694cc15c7ebSVivien Didelot 	if (!!value)
695cc15c7ebSVivien Didelot 		status |= SHT15_STATUS_HEATER;
696cc15c7ebSVivien Didelot 	else
697cc15c7ebSVivien Didelot 		status &= ~SHT15_STATUS_HEATER;
698cc15c7ebSVivien Didelot 
699cc15c7ebSVivien Didelot 	ret = sht15_send_status(data, status);
700cc15c7ebSVivien Didelot 	mutex_unlock(&data->read_lock);
701cc15c7ebSVivien Didelot 
702cc15c7ebSVivien Didelot 	return ret ? ret : count;
703cc15c7ebSVivien Didelot }
704cc15c7ebSVivien Didelot 
705cc15c7ebSVivien Didelot /**
70699a0378dSVivien Didelot  * sht15_show_temp() - show temperature measurement value in sysfs
70799a0378dSVivien Didelot  * @dev:	device.
70899a0378dSVivien Didelot  * @attr:	device attribute.
70999a0378dSVivien Didelot  * @buf:	sysfs buffer where measurement values are written to.
71099a0378dSVivien Didelot  *
71199a0378dSVivien Didelot  * Will be called on read access to temp1_input sysfs attribute.
71299a0378dSVivien Didelot  * Returns number of bytes written into buffer, negative errno on error.
71399a0378dSVivien Didelot  */
714251eb40fSJonathan Cameron static ssize_t sht15_show_temp(struct device *dev,
715251eb40fSJonathan Cameron 			       struct device_attribute *attr,
716251eb40fSJonathan Cameron 			       char *buf)
717251eb40fSJonathan Cameron {
718251eb40fSJonathan Cameron 	int ret;
719251eb40fSJonathan Cameron 	struct sht15_data *data = dev_get_drvdata(dev);
720251eb40fSJonathan Cameron 
721251eb40fSJonathan Cameron 	/* Technically no need to read humidity as well */
72299a0378dSVivien Didelot 	ret = sht15_update_measurements(data);
723251eb40fSJonathan Cameron 
724251eb40fSJonathan Cameron 	return ret ? ret : sprintf(buf, "%d\n",
725251eb40fSJonathan Cameron 				   sht15_calc_temp(data));
726251eb40fSJonathan Cameron }
727251eb40fSJonathan Cameron 
72899a0378dSVivien Didelot /**
72999a0378dSVivien Didelot  * sht15_show_humidity() - show humidity measurement value in sysfs
73099a0378dSVivien Didelot  * @dev:	device.
73199a0378dSVivien Didelot  * @attr:	device attribute.
73299a0378dSVivien Didelot  * @buf:	sysfs buffer where measurement values are written to.
73399a0378dSVivien Didelot  *
73499a0378dSVivien Didelot  * Will be called on read access to humidity1_input sysfs attribute.
73599a0378dSVivien Didelot  * Returns number of bytes written into buffer, negative errno on error.
73699a0378dSVivien Didelot  */
737251eb40fSJonathan Cameron static ssize_t sht15_show_humidity(struct device *dev,
738251eb40fSJonathan Cameron 				   struct device_attribute *attr,
739251eb40fSJonathan Cameron 				   char *buf)
740251eb40fSJonathan Cameron {
741251eb40fSJonathan Cameron 	int ret;
742251eb40fSJonathan Cameron 	struct sht15_data *data = dev_get_drvdata(dev);
743251eb40fSJonathan Cameron 
74499a0378dSVivien Didelot 	ret = sht15_update_measurements(data);
745251eb40fSJonathan Cameron 
746251eb40fSJonathan Cameron 	return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
74799a0378dSVivien Didelot }
74899a0378dSVivien Didelot 
749251eb40fSJonathan Cameron static ssize_t show_name(struct device *dev,
750251eb40fSJonathan Cameron 			 struct device_attribute *attr,
751251eb40fSJonathan Cameron 			 char *buf)
752251eb40fSJonathan Cameron {
753251eb40fSJonathan Cameron 	struct platform_device *pdev = to_platform_device(dev);
754251eb40fSJonathan Cameron 	return sprintf(buf, "%s\n", pdev->name);
755251eb40fSJonathan Cameron }
756251eb40fSJonathan Cameron 
75799a0378dSVivien Didelot static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
75899a0378dSVivien Didelot 			  sht15_show_temp, NULL, 0);
75999a0378dSVivien Didelot static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
76099a0378dSVivien Didelot 			  sht15_show_humidity, NULL, 0);
761cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL,
762cc15c7ebSVivien Didelot 			  SHT15_STATUS_LOW_BATTERY);
763cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL,
764cc15c7ebSVivien Didelot 			  SHT15_STATUS_LOW_BATTERY);
765cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status,
766cc15c7ebSVivien Didelot 			  sht15_store_heater, SHT15_STATUS_HEATER);
767251eb40fSJonathan Cameron static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
768251eb40fSJonathan Cameron static struct attribute *sht15_attrs[] = {
769251eb40fSJonathan Cameron 	&sensor_dev_attr_temp1_input.dev_attr.attr,
770251eb40fSJonathan Cameron 	&sensor_dev_attr_humidity1_input.dev_attr.attr,
771cc15c7ebSVivien Didelot 	&sensor_dev_attr_temp1_fault.dev_attr.attr,
772cc15c7ebSVivien Didelot 	&sensor_dev_attr_humidity1_fault.dev_attr.attr,
773cc15c7ebSVivien Didelot 	&sensor_dev_attr_heater_enable.dev_attr.attr,
774251eb40fSJonathan Cameron 	&dev_attr_name.attr,
775251eb40fSJonathan Cameron 	NULL,
776251eb40fSJonathan Cameron };
777251eb40fSJonathan Cameron 
778251eb40fSJonathan Cameron static const struct attribute_group sht15_attr_group = {
779251eb40fSJonathan Cameron 	.attrs = sht15_attrs,
780251eb40fSJonathan Cameron };
781251eb40fSJonathan Cameron 
782251eb40fSJonathan Cameron static irqreturn_t sht15_interrupt_fired(int irq, void *d)
783251eb40fSJonathan Cameron {
784251eb40fSJonathan Cameron 	struct sht15_data *data = d;
78599a0378dSVivien Didelot 
786251eb40fSJonathan Cameron 	/* First disable the interrupt */
787251eb40fSJonathan Cameron 	disable_irq_nosync(irq);
788251eb40fSJonathan Cameron 	atomic_inc(&data->interrupt_handled);
789251eb40fSJonathan Cameron 	/* Then schedule a reading work struct */
79099a0378dSVivien Didelot 	if (data->state != SHT15_READING_NOTHING)
791251eb40fSJonathan Cameron 		schedule_work(&data->read_work);
792251eb40fSJonathan Cameron 	return IRQ_HANDLED;
793251eb40fSJonathan Cameron }
794251eb40fSJonathan Cameron 
795251eb40fSJonathan Cameron static void sht15_bh_read_data(struct work_struct *work_s)
796251eb40fSJonathan Cameron {
797251eb40fSJonathan Cameron 	uint16_t val = 0;
79882c7465bSJerome Oufella 	u8 dev_checksum = 0;
79982c7465bSJerome Oufella 	u8 checksum_vals[3];
800251eb40fSJonathan Cameron 	struct sht15_data *data
801251eb40fSJonathan Cameron 		= container_of(work_s, struct sht15_data,
802251eb40fSJonathan Cameron 			       read_work);
80399a0378dSVivien Didelot 
804251eb40fSJonathan Cameron 	/* Firstly, verify the line is low */
805251eb40fSJonathan Cameron 	if (gpio_get_value(data->pdata->gpio_data)) {
80699a0378dSVivien Didelot 		/*
80799a0378dSVivien Didelot 		 * If not, then start the interrupt again - care here as could
80899a0378dSVivien Didelot 		 * have gone low in meantime so verify it hasn't!
809251eb40fSJonathan Cameron 		 */
810251eb40fSJonathan Cameron 		atomic_set(&data->interrupt_handled, 0);
811251eb40fSJonathan Cameron 		enable_irq(gpio_to_irq(data->pdata->gpio_data));
812c9e1498aSFrans Meulenbroeks 		/* If still not occurred or another handler was scheduled */
813251eb40fSJonathan Cameron 		if (gpio_get_value(data->pdata->gpio_data)
814251eb40fSJonathan Cameron 		    || atomic_read(&data->interrupt_handled))
815251eb40fSJonathan Cameron 			return;
816251eb40fSJonathan Cameron 	}
81799a0378dSVivien Didelot 
818251eb40fSJonathan Cameron 	/* Read the data back from the device */
819cc15c7ebSVivien Didelot 	val = sht15_read_byte(data);
820cc15c7ebSVivien Didelot 	val <<= 8;
821251eb40fSJonathan Cameron 	sht15_ack(data);
822cc15c7ebSVivien Didelot 	val |= sht15_read_byte(data);
82399a0378dSVivien Didelot 
82482c7465bSJerome Oufella 	if (data->checksumming) {
82582c7465bSJerome Oufella 		/*
82682c7465bSJerome Oufella 		 * Ask the device for a checksum and read it back.
82782c7465bSJerome Oufella 		 * Note: the device sends the checksum byte reversed.
82882c7465bSJerome Oufella 		 */
82982c7465bSJerome Oufella 		sht15_ack(data);
83082c7465bSJerome Oufella 		dev_checksum = sht15_reverse(sht15_read_byte(data));
83182c7465bSJerome Oufella 		checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
83282c7465bSJerome Oufella 			SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
83382c7465bSJerome Oufella 		checksum_vals[1] = (u8) (val >> 8);
83482c7465bSJerome Oufella 		checksum_vals[2] = (u8) val;
83582c7465bSJerome Oufella 		data->checksum_ok
83682c7465bSJerome Oufella 			= (sht15_crc8(data, checksum_vals, 3) == dev_checksum);
83782c7465bSJerome Oufella 	}
83882c7465bSJerome Oufella 
839251eb40fSJonathan Cameron 	/* Tell the device we are done */
840251eb40fSJonathan Cameron 	sht15_end_transmission(data);
841251eb40fSJonathan Cameron 
84299a0378dSVivien Didelot 	switch (data->state) {
843251eb40fSJonathan Cameron 	case SHT15_READING_TEMP:
844251eb40fSJonathan Cameron 		data->val_temp = val;
845251eb40fSJonathan Cameron 		break;
846251eb40fSJonathan Cameron 	case SHT15_READING_HUMID:
847251eb40fSJonathan Cameron 		data->val_humid = val;
848251eb40fSJonathan Cameron 		break;
84999a0378dSVivien Didelot 	default:
85099a0378dSVivien Didelot 		break;
851251eb40fSJonathan Cameron 	}
852251eb40fSJonathan Cameron 
85399a0378dSVivien Didelot 	data->state = SHT15_READING_NOTHING;
854251eb40fSJonathan Cameron 	wake_up(&data->wait_queue);
855251eb40fSJonathan Cameron }
856251eb40fSJonathan Cameron 
857251eb40fSJonathan Cameron static void sht15_update_voltage(struct work_struct *work_s)
858251eb40fSJonathan Cameron {
859251eb40fSJonathan Cameron 	struct sht15_data *data
860251eb40fSJonathan Cameron 		= container_of(work_s, struct sht15_data,
861251eb40fSJonathan Cameron 			       update_supply_work);
862251eb40fSJonathan Cameron 	data->supply_uV = regulator_get_voltage(data->reg);
863251eb40fSJonathan Cameron }
864251eb40fSJonathan Cameron 
865251eb40fSJonathan Cameron /**
866251eb40fSJonathan Cameron  * sht15_invalidate_voltage() - mark supply voltage invalid when notified by reg
867251eb40fSJonathan Cameron  * @nb:		associated notification structure
868251eb40fSJonathan Cameron  * @event:	voltage regulator state change event code
869251eb40fSJonathan Cameron  * @ignored:	function parameter - ignored here
870251eb40fSJonathan Cameron  *
871251eb40fSJonathan Cameron  * Note that as the notification code holds the regulator lock, we have
872251eb40fSJonathan Cameron  * to schedule an update of the supply voltage rather than getting it directly.
87399a0378dSVivien Didelot  */
874251eb40fSJonathan Cameron static int sht15_invalidate_voltage(struct notifier_block *nb,
875251eb40fSJonathan Cameron 				    unsigned long event,
876251eb40fSJonathan Cameron 				    void *ignored)
877251eb40fSJonathan Cameron {
878251eb40fSJonathan Cameron 	struct sht15_data *data = container_of(nb, struct sht15_data, nb);
879251eb40fSJonathan Cameron 
880251eb40fSJonathan Cameron 	if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
881251eb40fSJonathan Cameron 		data->supply_uV_valid = false;
882251eb40fSJonathan Cameron 	schedule_work(&data->update_supply_work);
883251eb40fSJonathan Cameron 
884251eb40fSJonathan Cameron 	return NOTIFY_OK;
885251eb40fSJonathan Cameron }
886251eb40fSJonathan Cameron 
887251eb40fSJonathan Cameron static int __devinit sht15_probe(struct platform_device *pdev)
888251eb40fSJonathan Cameron {
8896edf3c30SVivien Didelot 	int ret;
89038fe7560SGuenter Roeck 	struct sht15_data *data;
891cc15c7ebSVivien Didelot 	u8 status = 0;
892251eb40fSJonathan Cameron 
89338fe7560SGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
89438fe7560SGuenter Roeck 	if (!data)
89538fe7560SGuenter Roeck 		return -ENOMEM;
896251eb40fSJonathan Cameron 
897251eb40fSJonathan Cameron 	INIT_WORK(&data->read_work, sht15_bh_read_data);
898251eb40fSJonathan Cameron 	INIT_WORK(&data->update_supply_work, sht15_update_voltage);
899251eb40fSJonathan Cameron 	platform_set_drvdata(pdev, data);
900251eb40fSJonathan Cameron 	mutex_init(&data->read_lock);
901251eb40fSJonathan Cameron 	data->dev = &pdev->dev;
902251eb40fSJonathan Cameron 	init_waitqueue_head(&data->wait_queue);
903251eb40fSJonathan Cameron 
904251eb40fSJonathan Cameron 	if (pdev->dev.platform_data == NULL) {
90599a0378dSVivien Didelot 		dev_err(&pdev->dev, "no platform data supplied\n");
90638fe7560SGuenter Roeck 		return -EINVAL;
907251eb40fSJonathan Cameron 	}
908251eb40fSJonathan Cameron 	data->pdata = pdev->dev.platform_data;
909251eb40fSJonathan Cameron 	data->supply_uV = data->pdata->supply_mv * 1000;
91082c7465bSJerome Oufella 	if (data->pdata->checksum)
91182c7465bSJerome Oufella 		data->checksumming = true;
912cc15c7ebSVivien Didelot 	if (data->pdata->no_otp_reload)
913cc15c7ebSVivien Didelot 		status |= SHT15_STATUS_NO_OTP_RELOAD;
914cc15c7ebSVivien Didelot 	if (data->pdata->low_resolution)
915cc15c7ebSVivien Didelot 		status |= SHT15_STATUS_LOW_RESOLUTION;
916251eb40fSJonathan Cameron 
91799a0378dSVivien Didelot 	/*
91899a0378dSVivien Didelot 	 * If a regulator is available,
91999a0378dSVivien Didelot 	 * query what the supply voltage actually is!
92099a0378dSVivien Didelot 	 */
92138fe7560SGuenter Roeck 	data->reg = devm_regulator_get(data->dev, "vcc");
922251eb40fSJonathan Cameron 	if (!IS_ERR(data->reg)) {
923c7a78d2cSJean Delvare 		int voltage;
924c7a78d2cSJean Delvare 
925c7a78d2cSJean Delvare 		voltage = regulator_get_voltage(data->reg);
926c7a78d2cSJean Delvare 		if (voltage)
927c7a78d2cSJean Delvare 			data->supply_uV = voltage;
928c7a78d2cSJean Delvare 
929251eb40fSJonathan Cameron 		regulator_enable(data->reg);
93099a0378dSVivien Didelot 		/*
93199a0378dSVivien Didelot 		 * Setup a notifier block to update this if another device
93299a0378dSVivien Didelot 		 * causes the voltage to change
93399a0378dSVivien Didelot 		 */
934251eb40fSJonathan Cameron 		data->nb.notifier_call = &sht15_invalidate_voltage;
935251eb40fSJonathan Cameron 		ret = regulator_register_notifier(data->reg, &data->nb);
936181148aeSVivien Didelot 		if (ret) {
937181148aeSVivien Didelot 			dev_err(&pdev->dev,
938181148aeSVivien Didelot 				"regulator notifier request failed\n");
939181148aeSVivien Didelot 			regulator_disable(data->reg);
94038fe7560SGuenter Roeck 			return ret;
941181148aeSVivien Didelot 		}
942251eb40fSJonathan Cameron 	}
94399a0378dSVivien Didelot 
944251eb40fSJonathan Cameron 	/* Try requesting the GPIOs */
94538fe7560SGuenter Roeck 	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
946251eb40fSJonathan Cameron 	if (ret) {
94799a0378dSVivien Didelot 		dev_err(&pdev->dev, "gpio request failed\n");
948181148aeSVivien Didelot 		goto err_release_reg;
949251eb40fSJonathan Cameron 	}
950251eb40fSJonathan Cameron 	gpio_direction_output(data->pdata->gpio_sck, 0);
95199a0378dSVivien Didelot 
95238fe7560SGuenter Roeck 	ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
95338fe7560SGuenter Roeck 				"SHT15 data");
954251eb40fSJonathan Cameron 	if (ret) {
95599a0378dSVivien Didelot 		dev_err(&pdev->dev, "gpio request failed\n");
95638fe7560SGuenter Roeck 		goto err_release_reg;
957251eb40fSJonathan Cameron 	}
958251eb40fSJonathan Cameron 
95938fe7560SGuenter Roeck 	ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
960251eb40fSJonathan Cameron 			       sht15_interrupt_fired,
961251eb40fSJonathan Cameron 			       IRQF_TRIGGER_FALLING,
962251eb40fSJonathan Cameron 			       "sht15 data",
963251eb40fSJonathan Cameron 			       data);
964251eb40fSJonathan Cameron 	if (ret) {
96599a0378dSVivien Didelot 		dev_err(&pdev->dev, "failed to get irq for data line\n");
96638fe7560SGuenter Roeck 		goto err_release_reg;
967251eb40fSJonathan Cameron 	}
968251eb40fSJonathan Cameron 	disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
969251eb40fSJonathan Cameron 	sht15_connection_reset(data);
970181148aeSVivien Didelot 	ret = sht15_soft_reset(data);
971181148aeSVivien Didelot 	if (ret)
97238fe7560SGuenter Roeck 		goto err_release_reg;
973181148aeSVivien Didelot 
974cc15c7ebSVivien Didelot 	/* write status with platform data options */
975cc15c7ebSVivien Didelot 	if (status) {
976cc15c7ebSVivien Didelot 		ret = sht15_send_status(data, status);
977cc15c7ebSVivien Didelot 		if (ret)
97838fe7560SGuenter Roeck 			goto err_release_reg;
979cc15c7ebSVivien Didelot 	}
980cc15c7ebSVivien Didelot 
981181148aeSVivien Didelot 	ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
982181148aeSVivien Didelot 	if (ret) {
983181148aeSVivien Didelot 		dev_err(&pdev->dev, "sysfs create failed\n");
98438fe7560SGuenter Roeck 		goto err_release_reg;
985181148aeSVivien Didelot 	}
986251eb40fSJonathan Cameron 
987251eb40fSJonathan Cameron 	data->hwmon_dev = hwmon_device_register(data->dev);
988251eb40fSJonathan Cameron 	if (IS_ERR(data->hwmon_dev)) {
989251eb40fSJonathan Cameron 		ret = PTR_ERR(data->hwmon_dev);
990181148aeSVivien Didelot 		goto err_release_sysfs_group;
991251eb40fSJonathan Cameron 	}
99299a0378dSVivien Didelot 
993251eb40fSJonathan Cameron 	return 0;
994251eb40fSJonathan Cameron 
995181148aeSVivien Didelot err_release_sysfs_group:
996181148aeSVivien Didelot 	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
997181148aeSVivien Didelot err_release_reg:
998181148aeSVivien Didelot 	if (!IS_ERR(data->reg)) {
999181148aeSVivien Didelot 		regulator_unregister_notifier(data->reg, &data->nb);
1000181148aeSVivien Didelot 		regulator_disable(data->reg);
1001181148aeSVivien Didelot 	}
1002251eb40fSJonathan Cameron 	return ret;
1003251eb40fSJonathan Cameron }
1004251eb40fSJonathan Cameron 
1005251eb40fSJonathan Cameron static int __devexit sht15_remove(struct platform_device *pdev)
1006251eb40fSJonathan Cameron {
1007251eb40fSJonathan Cameron 	struct sht15_data *data = platform_get_drvdata(pdev);
1008251eb40fSJonathan Cameron 
100999a0378dSVivien Didelot 	/*
101099a0378dSVivien Didelot 	 * Make sure any reads from the device are done and
101199a0378dSVivien Didelot 	 * prevent new ones beginning
101299a0378dSVivien Didelot 	 */
1013251eb40fSJonathan Cameron 	mutex_lock(&data->read_lock);
1014cc15c7ebSVivien Didelot 	if (sht15_soft_reset(data)) {
1015cc15c7ebSVivien Didelot 		mutex_unlock(&data->read_lock);
1016cc15c7ebSVivien Didelot 		return -EFAULT;
1017cc15c7ebSVivien Didelot 	}
1018251eb40fSJonathan Cameron 	hwmon_device_unregister(data->hwmon_dev);
1019251eb40fSJonathan Cameron 	sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
1020251eb40fSJonathan Cameron 	if (!IS_ERR(data->reg)) {
1021251eb40fSJonathan Cameron 		regulator_unregister_notifier(data->reg, &data->nb);
1022251eb40fSJonathan Cameron 		regulator_disable(data->reg);
1023251eb40fSJonathan Cameron 	}
1024251eb40fSJonathan Cameron 
1025251eb40fSJonathan Cameron 	mutex_unlock(&data->read_lock);
102699a0378dSVivien Didelot 
1027251eb40fSJonathan Cameron 	return 0;
1028251eb40fSJonathan Cameron }
1029251eb40fSJonathan Cameron 
1030edec5af7SVivien Didelot static struct platform_device_id sht15_device_ids[] = {
1031edec5af7SVivien Didelot 	{ "sht10", sht10 },
1032edec5af7SVivien Didelot 	{ "sht11", sht11 },
1033edec5af7SVivien Didelot 	{ "sht15", sht15 },
1034edec5af7SVivien Didelot 	{ "sht71", sht71 },
1035edec5af7SVivien Didelot 	{ "sht75", sht75 },
1036edec5af7SVivien Didelot 	{ }
1037edec5af7SVivien Didelot };
1038edec5af7SVivien Didelot MODULE_DEVICE_TABLE(platform, sht15_device_ids);
1039edec5af7SVivien Didelot 
1040edec5af7SVivien Didelot static struct platform_driver sht15_driver = {
1041251eb40fSJonathan Cameron 	.driver = {
1042251eb40fSJonathan Cameron 		.name = "sht15",
1043251eb40fSJonathan Cameron 		.owner = THIS_MODULE,
1044251eb40fSJonathan Cameron 	},
1045251eb40fSJonathan Cameron 	.probe = sht15_probe,
10469e5e9b7aSBill Pemberton 	.remove = sht15_remove,
1047edec5af7SVivien Didelot 	.id_table = sht15_device_ids,
1048251eb40fSJonathan Cameron };
1049edec5af7SVivien Didelot module_platform_driver(sht15_driver);
1050251eb40fSJonathan Cameron 
1051251eb40fSJonathan Cameron MODULE_LICENSE("GPL");
1052edec5af7SVivien Didelot MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver");
1053