139ea6ea3SFabio Estevam // SPDX-License-Identifier: GPL-2.0
2251eb40fSJonathan Cameron /*
3251eb40fSJonathan Cameron * sht15.c - support for the SHT15 Temperature and Humidity Sensor
4251eb40fSJonathan Cameron *
5edec5af7SVivien Didelot * Portions Copyright (c) 2010-2012 Savoir-faire Linux Inc.
682c7465bSJerome Oufella * Jerome Oufella <jerome.oufella@savoirfairelinux.com>
7cc15c7ebSVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
8cc15c7ebSVivien Didelot *
9251eb40fSJonathan Cameron * Copyright (c) 2009 Jonathan Cameron
10251eb40fSJonathan Cameron *
11251eb40fSJonathan Cameron * Copyright (c) 2007 Wouter Horre
12251eb40fSJonathan Cameron *
137ebd8b66SMauro Carvalho Chehab * For further information, see the Documentation/hwmon/sht15.rst file.
14251eb40fSJonathan Cameron */
15251eb40fSJonathan Cameron
16251eb40fSJonathan Cameron #include <linux/interrupt.h>
17251eb40fSJonathan Cameron #include <linux/irq.h>
18251eb40fSJonathan Cameron #include <linux/module.h>
19251eb40fSJonathan Cameron #include <linux/init.h>
20251eb40fSJonathan Cameron #include <linux/hwmon.h>
21251eb40fSJonathan Cameron #include <linux/hwmon-sysfs.h>
22251eb40fSJonathan Cameron #include <linux/mutex.h>
23251eb40fSJonathan Cameron #include <linux/platform_device.h>
24d43c36dcSAlexey Dobriyan #include <linux/sched.h>
25251eb40fSJonathan Cameron #include <linux/delay.h>
26251eb40fSJonathan Cameron #include <linux/jiffies.h>
27251eb40fSJonathan Cameron #include <linux/err.h>
28251eb40fSJonathan Cameron #include <linux/regulator/consumer.h>
295a0e3ad6STejun Heo #include <linux/slab.h>
3060063497SArun Sharma #include <linux/atomic.h>
3133836ee9Syalin wang #include <linux/bitrev.h>
3218673114SLinus Walleij #include <linux/gpio/consumer.h>
3318673114SLinus Walleij #include <linux/of.h>
34251eb40fSJonathan Cameron
3599a0378dSVivien Didelot /* Commands */
3699a0378dSVivien Didelot #define SHT15_MEASURE_TEMP 0x03
3799a0378dSVivien Didelot #define SHT15_MEASURE_RH 0x05
38cc15c7ebSVivien Didelot #define SHT15_WRITE_STATUS 0x06
39cc15c7ebSVivien Didelot #define SHT15_READ_STATUS 0x07
40181148aeSVivien Didelot #define SHT15_SOFT_RESET 0x1E
41251eb40fSJonathan Cameron
4299a0378dSVivien Didelot /* Min timings */
4399a0378dSVivien Didelot #define SHT15_TSCKL 100 /* (nsecs) clock low */
4499a0378dSVivien Didelot #define SHT15_TSCKH 100 /* (nsecs) clock high */
4599a0378dSVivien Didelot #define SHT15_TSU 150 /* (nsecs) data setup time */
46181148aeSVivien Didelot #define SHT15_TSRST 11 /* (msecs) soft reset time */
47251eb40fSJonathan Cameron
48cc15c7ebSVivien Didelot /* Status Register Bits */
49cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_RESOLUTION 0x01
50cc15c7ebSVivien Didelot #define SHT15_STATUS_NO_OTP_RELOAD 0x02
51cc15c7ebSVivien Didelot #define SHT15_STATUS_HEATER 0x04
52cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_BATTERY 0x40
53cc15c7ebSVivien Didelot
54edec5af7SVivien Didelot /* List of supported chips */
55edec5af7SVivien Didelot enum sht15_chips { sht10, sht11, sht15, sht71, sht75 };
56edec5af7SVivien Didelot
5799a0378dSVivien Didelot /* Actions the driver may be doing */
5899a0378dSVivien Didelot enum sht15_state {
5999a0378dSVivien Didelot SHT15_READING_NOTHING,
6099a0378dSVivien Didelot SHT15_READING_TEMP,
6199a0378dSVivien Didelot SHT15_READING_HUMID
6299a0378dSVivien Didelot };
63251eb40fSJonathan Cameron
64251eb40fSJonathan Cameron /**
6525985edcSLucas De Marchi * struct sht15_temppair - elements of voltage dependent temp calc
66251eb40fSJonathan Cameron * @vdd: supply voltage in microvolts
67251eb40fSJonathan Cameron * @d1: see data sheet
68251eb40fSJonathan Cameron */
69251eb40fSJonathan Cameron struct sht15_temppair {
70251eb40fSJonathan Cameron int vdd; /* microvolts */
71251eb40fSJonathan Cameron int d1;
72251eb40fSJonathan Cameron };
73251eb40fSJonathan Cameron
7499a0378dSVivien Didelot /* Table 9 from datasheet - relates temperature calculation to supply voltage */
75251eb40fSJonathan Cameron static const struct sht15_temppair temppoints[] = {
76251eb40fSJonathan Cameron { 2500000, -39400 },
77251eb40fSJonathan Cameron { 3000000, -39600 },
78251eb40fSJonathan Cameron { 3500000, -39700 },
79251eb40fSJonathan Cameron { 4000000, -39800 },
80251eb40fSJonathan Cameron { 5000000, -40100 },
81251eb40fSJonathan Cameron };
82251eb40fSJonathan Cameron
8382c7465bSJerome Oufella /* Table from CRC datasheet, section 2.4 */
8482c7465bSJerome Oufella static const u8 sht15_crc8_table[] = {
8582c7465bSJerome Oufella 0, 49, 98, 83, 196, 245, 166, 151,
8682c7465bSJerome Oufella 185, 136, 219, 234, 125, 76, 31, 46,
8782c7465bSJerome Oufella 67, 114, 33, 16, 135, 182, 229, 212,
8882c7465bSJerome Oufella 250, 203, 152, 169, 62, 15, 92, 109,
8982c7465bSJerome Oufella 134, 183, 228, 213, 66, 115, 32, 17,
9082c7465bSJerome Oufella 63, 14, 93, 108, 251, 202, 153, 168,
9182c7465bSJerome Oufella 197, 244, 167, 150, 1, 48, 99, 82,
9282c7465bSJerome Oufella 124, 77, 30, 47, 184, 137, 218, 235,
9382c7465bSJerome Oufella 61, 12, 95, 110, 249, 200, 155, 170,
9482c7465bSJerome Oufella 132, 181, 230, 215, 64, 113, 34, 19,
9582c7465bSJerome Oufella 126, 79, 28, 45, 186, 139, 216, 233,
9682c7465bSJerome Oufella 199, 246, 165, 148, 3, 50, 97, 80,
9782c7465bSJerome Oufella 187, 138, 217, 232, 127, 78, 29, 44,
9882c7465bSJerome Oufella 2, 51, 96, 81, 198, 247, 164, 149,
9982c7465bSJerome Oufella 248, 201, 154, 171, 60, 13, 94, 111,
10082c7465bSJerome Oufella 65, 112, 35, 18, 133, 180, 231, 214,
10182c7465bSJerome Oufella 122, 75, 24, 41, 190, 143, 220, 237,
10282c7465bSJerome Oufella 195, 242, 161, 144, 7, 54, 101, 84,
10382c7465bSJerome Oufella 57, 8, 91, 106, 253, 204, 159, 174,
10482c7465bSJerome Oufella 128, 177, 226, 211, 68, 117, 38, 23,
10582c7465bSJerome Oufella 252, 205, 158, 175, 56, 9, 90, 107,
10682c7465bSJerome Oufella 69, 116, 39, 22, 129, 176, 227, 210,
10782c7465bSJerome Oufella 191, 142, 221, 236, 123, 74, 25, 40,
10882c7465bSJerome Oufella 6, 55, 100, 85, 194, 243, 160, 145,
10982c7465bSJerome Oufella 71, 118, 37, 20, 131, 178, 225, 208,
11082c7465bSJerome Oufella 254, 207, 156, 173, 58, 11, 88, 105,
11182c7465bSJerome Oufella 4, 53, 102, 87, 192, 241, 162, 147,
11282c7465bSJerome Oufella 189, 140, 223, 238, 121, 72, 27, 42,
11382c7465bSJerome Oufella 193, 240, 163, 146, 5, 52, 103, 86,
11482c7465bSJerome Oufella 120, 73, 26, 43, 188, 141, 222, 239,
11582c7465bSJerome Oufella 130, 179, 224, 209, 70, 119, 36, 21,
11682c7465bSJerome Oufella 59, 10, 89, 104, 255, 206, 157, 172
11782c7465bSJerome Oufella };
11882c7465bSJerome Oufella
119251eb40fSJonathan Cameron /**
120251eb40fSJonathan Cameron * struct sht15_data - device instance specific data
12118673114SLinus Walleij * @sck: clock GPIO line
12218673114SLinus Walleij * @data: data GPIO line
12399a0378dSVivien Didelot * @read_work: bh of interrupt handler.
12499a0378dSVivien Didelot * @wait_queue: wait queue for getting values from device.
12599a0378dSVivien Didelot * @val_temp: last temperature value read from device.
12699a0378dSVivien Didelot * @val_humid: last humidity value read from device.
127cc15c7ebSVivien Didelot * @val_status: last status register value read from device.
12882c7465bSJerome Oufella * @checksum_ok: last value read from the device passed CRC validation.
12982c7465bSJerome Oufella * @checksumming: flag used to enable the data validation with CRC.
13099a0378dSVivien Didelot * @state: state identifying the action the driver is doing.
13199a0378dSVivien Didelot * @measurements_valid: are the current stored measures valid (start condition).
132cc15c7ebSVivien Didelot * @status_valid: is the current stored status valid (start condition).
13399a0378dSVivien Didelot * @last_measurement: time of last measure.
134cc15c7ebSVivien Didelot * @last_status: time of last status reading.
13599a0378dSVivien Didelot * @read_lock: mutex to ensure only one read in progress at a time.
13699a0378dSVivien Didelot * @dev: associate device structure.
13799a0378dSVivien Didelot * @hwmon_dev: device associated with hwmon subsystem.
13899a0378dSVivien Didelot * @reg: associated regulator (if specified).
13999a0378dSVivien Didelot * @nb: notifier block to handle notifications of voltage
14099a0378dSVivien Didelot * changes.
141142c0901SVivien Didelot * @supply_uv: local copy of supply voltage used to allow use of
14299a0378dSVivien Didelot * regulator consumer if available.
143142c0901SVivien Didelot * @supply_uv_valid: indicates that an updated value has not yet been
14499a0378dSVivien Didelot * obtained from the regulator and so any calculations
145251eb40fSJonathan Cameron * based upon it will be invalid.
146142c0901SVivien Didelot * @update_supply_work: work struct that is used to update the supply_uv.
14799a0378dSVivien Didelot * @interrupt_handled: flag used to indicate a handler has been scheduled.
148251eb40fSJonathan Cameron */
149251eb40fSJonathan Cameron struct sht15_data {
15018673114SLinus Walleij struct gpio_desc *sck;
15118673114SLinus Walleij struct gpio_desc *data;
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;
169142c0901SVivien Didelot int supply_uv;
170142c0901SVivien 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_crc8() - compute crc8
17782c7465bSJerome Oufella * @data: sht15 specific data.
17882c7465bSJerome Oufella * @value: sht15 retrieved data.
179d5324e90SGuenter Roeck * @len: Length of retrieved data
18082c7465bSJerome Oufella *
18182c7465bSJerome Oufella * This implements section 2 of the CRC datasheet.
18282c7465bSJerome Oufella */
sht15_crc8(struct sht15_data * data,const u8 * value,int len)18382c7465bSJerome Oufella static u8 sht15_crc8(struct sht15_data *data,
18482c7465bSJerome Oufella const u8 *value,
18582c7465bSJerome Oufella int len)
18682c7465bSJerome Oufella {
18733836ee9Syalin wang u8 crc = bitrev8(data->val_status & 0x0F);
18882c7465bSJerome Oufella
18982c7465bSJerome Oufella while (len--) {
19082c7465bSJerome Oufella crc = sht15_crc8_table[*value ^ crc];
19182c7465bSJerome Oufella value++;
19282c7465bSJerome Oufella }
19382c7465bSJerome Oufella
19482c7465bSJerome Oufella return crc;
19582c7465bSJerome Oufella }
19682c7465bSJerome Oufella
19782c7465bSJerome Oufella /**
198251eb40fSJonathan Cameron * sht15_connection_reset() - reset the comms interface
199251eb40fSJonathan Cameron * @data: sht15 specific data
200251eb40fSJonathan Cameron *
201251eb40fSJonathan Cameron * This implements section 3.4 of the data sheet
202251eb40fSJonathan Cameron */
sht15_connection_reset(struct sht15_data * data)203412e29c1SVivien Didelot static int sht15_connection_reset(struct sht15_data *data)
204251eb40fSJonathan Cameron {
205412e29c1SVivien Didelot int i, err;
20699a0378dSVivien Didelot
20718673114SLinus Walleij err = gpiod_direction_output(data->data, 1);
208412e29c1SVivien Didelot if (err)
209412e29c1SVivien Didelot return err;
210251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
21118673114SLinus Walleij gpiod_set_value(data->sck, 0);
212251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
213251eb40fSJonathan Cameron for (i = 0; i < 9; ++i) {
21418673114SLinus Walleij gpiod_set_value(data->sck, 1);
215251eb40fSJonathan Cameron ndelay(SHT15_TSCKH);
21618673114SLinus Walleij gpiod_set_value(data->sck, 0);
217251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
218251eb40fSJonathan Cameron }
219412e29c1SVivien Didelot return 0;
220251eb40fSJonathan Cameron }
22199a0378dSVivien Didelot
222251eb40fSJonathan Cameron /**
223251eb40fSJonathan Cameron * sht15_send_bit() - send an individual bit to the device
224251eb40fSJonathan Cameron * @data: device state data
225251eb40fSJonathan Cameron * @val: value of bit to be sent
22699a0378dSVivien Didelot */
sht15_send_bit(struct sht15_data * data,int val)227251eb40fSJonathan Cameron static inline void sht15_send_bit(struct sht15_data *data, int val)
228251eb40fSJonathan Cameron {
22918673114SLinus Walleij gpiod_set_value(data->data, val);
230251eb40fSJonathan Cameron ndelay(SHT15_TSU);
23118673114SLinus Walleij gpiod_set_value(data->sck, 1);
232251eb40fSJonathan Cameron ndelay(SHT15_TSCKH);
23318673114SLinus Walleij gpiod_set_value(data->sck, 0);
234251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); /* clock low time */
235251eb40fSJonathan Cameron }
236251eb40fSJonathan Cameron
237251eb40fSJonathan Cameron /**
238251eb40fSJonathan Cameron * sht15_transmission_start() - specific sequence for new transmission
239251eb40fSJonathan Cameron * @data: device state data
24099a0378dSVivien Didelot *
241251eb40fSJonathan Cameron * Timings for this are not documented on the data sheet, so very
242251eb40fSJonathan Cameron * conservative ones used in implementation. This implements
243251eb40fSJonathan Cameron * figure 12 on the data sheet.
24499a0378dSVivien Didelot */
sht15_transmission_start(struct sht15_data * data)245412e29c1SVivien Didelot static int sht15_transmission_start(struct sht15_data *data)
246251eb40fSJonathan Cameron {
247412e29c1SVivien Didelot int err;
248412e29c1SVivien Didelot
249251eb40fSJonathan Cameron /* ensure data is high and output */
25018673114SLinus Walleij err = gpiod_direction_output(data->data, 1);
251412e29c1SVivien Didelot if (err)
252412e29c1SVivien Didelot return err;
253251eb40fSJonathan Cameron ndelay(SHT15_TSU);
25418673114SLinus Walleij gpiod_set_value(data->sck, 0);
255251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
25618673114SLinus Walleij gpiod_set_value(data->sck, 1);
257251eb40fSJonathan Cameron ndelay(SHT15_TSCKH);
25818673114SLinus Walleij gpiod_set_value(data->data, 0);
259251eb40fSJonathan Cameron ndelay(SHT15_TSU);
26018673114SLinus Walleij gpiod_set_value(data->sck, 0);
261251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
26218673114SLinus Walleij gpiod_set_value(data->sck, 1);
263251eb40fSJonathan Cameron ndelay(SHT15_TSCKH);
26418673114SLinus Walleij gpiod_set_value(data->data, 1);
265251eb40fSJonathan Cameron ndelay(SHT15_TSU);
26618673114SLinus Walleij gpiod_set_value(data->sck, 0);
267251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
268412e29c1SVivien Didelot return 0;
269251eb40fSJonathan Cameron }
27099a0378dSVivien Didelot
271251eb40fSJonathan Cameron /**
272251eb40fSJonathan Cameron * sht15_send_byte() - send a single byte to the device
273251eb40fSJonathan Cameron * @data: device state
274251eb40fSJonathan Cameron * @byte: value to be sent
27599a0378dSVivien Didelot */
sht15_send_byte(struct sht15_data * data,u8 byte)276251eb40fSJonathan Cameron static void sht15_send_byte(struct sht15_data *data, u8 byte)
277251eb40fSJonathan Cameron {
278251eb40fSJonathan Cameron int i;
27999a0378dSVivien Didelot
280251eb40fSJonathan Cameron for (i = 0; i < 8; i++) {
281251eb40fSJonathan Cameron sht15_send_bit(data, !!(byte & 0x80));
282251eb40fSJonathan Cameron byte <<= 1;
283251eb40fSJonathan Cameron }
284251eb40fSJonathan Cameron }
28599a0378dSVivien Didelot
286251eb40fSJonathan Cameron /**
287251eb40fSJonathan Cameron * sht15_wait_for_response() - checks for ack from device
288251eb40fSJonathan Cameron * @data: device state
28999a0378dSVivien Didelot */
sht15_wait_for_response(struct sht15_data * data)290251eb40fSJonathan Cameron static int sht15_wait_for_response(struct sht15_data *data)
291251eb40fSJonathan Cameron {
292412e29c1SVivien Didelot int err;
293412e29c1SVivien Didelot
29418673114SLinus Walleij err = gpiod_direction_input(data->data);
295412e29c1SVivien Didelot if (err)
296412e29c1SVivien Didelot return err;
29718673114SLinus Walleij gpiod_set_value(data->sck, 1);
298251eb40fSJonathan Cameron ndelay(SHT15_TSCKH);
29918673114SLinus Walleij if (gpiod_get_value(data->data)) {
30018673114SLinus Walleij gpiod_set_value(data->sck, 0);
301251eb40fSJonathan Cameron dev_err(data->dev, "Command not acknowledged\n");
302412e29c1SVivien Didelot err = sht15_connection_reset(data);
303412e29c1SVivien Didelot if (err)
304412e29c1SVivien Didelot return err;
305251eb40fSJonathan Cameron return -EIO;
306251eb40fSJonathan Cameron }
30718673114SLinus Walleij gpiod_set_value(data->sck, 0);
308251eb40fSJonathan Cameron ndelay(SHT15_TSCKL);
309251eb40fSJonathan Cameron return 0;
310251eb40fSJonathan Cameron }
311251eb40fSJonathan Cameron
312251eb40fSJonathan Cameron /**
313251eb40fSJonathan Cameron * sht15_send_cmd() - Sends a command to the device.
314251eb40fSJonathan Cameron * @data: device state
315251eb40fSJonathan Cameron * @cmd: command byte to be sent
316251eb40fSJonathan Cameron *
317251eb40fSJonathan Cameron * On entry, sck is output low, data is output pull high
318251eb40fSJonathan Cameron * and the interrupt disabled.
31999a0378dSVivien Didelot */
sht15_send_cmd(struct sht15_data * data,u8 cmd)320251eb40fSJonathan Cameron static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
321251eb40fSJonathan Cameron {
322412e29c1SVivien Didelot int err;
32399a0378dSVivien Didelot
324412e29c1SVivien Didelot err = sht15_transmission_start(data);
325412e29c1SVivien Didelot if (err)
326412e29c1SVivien Didelot return err;
327251eb40fSJonathan Cameron sht15_send_byte(data, cmd);
328412e29c1SVivien Didelot return sht15_wait_for_response(data);
329251eb40fSJonathan Cameron }
33099a0378dSVivien Didelot
331251eb40fSJonathan Cameron /**
332181148aeSVivien Didelot * sht15_soft_reset() - send a soft reset command
333181148aeSVivien Didelot * @data: sht15 specific data.
334181148aeSVivien Didelot *
335181148aeSVivien Didelot * As described in section 3.2 of the datasheet.
336181148aeSVivien Didelot */
sht15_soft_reset(struct sht15_data * data)337181148aeSVivien Didelot static int sht15_soft_reset(struct sht15_data *data)
338181148aeSVivien Didelot {
339181148aeSVivien Didelot int ret;
340181148aeSVivien Didelot
341181148aeSVivien Didelot ret = sht15_send_cmd(data, SHT15_SOFT_RESET);
342181148aeSVivien Didelot if (ret)
343181148aeSVivien Didelot return ret;
344181148aeSVivien Didelot msleep(SHT15_TSRST);
345cc15c7ebSVivien Didelot /* device resets default hardware status register value */
346cc15c7ebSVivien Didelot data->val_status = 0;
347181148aeSVivien Didelot
348cc15c7ebSVivien Didelot return ret;
349cc15c7ebSVivien Didelot }
350cc15c7ebSVivien Didelot
351cc15c7ebSVivien Didelot /**
35282c7465bSJerome Oufella * sht15_ack() - send a ack
35382c7465bSJerome Oufella * @data: sht15 specific data.
35482c7465bSJerome Oufella *
35582c7465bSJerome Oufella * Each byte of data is acknowledged by pulling the data line
35682c7465bSJerome Oufella * low for one clock pulse.
35782c7465bSJerome Oufella */
sht15_ack(struct sht15_data * data)358412e29c1SVivien Didelot static int sht15_ack(struct sht15_data *data)
35982c7465bSJerome Oufella {
360412e29c1SVivien Didelot int err;
361412e29c1SVivien Didelot
36218673114SLinus Walleij err = gpiod_direction_output(data->data, 0);
363412e29c1SVivien Didelot if (err)
364412e29c1SVivien Didelot return err;
36582c7465bSJerome Oufella ndelay(SHT15_TSU);
36618673114SLinus Walleij gpiod_set_value(data->sck, 1);
36782c7465bSJerome Oufella ndelay(SHT15_TSU);
36818673114SLinus Walleij gpiod_set_value(data->sck, 0);
36982c7465bSJerome Oufella ndelay(SHT15_TSU);
37018673114SLinus Walleij gpiod_set_value(data->data, 1);
37182c7465bSJerome Oufella
37218673114SLinus Walleij return gpiod_direction_input(data->data);
37382c7465bSJerome Oufella }
37482c7465bSJerome Oufella
37582c7465bSJerome Oufella /**
376cc15c7ebSVivien Didelot * sht15_end_transmission() - notify device of end of transmission
377cc15c7ebSVivien Didelot * @data: device state.
378cc15c7ebSVivien Didelot *
379cc15c7ebSVivien Didelot * This is basically a NAK (single clock pulse, data high).
380cc15c7ebSVivien Didelot */
sht15_end_transmission(struct sht15_data * data)381412e29c1SVivien Didelot static int sht15_end_transmission(struct sht15_data *data)
382cc15c7ebSVivien Didelot {
383412e29c1SVivien Didelot int err;
384412e29c1SVivien Didelot
38518673114SLinus Walleij err = gpiod_direction_output(data->data, 1);
386412e29c1SVivien Didelot if (err)
387412e29c1SVivien Didelot return err;
388cc15c7ebSVivien Didelot ndelay(SHT15_TSU);
38918673114SLinus Walleij gpiod_set_value(data->sck, 1);
390cc15c7ebSVivien Didelot ndelay(SHT15_TSCKH);
39118673114SLinus Walleij gpiod_set_value(data->sck, 0);
392cc15c7ebSVivien Didelot ndelay(SHT15_TSCKL);
393412e29c1SVivien Didelot return 0;
394cc15c7ebSVivien Didelot }
395cc15c7ebSVivien Didelot
396cc15c7ebSVivien Didelot /**
397cc15c7ebSVivien Didelot * sht15_read_byte() - Read a byte back from the device
398cc15c7ebSVivien Didelot * @data: device state.
399cc15c7ebSVivien Didelot */
sht15_read_byte(struct sht15_data * data)400cc15c7ebSVivien Didelot static u8 sht15_read_byte(struct sht15_data *data)
401cc15c7ebSVivien Didelot {
402cc15c7ebSVivien Didelot int i;
403cc15c7ebSVivien Didelot u8 byte = 0;
404cc15c7ebSVivien Didelot
405cc15c7ebSVivien Didelot for (i = 0; i < 8; ++i) {
406cc15c7ebSVivien Didelot byte <<= 1;
40718673114SLinus Walleij gpiod_set_value(data->sck, 1);
408cc15c7ebSVivien Didelot ndelay(SHT15_TSCKH);
40918673114SLinus Walleij byte |= !!gpiod_get_value(data->data);
41018673114SLinus Walleij gpiod_set_value(data->sck, 0);
411cc15c7ebSVivien Didelot ndelay(SHT15_TSCKL);
412cc15c7ebSVivien Didelot }
413cc15c7ebSVivien Didelot return byte;
414cc15c7ebSVivien Didelot }
415cc15c7ebSVivien Didelot
416cc15c7ebSVivien Didelot /**
417cc15c7ebSVivien Didelot * sht15_send_status() - write the status register byte
418cc15c7ebSVivien Didelot * @data: sht15 specific data.
419cc15c7ebSVivien Didelot * @status: the byte to set the status register with.
420cc15c7ebSVivien Didelot *
421cc15c7ebSVivien Didelot * As described in figure 14 and table 5 of the datasheet.
422cc15c7ebSVivien Didelot */
sht15_send_status(struct sht15_data * data,u8 status)423cc15c7ebSVivien Didelot static int sht15_send_status(struct sht15_data *data, u8 status)
424cc15c7ebSVivien Didelot {
425412e29c1SVivien Didelot int err;
426cc15c7ebSVivien Didelot
427412e29c1SVivien Didelot err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
428412e29c1SVivien Didelot if (err)
429412e29c1SVivien Didelot return err;
43018673114SLinus Walleij err = gpiod_direction_output(data->data, 1);
431412e29c1SVivien Didelot if (err)
432412e29c1SVivien Didelot return err;
433cc15c7ebSVivien Didelot ndelay(SHT15_TSU);
434cc15c7ebSVivien Didelot sht15_send_byte(data, status);
435412e29c1SVivien Didelot err = sht15_wait_for_response(data);
436412e29c1SVivien Didelot if (err)
437412e29c1SVivien Didelot return err;
438cc15c7ebSVivien Didelot
439cc15c7ebSVivien Didelot data->val_status = status;
440181148aeSVivien Didelot return 0;
441181148aeSVivien Didelot }
442181148aeSVivien Didelot
443181148aeSVivien Didelot /**
444cc15c7ebSVivien Didelot * sht15_update_status() - get updated status register from device if too old
445cc15c7ebSVivien Didelot * @data: device instance specific data.
446cc15c7ebSVivien Didelot *
447cc15c7ebSVivien Didelot * As described in figure 15 and table 5 of the datasheet.
448cc15c7ebSVivien Didelot */
sht15_update_status(struct sht15_data * data)449cc15c7ebSVivien Didelot static int sht15_update_status(struct sht15_data *data)
450cc15c7ebSVivien Didelot {
451cc15c7ebSVivien Didelot int ret = 0;
452cc15c7ebSVivien Didelot u8 status;
45382c7465bSJerome Oufella u8 previous_config;
45482c7465bSJerome Oufella u8 dev_checksum = 0;
45582c7465bSJerome Oufella u8 checksum_vals[2];
456cc15c7ebSVivien Didelot int timeout = HZ;
457cc15c7ebSVivien Didelot
458cc15c7ebSVivien Didelot mutex_lock(&data->read_lock);
459cc15c7ebSVivien Didelot if (time_after(jiffies, data->last_status + timeout)
460cc15c7ebSVivien Didelot || !data->status_valid) {
461cc15c7ebSVivien Didelot ret = sht15_send_cmd(data, SHT15_READ_STATUS);
462cc15c7ebSVivien Didelot if (ret)
463412e29c1SVivien Didelot goto unlock;
464cc15c7ebSVivien Didelot status = sht15_read_byte(data);
465cc15c7ebSVivien Didelot
46682c7465bSJerome Oufella if (data->checksumming) {
46782c7465bSJerome Oufella sht15_ack(data);
46833836ee9Syalin wang dev_checksum = bitrev8(sht15_read_byte(data));
46982c7465bSJerome Oufella checksum_vals[0] = SHT15_READ_STATUS;
47082c7465bSJerome Oufella checksum_vals[1] = status;
47182c7465bSJerome Oufella data->checksum_ok = (sht15_crc8(data, checksum_vals, 2)
47282c7465bSJerome Oufella == dev_checksum);
47382c7465bSJerome Oufella }
47482c7465bSJerome Oufella
475412e29c1SVivien Didelot ret = sht15_end_transmission(data);
476412e29c1SVivien Didelot if (ret)
477412e29c1SVivien Didelot goto unlock;
478cc15c7ebSVivien Didelot
47982c7465bSJerome Oufella /*
48082c7465bSJerome Oufella * Perform checksum validation on the received data.
48182c7465bSJerome Oufella * Specification mentions that in case a checksum verification
48282c7465bSJerome Oufella * fails, a soft reset command must be sent to the device.
48382c7465bSJerome Oufella */
48482c7465bSJerome Oufella if (data->checksumming && !data->checksum_ok) {
48582c7465bSJerome Oufella previous_config = data->val_status & 0x07;
48682c7465bSJerome Oufella ret = sht15_soft_reset(data);
48782c7465bSJerome Oufella if (ret)
488412e29c1SVivien Didelot goto unlock;
48982c7465bSJerome Oufella if (previous_config) {
49082c7465bSJerome Oufella ret = sht15_send_status(data, previous_config);
49182c7465bSJerome Oufella if (ret) {
49282c7465bSJerome Oufella dev_err(data->dev,
49382c7465bSJerome Oufella "CRC validation failed, unable "
49482c7465bSJerome Oufella "to restore device settings\n");
495412e29c1SVivien Didelot goto unlock;
49682c7465bSJerome Oufella }
49782c7465bSJerome Oufella }
49882c7465bSJerome Oufella ret = -EAGAIN;
499412e29c1SVivien Didelot goto unlock;
50082c7465bSJerome Oufella }
50182c7465bSJerome Oufella
502cc15c7ebSVivien Didelot data->val_status = status;
503cc15c7ebSVivien Didelot data->status_valid = true;
504cc15c7ebSVivien Didelot data->last_status = jiffies;
505cc15c7ebSVivien Didelot }
506cc15c7ebSVivien Didelot
507412e29c1SVivien Didelot unlock:
508412e29c1SVivien Didelot mutex_unlock(&data->read_lock);
509cc15c7ebSVivien Didelot return ret;
510cc15c7ebSVivien Didelot }
511cc15c7ebSVivien Didelot
512cc15c7ebSVivien Didelot /**
51399a0378dSVivien Didelot * sht15_measurement() - get a new value from device
514251eb40fSJonathan Cameron * @data: device instance specific data
515251eb40fSJonathan Cameron * @command: command sent to request value
516251eb40fSJonathan Cameron * @timeout_msecs: timeout after which comms are assumed
517251eb40fSJonathan Cameron * to have failed are reset.
51899a0378dSVivien Didelot */
sht15_measurement(struct sht15_data * data,int command,int timeout_msecs)51999a0378dSVivien Didelot static int sht15_measurement(struct sht15_data *data,
520251eb40fSJonathan Cameron int command,
521251eb40fSJonathan Cameron int timeout_msecs)
522251eb40fSJonathan Cameron {
523251eb40fSJonathan Cameron int ret;
52482c7465bSJerome Oufella u8 previous_config;
52599a0378dSVivien Didelot
526251eb40fSJonathan Cameron ret = sht15_send_cmd(data, command);
527251eb40fSJonathan Cameron if (ret)
528251eb40fSJonathan Cameron return ret;
529251eb40fSJonathan Cameron
53018673114SLinus Walleij ret = gpiod_direction_input(data->data);
531412e29c1SVivien Didelot if (ret)
532412e29c1SVivien Didelot return ret;
533251eb40fSJonathan Cameron atomic_set(&data->interrupt_handled, 0);
534251eb40fSJonathan Cameron
53518673114SLinus Walleij enable_irq(gpiod_to_irq(data->data));
53618673114SLinus Walleij if (gpiod_get_value(data->data) == 0) {
53718673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data));
53825985edcSLucas De Marchi /* Only relevant if the interrupt hasn't occurred. */
539251eb40fSJonathan Cameron if (!atomic_read(&data->interrupt_handled))
540251eb40fSJonathan Cameron schedule_work(&data->read_work);
541251eb40fSJonathan Cameron }
542251eb40fSJonathan Cameron ret = wait_event_timeout(data->wait_queue,
54399a0378dSVivien Didelot (data->state == SHT15_READING_NOTHING),
544251eb40fSJonathan Cameron msecs_to_jiffies(timeout_msecs));
545412e29c1SVivien Didelot if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */
546412e29c1SVivien Didelot data->state = SHT15_READING_NOTHING;
547412e29c1SVivien Didelot return -EIO;
548412e29c1SVivien Didelot } else if (ret == 0) { /* timeout occurred */
54918673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data));
550412e29c1SVivien Didelot ret = sht15_connection_reset(data);
551412e29c1SVivien Didelot if (ret)
552412e29c1SVivien Didelot return ret;
553251eb40fSJonathan Cameron return -ETIME;
554251eb40fSJonathan Cameron }
55582c7465bSJerome Oufella
55682c7465bSJerome Oufella /*
55782c7465bSJerome Oufella * Perform checksum validation on the received data.
55882c7465bSJerome Oufella * Specification mentions that in case a checksum verification fails,
55982c7465bSJerome Oufella * a soft reset command must be sent to the device.
56082c7465bSJerome Oufella */
56182c7465bSJerome Oufella if (data->checksumming && !data->checksum_ok) {
56282c7465bSJerome Oufella previous_config = data->val_status & 0x07;
56382c7465bSJerome Oufella ret = sht15_soft_reset(data);
56482c7465bSJerome Oufella if (ret)
56582c7465bSJerome Oufella return ret;
56682c7465bSJerome Oufella if (previous_config) {
56782c7465bSJerome Oufella ret = sht15_send_status(data, previous_config);
56882c7465bSJerome Oufella if (ret) {
56982c7465bSJerome Oufella dev_err(data->dev,
57082c7465bSJerome Oufella "CRC validation failed, unable "
57182c7465bSJerome Oufella "to restore device settings\n");
57282c7465bSJerome Oufella return ret;
57382c7465bSJerome Oufella }
57482c7465bSJerome Oufella }
57582c7465bSJerome Oufella return -EAGAIN;
57682c7465bSJerome Oufella }
57782c7465bSJerome Oufella
578251eb40fSJonathan Cameron return 0;
579251eb40fSJonathan Cameron }
580251eb40fSJonathan Cameron
581251eb40fSJonathan Cameron /**
58299a0378dSVivien Didelot * sht15_update_measurements() - get updated measures from device if too old
583251eb40fSJonathan Cameron * @data: device state
58499a0378dSVivien Didelot */
sht15_update_measurements(struct sht15_data * data)58599a0378dSVivien Didelot static int sht15_update_measurements(struct sht15_data *data)
586251eb40fSJonathan Cameron {
587251eb40fSJonathan Cameron int ret = 0;
588251eb40fSJonathan Cameron int timeout = HZ;
589251eb40fSJonathan Cameron
590251eb40fSJonathan Cameron mutex_lock(&data->read_lock);
59199a0378dSVivien Didelot if (time_after(jiffies, data->last_measurement + timeout)
59299a0378dSVivien Didelot || !data->measurements_valid) {
59399a0378dSVivien Didelot data->state = SHT15_READING_HUMID;
59499a0378dSVivien Didelot ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
595251eb40fSJonathan Cameron if (ret)
596412e29c1SVivien Didelot goto unlock;
59799a0378dSVivien Didelot data->state = SHT15_READING_TEMP;
59899a0378dSVivien Didelot ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
599251eb40fSJonathan Cameron if (ret)
600412e29c1SVivien Didelot goto unlock;
60199a0378dSVivien Didelot data->measurements_valid = true;
60299a0378dSVivien Didelot data->last_measurement = jiffies;
603251eb40fSJonathan Cameron }
604251eb40fSJonathan Cameron
605412e29c1SVivien Didelot unlock:
606412e29c1SVivien Didelot mutex_unlock(&data->read_lock);
607251eb40fSJonathan Cameron return ret;
608251eb40fSJonathan Cameron }
609251eb40fSJonathan Cameron
610251eb40fSJonathan Cameron /**
611251eb40fSJonathan Cameron * sht15_calc_temp() - convert the raw reading to a temperature
612251eb40fSJonathan Cameron * @data: device state
613251eb40fSJonathan Cameron *
614251eb40fSJonathan Cameron * As per section 4.3 of the data sheet.
61599a0378dSVivien Didelot */
sht15_calc_temp(struct sht15_data * data)616251eb40fSJonathan Cameron static inline int sht15_calc_temp(struct sht15_data *data)
617251eb40fSJonathan Cameron {
618328a2c22SJerome Oufella int d1 = temppoints[0].d1;
619cc15c7ebSVivien Didelot int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
620251eb40fSJonathan Cameron int i;
621251eb40fSJonathan Cameron
622328a2c22SJerome Oufella for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
623251eb40fSJonathan Cameron /* Find pointer to interpolate */
624142c0901SVivien Didelot if (data->supply_uv > temppoints[i - 1].vdd) {
625142c0901SVivien Didelot d1 = (data->supply_uv - temppoints[i - 1].vdd)
626251eb40fSJonathan Cameron * (temppoints[i].d1 - temppoints[i - 1].d1)
627251eb40fSJonathan Cameron / (temppoints[i].vdd - temppoints[i - 1].vdd)
628251eb40fSJonathan Cameron + temppoints[i - 1].d1;
629251eb40fSJonathan Cameron break;
630251eb40fSJonathan Cameron }
631251eb40fSJonathan Cameron
632cc15c7ebSVivien Didelot return data->val_temp * d2 + d1;
633251eb40fSJonathan Cameron }
634251eb40fSJonathan Cameron
635251eb40fSJonathan Cameron /**
636251eb40fSJonathan Cameron * sht15_calc_humid() - using last temperature convert raw to humid
637251eb40fSJonathan Cameron * @data: device state
638251eb40fSJonathan Cameron *
639251eb40fSJonathan Cameron * This is the temperature compensated version as per section 4.2 of
640251eb40fSJonathan Cameron * the data sheet.
64199a0378dSVivien Didelot *
64299a0378dSVivien Didelot * The sensor is assumed to be V3, which is compatible with V4.
64399a0378dSVivien Didelot * Humidity conversion coefficients are shown in table 7 of the datasheet.
64499a0378dSVivien Didelot */
sht15_calc_humid(struct sht15_data * data)645251eb40fSJonathan Cameron static inline int sht15_calc_humid(struct sht15_data *data)
646251eb40fSJonathan Cameron {
64799a0378dSVivien Didelot int rh_linear; /* milli percent */
648251eb40fSJonathan Cameron int temp = sht15_calc_temp(data);
649cc15c7ebSVivien Didelot int c2, c3;
650cc15c7ebSVivien Didelot int t2;
651251eb40fSJonathan Cameron const int c1 = -4;
652cc15c7ebSVivien Didelot
653cc15c7ebSVivien Didelot if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
654cc15c7ebSVivien Didelot c2 = 648000; /* x 10 ^ -6 */
655cc15c7ebSVivien Didelot c3 = -7200; /* x 10 ^ -7 */
656cc15c7ebSVivien Didelot t2 = 1280;
657cc15c7ebSVivien Didelot } else {
658cc15c7ebSVivien Didelot c2 = 40500; /* x 10 ^ -6 */
659cc15c7ebSVivien Didelot c3 = -28; /* x 10 ^ -7 */
660cc15c7ebSVivien Didelot t2 = 80;
661cc15c7ebSVivien Didelot }
662251eb40fSJonathan Cameron
66399a0378dSVivien Didelot rh_linear = c1 * 1000
664251eb40fSJonathan Cameron + c2 * data->val_humid / 1000
665ccd32e73SVivien Didelot + (data->val_humid * data->val_humid * c3) / 10000;
666cc15c7ebSVivien Didelot return (temp - 25000) * (10000 + t2 * data->val_humid)
66799a0378dSVivien Didelot / 1000000 + rh_linear;
668251eb40fSJonathan Cameron }
669251eb40fSJonathan Cameron
67099a0378dSVivien Didelot /**
671*ffdb3ba0SRandy Dunlap * sht15_status_show() - show status information in sysfs
672cc15c7ebSVivien Didelot * @dev: device.
673cc15c7ebSVivien Didelot * @attr: device attribute.
674cc15c7ebSVivien Didelot * @buf: sysfs buffer where information is written to.
675cc15c7ebSVivien Didelot *
676cc15c7ebSVivien Didelot * Will be called on read access to temp1_fault, humidity1_fault
677cc15c7ebSVivien Didelot * and heater_enable sysfs attributes.
678cc15c7ebSVivien Didelot * Returns number of bytes written into buffer, negative errno on error.
679cc15c7ebSVivien Didelot */
sht15_status_show(struct device * dev,struct device_attribute * attr,char * buf)68041c9a49aSGuenter Roeck static ssize_t sht15_status_show(struct device *dev,
68141c9a49aSGuenter Roeck struct device_attribute *attr, char *buf)
682cc15c7ebSVivien Didelot {
683cc15c7ebSVivien Didelot int ret;
684cc15c7ebSVivien Didelot struct sht15_data *data = dev_get_drvdata(dev);
685cc15c7ebSVivien Didelot u8 bit = to_sensor_dev_attr(attr)->index;
686cc15c7ebSVivien Didelot
687cc15c7ebSVivien Didelot ret = sht15_update_status(data);
688cc15c7ebSVivien Didelot
689cc15c7ebSVivien Didelot return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
690cc15c7ebSVivien Didelot }
691cc15c7ebSVivien Didelot
692cc15c7ebSVivien Didelot /**
693*ffdb3ba0SRandy Dunlap * sht15_status_store() - change heater state via sysfs
694cc15c7ebSVivien Didelot * @dev: device.
695cc15c7ebSVivien Didelot * @attr: device attribute.
696cc15c7ebSVivien Didelot * @buf: sysfs buffer to read the new heater state from.
697cc15c7ebSVivien Didelot * @count: length of the data.
698cc15c7ebSVivien Didelot *
699e9b6e9f3SVivien Didelot * Will be called on write access to heater_enable sysfs attribute.
700cc15c7ebSVivien Didelot * Returns number of bytes actually decoded, negative errno on error.
701cc15c7ebSVivien Didelot */
sht15_status_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)70241c9a49aSGuenter Roeck static ssize_t sht15_status_store(struct device *dev,
703cc15c7ebSVivien Didelot struct device_attribute *attr,
704cc15c7ebSVivien Didelot const char *buf, size_t count)
705cc15c7ebSVivien Didelot {
706cc15c7ebSVivien Didelot int ret;
707cc15c7ebSVivien Didelot struct sht15_data *data = dev_get_drvdata(dev);
708cc15c7ebSVivien Didelot long value;
709cc15c7ebSVivien Didelot u8 status;
710cc15c7ebSVivien Didelot
711179c4fdbSFrans Meulenbroeks if (kstrtol(buf, 10, &value))
712cc15c7ebSVivien Didelot return -EINVAL;
713cc15c7ebSVivien Didelot
714cc15c7ebSVivien Didelot mutex_lock(&data->read_lock);
715cc15c7ebSVivien Didelot status = data->val_status & 0x07;
716cc15c7ebSVivien Didelot if (!!value)
717cc15c7ebSVivien Didelot status |= SHT15_STATUS_HEATER;
718cc15c7ebSVivien Didelot else
719cc15c7ebSVivien Didelot status &= ~SHT15_STATUS_HEATER;
720cc15c7ebSVivien Didelot
721cc15c7ebSVivien Didelot ret = sht15_send_status(data, status);
722cc15c7ebSVivien Didelot mutex_unlock(&data->read_lock);
723cc15c7ebSVivien Didelot
724cc15c7ebSVivien Didelot return ret ? ret : count;
725cc15c7ebSVivien Didelot }
726cc15c7ebSVivien Didelot
727cc15c7ebSVivien Didelot /**
728*ffdb3ba0SRandy Dunlap * sht15_temp_show() - show temperature measurement value in sysfs
72999a0378dSVivien Didelot * @dev: device.
73099a0378dSVivien Didelot * @attr: device attribute.
73199a0378dSVivien Didelot * @buf: sysfs buffer where measurement values are written to.
73299a0378dSVivien Didelot *
73399a0378dSVivien Didelot * Will be called on read access to temp1_input sysfs attribute.
73499a0378dSVivien Didelot * Returns number of bytes written into buffer, negative errno on error.
73599a0378dSVivien Didelot */
sht15_temp_show(struct device * dev,struct device_attribute * attr,char * buf)73641c9a49aSGuenter Roeck static ssize_t sht15_temp_show(struct device *dev,
73741c9a49aSGuenter Roeck struct device_attribute *attr, char *buf)
738251eb40fSJonathan Cameron {
739251eb40fSJonathan Cameron int ret;
740251eb40fSJonathan Cameron struct sht15_data *data = dev_get_drvdata(dev);
741251eb40fSJonathan Cameron
742251eb40fSJonathan Cameron /* Technically no need to read humidity as well */
74399a0378dSVivien Didelot ret = sht15_update_measurements(data);
744251eb40fSJonathan Cameron
745251eb40fSJonathan Cameron return ret ? ret : sprintf(buf, "%d\n",
746251eb40fSJonathan Cameron sht15_calc_temp(data));
747251eb40fSJonathan Cameron }
748251eb40fSJonathan Cameron
74999a0378dSVivien Didelot /**
750*ffdb3ba0SRandy Dunlap * sht15_humidity_show() - show humidity measurement value in sysfs
75199a0378dSVivien Didelot * @dev: device.
75299a0378dSVivien Didelot * @attr: device attribute.
75399a0378dSVivien Didelot * @buf: sysfs buffer where measurement values are written to.
75499a0378dSVivien Didelot *
75599a0378dSVivien Didelot * Will be called on read access to humidity1_input sysfs attribute.
75699a0378dSVivien Didelot * Returns number of bytes written into buffer, negative errno on error.
75799a0378dSVivien Didelot */
sht15_humidity_show(struct device * dev,struct device_attribute * attr,char * buf)75841c9a49aSGuenter Roeck static ssize_t sht15_humidity_show(struct device *dev,
75941c9a49aSGuenter Roeck struct device_attribute *attr, char *buf)
760251eb40fSJonathan Cameron {
761251eb40fSJonathan Cameron int ret;
762251eb40fSJonathan Cameron struct sht15_data *data = dev_get_drvdata(dev);
763251eb40fSJonathan Cameron
76499a0378dSVivien Didelot ret = sht15_update_measurements(data);
765251eb40fSJonathan Cameron
766251eb40fSJonathan Cameron return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
76799a0378dSVivien Didelot }
76899a0378dSVivien Didelot
name_show(struct device * dev,struct device_attribute * attr,char * buf)769af3d387fSJulia Lawall static ssize_t name_show(struct device *dev,
770251eb40fSJonathan Cameron struct device_attribute *attr,
771251eb40fSJonathan Cameron char *buf)
772251eb40fSJonathan Cameron {
773251eb40fSJonathan Cameron struct platform_device *pdev = to_platform_device(dev);
774251eb40fSJonathan Cameron return sprintf(buf, "%s\n", pdev->name);
775251eb40fSJonathan Cameron }
776251eb40fSJonathan Cameron
77741c9a49aSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_input, sht15_temp, 0);
77841c9a49aSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(humidity1_input, sht15_humidity, 0);
77941c9a49aSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp1_fault, sht15_status,
780cc15c7ebSVivien Didelot SHT15_STATUS_LOW_BATTERY);
78141c9a49aSGuenter Roeck static SENSOR_DEVICE_ATTR_RO(humidity1_fault, sht15_status,
782cc15c7ebSVivien Didelot SHT15_STATUS_LOW_BATTERY);
78341c9a49aSGuenter Roeck static SENSOR_DEVICE_ATTR_RW(heater_enable, sht15_status, SHT15_STATUS_HEATER);
784af3d387fSJulia Lawall static DEVICE_ATTR_RO(name);
785251eb40fSJonathan Cameron static struct attribute *sht15_attrs[] = {
786251eb40fSJonathan Cameron &sensor_dev_attr_temp1_input.dev_attr.attr,
787251eb40fSJonathan Cameron &sensor_dev_attr_humidity1_input.dev_attr.attr,
788cc15c7ebSVivien Didelot &sensor_dev_attr_temp1_fault.dev_attr.attr,
789cc15c7ebSVivien Didelot &sensor_dev_attr_humidity1_fault.dev_attr.attr,
790cc15c7ebSVivien Didelot &sensor_dev_attr_heater_enable.dev_attr.attr,
791251eb40fSJonathan Cameron &dev_attr_name.attr,
792251eb40fSJonathan Cameron NULL,
793251eb40fSJonathan Cameron };
794251eb40fSJonathan Cameron
795251eb40fSJonathan Cameron static const struct attribute_group sht15_attr_group = {
796251eb40fSJonathan Cameron .attrs = sht15_attrs,
797251eb40fSJonathan Cameron };
798251eb40fSJonathan Cameron
sht15_interrupt_fired(int irq,void * d)799251eb40fSJonathan Cameron static irqreturn_t sht15_interrupt_fired(int irq, void *d)
800251eb40fSJonathan Cameron {
801251eb40fSJonathan Cameron struct sht15_data *data = d;
80299a0378dSVivien Didelot
803251eb40fSJonathan Cameron /* First disable the interrupt */
804251eb40fSJonathan Cameron disable_irq_nosync(irq);
805251eb40fSJonathan Cameron atomic_inc(&data->interrupt_handled);
806251eb40fSJonathan Cameron /* Then schedule a reading work struct */
80799a0378dSVivien Didelot if (data->state != SHT15_READING_NOTHING)
808251eb40fSJonathan Cameron schedule_work(&data->read_work);
809251eb40fSJonathan Cameron return IRQ_HANDLED;
810251eb40fSJonathan Cameron }
811251eb40fSJonathan Cameron
sht15_bh_read_data(struct work_struct * work_s)812251eb40fSJonathan Cameron static void sht15_bh_read_data(struct work_struct *work_s)
813251eb40fSJonathan Cameron {
814251eb40fSJonathan Cameron uint16_t val = 0;
81582c7465bSJerome Oufella u8 dev_checksum = 0;
81682c7465bSJerome Oufella u8 checksum_vals[3];
817251eb40fSJonathan Cameron struct sht15_data *data
818251eb40fSJonathan Cameron = container_of(work_s, struct sht15_data,
819251eb40fSJonathan Cameron read_work);
82099a0378dSVivien Didelot
821251eb40fSJonathan Cameron /* Firstly, verify the line is low */
82218673114SLinus Walleij if (gpiod_get_value(data->data)) {
82399a0378dSVivien Didelot /*
82499a0378dSVivien Didelot * If not, then start the interrupt again - care here as could
82599a0378dSVivien Didelot * have gone low in meantime so verify it hasn't!
826251eb40fSJonathan Cameron */
827251eb40fSJonathan Cameron atomic_set(&data->interrupt_handled, 0);
82818673114SLinus Walleij enable_irq(gpiod_to_irq(data->data));
829c9e1498aSFrans Meulenbroeks /* If still not occurred or another handler was scheduled */
83018673114SLinus Walleij if (gpiod_get_value(data->data)
831251eb40fSJonathan Cameron || atomic_read(&data->interrupt_handled))
832251eb40fSJonathan Cameron return;
833251eb40fSJonathan Cameron }
83499a0378dSVivien Didelot
835251eb40fSJonathan Cameron /* Read the data back from the device */
836cc15c7ebSVivien Didelot val = sht15_read_byte(data);
837cc15c7ebSVivien Didelot val <<= 8;
838412e29c1SVivien Didelot if (sht15_ack(data))
839412e29c1SVivien Didelot goto wakeup;
840cc15c7ebSVivien Didelot val |= sht15_read_byte(data);
84199a0378dSVivien Didelot
84282c7465bSJerome Oufella if (data->checksumming) {
84382c7465bSJerome Oufella /*
84482c7465bSJerome Oufella * Ask the device for a checksum and read it back.
84582c7465bSJerome Oufella * Note: the device sends the checksum byte reversed.
84682c7465bSJerome Oufella */
847412e29c1SVivien Didelot if (sht15_ack(data))
848412e29c1SVivien Didelot goto wakeup;
84933836ee9Syalin wang dev_checksum = bitrev8(sht15_read_byte(data));
85082c7465bSJerome Oufella checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
85182c7465bSJerome Oufella SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
85282c7465bSJerome Oufella checksum_vals[1] = (u8) (val >> 8);
85382c7465bSJerome Oufella checksum_vals[2] = (u8) val;
85482c7465bSJerome Oufella data->checksum_ok
85582c7465bSJerome Oufella = (sht15_crc8(data, checksum_vals, 3) == dev_checksum);
85682c7465bSJerome Oufella }
85782c7465bSJerome Oufella
858251eb40fSJonathan Cameron /* Tell the device we are done */
859412e29c1SVivien Didelot if (sht15_end_transmission(data))
860412e29c1SVivien Didelot goto wakeup;
861251eb40fSJonathan Cameron
86299a0378dSVivien Didelot switch (data->state) {
863251eb40fSJonathan Cameron case SHT15_READING_TEMP:
864251eb40fSJonathan Cameron data->val_temp = val;
865251eb40fSJonathan Cameron break;
866251eb40fSJonathan Cameron case SHT15_READING_HUMID:
867251eb40fSJonathan Cameron data->val_humid = val;
868251eb40fSJonathan Cameron break;
86999a0378dSVivien Didelot default:
87099a0378dSVivien Didelot break;
871251eb40fSJonathan Cameron }
872251eb40fSJonathan Cameron
87399a0378dSVivien Didelot data->state = SHT15_READING_NOTHING;
874412e29c1SVivien Didelot wakeup:
875251eb40fSJonathan Cameron wake_up(&data->wait_queue);
876251eb40fSJonathan Cameron }
877251eb40fSJonathan Cameron
sht15_update_voltage(struct work_struct * work_s)878251eb40fSJonathan Cameron static void sht15_update_voltage(struct work_struct *work_s)
879251eb40fSJonathan Cameron {
880251eb40fSJonathan Cameron struct sht15_data *data
881251eb40fSJonathan Cameron = container_of(work_s, struct sht15_data,
882251eb40fSJonathan Cameron update_supply_work);
883142c0901SVivien Didelot data->supply_uv = regulator_get_voltage(data->reg);
884251eb40fSJonathan Cameron }
885251eb40fSJonathan Cameron
886251eb40fSJonathan Cameron /**
887251eb40fSJonathan Cameron * sht15_invalidate_voltage() - mark supply voltage invalid when notified by reg
888251eb40fSJonathan Cameron * @nb: associated notification structure
889251eb40fSJonathan Cameron * @event: voltage regulator state change event code
890251eb40fSJonathan Cameron * @ignored: function parameter - ignored here
891251eb40fSJonathan Cameron *
892251eb40fSJonathan Cameron * Note that as the notification code holds the regulator lock, we have
893251eb40fSJonathan Cameron * to schedule an update of the supply voltage rather than getting it directly.
89499a0378dSVivien Didelot */
sht15_invalidate_voltage(struct notifier_block * nb,unsigned long event,void * ignored)895251eb40fSJonathan Cameron static int sht15_invalidate_voltage(struct notifier_block *nb,
896251eb40fSJonathan Cameron unsigned long event,
897251eb40fSJonathan Cameron void *ignored)
898251eb40fSJonathan Cameron {
899251eb40fSJonathan Cameron struct sht15_data *data = container_of(nb, struct sht15_data, nb);
900251eb40fSJonathan Cameron
901251eb40fSJonathan Cameron if (event == REGULATOR_EVENT_VOLTAGE_CHANGE)
902142c0901SVivien Didelot data->supply_uv_valid = false;
903251eb40fSJonathan Cameron schedule_work(&data->update_supply_work);
904251eb40fSJonathan Cameron
905251eb40fSJonathan Cameron return NOTIFY_OK;
906251eb40fSJonathan Cameron }
907251eb40fSJonathan Cameron
9082f1736ffSMarco Franchi #ifdef CONFIG_OF
9092f1736ffSMarco Franchi static const struct of_device_id sht15_dt_match[] = {
9102f1736ffSMarco Franchi { .compatible = "sensirion,sht15" },
9112f1736ffSMarco Franchi { },
9122f1736ffSMarco Franchi };
9132f1736ffSMarco Franchi MODULE_DEVICE_TABLE(of, sht15_dt_match);
9142f1736ffSMarco Franchi #endif
9152f1736ffSMarco Franchi
sht15_probe(struct platform_device * pdev)9166c931ae1SBill Pemberton static int sht15_probe(struct platform_device *pdev)
917251eb40fSJonathan Cameron {
9186edf3c30SVivien Didelot int ret;
91938fe7560SGuenter Roeck struct sht15_data *data;
920251eb40fSJonathan Cameron
92138fe7560SGuenter Roeck data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
92238fe7560SGuenter Roeck if (!data)
92338fe7560SGuenter Roeck return -ENOMEM;
924251eb40fSJonathan Cameron
925251eb40fSJonathan Cameron INIT_WORK(&data->read_work, sht15_bh_read_data);
926251eb40fSJonathan Cameron INIT_WORK(&data->update_supply_work, sht15_update_voltage);
927251eb40fSJonathan Cameron platform_set_drvdata(pdev, data);
928251eb40fSJonathan Cameron mutex_init(&data->read_lock);
929251eb40fSJonathan Cameron data->dev = &pdev->dev;
930251eb40fSJonathan Cameron init_waitqueue_head(&data->wait_queue);
931251eb40fSJonathan Cameron
93299a0378dSVivien Didelot /*
93399a0378dSVivien Didelot * If a regulator is available,
93499a0378dSVivien Didelot * query what the supply voltage actually is!
93599a0378dSVivien Didelot */
9369e059bacSMark Brown data->reg = devm_regulator_get_optional(data->dev, "vcc");
937251eb40fSJonathan Cameron if (!IS_ERR(data->reg)) {
938c7a78d2cSJean Delvare int voltage;
939c7a78d2cSJean Delvare
940c7a78d2cSJean Delvare voltage = regulator_get_voltage(data->reg);
941c7a78d2cSJean Delvare if (voltage)
942142c0901SVivien Didelot data->supply_uv = voltage;
943c7a78d2cSJean Delvare
9443e78080fSMark Brown ret = regulator_enable(data->reg);
9453e78080fSMark Brown if (ret != 0) {
9463e78080fSMark Brown dev_err(&pdev->dev,
9473e78080fSMark Brown "failed to enable regulator: %d\n", ret);
9483e78080fSMark Brown return ret;
9493e78080fSMark Brown }
9503e78080fSMark Brown
95199a0378dSVivien Didelot /*
95299a0378dSVivien Didelot * Setup a notifier block to update this if another device
95399a0378dSVivien Didelot * causes the voltage to change
95499a0378dSVivien Didelot */
955251eb40fSJonathan Cameron data->nb.notifier_call = &sht15_invalidate_voltage;
956251eb40fSJonathan Cameron ret = regulator_register_notifier(data->reg, &data->nb);
957181148aeSVivien Didelot if (ret) {
958181148aeSVivien Didelot dev_err(&pdev->dev,
959181148aeSVivien Didelot "regulator notifier request failed\n");
960181148aeSVivien Didelot regulator_disable(data->reg);
96138fe7560SGuenter Roeck return ret;
962181148aeSVivien Didelot }
963251eb40fSJonathan Cameron }
96499a0378dSVivien Didelot
965251eb40fSJonathan Cameron /* Try requesting the GPIOs */
96618673114SLinus Walleij data->sck = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_LOW);
96718673114SLinus Walleij if (IS_ERR(data->sck)) {
96818673114SLinus Walleij ret = PTR_ERR(data->sck);
969412e29c1SVivien Didelot dev_err(&pdev->dev, "clock line GPIO request failed\n");
970181148aeSVivien Didelot goto err_release_reg;
971251eb40fSJonathan Cameron }
97218673114SLinus Walleij data->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN);
97318673114SLinus Walleij if (IS_ERR(data->data)) {
97418673114SLinus Walleij ret = PTR_ERR(data->data);
975412e29c1SVivien Didelot dev_err(&pdev->dev, "data line GPIO request failed\n");
97638fe7560SGuenter Roeck goto err_release_reg;
977251eb40fSJonathan Cameron }
978251eb40fSJonathan Cameron
97918673114SLinus Walleij ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
980251eb40fSJonathan Cameron sht15_interrupt_fired,
981251eb40fSJonathan Cameron IRQF_TRIGGER_FALLING,
982251eb40fSJonathan Cameron "sht15 data",
983251eb40fSJonathan Cameron data);
984251eb40fSJonathan Cameron if (ret) {
98599a0378dSVivien Didelot dev_err(&pdev->dev, "failed to get irq for data line\n");
98638fe7560SGuenter Roeck goto err_release_reg;
987251eb40fSJonathan Cameron }
98818673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data));
989412e29c1SVivien Didelot ret = sht15_connection_reset(data);
990412e29c1SVivien Didelot if (ret)
991412e29c1SVivien Didelot goto err_release_reg;
992181148aeSVivien Didelot ret = sht15_soft_reset(data);
993181148aeSVivien Didelot if (ret)
99438fe7560SGuenter Roeck goto err_release_reg;
995181148aeSVivien Didelot
996181148aeSVivien Didelot ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
997181148aeSVivien Didelot if (ret) {
998181148aeSVivien Didelot dev_err(&pdev->dev, "sysfs create failed\n");
99938fe7560SGuenter Roeck goto err_release_reg;
1000181148aeSVivien Didelot }
1001251eb40fSJonathan Cameron
1002251eb40fSJonathan Cameron data->hwmon_dev = hwmon_device_register(data->dev);
1003251eb40fSJonathan Cameron if (IS_ERR(data->hwmon_dev)) {
1004251eb40fSJonathan Cameron ret = PTR_ERR(data->hwmon_dev);
1005181148aeSVivien Didelot goto err_release_sysfs_group;
1006251eb40fSJonathan Cameron }
100799a0378dSVivien Didelot
1008251eb40fSJonathan Cameron return 0;
1009251eb40fSJonathan Cameron
1010181148aeSVivien Didelot err_release_sysfs_group:
1011181148aeSVivien Didelot sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
1012181148aeSVivien Didelot err_release_reg:
1013181148aeSVivien Didelot if (!IS_ERR(data->reg)) {
1014181148aeSVivien Didelot regulator_unregister_notifier(data->reg, &data->nb);
1015181148aeSVivien Didelot regulator_disable(data->reg);
1016181148aeSVivien Didelot }
1017251eb40fSJonathan Cameron return ret;
1018251eb40fSJonathan Cameron }
1019251eb40fSJonathan Cameron
sht15_remove(struct platform_device * pdev)1020281dfd0bSBill Pemberton static int sht15_remove(struct platform_device *pdev)
1021251eb40fSJonathan Cameron {
1022251eb40fSJonathan Cameron struct sht15_data *data = platform_get_drvdata(pdev);
10237d4edcccSUwe Kleine-König int ret;
1024251eb40fSJonathan Cameron
1025251eb40fSJonathan Cameron hwmon_device_unregister(data->hwmon_dev);
1026251eb40fSJonathan Cameron sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
10277d4edcccSUwe Kleine-König
10287d4edcccSUwe Kleine-König ret = sht15_soft_reset(data);
10297d4edcccSUwe Kleine-König if (ret)
10307d4edcccSUwe Kleine-König dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
10317d4edcccSUwe Kleine-König
1032251eb40fSJonathan Cameron if (!IS_ERR(data->reg)) {
1033251eb40fSJonathan Cameron regulator_unregister_notifier(data->reg, &data->nb);
1034251eb40fSJonathan Cameron regulator_disable(data->reg);
1035251eb40fSJonathan Cameron }
1036251eb40fSJonathan Cameron
1037251eb40fSJonathan Cameron return 0;
1038251eb40fSJonathan Cameron }
1039251eb40fSJonathan Cameron
10409c40723eSKrzysztof Kozlowski static const struct platform_device_id sht15_device_ids[] = {
1041edec5af7SVivien Didelot { "sht10", sht10 },
1042edec5af7SVivien Didelot { "sht11", sht11 },
1043edec5af7SVivien Didelot { "sht15", sht15 },
1044edec5af7SVivien Didelot { "sht71", sht71 },
1045edec5af7SVivien Didelot { "sht75", sht75 },
1046edec5af7SVivien Didelot { }
1047edec5af7SVivien Didelot };
1048edec5af7SVivien Didelot MODULE_DEVICE_TABLE(platform, sht15_device_ids);
1049edec5af7SVivien Didelot
1050edec5af7SVivien Didelot static struct platform_driver sht15_driver = {
1051251eb40fSJonathan Cameron .driver = {
1052251eb40fSJonathan Cameron .name = "sht15",
10532f1736ffSMarco Franchi .of_match_table = of_match_ptr(sht15_dt_match),
1054251eb40fSJonathan Cameron },
1055251eb40fSJonathan Cameron .probe = sht15_probe,
10569e5e9b7aSBill Pemberton .remove = sht15_remove,
1057edec5af7SVivien Didelot .id_table = sht15_device_ids,
1058251eb40fSJonathan Cameron };
1059edec5af7SVivien Didelot module_platform_driver(sht15_driver);
1060251eb40fSJonathan Cameron
1061251eb40fSJonathan Cameron MODULE_LICENSE("GPL");
1062edec5af7SVivien Didelot MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver");
1063