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/module.h> 22251eb40fSJonathan Cameron #include <linux/init.h> 23251eb40fSJonathan Cameron #include <linux/hwmon.h> 24251eb40fSJonathan Cameron #include <linux/hwmon-sysfs.h> 25251eb40fSJonathan Cameron #include <linux/mutex.h> 26251eb40fSJonathan Cameron #include <linux/platform_device.h> 27d43c36dcSAlexey Dobriyan #include <linux/sched.h> 28251eb40fSJonathan Cameron #include <linux/delay.h> 29251eb40fSJonathan Cameron #include <linux/jiffies.h> 30251eb40fSJonathan Cameron #include <linux/err.h> 31251eb40fSJonathan Cameron #include <linux/regulator/consumer.h> 325a0e3ad6STejun Heo #include <linux/slab.h> 3360063497SArun Sharma #include <linux/atomic.h> 3433836ee9Syalin wang #include <linux/bitrev.h> 3518673114SLinus Walleij #include <linux/gpio/consumer.h> 3618673114SLinus Walleij #include <linux/of.h> 37251eb40fSJonathan Cameron 3899a0378dSVivien Didelot /* Commands */ 3999a0378dSVivien Didelot #define SHT15_MEASURE_TEMP 0x03 4099a0378dSVivien Didelot #define SHT15_MEASURE_RH 0x05 41cc15c7ebSVivien Didelot #define SHT15_WRITE_STATUS 0x06 42cc15c7ebSVivien Didelot #define SHT15_READ_STATUS 0x07 43181148aeSVivien Didelot #define SHT15_SOFT_RESET 0x1E 44251eb40fSJonathan Cameron 4599a0378dSVivien Didelot /* Min timings */ 4699a0378dSVivien Didelot #define SHT15_TSCKL 100 /* (nsecs) clock low */ 4799a0378dSVivien Didelot #define SHT15_TSCKH 100 /* (nsecs) clock high */ 4899a0378dSVivien Didelot #define SHT15_TSU 150 /* (nsecs) data setup time */ 49181148aeSVivien Didelot #define SHT15_TSRST 11 /* (msecs) soft reset time */ 50251eb40fSJonathan Cameron 51cc15c7ebSVivien Didelot /* Status Register Bits */ 52cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_RESOLUTION 0x01 53cc15c7ebSVivien Didelot #define SHT15_STATUS_NO_OTP_RELOAD 0x02 54cc15c7ebSVivien Didelot #define SHT15_STATUS_HEATER 0x04 55cc15c7ebSVivien Didelot #define SHT15_STATUS_LOW_BATTERY 0x40 56cc15c7ebSVivien Didelot 57edec5af7SVivien Didelot /* List of supported chips */ 58edec5af7SVivien Didelot enum sht15_chips { sht10, sht11, sht15, sht71, sht75 }; 59edec5af7SVivien Didelot 6099a0378dSVivien Didelot /* Actions the driver may be doing */ 6199a0378dSVivien Didelot enum sht15_state { 6299a0378dSVivien Didelot SHT15_READING_NOTHING, 6399a0378dSVivien Didelot SHT15_READING_TEMP, 6499a0378dSVivien Didelot SHT15_READING_HUMID 6599a0378dSVivien Didelot }; 66251eb40fSJonathan Cameron 67251eb40fSJonathan Cameron /** 6825985edcSLucas De Marchi * struct sht15_temppair - elements of voltage dependent temp calc 69251eb40fSJonathan Cameron * @vdd: supply voltage in microvolts 70251eb40fSJonathan Cameron * @d1: see data sheet 71251eb40fSJonathan Cameron */ 72251eb40fSJonathan Cameron struct sht15_temppair { 73251eb40fSJonathan Cameron int vdd; /* microvolts */ 74251eb40fSJonathan Cameron int d1; 75251eb40fSJonathan Cameron }; 76251eb40fSJonathan Cameron 7799a0378dSVivien Didelot /* Table 9 from datasheet - relates temperature calculation to supply voltage */ 78251eb40fSJonathan Cameron static const struct sht15_temppair temppoints[] = { 79251eb40fSJonathan Cameron { 2500000, -39400 }, 80251eb40fSJonathan Cameron { 3000000, -39600 }, 81251eb40fSJonathan Cameron { 3500000, -39700 }, 82251eb40fSJonathan Cameron { 4000000, -39800 }, 83251eb40fSJonathan Cameron { 5000000, -40100 }, 84251eb40fSJonathan Cameron }; 85251eb40fSJonathan Cameron 8682c7465bSJerome Oufella /* Table from CRC datasheet, section 2.4 */ 8782c7465bSJerome Oufella static const u8 sht15_crc8_table[] = { 8882c7465bSJerome Oufella 0, 49, 98, 83, 196, 245, 166, 151, 8982c7465bSJerome Oufella 185, 136, 219, 234, 125, 76, 31, 46, 9082c7465bSJerome Oufella 67, 114, 33, 16, 135, 182, 229, 212, 9182c7465bSJerome Oufella 250, 203, 152, 169, 62, 15, 92, 109, 9282c7465bSJerome Oufella 134, 183, 228, 213, 66, 115, 32, 17, 9382c7465bSJerome Oufella 63, 14, 93, 108, 251, 202, 153, 168, 9482c7465bSJerome Oufella 197, 244, 167, 150, 1, 48, 99, 82, 9582c7465bSJerome Oufella 124, 77, 30, 47, 184, 137, 218, 235, 9682c7465bSJerome Oufella 61, 12, 95, 110, 249, 200, 155, 170, 9782c7465bSJerome Oufella 132, 181, 230, 215, 64, 113, 34, 19, 9882c7465bSJerome Oufella 126, 79, 28, 45, 186, 139, 216, 233, 9982c7465bSJerome Oufella 199, 246, 165, 148, 3, 50, 97, 80, 10082c7465bSJerome Oufella 187, 138, 217, 232, 127, 78, 29, 44, 10182c7465bSJerome Oufella 2, 51, 96, 81, 198, 247, 164, 149, 10282c7465bSJerome Oufella 248, 201, 154, 171, 60, 13, 94, 111, 10382c7465bSJerome Oufella 65, 112, 35, 18, 133, 180, 231, 214, 10482c7465bSJerome Oufella 122, 75, 24, 41, 190, 143, 220, 237, 10582c7465bSJerome Oufella 195, 242, 161, 144, 7, 54, 101, 84, 10682c7465bSJerome Oufella 57, 8, 91, 106, 253, 204, 159, 174, 10782c7465bSJerome Oufella 128, 177, 226, 211, 68, 117, 38, 23, 10882c7465bSJerome Oufella 252, 205, 158, 175, 56, 9, 90, 107, 10982c7465bSJerome Oufella 69, 116, 39, 22, 129, 176, 227, 210, 11082c7465bSJerome Oufella 191, 142, 221, 236, 123, 74, 25, 40, 11182c7465bSJerome Oufella 6, 55, 100, 85, 194, 243, 160, 145, 11282c7465bSJerome Oufella 71, 118, 37, 20, 131, 178, 225, 208, 11382c7465bSJerome Oufella 254, 207, 156, 173, 58, 11, 88, 105, 11482c7465bSJerome Oufella 4, 53, 102, 87, 192, 241, 162, 147, 11582c7465bSJerome Oufella 189, 140, 223, 238, 121, 72, 27, 42, 11682c7465bSJerome Oufella 193, 240, 163, 146, 5, 52, 103, 86, 11782c7465bSJerome Oufella 120, 73, 26, 43, 188, 141, 222, 239, 11882c7465bSJerome Oufella 130, 179, 224, 209, 70, 119, 36, 21, 11982c7465bSJerome Oufella 59, 10, 89, 104, 255, 206, 157, 172 12082c7465bSJerome Oufella }; 12182c7465bSJerome Oufella 122251eb40fSJonathan Cameron /** 123251eb40fSJonathan Cameron * struct sht15_data - device instance specific data 12418673114SLinus Walleij * @sck: clock GPIO line 12518673114SLinus Walleij * @data: data GPIO line 12699a0378dSVivien Didelot * @read_work: bh of interrupt handler. 12799a0378dSVivien Didelot * @wait_queue: wait queue for getting values from device. 12899a0378dSVivien Didelot * @val_temp: last temperature value read from device. 12999a0378dSVivien Didelot * @val_humid: last humidity value read from device. 130cc15c7ebSVivien Didelot * @val_status: last status register value read from device. 13182c7465bSJerome Oufella * @checksum_ok: last value read from the device passed CRC validation. 13282c7465bSJerome Oufella * @checksumming: flag used to enable the data validation with CRC. 13399a0378dSVivien Didelot * @state: state identifying the action the driver is doing. 13499a0378dSVivien Didelot * @measurements_valid: are the current stored measures valid (start condition). 135cc15c7ebSVivien Didelot * @status_valid: is the current stored status valid (start condition). 13699a0378dSVivien Didelot * @last_measurement: time of last measure. 137cc15c7ebSVivien Didelot * @last_status: time of last status reading. 13899a0378dSVivien Didelot * @read_lock: mutex to ensure only one read in progress at a time. 13999a0378dSVivien Didelot * @dev: associate device structure. 14099a0378dSVivien Didelot * @hwmon_dev: device associated with hwmon subsystem. 14199a0378dSVivien Didelot * @reg: associated regulator (if specified). 14299a0378dSVivien Didelot * @nb: notifier block to handle notifications of voltage 14399a0378dSVivien Didelot * changes. 144142c0901SVivien Didelot * @supply_uv: local copy of supply voltage used to allow use of 14599a0378dSVivien Didelot * regulator consumer if available. 146142c0901SVivien Didelot * @supply_uv_valid: indicates that an updated value has not yet been 14799a0378dSVivien Didelot * obtained from the regulator and so any calculations 148251eb40fSJonathan Cameron * based upon it will be invalid. 149142c0901SVivien Didelot * @update_supply_work: work struct that is used to update the supply_uv. 15099a0378dSVivien Didelot * @interrupt_handled: flag used to indicate a handler has been scheduled. 151251eb40fSJonathan Cameron */ 152251eb40fSJonathan Cameron struct sht15_data { 15318673114SLinus Walleij struct gpio_desc *sck; 15418673114SLinus Walleij struct gpio_desc *data; 155251eb40fSJonathan Cameron struct work_struct read_work; 156251eb40fSJonathan Cameron wait_queue_head_t wait_queue; 157251eb40fSJonathan Cameron uint16_t val_temp; 158251eb40fSJonathan Cameron uint16_t val_humid; 159cc15c7ebSVivien Didelot u8 val_status; 16082c7465bSJerome Oufella bool checksum_ok; 16182c7465bSJerome Oufella bool checksumming; 16299a0378dSVivien Didelot enum sht15_state state; 16399a0378dSVivien Didelot bool measurements_valid; 164cc15c7ebSVivien Didelot bool status_valid; 16599a0378dSVivien Didelot unsigned long last_measurement; 166cc15c7ebSVivien Didelot unsigned long last_status; 167251eb40fSJonathan Cameron struct mutex read_lock; 168251eb40fSJonathan Cameron struct device *dev; 169251eb40fSJonathan Cameron struct device *hwmon_dev; 170251eb40fSJonathan Cameron struct regulator *reg; 171251eb40fSJonathan Cameron struct notifier_block nb; 172142c0901SVivien Didelot int supply_uv; 173142c0901SVivien Didelot bool supply_uv_valid; 174251eb40fSJonathan Cameron struct work_struct update_supply_work; 175251eb40fSJonathan Cameron atomic_t interrupt_handled; 176251eb40fSJonathan Cameron }; 177251eb40fSJonathan Cameron 178251eb40fSJonathan Cameron /** 17982c7465bSJerome Oufella * sht15_crc8() - compute crc8 18082c7465bSJerome Oufella * @data: sht15 specific data. 18182c7465bSJerome Oufella * @value: sht15 retrieved data. 182d5324e90SGuenter Roeck * @len: Length of retrieved data 18382c7465bSJerome Oufella * 18482c7465bSJerome Oufella * This implements section 2 of the CRC datasheet. 18582c7465bSJerome Oufella */ 18682c7465bSJerome Oufella static u8 sht15_crc8(struct sht15_data *data, 18782c7465bSJerome Oufella const u8 *value, 18882c7465bSJerome Oufella int len) 18982c7465bSJerome Oufella { 19033836ee9Syalin wang u8 crc = bitrev8(data->val_status & 0x0F); 19182c7465bSJerome Oufella 19282c7465bSJerome Oufella while (len--) { 19382c7465bSJerome Oufella crc = sht15_crc8_table[*value ^ crc]; 19482c7465bSJerome Oufella value++; 19582c7465bSJerome Oufella } 19682c7465bSJerome Oufella 19782c7465bSJerome Oufella return crc; 19882c7465bSJerome Oufella } 19982c7465bSJerome Oufella 20082c7465bSJerome Oufella /** 201251eb40fSJonathan Cameron * sht15_connection_reset() - reset the comms interface 202251eb40fSJonathan Cameron * @data: sht15 specific data 203251eb40fSJonathan Cameron * 204251eb40fSJonathan Cameron * This implements section 3.4 of the data sheet 205251eb40fSJonathan Cameron */ 206412e29c1SVivien Didelot static int sht15_connection_reset(struct sht15_data *data) 207251eb40fSJonathan Cameron { 208412e29c1SVivien Didelot int i, err; 20999a0378dSVivien Didelot 21018673114SLinus Walleij err = gpiod_direction_output(data->data, 1); 211412e29c1SVivien Didelot if (err) 212412e29c1SVivien Didelot return err; 213251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 21418673114SLinus Walleij gpiod_set_value(data->sck, 0); 215251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 216251eb40fSJonathan Cameron for (i = 0; i < 9; ++i) { 21718673114SLinus Walleij gpiod_set_value(data->sck, 1); 218251eb40fSJonathan Cameron ndelay(SHT15_TSCKH); 21918673114SLinus Walleij gpiod_set_value(data->sck, 0); 220251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 221251eb40fSJonathan Cameron } 222412e29c1SVivien Didelot return 0; 223251eb40fSJonathan Cameron } 22499a0378dSVivien Didelot 225251eb40fSJonathan Cameron /** 226251eb40fSJonathan Cameron * sht15_send_bit() - send an individual bit to the device 227251eb40fSJonathan Cameron * @data: device state data 228251eb40fSJonathan Cameron * @val: value of bit to be sent 22999a0378dSVivien Didelot */ 230251eb40fSJonathan Cameron static inline void sht15_send_bit(struct sht15_data *data, int val) 231251eb40fSJonathan Cameron { 23218673114SLinus Walleij gpiod_set_value(data->data, val); 233251eb40fSJonathan Cameron ndelay(SHT15_TSU); 23418673114SLinus Walleij gpiod_set_value(data->sck, 1); 235251eb40fSJonathan Cameron ndelay(SHT15_TSCKH); 23618673114SLinus Walleij gpiod_set_value(data->sck, 0); 237251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); /* clock low time */ 238251eb40fSJonathan Cameron } 239251eb40fSJonathan Cameron 240251eb40fSJonathan Cameron /** 241251eb40fSJonathan Cameron * sht15_transmission_start() - specific sequence for new transmission 242251eb40fSJonathan Cameron * @data: device state data 24399a0378dSVivien Didelot * 244251eb40fSJonathan Cameron * Timings for this are not documented on the data sheet, so very 245251eb40fSJonathan Cameron * conservative ones used in implementation. This implements 246251eb40fSJonathan Cameron * figure 12 on the data sheet. 24799a0378dSVivien Didelot */ 248412e29c1SVivien Didelot static int sht15_transmission_start(struct sht15_data *data) 249251eb40fSJonathan Cameron { 250412e29c1SVivien Didelot int err; 251412e29c1SVivien Didelot 252251eb40fSJonathan Cameron /* ensure data is high and output */ 25318673114SLinus Walleij err = gpiod_direction_output(data->data, 1); 254412e29c1SVivien Didelot if (err) 255412e29c1SVivien Didelot return err; 256251eb40fSJonathan Cameron ndelay(SHT15_TSU); 25718673114SLinus Walleij gpiod_set_value(data->sck, 0); 258251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 25918673114SLinus Walleij gpiod_set_value(data->sck, 1); 260251eb40fSJonathan Cameron ndelay(SHT15_TSCKH); 26118673114SLinus Walleij gpiod_set_value(data->data, 0); 262251eb40fSJonathan Cameron ndelay(SHT15_TSU); 26318673114SLinus Walleij gpiod_set_value(data->sck, 0); 264251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 26518673114SLinus Walleij gpiod_set_value(data->sck, 1); 266251eb40fSJonathan Cameron ndelay(SHT15_TSCKH); 26718673114SLinus Walleij gpiod_set_value(data->data, 1); 268251eb40fSJonathan Cameron ndelay(SHT15_TSU); 26918673114SLinus Walleij gpiod_set_value(data->sck, 0); 270251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 271412e29c1SVivien Didelot return 0; 272251eb40fSJonathan Cameron } 27399a0378dSVivien Didelot 274251eb40fSJonathan Cameron /** 275251eb40fSJonathan Cameron * sht15_send_byte() - send a single byte to the device 276251eb40fSJonathan Cameron * @data: device state 277251eb40fSJonathan Cameron * @byte: value to be sent 27899a0378dSVivien Didelot */ 279251eb40fSJonathan Cameron static void sht15_send_byte(struct sht15_data *data, u8 byte) 280251eb40fSJonathan Cameron { 281251eb40fSJonathan Cameron int i; 28299a0378dSVivien Didelot 283251eb40fSJonathan Cameron for (i = 0; i < 8; i++) { 284251eb40fSJonathan Cameron sht15_send_bit(data, !!(byte & 0x80)); 285251eb40fSJonathan Cameron byte <<= 1; 286251eb40fSJonathan Cameron } 287251eb40fSJonathan Cameron } 28899a0378dSVivien Didelot 289251eb40fSJonathan Cameron /** 290251eb40fSJonathan Cameron * sht15_wait_for_response() - checks for ack from device 291251eb40fSJonathan Cameron * @data: device state 29299a0378dSVivien Didelot */ 293251eb40fSJonathan Cameron static int sht15_wait_for_response(struct sht15_data *data) 294251eb40fSJonathan Cameron { 295412e29c1SVivien Didelot int err; 296412e29c1SVivien Didelot 29718673114SLinus Walleij err = gpiod_direction_input(data->data); 298412e29c1SVivien Didelot if (err) 299412e29c1SVivien Didelot return err; 30018673114SLinus Walleij gpiod_set_value(data->sck, 1); 301251eb40fSJonathan Cameron ndelay(SHT15_TSCKH); 30218673114SLinus Walleij if (gpiod_get_value(data->data)) { 30318673114SLinus Walleij gpiod_set_value(data->sck, 0); 304251eb40fSJonathan Cameron dev_err(data->dev, "Command not acknowledged\n"); 305412e29c1SVivien Didelot err = sht15_connection_reset(data); 306412e29c1SVivien Didelot if (err) 307412e29c1SVivien Didelot return err; 308251eb40fSJonathan Cameron return -EIO; 309251eb40fSJonathan Cameron } 31018673114SLinus Walleij gpiod_set_value(data->sck, 0); 311251eb40fSJonathan Cameron ndelay(SHT15_TSCKL); 312251eb40fSJonathan Cameron return 0; 313251eb40fSJonathan Cameron } 314251eb40fSJonathan Cameron 315251eb40fSJonathan Cameron /** 316251eb40fSJonathan Cameron * sht15_send_cmd() - Sends a command to the device. 317251eb40fSJonathan Cameron * @data: device state 318251eb40fSJonathan Cameron * @cmd: command byte to be sent 319251eb40fSJonathan Cameron * 320251eb40fSJonathan Cameron * On entry, sck is output low, data is output pull high 321251eb40fSJonathan Cameron * and the interrupt disabled. 32299a0378dSVivien Didelot */ 323251eb40fSJonathan Cameron static int sht15_send_cmd(struct sht15_data *data, u8 cmd) 324251eb40fSJonathan Cameron { 325412e29c1SVivien Didelot int err; 32699a0378dSVivien Didelot 327412e29c1SVivien Didelot err = sht15_transmission_start(data); 328412e29c1SVivien Didelot if (err) 329412e29c1SVivien Didelot return err; 330251eb40fSJonathan Cameron sht15_send_byte(data, cmd); 331412e29c1SVivien Didelot return sht15_wait_for_response(data); 332251eb40fSJonathan Cameron } 33399a0378dSVivien Didelot 334251eb40fSJonathan Cameron /** 335181148aeSVivien Didelot * sht15_soft_reset() - send a soft reset command 336181148aeSVivien Didelot * @data: sht15 specific data. 337181148aeSVivien Didelot * 338181148aeSVivien Didelot * As described in section 3.2 of the datasheet. 339181148aeSVivien Didelot */ 340181148aeSVivien Didelot static int sht15_soft_reset(struct sht15_data *data) 341181148aeSVivien Didelot { 342181148aeSVivien Didelot int ret; 343181148aeSVivien Didelot 344181148aeSVivien Didelot ret = sht15_send_cmd(data, SHT15_SOFT_RESET); 345181148aeSVivien Didelot if (ret) 346181148aeSVivien Didelot return ret; 347181148aeSVivien Didelot msleep(SHT15_TSRST); 348cc15c7ebSVivien Didelot /* device resets default hardware status register value */ 349cc15c7ebSVivien Didelot data->val_status = 0; 350181148aeSVivien Didelot 351cc15c7ebSVivien Didelot return ret; 352cc15c7ebSVivien Didelot } 353cc15c7ebSVivien Didelot 354cc15c7ebSVivien Didelot /** 35582c7465bSJerome Oufella * sht15_ack() - send a ack 35682c7465bSJerome Oufella * @data: sht15 specific data. 35782c7465bSJerome Oufella * 35882c7465bSJerome Oufella * Each byte of data is acknowledged by pulling the data line 35982c7465bSJerome Oufella * low for one clock pulse. 36082c7465bSJerome Oufella */ 361412e29c1SVivien Didelot static int sht15_ack(struct sht15_data *data) 36282c7465bSJerome Oufella { 363412e29c1SVivien Didelot int err; 364412e29c1SVivien Didelot 36518673114SLinus Walleij err = gpiod_direction_output(data->data, 0); 366412e29c1SVivien Didelot if (err) 367412e29c1SVivien Didelot return err; 36882c7465bSJerome Oufella ndelay(SHT15_TSU); 36918673114SLinus Walleij gpiod_set_value(data->sck, 1); 37082c7465bSJerome Oufella ndelay(SHT15_TSU); 37118673114SLinus Walleij gpiod_set_value(data->sck, 0); 37282c7465bSJerome Oufella ndelay(SHT15_TSU); 37318673114SLinus Walleij gpiod_set_value(data->data, 1); 37482c7465bSJerome Oufella 37518673114SLinus Walleij return gpiod_direction_input(data->data); 37682c7465bSJerome Oufella } 37782c7465bSJerome Oufella 37882c7465bSJerome Oufella /** 379cc15c7ebSVivien Didelot * sht15_end_transmission() - notify device of end of transmission 380cc15c7ebSVivien Didelot * @data: device state. 381cc15c7ebSVivien Didelot * 382cc15c7ebSVivien Didelot * This is basically a NAK (single clock pulse, data high). 383cc15c7ebSVivien Didelot */ 384412e29c1SVivien Didelot static int sht15_end_transmission(struct sht15_data *data) 385cc15c7ebSVivien Didelot { 386412e29c1SVivien Didelot int err; 387412e29c1SVivien Didelot 38818673114SLinus Walleij err = gpiod_direction_output(data->data, 1); 389412e29c1SVivien Didelot if (err) 390412e29c1SVivien Didelot return err; 391cc15c7ebSVivien Didelot ndelay(SHT15_TSU); 39218673114SLinus Walleij gpiod_set_value(data->sck, 1); 393cc15c7ebSVivien Didelot ndelay(SHT15_TSCKH); 39418673114SLinus Walleij gpiod_set_value(data->sck, 0); 395cc15c7ebSVivien Didelot ndelay(SHT15_TSCKL); 396412e29c1SVivien Didelot return 0; 397cc15c7ebSVivien Didelot } 398cc15c7ebSVivien Didelot 399cc15c7ebSVivien Didelot /** 400cc15c7ebSVivien Didelot * sht15_read_byte() - Read a byte back from the device 401cc15c7ebSVivien Didelot * @data: device state. 402cc15c7ebSVivien Didelot */ 403cc15c7ebSVivien Didelot static u8 sht15_read_byte(struct sht15_data *data) 404cc15c7ebSVivien Didelot { 405cc15c7ebSVivien Didelot int i; 406cc15c7ebSVivien Didelot u8 byte = 0; 407cc15c7ebSVivien Didelot 408cc15c7ebSVivien Didelot for (i = 0; i < 8; ++i) { 409cc15c7ebSVivien Didelot byte <<= 1; 41018673114SLinus Walleij gpiod_set_value(data->sck, 1); 411cc15c7ebSVivien Didelot ndelay(SHT15_TSCKH); 41218673114SLinus Walleij byte |= !!gpiod_get_value(data->data); 41318673114SLinus Walleij gpiod_set_value(data->sck, 0); 414cc15c7ebSVivien Didelot ndelay(SHT15_TSCKL); 415cc15c7ebSVivien Didelot } 416cc15c7ebSVivien Didelot return byte; 417cc15c7ebSVivien Didelot } 418cc15c7ebSVivien Didelot 419cc15c7ebSVivien Didelot /** 420cc15c7ebSVivien Didelot * sht15_send_status() - write the status register byte 421cc15c7ebSVivien Didelot * @data: sht15 specific data. 422cc15c7ebSVivien Didelot * @status: the byte to set the status register with. 423cc15c7ebSVivien Didelot * 424cc15c7ebSVivien Didelot * As described in figure 14 and table 5 of the datasheet. 425cc15c7ebSVivien Didelot */ 426cc15c7ebSVivien Didelot static int sht15_send_status(struct sht15_data *data, u8 status) 427cc15c7ebSVivien Didelot { 428412e29c1SVivien Didelot int err; 429cc15c7ebSVivien Didelot 430412e29c1SVivien Didelot err = sht15_send_cmd(data, SHT15_WRITE_STATUS); 431412e29c1SVivien Didelot if (err) 432412e29c1SVivien Didelot return err; 43318673114SLinus Walleij err = gpiod_direction_output(data->data, 1); 434412e29c1SVivien Didelot if (err) 435412e29c1SVivien Didelot return err; 436cc15c7ebSVivien Didelot ndelay(SHT15_TSU); 437cc15c7ebSVivien Didelot sht15_send_byte(data, status); 438412e29c1SVivien Didelot err = sht15_wait_for_response(data); 439412e29c1SVivien Didelot if (err) 440412e29c1SVivien Didelot return err; 441cc15c7ebSVivien Didelot 442cc15c7ebSVivien Didelot data->val_status = status; 443181148aeSVivien Didelot return 0; 444181148aeSVivien Didelot } 445181148aeSVivien Didelot 446181148aeSVivien Didelot /** 447cc15c7ebSVivien Didelot * sht15_update_status() - get updated status register from device if too old 448cc15c7ebSVivien Didelot * @data: device instance specific data. 449cc15c7ebSVivien Didelot * 450cc15c7ebSVivien Didelot * As described in figure 15 and table 5 of the datasheet. 451cc15c7ebSVivien Didelot */ 452cc15c7ebSVivien Didelot static int sht15_update_status(struct sht15_data *data) 453cc15c7ebSVivien Didelot { 454cc15c7ebSVivien Didelot int ret = 0; 455cc15c7ebSVivien Didelot u8 status; 45682c7465bSJerome Oufella u8 previous_config; 45782c7465bSJerome Oufella u8 dev_checksum = 0; 45882c7465bSJerome Oufella u8 checksum_vals[2]; 459cc15c7ebSVivien Didelot int timeout = HZ; 460cc15c7ebSVivien Didelot 461cc15c7ebSVivien Didelot mutex_lock(&data->read_lock); 462cc15c7ebSVivien Didelot if (time_after(jiffies, data->last_status + timeout) 463cc15c7ebSVivien Didelot || !data->status_valid) { 464cc15c7ebSVivien Didelot ret = sht15_send_cmd(data, SHT15_READ_STATUS); 465cc15c7ebSVivien Didelot if (ret) 466412e29c1SVivien Didelot goto unlock; 467cc15c7ebSVivien Didelot status = sht15_read_byte(data); 468cc15c7ebSVivien Didelot 46982c7465bSJerome Oufella if (data->checksumming) { 47082c7465bSJerome Oufella sht15_ack(data); 47133836ee9Syalin wang dev_checksum = bitrev8(sht15_read_byte(data)); 47282c7465bSJerome Oufella checksum_vals[0] = SHT15_READ_STATUS; 47382c7465bSJerome Oufella checksum_vals[1] = status; 47482c7465bSJerome Oufella data->checksum_ok = (sht15_crc8(data, checksum_vals, 2) 47582c7465bSJerome Oufella == dev_checksum); 47682c7465bSJerome Oufella } 47782c7465bSJerome Oufella 478412e29c1SVivien Didelot ret = sht15_end_transmission(data); 479412e29c1SVivien Didelot if (ret) 480412e29c1SVivien Didelot goto unlock; 481cc15c7ebSVivien Didelot 48282c7465bSJerome Oufella /* 48382c7465bSJerome Oufella * Perform checksum validation on the received data. 48482c7465bSJerome Oufella * Specification mentions that in case a checksum verification 48582c7465bSJerome Oufella * fails, a soft reset command must be sent to the device. 48682c7465bSJerome Oufella */ 48782c7465bSJerome Oufella if (data->checksumming && !data->checksum_ok) { 48882c7465bSJerome Oufella previous_config = data->val_status & 0x07; 48982c7465bSJerome Oufella ret = sht15_soft_reset(data); 49082c7465bSJerome Oufella if (ret) 491412e29c1SVivien Didelot goto unlock; 49282c7465bSJerome Oufella if (previous_config) { 49382c7465bSJerome Oufella ret = sht15_send_status(data, previous_config); 49482c7465bSJerome Oufella if (ret) { 49582c7465bSJerome Oufella dev_err(data->dev, 49682c7465bSJerome Oufella "CRC validation failed, unable " 49782c7465bSJerome Oufella "to restore device settings\n"); 498412e29c1SVivien Didelot goto unlock; 49982c7465bSJerome Oufella } 50082c7465bSJerome Oufella } 50182c7465bSJerome Oufella ret = -EAGAIN; 502412e29c1SVivien Didelot goto unlock; 50382c7465bSJerome Oufella } 50482c7465bSJerome Oufella 505cc15c7ebSVivien Didelot data->val_status = status; 506cc15c7ebSVivien Didelot data->status_valid = true; 507cc15c7ebSVivien Didelot data->last_status = jiffies; 508cc15c7ebSVivien Didelot } 509cc15c7ebSVivien Didelot 510412e29c1SVivien Didelot unlock: 511412e29c1SVivien Didelot mutex_unlock(&data->read_lock); 512cc15c7ebSVivien Didelot return ret; 513cc15c7ebSVivien Didelot } 514cc15c7ebSVivien Didelot 515cc15c7ebSVivien Didelot /** 51699a0378dSVivien Didelot * sht15_measurement() - get a new value from device 517251eb40fSJonathan Cameron * @data: device instance specific data 518251eb40fSJonathan Cameron * @command: command sent to request value 519251eb40fSJonathan Cameron * @timeout_msecs: timeout after which comms are assumed 520251eb40fSJonathan Cameron * to have failed are reset. 52199a0378dSVivien Didelot */ 52299a0378dSVivien Didelot static int sht15_measurement(struct sht15_data *data, 523251eb40fSJonathan Cameron int command, 524251eb40fSJonathan Cameron int timeout_msecs) 525251eb40fSJonathan Cameron { 526251eb40fSJonathan Cameron int ret; 52782c7465bSJerome Oufella u8 previous_config; 52899a0378dSVivien Didelot 529251eb40fSJonathan Cameron ret = sht15_send_cmd(data, command); 530251eb40fSJonathan Cameron if (ret) 531251eb40fSJonathan Cameron return ret; 532251eb40fSJonathan Cameron 53318673114SLinus Walleij ret = gpiod_direction_input(data->data); 534412e29c1SVivien Didelot if (ret) 535412e29c1SVivien Didelot return ret; 536251eb40fSJonathan Cameron atomic_set(&data->interrupt_handled, 0); 537251eb40fSJonathan Cameron 53818673114SLinus Walleij enable_irq(gpiod_to_irq(data->data)); 53918673114SLinus Walleij if (gpiod_get_value(data->data) == 0) { 54018673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data)); 54125985edcSLucas De Marchi /* Only relevant if the interrupt hasn't occurred. */ 542251eb40fSJonathan Cameron if (!atomic_read(&data->interrupt_handled)) 543251eb40fSJonathan Cameron schedule_work(&data->read_work); 544251eb40fSJonathan Cameron } 545251eb40fSJonathan Cameron ret = wait_event_timeout(data->wait_queue, 54699a0378dSVivien Didelot (data->state == SHT15_READING_NOTHING), 547251eb40fSJonathan Cameron msecs_to_jiffies(timeout_msecs)); 548412e29c1SVivien Didelot if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */ 549412e29c1SVivien Didelot data->state = SHT15_READING_NOTHING; 550412e29c1SVivien Didelot return -EIO; 551412e29c1SVivien Didelot } else if (ret == 0) { /* timeout occurred */ 55218673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data)); 553412e29c1SVivien Didelot ret = sht15_connection_reset(data); 554412e29c1SVivien Didelot if (ret) 555412e29c1SVivien Didelot return ret; 556251eb40fSJonathan Cameron return -ETIME; 557251eb40fSJonathan Cameron } 55882c7465bSJerome Oufella 55982c7465bSJerome Oufella /* 56082c7465bSJerome Oufella * Perform checksum validation on the received data. 56182c7465bSJerome Oufella * Specification mentions that in case a checksum verification fails, 56282c7465bSJerome Oufella * a soft reset command must be sent to the device. 56382c7465bSJerome Oufella */ 56482c7465bSJerome Oufella if (data->checksumming && !data->checksum_ok) { 56582c7465bSJerome Oufella previous_config = data->val_status & 0x07; 56682c7465bSJerome Oufella ret = sht15_soft_reset(data); 56782c7465bSJerome Oufella if (ret) 56882c7465bSJerome Oufella return ret; 56982c7465bSJerome Oufella if (previous_config) { 57082c7465bSJerome Oufella ret = sht15_send_status(data, previous_config); 57182c7465bSJerome Oufella if (ret) { 57282c7465bSJerome Oufella dev_err(data->dev, 57382c7465bSJerome Oufella "CRC validation failed, unable " 57482c7465bSJerome Oufella "to restore device settings\n"); 57582c7465bSJerome Oufella return ret; 57682c7465bSJerome Oufella } 57782c7465bSJerome Oufella } 57882c7465bSJerome Oufella return -EAGAIN; 57982c7465bSJerome Oufella } 58082c7465bSJerome Oufella 581251eb40fSJonathan Cameron return 0; 582251eb40fSJonathan Cameron } 583251eb40fSJonathan Cameron 584251eb40fSJonathan Cameron /** 58599a0378dSVivien Didelot * sht15_update_measurements() - get updated measures from device if too old 586251eb40fSJonathan Cameron * @data: device state 58799a0378dSVivien Didelot */ 58899a0378dSVivien Didelot static int sht15_update_measurements(struct sht15_data *data) 589251eb40fSJonathan Cameron { 590251eb40fSJonathan Cameron int ret = 0; 591251eb40fSJonathan Cameron int timeout = HZ; 592251eb40fSJonathan Cameron 593251eb40fSJonathan Cameron mutex_lock(&data->read_lock); 59499a0378dSVivien Didelot if (time_after(jiffies, data->last_measurement + timeout) 59599a0378dSVivien Didelot || !data->measurements_valid) { 59699a0378dSVivien Didelot data->state = SHT15_READING_HUMID; 59799a0378dSVivien Didelot ret = sht15_measurement(data, SHT15_MEASURE_RH, 160); 598251eb40fSJonathan Cameron if (ret) 599412e29c1SVivien Didelot goto unlock; 60099a0378dSVivien Didelot data->state = SHT15_READING_TEMP; 60199a0378dSVivien Didelot ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400); 602251eb40fSJonathan Cameron if (ret) 603412e29c1SVivien Didelot goto unlock; 60499a0378dSVivien Didelot data->measurements_valid = true; 60599a0378dSVivien Didelot data->last_measurement = jiffies; 606251eb40fSJonathan Cameron } 607251eb40fSJonathan Cameron 608412e29c1SVivien Didelot unlock: 609412e29c1SVivien Didelot mutex_unlock(&data->read_lock); 610251eb40fSJonathan Cameron return ret; 611251eb40fSJonathan Cameron } 612251eb40fSJonathan Cameron 613251eb40fSJonathan Cameron /** 614251eb40fSJonathan Cameron * sht15_calc_temp() - convert the raw reading to a temperature 615251eb40fSJonathan Cameron * @data: device state 616251eb40fSJonathan Cameron * 617251eb40fSJonathan Cameron * As per section 4.3 of the data sheet. 61899a0378dSVivien Didelot */ 619251eb40fSJonathan Cameron static inline int sht15_calc_temp(struct sht15_data *data) 620251eb40fSJonathan Cameron { 621328a2c22SJerome Oufella int d1 = temppoints[0].d1; 622cc15c7ebSVivien Didelot int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10; 623251eb40fSJonathan Cameron int i; 624251eb40fSJonathan Cameron 625328a2c22SJerome Oufella for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--) 626251eb40fSJonathan Cameron /* Find pointer to interpolate */ 627142c0901SVivien Didelot if (data->supply_uv > temppoints[i - 1].vdd) { 628142c0901SVivien Didelot d1 = (data->supply_uv - temppoints[i - 1].vdd) 629251eb40fSJonathan Cameron * (temppoints[i].d1 - temppoints[i - 1].d1) 630251eb40fSJonathan Cameron / (temppoints[i].vdd - temppoints[i - 1].vdd) 631251eb40fSJonathan Cameron + temppoints[i - 1].d1; 632251eb40fSJonathan Cameron break; 633251eb40fSJonathan Cameron } 634251eb40fSJonathan Cameron 635cc15c7ebSVivien Didelot return data->val_temp * d2 + d1; 636251eb40fSJonathan Cameron } 637251eb40fSJonathan Cameron 638251eb40fSJonathan Cameron /** 639251eb40fSJonathan Cameron * sht15_calc_humid() - using last temperature convert raw to humid 640251eb40fSJonathan Cameron * @data: device state 641251eb40fSJonathan Cameron * 642251eb40fSJonathan Cameron * This is the temperature compensated version as per section 4.2 of 643251eb40fSJonathan Cameron * the data sheet. 64499a0378dSVivien Didelot * 64599a0378dSVivien Didelot * The sensor is assumed to be V3, which is compatible with V4. 64699a0378dSVivien Didelot * Humidity conversion coefficients are shown in table 7 of the datasheet. 64799a0378dSVivien Didelot */ 648251eb40fSJonathan Cameron static inline int sht15_calc_humid(struct sht15_data *data) 649251eb40fSJonathan Cameron { 65099a0378dSVivien Didelot int rh_linear; /* milli percent */ 651251eb40fSJonathan Cameron int temp = sht15_calc_temp(data); 652cc15c7ebSVivien Didelot int c2, c3; 653cc15c7ebSVivien Didelot int t2; 654251eb40fSJonathan Cameron const int c1 = -4; 655cc15c7ebSVivien Didelot 656cc15c7ebSVivien Didelot if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) { 657cc15c7ebSVivien Didelot c2 = 648000; /* x 10 ^ -6 */ 658cc15c7ebSVivien Didelot c3 = -7200; /* x 10 ^ -7 */ 659cc15c7ebSVivien Didelot t2 = 1280; 660cc15c7ebSVivien Didelot } else { 661cc15c7ebSVivien Didelot c2 = 40500; /* x 10 ^ -6 */ 662cc15c7ebSVivien Didelot c3 = -28; /* x 10 ^ -7 */ 663cc15c7ebSVivien Didelot t2 = 80; 664cc15c7ebSVivien Didelot } 665251eb40fSJonathan Cameron 66699a0378dSVivien Didelot rh_linear = c1 * 1000 667251eb40fSJonathan Cameron + c2 * data->val_humid / 1000 668ccd32e73SVivien Didelot + (data->val_humid * data->val_humid * c3) / 10000; 669cc15c7ebSVivien Didelot return (temp - 25000) * (10000 + t2 * data->val_humid) 67099a0378dSVivien Didelot / 1000000 + rh_linear; 671251eb40fSJonathan Cameron } 672251eb40fSJonathan Cameron 67399a0378dSVivien Didelot /** 674cc15c7ebSVivien Didelot * sht15_show_status() - show status information in sysfs 675cc15c7ebSVivien Didelot * @dev: device. 676cc15c7ebSVivien Didelot * @attr: device attribute. 677cc15c7ebSVivien Didelot * @buf: sysfs buffer where information is written to. 678cc15c7ebSVivien Didelot * 679cc15c7ebSVivien Didelot * Will be called on read access to temp1_fault, humidity1_fault 680cc15c7ebSVivien Didelot * and heater_enable sysfs attributes. 681cc15c7ebSVivien Didelot * Returns number of bytes written into buffer, negative errno on error. 682cc15c7ebSVivien Didelot */ 683cc15c7ebSVivien Didelot static ssize_t sht15_show_status(struct device *dev, 684cc15c7ebSVivien Didelot struct device_attribute *attr, 685cc15c7ebSVivien Didelot char *buf) 686cc15c7ebSVivien Didelot { 687cc15c7ebSVivien Didelot int ret; 688cc15c7ebSVivien Didelot struct sht15_data *data = dev_get_drvdata(dev); 689cc15c7ebSVivien Didelot u8 bit = to_sensor_dev_attr(attr)->index; 690cc15c7ebSVivien Didelot 691cc15c7ebSVivien Didelot ret = sht15_update_status(data); 692cc15c7ebSVivien Didelot 693cc15c7ebSVivien Didelot return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit)); 694cc15c7ebSVivien Didelot } 695cc15c7ebSVivien Didelot 696cc15c7ebSVivien Didelot /** 697cc15c7ebSVivien Didelot * sht15_store_heater() - change heater state via sysfs 698cc15c7ebSVivien Didelot * @dev: device. 699cc15c7ebSVivien Didelot * @attr: device attribute. 700cc15c7ebSVivien Didelot * @buf: sysfs buffer to read the new heater state from. 701cc15c7ebSVivien Didelot * @count: length of the data. 702cc15c7ebSVivien Didelot * 703e9b6e9f3SVivien Didelot * Will be called on write access to heater_enable sysfs attribute. 704cc15c7ebSVivien Didelot * Returns number of bytes actually decoded, negative errno on error. 705cc15c7ebSVivien Didelot */ 706cc15c7ebSVivien Didelot static ssize_t sht15_store_heater(struct device *dev, 707cc15c7ebSVivien Didelot struct device_attribute *attr, 708cc15c7ebSVivien Didelot const char *buf, size_t count) 709cc15c7ebSVivien Didelot { 710cc15c7ebSVivien Didelot int ret; 711cc15c7ebSVivien Didelot struct sht15_data *data = dev_get_drvdata(dev); 712cc15c7ebSVivien Didelot long value; 713cc15c7ebSVivien Didelot u8 status; 714cc15c7ebSVivien Didelot 715179c4fdbSFrans Meulenbroeks if (kstrtol(buf, 10, &value)) 716cc15c7ebSVivien Didelot return -EINVAL; 717cc15c7ebSVivien Didelot 718cc15c7ebSVivien Didelot mutex_lock(&data->read_lock); 719cc15c7ebSVivien Didelot status = data->val_status & 0x07; 720cc15c7ebSVivien Didelot if (!!value) 721cc15c7ebSVivien Didelot status |= SHT15_STATUS_HEATER; 722cc15c7ebSVivien Didelot else 723cc15c7ebSVivien Didelot status &= ~SHT15_STATUS_HEATER; 724cc15c7ebSVivien Didelot 725cc15c7ebSVivien Didelot ret = sht15_send_status(data, status); 726cc15c7ebSVivien Didelot mutex_unlock(&data->read_lock); 727cc15c7ebSVivien Didelot 728cc15c7ebSVivien Didelot return ret ? ret : count; 729cc15c7ebSVivien Didelot } 730cc15c7ebSVivien Didelot 731cc15c7ebSVivien Didelot /** 73299a0378dSVivien Didelot * sht15_show_temp() - show temperature measurement value in sysfs 73399a0378dSVivien Didelot * @dev: device. 73499a0378dSVivien Didelot * @attr: device attribute. 73599a0378dSVivien Didelot * @buf: sysfs buffer where measurement values are written to. 73699a0378dSVivien Didelot * 73799a0378dSVivien Didelot * Will be called on read access to temp1_input sysfs attribute. 73899a0378dSVivien Didelot * Returns number of bytes written into buffer, negative errno on error. 73999a0378dSVivien Didelot */ 740251eb40fSJonathan Cameron static ssize_t sht15_show_temp(struct device *dev, 741251eb40fSJonathan Cameron struct device_attribute *attr, 742251eb40fSJonathan Cameron char *buf) 743251eb40fSJonathan Cameron { 744251eb40fSJonathan Cameron int ret; 745251eb40fSJonathan Cameron struct sht15_data *data = dev_get_drvdata(dev); 746251eb40fSJonathan Cameron 747251eb40fSJonathan Cameron /* Technically no need to read humidity as well */ 74899a0378dSVivien Didelot ret = sht15_update_measurements(data); 749251eb40fSJonathan Cameron 750251eb40fSJonathan Cameron return ret ? ret : sprintf(buf, "%d\n", 751251eb40fSJonathan Cameron sht15_calc_temp(data)); 752251eb40fSJonathan Cameron } 753251eb40fSJonathan Cameron 75499a0378dSVivien Didelot /** 75599a0378dSVivien Didelot * sht15_show_humidity() - show humidity measurement value in sysfs 75699a0378dSVivien Didelot * @dev: device. 75799a0378dSVivien Didelot * @attr: device attribute. 75899a0378dSVivien Didelot * @buf: sysfs buffer where measurement values are written to. 75999a0378dSVivien Didelot * 76099a0378dSVivien Didelot * Will be called on read access to humidity1_input sysfs attribute. 76199a0378dSVivien Didelot * Returns number of bytes written into buffer, negative errno on error. 76299a0378dSVivien Didelot */ 763251eb40fSJonathan Cameron static ssize_t sht15_show_humidity(struct device *dev, 764251eb40fSJonathan Cameron struct device_attribute *attr, 765251eb40fSJonathan Cameron char *buf) 766251eb40fSJonathan Cameron { 767251eb40fSJonathan Cameron int ret; 768251eb40fSJonathan Cameron struct sht15_data *data = dev_get_drvdata(dev); 769251eb40fSJonathan Cameron 77099a0378dSVivien Didelot ret = sht15_update_measurements(data); 771251eb40fSJonathan Cameron 772251eb40fSJonathan Cameron return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data)); 77399a0378dSVivien Didelot } 77499a0378dSVivien Didelot 775af3d387fSJulia Lawall static ssize_t name_show(struct device *dev, 776251eb40fSJonathan Cameron struct device_attribute *attr, 777251eb40fSJonathan Cameron char *buf) 778251eb40fSJonathan Cameron { 779251eb40fSJonathan Cameron struct platform_device *pdev = to_platform_device(dev); 780251eb40fSJonathan Cameron return sprintf(buf, "%s\n", pdev->name); 781251eb40fSJonathan Cameron } 782251eb40fSJonathan Cameron 78399a0378dSVivien Didelot static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, 78499a0378dSVivien Didelot sht15_show_temp, NULL, 0); 78599a0378dSVivien Didelot static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, 78699a0378dSVivien Didelot sht15_show_humidity, NULL, 0); 787cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL, 788cc15c7ebSVivien Didelot SHT15_STATUS_LOW_BATTERY); 789cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL, 790cc15c7ebSVivien Didelot SHT15_STATUS_LOW_BATTERY); 791cc15c7ebSVivien Didelot static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status, 792cc15c7ebSVivien Didelot sht15_store_heater, SHT15_STATUS_HEATER); 793af3d387fSJulia Lawall static DEVICE_ATTR_RO(name); 794251eb40fSJonathan Cameron static struct attribute *sht15_attrs[] = { 795251eb40fSJonathan Cameron &sensor_dev_attr_temp1_input.dev_attr.attr, 796251eb40fSJonathan Cameron &sensor_dev_attr_humidity1_input.dev_attr.attr, 797cc15c7ebSVivien Didelot &sensor_dev_attr_temp1_fault.dev_attr.attr, 798cc15c7ebSVivien Didelot &sensor_dev_attr_humidity1_fault.dev_attr.attr, 799cc15c7ebSVivien Didelot &sensor_dev_attr_heater_enable.dev_attr.attr, 800251eb40fSJonathan Cameron &dev_attr_name.attr, 801251eb40fSJonathan Cameron NULL, 802251eb40fSJonathan Cameron }; 803251eb40fSJonathan Cameron 804251eb40fSJonathan Cameron static const struct attribute_group sht15_attr_group = { 805251eb40fSJonathan Cameron .attrs = sht15_attrs, 806251eb40fSJonathan Cameron }; 807251eb40fSJonathan Cameron 808251eb40fSJonathan Cameron static irqreturn_t sht15_interrupt_fired(int irq, void *d) 809251eb40fSJonathan Cameron { 810251eb40fSJonathan Cameron struct sht15_data *data = d; 81199a0378dSVivien Didelot 812251eb40fSJonathan Cameron /* First disable the interrupt */ 813251eb40fSJonathan Cameron disable_irq_nosync(irq); 814251eb40fSJonathan Cameron atomic_inc(&data->interrupt_handled); 815251eb40fSJonathan Cameron /* Then schedule a reading work struct */ 81699a0378dSVivien Didelot if (data->state != SHT15_READING_NOTHING) 817251eb40fSJonathan Cameron schedule_work(&data->read_work); 818251eb40fSJonathan Cameron return IRQ_HANDLED; 819251eb40fSJonathan Cameron } 820251eb40fSJonathan Cameron 821251eb40fSJonathan Cameron static void sht15_bh_read_data(struct work_struct *work_s) 822251eb40fSJonathan Cameron { 823251eb40fSJonathan Cameron uint16_t val = 0; 82482c7465bSJerome Oufella u8 dev_checksum = 0; 82582c7465bSJerome Oufella u8 checksum_vals[3]; 826251eb40fSJonathan Cameron struct sht15_data *data 827251eb40fSJonathan Cameron = container_of(work_s, struct sht15_data, 828251eb40fSJonathan Cameron read_work); 82999a0378dSVivien Didelot 830251eb40fSJonathan Cameron /* Firstly, verify the line is low */ 83118673114SLinus Walleij if (gpiod_get_value(data->data)) { 83299a0378dSVivien Didelot /* 83399a0378dSVivien Didelot * If not, then start the interrupt again - care here as could 83499a0378dSVivien Didelot * have gone low in meantime so verify it hasn't! 835251eb40fSJonathan Cameron */ 836251eb40fSJonathan Cameron atomic_set(&data->interrupt_handled, 0); 83718673114SLinus Walleij enable_irq(gpiod_to_irq(data->data)); 838c9e1498aSFrans Meulenbroeks /* If still not occurred or another handler was scheduled */ 83918673114SLinus Walleij if (gpiod_get_value(data->data) 840251eb40fSJonathan Cameron || atomic_read(&data->interrupt_handled)) 841251eb40fSJonathan Cameron return; 842251eb40fSJonathan Cameron } 84399a0378dSVivien Didelot 844251eb40fSJonathan Cameron /* Read the data back from the device */ 845cc15c7ebSVivien Didelot val = sht15_read_byte(data); 846cc15c7ebSVivien Didelot val <<= 8; 847412e29c1SVivien Didelot if (sht15_ack(data)) 848412e29c1SVivien Didelot goto wakeup; 849cc15c7ebSVivien Didelot val |= sht15_read_byte(data); 85099a0378dSVivien Didelot 85182c7465bSJerome Oufella if (data->checksumming) { 85282c7465bSJerome Oufella /* 85382c7465bSJerome Oufella * Ask the device for a checksum and read it back. 85482c7465bSJerome Oufella * Note: the device sends the checksum byte reversed. 85582c7465bSJerome Oufella */ 856412e29c1SVivien Didelot if (sht15_ack(data)) 857412e29c1SVivien Didelot goto wakeup; 85833836ee9Syalin wang dev_checksum = bitrev8(sht15_read_byte(data)); 85982c7465bSJerome Oufella checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? 86082c7465bSJerome Oufella SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; 86182c7465bSJerome Oufella checksum_vals[1] = (u8) (val >> 8); 86282c7465bSJerome Oufella checksum_vals[2] = (u8) val; 86382c7465bSJerome Oufella data->checksum_ok 86482c7465bSJerome Oufella = (sht15_crc8(data, checksum_vals, 3) == dev_checksum); 86582c7465bSJerome Oufella } 86682c7465bSJerome Oufella 867251eb40fSJonathan Cameron /* Tell the device we are done */ 868412e29c1SVivien Didelot if (sht15_end_transmission(data)) 869412e29c1SVivien Didelot goto wakeup; 870251eb40fSJonathan Cameron 87199a0378dSVivien Didelot switch (data->state) { 872251eb40fSJonathan Cameron case SHT15_READING_TEMP: 873251eb40fSJonathan Cameron data->val_temp = val; 874251eb40fSJonathan Cameron break; 875251eb40fSJonathan Cameron case SHT15_READING_HUMID: 876251eb40fSJonathan Cameron data->val_humid = val; 877251eb40fSJonathan Cameron break; 87899a0378dSVivien Didelot default: 87999a0378dSVivien Didelot break; 880251eb40fSJonathan Cameron } 881251eb40fSJonathan Cameron 88299a0378dSVivien Didelot data->state = SHT15_READING_NOTHING; 883412e29c1SVivien Didelot wakeup: 884251eb40fSJonathan Cameron wake_up(&data->wait_queue); 885251eb40fSJonathan Cameron } 886251eb40fSJonathan Cameron 887251eb40fSJonathan Cameron static void sht15_update_voltage(struct work_struct *work_s) 888251eb40fSJonathan Cameron { 889251eb40fSJonathan Cameron struct sht15_data *data 890251eb40fSJonathan Cameron = container_of(work_s, struct sht15_data, 891251eb40fSJonathan Cameron update_supply_work); 892142c0901SVivien Didelot data->supply_uv = regulator_get_voltage(data->reg); 893251eb40fSJonathan Cameron } 894251eb40fSJonathan Cameron 895251eb40fSJonathan Cameron /** 896251eb40fSJonathan Cameron * sht15_invalidate_voltage() - mark supply voltage invalid when notified by reg 897251eb40fSJonathan Cameron * @nb: associated notification structure 898251eb40fSJonathan Cameron * @event: voltage regulator state change event code 899251eb40fSJonathan Cameron * @ignored: function parameter - ignored here 900251eb40fSJonathan Cameron * 901251eb40fSJonathan Cameron * Note that as the notification code holds the regulator lock, we have 902251eb40fSJonathan Cameron * to schedule an update of the supply voltage rather than getting it directly. 90399a0378dSVivien Didelot */ 904251eb40fSJonathan Cameron static int sht15_invalidate_voltage(struct notifier_block *nb, 905251eb40fSJonathan Cameron unsigned long event, 906251eb40fSJonathan Cameron void *ignored) 907251eb40fSJonathan Cameron { 908251eb40fSJonathan Cameron struct sht15_data *data = container_of(nb, struct sht15_data, nb); 909251eb40fSJonathan Cameron 910251eb40fSJonathan Cameron if (event == REGULATOR_EVENT_VOLTAGE_CHANGE) 911142c0901SVivien Didelot data->supply_uv_valid = false; 912251eb40fSJonathan Cameron schedule_work(&data->update_supply_work); 913251eb40fSJonathan Cameron 914251eb40fSJonathan Cameron return NOTIFY_OK; 915251eb40fSJonathan Cameron } 916251eb40fSJonathan Cameron 9172f1736ffSMarco Franchi #ifdef CONFIG_OF 9182f1736ffSMarco Franchi static const struct of_device_id sht15_dt_match[] = { 9192f1736ffSMarco Franchi { .compatible = "sensirion,sht15" }, 9202f1736ffSMarco Franchi { }, 9212f1736ffSMarco Franchi }; 9222f1736ffSMarco Franchi MODULE_DEVICE_TABLE(of, sht15_dt_match); 9232f1736ffSMarco Franchi #endif 9242f1736ffSMarco Franchi 9256c931ae1SBill Pemberton static int sht15_probe(struct platform_device *pdev) 926251eb40fSJonathan Cameron { 9276edf3c30SVivien Didelot int ret; 92838fe7560SGuenter Roeck struct sht15_data *data; 929251eb40fSJonathan Cameron 93038fe7560SGuenter Roeck data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 93138fe7560SGuenter Roeck if (!data) 93238fe7560SGuenter Roeck return -ENOMEM; 933251eb40fSJonathan Cameron 934251eb40fSJonathan Cameron INIT_WORK(&data->read_work, sht15_bh_read_data); 935251eb40fSJonathan Cameron INIT_WORK(&data->update_supply_work, sht15_update_voltage); 936251eb40fSJonathan Cameron platform_set_drvdata(pdev, data); 937251eb40fSJonathan Cameron mutex_init(&data->read_lock); 938251eb40fSJonathan Cameron data->dev = &pdev->dev; 939251eb40fSJonathan Cameron init_waitqueue_head(&data->wait_queue); 940251eb40fSJonathan Cameron 94199a0378dSVivien Didelot /* 94299a0378dSVivien Didelot * If a regulator is available, 94399a0378dSVivien Didelot * query what the supply voltage actually is! 94499a0378dSVivien Didelot */ 9459e059bacSMark Brown data->reg = devm_regulator_get_optional(data->dev, "vcc"); 946251eb40fSJonathan Cameron if (!IS_ERR(data->reg)) { 947c7a78d2cSJean Delvare int voltage; 948c7a78d2cSJean Delvare 949c7a78d2cSJean Delvare voltage = regulator_get_voltage(data->reg); 950c7a78d2cSJean Delvare if (voltage) 951142c0901SVivien Didelot data->supply_uv = voltage; 952c7a78d2cSJean Delvare 9533e78080fSMark Brown ret = regulator_enable(data->reg); 9543e78080fSMark Brown if (ret != 0) { 9553e78080fSMark Brown dev_err(&pdev->dev, 9563e78080fSMark Brown "failed to enable regulator: %d\n", ret); 9573e78080fSMark Brown return ret; 9583e78080fSMark Brown } 9593e78080fSMark Brown 96099a0378dSVivien Didelot /* 96199a0378dSVivien Didelot * Setup a notifier block to update this if another device 96299a0378dSVivien Didelot * causes the voltage to change 96399a0378dSVivien Didelot */ 964251eb40fSJonathan Cameron data->nb.notifier_call = &sht15_invalidate_voltage; 965251eb40fSJonathan Cameron ret = regulator_register_notifier(data->reg, &data->nb); 966181148aeSVivien Didelot if (ret) { 967181148aeSVivien Didelot dev_err(&pdev->dev, 968181148aeSVivien Didelot "regulator notifier request failed\n"); 969181148aeSVivien Didelot regulator_disable(data->reg); 97038fe7560SGuenter Roeck return ret; 971181148aeSVivien Didelot } 972251eb40fSJonathan Cameron } 97399a0378dSVivien Didelot 974251eb40fSJonathan Cameron /* Try requesting the GPIOs */ 97518673114SLinus Walleij data->sck = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_LOW); 97618673114SLinus Walleij if (IS_ERR(data->sck)) { 97718673114SLinus Walleij ret = PTR_ERR(data->sck); 978412e29c1SVivien Didelot dev_err(&pdev->dev, "clock line GPIO request failed\n"); 979181148aeSVivien Didelot goto err_release_reg; 980251eb40fSJonathan Cameron } 98118673114SLinus Walleij data->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN); 98218673114SLinus Walleij if (IS_ERR(data->data)) { 98318673114SLinus Walleij ret = PTR_ERR(data->data); 984412e29c1SVivien Didelot dev_err(&pdev->dev, "data line GPIO request failed\n"); 98538fe7560SGuenter Roeck goto err_release_reg; 986251eb40fSJonathan Cameron } 987251eb40fSJonathan Cameron 98818673114SLinus Walleij ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data), 989251eb40fSJonathan Cameron sht15_interrupt_fired, 990251eb40fSJonathan Cameron IRQF_TRIGGER_FALLING, 991251eb40fSJonathan Cameron "sht15 data", 992251eb40fSJonathan Cameron data); 993251eb40fSJonathan Cameron if (ret) { 99499a0378dSVivien Didelot dev_err(&pdev->dev, "failed to get irq for data line\n"); 99538fe7560SGuenter Roeck goto err_release_reg; 996251eb40fSJonathan Cameron } 99718673114SLinus Walleij disable_irq_nosync(gpiod_to_irq(data->data)); 998412e29c1SVivien Didelot ret = sht15_connection_reset(data); 999412e29c1SVivien Didelot if (ret) 1000412e29c1SVivien Didelot goto err_release_reg; 1001181148aeSVivien Didelot ret = sht15_soft_reset(data); 1002181148aeSVivien Didelot if (ret) 100338fe7560SGuenter Roeck goto err_release_reg; 1004181148aeSVivien Didelot 1005181148aeSVivien Didelot ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group); 1006181148aeSVivien Didelot if (ret) { 1007181148aeSVivien Didelot dev_err(&pdev->dev, "sysfs create failed\n"); 100838fe7560SGuenter Roeck goto err_release_reg; 1009181148aeSVivien Didelot } 1010251eb40fSJonathan Cameron 1011251eb40fSJonathan Cameron data->hwmon_dev = hwmon_device_register(data->dev); 1012251eb40fSJonathan Cameron if (IS_ERR(data->hwmon_dev)) { 1013251eb40fSJonathan Cameron ret = PTR_ERR(data->hwmon_dev); 1014181148aeSVivien Didelot goto err_release_sysfs_group; 1015251eb40fSJonathan Cameron } 101699a0378dSVivien Didelot 1017251eb40fSJonathan Cameron return 0; 1018251eb40fSJonathan Cameron 1019181148aeSVivien Didelot err_release_sysfs_group: 1020181148aeSVivien Didelot sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group); 1021181148aeSVivien Didelot err_release_reg: 1022181148aeSVivien Didelot if (!IS_ERR(data->reg)) { 1023181148aeSVivien Didelot regulator_unregister_notifier(data->reg, &data->nb); 1024181148aeSVivien Didelot regulator_disable(data->reg); 1025181148aeSVivien Didelot } 1026251eb40fSJonathan Cameron return ret; 1027251eb40fSJonathan Cameron } 1028251eb40fSJonathan Cameron 1029281dfd0bSBill Pemberton static int sht15_remove(struct platform_device *pdev) 1030251eb40fSJonathan Cameron { 1031251eb40fSJonathan Cameron struct sht15_data *data = platform_get_drvdata(pdev); 1032251eb40fSJonathan Cameron 103399a0378dSVivien Didelot /* 103499a0378dSVivien Didelot * Make sure any reads from the device are done and 103599a0378dSVivien Didelot * prevent new ones beginning 103699a0378dSVivien Didelot */ 1037251eb40fSJonathan Cameron mutex_lock(&data->read_lock); 1038cc15c7ebSVivien Didelot if (sht15_soft_reset(data)) { 1039cc15c7ebSVivien Didelot mutex_unlock(&data->read_lock); 1040cc15c7ebSVivien Didelot return -EFAULT; 1041cc15c7ebSVivien Didelot } 1042251eb40fSJonathan Cameron hwmon_device_unregister(data->hwmon_dev); 1043251eb40fSJonathan Cameron sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group); 1044251eb40fSJonathan Cameron if (!IS_ERR(data->reg)) { 1045251eb40fSJonathan Cameron regulator_unregister_notifier(data->reg, &data->nb); 1046251eb40fSJonathan Cameron regulator_disable(data->reg); 1047251eb40fSJonathan Cameron } 1048251eb40fSJonathan Cameron 1049251eb40fSJonathan Cameron mutex_unlock(&data->read_lock); 105099a0378dSVivien Didelot 1051251eb40fSJonathan Cameron return 0; 1052251eb40fSJonathan Cameron } 1053251eb40fSJonathan Cameron 10549c40723eSKrzysztof Kozlowski static const struct platform_device_id sht15_device_ids[] = { 1055edec5af7SVivien Didelot { "sht10", sht10 }, 1056edec5af7SVivien Didelot { "sht11", sht11 }, 1057edec5af7SVivien Didelot { "sht15", sht15 }, 1058edec5af7SVivien Didelot { "sht71", sht71 }, 1059edec5af7SVivien Didelot { "sht75", sht75 }, 1060edec5af7SVivien Didelot { } 1061edec5af7SVivien Didelot }; 1062edec5af7SVivien Didelot MODULE_DEVICE_TABLE(platform, sht15_device_ids); 1063edec5af7SVivien Didelot 1064edec5af7SVivien Didelot static struct platform_driver sht15_driver = { 1065251eb40fSJonathan Cameron .driver = { 1066251eb40fSJonathan Cameron .name = "sht15", 10672f1736ffSMarco Franchi .of_match_table = of_match_ptr(sht15_dt_match), 1068251eb40fSJonathan Cameron }, 1069251eb40fSJonathan Cameron .probe = sht15_probe, 10709e5e9b7aSBill Pemberton .remove = sht15_remove, 1071edec5af7SVivien Didelot .id_table = sht15_device_ids, 1072251eb40fSJonathan Cameron }; 1073edec5af7SVivien Didelot module_platform_driver(sht15_driver); 1074251eb40fSJonathan Cameron 1075251eb40fSJonathan Cameron MODULE_LICENSE("GPL"); 1076edec5af7SVivien Didelot MODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver"); 1077