18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sht15.c - support for the SHT15 Temperature and Humidity Sensor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Portions Copyright (c) 2010-2012 Savoir-faire Linux Inc. 68c2ecf20Sopenharmony_ci * Jerome Oufella <jerome.oufella@savoirfairelinux.com> 78c2ecf20Sopenharmony_ci * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2009 Jonathan Cameron 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2007 Wouter Horre 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * For further information, see the Documentation/hwmon/sht15.rst file. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/irq.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 218c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 228c2ecf20Sopenharmony_ci#include <linux/mutex.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/sched.h> 258c2ecf20Sopenharmony_ci#include <linux/delay.h> 268c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 278c2ecf20Sopenharmony_ci#include <linux/err.h> 288c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/atomic.h> 318c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 328c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 338c2ecf20Sopenharmony_ci#include <linux/of.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Commands */ 368c2ecf20Sopenharmony_ci#define SHT15_MEASURE_TEMP 0x03 378c2ecf20Sopenharmony_ci#define SHT15_MEASURE_RH 0x05 388c2ecf20Sopenharmony_ci#define SHT15_WRITE_STATUS 0x06 398c2ecf20Sopenharmony_ci#define SHT15_READ_STATUS 0x07 408c2ecf20Sopenharmony_ci#define SHT15_SOFT_RESET 0x1E 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Min timings */ 438c2ecf20Sopenharmony_ci#define SHT15_TSCKL 100 /* (nsecs) clock low */ 448c2ecf20Sopenharmony_ci#define SHT15_TSCKH 100 /* (nsecs) clock high */ 458c2ecf20Sopenharmony_ci#define SHT15_TSU 150 /* (nsecs) data setup time */ 468c2ecf20Sopenharmony_ci#define SHT15_TSRST 11 /* (msecs) soft reset time */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Status Register Bits */ 498c2ecf20Sopenharmony_ci#define SHT15_STATUS_LOW_RESOLUTION 0x01 508c2ecf20Sopenharmony_ci#define SHT15_STATUS_NO_OTP_RELOAD 0x02 518c2ecf20Sopenharmony_ci#define SHT15_STATUS_HEATER 0x04 528c2ecf20Sopenharmony_ci#define SHT15_STATUS_LOW_BATTERY 0x40 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* List of supported chips */ 558c2ecf20Sopenharmony_cienum sht15_chips { sht10, sht11, sht15, sht71, sht75 }; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Actions the driver may be doing */ 588c2ecf20Sopenharmony_cienum sht15_state { 598c2ecf20Sopenharmony_ci SHT15_READING_NOTHING, 608c2ecf20Sopenharmony_ci SHT15_READING_TEMP, 618c2ecf20Sopenharmony_ci SHT15_READING_HUMID 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * struct sht15_temppair - elements of voltage dependent temp calc 668c2ecf20Sopenharmony_ci * @vdd: supply voltage in microvolts 678c2ecf20Sopenharmony_ci * @d1: see data sheet 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistruct sht15_temppair { 708c2ecf20Sopenharmony_ci int vdd; /* microvolts */ 718c2ecf20Sopenharmony_ci int d1; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Table 9 from datasheet - relates temperature calculation to supply voltage */ 758c2ecf20Sopenharmony_cistatic const struct sht15_temppair temppoints[] = { 768c2ecf20Sopenharmony_ci { 2500000, -39400 }, 778c2ecf20Sopenharmony_ci { 3000000, -39600 }, 788c2ecf20Sopenharmony_ci { 3500000, -39700 }, 798c2ecf20Sopenharmony_ci { 4000000, -39800 }, 808c2ecf20Sopenharmony_ci { 5000000, -40100 }, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Table from CRC datasheet, section 2.4 */ 848c2ecf20Sopenharmony_cistatic const u8 sht15_crc8_table[] = { 858c2ecf20Sopenharmony_ci 0, 49, 98, 83, 196, 245, 166, 151, 868c2ecf20Sopenharmony_ci 185, 136, 219, 234, 125, 76, 31, 46, 878c2ecf20Sopenharmony_ci 67, 114, 33, 16, 135, 182, 229, 212, 888c2ecf20Sopenharmony_ci 250, 203, 152, 169, 62, 15, 92, 109, 898c2ecf20Sopenharmony_ci 134, 183, 228, 213, 66, 115, 32, 17, 908c2ecf20Sopenharmony_ci 63, 14, 93, 108, 251, 202, 153, 168, 918c2ecf20Sopenharmony_ci 197, 244, 167, 150, 1, 48, 99, 82, 928c2ecf20Sopenharmony_ci 124, 77, 30, 47, 184, 137, 218, 235, 938c2ecf20Sopenharmony_ci 61, 12, 95, 110, 249, 200, 155, 170, 948c2ecf20Sopenharmony_ci 132, 181, 230, 215, 64, 113, 34, 19, 958c2ecf20Sopenharmony_ci 126, 79, 28, 45, 186, 139, 216, 233, 968c2ecf20Sopenharmony_ci 199, 246, 165, 148, 3, 50, 97, 80, 978c2ecf20Sopenharmony_ci 187, 138, 217, 232, 127, 78, 29, 44, 988c2ecf20Sopenharmony_ci 2, 51, 96, 81, 198, 247, 164, 149, 998c2ecf20Sopenharmony_ci 248, 201, 154, 171, 60, 13, 94, 111, 1008c2ecf20Sopenharmony_ci 65, 112, 35, 18, 133, 180, 231, 214, 1018c2ecf20Sopenharmony_ci 122, 75, 24, 41, 190, 143, 220, 237, 1028c2ecf20Sopenharmony_ci 195, 242, 161, 144, 7, 54, 101, 84, 1038c2ecf20Sopenharmony_ci 57, 8, 91, 106, 253, 204, 159, 174, 1048c2ecf20Sopenharmony_ci 128, 177, 226, 211, 68, 117, 38, 23, 1058c2ecf20Sopenharmony_ci 252, 205, 158, 175, 56, 9, 90, 107, 1068c2ecf20Sopenharmony_ci 69, 116, 39, 22, 129, 176, 227, 210, 1078c2ecf20Sopenharmony_ci 191, 142, 221, 236, 123, 74, 25, 40, 1088c2ecf20Sopenharmony_ci 6, 55, 100, 85, 194, 243, 160, 145, 1098c2ecf20Sopenharmony_ci 71, 118, 37, 20, 131, 178, 225, 208, 1108c2ecf20Sopenharmony_ci 254, 207, 156, 173, 58, 11, 88, 105, 1118c2ecf20Sopenharmony_ci 4, 53, 102, 87, 192, 241, 162, 147, 1128c2ecf20Sopenharmony_ci 189, 140, 223, 238, 121, 72, 27, 42, 1138c2ecf20Sopenharmony_ci 193, 240, 163, 146, 5, 52, 103, 86, 1148c2ecf20Sopenharmony_ci 120, 73, 26, 43, 188, 141, 222, 239, 1158c2ecf20Sopenharmony_ci 130, 179, 224, 209, 70, 119, 36, 21, 1168c2ecf20Sopenharmony_ci 59, 10, 89, 104, 255, 206, 157, 172 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/** 1208c2ecf20Sopenharmony_ci * struct sht15_data - device instance specific data 1218c2ecf20Sopenharmony_ci * @sck: clock GPIO line 1228c2ecf20Sopenharmony_ci * @data: data GPIO line 1238c2ecf20Sopenharmony_ci * @read_work: bh of interrupt handler. 1248c2ecf20Sopenharmony_ci * @wait_queue: wait queue for getting values from device. 1258c2ecf20Sopenharmony_ci * @val_temp: last temperature value read from device. 1268c2ecf20Sopenharmony_ci * @val_humid: last humidity value read from device. 1278c2ecf20Sopenharmony_ci * @val_status: last status register value read from device. 1288c2ecf20Sopenharmony_ci * @checksum_ok: last value read from the device passed CRC validation. 1298c2ecf20Sopenharmony_ci * @checksumming: flag used to enable the data validation with CRC. 1308c2ecf20Sopenharmony_ci * @state: state identifying the action the driver is doing. 1318c2ecf20Sopenharmony_ci * @measurements_valid: are the current stored measures valid (start condition). 1328c2ecf20Sopenharmony_ci * @status_valid: is the current stored status valid (start condition). 1338c2ecf20Sopenharmony_ci * @last_measurement: time of last measure. 1348c2ecf20Sopenharmony_ci * @last_status: time of last status reading. 1358c2ecf20Sopenharmony_ci * @read_lock: mutex to ensure only one read in progress at a time. 1368c2ecf20Sopenharmony_ci * @dev: associate device structure. 1378c2ecf20Sopenharmony_ci * @hwmon_dev: device associated with hwmon subsystem. 1388c2ecf20Sopenharmony_ci * @reg: associated regulator (if specified). 1398c2ecf20Sopenharmony_ci * @nb: notifier block to handle notifications of voltage 1408c2ecf20Sopenharmony_ci * changes. 1418c2ecf20Sopenharmony_ci * @supply_uv: local copy of supply voltage used to allow use of 1428c2ecf20Sopenharmony_ci * regulator consumer if available. 1438c2ecf20Sopenharmony_ci * @supply_uv_valid: indicates that an updated value has not yet been 1448c2ecf20Sopenharmony_ci * obtained from the regulator and so any calculations 1458c2ecf20Sopenharmony_ci * based upon it will be invalid. 1468c2ecf20Sopenharmony_ci * @update_supply_work: work struct that is used to update the supply_uv. 1478c2ecf20Sopenharmony_ci * @interrupt_handled: flag used to indicate a handler has been scheduled. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistruct sht15_data { 1508c2ecf20Sopenharmony_ci struct gpio_desc *sck; 1518c2ecf20Sopenharmony_ci struct gpio_desc *data; 1528c2ecf20Sopenharmony_ci struct work_struct read_work; 1538c2ecf20Sopenharmony_ci wait_queue_head_t wait_queue; 1548c2ecf20Sopenharmony_ci uint16_t val_temp; 1558c2ecf20Sopenharmony_ci uint16_t val_humid; 1568c2ecf20Sopenharmony_ci u8 val_status; 1578c2ecf20Sopenharmony_ci bool checksum_ok; 1588c2ecf20Sopenharmony_ci bool checksumming; 1598c2ecf20Sopenharmony_ci enum sht15_state state; 1608c2ecf20Sopenharmony_ci bool measurements_valid; 1618c2ecf20Sopenharmony_ci bool status_valid; 1628c2ecf20Sopenharmony_ci unsigned long last_measurement; 1638c2ecf20Sopenharmony_ci unsigned long last_status; 1648c2ecf20Sopenharmony_ci struct mutex read_lock; 1658c2ecf20Sopenharmony_ci struct device *dev; 1668c2ecf20Sopenharmony_ci struct device *hwmon_dev; 1678c2ecf20Sopenharmony_ci struct regulator *reg; 1688c2ecf20Sopenharmony_ci struct notifier_block nb; 1698c2ecf20Sopenharmony_ci int supply_uv; 1708c2ecf20Sopenharmony_ci bool supply_uv_valid; 1718c2ecf20Sopenharmony_ci struct work_struct update_supply_work; 1728c2ecf20Sopenharmony_ci atomic_t interrupt_handled; 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/** 1768c2ecf20Sopenharmony_ci * sht15_crc8() - compute crc8 1778c2ecf20Sopenharmony_ci * @data: sht15 specific data. 1788c2ecf20Sopenharmony_ci * @value: sht15 retrieved data. 1798c2ecf20Sopenharmony_ci * @len: Length of retrieved data 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * This implements section 2 of the CRC datasheet. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistatic u8 sht15_crc8(struct sht15_data *data, 1848c2ecf20Sopenharmony_ci const u8 *value, 1858c2ecf20Sopenharmony_ci int len) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci u8 crc = bitrev8(data->val_status & 0x0F); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci while (len--) { 1908c2ecf20Sopenharmony_ci crc = sht15_crc8_table[*value ^ crc]; 1918c2ecf20Sopenharmony_ci value++; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return crc; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/** 1988c2ecf20Sopenharmony_ci * sht15_connection_reset() - reset the comms interface 1998c2ecf20Sopenharmony_ci * @data: sht15 specific data 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * This implements section 3.4 of the data sheet 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_cistatic int sht15_connection_reset(struct sht15_data *data) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int i, err; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci err = gpiod_direction_output(data->data, 1); 2088c2ecf20Sopenharmony_ci if (err) 2098c2ecf20Sopenharmony_ci return err; 2108c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2118c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2128c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2138c2ecf20Sopenharmony_ci for (i = 0; i < 9; ++i) { 2148c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 2158c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 2168c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2178c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/** 2238c2ecf20Sopenharmony_ci * sht15_send_bit() - send an individual bit to the device 2248c2ecf20Sopenharmony_ci * @data: device state data 2258c2ecf20Sopenharmony_ci * @val: value of bit to be sent 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic inline void sht15_send_bit(struct sht15_data *data, int val) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci gpiod_set_value(data->data, val); 2308c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 2318c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 2328c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 2338c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2348c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); /* clock low time */ 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * sht15_transmission_start() - specific sequence for new transmission 2398c2ecf20Sopenharmony_ci * @data: device state data 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Timings for this are not documented on the data sheet, so very 2428c2ecf20Sopenharmony_ci * conservative ones used in implementation. This implements 2438c2ecf20Sopenharmony_ci * figure 12 on the data sheet. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_cistatic int sht15_transmission_start(struct sht15_data *data) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int err; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* ensure data is high and output */ 2508c2ecf20Sopenharmony_ci err = gpiod_direction_output(data->data, 1); 2518c2ecf20Sopenharmony_ci if (err) 2528c2ecf20Sopenharmony_ci return err; 2538c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 2548c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2558c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2568c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 2578c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 2588c2ecf20Sopenharmony_ci gpiod_set_value(data->data, 0); 2598c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 2608c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2618c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2628c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 2638c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 2648c2ecf20Sopenharmony_ci gpiod_set_value(data->data, 1); 2658c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 2668c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 2678c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/** 2728c2ecf20Sopenharmony_ci * sht15_send_byte() - send a single byte to the device 2738c2ecf20Sopenharmony_ci * @data: device state 2748c2ecf20Sopenharmony_ci * @byte: value to be sent 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_cistatic void sht15_send_byte(struct sht15_data *data, u8 byte) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int i; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 2818c2ecf20Sopenharmony_ci sht15_send_bit(data, !!(byte & 0x80)); 2828c2ecf20Sopenharmony_ci byte <<= 1; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * sht15_wait_for_response() - checks for ack from device 2888c2ecf20Sopenharmony_ci * @data: device state 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic int sht15_wait_for_response(struct sht15_data *data) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int err; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci err = gpiod_direction_input(data->data); 2958c2ecf20Sopenharmony_ci if (err) 2968c2ecf20Sopenharmony_ci return err; 2978c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 2988c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 2998c2ecf20Sopenharmony_ci if (gpiod_get_value(data->data)) { 3008c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 3018c2ecf20Sopenharmony_ci dev_err(data->dev, "Command not acknowledged\n"); 3028c2ecf20Sopenharmony_ci err = sht15_connection_reset(data); 3038c2ecf20Sopenharmony_ci if (err) 3048c2ecf20Sopenharmony_ci return err; 3058c2ecf20Sopenharmony_ci return -EIO; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 3088c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/** 3138c2ecf20Sopenharmony_ci * sht15_send_cmd() - Sends a command to the device. 3148c2ecf20Sopenharmony_ci * @data: device state 3158c2ecf20Sopenharmony_ci * @cmd: command byte to be sent 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * On entry, sck is output low, data is output pull high 3188c2ecf20Sopenharmony_ci * and the interrupt disabled. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_cistatic int sht15_send_cmd(struct sht15_data *data, u8 cmd) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci int err; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci err = sht15_transmission_start(data); 3258c2ecf20Sopenharmony_ci if (err) 3268c2ecf20Sopenharmony_ci return err; 3278c2ecf20Sopenharmony_ci sht15_send_byte(data, cmd); 3288c2ecf20Sopenharmony_ci return sht15_wait_for_response(data); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/** 3328c2ecf20Sopenharmony_ci * sht15_soft_reset() - send a soft reset command 3338c2ecf20Sopenharmony_ci * @data: sht15 specific data. 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * As described in section 3.2 of the datasheet. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic int sht15_soft_reset(struct sht15_data *data) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci int ret; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = sht15_send_cmd(data, SHT15_SOFT_RESET); 3428c2ecf20Sopenharmony_ci if (ret) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci msleep(SHT15_TSRST); 3458c2ecf20Sopenharmony_ci /* device resets default hardware status register value */ 3468c2ecf20Sopenharmony_ci data->val_status = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * sht15_ack() - send a ack 3538c2ecf20Sopenharmony_ci * @data: sht15 specific data. 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Each byte of data is acknowledged by pulling the data line 3568c2ecf20Sopenharmony_ci * low for one clock pulse. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_cistatic int sht15_ack(struct sht15_data *data) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int err; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci err = gpiod_direction_output(data->data, 0); 3638c2ecf20Sopenharmony_ci if (err) 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 3668c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 3678c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 3688c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 3698c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 3708c2ecf20Sopenharmony_ci gpiod_set_value(data->data, 1); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return gpiod_direction_input(data->data); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/** 3768c2ecf20Sopenharmony_ci * sht15_end_transmission() - notify device of end of transmission 3778c2ecf20Sopenharmony_ci * @data: device state. 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * This is basically a NAK (single clock pulse, data high). 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_cistatic int sht15_end_transmission(struct sht15_data *data) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci int err; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci err = gpiod_direction_output(data->data, 1); 3868c2ecf20Sopenharmony_ci if (err) 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 3898c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 3908c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 3918c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 3928c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/** 3978c2ecf20Sopenharmony_ci * sht15_read_byte() - Read a byte back from the device 3988c2ecf20Sopenharmony_ci * @data: device state. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic u8 sht15_read_byte(struct sht15_data *data) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci int i; 4038c2ecf20Sopenharmony_ci u8 byte = 0; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 4068c2ecf20Sopenharmony_ci byte <<= 1; 4078c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 1); 4088c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKH); 4098c2ecf20Sopenharmony_ci byte |= !!gpiod_get_value(data->data); 4108c2ecf20Sopenharmony_ci gpiod_set_value(data->sck, 0); 4118c2ecf20Sopenharmony_ci ndelay(SHT15_TSCKL); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci return byte; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/** 4178c2ecf20Sopenharmony_ci * sht15_send_status() - write the status register byte 4188c2ecf20Sopenharmony_ci * @data: sht15 specific data. 4198c2ecf20Sopenharmony_ci * @status: the byte to set the status register with. 4208c2ecf20Sopenharmony_ci * 4218c2ecf20Sopenharmony_ci * As described in figure 14 and table 5 of the datasheet. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_cistatic int sht15_send_status(struct sht15_data *data, u8 status) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci int err; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci err = sht15_send_cmd(data, SHT15_WRITE_STATUS); 4288c2ecf20Sopenharmony_ci if (err) 4298c2ecf20Sopenharmony_ci return err; 4308c2ecf20Sopenharmony_ci err = gpiod_direction_output(data->data, 1); 4318c2ecf20Sopenharmony_ci if (err) 4328c2ecf20Sopenharmony_ci return err; 4338c2ecf20Sopenharmony_ci ndelay(SHT15_TSU); 4348c2ecf20Sopenharmony_ci sht15_send_byte(data, status); 4358c2ecf20Sopenharmony_ci err = sht15_wait_for_response(data); 4368c2ecf20Sopenharmony_ci if (err) 4378c2ecf20Sopenharmony_ci return err; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci data->val_status = status; 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci/** 4448c2ecf20Sopenharmony_ci * sht15_update_status() - get updated status register from device if too old 4458c2ecf20Sopenharmony_ci * @data: device instance specific data. 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci * As described in figure 15 and table 5 of the datasheet. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_cistatic int sht15_update_status(struct sht15_data *data) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int ret = 0; 4528c2ecf20Sopenharmony_ci u8 status; 4538c2ecf20Sopenharmony_ci u8 previous_config; 4548c2ecf20Sopenharmony_ci u8 dev_checksum = 0; 4558c2ecf20Sopenharmony_ci u8 checksum_vals[2]; 4568c2ecf20Sopenharmony_ci int timeout = HZ; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci mutex_lock(&data->read_lock); 4598c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_status + timeout) 4608c2ecf20Sopenharmony_ci || !data->status_valid) { 4618c2ecf20Sopenharmony_ci ret = sht15_send_cmd(data, SHT15_READ_STATUS); 4628c2ecf20Sopenharmony_ci if (ret) 4638c2ecf20Sopenharmony_ci goto unlock; 4648c2ecf20Sopenharmony_ci status = sht15_read_byte(data); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (data->checksumming) { 4678c2ecf20Sopenharmony_ci sht15_ack(data); 4688c2ecf20Sopenharmony_ci dev_checksum = bitrev8(sht15_read_byte(data)); 4698c2ecf20Sopenharmony_ci checksum_vals[0] = SHT15_READ_STATUS; 4708c2ecf20Sopenharmony_ci checksum_vals[1] = status; 4718c2ecf20Sopenharmony_ci data->checksum_ok = (sht15_crc8(data, checksum_vals, 2) 4728c2ecf20Sopenharmony_ci == dev_checksum); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci ret = sht15_end_transmission(data); 4768c2ecf20Sopenharmony_ci if (ret) 4778c2ecf20Sopenharmony_ci goto unlock; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* 4808c2ecf20Sopenharmony_ci * Perform checksum validation on the received data. 4818c2ecf20Sopenharmony_ci * Specification mentions that in case a checksum verification 4828c2ecf20Sopenharmony_ci * fails, a soft reset command must be sent to the device. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci if (data->checksumming && !data->checksum_ok) { 4858c2ecf20Sopenharmony_ci previous_config = data->val_status & 0x07; 4868c2ecf20Sopenharmony_ci ret = sht15_soft_reset(data); 4878c2ecf20Sopenharmony_ci if (ret) 4888c2ecf20Sopenharmony_ci goto unlock; 4898c2ecf20Sopenharmony_ci if (previous_config) { 4908c2ecf20Sopenharmony_ci ret = sht15_send_status(data, previous_config); 4918c2ecf20Sopenharmony_ci if (ret) { 4928c2ecf20Sopenharmony_ci dev_err(data->dev, 4938c2ecf20Sopenharmony_ci "CRC validation failed, unable " 4948c2ecf20Sopenharmony_ci "to restore device settings\n"); 4958c2ecf20Sopenharmony_ci goto unlock; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci ret = -EAGAIN; 4998c2ecf20Sopenharmony_ci goto unlock; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci data->val_status = status; 5038c2ecf20Sopenharmony_ci data->status_valid = true; 5048c2ecf20Sopenharmony_ci data->last_status = jiffies; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ciunlock: 5088c2ecf20Sopenharmony_ci mutex_unlock(&data->read_lock); 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** 5138c2ecf20Sopenharmony_ci * sht15_measurement() - get a new value from device 5148c2ecf20Sopenharmony_ci * @data: device instance specific data 5158c2ecf20Sopenharmony_ci * @command: command sent to request value 5168c2ecf20Sopenharmony_ci * @timeout_msecs: timeout after which comms are assumed 5178c2ecf20Sopenharmony_ci * to have failed are reset. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cistatic int sht15_measurement(struct sht15_data *data, 5208c2ecf20Sopenharmony_ci int command, 5218c2ecf20Sopenharmony_ci int timeout_msecs) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci int ret; 5248c2ecf20Sopenharmony_ci u8 previous_config; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ret = sht15_send_cmd(data, command); 5278c2ecf20Sopenharmony_ci if (ret) 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci ret = gpiod_direction_input(data->data); 5318c2ecf20Sopenharmony_ci if (ret) 5328c2ecf20Sopenharmony_ci return ret; 5338c2ecf20Sopenharmony_ci atomic_set(&data->interrupt_handled, 0); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci enable_irq(gpiod_to_irq(data->data)); 5368c2ecf20Sopenharmony_ci if (gpiod_get_value(data->data) == 0) { 5378c2ecf20Sopenharmony_ci disable_irq_nosync(gpiod_to_irq(data->data)); 5388c2ecf20Sopenharmony_ci /* Only relevant if the interrupt hasn't occurred. */ 5398c2ecf20Sopenharmony_ci if (!atomic_read(&data->interrupt_handled)) 5408c2ecf20Sopenharmony_ci schedule_work(&data->read_work); 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci ret = wait_event_timeout(data->wait_queue, 5438c2ecf20Sopenharmony_ci (data->state == SHT15_READING_NOTHING), 5448c2ecf20Sopenharmony_ci msecs_to_jiffies(timeout_msecs)); 5458c2ecf20Sopenharmony_ci if (data->state != SHT15_READING_NOTHING) { /* I/O error occurred */ 5468c2ecf20Sopenharmony_ci data->state = SHT15_READING_NOTHING; 5478c2ecf20Sopenharmony_ci return -EIO; 5488c2ecf20Sopenharmony_ci } else if (ret == 0) { /* timeout occurred */ 5498c2ecf20Sopenharmony_ci disable_irq_nosync(gpiod_to_irq(data->data)); 5508c2ecf20Sopenharmony_ci ret = sht15_connection_reset(data); 5518c2ecf20Sopenharmony_ci if (ret) 5528c2ecf20Sopenharmony_ci return ret; 5538c2ecf20Sopenharmony_ci return -ETIME; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * Perform checksum validation on the received data. 5588c2ecf20Sopenharmony_ci * Specification mentions that in case a checksum verification fails, 5598c2ecf20Sopenharmony_ci * a soft reset command must be sent to the device. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci if (data->checksumming && !data->checksum_ok) { 5628c2ecf20Sopenharmony_ci previous_config = data->val_status & 0x07; 5638c2ecf20Sopenharmony_ci ret = sht15_soft_reset(data); 5648c2ecf20Sopenharmony_ci if (ret) 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci if (previous_config) { 5678c2ecf20Sopenharmony_ci ret = sht15_send_status(data, previous_config); 5688c2ecf20Sopenharmony_ci if (ret) { 5698c2ecf20Sopenharmony_ci dev_err(data->dev, 5708c2ecf20Sopenharmony_ci "CRC validation failed, unable " 5718c2ecf20Sopenharmony_ci "to restore device settings\n"); 5728c2ecf20Sopenharmony_ci return ret; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci return -EAGAIN; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return 0; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/** 5828c2ecf20Sopenharmony_ci * sht15_update_measurements() - get updated measures from device if too old 5838c2ecf20Sopenharmony_ci * @data: device state 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic int sht15_update_measurements(struct sht15_data *data) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci int ret = 0; 5888c2ecf20Sopenharmony_ci int timeout = HZ; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci mutex_lock(&data->read_lock); 5918c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_measurement + timeout) 5928c2ecf20Sopenharmony_ci || !data->measurements_valid) { 5938c2ecf20Sopenharmony_ci data->state = SHT15_READING_HUMID; 5948c2ecf20Sopenharmony_ci ret = sht15_measurement(data, SHT15_MEASURE_RH, 160); 5958c2ecf20Sopenharmony_ci if (ret) 5968c2ecf20Sopenharmony_ci goto unlock; 5978c2ecf20Sopenharmony_ci data->state = SHT15_READING_TEMP; 5988c2ecf20Sopenharmony_ci ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci goto unlock; 6018c2ecf20Sopenharmony_ci data->measurements_valid = true; 6028c2ecf20Sopenharmony_ci data->last_measurement = jiffies; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ciunlock: 6068c2ecf20Sopenharmony_ci mutex_unlock(&data->read_lock); 6078c2ecf20Sopenharmony_ci return ret; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci/** 6118c2ecf20Sopenharmony_ci * sht15_calc_temp() - convert the raw reading to a temperature 6128c2ecf20Sopenharmony_ci * @data: device state 6138c2ecf20Sopenharmony_ci * 6148c2ecf20Sopenharmony_ci * As per section 4.3 of the data sheet. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_cistatic inline int sht15_calc_temp(struct sht15_data *data) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci int d1 = temppoints[0].d1; 6198c2ecf20Sopenharmony_ci int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10; 6208c2ecf20Sopenharmony_ci int i; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--) 6238c2ecf20Sopenharmony_ci /* Find pointer to interpolate */ 6248c2ecf20Sopenharmony_ci if (data->supply_uv > temppoints[i - 1].vdd) { 6258c2ecf20Sopenharmony_ci d1 = (data->supply_uv - temppoints[i - 1].vdd) 6268c2ecf20Sopenharmony_ci * (temppoints[i].d1 - temppoints[i - 1].d1) 6278c2ecf20Sopenharmony_ci / (temppoints[i].vdd - temppoints[i - 1].vdd) 6288c2ecf20Sopenharmony_ci + temppoints[i - 1].d1; 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return data->val_temp * d2 + d1; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/** 6368c2ecf20Sopenharmony_ci * sht15_calc_humid() - using last temperature convert raw to humid 6378c2ecf20Sopenharmony_ci * @data: device state 6388c2ecf20Sopenharmony_ci * 6398c2ecf20Sopenharmony_ci * This is the temperature compensated version as per section 4.2 of 6408c2ecf20Sopenharmony_ci * the data sheet. 6418c2ecf20Sopenharmony_ci * 6428c2ecf20Sopenharmony_ci * The sensor is assumed to be V3, which is compatible with V4. 6438c2ecf20Sopenharmony_ci * Humidity conversion coefficients are shown in table 7 of the datasheet. 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_cistatic inline int sht15_calc_humid(struct sht15_data *data) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci int rh_linear; /* milli percent */ 6488c2ecf20Sopenharmony_ci int temp = sht15_calc_temp(data); 6498c2ecf20Sopenharmony_ci int c2, c3; 6508c2ecf20Sopenharmony_ci int t2; 6518c2ecf20Sopenharmony_ci const int c1 = -4; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) { 6548c2ecf20Sopenharmony_ci c2 = 648000; /* x 10 ^ -6 */ 6558c2ecf20Sopenharmony_ci c3 = -7200; /* x 10 ^ -7 */ 6568c2ecf20Sopenharmony_ci t2 = 1280; 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci c2 = 40500; /* x 10 ^ -6 */ 6598c2ecf20Sopenharmony_ci c3 = -28; /* x 10 ^ -7 */ 6608c2ecf20Sopenharmony_ci t2 = 80; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci rh_linear = c1 * 1000 6648c2ecf20Sopenharmony_ci + c2 * data->val_humid / 1000 6658c2ecf20Sopenharmony_ci + (data->val_humid * data->val_humid * c3) / 10000; 6668c2ecf20Sopenharmony_ci return (temp - 25000) * (10000 + t2 * data->val_humid) 6678c2ecf20Sopenharmony_ci / 1000000 + rh_linear; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/** 6718c2ecf20Sopenharmony_ci * sht15_show_status() - show status information in sysfs 6728c2ecf20Sopenharmony_ci * @dev: device. 6738c2ecf20Sopenharmony_ci * @attr: device attribute. 6748c2ecf20Sopenharmony_ci * @buf: sysfs buffer where information is written to. 6758c2ecf20Sopenharmony_ci * 6768c2ecf20Sopenharmony_ci * Will be called on read access to temp1_fault, humidity1_fault 6778c2ecf20Sopenharmony_ci * and heater_enable sysfs attributes. 6788c2ecf20Sopenharmony_ci * Returns number of bytes written into buffer, negative errno on error. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_cistatic ssize_t sht15_status_show(struct device *dev, 6818c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci int ret; 6848c2ecf20Sopenharmony_ci struct sht15_data *data = dev_get_drvdata(dev); 6858c2ecf20Sopenharmony_ci u8 bit = to_sensor_dev_attr(attr)->index; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci ret = sht15_update_status(data); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit)); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/** 6938c2ecf20Sopenharmony_ci * sht15_store_heater() - change heater state via sysfs 6948c2ecf20Sopenharmony_ci * @dev: device. 6958c2ecf20Sopenharmony_ci * @attr: device attribute. 6968c2ecf20Sopenharmony_ci * @buf: sysfs buffer to read the new heater state from. 6978c2ecf20Sopenharmony_ci * @count: length of the data. 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * Will be called on write access to heater_enable sysfs attribute. 7008c2ecf20Sopenharmony_ci * Returns number of bytes actually decoded, negative errno on error. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_cistatic ssize_t sht15_status_store(struct device *dev, 7038c2ecf20Sopenharmony_ci struct device_attribute *attr, 7048c2ecf20Sopenharmony_ci const char *buf, size_t count) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci int ret; 7078c2ecf20Sopenharmony_ci struct sht15_data *data = dev_get_drvdata(dev); 7088c2ecf20Sopenharmony_ci long value; 7098c2ecf20Sopenharmony_ci u8 status; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &value)) 7128c2ecf20Sopenharmony_ci return -EINVAL; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci mutex_lock(&data->read_lock); 7158c2ecf20Sopenharmony_ci status = data->val_status & 0x07; 7168c2ecf20Sopenharmony_ci if (!!value) 7178c2ecf20Sopenharmony_ci status |= SHT15_STATUS_HEATER; 7188c2ecf20Sopenharmony_ci else 7198c2ecf20Sopenharmony_ci status &= ~SHT15_STATUS_HEATER; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ret = sht15_send_status(data, status); 7228c2ecf20Sopenharmony_ci mutex_unlock(&data->read_lock); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return ret ? ret : count; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci/** 7288c2ecf20Sopenharmony_ci * sht15_show_temp() - show temperature measurement value in sysfs 7298c2ecf20Sopenharmony_ci * @dev: device. 7308c2ecf20Sopenharmony_ci * @attr: device attribute. 7318c2ecf20Sopenharmony_ci * @buf: sysfs buffer where measurement values are written to. 7328c2ecf20Sopenharmony_ci * 7338c2ecf20Sopenharmony_ci * Will be called on read access to temp1_input sysfs attribute. 7348c2ecf20Sopenharmony_ci * Returns number of bytes written into buffer, negative errno on error. 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_cistatic ssize_t sht15_temp_show(struct device *dev, 7378c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci int ret; 7408c2ecf20Sopenharmony_ci struct sht15_data *data = dev_get_drvdata(dev); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Technically no need to read humidity as well */ 7438c2ecf20Sopenharmony_ci ret = sht15_update_measurements(data); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return ret ? ret : sprintf(buf, "%d\n", 7468c2ecf20Sopenharmony_ci sht15_calc_temp(data)); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci/** 7508c2ecf20Sopenharmony_ci * sht15_show_humidity() - show humidity measurement value in sysfs 7518c2ecf20Sopenharmony_ci * @dev: device. 7528c2ecf20Sopenharmony_ci * @attr: device attribute. 7538c2ecf20Sopenharmony_ci * @buf: sysfs buffer where measurement values are written to. 7548c2ecf20Sopenharmony_ci * 7558c2ecf20Sopenharmony_ci * Will be called on read access to humidity1_input sysfs attribute. 7568c2ecf20Sopenharmony_ci * Returns number of bytes written into buffer, negative errno on error. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_cistatic ssize_t sht15_humidity_show(struct device *dev, 7598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci int ret; 7628c2ecf20Sopenharmony_ci struct sht15_data *data = dev_get_drvdata(dev); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci ret = sht15_update_measurements(data); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data)); 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, 7708c2ecf20Sopenharmony_ci struct device_attribute *attr, 7718c2ecf20Sopenharmony_ci char *buf) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 7748c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", pdev->name); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, sht15_temp, 0); 7788c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(humidity1_input, sht15_humidity, 0); 7798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_fault, sht15_status, 7808c2ecf20Sopenharmony_ci SHT15_STATUS_LOW_BATTERY); 7818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(humidity1_fault, sht15_status, 7828c2ecf20Sopenharmony_ci SHT15_STATUS_LOW_BATTERY); 7838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(heater_enable, sht15_status, SHT15_STATUS_HEATER); 7848c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name); 7858c2ecf20Sopenharmony_cistatic struct attribute *sht15_attrs[] = { 7868c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 7878c2ecf20Sopenharmony_ci &sensor_dev_attr_humidity1_input.dev_attr.attr, 7888c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_fault.dev_attr.attr, 7898c2ecf20Sopenharmony_ci &sensor_dev_attr_humidity1_fault.dev_attr.attr, 7908c2ecf20Sopenharmony_ci &sensor_dev_attr_heater_enable.dev_attr.attr, 7918c2ecf20Sopenharmony_ci &dev_attr_name.attr, 7928c2ecf20Sopenharmony_ci NULL, 7938c2ecf20Sopenharmony_ci}; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic const struct attribute_group sht15_attr_group = { 7968c2ecf20Sopenharmony_ci .attrs = sht15_attrs, 7978c2ecf20Sopenharmony_ci}; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic irqreturn_t sht15_interrupt_fired(int irq, void *d) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct sht15_data *data = d; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* First disable the interrupt */ 8048c2ecf20Sopenharmony_ci disable_irq_nosync(irq); 8058c2ecf20Sopenharmony_ci atomic_inc(&data->interrupt_handled); 8068c2ecf20Sopenharmony_ci /* Then schedule a reading work struct */ 8078c2ecf20Sopenharmony_ci if (data->state != SHT15_READING_NOTHING) 8088c2ecf20Sopenharmony_ci schedule_work(&data->read_work); 8098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic void sht15_bh_read_data(struct work_struct *work_s) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci uint16_t val = 0; 8158c2ecf20Sopenharmony_ci u8 dev_checksum = 0; 8168c2ecf20Sopenharmony_ci u8 checksum_vals[3]; 8178c2ecf20Sopenharmony_ci struct sht15_data *data 8188c2ecf20Sopenharmony_ci = container_of(work_s, struct sht15_data, 8198c2ecf20Sopenharmony_ci read_work); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Firstly, verify the line is low */ 8228c2ecf20Sopenharmony_ci if (gpiod_get_value(data->data)) { 8238c2ecf20Sopenharmony_ci /* 8248c2ecf20Sopenharmony_ci * If not, then start the interrupt again - care here as could 8258c2ecf20Sopenharmony_ci * have gone low in meantime so verify it hasn't! 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci atomic_set(&data->interrupt_handled, 0); 8288c2ecf20Sopenharmony_ci enable_irq(gpiod_to_irq(data->data)); 8298c2ecf20Sopenharmony_ci /* If still not occurred or another handler was scheduled */ 8308c2ecf20Sopenharmony_ci if (gpiod_get_value(data->data) 8318c2ecf20Sopenharmony_ci || atomic_read(&data->interrupt_handled)) 8328c2ecf20Sopenharmony_ci return; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* Read the data back from the device */ 8368c2ecf20Sopenharmony_ci val = sht15_read_byte(data); 8378c2ecf20Sopenharmony_ci val <<= 8; 8388c2ecf20Sopenharmony_ci if (sht15_ack(data)) 8398c2ecf20Sopenharmony_ci goto wakeup; 8408c2ecf20Sopenharmony_ci val |= sht15_read_byte(data); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (data->checksumming) { 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * Ask the device for a checksum and read it back. 8458c2ecf20Sopenharmony_ci * Note: the device sends the checksum byte reversed. 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ci if (sht15_ack(data)) 8488c2ecf20Sopenharmony_ci goto wakeup; 8498c2ecf20Sopenharmony_ci dev_checksum = bitrev8(sht15_read_byte(data)); 8508c2ecf20Sopenharmony_ci checksum_vals[0] = (data->state == SHT15_READING_TEMP) ? 8518c2ecf20Sopenharmony_ci SHT15_MEASURE_TEMP : SHT15_MEASURE_RH; 8528c2ecf20Sopenharmony_ci checksum_vals[1] = (u8) (val >> 8); 8538c2ecf20Sopenharmony_ci checksum_vals[2] = (u8) val; 8548c2ecf20Sopenharmony_ci data->checksum_ok 8558c2ecf20Sopenharmony_ci = (sht15_crc8(data, checksum_vals, 3) == dev_checksum); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Tell the device we are done */ 8598c2ecf20Sopenharmony_ci if (sht15_end_transmission(data)) 8608c2ecf20Sopenharmony_ci goto wakeup; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci switch (data->state) { 8638c2ecf20Sopenharmony_ci case SHT15_READING_TEMP: 8648c2ecf20Sopenharmony_ci data->val_temp = val; 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci case SHT15_READING_HUMID: 8678c2ecf20Sopenharmony_ci data->val_humid = val; 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci default: 8708c2ecf20Sopenharmony_ci break; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci data->state = SHT15_READING_NOTHING; 8748c2ecf20Sopenharmony_ciwakeup: 8758c2ecf20Sopenharmony_ci wake_up(&data->wait_queue); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic void sht15_update_voltage(struct work_struct *work_s) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct sht15_data *data 8818c2ecf20Sopenharmony_ci = container_of(work_s, struct sht15_data, 8828c2ecf20Sopenharmony_ci update_supply_work); 8838c2ecf20Sopenharmony_ci data->supply_uv = regulator_get_voltage(data->reg); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/** 8878c2ecf20Sopenharmony_ci * sht15_invalidate_voltage() - mark supply voltage invalid when notified by reg 8888c2ecf20Sopenharmony_ci * @nb: associated notification structure 8898c2ecf20Sopenharmony_ci * @event: voltage regulator state change event code 8908c2ecf20Sopenharmony_ci * @ignored: function parameter - ignored here 8918c2ecf20Sopenharmony_ci * 8928c2ecf20Sopenharmony_ci * Note that as the notification code holds the regulator lock, we have 8938c2ecf20Sopenharmony_ci * to schedule an update of the supply voltage rather than getting it directly. 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_cistatic int sht15_invalidate_voltage(struct notifier_block *nb, 8968c2ecf20Sopenharmony_ci unsigned long event, 8978c2ecf20Sopenharmony_ci void *ignored) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct sht15_data *data = container_of(nb, struct sht15_data, nb); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (event == REGULATOR_EVENT_VOLTAGE_CHANGE) 9028c2ecf20Sopenharmony_ci data->supply_uv_valid = false; 9038c2ecf20Sopenharmony_ci schedule_work(&data->update_supply_work); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return NOTIFY_OK; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 9098c2ecf20Sopenharmony_cistatic const struct of_device_id sht15_dt_match[] = { 9108c2ecf20Sopenharmony_ci { .compatible = "sensirion,sht15" }, 9118c2ecf20Sopenharmony_ci { }, 9128c2ecf20Sopenharmony_ci}; 9138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sht15_dt_match); 9148c2ecf20Sopenharmony_ci#endif 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int sht15_probe(struct platform_device *pdev) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci int ret; 9198c2ecf20Sopenharmony_ci struct sht15_data *data; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 9228c2ecf20Sopenharmony_ci if (!data) 9238c2ecf20Sopenharmony_ci return -ENOMEM; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci INIT_WORK(&data->read_work, sht15_bh_read_data); 9268c2ecf20Sopenharmony_ci INIT_WORK(&data->update_supply_work, sht15_update_voltage); 9278c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 9288c2ecf20Sopenharmony_ci mutex_init(&data->read_lock); 9298c2ecf20Sopenharmony_ci data->dev = &pdev->dev; 9308c2ecf20Sopenharmony_ci init_waitqueue_head(&data->wait_queue); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* 9338c2ecf20Sopenharmony_ci * If a regulator is available, 9348c2ecf20Sopenharmony_ci * query what the supply voltage actually is! 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci data->reg = devm_regulator_get_optional(data->dev, "vcc"); 9378c2ecf20Sopenharmony_ci if (!IS_ERR(data->reg)) { 9388c2ecf20Sopenharmony_ci int voltage; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci voltage = regulator_get_voltage(data->reg); 9418c2ecf20Sopenharmony_ci if (voltage) 9428c2ecf20Sopenharmony_ci data->supply_uv = voltage; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci ret = regulator_enable(data->reg); 9458c2ecf20Sopenharmony_ci if (ret != 0) { 9468c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 9478c2ecf20Sopenharmony_ci "failed to enable regulator: %d\n", ret); 9488c2ecf20Sopenharmony_ci return ret; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* 9528c2ecf20Sopenharmony_ci * Setup a notifier block to update this if another device 9538c2ecf20Sopenharmony_ci * causes the voltage to change 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_ci data->nb.notifier_call = &sht15_invalidate_voltage; 9568c2ecf20Sopenharmony_ci ret = regulator_register_notifier(data->reg, &data->nb); 9578c2ecf20Sopenharmony_ci if (ret) { 9588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 9598c2ecf20Sopenharmony_ci "regulator notifier request failed\n"); 9608c2ecf20Sopenharmony_ci regulator_disable(data->reg); 9618c2ecf20Sopenharmony_ci return ret; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* Try requesting the GPIOs */ 9668c2ecf20Sopenharmony_ci data->sck = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_LOW); 9678c2ecf20Sopenharmony_ci if (IS_ERR(data->sck)) { 9688c2ecf20Sopenharmony_ci ret = PTR_ERR(data->sck); 9698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "clock line GPIO request failed\n"); 9708c2ecf20Sopenharmony_ci goto err_release_reg; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci data->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN); 9738c2ecf20Sopenharmony_ci if (IS_ERR(data->data)) { 9748c2ecf20Sopenharmony_ci ret = PTR_ERR(data->data); 9758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "data line GPIO request failed\n"); 9768c2ecf20Sopenharmony_ci goto err_release_reg; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data), 9808c2ecf20Sopenharmony_ci sht15_interrupt_fired, 9818c2ecf20Sopenharmony_ci IRQF_TRIGGER_FALLING, 9828c2ecf20Sopenharmony_ci "sht15 data", 9838c2ecf20Sopenharmony_ci data); 9848c2ecf20Sopenharmony_ci if (ret) { 9858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get irq for data line\n"); 9868c2ecf20Sopenharmony_ci goto err_release_reg; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci disable_irq_nosync(gpiod_to_irq(data->data)); 9898c2ecf20Sopenharmony_ci ret = sht15_connection_reset(data); 9908c2ecf20Sopenharmony_ci if (ret) 9918c2ecf20Sopenharmony_ci goto err_release_reg; 9928c2ecf20Sopenharmony_ci ret = sht15_soft_reset(data); 9938c2ecf20Sopenharmony_ci if (ret) 9948c2ecf20Sopenharmony_ci goto err_release_reg; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group); 9978c2ecf20Sopenharmony_ci if (ret) { 9988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "sysfs create failed\n"); 9998c2ecf20Sopenharmony_ci goto err_release_reg; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci data->hwmon_dev = hwmon_device_register(data->dev); 10038c2ecf20Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 10048c2ecf20Sopenharmony_ci ret = PTR_ERR(data->hwmon_dev); 10058c2ecf20Sopenharmony_ci goto err_release_sysfs_group; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci return 0; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cierr_release_sysfs_group: 10118c2ecf20Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group); 10128c2ecf20Sopenharmony_cierr_release_reg: 10138c2ecf20Sopenharmony_ci if (!IS_ERR(data->reg)) { 10148c2ecf20Sopenharmony_ci regulator_unregister_notifier(data->reg, &data->nb); 10158c2ecf20Sopenharmony_ci regulator_disable(data->reg); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci return ret; 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic int sht15_remove(struct platform_device *pdev) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct sht15_data *data = platform_get_drvdata(pdev); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* 10258c2ecf20Sopenharmony_ci * Make sure any reads from the device are done and 10268c2ecf20Sopenharmony_ci * prevent new ones beginning 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ci mutex_lock(&data->read_lock); 10298c2ecf20Sopenharmony_ci if (sht15_soft_reset(data)) { 10308c2ecf20Sopenharmony_ci mutex_unlock(&data->read_lock); 10318c2ecf20Sopenharmony_ci return -EFAULT; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 10348c2ecf20Sopenharmony_ci sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group); 10358c2ecf20Sopenharmony_ci if (!IS_ERR(data->reg)) { 10368c2ecf20Sopenharmony_ci regulator_unregister_notifier(data->reg, &data->nb); 10378c2ecf20Sopenharmony_ci regulator_disable(data->reg); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci mutex_unlock(&data->read_lock); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic const struct platform_device_id sht15_device_ids[] = { 10468c2ecf20Sopenharmony_ci { "sht10", sht10 }, 10478c2ecf20Sopenharmony_ci { "sht11", sht11 }, 10488c2ecf20Sopenharmony_ci { "sht15", sht15 }, 10498c2ecf20Sopenharmony_ci { "sht71", sht71 }, 10508c2ecf20Sopenharmony_ci { "sht75", sht75 }, 10518c2ecf20Sopenharmony_ci { } 10528c2ecf20Sopenharmony_ci}; 10538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sht15_device_ids); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic struct platform_driver sht15_driver = { 10568c2ecf20Sopenharmony_ci .driver = { 10578c2ecf20Sopenharmony_ci .name = "sht15", 10588c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sht15_dt_match), 10598c2ecf20Sopenharmony_ci }, 10608c2ecf20Sopenharmony_ci .probe = sht15_probe, 10618c2ecf20Sopenharmony_ci .remove = sht15_remove, 10628c2ecf20Sopenharmony_ci .id_table = sht15_device_ids, 10638c2ecf20Sopenharmony_ci}; 10648c2ecf20Sopenharmony_cimodule_platform_driver(sht15_driver); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 10678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sensirion SHT15 temperature and humidity sensor driver"); 1068