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