diff mbox

[v2] hwmon: (sht21) Add Electronic Identification Code retrieval

Message ID 1482103139-12127-1-git-send-email-pab@pabigot.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Peter A. Bigot Dec. 18, 2016, 11:18 p.m. UTC
Expose the per-chip unique identifier so it can be used to identify the
sensor producing the measurements.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
---
v2: Remove unnecessary copyright/authorship claims.
    Define symbolic names for serial number read commands.
    Provide separate function to read EIC.
    Rearrange device data structure slightly to reduce alignment padding.
    Store EIC in ASCII form and mark validity using non-NUL character.
    Use hard-coded lengths and avoid redundant assignments.
    Change attribute name.

 Documentation/hwmon/sht21 |  5 +--
 drivers/hwmon/sht21.c     | 92 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 93 insertions(+), 4 deletions(-)

Comments

Guenter Roeck Dec. 23, 2016, 2:01 a.m. UTC | #1
On 12/18/2016 03:18 PM, Peter A. Bigot wrote:
> Expose the per-chip unique identifier so it can be used to identify the
> sensor producing the measurements.
>
> Signed-off-by: Peter A. Bigot <pab@pabigot.com>
> ---
> v2: Remove unnecessary copyright/authorship claims.
>     Define symbolic names for serial number read commands.
>     Provide separate function to read EIC.
>     Rearrange device data structure slightly to reduce alignment padding.
>     Store EIC in ASCII form and mark validity using non-NUL character.
>     Use hard-coded lengths and avoid redundant assignments.
>     Change attribute name.
>
>  Documentation/hwmon/sht21 |  5 +--
>  drivers/hwmon/sht21.c     | 92 +++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 93 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21
> index db17fda..47f4765 100644
> --- a/Documentation/hwmon/sht21
> +++ b/Documentation/hwmon/sht21
> @@ -35,6 +35,7 @@ sysfs-Interface
>
>  temp1_input - temperature input
>  humidity1_input - humidity input
> +eic - Electronic Identification Code
>
>  Notes
>  -----
> @@ -45,5 +46,5 @@ humidity and 66 ms for temperature. To keep self heating below 0.1 degree
>  Celsius, the device should not be active for more than 10% of the time,
>  e.g. maximum two measurements per second at the given resolution.
>
> -Different resolutions, the on-chip heater, using the CRC checksum and reading
> -the serial number are not supported yet.
> +Different resolutions, the on-chip heater, and using the CRC checksum
> +are not supported yet.
> diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
> index 84cdb1c..00648e4 100644
> --- a/drivers/hwmon/sht21.c
> +++ b/drivers/hwmon/sht21.c
> @@ -34,23 +34,29 @@
>  /* I2C command bytes */
>  #define SHT21_TRIG_T_MEASUREMENT_HM  0xe3
>  #define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
> +#define SHT21_READ_SNB_CMD1 0xFA
> +#define SHT21_READ_SNB_CMD2 0x0F
> +#define SHT21_READ_SNAC_CMD1 0xFC
> +#define SHT21_READ_SNAC_CMD2 0xC9
>
>  /**
>   * struct sht21 - SHT21 device specific data
>   * @hwmon_dev: device registered with hwmon
>   * @lock: mutex to protect measurement values
> - * @valid: only 0 before first measurement is taken
>   * @last_update: time of last update (jiffies)
>   * @temperature: cached temperature measurement value
>   * @humidity: cached humidity measurement value
> + * @valid: only 0 before first measurement is taken
> + * @eic: cached electronic identification code text
>   */
>  struct sht21 {
>  	struct i2c_client *client;
>  	struct mutex lock;
> -	char valid;
>  	unsigned long last_update;
>  	int temperature;
>  	int humidity;
> +	char valid;
> +	char eic[18];
>  };
>
>  /**
> @@ -165,15 +171,97 @@ static ssize_t sht21_show_humidity(struct device *dev,
>  	return sprintf(buf, "%d\n", sht21->humidity);
>  }
>
> +static ssize_t eic_read(struct sht21 *sht21)
> +{
> +	struct i2c_client *client = sht21->client;
> +	u8 tx[2];
> +	u8 rx[8];
> +	u8 eic[8];
> +	struct i2c_msg msgs[2] = {
> +		{
> +			.addr = client->addr,
> +			.flags = 0,
> +			.len = 2,
> +			.buf = tx,
> +		},
> +		{
> +			.addr = client->addr,
> +			.flags = I2C_M_RD,
> +			.len = 8,
> +			.buf = rx,
> +		},
> +	};
> +	int ret;
> +
> +	tx[0] = SHT21_READ_SNB_CMD1;
> +	tx[1] = SHT21_READ_SNB_CMD2;
> +	ret = i2c_transfer(client->adapter, msgs, 2);
> +	if (ret < 0)
> +		goto out;
> +	eic[2] = rx[0];
> +	eic[3] = rx[2];
> +	eic[4] = rx[4];
> +	eic[5] = rx[6];
> +
> +	tx[0] = SHT21_READ_SNAC_CMD1;
> +	tx[1] = SHT21_READ_SNAC_CMD2;
> +	msgs[1].len = 6;
> +	ret = i2c_transfer(client->adapter, msgs, 2);
> +	if (ret < 0)
> +		goto out;
> +	eic[0] = rx[3];
> +	eic[1] = rx[4];
> +	eic[6] = rx[0];
> +	eic[7] = rx[1];
> +
> +	ret = snprintf(sht21->eic, sizeof(sht21->eic),
> +		       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
> +		       eic[0], eic[1], eic[2], eic[3],
> +		       eic[4], eic[5], eic[6], eic[7]);
> +out:
> +	if (ret < 0)
> +		sht21->eic[0] = 0;
> +
> +	return ret;
> +}
> +
> +/**
> + * sht21_show_eic() - show Electronic Identification Code in sysfs
> + * @dev: device
> + * @attr: device attribute
> + * @buf: sysfs buffer (PAGE_SIZE) where EIC is written
> + *
> + * Will be called on read access to eic sysfs attribute.
> + * Returns number of bytes written into buffer, negative errno on error.
> + */
> +static ssize_t sht21_show_eic(struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct sht21 *sht21 = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = sizeof(sht21->eic) - 1;
> +	mutex_lock(&sht21->lock);
> +	if (!sht21->eic[0])
> +		ret = eic_read(sht21);
> +	if (ret > 0)
> +		memcpy(buf, sht21->eic, ret);
> +	mutex_unlock(&sht21->lock);
> +	return ret;
> +}
> +
>  /* sysfs attributes */
>  static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
>  	NULL, 0);
>  static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
>  	NULL, 0);
> +static SENSOR_DEVICE_ATTR(eic, 0444, sht21_show_eic, NULL, 0);
>

Actually, you should use DEVICE_ATTR_RO() here (that requires the function
to be renamed to eic_show).

[ Sorry, I didn't realize that earlier ]

Thanks,
Guenter

>  static struct attribute *sht21_attrs[] = {
>  	&sensor_dev_attr_temp1_input.dev_attr.attr,
>  	&sensor_dev_attr_humidity1_input.dev_attr.attr,
> +	&sensor_dev_attr_eic.dev_attr.attr,
>  	NULL
>  };
>
>

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21
index db17fda..47f4765 100644
--- a/Documentation/hwmon/sht21
+++ b/Documentation/hwmon/sht21
@@ -35,6 +35,7 @@  sysfs-Interface
 
 temp1_input - temperature input
 humidity1_input - humidity input
+eic - Electronic Identification Code
 
 Notes
 -----
@@ -45,5 +46,5 @@  humidity and 66 ms for temperature. To keep self heating below 0.1 degree
 Celsius, the device should not be active for more than 10% of the time,
 e.g. maximum two measurements per second at the given resolution.
 
-Different resolutions, the on-chip heater, using the CRC checksum and reading
-the serial number are not supported yet.
+Different resolutions, the on-chip heater, and using the CRC checksum
+are not supported yet.
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
index 84cdb1c..00648e4 100644
--- a/drivers/hwmon/sht21.c
+++ b/drivers/hwmon/sht21.c
@@ -34,23 +34,29 @@ 
 /* I2C command bytes */
 #define SHT21_TRIG_T_MEASUREMENT_HM  0xe3
 #define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
+#define SHT21_READ_SNB_CMD1 0xFA
+#define SHT21_READ_SNB_CMD2 0x0F
+#define SHT21_READ_SNAC_CMD1 0xFC
+#define SHT21_READ_SNAC_CMD2 0xC9
 
 /**
  * struct sht21 - SHT21 device specific data
  * @hwmon_dev: device registered with hwmon
  * @lock: mutex to protect measurement values
- * @valid: only 0 before first measurement is taken
  * @last_update: time of last update (jiffies)
  * @temperature: cached temperature measurement value
  * @humidity: cached humidity measurement value
+ * @valid: only 0 before first measurement is taken
+ * @eic: cached electronic identification code text
  */
 struct sht21 {
 	struct i2c_client *client;
 	struct mutex lock;
-	char valid;
 	unsigned long last_update;
 	int temperature;
 	int humidity;
+	char valid;
+	char eic[18];
 };
 
 /**
@@ -165,15 +171,97 @@  static ssize_t sht21_show_humidity(struct device *dev,
 	return sprintf(buf, "%d\n", sht21->humidity);
 }
 
+static ssize_t eic_read(struct sht21 *sht21)
+{
+	struct i2c_client *client = sht21->client;
+	u8 tx[2];
+	u8 rx[8];
+	u8 eic[8];
+	struct i2c_msg msgs[2] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 2,
+			.buf = tx,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = 8,
+			.buf = rx,
+		},
+	};
+	int ret;
+
+	tx[0] = SHT21_READ_SNB_CMD1;
+	tx[1] = SHT21_READ_SNB_CMD2;
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret < 0)
+		goto out;
+	eic[2] = rx[0];
+	eic[3] = rx[2];
+	eic[4] = rx[4];
+	eic[5] = rx[6];
+
+	tx[0] = SHT21_READ_SNAC_CMD1;
+	tx[1] = SHT21_READ_SNAC_CMD2;
+	msgs[1].len = 6;
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret < 0)
+		goto out;
+	eic[0] = rx[3];
+	eic[1] = rx[4];
+	eic[6] = rx[0];
+	eic[7] = rx[1];
+
+	ret = snprintf(sht21->eic, sizeof(sht21->eic),
+		       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+		       eic[0], eic[1], eic[2], eic[3],
+		       eic[4], eic[5], eic[6], eic[7]);
+out:
+	if (ret < 0)
+		sht21->eic[0] = 0;
+
+	return ret;
+}
+
+/**
+ * sht21_show_eic() - show Electronic Identification Code in sysfs
+ * @dev: device
+ * @attr: device attribute
+ * @buf: sysfs buffer (PAGE_SIZE) where EIC is written
+ *
+ * Will be called on read access to eic sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht21_show_eic(struct device *dev,
+	struct device_attribute *attr,
+	char *buf)
+{
+	struct sht21 *sht21 = dev_get_drvdata(dev);
+	int ret;
+
+	ret = sizeof(sht21->eic) - 1;
+	mutex_lock(&sht21->lock);
+	if (!sht21->eic[0])
+		ret = eic_read(sht21);
+	if (ret > 0)
+		memcpy(buf, sht21->eic, ret);
+	mutex_unlock(&sht21->lock);
+	return ret;
+}
+
 /* sysfs attributes */
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
 	NULL, 0);
 static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
 	NULL, 0);
+static SENSOR_DEVICE_ATTR(eic, 0444, sht21_show_eic, NULL, 0);
 
 static struct attribute *sht21_attrs[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	&sensor_dev_attr_eic.dev_attr.attr,
 	NULL
 };