Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: (sht3x) read out sensor serial number

The temperature/humidity sensors of the STS3x/SHT3x family are
calibrated and factory-programmed with a unique serial number.
For some sensors, this serial number can be used to obtain a calibration
certificate via an API provided by the manufacturer (Sensirion).
Expose the serial number via debugfs.

Tested with: 2x STS31, 1x STS32, 1x SHT31

Signed-off-by: Stefan Gloor <code@stefan-gloor.ch>
Link: https://lore.kernel.org/r/20240131111512.25321-2-code@stefan-gloor.ch
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Stefan Gloor and committed by
Guenter Roeck
9d613d9b f20b4a93

+76 -1
+11
Documentation/hwmon/sht3x.rst
··· 65 65 values, the alert bit is set to 0 and the alert pin on the sensor is set to 66 66 low. 67 67 68 + The serial number exposed to debugfs allows for unique identification of the 69 + sensors. For sts32, sts33 and sht33, the manufacturer provides calibration 70 + certificates through an API. 71 + 68 72 sysfs-Interface 69 73 --------------- 70 74 ··· 102 98 - 0: low repeatability 103 99 - 1: medium repeatability 104 100 - 2: high repeatability 101 + =================== ============================================================ 102 + 103 + debugfs-Interface 104 + ----------------- 105 + 106 + =================== ============================================================ 107 + serial_number: unique serial number of the sensor in decimal 105 108 =================== ============================================================
+65 -1
drivers/hwmon/sht3x.c
··· 10 10 11 11 #include <asm/page.h> 12 12 #include <linux/crc8.h> 13 + #include <linux/debugfs.h> 13 14 #include <linux/delay.h> 14 15 #include <linux/err.h> 15 16 #include <linux/hwmon.h> ··· 42 41 /* other commands */ 43 42 static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; 44 43 static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; 44 + static const unsigned char sht3x_cmd_read_serial_number[] = { 0x37, 0x80 }; 45 + 46 + static struct dentry *debugfs; 45 47 46 48 /* delays for single-shot mode i2c commands, both in us */ 47 49 #define SHT3X_SINGLE_WAIT_TIME_HPM 15000 ··· 167 163 enum sht3x_chips chip_id; 168 164 struct mutex i2c_lock; /* lock for sending i2c commands */ 169 165 struct mutex data_lock; /* lock for updating driver data */ 166 + struct dentry *sensor_dir; 170 167 171 168 u8 mode; 172 169 const unsigned char *command; 173 170 u32 wait_time; /* in us*/ 174 171 unsigned long last_update; /* last update in periodic mode*/ 175 172 enum sht3x_repeatability repeatability; 173 + u32 serial_number; 176 174 177 175 /* 178 176 * cached values for temperature and humidity and limits ··· 837 831 } 838 832 } 839 833 834 + static void sht3x_debugfs_init(struct sht3x_data *data) 835 + { 836 + char name[32]; 837 + 838 + snprintf(name, sizeof(name), "i2c%u-%02x", 839 + data->client->adapter->nr, data->client->addr); 840 + data->sensor_dir = debugfs_create_dir(name, debugfs); 841 + debugfs_create_u32("serial_number", 0444, 842 + data->sensor_dir, &data->serial_number); 843 + } 844 + 845 + static void sht3x_debugfs_remove(void *sensor_dir) 846 + { 847 + debugfs_remove_recursive(sensor_dir); 848 + } 849 + 850 + static int sht3x_serial_number_read(struct sht3x_data *data) 851 + { 852 + int ret; 853 + char buffer[SHT3X_RESPONSE_LENGTH]; 854 + struct i2c_client *client = data->client; 855 + 856 + ret = sht3x_read_from_command(client, data, 857 + sht3x_cmd_read_serial_number, 858 + buffer, 859 + SHT3X_RESPONSE_LENGTH, 0); 860 + if (ret) 861 + return ret; 862 + 863 + data->serial_number = (buffer[0] << 24) | (buffer[1] << 16) | 864 + (buffer[3] << 8) | buffer[4]; 865 + return ret; 866 + } 867 + 840 868 static const struct hwmon_ops sht3x_ops = { 841 869 .is_visible = sht3x_is_visible, 842 870 .read = sht3x_read, ··· 939 899 if (ret) 940 900 return ret; 941 901 902 + ret = sht3x_serial_number_read(data); 903 + if (ret) { 904 + dev_dbg(dev, "unable to read serial number\n"); 905 + } else { 906 + sht3x_debugfs_init(data); 907 + ret = devm_add_action_or_reset(dev, 908 + sht3x_debugfs_remove, 909 + data->sensor_dir); 910 + if (ret) 911 + return ret; 912 + } 913 + 942 914 hwmon_dev = devm_hwmon_device_register_with_info(dev, 943 915 client->name, 944 916 data, ··· 969 917 .id_table = sht3x_ids, 970 918 }; 971 919 972 - module_i2c_driver(sht3x_i2c_driver); 920 + static int __init sht3x_init(void) 921 + { 922 + debugfs = debugfs_create_dir("sht3x", NULL); 923 + return i2c_add_driver(&sht3x_i2c_driver); 924 + } 925 + module_init(sht3x_init); 926 + 927 + static void __exit sht3x_cleanup(void) 928 + { 929 + debugfs_remove_recursive(debugfs); 930 + i2c_del_driver(&sht3x_i2c_driver); 931 + } 932 + module_exit(sht3x_cleanup); 973 933 974 934 MODULE_AUTHOR("David Frey <david.frey@sensirion.com>"); 975 935 MODULE_AUTHOR("Pascal Sachs <pascal.sachs@sensirion.com>");