All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development
@ 2015-07-30  9:25 Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 1/6] iio: Add meas-spec sensors common part Ludovic Tancerel
                   ` (5 more replies)
  0 siblings, 6 replies; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

This is the resubmission of patches for measurement specialties drivers.
The format of patchset has been moved into several incremental patches as requested, plus the other feedback.
The list of changes are :
        - Split into multiple patches
        - the split of MS8607 into 2 drivers based on htu21 ans ms5637
        - Alignment of units for processed channels
        - Documentation of private ABI
        - kernel-doc for exported functions
        - Other minor changes from feedback

Please have a look,
and thanks a lot for your feedback.

Regards,
Ludovic

revision history
----------------
v2      Split ms8607/Align units/Document private ABI/ kernel-doc ABI
v1      initial post

Ludovic Tancerel (6):
  Add iio: meas-spec sensors common part
  Add iio: tsys01 meas-spec driver support
  Add iio: tsys02d meas-spec driver support
  Add iio: htu21 meas-spec driver support
  Add iio: ms5637 meas-spec driver support
  Add iio: ms8607 meas-spec driver support

 Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  15 +
 drivers/iio/common/Kconfig                        |   1 +
 drivers/iio/common/Makefile                       |   1 +
 drivers/iio/common/ms_sensors/Kconfig             |   6 +
 drivers/iio/common/ms_sensors/Makefile            |   5 +
 drivers/iio/common/ms_sensors/ms_sensors_i2c.c    | 634 ++++++++++++++++++++++
 drivers/iio/common/ms_sensors/ms_sensors_i2c.h    |  54 ++
 drivers/iio/humidity/Kconfig                      |  11 +
 drivers/iio/humidity/Makefile                     |   1 +
 drivers/iio/humidity/htu21.c                      | 254 +++++++++
 drivers/iio/pressure/Kconfig                      |  28 +-
 drivers/iio/pressure/Makefile                     |   1 +
 drivers/iio/pressure/ms5637.c                     | 192 +++++++
 drivers/iio/temperature/Kconfig                   |  22 +
 drivers/iio/temperature/Makefile                  |   2 +
 drivers/iio/temperature/tsys01.c                  | 232 ++++++++
 drivers/iio/temperature/tsys02d.c                 | 193 +++++++
 17 files changed, 1650 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-meas-spec
 create mode 100644 drivers/iio/common/ms_sensors/Kconfig
 create mode 100644 drivers/iio/common/ms_sensors/Makefile
 create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
 create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
 create mode 100644 drivers/iio/humidity/htu21.c
 create mode 100644 drivers/iio/pressure/ms5637.c
 create mode 100644 drivers/iio/temperature/tsys01.c
 create mode 100644 drivers/iio/temperature/tsys02d.c

-- 
2.3.7


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-08-08 16:58   ` Jonathan Cameron
  2015-07-30  9:25 ` [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support Ludovic Tancerel
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 drivers/iio/common/Kconfig                     |   1 +
 drivers/iio/common/Makefile                    |   1 +
 drivers/iio/common/ms_sensors/Kconfig          |   6 +
 drivers/iio/common/ms_sensors/Makefile         |   5 +
 drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
 drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
 6 files changed, 701 insertions(+)
 create mode 100644 drivers/iio/common/ms_sensors/Kconfig
 create mode 100644 drivers/iio/common/ms_sensors/Makefile
 create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
 create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h

diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 790f106..26a6026 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,5 +3,6 @@
 #
 
 source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/ms_sensors/Kconfig"
 source "drivers/iio/common/ssp_sensors/Kconfig"
 source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index b1e4d9c..585da6a 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,5 +8,6 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-y += hid-sensors/
+obj-y += ms_sensors/
 obj-y += ssp_sensors/
 obj-y += st_sensors/
diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
new file mode 100644
index 0000000..b28a92b
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Kconfig
@@ -0,0 +1,6 @@
+#
+# Measurements Specialties sensors common library
+#
+
+config IIO_MS_SENSORS_I2C
+        tristate
diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
new file mode 100644
index 0000000..7846428
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Measurement Specialties sensor common modules.
+#
+
+obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
new file mode 100644
index 0000000..f5d27b6
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -0,0 +1,634 @@
+/*
+ * Measurements Specialties driver common i2c functions
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include "ms_sensors_i2c.h"
+
+/* Conversion times in us */
+static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
+						       13000, 7000 };
+static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
+						       5000, 8000 };
+static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
+						     4100, 8220, 16440 };
+
+#define MS_SENSORS_SERIAL_READ_MSB		0xFA0F
+#define MS_SENSORS_SERIAL_READ_LSB		0xFCC9
+#define MS_SENSORS_USER_REG_WRITE		0xE6
+#define MS_SENSORS_USER_REG_READ		0xE7
+#define MS_SENSORS_HT_T_CONVERSION_START	0xF3
+#define MS_SENSORS_HT_H_CONVERSION_START	0xF5
+
+#define MS_SENSORS_TP_PROM_READ			0xA0
+#define MS_SENSORS_TP_T_CONVERSION_START	0x50
+#define MS_SENSORS_TP_P_CONVERSION_START	0x40
+#define MS_SENSORS_TP_ADC_READ			0x00
+
+#define MS_SENSORS_NO_READ_CMD			0xFF
+
+/**
+ * ms_sensors_i2c_reset() - i2c reset function
+ * @cli:	pointer on i2c client
+ * @cmd:	reset cmd. Depends on device in use
+ * @delay:	usleep minimal delay after reset command is issued
+ *
+ * Generic I2C reset function for Measurement Specialties devices
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay)
+{
+	int ret;
+	struct i2c_client *client = cli;
+
+	ret = i2c_smbus_write_byte(client, cmd);
+	if (ret) {
+		dev_err(&client->dev, "Failed to reset device\n");
+		return ret;
+	}
+	usleep_range(delay, delay + 1000);
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_reset);
+
+/**
+ * ms_sensors_i2c_read_prom_word() - i2c prom word read function
+ * @cli:	pointer on i2c client
+ * @cmd:	PROM read cmd. Depends on device and prom id
+ * @word:	pointer on word destination value
+ *
+ * Generic i2c prom word read function for Measurement Specialties devices
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word)
+{
+	int ret;
+	struct i2c_client *client = (struct i2c_client *)cli;
+
+	ret = i2c_smbus_read_word_swapped(client, cmd);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read prom word\n");
+		return ret;
+	}
+	*word = ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_read_prom_word);
+
+/**
+ * ms_sensors_i2c_convert_and_read() - i2c ADC conversion & read function
+ * @cli:	pointer on i2c client
+ * @conv:	ADC conversion command. Depends on device in use
+ * @rd:		ADC read command. Depends on device in use
+ * @delay:	usleep minimal delay after conversion command is issued
+ * @adc:	pointer on ADC destination value
+ *
+ * Generic i2c ADC conversion & read function for Measurement Specialties
+ * devices.
+ * The function will issue conversion command, sleep appopriate delay, and
+ * issue command to read ADC
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
+				    unsigned int delay, u32 *adc)
+{
+	int ret;
+	u32 buf = 0;
+	struct i2c_client *client = (struct i2c_client *)cli;
+
+	/* Trigger conversion */
+	ret = i2c_smbus_write_byte(client, conv);
+	if (ret)
+		goto err;
+	usleep_range(delay, delay + 1000);
+
+	/* Retrieve ADC value */
+	if (rd != MS_SENSORS_NO_READ_CMD)
+		ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
+	else
+		ret = i2c_master_recv(client, (u8 *)&buf, 3);
+	if (ret < 0)
+		goto err;
+
+	dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
+	*adc = be32_to_cpu(buf) >> 8;
+
+	return 0;
+err:
+	dev_err(&client->dev, "Unable to make sensor adc conversion\n");
+	return ret;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_convert_and_read);
+
+/**
+ * ms_sensors_crc_valid() - CRC check function
+ * @value:	input and CRC compare value
+ *
+ * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
+ * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
+ * The argument contains CRC value in LSB byte while the bytes 1 and 2
+ * are used for CRC computation
+ *
+ * Return: 1 if CRC is valid, 0 otherwise.
+ */
+static bool ms_sensors_crc_valid(u32 value)
+{
+	u32 polynom = 0x988000;	/* x^8 + x^5 + x^4 + 1 */
+	u32 msb = 0x800000;
+	u32 mask = 0xFF8000;
+	u32 result = value & 0xFFFF00;
+	u8 crc = value & 0xFF;
+
+	while (msb != 0x80) {
+		if (result & msb)
+			result = ((result ^ polynom) & mask)
+				| (result & ~mask);
+		msb >>= 1;
+		mask >>= 1;
+		polynom >>= 1;
+	}
+
+	return result == crc;
+}
+
+/**
+ * ms_sensors_i2c_read_serial() - i2c serial number read function
+ * @cli:	pointer on i2c client
+ * @sn:		pointer on 64-bits destination value
+ *
+ * Generic i2c serial number read function for Measurement Specialties devices.
+ * This function is used for TSYS02d, HTU21, MS8607 chipset.
+ * Refer to datasheet:
+ *	http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
+{
+	u8 i;
+	u64 rcv_buf = 0;
+	u16 send_buf;
+	int ret;
+
+	struct i2c_msg msg[2] = {
+		{
+		 .addr = client->addr,
+		 .flags = client->flags,
+		 .len = 2,
+		 .buf = (char *)&send_buf,
+		 },
+		{
+		 .addr = client->addr,
+		 .flags = client->flags | I2C_M_RD,
+		 .buf = (char *)&rcv_buf,
+		 },
+	};
+
+	/* Read MSB part of serial number */
+	send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
+	msg[1].len = 8;
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		goto err;
+
+	rcv_buf = be64_to_cpu(rcv_buf);
+	dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
+
+	for (i = 0; i < 64; i += 16) {
+		if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
+			return -ENODEV;
+	}
+
+	*sn = (((rcv_buf >> 32) & 0xFF000000) |
+	       ((rcv_buf >> 24) & 0x00FF0000) |
+	       ((rcv_buf >> 16) & 0x0000FF00) |
+	       ((rcv_buf >> 8) & 0x000000FF)) << 16;
+
+	/* Read LSB part of serial number */
+	send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
+	msg[1].len = 6;
+	rcv_buf = 0;
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		goto err;
+
+	rcv_buf = be64_to_cpu(rcv_buf) >> 16;
+	dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
+
+	for (i = 0; i < 48; i += 24) {
+		if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
+			return -ENODEV;
+	}
+
+	*sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
+
+	return 0;
+
+err:
+	dev_err(&client->dev, "Unable to read device serial number");
+	return ret;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
+
+static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
+					u8 *user_reg)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
+	if (ret)
+		goto err;
+
+	ret = i2c_master_recv(client, user_reg, 1);
+	if (ret < 0)
+		goto err;
+	dev_dbg(&client->dev, "User register :%x\n", *user_reg);
+
+	return 0;
+err:
+	dev_err(&client->dev, "Unable to read user reg");
+	return ret;
+}
+
+/**
+ * ms_sensors_i2c_write_resolution() - set resolution i2c function
+ * @dev_data:	pointer on temperature/humidity device data
+ * @i:		resolution index to set
+ *
+ * That function will program the appropriate resolution based on the index
+ * provided when user space will set samp_freq channel.
+ * That function is used for TSYS02D, HTU21 and MS8607 chipsets
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
+					u8 i)
+{
+	u8 user_reg;
+	int ret;
+
+	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
+	if (ret)
+		return ret;
+
+	user_reg &= 0x7E;
+	user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
+
+	return i2c_smbus_write_byte_data(dev_data->client,
+					 MS_SENSORS_USER_REG_WRITE,
+					 user_reg);
+}
+EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
+
+/**
+ * ms_sensors_i2c_show_battery_low() - show device battery low indicator
+ * @dev_data:	pointer on temperature/humidity device data
+ * @buf:	pointer on char buffer to write result
+ *
+ * That function will read battery indicator value in the device and
+ * return 1 if the device voltage is below 2.25V.
+ * That function is used for TSYS02D, HTU21 and MS8607 chipsets
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
+					char *buf)
+{
+	int ret;
+	u8 user_reg;
+
+	mutex_lock(&dev_data->lock);
+	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
+}
+EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
+
+/**
+ * ms_sensors_i2c_show_heater() - show device heater
+ * @dev_data:	pointer on temperature/humidity device data
+ * @buf:	pointer on char buffer to write result
+ *
+ * That function will read heater enable value in the device and
+ * return 1 if the heater is enabled
+ * That function is used for HTU21 and MS8607 chipsets
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
+				   char *buf)
+{
+	u8 user_reg;
+	int ret;
+
+	mutex_lock(&dev_data->lock);
+	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
+}
+EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
+
+/**
+ * ms_sensors_i2c_write_heater() - write device heater
+ * @dev_data:	pointer on temperature/humidity device data
+ * @buf:	pointer on char buffer from user space
+ * @len:	length of buf
+ *
+ * That function will write 1 or 0 value in the device
+ * to enable or disable heater
+ * That function is used for HTU21 and MS8607 chipsets
+ *
+ * Return: length of buffer, negative errno otherwise.
+ */
+ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
+				    const char *buf, size_t len)
+{
+	u8 val, user_reg;
+	int ret;
+
+	ret = kstrtou8(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	mutex_lock(&dev_data->lock);
+	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
+	if (ret) {
+		mutex_unlock(&dev_data->lock);
+		return ret;
+	}
+
+	user_reg &= 0xFB;
+	user_reg |= val << 2;
+
+	ret = i2c_smbus_write_byte_data(dev_data->client,
+					MS_SENSORS_USER_REG_WRITE,
+					user_reg);
+	mutex_unlock(&dev_data->lock);
+	if (ret) {
+		dev_err(&dev_data->client->dev, "Unable to write user reg\n");
+		return ret;
+	}
+
+	return len;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
+
+/**
+ * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
+ * @dev_data:	pointer on temperature/humidity device data
+ * @temperature:pointer on temperature destination value
+ *
+ * That function will get temperature ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * That function is used for TSYS02D, HTU21 and MS8607 chipsets
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
+				       s32 *temperature)
+{
+	int ret;
+	u32 adc;
+	u16 delay;
+
+	mutex_lock(&dev_data->lock);
+	delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
+	ret = ms_sensors_i2c_convert_and_read(dev_data->client,
+					      MS_SENSORS_HT_T_CONVERSION_START,
+					      MS_SENSORS_NO_READ_CMD,
+					      delay, &adc);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	if (!ms_sensors_crc_valid(adc)) {
+		dev_err(&dev_data->client->dev,
+			"Temperature read crc check error\n");
+		return -ENODEV;
+	}
+
+	/* Temperature algorithm */
+	*temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
+
+/**
+ * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
+ * @dev_data:	pointer on temperature/humidity device data
+ * @humidity:	pointer on humidity destination value
+ *
+ * That function will get humidity ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * That function is used for HTU21 and MS8607 chipsets
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
+				    u32 *humidity)
+{
+	int ret;
+	u32 adc;
+	u16 delay;
+
+	mutex_lock(&dev_data->lock);
+	delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
+	ret = ms_sensors_i2c_convert_and_read(dev_data->client,
+					      MS_SENSORS_HT_H_CONVERSION_START,
+					      MS_SENSORS_NO_READ_CMD,
+					      delay, &adc);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	if (!ms_sensors_crc_valid(adc)) {
+		dev_err(&dev_data->client->dev,
+			"Humidity read crc check error\n");
+		return -ENODEV;
+	}
+
+	/* Humidity algorithm */
+	*humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
+	if (*humidity >= 100000)
+		*humidity = 100000;
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
+
+/* CRC check function for Temperature and pressure devices
+ * That function is only used when reading PROM coefficients */
+static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
+{
+	unsigned int cnt, n_bit;
+	u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
+
+	prom[len - 1] = 0;
+	prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
+
+	for (cnt = 0; cnt < len * 2; cnt++) {
+		if (cnt % 2 == 1)
+			n_rem ^= prom[cnt >> 1] & 0x00FF;
+		else
+			n_rem ^= prom[cnt >> 1] >> 8;
+
+		for (n_bit = 8; n_bit > 0; n_bit--) {
+			if (n_rem & 0x8000)
+				n_rem = (n_rem << 1) ^ 0x3000;
+			else
+				n_rem <<= 1;
+		}
+	}
+	n_rem >>= 12;
+	prom[0] = crc_read;
+
+	return n_rem == crc;
+}
+
+/**
+ * ms_sensors_tp_read_prom() - prom coeff read function
+ * @dev_data:	pointer on temperature/pressure device data
+ *
+ * That function will read prom coefficients and check CRC
+ * That function is used for MS5637 and MS8607 chipsets
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
+{
+	int i, ret;
+
+	for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
+		ret = ms_sensors_i2c_read_prom_word(
+					dev_data->client,
+					MS_SENSORS_TP_PROM_READ + (i << 1),
+					&dev_data->prom[i]);
+
+		if (ret)
+			return ret;
+	}
+
+	if (!ms_sensors_tp_crc_valid(dev_data->prom,
+				     MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
+		dev_err(&dev_data->client->dev,
+			"Calibration coefficients crc check error\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_tp_read_prom);
+
+/**
+ * ms_sensors_read_temp_and_pressure() - read temp and pressure
+ * @dev_data:	pointer on temperature/pressure device data
+ * @temperature:pointer on temperature destination value
+ * @pressure:	pointer on pressure destination value
+ *
+ * That function will read ADC and compute pressure and temperature value
+ * That function is used for MS5637 and MS8607 chipsets
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+				      int *temperature,
+				      unsigned int *pressure)
+{
+	int ret;
+	u32 t_adc, p_adc;
+	s32 dt, temp;
+	s64 off, sens, t2, off2, sens2;
+	u16 *prom = dev_data->prom, delay;
+	u8 i;
+
+	mutex_lock(&dev_data->lock);
+	i = dev_data->res_index * 2;
+	delay = ms_sensors_tp_conversion_time[dev_data->res_index];
+	ret = ms_sensors_i2c_convert_and_read(
+					dev_data->client,
+					MS_SENSORS_TP_T_CONVERSION_START + i,
+					MS_SENSORS_TP_ADC_READ,
+					delay, &t_adc);
+	if (ret) {
+		mutex_unlock(&dev_data->lock);
+		return ret;
+	}
+	ret = ms_sensors_i2c_convert_and_read(
+					dev_data->client,
+					MS_SENSORS_TP_P_CONVERSION_START + i,
+					MS_SENSORS_TP_ADC_READ,
+					delay, &p_adc);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	dt = (s32)t_adc - (prom[5] << 8);
+
+	/* Actual temperature = 2000 + dT * TEMPSENS */
+	temp = 2000 + (((s64)dt * prom[6]) >> 23);
+
+	/* Second order temperature compensation */
+	if (temp < 2000) {
+		s64 tmp = (s64)temp - 2000;
+
+		t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
+		off2 = (61 * tmp * tmp) >> 4;
+		sens2 = (29 * tmp * tmp) >> 4;
+
+		if (temp < -1500) {
+			s64 tmp = (s64)temp + 1500;
+
+			off2 += 17 * tmp * tmp;
+			sens2 += 9 * tmp * tmp;
+		}
+	} else {
+		t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
+		off2 = 0;
+		sens2 = 0;
+	}
+
+	/* OFF = OFF_T1 + TCO * dT */
+	off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
+	off -= off2;
+
+	/* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
+	sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
+	sens -= sens2;
+
+	/* Temperature compensated pressure = D1 * SENS - OFF */
+	*temperature = (temp - t2) * 10;
+	*pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
+
+	return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
+
+MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
new file mode 100644
index 0000000..a521428
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
@@ -0,0 +1,54 @@
+/*
+ * Measurements Specialties common sensor driver
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _MS_SENSORS_I2C_H
+#define _MS_SENSORS_I2C_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#define MS_SENSORS_TP_PROM_WORDS_NB		7
+
+struct ms_ht_dev {
+	struct i2c_client *client;
+	struct mutex lock; /* mutex protecting data structure */
+	u8 res_index;
+};
+
+struct ms_tp_dev {
+	struct i2c_client *client;
+	struct mutex lock; /* mutex protecting data structure */
+	/* Added element for CRC computation */
+	u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
+	u8 res_index;
+};
+
+int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
+int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
+int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
+				    unsigned int delay, u32 *adc);
+int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
+ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
+ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
+				    const char *buf, size_t len);
+int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
+				       s32 *temperature);
+int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
+				    u32 *humidity);
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+				      int *temperature,
+				      unsigned int *pressure);
+
+#endif /* _MS_SENSORS_I2C_H */
-- 
2.3.7


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 1/6] iio: Add meas-spec sensors common part Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-08-08 17:03   ` Jonathan Cameron
  2015-07-30  9:25 ` [PATCH V2 3/6] iio: Add tsys02d " Ludovic Tancerel
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 drivers/iio/temperature/Kconfig  |  11 ++
 drivers/iio/temperature/Makefile |   1 +
 drivers/iio/temperature/tsys01.c | 232 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 244 insertions(+)
 create mode 100644 drivers/iio/temperature/tsys01.c

diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 21feaa4..35712032 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -23,4 +23,15 @@ config TMP006
 	  This driver can also be built as a module. If so, the module will
 	  be called tmp006.
 
+config TSYS01
+	tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
+	depends on I2C
+	select IIO_MS_SENSORS_I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  TSYS01 I2C temperature sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called tsys01.
+
 endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 40710a8..368a2a2 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_MLX90614) += mlx90614.o
 obj-$(CONFIG_TMP006) += tmp006.o
+obj-$(CONFIG_TSYS01) += tsys01.o
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
new file mode 100644
index 0000000..c863aaf
--- /dev/null
+++ b/drivers/iio/temperature/tsys01.c
@@ -0,0 +1,232 @@
+/*
+ * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
+ *
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+/* TSYS01 Commands */
+#define TSYS01_RESET				0x1E
+#define TSYS01_CONVERSION_START			0x48
+#define TSYS01_ADC_READ				0x00
+#define TSYS01_PROM_READ			0xA0
+
+#define TSYS01_PROM_WORDS_NB			8
+
+struct tsys01_dev {
+	void *client;
+	struct mutex lock; /* lock during conversion */
+
+	int (*reset)(void *cli, u8 cmd, unsigned int delay);
+	int (*convert_and_read)(void *cli, u8 conv, u8 rd,
+				unsigned int delay, u32 *adc);
+	int (*read_prom_word)(void *cli, int cmd, u16 *word);
+
+	u16 prom[TSYS01_PROM_WORDS_NB];
+};
+
+/* Multiplication coefficients for temperature computation */
+static const int coeff_mul[] = { -1500000, 1000000, -2000000,
+				 4000000, -2000000 };
+
+static int tsys01_read_temperature(struct iio_dev *indio_dev,
+				   s32 *temperature)
+{
+	int ret, i;
+	u32 adc;
+	s64 temp = 0;
+	struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+	mutex_lock(&dev_data->lock);
+	ret = dev_data->convert_and_read(dev_data->client,
+					 TSYS01_CONVERSION_START,
+					 TSYS01_ADC_READ, 9000, &adc);
+	mutex_unlock(&dev_data->lock);
+	if (ret)
+		return ret;
+
+	adc >>= 8;
+
+	/* Temperature algorithm */
+	for (i = 4; i > 0; i--) {
+		temp += coeff_mul[i] *
+			(s64)dev_data->prom[5 - i];
+		temp *= (s64)adc;
+		temp = div64_s64(temp, 100000);
+	}
+	temp *= 10;
+	temp += coeff_mul[0] * (s64)dev_data->prom[5];
+	temp = div64_s64(temp, 100000);
+
+	*temperature = temp;
+
+	return 0;
+}
+
+static int tsys01_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *channel, int *val,
+			   int *val2, long mask)
+{
+	int ret;
+	s32 temperature;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (channel->type) {
+		case IIO_TEMP:	/* in milli °C */
+			ret = tsys01_read_temperature(indio_dev, &temperature);
+			if (ret)
+				return ret;
+			*val = temperature;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_chan_spec tsys01_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+	}
+};
+
+static const struct iio_info tsys01_info = {
+	.read_raw = tsys01_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static bool tsys01_crc_valid(u16 *n_prom)
+{
+	u8 cnt;
+	u8 sum = 0;
+
+	for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
+		sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
+
+	return (sum == 0);
+}
+
+static int tsys01_read_prom(struct iio_dev *indio_dev)
+{
+	int i, ret;
+	struct tsys01_dev *dev_data = iio_priv(indio_dev);
+	char buf[7 * TSYS01_PROM_WORDS_NB + 1];
+	char *ptr = buf;
+
+	for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
+		ret = dev_data->read_prom_word(dev_data->client,
+					       TSYS01_PROM_READ + (i << 1),
+					       &dev_data->prom[i]);
+		if (ret)
+			return ret;
+
+		ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
+		ptr += ret;
+	}
+
+	if (!tsys01_crc_valid(dev_data->prom)) {
+		dev_err(&indio_dev->dev, "prom crc check error\n");
+		return -ENODEV;
+	}
+	*ptr = 0;
+	dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
+
+	return 0;
+}
+
+static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
+{
+	int ret;
+	struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+	mutex_init(&dev_data->lock);
+
+	indio_dev->info = &tsys01_info;
+	indio_dev->name = dev->driver->name;
+	indio_dev->dev.parent = dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = tsys01_channels;
+	indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
+
+	ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
+	if (ret)
+		return ret;
+
+	ret = tsys01_read_prom(indio_dev);
+	if (ret)
+		return ret;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static int tsys01_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct tsys01_dev *dev_data;
+	struct iio_dev *indio_dev;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA |
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev,
+			"Adapter does not support some i2c transaction\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_data = iio_priv(indio_dev);
+	dev_data->client = client;
+	dev_data->reset = ms_sensors_i2c_reset;
+	dev_data->read_prom_word = ms_sensors_i2c_read_prom_word;
+	dev_data->convert_and_read = ms_sensors_i2c_convert_and_read;
+
+	i2c_set_clientdata(client, indio_dev);
+
+	return tsys01_probe(indio_dev, &client->dev);
+}
+
+static const struct i2c_device_id tsys01_id[] = {
+	{"tsys01", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tsys01_id);
+
+static struct i2c_driver tsys01_driver = {
+	.probe = tsys01_i2c_probe,
+	.id_table = tsys01_id,
+	.driver = {
+		   .name = "tsys01",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+module_i2c_driver(tsys01_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.3.7


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH V2 3/6] iio: Add tsys02d meas-spec driver support
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 1/6] iio: Add meas-spec sensors common part Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-08-08 17:15   ` Jonathan Cameron
  2015-07-30  9:25 ` [PATCH V2 4/6] iio: Add htu21 " Ludovic Tancerel
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
 drivers/iio/temperature/Kconfig                   |  11 ++
 drivers/iio/temperature/Makefile                  |   1 +
 drivers/iio/temperature/tsys02d.c                 | 193 ++++++++++++++++++++++
 4 files changed, 212 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-meas-spec
 create mode 100644 drivers/iio/temperature/tsys02d.c

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
new file mode 100644
index 0000000..6d47e54
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
@@ -0,0 +1,7 @@
+What:           /sys/bus/iio/devices/iio:deviceX/battery_low
+KernelVersion:  4.1.0
+Contact:        linux-iio@vger.kernel.org
+Description:
+                Reading returns either '1' or '0'. '1' means that the
+                battery level supplied to sensor is below 2.25V.
+                This ABI is available for tsys02d, htu21, ms8607
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 35712032..c4664e5 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -34,4 +34,15 @@ config TSYS01
 	  This driver can also be built as a module. If so, the module will
 	  be called tsys01.
 
+config TSYS02D
+	tristate "Measurement Specialties TSYS02D temperature sensor"
+	depends on I2C
+	select IIO_MS_SENSORS_I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  TSYS02D temperature sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called tsys02d.
+
 endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 368a2a2..02bc79d 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_MLX90614) += mlx90614.o
 obj-$(CONFIG_TMP006) += tmp006.o
 obj-$(CONFIG_TSYS01) += tsys01.o
+obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
new file mode 100644
index 0000000..6971dab
--- /dev/null
+++ b/drivers/iio/temperature/tsys02d.c
@@ -0,0 +1,193 @@
+/*
+ * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define TSYS02D_RESET				0xFE
+
+static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
+/* String copy of the above const for readability purpose */
+static const char tsys02d_show_samp_freq[] = "20 40 70 140";
+
+static int tsys02d_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *channel, int *val,
+			    int *val2, long mask)
+{
+	int ret;
+	s32 temperature;
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (channel->type) {
+		case IIO_TEMP:	/* in milli °C */
+			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
+								 &temperature);
+			if (ret)
+				return ret;
+			*val = temperature;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = tsys02d_samp_freq[dev_data->res_index];
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tsys02d_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+	int i, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		i = ARRAY_SIZE(tsys02d_samp_freq);
+		while (i-- > 0)
+			if (val == tsys02d_samp_freq[i])
+				break;
+		if (i < 0)
+			return -EINVAL;
+		mutex_lock(&dev_data->lock);
+		dev_data->res_index = i;
+		ret = ms_sensors_i2c_write_resolution(dev_data, i);
+		mutex_unlock(&dev_data->lock);
+
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_chan_spec tsys02d_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	}
+};
+
+static ssize_t tsys02_read_battery_low(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_i2c_show_battery_low(dev_data, buf);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+		       tsys02_read_battery_low, NULL, 0);
+
+static struct attribute *tsys02d_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_battery_low.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group tsys02d_attribute_group = {
+	.attrs = tsys02d_attributes,
+};
+
+static const struct iio_info tsys02d_info = {
+	.read_raw = tsys02d_read_raw,
+	.write_raw = tsys02d_write_raw,
+	.attrs = &tsys02d_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+int tsys02d_probe(struct i2c_client *client,
+		  const struct i2c_device_id *id)
+{
+	struct ms_ht_dev *dev_data;
+	struct iio_dev *indio_dev;
+	int ret;
+	u64 serial_number;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev,
+			"Adapter does not support some i2c transaction\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_data = iio_priv(indio_dev);
+	dev_data->client = client;
+	dev_data->res_index = 0;
+	mutex_init(&dev_data->lock);
+
+	indio_dev->info = &tsys02d_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = tsys02d_channels;
+	indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
+
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = ms_sensors_i2c_reset(client, TSYS02D_RESET, 15000);
+	if (ret)
+		return ret;
+
+	ret = ms_sensors_i2c_read_serial(client, &serial_number);
+	if (ret)
+		return ret;
+	dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id tsys02d_id[] = {
+	{"tsys02d", 0},
+	{}
+};
+
+static struct i2c_driver tsys02d_driver = {
+	.probe = tsys02d_probe,
+	.id_table = tsys02d_id,
+	.driver = {
+		   .name = "tsys02d",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+module_i2c_driver(tsys02d_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.3.7


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH V2 4/6] iio: Add htu21 meas-spec driver support
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
                   ` (2 preceding siblings ...)
  2015-07-30  9:25 ` [PATCH V2 3/6] iio: Add tsys02d " Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-08-08 17:17   ` Jonathan Cameron
  2015-07-30  9:25 ` [PATCH V2 5/6] iio: Add ms5637 " Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 6/6] iio: Add ms8607 " Ludovic Tancerel
  5 siblings, 1 reply; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
 drivers/iio/humidity/Kconfig                      |  11 ++
 drivers/iio/humidity/Makefile                     |   1 +
 drivers/iio/humidity/htu21.c                      | 228 ++++++++++++++++++++++
 4 files changed, 247 insertions(+)
 create mode 100644 drivers/iio/humidity/htu21.c

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
index 6d47e54..7b09d3a 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
+++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
@@ -5,3 +5,10 @@ Description:
                 Reading returns either '1' or '0'. '1' means that the
                 battery level supplied to sensor is below 2.25V.
                 This ABI is available for tsys02d, htu21, ms8607
+What:           /sys/bus/iio/devices/iio:deviceX/heater_enable
+KernelVersion:  4.1.0
+Contact:        linux-iio@vger.kernel.org
+Description:
+                Enable or disable heater function by writing either
+		'1' or '0'.
+                Same reading values apply
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 4813b79..447a833 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -12,6 +12,17 @@ config DHT11
 	  Other sensors should work as well as long as they speak the
 	  same protocol.
 
+config HTU21
+	tristate "Measurement Specialties HTU21 humidity & temperature sensor"
+	depends on I2C
+        select IIO_MS_SENSORS_I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  HTU21 humidity and temperature sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called htu21.
+
 config SI7005
 	tristate "SI7005 relative humidity and temperature sensor"
 	depends on I2C
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index 86e2d26..826b1d5 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_HTU21) += htu21.o
 obj-$(CONFIG_SI7005) += si7005.o
 obj-$(CONFIG_SI7020) += si7020.o
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
new file mode 100644
index 0000000..870b631
--- /dev/null
+++ b/drivers/iio/humidity/htu21.c
@@ -0,0 +1,228 @@
+/*
+ * htu21.c - Support for Measurement-Specialties
+ *           htu21 temperature & humidity sensor
+ *
+ * Copyright (c) 2014 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/HTU21D.pdf
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define HTU21_RESET				0xFE
+
+static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
+/* String copy of the above const for readability purpose */
+static const char htu21_show_samp_freq[] = "20 40 70 120";
+
+static int htu21_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *channel, int *val,
+			  int *val2, long mask)
+{
+	int ret, temperature;
+	unsigned int humidity;
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		switch (channel->type) {
+		case IIO_TEMP:	/* in milli °C */
+			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
+								 &temperature);
+			if (ret)
+				return ret;
+			*val = temperature;
+
+			return IIO_VAL_INT;
+		case IIO_HUMIDITYRELATIVE:	/* in milli %RH */
+			ret = ms_sensors_i2c_ht_read_humidity(dev_data,
+							      &humidity);
+			if (ret)
+				return ret;
+			*val = humidity;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = htu21_samp_freq[dev_data->res_index];
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int htu21_write_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int val, int val2, long mask)
+{
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+	int i, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		i = ARRAY_SIZE(htu21_samp_freq);
+		while (i-- > 0)
+			if (val == htu21_samp_freq[i])
+				break;
+		if (i < 0)
+			return -EINVAL;
+		mutex_lock(&dev_data->lock);
+		dev_data->res_index = i;
+		ret = ms_sensors_i2c_write_resolution(dev_data, i);
+		mutex_unlock(&dev_data->lock);
+
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_chan_spec htu21_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 },
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 }
+};
+
+static ssize_t htu21_show_battery_low(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_i2c_show_battery_low(dev_data, buf);
+}
+
+static ssize_t htu21_show_heater(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_i2c_show_heater(dev_data, buf);
+}
+
+static ssize_t htu21_write_heater(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+	return ms_sensors_i2c_write_heater(dev_data, buf, len);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+		       htu21_show_battery_low, NULL, 0);
+static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
+		       htu21_show_heater, htu21_write_heater, 0);
+
+static struct attribute *htu21_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	&iio_dev_attr_battery_low.dev_attr.attr,
+	&iio_dev_attr_heater_enable.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group htu21_attribute_group = {
+	.attrs = htu21_attributes,
+};
+
+static const struct iio_info htu21_info = {
+	.read_raw = htu21_read_raw,
+	.write_raw = htu21_write_raw,
+	.attrs = &htu21_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+int htu21_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct ms_ht_dev *dev_data;
+	struct iio_dev *indio_dev;
+	int ret;
+	u64 serial_number;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev,
+			"Adapter does not support some i2c transaction\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_data = iio_priv(indio_dev);
+	dev_data->client = client;
+	dev_data->res_index = 0;
+	mutex_init(&dev_data->lock);
+
+	indio_dev->info = &htu21_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = htu21_channels;
+	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = ms_sensors_i2c_reset(client, HTU21_RESET, 15000);
+	if (ret)
+		return ret;
+
+	ret = ms_sensors_i2c_read_serial(client, &serial_number);
+	if (ret)
+		return ret;
+	dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id htu21_id[] = {
+	{"htu21", 0},
+	{}
+};
+
+static struct i2c_driver htu21_driver = {
+	.probe = htu21_probe,
+	.id_table = htu21_id,
+	.driver = {
+		   .name = "htu21",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.3.7


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH V2 5/6] iio: Add ms5637 meas-spec driver support
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
                   ` (3 preceding siblings ...)
  2015-07-30  9:25 ` [PATCH V2 4/6] iio: Add htu21 " Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-07-30  9:25 ` [PATCH V2 6/6] iio: Add ms8607 " Ludovic Tancerel
  5 siblings, 0 replies; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 drivers/iio/pressure/Kconfig  |  15 +++-
 drivers/iio/pressure/Makefile |   1 +
 drivers/iio/pressure/ms5637.c | 188 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 202 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/pressure/ms5637.c

diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index fa62950..8142cfe 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -53,9 +53,9 @@ config MPL3115
           will be called mpl3115.
 
 config MS5611
-	tristate "Measurement Specialities MS5611 pressure sensor driver"
+	tristate "Measurement Specialties MS5611 pressure sensor driver"
 	help
-	  Say Y here to build support for the Measurement Specialities
+	  Say Y here to build support for the Measurement Specialties
 	  MS5611 pressure and temperature sensor.
 
 	  To compile this driver as a module, choose M here: the module will
@@ -79,6 +79,17 @@ config MS5611_SPI
 	  To compile this driver as a module, choose M here: the module will
 	  be called ms5611_spi.
 
+config MS5637
+	tristate "Measurement Specialties MS5637 pressure & temperature sensor"
+	depends on I2C
+        select IIO_MS_SENSORS_I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  MS5637 pressure and temperature sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ms5637.
+
 config IIO_ST_PRESS
 	tristate "STMicroelectronics pressure sensor Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index a4f98f8..46571c96 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
 obj-$(CONFIG_MS5611) += ms5611_core.o
 obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
 obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
+obj-$(CONFIG_MS5637) += ms5637.o
 obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
 st_pressure-y := st_pressure_core.o
 st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
new file mode 100644
index 0000000..e2073fd
--- /dev/null
+++ b/drivers/iio/pressure/ms5637.c
@@ -0,0 +1,188 @@
+/*
+ * ms5637.c - Support for Measurement-Specialties ms5637
+ *            pressure & temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x76)
+ *
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
+ *
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 };
+/* String copy of the above const for readability purpose */
+static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30";
+
+static int ms5637_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *channel, int *val,
+			   int *val2, long mask)
+{
+	int ret;
+	int temperature;
+	unsigned int pressure;
+	struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = ms_sensors_read_temp_and_pressure(dev_data,
+							&temperature,
+							&pressure);
+		if (ret)
+			return ret;
+
+		switch (channel->type) {
+		case IIO_TEMP:	/* in milli °C */
+			*val = temperature;
+
+			return IIO_VAL_INT;
+		case IIO_PRESSURE:	/* in kPa */
+			*val = pressure / 1000;
+			*val2 = (pressure % 1000) * 1000;
+
+			return IIO_VAL_INT_PLUS_MICRO;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val = ms5637_samp_freq[dev_data->res_index];
+
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ms5637_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+	int i;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		i = ARRAY_SIZE(ms5637_samp_freq);
+		while (i-- > 0)
+			if (val == ms5637_samp_freq[i])
+				break;
+		if (i < 0)
+			return -EINVAL;
+		dev_data->res_index = i;
+
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_chan_spec ms5637_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	},
+	{
+		.type = IIO_PRESSURE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	}
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
+
+static struct attribute *ms5637_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ms5637_attribute_group = {
+	.attrs = ms5637_attributes,
+};
+
+static const struct iio_info ms5637_info = {
+	.read_raw = ms5637_read_raw,
+	.write_raw = ms5637_write_raw,
+	.attrs = &ms5637_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int ms5637_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct ms_tp_dev *dev_data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA |
+				     I2C_FUNC_SMBUS_WRITE_BYTE |
+				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+		dev_err(&client->dev,
+			"Adapter does not support some i2c transaction\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	dev_data = iio_priv(indio_dev);
+	dev_data->client = client;
+	dev_data->res_index = 5;
+	mutex_init(&dev_data->lock);
+
+	indio_dev->info = &ms5637_info;
+	indio_dev->name = id->name;
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = ms5637_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ms5637_channels);
+
+	i2c_set_clientdata(client, indio_dev);
+
+	ret = ms_sensors_i2c_reset(client, 0x1E, 3000);
+	if (ret)
+		return ret;
+
+	ret = ms_sensors_tp_read_prom(dev_data);
+	if (ret)
+		return ret;
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ms5637_id[] = {
+	{"ms5637", 0},
+	{}
+};
+
+static struct i2c_driver ms5637_driver = {
+	.probe = ms5637_probe,
+	.id_table = ms5637_id,
+	.driver = {
+		   .name = "ms5637",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+module_i2c_driver(ms5637_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.3.7

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH V2 6/6] iio: Add ms8607 meas-spec driver support
  2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
                   ` (4 preceding siblings ...)
  2015-07-30  9:25 ` [PATCH V2 5/6] iio: Add ms5637 " Ludovic Tancerel
@ 2015-07-30  9:25 ` Ludovic Tancerel
  2015-08-08 17:22   ` Jonathan Cameron
  5 siblings, 1 reply; 25+ messages in thread
From: Ludovic Tancerel @ 2015-07-30  9:25 UTC (permalink / raw)
  To: jic23, knaack.h, lars, pmeerw, linux-iio, ludovic.tancerel,
	William.Markezana

Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
---
 Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  1 +
 drivers/iio/humidity/htu21.c                      | 32 ++++++++++++++++++++---
 drivers/iio/pressure/Kconfig                      | 13 +++++++++
 drivers/iio/pressure/ms5637.c                     |  6 ++++-
 4 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
index 7b09d3a..df70dda6 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
+++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
@@ -12,3 +12,4 @@ Description:
                 Enable or disable heater function by writing either
 		'1' or '0'.
                 Same reading values apply
+		This ABI is available for htu21, ms8607
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
index 870b631..4720cbc 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -1,6 +1,7 @@
 /*
  * htu21.c - Support for Measurement-Specialties
  *           htu21 temperature & humidity sensor
+ *	     and humidity part of MS8607 sensor
  *
  * Copyright (c) 2014 Measurement-Specialties
  *
@@ -10,6 +11,8 @@
  *
  * Datasheet:
  *  http://www.meas-spec.com/downloads/HTU21D.pdf
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
  *
  */
 
@@ -25,6 +28,11 @@
 
 #define HTU21_RESET				0xFE
 
+enum {
+	HTU21,
+	MS8607
+};
+
 static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
 /* String copy of the above const for readability purpose */
 static const char htu21_show_samp_freq[] = "20 40 70 120";
@@ -107,6 +115,17 @@ static const struct iio_chan_spec htu21_channels[] = {
 	 }
 };
 
+/* Meas Spec recommendation is to not read temperature
+ * on this driver part for MS8607
+ */
+static const struct iio_chan_spec ms8607_channels[] = {
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	 }
+};
+
 static ssize_t htu21_show_battery_low(struct device *dev,
 				      struct device_attribute *attr, char *buf)
 {
@@ -189,8 +208,14 @@ int htu21_probe(struct i2c_client *client,
 	indio_dev->name = id->name;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = htu21_channels;
-	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+
+	if (id->driver_data == MS8607) {
+		indio_dev->channels = ms8607_channels;
+		indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
+	} else {
+		indio_dev->channels = htu21_channels;
+		indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+	}
 
 	i2c_set_clientdata(client, indio_dev);
 
@@ -207,7 +232,8 @@ int htu21_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id htu21_id[] = {
-	{"htu21", 0},
+	{"htu21", HTU21},
+	{"ms8607-h", MS8607},
 	{}
 };
 
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 8142cfe..e6a7fd5 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -90,6 +90,19 @@ config MS5637
 	  This driver can also be built as a module. If so, the module will
 	  be called ms5637.
 
+config MS8607
+	tristate "Measurement Specialties MS8607 pressure, temperature & humidity sensor"
+	depends on I2C
+        select IIO_MS_SENSORS_I2C
+        select HTU21
+        select MS5637
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  MS8607 pressure, temperature and humidity sensor.
+
+	  This is based on HTU21 and MS5637 drivers. If built as a module,
+	  modules to load will be htu21 and ms5637.
+
 config IIO_ST_PRESS
 	tristate "STMicroelectronics pressure sensor Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
index e2073fd..c185aa0 100644
--- a/drivers/iio/pressure/ms5637.c
+++ b/drivers/iio/pressure/ms5637.c
@@ -1,5 +1,5 @@
 /*
- * ms5637.c - Support for Measurement-Specialties ms5637
+ * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
  *            pressure & temperature sensor
  *
  * Copyright (c) 2015 Measurement-Specialties
@@ -10,8 +10,11 @@
  *
  * Datasheet:
  *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
+ * Datasheet:
+ *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
  *
  */
+
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -168,6 +171,7 @@ static int ms5637_probe(struct i2c_client *client,
 
 static const struct i2c_device_id ms5637_id[] = {
 	{"ms5637", 0},
+	{"ms8607-tp", 1},
 	{}
 };
 
-- 
2.3.7

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-07-30  9:25 ` [PATCH V2 1/6] iio: Add meas-spec sensors common part Ludovic Tancerel
@ 2015-08-08 16:58   ` Jonathan Cameron
  2015-08-10  7:43     ` Crt Mori
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 16:58 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana

On 30/07/15 10:25, Ludovic Tancerel wrote:
> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
A few bits inline.
Also, would prefer some basic description of the patch up here...
> ---
>  drivers/iio/common/Kconfig                     |   1 +
>  drivers/iio/common/Makefile                    |   1 +
>  drivers/iio/common/ms_sensors/Kconfig          |   6 +
>  drivers/iio/common/ms_sensors/Makefile         |   5 +
>  drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>  drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>  6 files changed, 701 insertions(+)
>  create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>  create mode 100644 drivers/iio/common/ms_sensors/Makefile
>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
> 
> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
> index 790f106..26a6026 100644
> --- a/drivers/iio/common/Kconfig
> +++ b/drivers/iio/common/Kconfig
> @@ -3,5 +3,6 @@
>  #
>  
>  source "drivers/iio/common/hid-sensors/Kconfig"
> +source "drivers/iio/common/ms_sensors/Kconfig"
>  source "drivers/iio/common/ssp_sensors/Kconfig"
>  source "drivers/iio/common/st_sensors/Kconfig"
> diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
> index b1e4d9c..585da6a 100644
> --- a/drivers/iio/common/Makefile
> +++ b/drivers/iio/common/Makefile
> @@ -8,5 +8,6 @@
>  
>  # When adding new entries keep the list in alphabetical order
>  obj-y += hid-sensors/
> +obj-y += ms_sensors/
>  obj-y += ssp_sensors/
>  obj-y += st_sensors/
> diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
> new file mode 100644
> index 0000000..b28a92b
> --- /dev/null
> +++ b/drivers/iio/common/ms_sensors/Kconfig
> @@ -0,0 +1,6 @@
> +#
> +# Measurements Specialties sensors common library
> +#
> +
> +config IIO_MS_SENSORS_I2C
> +        tristate
> diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
> new file mode 100644
> index 0000000..7846428
> --- /dev/null
> +++ b/drivers/iio/common/ms_sensors/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for the Measurement Specialties sensor common modules.
> +#
> +
> +obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
> new file mode 100644
> index 0000000..f5d27b6
> --- /dev/null
> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
> @@ -0,0 +1,634 @@
> +/*
> + * Measurements Specialties driver common i2c functions
> + *
> + * Copyright (c) 2015 Measurement-Specialties
> + *
> + * Licensed under the GPL-2.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/iio/iio.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +
> +#include "ms_sensors_i2c.h"
> +
> +/* Conversion times in us */
> +static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
> +						       13000, 7000 };
> +static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
> +						       5000, 8000 };
> +static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
> +						     4100, 8220, 16440 };
> +
> +#define MS_SENSORS_SERIAL_READ_MSB		0xFA0F
> +#define MS_SENSORS_SERIAL_READ_LSB		0xFCC9
> +#define MS_SENSORS_USER_REG_WRITE		0xE6
> +#define MS_SENSORS_USER_REG_READ		0xE7
> +#define MS_SENSORS_HT_T_CONVERSION_START	0xF3
> +#define MS_SENSORS_HT_H_CONVERSION_START	0xF5
> +
> +#define MS_SENSORS_TP_PROM_READ			0xA0
> +#define MS_SENSORS_TP_T_CONVERSION_START	0x50
> +#define MS_SENSORS_TP_P_CONVERSION_START	0x40
> +#define MS_SENSORS_TP_ADC_READ			0x00
> +
> +#define MS_SENSORS_NO_READ_CMD			0xFF
> +
> +/**
> + * ms_sensors_i2c_reset() - i2c reset function
> + * @cli:	pointer on i2c client
> + * @cmd:	reset cmd. Depends on device in use
> + * @delay:	usleep minimal delay after reset command is issued
> + *
> + * Generic I2C reset function for Measurement Specialties devices
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay)
> +{
> +	int ret;
> +	struct i2c_client *client = cli;
> +
> +	ret = i2c_smbus_write_byte(client, cmd);
> +	if (ret) {
> +		dev_err(&client->dev, "Failed to reset device\n");
> +		return ret;
> +	}
> +	usleep_range(delay, delay + 1000);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_reset);
> +
> +/**
> + * ms_sensors_i2c_read_prom_word() - i2c prom word read function
> + * @cli:	pointer on i2c client
> + * @cmd:	PROM read cmd. Depends on device and prom id
> + * @word:	pointer on word destination value
> + *
> + * Generic i2c prom word read function for Measurement Specialties devices
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word)
> +{
> +	int ret;
> +	struct i2c_client *client = (struct i2c_client *)cli;
> +
> +	ret = i2c_smbus_read_word_swapped(client, cmd);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Failed to read prom word\n");
> +		return ret;
> +	}
> +	*word = ret;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_read_prom_word);
> +
> +/**
> + * ms_sensors_i2c_convert_and_read() - i2c ADC conversion & read function
> + * @cli:	pointer on i2c client
> + * @conv:	ADC conversion command. Depends on device in use
> + * @rd:		ADC read command. Depends on device in use
> + * @delay:	usleep minimal delay after conversion command is issued
> + * @adc:	pointer on ADC destination value
> + *
> + * Generic i2c ADC conversion & read function for Measurement Specialties
> + * devices.
> + * The function will issue conversion command, sleep appopriate delay, and
> + * issue command to read ADC
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
> +				    unsigned int delay, u32 *adc)
> +{
> +	int ret;
> +	u32 buf = 0;
> +	struct i2c_client *client = (struct i2c_client *)cli;
> +
> +	/* Trigger conversion */
> +	ret = i2c_smbus_write_byte(client, conv);
> +	if (ret)
> +		goto err;
> +	usleep_range(delay, delay + 1000);
> +
> +	/* Retrieve ADC value */
> +	if (rd != MS_SENSORS_NO_READ_CMD)
> +		ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
> +	else
> +		ret = i2c_master_recv(client, (u8 *)&buf, 3);
> +	if (ret < 0)
> +		goto err;
> +
> +	dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
> +	*adc = be32_to_cpu(buf) >> 8;
> +
> +	return 0;
> +err:
> +	dev_err(&client->dev, "Unable to make sensor adc conversion\n");
> +	return ret;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_convert_and_read);
> +
> +/**
> + * ms_sensors_crc_valid() - CRC check function
> + * @value:	input and CRC compare value
> + *
> + * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
> + * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
> + * The argument contains CRC value in LSB byte while the bytes 1 and 2
> + * are used for CRC computation
> + *
> + * Return: 1 if CRC is valid, 0 otherwise.
> + */
> +static bool ms_sensors_crc_valid(u32 value)
> +{
> +	u32 polynom = 0x988000;	/* x^8 + x^5 + x^4 + 1 */
> +	u32 msb = 0x800000;
> +	u32 mask = 0xFF8000;
> +	u32 result = value & 0xFFFF00;
> +	u8 crc = value & 0xFF;
> +
> +	while (msb != 0x80) {
> +		if (result & msb)
> +			result = ((result ^ polynom) & mask)
> +				| (result & ~mask);
> +		msb >>= 1;
> +		mask >>= 1;
> +		polynom >>= 1;
> +	}
> +
> +	return result == crc;
> +}
> +
> +/**
> + * ms_sensors_i2c_read_serial() - i2c serial number read function
> + * @cli:	pointer on i2c client
> + * @sn:		pointer on 64-bits destination value
> + *
> + * Generic i2c serial number read function for Measurement Specialties devices.
> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
> + * Refer to datasheet:
> + *	http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
> +{
> +	u8 i;
> +	u64 rcv_buf = 0;
> +	u16 send_buf;
> +	int ret;
> +
> +	struct i2c_msg msg[2] = {
> +		{
> +		 .addr = client->addr,
> +		 .flags = client->flags,
> +		 .len = 2,
> +		 .buf = (char *)&send_buf,
If you are going to type cast, please match the (__u8 *) from
include/uapi/linux/i2c.h
> +		 },
> +		{
> +		 .addr = client->addr,
> +		 .flags = client->flags | I2C_M_RD,
> +		 .buf = (char *)&rcv_buf,
> +		 },
> +	};
> +
> +	/* Read MSB part of serial number */
> +	send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
> +	msg[1].len = 8;
> +	ret = i2c_transfer(client->adapter, msg, 2);
> +	if (ret < 0)
> +		goto err;
> +
> +	rcv_buf = be64_to_cpu(rcv_buf);
> +	dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
> +
> +	for (i = 0; i < 64; i += 16) {
> +		if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
> +			return -ENODEV;
> +	}
> +
> +	*sn = (((rcv_buf >> 32) & 0xFF000000) |
> +	       ((rcv_buf >> 24) & 0x00FF0000) |
> +	       ((rcv_buf >> 16) & 0x0000FF00) |
> +	       ((rcv_buf >> 8) & 0x000000FF)) << 16;
> +
> +	/* Read LSB part of serial number */
> +	send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
> +	msg[1].len = 6;
> +	rcv_buf = 0;
> +	ret = i2c_transfer(client->adapter, msg, 2);
> +	if (ret < 0)
> +		goto err;
> +
> +	rcv_buf = be64_to_cpu(rcv_buf) >> 16;
> +	dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
> +
> +	for (i = 0; i < 48; i += 24) {
> +		if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
> +			return -ENODEV;
> +	}
> +
> +	*sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
> +
> +	return 0;
> +
> +err:
Put this inline and drop the goto
> +	dev_err(&client->dev, "Unable to read device serial number");
> +	return ret;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
> +
What is meant by a user_reg as opposed to other regs?
> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
> +					u8 *user_reg)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
> +	if (ret)
> +		goto err;
> +
> +	ret = i2c_master_recv(client, user_reg, 1);
> +	if (ret < 0)
> +		goto err;
> +	dev_dbg(&client->dev, "User register :%x\n", *user_reg);
> +
> +	return 0;
> +err:
> +	dev_err(&client->dev, "Unable to read user reg");
> +	return ret;
> +}
> +
> +/**
> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
> + * @dev_data:	pointer on temperature/humidity device data
> + * @i:		resolution index to set
> + *
> + * That function will program the appropriate resolution based on the index
> + * provided when user space will set samp_freq channel.
> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
> +					u8 i)
> +{
> +	u8 user_reg;
> +	int ret;
> +
> +	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
> +	if (ret)
> +		return ret;
> +
> +	user_reg &= 0x7E;
> +	user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
> +
> +	return i2c_smbus_write_byte_data(dev_data->client,
> +					 MS_SENSORS_USER_REG_WRITE,
> +					 user_reg);
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
> +
> +/**
> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
> + * @dev_data:	pointer on temperature/humidity device data
> + * @buf:	pointer on char buffer to write result
> + *
> + * That function will read battery indicator value in the device and
> + * return 1 if the device voltage is below 2.25V.
> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
> + *
> + * Return: length of sprintf on success, negative errno otherwise.
> + */
> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
> +					char *buf)
> +{
> +	int ret;
> +	u8 user_reg;
> +
> +	mutex_lock(&dev_data->lock);
> +	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
> +
> +/**
> + * ms_sensors_i2c_show_heater() - show device heater
> + * @dev_data:	pointer on temperature/humidity device data
> + * @buf:	pointer on char buffer to write result
> + *
> + * That function will read heater enable value in the device and
> + * return 1 if the heater is enabled
> + * That function is used for HTU21 and MS8607 chipsets
> + *
> + * Return: length of sprintf on success, negative errno otherwise.
> + */
> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
> +				   char *buf)
> +{
> +	u8 user_reg;
> +	int ret;
> +
> +	mutex_lock(&dev_data->lock);
> +	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
> +
> +/**
> + * ms_sensors_i2c_write_heater() - write device heater
I'm not sure the _i2c_ bit is important in this function name...

> + * @dev_data:	pointer on temperature/humidity device data
> + * @buf:	pointer on char buffer from user space
> + * @len:	length of buf
> + *
> + * That function will write 1 or 0 value in the device
> + * to enable or disable heater
> + * That function is used for HTU21 and MS8607 chipsets
That->This
> + *
> + * Return: length of buffer, negative errno otherwise.
> + */
> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
> +				    const char *buf, size_t len)
> +{
> +	u8 val, user_reg;
> +	int ret;
> +
> +	ret = kstrtou8(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val > 1)
> +		return -EINVAL;
> +
> +	mutex_lock(&dev_data->lock);
> +	ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
> +	if (ret) {
> +		mutex_unlock(&dev_data->lock);
> +		return ret;
> +	}
> +
> +	user_reg &= 0xFB;
> +	user_reg |= val << 2;
> +
> +	ret = i2c_smbus_write_byte_data(dev_data->client,
> +					MS_SENSORS_USER_REG_WRITE,
> +					user_reg);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret) {
> +		dev_err(&dev_data->client->dev, "Unable to write user reg\n");
> +		return ret;
> +	}
> +
> +	return len;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
> +
> +/**
> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
> + * @dev_data:	pointer on temperature/humidity device data
> + * @temperature:pointer on temperature destination value
> + *
> + * That function will get temperature ADC value from the device,
> + * check the CRC and compute the temperature value.
> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
> +				       s32 *temperature)
> +{
> +	int ret;
> +	u32 adc;
> +	u16 delay;
> +
> +	mutex_lock(&dev_data->lock);
> +	delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
> +	ret = ms_sensors_i2c_convert_and_read(dev_data->client,
> +					      MS_SENSORS_HT_T_CONVERSION_START,
> +					      MS_SENSORS_NO_READ_CMD,
> +					      delay, &adc);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!ms_sensors_crc_valid(adc)) {
> +		dev_err(&dev_data->client->dev,
> +			"Temperature read crc check error\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Temperature algorithm */
> +	*temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
> +
> +/**
> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
> + * @dev_data:	pointer on temperature/humidity device data
> + * @humidity:	pointer on humidity destination value
> + *
> + * That function will get humidity ADC value from the device,
> + * check the CRC and compute the temperature value.
> + * That function is used for HTU21 and MS8607 chipsets
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
> +				    u32 *humidity)
> +{
> +	int ret;
> +	u32 adc;
> +	u16 delay;
> +
> +	mutex_lock(&dev_data->lock);
> +	delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
> +	ret = ms_sensors_i2c_convert_and_read(dev_data->client,
> +					      MS_SENSORS_HT_H_CONVERSION_START,
> +					      MS_SENSORS_NO_READ_CMD,
> +					      delay, &adc);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	if (!ms_sensors_crc_valid(adc)) {
> +		dev_err(&dev_data->client->dev,
> +			"Humidity read crc check error\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Humidity algorithm */
> +	*humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
> +	if (*humidity >= 100000)
> +		*humidity = 100000;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
> +
Multiline comment syntax is 
/*
 * CRC...
 */
 Or ideally use kernel-doc as you have for other functions below
 (not required as not exported)
 
> +/* CRC check function for Temperature and pressure devices
> + * That function is only used when reading PROM coefficients */
> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
> +{
> +	unsigned int cnt, n_bit;
> +	u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
> +
> +	prom[len - 1] = 0;
> +	prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
> +
> +	for (cnt = 0; cnt < len * 2; cnt++) {
> +		if (cnt % 2 == 1)
> +			n_rem ^= prom[cnt >> 1] & 0x00FF;
> +		else
> +			n_rem ^= prom[cnt >> 1] >> 8;
> +
> +		for (n_bit = 8; n_bit > 0; n_bit--) {
> +			if (n_rem & 0x8000)
> +				n_rem = (n_rem << 1) ^ 0x3000;
> +			else
> +				n_rem <<= 1;
> +		}
> +	}
> +	n_rem >>= 12;
> +	prom[0] = crc_read;
> +
> +	return n_rem == crc;
> +}
> +
> +/**
> + * ms_sensors_tp_read_prom() - prom coeff read function
> + * @dev_data:	pointer on temperature/pressure device data
pointer to temperature/... (fix throughout driver please)
> + *
> + * That function will read prom coefficients and check CRC
That -> This (and add a full stop at the end of the sentence.
> + * That function is used for MS5637 and MS8607 chipsets
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
> +		ret = ms_sensors_i2c_read_prom_word(
> +					dev_data->client,
> +					MS_SENSORS_TP_PROM_READ + (i << 1),
> +					&dev_data->prom[i]);
> +
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (!ms_sensors_tp_crc_valid(dev_data->prom,
> +				     MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
> +		dev_err(&dev_data->client->dev,
> +			"Calibration coefficients crc check error\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
> +
> +/**
> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
> + * @dev_data:	pointer on temperature/pressure device data
pointer to
> + * @temperature:pointer on temperature destination value
pointer to (also missing tab?)
> + * @pressure:	pointer on pressure destination value
> + *
> + * That function will read ADC and compute pressure and temperature value
That->This and full stop at end of sentence.

> + * That function is used for MS5637 and MS8607 chipsets
> + *
> + * Return: 0 on success, negative errno otherwise.
> + */
> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
> +				      int *temperature,
> +				      unsigned int *pressure)
> +{
> +	int ret;
> +	u32 t_adc, p_adc;
> +	s32 dt, temp;
> +	s64 off, sens, t2, off2, sens2;
> +	u16 *prom = dev_data->prom, delay;
> +	u8 i;
> +
> +	mutex_lock(&dev_data->lock);
> +	i = dev_data->res_index * 2;
> +	delay = ms_sensors_tp_conversion_time[dev_data->res_index];
Blank line here would improve readability.
> +	ret = ms_sensors_i2c_convert_and_read(
> +					dev_data->client,
> +					MS_SENSORS_TP_T_CONVERSION_START + i,
> +					MS_SENSORS_TP_ADC_READ,
> +					delay, &t_adc);
> +	if (ret) {
> +		mutex_unlock(&dev_data->lock);
> +		return ret;
> +	}
blank line here.
> +	ret = ms_sensors_i2c_convert_and_read(
> +					dev_data->client,
> +					MS_SENSORS_TP_P_CONVERSION_START + i,
> +					MS_SENSORS_TP_ADC_READ,
> +					delay, &p_adc);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	dt = (s32)t_adc - (prom[5] << 8);
> +
> +	/* Actual temperature = 2000 + dT * TEMPSENS */
> +	temp = 2000 + (((s64)dt * prom[6]) >> 23);
> +
> +	/* Second order temperature compensation */
> +	if (temp < 2000) {
> +		s64 tmp = (s64)temp - 2000;
> +
> +		t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
> +		off2 = (61 * tmp * tmp) >> 4;
> +		sens2 = (29 * tmp * tmp) >> 4;
> +
> +		if (temp < -1500) {
> +			s64 tmp = (s64)temp + 1500;
> +
> +			off2 += 17 * tmp * tmp;
> +			sens2 += 9 * tmp * tmp;
> +		}
> +	} else {
> +		t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
> +		off2 = 0;
> +		sens2 = 0;
> +	}
> +
> +	/* OFF = OFF_T1 + TCO * dT */
> +	off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
> +	off -= off2;
> +
> +	/* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
> +	sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
> +	sens -= sens2;
> +
> +	/* Temperature compensated pressure = D1 * SENS - OFF */
> +	*temperature = (temp - t2) * 10;
> +	*pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
> +
> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
> +MODULE_LICENSE("GPL v2");
> +
> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
> new file mode 100644
> index 0000000..a521428
> --- /dev/null
> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
> @@ -0,0 +1,54 @@
> +/*
> + * Measurements Specialties common sensor driver
> + *
> + * Copyright (c) 2015 Measurement-Specialties
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
Unnecesary blank line here.
> + */
> +
> +#ifndef _MS_SENSORS_I2C_H
> +#define _MS_SENSORS_I2C_H
> +
> +#include <linux/i2c.h>
> +#include <linux/mutex.h>
> +
> +#define MS_SENSORS_TP_PROM_WORDS_NB		7
> +
> +struct ms_ht_dev {
> +	struct i2c_client *client;
> +	struct mutex lock; /* mutex protecting data structure */
> +	u8 res_index;
> +};
> +
> +struct ms_tp_dev {
> +	struct i2c_client *client;
> +	struct mutex lock; /* mutex protecting data structure */
> +	/* Added element for CRC computation */
> +	u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
> +	u8 res_index;
> +};
> +
> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
> +				    unsigned int delay, u32 *adc);
> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
> +				    const char *buf, size_t len);
> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
> +				       s32 *temperature);
> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
> +				    u32 *humidity);
> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
> +				      int *temperature,
> +				      unsigned int *pressure);
> +
> +#endif /* _MS_SENSORS_I2C_H */
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support
  2015-07-30  9:25 ` [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support Ludovic Tancerel
@ 2015-08-08 17:03   ` Jonathan Cameron
  2015-08-08 17:04     ` Jonathan Cameron
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 17:03 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana

On 30/07/15 10:25, Ludovic Tancerel wrote:
> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
One little point inline (right at the end).

Jonathan
> ---
>  drivers/iio/temperature/Kconfig  |  11 ++
>  drivers/iio/temperature/Makefile |   1 +
>  drivers/iio/temperature/tsys01.c | 232 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 244 insertions(+)
>  create mode 100644 drivers/iio/temperature/tsys01.c
> 
> diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
> index 21feaa4..35712032 100644
> --- a/drivers/iio/temperature/Kconfig
> +++ b/drivers/iio/temperature/Kconfig
> @@ -23,4 +23,15 @@ config TMP006
>  	  This driver can also be built as a module. If so, the module will
>  	  be called tmp006.
>  
> +config TSYS01
> +	tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
> +	depends on I2C
> +	select IIO_MS_SENSORS_I2C
> +	help
> +	  If you say yes here you get support for the Measurement Specialties
> +	  TSYS01 I2C temperature sensor.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called tsys01.
> +
>  endmenu
> diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
> index 40710a8..368a2a2 100644
> --- a/drivers/iio/temperature/Makefile
> +++ b/drivers/iio/temperature/Makefile
> @@ -4,3 +4,4 @@
>  
>  obj-$(CONFIG_MLX90614) += mlx90614.o
>  obj-$(CONFIG_TMP006) += tmp006.o
> +obj-$(CONFIG_TSYS01) += tsys01.o
> diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
> new file mode 100644
> index 0000000..c863aaf
> --- /dev/null
> +++ b/drivers/iio/temperature/tsys01.c
> @@ -0,0 +1,232 @@
> +/*
> + * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
> + *
> + * Copyright (c) 2015 Measurement-Specialties
> + *
> + * Licensed under the GPL-2.
> + *
> + * Datasheet:
> + *  http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
> + *
> + */
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/device.h>
> +#include <linux/mutex.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/stat.h>
> +#include "../common/ms_sensors/ms_sensors_i2c.h"
> +
> +/* TSYS01 Commands */
> +#define TSYS01_RESET				0x1E
> +#define TSYS01_CONVERSION_START			0x48
> +#define TSYS01_ADC_READ				0x00
> +#define TSYS01_PROM_READ			0xA0
> +
> +#define TSYS01_PROM_WORDS_NB			8
> +
> +struct tsys01_dev {
> +	void *client;
> +	struct mutex lock; /* lock during conversion */
> +
> +	int (*reset)(void *cli, u8 cmd, unsigned int delay);
> +	int (*convert_and_read)(void *cli, u8 conv, u8 rd,
> +				unsigned int delay, u32 *adc);
> +	int (*read_prom_word)(void *cli, int cmd, u16 *word);
> +
> +	u16 prom[TSYS01_PROM_WORDS_NB];
> +};
> +
> +/* Multiplication coefficients for temperature computation */
> +static const int coeff_mul[] = { -1500000, 1000000, -2000000,
> +				 4000000, -2000000 };
> +
> +static int tsys01_read_temperature(struct iio_dev *indio_dev,
> +				   s32 *temperature)
> +{
> +	int ret, i;
> +	u32 adc;
> +	s64 temp = 0;
> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
> +
> +	mutex_lock(&dev_data->lock);
> +	ret = dev_data->convert_and_read(dev_data->client,
> +					 TSYS01_CONVERSION_START,
> +					 TSYS01_ADC_READ, 9000, &adc);
> +	mutex_unlock(&dev_data->lock);
> +	if (ret)
> +		return ret;
> +
> +	adc >>= 8;
> +
> +	/* Temperature algorithm */
> +	for (i = 4; i > 0; i--) {
> +		temp += coeff_mul[i] *
> +			(s64)dev_data->prom[5 - i];
> +		temp *= (s64)adc;
> +		temp = div64_s64(temp, 100000);
> +	}
> +	temp *= 10;
> +	temp += coeff_mul[0] * (s64)dev_data->prom[5];
> +	temp = div64_s64(temp, 100000);
> +
> +	*temperature = temp;
> +
> +	return 0;
> +}
> +
> +static int tsys01_read_raw(struct iio_dev *indio_dev,
> +			   struct iio_chan_spec const *channel, int *val,
> +			   int *val2, long mask)
> +{
> +	int ret;
> +	s32 temperature;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		switch (channel->type) {
> +		case IIO_TEMP:	/* in milli °C */
> +			ret = tsys01_read_temperature(indio_dev, &temperature);
> +			if (ret)
> +				return ret;
> +			*val = temperature;
> +
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_chan_spec tsys01_channels[] = {
> +	{
> +		.type = IIO_TEMP,
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
> +	}
> +};
> +
> +static const struct iio_info tsys01_info = {
> +	.read_raw = tsys01_read_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static bool tsys01_crc_valid(u16 *n_prom)
> +{
> +	u8 cnt;
> +	u8 sum = 0;
> +
> +	for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
> +		sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
> +
> +	return (sum == 0);
> +}
> +
> +static int tsys01_read_prom(struct iio_dev *indio_dev)
> +{
> +	int i, ret;
> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
> +	char buf[7 * TSYS01_PROM_WORDS_NB + 1];
> +	char *ptr = buf;
> +
> +	for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
> +		ret = dev_data->read_prom_word(dev_data->client,
> +					       TSYS01_PROM_READ + (i << 1),
> +					       &dev_data->prom[i]);
> +		if (ret)
> +			return ret;
> +
> +		ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
> +		ptr += ret;
> +	}
> +
> +	if (!tsys01_crc_valid(dev_data->prom)) {
> +		dev_err(&indio_dev->dev, "prom crc check error\n");
> +		return -ENODEV;
> +	}
> +	*ptr = 0;
> +	dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
> +
> +	return 0;
> +}
> +
> +static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
> +{
> +	int ret;
> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
> +
> +	mutex_init(&dev_data->lock);
> +
> +	indio_dev->info = &tsys01_info;
> +	indio_dev->name = dev->driver->name;
> +	indio_dev->dev.parent = dev;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = tsys01_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
> +
> +	ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
> +	if (ret)
> +		return ret;
> +
> +	ret = tsys01_read_prom(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	return devm_iio_device_register(dev, indio_dev);
> +}
> +
> +static int tsys01_i2c_probe(struct i2c_client *client,
> +			    const struct i2c_device_id *id)
> +{
> +	struct tsys01_dev *dev_data;
> +	struct iio_dev *indio_dev;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +				     I2C_FUNC_SMBUS_WORD_DATA |
> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
> +		dev_err(&client->dev,
> +			"Adapter does not support some i2c transaction\n");
> +		return -ENODEV;
> +	}
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	dev_data = iio_priv(indio_dev);
> +	dev_data->client = client;
> +	dev_data->reset = ms_sensors_i2c_reset;
> +	dev_data->read_prom_word = ms_sensors_i2c_read_prom_word;
> +	dev_data->convert_and_read = ms_sensors_i2c_convert_and_read;
> +
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	return tsys01_probe(indio_dev, &client->dev);
> +}
> +
> +static const struct i2c_device_id tsys01_id[] = {
> +	{"tsys01", 0},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(i2c, tsys01_id);
> +
> +static struct i2c_driver tsys01_driver = {
> +	.probe = tsys01_i2c_probe,
> +	.id_table = tsys01_id,
> +	.driver = {
> +		   .name = "tsys01",
> +		   .owner = THIS_MODULE,
Don't need to assign the .owner anymore as i2c_register_driver
(part of the module_i2c_driver macro) will do it.

> +		   },
> +};
> +
> +module_i2c_driver(tsys01_driver);
> +
> +MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support
  2015-08-08 17:03   ` Jonathan Cameron
@ 2015-08-08 17:04     ` Jonathan Cameron
  0 siblings, 0 replies; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 17:04 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana

On 08/08/15 18:03, Jonathan Cameron wrote:
> On 30/07/15 10:25, Ludovic Tancerel wrote:
>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
> One little point inline (right at the end).
One more thing, could you mention the type of sensor in the patch title.
Will make keeping track of which is which easier ;)

Also a brief description of the part in a new driver patch is always good 
(above the signed-off-by:)
> 
> Jonathan
>> ---
>>  drivers/iio/temperature/Kconfig  |  11 ++
>>  drivers/iio/temperature/Makefile |   1 +
>>  drivers/iio/temperature/tsys01.c | 232 +++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 244 insertions(+)
>>  create mode 100644 drivers/iio/temperature/tsys01.c
>>
>> diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
>> index 21feaa4..35712032 100644
>> --- a/drivers/iio/temperature/Kconfig
>> +++ b/drivers/iio/temperature/Kconfig
>> @@ -23,4 +23,15 @@ config TMP006
>>  	  This driver can also be built as a module. If so, the module will
>>  	  be called tmp006.
>>  
>> +config TSYS01
>> +	tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
>> +	depends on I2C
>> +	select IIO_MS_SENSORS_I2C
>> +	help
>> +	  If you say yes here you get support for the Measurement Specialties
>> +	  TSYS01 I2C temperature sensor.
>> +
>> +	  This driver can also be built as a module. If so, the module will
>> +	  be called tsys01.
>> +
>>  endmenu
>> diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
>> index 40710a8..368a2a2 100644
>> --- a/drivers/iio/temperature/Makefile
>> +++ b/drivers/iio/temperature/Makefile
>> @@ -4,3 +4,4 @@
>>  
>>  obj-$(CONFIG_MLX90614) += mlx90614.o
>>  obj-$(CONFIG_TMP006) += tmp006.o
>> +obj-$(CONFIG_TSYS01) += tsys01.o
>> diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
>> new file mode 100644
>> index 0000000..c863aaf
>> --- /dev/null
>> +++ b/drivers/iio/temperature/tsys01.c
>> @@ -0,0 +1,232 @@
>> +/*
>> + * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
>> + *
>> + * Copyright (c) 2015 Measurement-Specialties
>> + *
>> + * Licensed under the GPL-2.
>> + *
>> + * Datasheet:
>> + *  http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
>> + *
>> + */
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/sysfs.h>
>> +#include <linux/device.h>
>> +#include <linux/mutex.h>
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/stat.h>
>> +#include "../common/ms_sensors/ms_sensors_i2c.h"
>> +
>> +/* TSYS01 Commands */
>> +#define TSYS01_RESET				0x1E
>> +#define TSYS01_CONVERSION_START			0x48
>> +#define TSYS01_ADC_READ				0x00
>> +#define TSYS01_PROM_READ			0xA0
>> +
>> +#define TSYS01_PROM_WORDS_NB			8
>> +
>> +struct tsys01_dev {
>> +	void *client;
>> +	struct mutex lock; /* lock during conversion */
>> +
>> +	int (*reset)(void *cli, u8 cmd, unsigned int delay);
>> +	int (*convert_and_read)(void *cli, u8 conv, u8 rd,
>> +				unsigned int delay, u32 *adc);
>> +	int (*read_prom_word)(void *cli, int cmd, u16 *word);
>> +
>> +	u16 prom[TSYS01_PROM_WORDS_NB];
>> +};
>> +
>> +/* Multiplication coefficients for temperature computation */
>> +static const int coeff_mul[] = { -1500000, 1000000, -2000000,
>> +				 4000000, -2000000 };
>> +
>> +static int tsys01_read_temperature(struct iio_dev *indio_dev,
>> +				   s32 *temperature)
>> +{
>> +	int ret, i;
>> +	u32 adc;
>> +	s64 temp = 0;
>> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
>> +
>> +	mutex_lock(&dev_data->lock);
>> +	ret = dev_data->convert_and_read(dev_data->client,
>> +					 TSYS01_CONVERSION_START,
>> +					 TSYS01_ADC_READ, 9000, &adc);
>> +	mutex_unlock(&dev_data->lock);
>> +	if (ret)
>> +		return ret;
>> +
>> +	adc >>= 8;
>> +
>> +	/* Temperature algorithm */
>> +	for (i = 4; i > 0; i--) {
>> +		temp += coeff_mul[i] *
>> +			(s64)dev_data->prom[5 - i];
>> +		temp *= (s64)adc;
>> +		temp = div64_s64(temp, 100000);
>> +	}
>> +	temp *= 10;
>> +	temp += coeff_mul[0] * (s64)dev_data->prom[5];
>> +	temp = div64_s64(temp, 100000);
>> +
>> +	*temperature = temp;
>> +
>> +	return 0;
>> +}
>> +
>> +static int tsys01_read_raw(struct iio_dev *indio_dev,
>> +			   struct iio_chan_spec const *channel, int *val,
>> +			   int *val2, long mask)
>> +{
>> +	int ret;
>> +	s32 temperature;
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_PROCESSED:
>> +		switch (channel->type) {
>> +		case IIO_TEMP:	/* in milli °C */
>> +			ret = tsys01_read_temperature(indio_dev, &temperature);
>> +			if (ret)
>> +				return ret;
>> +			*val = temperature;
>> +
>> +			return IIO_VAL_INT;
>> +		default:
>> +			return -EINVAL;
>> +		}
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static const struct iio_chan_spec tsys01_channels[] = {
>> +	{
>> +		.type = IIO_TEMP,
>> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>> +	}
>> +};
>> +
>> +static const struct iio_info tsys01_info = {
>> +	.read_raw = tsys01_read_raw,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +static bool tsys01_crc_valid(u16 *n_prom)
>> +{
>> +	u8 cnt;
>> +	u8 sum = 0;
>> +
>> +	for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
>> +		sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
>> +
>> +	return (sum == 0);
>> +}
>> +
>> +static int tsys01_read_prom(struct iio_dev *indio_dev)
>> +{
>> +	int i, ret;
>> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
>> +	char buf[7 * TSYS01_PROM_WORDS_NB + 1];
>> +	char *ptr = buf;
>> +
>> +	for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
>> +		ret = dev_data->read_prom_word(dev_data->client,
>> +					       TSYS01_PROM_READ + (i << 1),
>> +					       &dev_data->prom[i]);
>> +		if (ret)
>> +			return ret;
>> +
>> +		ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
>> +		ptr += ret;
>> +	}
>> +
>> +	if (!tsys01_crc_valid(dev_data->prom)) {
>> +		dev_err(&indio_dev->dev, "prom crc check error\n");
>> +		return -ENODEV;
>> +	}
>> +	*ptr = 0;
>> +	dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
>> +{
>> +	int ret;
>> +	struct tsys01_dev *dev_data = iio_priv(indio_dev);
>> +
>> +	mutex_init(&dev_data->lock);
>> +
>> +	indio_dev->info = &tsys01_info;
>> +	indio_dev->name = dev->driver->name;
>> +	indio_dev->dev.parent = dev;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->channels = tsys01_channels;
>> +	indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
>> +
>> +	ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = tsys01_read_prom(indio_dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return devm_iio_device_register(dev, indio_dev);
>> +}
>> +
>> +static int tsys01_i2c_probe(struct i2c_client *client,
>> +			    const struct i2c_device_id *id)
>> +{
>> +	struct tsys01_dev *dev_data;
>> +	struct iio_dev *indio_dev;
>> +
>> +	if (!i2c_check_functionality(client->adapter,
>> +				     I2C_FUNC_SMBUS_WORD_DATA |
>> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
>> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
>> +		dev_err(&client->dev,
>> +			"Adapter does not support some i2c transaction\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	dev_data = iio_priv(indio_dev);
>> +	dev_data->client = client;
>> +	dev_data->reset = ms_sensors_i2c_reset;
>> +	dev_data->read_prom_word = ms_sensors_i2c_read_prom_word;
>> +	dev_data->convert_and_read = ms_sensors_i2c_convert_and_read;
>> +
>> +	i2c_set_clientdata(client, indio_dev);
>> +
>> +	return tsys01_probe(indio_dev, &client->dev);
>> +}
>> +
>> +static const struct i2c_device_id tsys01_id[] = {
>> +	{"tsys01", 0},
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(i2c, tsys01_id);
>> +
>> +static struct i2c_driver tsys01_driver = {
>> +	.probe = tsys01_i2c_probe,
>> +	.id_table = tsys01_id,
>> +	.driver = {
>> +		   .name = "tsys01",
>> +		   .owner = THIS_MODULE,
> Don't need to assign the .owner anymore as i2c_register_driver
> (part of the module_i2c_driver macro) will do it.
> 
>> +		   },
>> +};
>> +
>> +module_i2c_driver(tsys01_driver);
>> +
>> +MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>> +MODULE_LICENSE("GPL v2");
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 3/6] iio: Add tsys02d meas-spec driver support
  2015-07-30  9:25 ` [PATCH V2 3/6] iio: Add tsys02d " Ludovic Tancerel
@ 2015-08-08 17:15   ` Jonathan Cameron
  2015-08-09 12:33     ` Guenter Roeck
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 17:15 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana, Guenter Roeck, Jean Delvare

On 30/07/15 10:25, Ludovic Tancerel wrote:
The battery low indicator is certainly 'unusual' and undocumented on the
datasheet mentioned here.

Ah well.  Same owner point as with the previous driver. Otherwise
seems fine to me.  Have cc'd the hwmon guys in case they have comments.

Guenter / Jean, I would be more doubtful about having what is basically
a straight forward (if accurate) temperature IC in IIO except that
this is part of a series of parts including humidity and pressure sensors
in combined forms which are more common IIO fodder.

Jonathan
> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
> ---
>  Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
>  drivers/iio/temperature/Kconfig                   |  11 ++
>  drivers/iio/temperature/Makefile                  |   1 +
>  drivers/iio/temperature/tsys02d.c                 | 193 ++++++++++++++++++++++
>  4 files changed, 212 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>  create mode 100644 drivers/iio/temperature/tsys02d.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> new file mode 100644
> index 0000000..6d47e54
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> @@ -0,0 +1,7 @@
> +What:           /sys/bus/iio/devices/iio:deviceX/battery_low
> +KernelVersion:  4.1.0
> +Contact:        linux-iio@vger.kernel.org
> +Description:
> +                Reading returns either '1' or '0'. '1' means that the
> +                battery level supplied to sensor is below 2.25V.
> +                This ABI is available for tsys02d, htu21, ms8607

Hmm. This one is odd to find in IIO.  Also I can't actually find
reference to it on the datasheet.

You are quite correct in thinking this is device specific abi and
documenting it as you have.

Not sure we can do much else...
> diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
> index 35712032..c4664e5 100644
> --- a/drivers/iio/temperature/Kconfig
> +++ b/drivers/iio/temperature/Kconfig
> @@ -34,4 +34,15 @@ config TSYS01
>  	  This driver can also be built as a module. If so, the module will
>  	  be called tsys01.
>  
> +config TSYS02D
> +	tristate "Measurement Specialties TSYS02D temperature sensor"
> +	depends on I2C
> +	select IIO_MS_SENSORS_I2C
> +	help
> +	  If you say yes here you get support for the Measurement Specialties
> +	  TSYS02D temperature sensor.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called tsys02d.
> +
>  endmenu
> diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
> index 368a2a2..02bc79d 100644
> --- a/drivers/iio/temperature/Makefile
> +++ b/drivers/iio/temperature/Makefile
> @@ -5,3 +5,4 @@
>  obj-$(CONFIG_MLX90614) += mlx90614.o
>  obj-$(CONFIG_TMP006) += tmp006.o
>  obj-$(CONFIG_TSYS01) += tsys01.o
> +obj-$(CONFIG_TSYS02D) += tsys02d.o
> diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
> new file mode 100644
> index 0000000..6971dab
> --- /dev/null
> +++ b/drivers/iio/temperature/tsys02d.c
> @@ -0,0 +1,193 @@
> +/*
> + * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
> + *
> + * Copyright (c) 2015 Measurement-Specialties
> + *
> + * Licensed under the GPL-2.
> + *
> + * (7-bit I2C slave address 0x40)
> + *
> + * Datasheet:
> + *  http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/stat.h>
> +#include <linux/module.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +
> +#include "../common/ms_sensors/ms_sensors_i2c.h"
> +
> +#define TSYS02D_RESET				0xFE
> +
> +static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
> +/* String copy of the above const for readability purpose */
> +static const char tsys02d_show_samp_freq[] = "20 40 70 140";
> +
> +static int tsys02d_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *channel, int *val,
> +			    int *val2, long mask)
> +{
> +	int ret;
> +	s32 temperature;
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		switch (channel->type) {
> +		case IIO_TEMP:	/* in milli °C */
> +			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
> +								 &temperature);
> +			if (ret)
> +				return ret;
> +			*val = temperature;
> +
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		*val = tsys02d_samp_freq[dev_data->res_index];
> +
> +		return IIO_VAL_INT;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int tsys02d_write_raw(struct iio_dev *indio_dev,
> +			     struct iio_chan_spec const *chan,
> +			     int val, int val2, long mask)
> +{
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +	int i, ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		i = ARRAY_SIZE(tsys02d_samp_freq);
> +		while (i-- > 0)
> +			if (val == tsys02d_samp_freq[i])
> +				break;
> +		if (i < 0)
> +			return -EINVAL;
> +		mutex_lock(&dev_data->lock);
> +		dev_data->res_index = i;
> +		ret = ms_sensors_i2c_write_resolution(dev_data, i);
> +		mutex_unlock(&dev_data->lock);
> +
> +		return ret;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_chan_spec tsys02d_channels[] = {
> +	{
> +		.type = IIO_TEMP,
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +	}
> +};
> +
> +static ssize_t tsys02_read_battery_low(struct device *dev,
> +				       struct device_attribute *attr,
> +				       char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	return ms_sensors_i2c_show_battery_low(dev_data, buf);
> +}
> +
> +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
> +static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
> +		       tsys02_read_battery_low, NULL, 0);
> +
> +static struct attribute *tsys02d_attributes[] = {
> +	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
> +	&iio_dev_attr_battery_low.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group tsys02d_attribute_group = {
> +	.attrs = tsys02d_attributes,
> +};
> +
> +static const struct iio_info tsys02d_info = {
> +	.read_raw = tsys02d_read_raw,
> +	.write_raw = tsys02d_write_raw,
> +	.attrs = &tsys02d_attribute_group,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +int tsys02d_probe(struct i2c_client *client,
> +		  const struct i2c_device_id *id)
> +{
> +	struct ms_ht_dev *dev_data;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u64 serial_number;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
> +		dev_err(&client->dev,
> +			"Adapter does not support some i2c transaction\n");
> +		return -ENODEV;
> +	}
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	dev_data = iio_priv(indio_dev);
> +	dev_data->client = client;
> +	dev_data->res_index = 0;
> +	mutex_init(&dev_data->lock);
> +
> +	indio_dev->info = &tsys02d_info;
> +	indio_dev->name = id->name;
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = tsys02d_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
> +
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = ms_sensors_i2c_reset(client, TSYS02D_RESET, 15000);
> +	if (ret)
> +		return ret;
> +
> +	ret = ms_sensors_i2c_read_serial(client, &serial_number);
> +	if (ret)
> +		return ret;
> +	dev_info(&client->dev, "Serial number : %llx", serial_number);
> +
> +	return devm_iio_device_register(&client->dev, indio_dev);
> +}
> +
> +static const struct i2c_device_id tsys02d_id[] = {
> +	{"tsys02d", 0},
> +	{}
> +};
> +
> +static struct i2c_driver tsys02d_driver = {
> +	.probe = tsys02d_probe,
> +	.id_table = tsys02d_id,
> +	.driver = {
> +		   .name = "tsys02d",
> +		   .owner = THIS_MODULE,
Again, don't set owner (I'll only get a patch removing it a few days after
taking this one otherwise!)
> +		   },
> +};
> +
> +module_i2c_driver(tsys02d_driver);
> +
> +MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 4/6] iio: Add htu21 meas-spec driver support
  2015-07-30  9:25 ` [PATCH V2 4/6] iio: Add htu21 " Ludovic Tancerel
@ 2015-08-08 17:17   ` Jonathan Cameron
  0 siblings, 0 replies; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 17:17 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana

On 30/07/15 10:25, Ludovic Tancerel wrote:
> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
A quick comment inline.  Otherwise, the owner thing again.

Looking good.

Jonathan
> ---
>  Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
>  drivers/iio/humidity/Kconfig                      |  11 ++
>  drivers/iio/humidity/Makefile                     |   1 +
>  drivers/iio/humidity/htu21.c                      | 228 ++++++++++++++++++++++
>  4 files changed, 247 insertions(+)
>  create mode 100644 drivers/iio/humidity/htu21.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> index 6d47e54..7b09d3a 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> @@ -5,3 +5,10 @@ Description:
>                  Reading returns either '1' or '0'. '1' means that the
>                  battery level supplied to sensor is below 2.25V.
>                  This ABI is available for tsys02d, htu21, ms8607
> +What:           /sys/bus/iio/devices/iio:deviceX/heater_enable
> +KernelVersion:  4.1.0
> +Contact:        linux-iio@vger.kernel.org
> +Description:
> +                Enable or disable heater function by writing either
> +		'1' or '0'.
> +                Same reading values apply
This one is common enough for humidity sensors that perhaps we should
move it into the main abi docs?
> diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
> index 4813b79..447a833 100644
> --- a/drivers/iio/humidity/Kconfig
> +++ b/drivers/iio/humidity/Kconfig
> @@ -12,6 +12,17 @@ config DHT11
>  	  Other sensors should work as well as long as they speak the
>  	  same protocol.
>  
> +config HTU21
> +	tristate "Measurement Specialties HTU21 humidity & temperature sensor"
> +	depends on I2C
> +        select IIO_MS_SENSORS_I2C
> +	help
> +	  If you say yes here you get support for the Measurement Specialties
> +	  HTU21 humidity and temperature sensor.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called htu21.
> +
>  config SI7005
>  	tristate "SI7005 relative humidity and temperature sensor"
>  	depends on I2C
> diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
> index 86e2d26..826b1d5 100644
> --- a/drivers/iio/humidity/Makefile
> +++ b/drivers/iio/humidity/Makefile
> @@ -3,5 +3,6 @@
>  #
>  
>  obj-$(CONFIG_DHT11) += dht11.o
> +obj-$(CONFIG_HTU21) += htu21.o
>  obj-$(CONFIG_SI7005) += si7005.o
>  obj-$(CONFIG_SI7020) += si7020.o
> diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
> new file mode 100644
> index 0000000..870b631
> --- /dev/null
> +++ b/drivers/iio/humidity/htu21.c
> @@ -0,0 +1,228 @@
> +/*
> + * htu21.c - Support for Measurement-Specialties
> + *           htu21 temperature & humidity sensor
> + *
> + * Copyright (c) 2014 Measurement-Specialties
> + *
> + * Licensed under the GPL-2.
> + *
> + * (7-bit I2C slave address 0x40)
> + *
> + * Datasheet:
> + *  http://www.meas-spec.com/downloads/HTU21D.pdf
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/stat.h>
> +#include <linux/module.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +
> +#include "../common/ms_sensors/ms_sensors_i2c.h"
> +
> +#define HTU21_RESET				0xFE
> +
> +static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
> +/* String copy of the above const for readability purpose */
> +static const char htu21_show_samp_freq[] = "20 40 70 120";
> +
> +static int htu21_read_raw(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *channel, int *val,
> +			  int *val2, long mask)
> +{
> +	int ret, temperature;
> +	unsigned int humidity;
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_PROCESSED:
> +		switch (channel->type) {
> +		case IIO_TEMP:	/* in milli °C */
> +			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
> +								 &temperature);
> +			if (ret)
> +				return ret;
> +			*val = temperature;
> +
> +			return IIO_VAL_INT;
> +		case IIO_HUMIDITYRELATIVE:	/* in milli %RH */
> +			ret = ms_sensors_i2c_ht_read_humidity(dev_data,
> +							      &humidity);
> +			if (ret)
> +				return ret;
> +			*val = humidity;
> +
> +			return IIO_VAL_INT;
> +		default:
> +			return -EINVAL;
> +		}
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		*val = htu21_samp_freq[dev_data->res_index];
> +
> +		return IIO_VAL_INT;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int htu21_write_raw(struct iio_dev *indio_dev,
> +			   struct iio_chan_spec const *chan,
> +			   int val, int val2, long mask)
> +{
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +	int i, ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		i = ARRAY_SIZE(htu21_samp_freq);
> +		while (i-- > 0)
> +			if (val == htu21_samp_freq[i])
> +				break;
> +		if (i < 0)
> +			return -EINVAL;
> +		mutex_lock(&dev_data->lock);
> +		dev_data->res_index = i;
> +		ret = ms_sensors_i2c_write_resolution(dev_data, i);
> +		mutex_unlock(&dev_data->lock);
> +
> +		return ret;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static const struct iio_chan_spec htu21_channels[] = {
> +	{
> +		.type = IIO_TEMP,
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +	 },
> +	{
> +		.type = IIO_HUMIDITYRELATIVE,
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +	 }
> +};
> +
> +static ssize_t htu21_show_battery_low(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	return ms_sensors_i2c_show_battery_low(dev_data, buf);
> +}
> +
> +static ssize_t htu21_show_heater(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	return ms_sensors_i2c_show_heater(dev_data, buf);
> +}
> +
> +static ssize_t htu21_write_heater(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
> +
> +	return ms_sensors_i2c_write_heater(dev_data, buf, len);
> +}
> +
> +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
> +static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
> +		       htu21_show_battery_low, NULL, 0);
> +static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
> +		       htu21_show_heater, htu21_write_heater, 0);
> +
> +static struct attribute *htu21_attributes[] = {
> +	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
> +	&iio_dev_attr_battery_low.dev_attr.attr,
> +	&iio_dev_attr_heater_enable.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group htu21_attribute_group = {
> +	.attrs = htu21_attributes,
> +};
> +
> +static const struct iio_info htu21_info = {
> +	.read_raw = htu21_read_raw,
> +	.write_raw = htu21_write_raw,
> +	.attrs = &htu21_attribute_group,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +int htu21_probe(struct i2c_client *client,
> +		const struct i2c_device_id *id)
> +{
> +	struct ms_ht_dev *dev_data;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +	u64 serial_number;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
> +		dev_err(&client->dev,
> +			"Adapter does not support some i2c transaction\n");
> +		return -ENODEV;
> +	}
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	dev_data = iio_priv(indio_dev);
> +	dev_data->client = client;
> +	dev_data->res_index = 0;
> +	mutex_init(&dev_data->lock);
> +
> +	indio_dev->info = &htu21_info;
> +	indio_dev->name = id->name;
> +	indio_dev->dev.parent = &client->dev;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = htu21_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
> +
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	ret = ms_sensors_i2c_reset(client, HTU21_RESET, 15000);
> +	if (ret)
> +		return ret;
> +
> +	ret = ms_sensors_i2c_read_serial(client, &serial_number);
> +	if (ret)
> +		return ret;
> +	dev_info(&client->dev, "Serial number : %llx", serial_number);
> +
> +	return devm_iio_device_register(&client->dev, indio_dev);
> +}
> +
> +static const struct i2c_device_id htu21_id[] = {
> +	{"htu21", 0},
> +	{}
> +};
> +
> +static struct i2c_driver htu21_driver = {
> +	.probe = htu21_probe,
> +	.id_table = htu21_id,
> +	.driver = {
> +		   .name = "htu21",
> +		   .owner = THIS_MODULE,
> +		   },
> +};
> +
> +module_i2c_driver(htu21_driver);
> +
> +MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
> +MODULE_LICENSE("GPL v2");
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 6/6] iio: Add ms8607 meas-spec driver support
  2015-07-30  9:25 ` [PATCH V2 6/6] iio: Add ms8607 " Ludovic Tancerel
@ 2015-08-08 17:22   ` Jonathan Cameron
  2015-09-25  9:25     ` ludovic.tancerel
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-08 17:22 UTC (permalink / raw)
  To: Ludovic Tancerel, knaack.h, lars, pmeerw, linux-iio,
	William.Markezana

On 30/07/15 10:25, Ludovic Tancerel wrote:
> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
Little bits inline.

A nice looking patch set.  I was unsure the division made sense between the
core and the drivers, but it seems to work well.
Will be interesting to see what other parts measurement specialties comes out
with in the future!

Jonathan
> ---
>  Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  1 +
>  drivers/iio/humidity/htu21.c                      | 32 ++++++++++++++++++++---
>  drivers/iio/pressure/Kconfig                      | 13 +++++++++
>  drivers/iio/pressure/ms5637.c                     |  6 ++++-
>  4 files changed, 48 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> index 7b09d3a..df70dda6 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
> @@ -12,3 +12,4 @@ Description:
>                  Enable or disable heater function by writing either
>  		'1' or '0'.
>                  Same reading values apply
> +		This ABI is available for htu21, ms8607
> diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
> index 870b631..4720cbc 100644
> --- a/drivers/iio/humidity/htu21.c
> +++ b/drivers/iio/humidity/htu21.c
> @@ -1,6 +1,7 @@
>  /*
>   * htu21.c - Support for Measurement-Specialties
>   *           htu21 temperature & humidity sensor
> + *	     and humidity part of MS8607 sensor
>   *
>   * Copyright (c) 2014 Measurement-Specialties
>   *
> @@ -10,6 +11,8 @@
>   *
>   * Datasheet:
>   *  http://www.meas-spec.com/downloads/HTU21D.pdf
> + * Datasheet:
> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>   *
>   */
>  
> @@ -25,6 +28,11 @@
>  
>  #define HTU21_RESET				0xFE
>  
> +enum {
> +	HTU21,
> +	MS8607
> +};
> +
>  static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
>  /* String copy of the above const for readability purpose */
>  static const char htu21_show_samp_freq[] = "20 40 70 120";
> @@ -107,6 +115,17 @@ static const struct iio_chan_spec htu21_channels[] = {
>  	 }
>  };
>  
> +/* Meas Spec recommendation is to not read temperature
/*
 * Meas
> + * on this driver part for MS8607
> + */
> +static const struct iio_chan_spec ms8607_channels[] = {
> +	{
> +		.type = IIO_HUMIDITYRELATIVE,
> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +	 }
> +};
> +
>  static ssize_t htu21_show_battery_low(struct device *dev,
>  				      struct device_attribute *attr, char *buf)
>  {
> @@ -189,8 +208,14 @@ int htu21_probe(struct i2c_client *client,
>  	indio_dev->name = id->name;
>  	indio_dev->dev.parent = &client->dev;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->channels = htu21_channels;
> -	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
> +
> +	if (id->driver_data == MS8607) {
> +		indio_dev->channels = ms8607_channels;
> +		indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
> +	} else {
> +		indio_dev->channels = htu21_channels;
> +		indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
> +	}
>  
>  	i2c_set_clientdata(client, indio_dev);
>  
> @@ -207,7 +232,8 @@ int htu21_probe(struct i2c_client *client,
>  }
>  
>  static const struct i2c_device_id htu21_id[] = {
> -	{"htu21", 0},
> +	{"htu21", HTU21},
> +	{"ms8607-h", MS8607},
perhaps -humidity for clarity if not already in use out in the field.
>  	{}
>  };
>  
> diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
> index 8142cfe..e6a7fd5 100644
> --- a/drivers/iio/pressure/Kconfig
> +++ b/drivers/iio/pressure/Kconfig
> @@ -90,6 +90,19 @@ config MS5637
>  	  This driver can also be built as a module. If so, the module will
>  	  be called ms5637.
>  
> +config MS8607
> +	tristate "Measurement Specialties MS8607 pressure, temperature & humidity sensor"
> +	depends on I2C
> +        select IIO_MS_SENSORS_I2C
> +        select HTU21
> +        select MS5637
> +	help
> +	  If you say yes here you get support for the Measurement Specialties
> +	  MS8607 pressure, temperature and humidity sensor.
> +
> +	  This is based on HTU21 and MS5637 drivers. If built as a module,
> +	  modules to load will be htu21 and ms5637.
> +
Don't bother with the separate kconfig entry.  Just make sure the help texts for
the other two make it clear that they also support part of this device.

>  config IIO_ST_PRESS
>  	tristate "STMicroelectronics pressure sensor Driver"
>  	depends on (I2C || SPI_MASTER) && SYSFS
> diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
> index e2073fd..c185aa0 100644
> --- a/drivers/iio/pressure/ms5637.c
> +++ b/drivers/iio/pressure/ms5637.c
> @@ -1,5 +1,5 @@
>  /*
> - * ms5637.c - Support for Measurement-Specialties ms5637
> + * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
>   *            pressure & temperature sensor
>   *
>   * Copyright (c) 2015 Measurement-Specialties
> @@ -10,8 +10,11 @@
>   *
>   * Datasheet:
>   *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
> + * Datasheet:
> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>   *
>   */
> +
>  #include <linux/init.h>
>  #include <linux/device.h>
>  #include <linux/kernel.h>
> @@ -168,6 +171,7 @@ static int ms5637_probe(struct i2c_client *client,
>  
>  static const struct i2c_device_id ms5637_id[] = {
>  	{"ms5637", 0},
> +	{"ms8607-tp", 1},
Perhaps -temp for extra clarity (or are there devices out there already
using this naming?)
>  	{}
>  };
>  
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 3/6] iio: Add tsys02d meas-spec driver support
  2015-08-08 17:15   ` Jonathan Cameron
@ 2015-08-09 12:33     ` Guenter Roeck
  2015-08-09 20:13       ` Hartmut Knaack
  0 siblings, 1 reply; 25+ messages in thread
From: Guenter Roeck @ 2015-08-09 12:33 UTC (permalink / raw)
  To: Jonathan Cameron, Ludovic Tancerel, knaack.h, lars, pmeerw,
	linux-iio, William.Markezana, Jean Delvare

On 08/08/2015 10:15 AM, Jonathan Cameron wrote:
> On 30/07/15 10:25, Ludovic Tancerel wrote:
> The battery low indicator is certainly 'unusual' and undocumented on the
> datasheet mentioned here.
>
> Ah well.  Same owner point as with the previous driver. Otherwise
> seems fine to me.  Have cc'd the hwmon guys in case they have comments.
>
> Guenter / Jean, I would be more doubtful about having what is basically
> a straight forward (if accurate) temperature IC in IIO except that
> this is part of a series of parts including humidity and pressure sensors
> in combined forms which are more common IIO fodder.

Agreed; I would really not like to have common code between iio and hwmon.

Does the series include support for htu21d ? If so, we should probably drop
that driver from hwmon after it is available in iio.

Thanks,
Guenter

>
> Jonathan
>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>> ---
>>   Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
>>   drivers/iio/temperature/Kconfig                   |  11 ++
>>   drivers/iio/temperature/Makefile                  |   1 +
>>   drivers/iio/temperature/tsys02d.c                 | 193 ++++++++++++++++++++++
>>   4 files changed, 212 insertions(+)
>>   create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>   create mode 100644 drivers/iio/temperature/tsys02d.c
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>> new file mode 100644
>> index 0000000..6d47e54
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>> @@ -0,0 +1,7 @@
>> +What:           /sys/bus/iio/devices/iio:deviceX/battery_low
>> +KernelVersion:  4.1.0
>> +Contact:        linux-iio@vger.kernel.org
>> +Description:
>> +                Reading returns either '1' or '0'. '1' means that the
>> +                battery level supplied to sensor is below 2.25V.
>> +                This ABI is available for tsys02d, htu21, ms8607
>
> Hmm. This one is odd to find in IIO.  Also I can't actually find
> reference to it on the datasheet.
>
> You are quite correct in thinking this is device specific abi and
> documenting it as you have.
>
> Not sure we can do much else...
>> diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
>> index 35712032..c4664e5 100644
>> --- a/drivers/iio/temperature/Kconfig
>> +++ b/drivers/iio/temperature/Kconfig
>> @@ -34,4 +34,15 @@ config TSYS01
>>   	  This driver can also be built as a module. If so, the module will
>>   	  be called tsys01.
>>
>> +config TSYS02D
>> +	tristate "Measurement Specialties TSYS02D temperature sensor"
>> +	depends on I2C
>> +	select IIO_MS_SENSORS_I2C
>> +	help
>> +	  If you say yes here you get support for the Measurement Specialties
>> +	  TSYS02D temperature sensor.
>> +
>> +	  This driver can also be built as a module. If so, the module will
>> +	  be called tsys02d.
>> +
>>   endmenu
>> diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
>> index 368a2a2..02bc79d 100644
>> --- a/drivers/iio/temperature/Makefile
>> +++ b/drivers/iio/temperature/Makefile
>> @@ -5,3 +5,4 @@
>>   obj-$(CONFIG_MLX90614) += mlx90614.o
>>   obj-$(CONFIG_TMP006) += tmp006.o
>>   obj-$(CONFIG_TSYS01) += tsys01.o
>> +obj-$(CONFIG_TSYS02D) += tsys02d.o
>> diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
>> new file mode 100644
>> index 0000000..6971dab
>> --- /dev/null
>> +++ b/drivers/iio/temperature/tsys02d.c
>> @@ -0,0 +1,193 @@
>> +/*
>> + * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
>> + *
>> + * Copyright (c) 2015 Measurement-Specialties
>> + *
>> + * Licensed under the GPL-2.
>> + *
>> + * (7-bit I2C slave address 0x40)
>> + *
>> + * Datasheet:
>> + *  http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
>> + *
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/stat.h>
>> +#include <linux/module.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/sysfs.h>
>> +
>> +#include "../common/ms_sensors/ms_sensors_i2c.h"
>> +
>> +#define TSYS02D_RESET				0xFE
>> +
>> +static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
>> +/* String copy of the above const for readability purpose */
>> +static const char tsys02d_show_samp_freq[] = "20 40 70 140";
>> +
>> +static int tsys02d_read_raw(struct iio_dev *indio_dev,
>> +			    struct iio_chan_spec const *channel, int *val,
>> +			    int *val2, long mask)
>> +{
>> +	int ret;
>> +	s32 temperature;
>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_PROCESSED:
>> +		switch (channel->type) {
>> +		case IIO_TEMP:	/* in milli °C */
>> +			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
>> +								 &temperature);
>> +			if (ret)
>> +				return ret;
>> +			*val = temperature;
>> +
>> +			return IIO_VAL_INT;
>> +		default:
>> +			return -EINVAL;
>> +		}
>> +	case IIO_CHAN_INFO_SAMP_FREQ:
>> +		*val = tsys02d_samp_freq[dev_data->res_index];
>> +
>> +		return IIO_VAL_INT;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int tsys02d_write_raw(struct iio_dev *indio_dev,
>> +			     struct iio_chan_spec const *chan,
>> +			     int val, int val2, long mask)
>> +{
>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>> +	int i, ret;
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_SAMP_FREQ:
>> +		i = ARRAY_SIZE(tsys02d_samp_freq);
>> +		while (i-- > 0)
>> +			if (val == tsys02d_samp_freq[i])
>> +				break;
>> +		if (i < 0)
>> +			return -EINVAL;
>> +		mutex_lock(&dev_data->lock);
>> +		dev_data->res_index = i;
>> +		ret = ms_sensors_i2c_write_resolution(dev_data, i);
>> +		mutex_unlock(&dev_data->lock);
>> +
>> +		return ret;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static const struct iio_chan_spec tsys02d_channels[] = {
>> +	{
>> +		.type = IIO_TEMP,
>> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>> +	}
>> +};
>> +
>> +static ssize_t tsys02_read_battery_low(struct device *dev,
>> +				       struct device_attribute *attr,
>> +				       char *buf)
>> +{
>> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>> +
>> +	return ms_sensors_i2c_show_battery_low(dev_data, buf);
>> +}
>> +
>> +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
>> +static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
>> +		       tsys02_read_battery_low, NULL, 0);
>> +
>> +static struct attribute *tsys02d_attributes[] = {
>> +	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
>> +	&iio_dev_attr_battery_low.dev_attr.attr,
>> +	NULL,
>> +};
>> +
>> +static const struct attribute_group tsys02d_attribute_group = {
>> +	.attrs = tsys02d_attributes,
>> +};
>> +
>> +static const struct iio_info tsys02d_info = {
>> +	.read_raw = tsys02d_read_raw,
>> +	.write_raw = tsys02d_write_raw,
>> +	.attrs = &tsys02d_attribute_group,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +int tsys02d_probe(struct i2c_client *client,
>> +		  const struct i2c_device_id *id)
>> +{
>> +	struct ms_ht_dev *dev_data;
>> +	struct iio_dev *indio_dev;
>> +	int ret;
>> +	u64 serial_number;
>> +
>> +	if (!i2c_check_functionality(client->adapter,
>> +				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
>> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
>> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
>> +		dev_err(&client->dev,
>> +			"Adapter does not support some i2c transaction\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	dev_data = iio_priv(indio_dev);
>> +	dev_data->client = client;
>> +	dev_data->res_index = 0;
>> +	mutex_init(&dev_data->lock);
>> +
>> +	indio_dev->info = &tsys02d_info;
>> +	indio_dev->name = id->name;
>> +	indio_dev->dev.parent = &client->dev;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->channels = tsys02d_channels;
>> +	indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
>> +
>> +	i2c_set_clientdata(client, indio_dev);
>> +
>> +	ret = ms_sensors_i2c_reset(client, TSYS02D_RESET, 15000);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = ms_sensors_i2c_read_serial(client, &serial_number);
>> +	if (ret)
>> +		return ret;
>> +	dev_info(&client->dev, "Serial number : %llx", serial_number);
>> +
>> +	return devm_iio_device_register(&client->dev, indio_dev);
>> +}
>> +
>> +static const struct i2c_device_id tsys02d_id[] = {
>> +	{"tsys02d", 0},
>> +	{}
>> +};
>> +
>> +static struct i2c_driver tsys02d_driver = {
>> +	.probe = tsys02d_probe,
>> +	.id_table = tsys02d_id,
>> +	.driver = {
>> +		   .name = "tsys02d",
>> +		   .owner = THIS_MODULE,
> Again, don't set owner (I'll only get a patch removing it a few days after
> taking this one otherwise!)
>> +		   },
>> +};
>> +
>> +module_i2c_driver(tsys02d_driver);
>> +
>> +MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>> +MODULE_LICENSE("GPL v2");
>>
>
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 3/6] iio: Add tsys02d meas-spec driver support
  2015-08-09 12:33     ` Guenter Roeck
@ 2015-08-09 20:13       ` Hartmut Knaack
  2015-08-09 20:21         ` Guenter Roeck
  0 siblings, 1 reply; 25+ messages in thread
From: Hartmut Knaack @ 2015-08-09 20:13 UTC (permalink / raw)
  To: Guenter Roeck, Jonathan Cameron, Ludovic Tancerel, lars, pmeerw,
	linux-iio, William.Markezana, Jean Delvare

Guenter Roeck schrieb am 09.08.2015 um 14:33:
> On 08/08/2015 10:15 AM, Jonathan Cameron wrote:
>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>> The battery low indicator is certainly 'unusual' and undocumented on the
>> datasheet mentioned here.
>>
>> Ah well.  Same owner point as with the previous driver. Otherwise
>> seems fine to me.  Have cc'd the hwmon guys in case they have comments.
>>
>> Guenter / Jean, I would be more doubtful about having what is basically
>> a straight forward (if accurate) temperature IC in IIO except that
>> this is part of a series of parts including humidity and pressure sensors
>> in combined forms which are more common IIO fodder.
> 
> Agreed; I would really not like to have common code between iio and hwmon.
> 
> Does the series include support for htu21d ? If so, we should probably drop
> that driver from hwmon after it is available in iio.

Yes, it does.

http://www.spinics.net/lists/linux-iio/msg19918.html

> 
> Thanks,
> Guenter
> 
>>
>> Jonathan
>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>>> ---
>>>   Documentation/ABI/testing/sysfs-bus-iio-meas-spec |   7 +
>>>   drivers/iio/temperature/Kconfig                   |  11 ++
>>>   drivers/iio/temperature/Makefile                  |   1 +
>>>   drivers/iio/temperature/tsys02d.c                 | 193 ++++++++++++++++++++++
>>>   4 files changed, 212 insertions(+)
>>>   create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>>   create mode 100644 drivers/iio/temperature/tsys02d.c
>>>
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>> new file mode 100644
>>> index 0000000..6d47e54
>>> --- /dev/null
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>> @@ -0,0 +1,7 @@
>>> +What:           /sys/bus/iio/devices/iio:deviceX/battery_low
>>> +KernelVersion:  4.1.0
>>> +Contact:        linux-iio@vger.kernel.org
>>> +Description:
>>> +                Reading returns either '1' or '0'. '1' means that the
>>> +                battery level supplied to sensor is below 2.25V.
>>> +                This ABI is available for tsys02d, htu21, ms8607
>>
>> Hmm. This one is odd to find in IIO.  Also I can't actually find
>> reference to it on the datasheet.
>>
>> You are quite correct in thinking this is device specific abi and
>> documenting it as you have.
>>
>> Not sure we can do much else...
>>> diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
>>> index 35712032..c4664e5 100644
>>> --- a/drivers/iio/temperature/Kconfig
>>> +++ b/drivers/iio/temperature/Kconfig
>>> @@ -34,4 +34,15 @@ config TSYS01
>>>   	  This driver can also be built as a module. If so, the module will
>>>   	  be called tsys01.
>>>
>>> +config TSYS02D
>>> +	tristate "Measurement Specialties TSYS02D temperature sensor"
>>> +	depends on I2C
>>> +	select IIO_MS_SENSORS_I2C
>>> +	help
>>> +	  If you say yes here you get support for the Measurement Specialties
>>> +	  TSYS02D temperature sensor.
>>> +
>>> +	  This driver can also be built as a module. If so, the module will
>>> +	  be called tsys02d.
>>> +
>>>   endmenu
>>> diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
>>> index 368a2a2..02bc79d 100644
>>> --- a/drivers/iio/temperature/Makefile
>>> +++ b/drivers/iio/temperature/Makefile
>>> @@ -5,3 +5,4 @@
>>>   obj-$(CONFIG_MLX90614) += mlx90614.o
>>>   obj-$(CONFIG_TMP006) += tmp006.o
>>>   obj-$(CONFIG_TSYS01) += tsys01.o
>>> +obj-$(CONFIG_TSYS02D) += tsys02d.o
>>> diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
>>> new file mode 100644
>>> index 0000000..6971dab
>>> --- /dev/null
>>> +++ b/drivers/iio/temperature/tsys02d.c
>>> @@ -0,0 +1,193 @@
>>> +/*
>>> + * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
>>> + *
>>> + * Copyright (c) 2015 Measurement-Specialties
>>> + *
>>> + * Licensed under the GPL-2.
>>> + *
>>> + * (7-bit I2C slave address 0x40)
>>> + *
>>> + * Datasheet:
>>> + *  http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
>>> + *
>>> + */
>>> +
>>> +#include <linux/init.h>
>>> +#include <linux/device.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/stat.h>
>>> +#include <linux/module.h>
>>> +#include <linux/iio/iio.h>
>>> +#include <linux/iio/sysfs.h>
>>> +
>>> +#include "../common/ms_sensors/ms_sensors_i2c.h"
>>> +
>>> +#define TSYS02D_RESET				0xFE
>>> +
>>> +static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
>>> +/* String copy of the above const for readability purpose */
>>> +static const char tsys02d_show_samp_freq[] = "20 40 70 140";
>>> +
>>> +static int tsys02d_read_raw(struct iio_dev *indio_dev,
>>> +			    struct iio_chan_spec const *channel, int *val,
>>> +			    int *val2, long mask)
>>> +{
>>> +	int ret;
>>> +	s32 temperature;
>>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>>> +
>>> +	switch (mask) {
>>> +	case IIO_CHAN_INFO_PROCESSED:
>>> +		switch (channel->type) {
>>> +		case IIO_TEMP:	/* in milli °C */
>>> +			ret = ms_sensors_i2c_ht_read_temperature(dev_data,
>>> +								 &temperature);
>>> +			if (ret)
>>> +				return ret;
>>> +			*val = temperature;
>>> +
>>> +			return IIO_VAL_INT;
>>> +		default:
>>> +			return -EINVAL;
>>> +		}
>>> +	case IIO_CHAN_INFO_SAMP_FREQ:
>>> +		*val = tsys02d_samp_freq[dev_data->res_index];
>>> +
>>> +		return IIO_VAL_INT;
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>>> +}
>>> +
>>> +static int tsys02d_write_raw(struct iio_dev *indio_dev,
>>> +			     struct iio_chan_spec const *chan,
>>> +			     int val, int val2, long mask)
>>> +{
>>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>>> +	int i, ret;
>>> +
>>> +	switch (mask) {
>>> +	case IIO_CHAN_INFO_SAMP_FREQ:
>>> +		i = ARRAY_SIZE(tsys02d_samp_freq);
>>> +		while (i-- > 0)
>>> +			if (val == tsys02d_samp_freq[i])
>>> +				break;
>>> +		if (i < 0)
>>> +			return -EINVAL;
>>> +		mutex_lock(&dev_data->lock);
>>> +		dev_data->res_index = i;
>>> +		ret = ms_sensors_i2c_write_resolution(dev_data, i);
>>> +		mutex_unlock(&dev_data->lock);
>>> +
>>> +		return ret;
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>>> +}
>>> +
>>> +static const struct iio_chan_spec tsys02d_channels[] = {
>>> +	{
>>> +		.type = IIO_TEMP,
>>> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>>> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>> +	}
>>> +};
>>> +
>>> +static ssize_t tsys02_read_battery_low(struct device *dev,
>>> +				       struct device_attribute *attr,
>>> +				       char *buf)
>>> +{
>>> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>>> +	struct ms_ht_dev *dev_data = iio_priv(indio_dev);
>>> +
>>> +	return ms_sensors_i2c_show_battery_low(dev_data, buf);
>>> +}
>>> +
>>> +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
>>> +static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
>>> +		       tsys02_read_battery_low, NULL, 0);
>>> +
>>> +static struct attribute *tsys02d_attributes[] = {
>>> +	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
>>> +	&iio_dev_attr_battery_low.dev_attr.attr,
>>> +	NULL,
>>> +};
>>> +
>>> +static const struct attribute_group tsys02d_attribute_group = {
>>> +	.attrs = tsys02d_attributes,
>>> +};
>>> +
>>> +static const struct iio_info tsys02d_info = {
>>> +	.read_raw = tsys02d_read_raw,
>>> +	.write_raw = tsys02d_write_raw,
>>> +	.attrs = &tsys02d_attribute_group,
>>> +	.driver_module = THIS_MODULE,
>>> +};
>>> +
>>> +int tsys02d_probe(struct i2c_client *client,
>>> +		  const struct i2c_device_id *id)
>>> +{
>>> +	struct ms_ht_dev *dev_data;
>>> +	struct iio_dev *indio_dev;
>>> +	int ret;
>>> +	u64 serial_number;
>>> +
>>> +	if (!i2c_check_functionality(client->adapter,
>>> +				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
>>> +				     I2C_FUNC_SMBUS_WRITE_BYTE |
>>> +				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
>>> +		dev_err(&client->dev,
>>> +			"Adapter does not support some i2c transaction\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
>>> +	if (!indio_dev)
>>> +		return -ENOMEM;
>>> +
>>> +	dev_data = iio_priv(indio_dev);
>>> +	dev_data->client = client;
>>> +	dev_data->res_index = 0;
>>> +	mutex_init(&dev_data->lock);
>>> +
>>> +	indio_dev->info = &tsys02d_info;
>>> +	indio_dev->name = id->name;
>>> +	indio_dev->dev.parent = &client->dev;
>>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>>> +	indio_dev->channels = tsys02d_channels;
>>> +	indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
>>> +
>>> +	i2c_set_clientdata(client, indio_dev);
>>> +
>>> +	ret = ms_sensors_i2c_reset(client, TSYS02D_RESET, 15000);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = ms_sensors_i2c_read_serial(client, &serial_number);
>>> +	if (ret)
>>> +		return ret;
>>> +	dev_info(&client->dev, "Serial number : %llx", serial_number);
>>> +
>>> +	return devm_iio_device_register(&client->dev, indio_dev);
>>> +}
>>> +
>>> +static const struct i2c_device_id tsys02d_id[] = {
>>> +	{"tsys02d", 0},
>>> +	{}
>>> +};
>>> +
>>> +static struct i2c_driver tsys02d_driver = {
>>> +	.probe = tsys02d_probe,
>>> +	.id_table = tsys02d_id,
>>> +	.driver = {
>>> +		   .name = "tsys02d",
>>> +		   .owner = THIS_MODULE,
>> Again, don't set owner (I'll only get a patch removing it a few days after
>> taking this one otherwise!)
>>> +		   },
>>> +};
>>> +
>>> +module_i2c_driver(tsys02d_driver);
>>> +
>>> +MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
>>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>>> +MODULE_LICENSE("GPL v2");
>>>
>>
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 3/6] iio: Add tsys02d meas-spec driver support
  2015-08-09 20:13       ` Hartmut Knaack
@ 2015-08-09 20:21         ` Guenter Roeck
  0 siblings, 0 replies; 25+ messages in thread
From: Guenter Roeck @ 2015-08-09 20:21 UTC (permalink / raw)
  To: Hartmut Knaack, Jonathan Cameron, Ludovic Tancerel, lars, pmeerw,
	linux-iio, William.Markezana, Jean Delvare

On 08/09/2015 01:13 PM, Hartmut Knaack wrote:
> Guenter Roeck schrieb am 09.08.2015 um 14:33:
>> On 08/08/2015 10:15 AM, Jonathan Cameron wrote:
>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>> The battery low indicator is certainly 'unusual' and undocumented on the
>>> datasheet mentioned here.
>>>
>>> Ah well.  Same owner point as with the previous driver. Otherwise
>>> seems fine to me.  Have cc'd the hwmon guys in case they have comments.
>>>
>>> Guenter / Jean, I would be more doubtful about having what is basically
>>> a straight forward (if accurate) temperature IC in IIO except that
>>> this is part of a series of parts including humidity and pressure sensors
>>> in combined forms which are more common IIO fodder.
>>
>> Agreed; I would really not like to have common code between iio and hwmon.
>>
>> Does the series include support for htu21d ? If so, we should probably drop
>> that driver from hwmon after it is available in iio.
>
> Yes, it does.
>
> http://www.spinics.net/lists/linux-iio/msg19918.html
>

Ok, then let's drop it from hwmon after the iio driver is in mainline.

Guenter

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-08-08 16:58   ` Jonathan Cameron
@ 2015-08-10  7:43     ` Crt Mori
  2015-08-10 11:07       ` Crt Mori
  0 siblings, 1 reply; 25+ messages in thread
From: Crt Mori @ 2015-08-10  7:43 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Ludovic Tancerel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, linux-iio, William.Markezana

On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> wrote:
> On 30/07/15 10:25, Ludovic Tancerel wrote:
>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
> A few bits inline.
> Also, would prefer some basic description of the patch up here...
>> ---
>>  drivers/iio/common/Kconfig                     |   1 +
>>  drivers/iio/common/Makefile                    |   1 +
>>  drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>  drivers/iio/common/ms_sensors/Makefile         |   5 +
>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>  6 files changed, 701 insertions(+)
>>  create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>  create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>
>> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
>> index 790f106..26a6026 100644
>> --- a/drivers/iio/common/Kconfig
>> +++ b/drivers/iio/common/Kconfig
>> @@ -3,5 +3,6 @@
>>  #
>>
>>  source "drivers/iio/common/hid-sensors/Kconfig"
>> +source "drivers/iio/common/ms_sensors/Kconfig"
>>  source "drivers/iio/common/ssp_sensors/Kconfig"
>>  source "drivers/iio/common/st_sensors/Kconfig"
>> diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
>> index b1e4d9c..585da6a 100644
>> --- a/drivers/iio/common/Makefile
>> +++ b/drivers/iio/common/Makefile
>> @@ -8,5 +8,6 @@
>>
>>  # When adding new entries keep the list in alphabetical order
>>  obj-y += hid-sensors/
>> +obj-y += ms_sensors/
>>  obj-y += ssp_sensors/
>>  obj-y += st_sensors/
>> diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
>> new file mode 100644
>> index 0000000..b28a92b
>> --- /dev/null
>> +++ b/drivers/iio/common/ms_sensors/Kconfig
>> @@ -0,0 +1,6 @@
>> +#
>> +# Measurements Specialties sensors common library
>> +#
>> +
>> +config IIO_MS_SENSORS_I2C
>> +        tristate
>> diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
>> new file mode 100644
>> index 0000000..7846428
>> --- /dev/null
>> +++ b/drivers/iio/common/ms_sensors/Makefile
>> @@ -0,0 +1,5 @@
>> +#
>> +# Makefile for the Measurement Specialties sensor common modules.
>> +#
>> +
>> +obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>> new file mode 100644
>> index 0000000..f5d27b6
>> --- /dev/null
>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>> @@ -0,0 +1,634 @@
>> +/*
>> + * Measurements Specialties driver common i2c functions
>> + *
>> + * Copyright (c) 2015 Measurement-Specialties
>> + *
>> + * Licensed under the GPL-2.
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/device.h>
>> +#include <linux/delay.h>
>> +
>> +#include "ms_sensors_i2c.h"
>> +
>> +/* Conversion times in us */
>> +static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
>> +                                                    13000, 7000 };
>> +static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
>> +                                                    5000, 8000 };
>> +static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
>> +                                                  4100, 8220, 16440 };
>> +
>> +#define MS_SENSORS_SERIAL_READ_MSB           0xFA0F
>> +#define MS_SENSORS_SERIAL_READ_LSB           0xFCC9
>> +#define MS_SENSORS_USER_REG_WRITE            0xE6
>> +#define MS_SENSORS_USER_REG_READ             0xE7
>> +#define MS_SENSORS_HT_T_CONVERSION_START     0xF3
>> +#define MS_SENSORS_HT_H_CONVERSION_START     0xF5
>> +
>> +#define MS_SENSORS_TP_PROM_READ                      0xA0
>> +#define MS_SENSORS_TP_T_CONVERSION_START     0x50
>> +#define MS_SENSORS_TP_P_CONVERSION_START     0x40
>> +#define MS_SENSORS_TP_ADC_READ                       0x00
>> +
>> +#define MS_SENSORS_NO_READ_CMD                       0xFF
>> +
>> +/**
>> + * ms_sensors_i2c_reset() - i2c reset function
>> + * @cli:     pointer on i2c client
>> + * @cmd:     reset cmd. Depends on device in use
>> + * @delay:   usleep minimal delay after reset command is issued
>> + *
>> + * Generic I2C reset function for Measurement Specialties devices
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay)
>> +{
>> +     int ret;
>> +     struct i2c_client *client = cli;
>> +
>> +     ret = i2c_smbus_write_byte(client, cmd);
>> +     if (ret) {
>> +             dev_err(&client->dev, "Failed to reset device\n");
>> +             return ret;
>> +     }
>> +     usleep_range(delay, delay + 1000);
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_reset);
>> +
>> +/**
>> + * ms_sensors_i2c_read_prom_word() - i2c prom word read function
>> + * @cli:     pointer on i2c client
>> + * @cmd:     PROM read cmd. Depends on device and prom id
>> + * @word:    pointer on word destination value
>> + *
>> + * Generic i2c prom word read function for Measurement Specialties devices
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word)
>> +{
>> +     int ret;
>> +     struct i2c_client *client = (struct i2c_client *)cli;
>> +
>> +     ret = i2c_smbus_read_word_swapped(client, cmd);
>> +     if (ret < 0) {
>> +             dev_err(&client->dev, "Failed to read prom word\n");
>> +             return ret;
>> +     }
>> +     *word = ret;
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_read_prom_word);
>> +
>> +/**
>> + * ms_sensors_i2c_convert_and_read() - i2c ADC conversion & read function
>> + * @cli:     pointer on i2c client
>> + * @conv:    ADC conversion command. Depends on device in use
>> + * @rd:              ADC read command. Depends on device in use
>> + * @delay:   usleep minimal delay after conversion command is issued
>> + * @adc:     pointer on ADC destination value
>> + *
>> + * Generic i2c ADC conversion & read function for Measurement Specialties
>> + * devices.
>> + * The function will issue conversion command, sleep appopriate delay, and
>> + * issue command to read ADC
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>> +                                 unsigned int delay, u32 *adc)
>> +{
>> +     int ret;
>> +     u32 buf = 0;
>> +     struct i2c_client *client = (struct i2c_client *)cli;
>> +
>> +     /* Trigger conversion */
>> +     ret = i2c_smbus_write_byte(client, conv);
>> +     if (ret)
>> +             goto err;
>> +     usleep_range(delay, delay + 1000);
>> +
>> +     /* Retrieve ADC value */
>> +     if (rd != MS_SENSORS_NO_READ_CMD)
>> +             ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
>> +     else
>> +             ret = i2c_master_recv(client, (u8 *)&buf, 3);
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
>> +     *adc = be32_to_cpu(buf) >> 8;
>> +
>> +     return 0;
>> +err:
>> +     dev_err(&client->dev, "Unable to make sensor adc conversion\n");
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_convert_and_read);
>> +
>> +/**
>> + * ms_sensors_crc_valid() - CRC check function
>> + * @value:   input and CRC compare value
>> + *
>> + * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
>> + * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
>> + * The argument contains CRC value in LSB byte while the bytes 1 and 2
>> + * are used for CRC computation
>> + *
>> + * Return: 1 if CRC is valid, 0 otherwise.
>> + */
>> +static bool ms_sensors_crc_valid(u32 value)
>> +{
>> +     u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
>> +     u32 msb = 0x800000;
>> +     u32 mask = 0xFF8000;
>> +     u32 result = value & 0xFFFF00;
>> +     u8 crc = value & 0xFF;
>> +
>> +     while (msb != 0x80) {
>> +             if (result & msb)
>> +                     result = ((result ^ polynom) & mask)
>> +                             | (result & ~mask);
>> +             msb >>= 1;
>> +             mask >>= 1;
>> +             polynom >>= 1;
>> +     }
>> +
>> +     return result == crc;
>> +}
>> +
>> +/**
>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>> + * @cli:     pointer on i2c client
>> + * @sn:              pointer on 64-bits destination value
>> + *
>> + * Generic i2c serial number read function for Measurement Specialties devices.
>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>> + * Refer to datasheet:
>> + *   http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
>> +{
>> +     u8 i;
>> +     u64 rcv_buf = 0;
>> +     u16 send_buf;
>> +     int ret;
>> +
>> +     struct i2c_msg msg[2] = {
>> +             {
>> +              .addr = client->addr,
>> +              .flags = client->flags,
>> +              .len = 2,
>> +              .buf = (char *)&send_buf,
> If you are going to type cast, please match the (__u8 *) from
> include/uapi/linux/i2c.h
I am trying to push similar function (i2c_addressed_read) to i2c interface and
since this driver has created its own instance of it, I would prefer
we put it into
i2c-core.c . Could you please support that debate [1] ? I think there are quite
many drivers out there using the same function in a various way and it is
about time to have it included in i2c to have more uniform control.
>> +              },
>> +             {
>> +              .addr = client->addr,
>> +              .flags = client->flags | I2C_M_RD,
>> +              .buf = (char *)&rcv_buf,
>> +              },
>> +     };
>> +
>> +     /* Read MSB part of serial number */
>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>> +     msg[1].len = 8;
>> +     ret = i2c_transfer(client->adapter, msg, 2);
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     rcv_buf = be64_to_cpu(rcv_buf);
>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>> +
>> +     for (i = 0; i < 64; i += 16) {
>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>> +                     return -ENODEV;
>> +     }
>> +
>> +     *sn = (((rcv_buf >> 32) & 0xFF000000) |
>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>> +
>> +     /* Read LSB part of serial number */
>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>> +     msg[1].len = 6;
>> +     rcv_buf = 0;
>> +     ret = i2c_transfer(client->adapter, msg, 2);
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     rcv_buf = be64_to_cpu(rcv_buf) >> 16;
>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>> +
>> +     for (i = 0; i < 48; i += 24) {
>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
>> +                     return -ENODEV;
>> +     }
>> +
>> +     *sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>> +
>> +     return 0;
>> +
>> +err:
> Put this inline and drop the goto
>> +     dev_err(&client->dev, "Unable to read device serial number");
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>> +
> What is meant by a user_reg as opposed to other regs?
>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
>> +                                     u8 *user_reg)
>> +{
>> +     int ret;
>> +
>> +     ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
>> +     if (ret)
>> +             goto err;
>> +
>> +     ret = i2c_master_recv(client, user_reg, 1);
>> +     if (ret < 0)
>> +             goto err;
>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>> +
>> +     return 0;
>> +err:
>> +     dev_err(&client->dev, "Unable to read user reg");
>> +     return ret;
>> +}
>> +
>> +/**
>> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @i:               resolution index to set
>> + *
>> + * That function will program the appropriate resolution based on the index
>> + * provided when user space will set samp_freq channel.
>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
>> +                                     u8 i)
>> +{
>> +     u8 user_reg;
>> +     int ret;
>> +
>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>> +     if (ret)
>> +             return ret;
>> +
>> +     user_reg &= 0x7E;
>> +     user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
>> +
>> +     return i2c_smbus_write_byte_data(dev_data->client,
>> +                                      MS_SENSORS_USER_REG_WRITE,
>> +                                      user_reg);
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>> +
>> +/**
>> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @buf:     pointer on char buffer to write result
>> + *
>> + * That function will read battery indicator value in the device and
>> + * return 1 if the device voltage is below 2.25V.
>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>> + *
>> + * Return: length of sprintf on success, negative errno otherwise.
>> + */
>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
>> +                                     char *buf)
>> +{
>> +     int ret;
>> +     u8 user_reg;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>> +
>> +/**
>> + * ms_sensors_i2c_show_heater() - show device heater
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @buf:     pointer on char buffer to write result
>> + *
>> + * That function will read heater enable value in the device and
>> + * return 1 if the heater is enabled
>> + * That function is used for HTU21 and MS8607 chipsets
>> + *
>> + * Return: length of sprintf on success, negative errno otherwise.
>> + */
>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>> +                                char *buf)
>> +{
>> +     u8 user_reg;
>> +     int ret;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>> +
>> +/**
>> + * ms_sensors_i2c_write_heater() - write device heater
> I'm not sure the _i2c_ bit is important in this function name...
>
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @buf:     pointer on char buffer from user space
>> + * @len:     length of buf
>> + *
>> + * That function will write 1 or 0 value in the device
>> + * to enable or disable heater
>> + * That function is used for HTU21 and MS8607 chipsets
> That->This
>> + *
>> + * Return: length of buffer, negative errno otherwise.
>> + */
>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>> +                                 const char *buf, size_t len)
>> +{
>> +     u8 val, user_reg;
>> +     int ret;
>> +
>> +     ret = kstrtou8(buf, 10, &val);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (val > 1)
>> +             return -EINVAL;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>> +     if (ret) {
>> +             mutex_unlock(&dev_data->lock);
>> +             return ret;
>> +     }
>> +
>> +     user_reg &= 0xFB;
>> +     user_reg |= val << 2;
>> +
>> +     ret = i2c_smbus_write_byte_data(dev_data->client,
>> +                                     MS_SENSORS_USER_REG_WRITE,
>> +                                     user_reg);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret) {
>> +             dev_err(&dev_data->client->dev, "Unable to write user reg\n");
>> +             return ret;
>> +     }
>> +
>> +     return len;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>> +
>> +/**
>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @temperature:pointer on temperature destination value
>> + *
>> + * That function will get temperature ADC value from the device,
>> + * check the CRC and compute the temperature value.
>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>> +                                    s32 *temperature)
>> +{
>> +     int ret;
>> +     u32 adc;
>> +     u16 delay;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>> +                                           MS_SENSORS_HT_T_CONVERSION_START,
>> +                                           MS_SENSORS_NO_READ_CMD,
>> +                                           delay, &adc);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (!ms_sensors_crc_valid(adc)) {
>> +             dev_err(&dev_data->client->dev,
>> +                     "Temperature read crc check error\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     /* Temperature algorithm */
>> +     *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>> +
>> +/**
>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>> + * @dev_data:        pointer on temperature/humidity device data
>> + * @humidity:        pointer on humidity destination value
>> + *
>> + * That function will get humidity ADC value from the device,
>> + * check the CRC and compute the temperature value.
>> + * That function is used for HTU21 and MS8607 chipsets
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>> +                                 u32 *humidity)
>> +{
>> +     int ret;
>> +     u32 adc;
>> +     u16 delay;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>> +                                           MS_SENSORS_HT_H_CONVERSION_START,
>> +                                           MS_SENSORS_NO_READ_CMD,
>> +                                           delay, &adc);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (!ms_sensors_crc_valid(adc)) {
>> +             dev_err(&dev_data->client->dev,
>> +                     "Humidity read crc check error\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     /* Humidity algorithm */
>> +     *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>> +     if (*humidity >= 100000)
>> +             *humidity = 100000;
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>> +
> Multiline comment syntax is
> /*
>  * CRC...
>  */
>  Or ideally use kernel-doc as you have for other functions below
>  (not required as not exported)
>
>> +/* CRC check function for Temperature and pressure devices
>> + * That function is only used when reading PROM coefficients */
>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>> +{
>> +     unsigned int cnt, n_bit;
>> +     u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
>> +
>> +     prom[len - 1] = 0;
>> +     prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
>> +
>> +     for (cnt = 0; cnt < len * 2; cnt++) {
>> +             if (cnt % 2 == 1)
>> +                     n_rem ^= prom[cnt >> 1] & 0x00FF;
>> +             else
>> +                     n_rem ^= prom[cnt >> 1] >> 8;
>> +
>> +             for (n_bit = 8; n_bit > 0; n_bit--) {
>> +                     if (n_rem & 0x8000)
>> +                             n_rem = (n_rem << 1) ^ 0x3000;
>> +                     else
>> +                             n_rem <<= 1;
>> +             }
>> +     }
>> +     n_rem >>= 12;
>> +     prom[0] = crc_read;
>> +
>> +     return n_rem == crc;
>> +}
>> +
>> +/**
>> + * ms_sensors_tp_read_prom() - prom coeff read function
>> + * @dev_data:        pointer on temperature/pressure device data
> pointer to temperature/... (fix throughout driver please)
>> + *
>> + * That function will read prom coefficients and check CRC
> That -> This (and add a full stop at the end of the sentence.
>> + * That function is used for MS5637 and MS8607 chipsets
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>> +{
>> +     int i, ret;
>> +
>> +     for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>> +             ret = ms_sensors_i2c_read_prom_word(
>> +                                     dev_data->client,
>> +                                     MS_SENSORS_TP_PROM_READ + (i << 1),
>> +                                     &dev_data->prom[i]);
>> +
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
>> +             dev_err(&dev_data->client->dev,
>> +                     "Calibration coefficients crc check error\n");
>> +             return -ENODEV;
>> +     }
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>> +
>> +/**
>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>> + * @dev_data:        pointer on temperature/pressure device data
> pointer to
>> + * @temperature:pointer on temperature destination value
> pointer to (also missing tab?)
>> + * @pressure:        pointer on pressure destination value
>> + *
>> + * That function will read ADC and compute pressure and temperature value
> That->This and full stop at end of sentence.
>
>> + * That function is used for MS5637 and MS8607 chipsets
>> + *
>> + * Return: 0 on success, negative errno otherwise.
>> + */
>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>> +                                   int *temperature,
>> +                                   unsigned int *pressure)
>> +{
>> +     int ret;
>> +     u32 t_adc, p_adc;
>> +     s32 dt, temp;
>> +     s64 off, sens, t2, off2, sens2;
>> +     u16 *prom = dev_data->prom, delay;
>> +     u8 i;
>> +
>> +     mutex_lock(&dev_data->lock);
>> +     i = dev_data->res_index * 2;
>> +     delay = ms_sensors_tp_conversion_time[dev_data->res_index];
> Blank line here would improve readability.
>> +     ret = ms_sensors_i2c_convert_and_read(
>> +                                     dev_data->client,
>> +                                     MS_SENSORS_TP_T_CONVERSION_START + i,
>> +                                     MS_SENSORS_TP_ADC_READ,
>> +                                     delay, &t_adc);
>> +     if (ret) {
>> +             mutex_unlock(&dev_data->lock);
>> +             return ret;
>> +     }
> blank line here.
>> +     ret = ms_sensors_i2c_convert_and_read(
>> +                                     dev_data->client,
>> +                                     MS_SENSORS_TP_P_CONVERSION_START + i,
>> +                                     MS_SENSORS_TP_ADC_READ,
>> +                                     delay, &p_adc);
>> +     mutex_unlock(&dev_data->lock);
>> +     if (ret)
>> +             return ret;
>> +
>> +     dt = (s32)t_adc - (prom[5] << 8);
>> +
>> +     /* Actual temperature = 2000 + dT * TEMPSENS */
>> +     temp = 2000 + (((s64)dt * prom[6]) >> 23);
>> +
>> +     /* Second order temperature compensation */
>> +     if (temp < 2000) {
>> +             s64 tmp = (s64)temp - 2000;
>> +
>> +             t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
>> +             off2 = (61 * tmp * tmp) >> 4;
>> +             sens2 = (29 * tmp * tmp) >> 4;
>> +
>> +             if (temp < -1500) {
>> +                     s64 tmp = (s64)temp + 1500;
>> +
>> +                     off2 += 17 * tmp * tmp;
>> +                     sens2 += 9 * tmp * tmp;
>> +             }
>> +     } else {
>> +             t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
>> +             off2 = 0;
>> +             sens2 = 0;
>> +     }
>> +
>> +     /* OFF = OFF_T1 + TCO * dT */
>> +     off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
>> +     off -= off2;
>> +
>> +     /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
>> +     sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
>> +     sens -= sens2;
>> +
>> +     /* Temperature compensated pressure = D1 * SENS - OFF */
>> +     *temperature = (temp - t2) * 10;
>> +     *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
>> +
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>> +
>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>> +MODULE_LICENSE("GPL v2");
>> +
>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>> new file mode 100644
>> index 0000000..a521428
>> --- /dev/null
>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>> @@ -0,0 +1,54 @@
>> +/*
>> + * Measurements Specialties common sensor driver
>> + *
>> + * Copyright (c) 2015 Measurement-Specialties
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
> Unnecesary blank line here.
>> + */
>> +
>> +#ifndef _MS_SENSORS_I2C_H
>> +#define _MS_SENSORS_I2C_H
>> +
>> +#include <linux/i2c.h>
>> +#include <linux/mutex.h>
>> +
>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>> +
>> +struct ms_ht_dev {
>> +     struct i2c_client *client;
>> +     struct mutex lock; /* mutex protecting data structure */
>> +     u8 res_index;
>> +};
>> +
>> +struct ms_tp_dev {
>> +     struct i2c_client *client;
>> +     struct mutex lock; /* mutex protecting data structure */
>> +     /* Added element for CRC computation */
>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>> +     u8 res_index;
>> +};
>> +
>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>> +                                 unsigned int delay, u32 *adc);
>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>> +                                 const char *buf, size_t len);
>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>> +                                    s32 *temperature);
>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>> +                                 u32 *humidity);
>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>> +                                   int *temperature,
>> +                                   unsigned int *pressure);
>> +
>> +#endif /* _MS_SENSORS_I2C_H */
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-08-10  7:43     ` Crt Mori
@ 2015-08-10 11:07       ` Crt Mori
  2015-08-15 20:09         ` Jonathan Cameron
  0 siblings, 1 reply; 25+ messages in thread
From: Crt Mori @ 2015-08-10 11:07 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Ludovic Tancerel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, linux-iio, William.Markezana

On 10 August 2015 at 09:43, Crt Mori <cmo@melexis.com> wrote:
> On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> wrote:
>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>> A few bits inline.
>> Also, would prefer some basic description of the patch up here...
>>> ---
>>>  drivers/iio/common/Kconfig                     |   1 +
>>>  drivers/iio/common/Makefile                    |   1 +
>>>  drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>>  drivers/iio/common/ms_sensors/Makefile         |   5 +
>>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>>  6 files changed, 701 insertions(+)
>>>  create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>>  create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>
>>> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
>>> index 790f106..26a6026 100644
>>> --- a/drivers/iio/common/Kconfig
>>> +++ b/drivers/iio/common/Kconfig
>>> @@ -3,5 +3,6 @@
>>>  #
>>>
>>>  source "drivers/iio/common/hid-sensors/Kconfig"
>>> +source "drivers/iio/common/ms_sensors/Kconfig"
>>>  source "drivers/iio/common/ssp_sensors/Kconfig"
>>>  source "drivers/iio/common/st_sensors/Kconfig"
>>> diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
>>> index b1e4d9c..585da6a 100644
>>> --- a/drivers/iio/common/Makefile
>>> +++ b/drivers/iio/common/Makefile
>>> @@ -8,5 +8,6 @@
>>>
>>>  # When adding new entries keep the list in alphabetical order
>>>  obj-y += hid-sensors/
>>> +obj-y += ms_sensors/
>>>  obj-y += ssp_sensors/
>>>  obj-y += st_sensors/
>>> diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
>>> new file mode 100644
>>> index 0000000..b28a92b
>>> --- /dev/null
>>> +++ b/drivers/iio/common/ms_sensors/Kconfig
>>> @@ -0,0 +1,6 @@
>>> +#
>>> +# Measurements Specialties sensors common library
>>> +#
>>> +
>>> +config IIO_MS_SENSORS_I2C
>>> +        tristate
>>> diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
>>> new file mode 100644
>>> index 0000000..7846428
>>> --- /dev/null
>>> +++ b/drivers/iio/common/ms_sensors/Makefile
>>> @@ -0,0 +1,5 @@
>>> +#
>>> +# Makefile for the Measurement Specialties sensor common modules.
>>> +#
>>> +
>>> +obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>> new file mode 100644
>>> index 0000000..f5d27b6
>>> --- /dev/null
>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>> @@ -0,0 +1,634 @@
>>> +/*
>>> + * Measurements Specialties driver common i2c functions
>>> + *
>>> + * Copyright (c) 2015 Measurement-Specialties
>>> + *
>>> + * Licensed under the GPL-2.
>>> + *
>>> + */
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/iio/iio.h>
>>> +#include <linux/device.h>
>>> +#include <linux/delay.h>
>>> +
>>> +#include "ms_sensors_i2c.h"
>>> +
>>> +/* Conversion times in us */
>>> +static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
>>> +                                                    13000, 7000 };
>>> +static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
>>> +                                                    5000, 8000 };
>>> +static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
>>> +                                                  4100, 8220, 16440 };
>>> +
>>> +#define MS_SENSORS_SERIAL_READ_MSB           0xFA0F
>>> +#define MS_SENSORS_SERIAL_READ_LSB           0xFCC9
>>> +#define MS_SENSORS_USER_REG_WRITE            0xE6
>>> +#define MS_SENSORS_USER_REG_READ             0xE7
>>> +#define MS_SENSORS_HT_T_CONVERSION_START     0xF3
>>> +#define MS_SENSORS_HT_H_CONVERSION_START     0xF5
>>> +
>>> +#define MS_SENSORS_TP_PROM_READ                      0xA0
>>> +#define MS_SENSORS_TP_T_CONVERSION_START     0x50
>>> +#define MS_SENSORS_TP_P_CONVERSION_START     0x40
>>> +#define MS_SENSORS_TP_ADC_READ                       0x00
>>> +
>>> +#define MS_SENSORS_NO_READ_CMD                       0xFF
>>> +
>>> +/**
>>> + * ms_sensors_i2c_reset() - i2c reset function
>>> + * @cli:     pointer on i2c client
>>> + * @cmd:     reset cmd. Depends on device in use
>>> + * @delay:   usleep minimal delay after reset command is issued
>>> + *
>>> + * Generic I2C reset function for Measurement Specialties devices
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay)
>>> +{
>>> +     int ret;
>>> +     struct i2c_client *client = cli;
>>> +
>>> +     ret = i2c_smbus_write_byte(client, cmd);
>>> +     if (ret) {
>>> +             dev_err(&client->dev, "Failed to reset device\n");
>>> +             return ret;
>>> +     }
>>> +     usleep_range(delay, delay + 1000);
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_reset);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_read_prom_word() - i2c prom word read function
>>> + * @cli:     pointer on i2c client
>>> + * @cmd:     PROM read cmd. Depends on device and prom id
>>> + * @word:    pointer on word destination value
>>> + *
>>> + * Generic i2c prom word read function for Measurement Specialties devices
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word)
>>> +{
>>> +     int ret;
>>> +     struct i2c_client *client = (struct i2c_client *)cli;
>>> +
>>> +     ret = i2c_smbus_read_word_swapped(client, cmd);
>>> +     if (ret < 0) {
>>> +             dev_err(&client->dev, "Failed to read prom word\n");
>>> +             return ret;
>>> +     }
>>> +     *word = ret;
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_prom_word);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_convert_and_read() - i2c ADC conversion & read function
>>> + * @cli:     pointer on i2c client
>>> + * @conv:    ADC conversion command. Depends on device in use
>>> + * @rd:              ADC read command. Depends on device in use
>>> + * @delay:   usleep minimal delay after conversion command is issued
>>> + * @adc:     pointer on ADC destination value
>>> + *
>>> + * Generic i2c ADC conversion & read function for Measurement Specialties
>>> + * devices.
>>> + * The function will issue conversion command, sleep appopriate delay, and
>>> + * issue command to read ADC
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>> +                                 unsigned int delay, u32 *adc)
>>> +{
>>> +     int ret;
>>> +     u32 buf = 0;
>>> +     struct i2c_client *client = (struct i2c_client *)cli;
>>> +
>>> +     /* Trigger conversion */
>>> +     ret = i2c_smbus_write_byte(client, conv);
>>> +     if (ret)
>>> +             goto err;
>>> +     usleep_range(delay, delay + 1000);
>>> +
>>> +     /* Retrieve ADC value */
>>> +     if (rd != MS_SENSORS_NO_READ_CMD)
>>> +             ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
>>> +     else
>>> +             ret = i2c_master_recv(client, (u8 *)&buf, 3);
>>> +     if (ret < 0)
>>> +             goto err;
>>> +
>>> +     dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
>>> +     *adc = be32_to_cpu(buf) >> 8;
>>> +
>>> +     return 0;
>>> +err:
>>> +     dev_err(&client->dev, "Unable to make sensor adc conversion\n");
>>> +     return ret;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_convert_and_read);
>>> +
>>> +/**
>>> + * ms_sensors_crc_valid() - CRC check function
>>> + * @value:   input and CRC compare value
>>> + *
>>> + * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
>>> + * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
>>> + * The argument contains CRC value in LSB byte while the bytes 1 and 2
>>> + * are used for CRC computation
>>> + *
>>> + * Return: 1 if CRC is valid, 0 otherwise.
>>> + */
>>> +static bool ms_sensors_crc_valid(u32 value)
>>> +{
>>> +     u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
>>> +     u32 msb = 0x800000;
>>> +     u32 mask = 0xFF8000;
>>> +     u32 result = value & 0xFFFF00;
>>> +     u8 crc = value & 0xFF;
>>> +
>>> +     while (msb != 0x80) {
>>> +             if (result & msb)
>>> +                     result = ((result ^ polynom) & mask)
>>> +                             | (result & ~mask);
>>> +             msb >>= 1;
>>> +             mask >>= 1;
>>> +             polynom >>= 1;
>>> +     }
>>> +
>>> +     return result == crc;
>>> +}
>>> +
>>> +/**
>>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>>> + * @cli:     pointer on i2c client
>>> + * @sn:              pointer on 64-bits destination value
>>> + *
>>> + * Generic i2c serial number read function for Measurement Specialties devices.
>>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>>> + * Refer to datasheet:
>>> + *   http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
>>> +{
>>> +     u8 i;
>>> +     u64 rcv_buf = 0;
>>> +     u16 send_buf;
>>> +     int ret;
>>> +
>>> +     struct i2c_msg msg[2] = {
>>> +             {
>>> +              .addr = client->addr,
>>> +              .flags = client->flags,
>>> +              .len = 2,
>>> +              .buf = (char *)&send_buf,
>> If you are going to type cast, please match the (__u8 *) from
>> include/uapi/linux/i2c.h
> I am trying to push similar function (i2c_addressed_read) to i2c interface and
> since this driver has created its own instance of it, I would prefer
> we put it into
> i2c-core.c . Could you please support that debate [1] ? I think there are quite
> many drivers out there using the same function in a various way and it is
> about time to have it included in i2c to have more uniform control.

You should use: regmap_i2c_read (#include <linux/regmap.h>)

>>> +              },
>>> +             {
>>> +              .addr = client->addr,
>>> +              .flags = client->flags | I2C_M_RD,
>>> +              .buf = (char *)&rcv_buf,
>>> +              },
>>> +     };
>>> +
>>> +     /* Read MSB part of serial number */
>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>>> +     msg[1].len = 8;
>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>> +     if (ret < 0)
>>> +             goto err;
>>> +
>>> +     rcv_buf = be64_to_cpu(rcv_buf);
>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>> +
>>> +     for (i = 0; i < 64; i += 16) {
>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>>> +                     return -ENODEV;
>>> +     }
>>> +
>>> +     *sn = (((rcv_buf >> 32) & 0xFF000000) |
>>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>>> +
>>> +     /* Read LSB part of serial number */
>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>>> +     msg[1].len = 6;
>>> +     rcv_buf = 0;
>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>> +     if (ret < 0)
>>> +             goto err;
>>> +
>>> +     rcv_buf = be64_to_cpu(rcv_buf) >> 16;
>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>> +
>>> +     for (i = 0; i < 48; i += 24) {
>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
>>> +                     return -ENODEV;
>>> +     }
>>> +
>>> +     *sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>>> +
>>> +     return 0;
>>> +
>>> +err:
>> Put this inline and drop the goto
>>> +     dev_err(&client->dev, "Unable to read device serial number");
>>> +     return ret;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>>> +
>> What is meant by a user_reg as opposed to other regs?
>>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
>>> +                                     u8 *user_reg)
>>> +{
>>> +     int ret;
>>> +
>>> +     ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
>>> +     if (ret)
>>> +             goto err;
>>> +
>>> +     ret = i2c_master_recv(client, user_reg, 1);
>>> +     if (ret < 0)
>>> +             goto err;
>>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>>> +
>>> +     return 0;
>>> +err:
>>> +     dev_err(&client->dev, "Unable to read user reg");
>>> +     return ret;
>>> +}
>>> +
>>> +/**
>>> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @i:               resolution index to set
>>> + *
>>> + * That function will program the appropriate resolution based on the index
>>> + * provided when user space will set samp_freq channel.
>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
>>> +                                     u8 i)
>>> +{
>>> +     u8 user_reg;
>>> +     int ret;
>>> +
>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     user_reg &= 0x7E;
>>> +     user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
>>> +
>>> +     return i2c_smbus_write_byte_data(dev_data->client,
>>> +                                      MS_SENSORS_USER_REG_WRITE,
>>> +                                      user_reg);
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @buf:     pointer on char buffer to write result
>>> + *
>>> + * That function will read battery indicator value in the device and
>>> + * return 1 if the device voltage is below 2.25V.
>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>> + *
>>> + * Return: length of sprintf on success, negative errno otherwise.
>>> + */
>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
>>> +                                     char *buf)
>>> +{
>>> +     int ret;
>>> +     u8 user_reg;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_show_heater() - show device heater
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @buf:     pointer on char buffer to write result
>>> + *
>>> + * That function will read heater enable value in the device and
>>> + * return 1 if the heater is enabled
>>> + * That function is used for HTU21 and MS8607 chipsets
>>> + *
>>> + * Return: length of sprintf on success, negative errno otherwise.
>>> + */
>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>>> +                                char *buf)
>>> +{
>>> +     u8 user_reg;
>>> +     int ret;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_write_heater() - write device heater
>> I'm not sure the _i2c_ bit is important in this function name...
>>
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @buf:     pointer on char buffer from user space
>>> + * @len:     length of buf
>>> + *
>>> + * That function will write 1 or 0 value in the device
>>> + * to enable or disable heater
>>> + * That function is used for HTU21 and MS8607 chipsets
>> That->This
>>> + *
>>> + * Return: length of buffer, negative errno otherwise.
>>> + */
>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>> +                                 const char *buf, size_t len)
>>> +{
>>> +     u8 val, user_reg;
>>> +     int ret;
>>> +
>>> +     ret = kstrtou8(buf, 10, &val);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     if (val > 1)
>>> +             return -EINVAL;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>> +     if (ret) {
>>> +             mutex_unlock(&dev_data->lock);
>>> +             return ret;
>>> +     }
>>> +
>>> +     user_reg &= 0xFB;
>>> +     user_reg |= val << 2;
>>> +
>>> +     ret = i2c_smbus_write_byte_data(dev_data->client,
>>> +                                     MS_SENSORS_USER_REG_WRITE,
>>> +                                     user_reg);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret) {
>>> +             dev_err(&dev_data->client->dev, "Unable to write user reg\n");
>>> +             return ret;
>>> +     }
>>> +
>>> +     return len;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @temperature:pointer on temperature destination value
>>> + *
>>> + * That function will get temperature ADC value from the device,
>>> + * check the CRC and compute the temperature value.
>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>> +                                    s32 *temperature)
>>> +{
>>> +     int ret;
>>> +     u32 adc;
>>> +     u16 delay;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>> +                                           MS_SENSORS_HT_T_CONVERSION_START,
>>> +                                           MS_SENSORS_NO_READ_CMD,
>>> +                                           delay, &adc);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     if (!ms_sensors_crc_valid(adc)) {
>>> +             dev_err(&dev_data->client->dev,
>>> +                     "Temperature read crc check error\n");
>>> +             return -ENODEV;
>>> +     }
>>> +
>>> +     /* Temperature algorithm */
>>> +     *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>>> +
>>> +/**
>>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>>> + * @dev_data:        pointer on temperature/humidity device data
>>> + * @humidity:        pointer on humidity destination value
>>> + *
>>> + * That function will get humidity ADC value from the device,
>>> + * check the CRC and compute the temperature value.
>>> + * That function is used for HTU21 and MS8607 chipsets
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>> +                                 u32 *humidity)
>>> +{
>>> +     int ret;
>>> +     u32 adc;
>>> +     u16 delay;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>> +                                           MS_SENSORS_HT_H_CONVERSION_START,
>>> +                                           MS_SENSORS_NO_READ_CMD,
>>> +                                           delay, &adc);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     if (!ms_sensors_crc_valid(adc)) {
>>> +             dev_err(&dev_data->client->dev,
>>> +                     "Humidity read crc check error\n");
>>> +             return -ENODEV;
>>> +     }
>>> +
>>> +     /* Humidity algorithm */
>>> +     *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>>> +     if (*humidity >= 100000)
>>> +             *humidity = 100000;
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>>> +
>> Multiline comment syntax is
>> /*
>>  * CRC...
>>  */
>>  Or ideally use kernel-doc as you have for other functions below
>>  (not required as not exported)
>>
>>> +/* CRC check function for Temperature and pressure devices
>>> + * That function is only used when reading PROM coefficients */
>>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>>> +{
>>> +     unsigned int cnt, n_bit;
>>> +     u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
>>> +
>>> +     prom[len - 1] = 0;
>>> +     prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
>>> +
>>> +     for (cnt = 0; cnt < len * 2; cnt++) {
>>> +             if (cnt % 2 == 1)
>>> +                     n_rem ^= prom[cnt >> 1] & 0x00FF;
>>> +             else
>>> +                     n_rem ^= prom[cnt >> 1] >> 8;
>>> +
>>> +             for (n_bit = 8; n_bit > 0; n_bit--) {
>>> +                     if (n_rem & 0x8000)
>>> +                             n_rem = (n_rem << 1) ^ 0x3000;
>>> +                     else
>>> +                             n_rem <<= 1;
>>> +             }
>>> +     }
>>> +     n_rem >>= 12;
>>> +     prom[0] = crc_read;
>>> +
>>> +     return n_rem == crc;
>>> +}
>>> +
>>> +/**
>>> + * ms_sensors_tp_read_prom() - prom coeff read function
>>> + * @dev_data:        pointer on temperature/pressure device data
>> pointer to temperature/... (fix throughout driver please)
>>> + *
>>> + * That function will read prom coefficients and check CRC
>> That -> This (and add a full stop at the end of the sentence.
>>> + * That function is used for MS5637 and MS8607 chipsets
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>>> +{
>>> +     int i, ret;
>>> +
>>> +     for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>>> +             ret = ms_sensors_i2c_read_prom_word(
>>> +                                     dev_data->client,
>>> +                                     MS_SENSORS_TP_PROM_READ + (i << 1),
>>> +                                     &dev_data->prom[i]);
>>> +
>>> +             if (ret)
>>> +                     return ret;
>>> +     }
>>> +
>>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
>>> +             dev_err(&dev_data->client->dev,
>>> +                     "Calibration coefficients crc check error\n");
>>> +             return -ENODEV;
>>> +     }
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>>> +
>>> +/**
>>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>>> + * @dev_data:        pointer on temperature/pressure device data
>> pointer to
>>> + * @temperature:pointer on temperature destination value
>> pointer to (also missing tab?)
>>> + * @pressure:        pointer on pressure destination value
>>> + *
>>> + * That function will read ADC and compute pressure and temperature value
>> That->This and full stop at end of sentence.
>>
>>> + * That function is used for MS5637 and MS8607 chipsets
>>> + *
>>> + * Return: 0 on success, negative errno otherwise.
>>> + */
>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>> +                                   int *temperature,
>>> +                                   unsigned int *pressure)
>>> +{
>>> +     int ret;
>>> +     u32 t_adc, p_adc;
>>> +     s32 dt, temp;
>>> +     s64 off, sens, t2, off2, sens2;
>>> +     u16 *prom = dev_data->prom, delay;
>>> +     u8 i;
>>> +
>>> +     mutex_lock(&dev_data->lock);
>>> +     i = dev_data->res_index * 2;
>>> +     delay = ms_sensors_tp_conversion_time[dev_data->res_index];
>> Blank line here would improve readability.
>>> +     ret = ms_sensors_i2c_convert_and_read(
>>> +                                     dev_data->client,
>>> +                                     MS_SENSORS_TP_T_CONVERSION_START + i,
>>> +                                     MS_SENSORS_TP_ADC_READ,
>>> +                                     delay, &t_adc);
>>> +     if (ret) {
>>> +             mutex_unlock(&dev_data->lock);
>>> +             return ret;
>>> +     }
>> blank line here.
>>> +     ret = ms_sensors_i2c_convert_and_read(
>>> +                                     dev_data->client,
>>> +                                     MS_SENSORS_TP_P_CONVERSION_START + i,
>>> +                                     MS_SENSORS_TP_ADC_READ,
>>> +                                     delay, &p_adc);
>>> +     mutex_unlock(&dev_data->lock);
>>> +     if (ret)
>>> +             return ret;
>>> +
>>> +     dt = (s32)t_adc - (prom[5] << 8);
>>> +
>>> +     /* Actual temperature = 2000 + dT * TEMPSENS */
>>> +     temp = 2000 + (((s64)dt * prom[6]) >> 23);
>>> +
>>> +     /* Second order temperature compensation */
>>> +     if (temp < 2000) {
>>> +             s64 tmp = (s64)temp - 2000;
>>> +
>>> +             t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
>>> +             off2 = (61 * tmp * tmp) >> 4;
>>> +             sens2 = (29 * tmp * tmp) >> 4;
>>> +
>>> +             if (temp < -1500) {
>>> +                     s64 tmp = (s64)temp + 1500;
>>> +
>>> +                     off2 += 17 * tmp * tmp;
>>> +                     sens2 += 9 * tmp * tmp;
>>> +             }
>>> +     } else {
>>> +             t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
>>> +             off2 = 0;
>>> +             sens2 = 0;
>>> +     }
>>> +
>>> +     /* OFF = OFF_T1 + TCO * dT */
>>> +     off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
>>> +     off -= off2;
>>> +
>>> +     /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
>>> +     sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
>>> +     sens -= sens2;
>>> +
>>> +     /* Temperature compensated pressure = D1 * SENS - OFF */
>>> +     *temperature = (temp - t2) * 10;
>>> +     *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
>>> +
>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>>> +
>>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>>> +MODULE_LICENSE("GPL v2");
>>> +
>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>> new file mode 100644
>>> index 0000000..a521428
>>> --- /dev/null
>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>> @@ -0,0 +1,54 @@
>>> +/*
>>> + * Measurements Specialties common sensor driver
>>> + *
>>> + * Copyright (c) 2015 Measurement-Specialties
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>> Unnecesary blank line here.
>>> + */
>>> +
>>> +#ifndef _MS_SENSORS_I2C_H
>>> +#define _MS_SENSORS_I2C_H
>>> +
>>> +#include <linux/i2c.h>
>>> +#include <linux/mutex.h>
>>> +
>>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>>> +
>>> +struct ms_ht_dev {
>>> +     struct i2c_client *client;
>>> +     struct mutex lock; /* mutex protecting data structure */
>>> +     u8 res_index;
>>> +};
>>> +
>>> +struct ms_tp_dev {
>>> +     struct i2c_client *client;
>>> +     struct mutex lock; /* mutex protecting data structure */
>>> +     /* Added element for CRC computation */
>>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>>> +     u8 res_index;
>>> +};
>>> +
>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>> +                                 unsigned int delay, u32 *adc);
>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
>>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>> +                                 const char *buf, size_t len);
>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>> +                                    s32 *temperature);
>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>> +                                 u32 *humidity);
>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>> +                                   int *temperature,
>>> +                                   unsigned int *pressure);
>>> +
>>> +#endif /* _MS_SENSORS_I2C_H */
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> [1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-08-10 11:07       ` Crt Mori
@ 2015-08-15 20:09         ` Jonathan Cameron
  2015-09-14 12:56           ` ludovic.tancerel
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-08-15 20:09 UTC (permalink / raw)
  To: Crt Mori
  Cc: Ludovic Tancerel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald, linux-iio, William.Markezana

On 10/08/15 12:07, Crt Mori wrote:
> On 10 August 2015 at 09:43, Crt Mori <cmo@melexis.com> wrote:
>> On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> wrote:
>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>>> A few bits inline.
>>> Also, would prefer some basic description of the patch up here...
>>>> ---
>>>>  drivers/iio/common/Kconfig                     |   1 +
>>>>  drivers/iio/common/Makefile                    |   1 +
>>>>  drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>>>  drivers/iio/common/ms_sensors/Makefile         |   5 +
>>>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>>>>  drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>>>  6 files changed, 701 insertions(+)
>>>>  create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>>>  create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>>  create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>
>>>> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
>>>> index 790f106..26a6026 100644
>>>> --- a/drivers/iio/common/Kconfig
>>>> +++ b/drivers/iio/common/Kconfig
>>>> @@ -3,5 +3,6 @@
>>>>  #
>>>>
>>>>  source "drivers/iio/common/hid-sensors/Kconfig"
>>>> +source "drivers/iio/common/ms_sensors/Kconfig"
>>>>  source "drivers/iio/common/ssp_sensors/Kconfig"
>>>>  source "drivers/iio/common/st_sensors/Kconfig"
>>>> diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
>>>> index b1e4d9c..585da6a 100644
>>>> --- a/drivers/iio/common/Makefile
>>>> +++ b/drivers/iio/common/Makefile
>>>> @@ -8,5 +8,6 @@
>>>>
>>>>  # When adding new entries keep the list in alphabetical order
>>>>  obj-y += hid-sensors/
>>>> +obj-y += ms_sensors/
>>>>  obj-y += ssp_sensors/
>>>>  obj-y += st_sensors/
>>>> diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
>>>> new file mode 100644
>>>> index 0000000..b28a92b
>>>> --- /dev/null
>>>> +++ b/drivers/iio/common/ms_sensors/Kconfig
>>>> @@ -0,0 +1,6 @@
>>>> +#
>>>> +# Measurements Specialties sensors common library
>>>> +#
>>>> +
>>>> +config IIO_MS_SENSORS_I2C
>>>> +        tristate
>>>> diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
>>>> new file mode 100644
>>>> index 0000000..7846428
>>>> --- /dev/null
>>>> +++ b/drivers/iio/common/ms_sensors/Makefile
>>>> @@ -0,0 +1,5 @@
>>>> +#
>>>> +# Makefile for the Measurement Specialties sensor common modules.
>>>> +#
>>>> +
>>>> +obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
>>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>> new file mode 100644
>>>> index 0000000..f5d27b6
>>>> --- /dev/null
>>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>> @@ -0,0 +1,634 @@
>>>> +/*
>>>> + * Measurements Specialties driver common i2c functions
>>>> + *
>>>> + * Copyright (c) 2015 Measurement-Specialties
>>>> + *
>>>> + * Licensed under the GPL-2.
>>>> + *
>>>> + */
>>>> +
>>>> +#include <linux/module.h>
>>>> +#include <linux/iio/iio.h>
>>>> +#include <linux/device.h>
>>>> +#include <linux/delay.h>
>>>> +
>>>> +#include "ms_sensors_i2c.h"
>>>> +
>>>> +/* Conversion times in us */
>>>> +static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
>>>> +                                                    13000, 7000 };
>>>> +static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
>>>> +                                                    5000, 8000 };
>>>> +static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
>>>> +                                                  4100, 8220, 16440 };
>>>> +
>>>> +#define MS_SENSORS_SERIAL_READ_MSB           0xFA0F
>>>> +#define MS_SENSORS_SERIAL_READ_LSB           0xFCC9
>>>> +#define MS_SENSORS_USER_REG_WRITE            0xE6
>>>> +#define MS_SENSORS_USER_REG_READ             0xE7
>>>> +#define MS_SENSORS_HT_T_CONVERSION_START     0xF3
>>>> +#define MS_SENSORS_HT_H_CONVERSION_START     0xF5
>>>> +
>>>> +#define MS_SENSORS_TP_PROM_READ                      0xA0
>>>> +#define MS_SENSORS_TP_T_CONVERSION_START     0x50
>>>> +#define MS_SENSORS_TP_P_CONVERSION_START     0x40
>>>> +#define MS_SENSORS_TP_ADC_READ                       0x00
>>>> +
>>>> +#define MS_SENSORS_NO_READ_CMD                       0xFF
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_reset() - i2c reset function
>>>> + * @cli:     pointer on i2c client
>>>> + * @cmd:     reset cmd. Depends on device in use
>>>> + * @delay:   usleep minimal delay after reset command is issued
>>>> + *
>>>> + * Generic I2C reset function for Measurement Specialties devices
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay)
>>>> +{
>>>> +     int ret;
>>>> +     struct i2c_client *client = cli;
>>>> +
>>>> +     ret = i2c_smbus_write_byte(client, cmd);
>>>> +     if (ret) {
>>>> +             dev_err(&client->dev, "Failed to reset device\n");
>>>> +             return ret;
>>>> +     }
>>>> +     usleep_range(delay, delay + 1000);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_reset);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_read_prom_word() - i2c prom word read function
>>>> + * @cli:     pointer on i2c client
>>>> + * @cmd:     PROM read cmd. Depends on device and prom id
>>>> + * @word:    pointer on word destination value
>>>> + *
>>>> + * Generic i2c prom word read function for Measurement Specialties devices
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word)
>>>> +{
>>>> +     int ret;
>>>> +     struct i2c_client *client = (struct i2c_client *)cli;
>>>> +
>>>> +     ret = i2c_smbus_read_word_swapped(client, cmd);
>>>> +     if (ret < 0) {
>>>> +             dev_err(&client->dev, "Failed to read prom word\n");
>>>> +             return ret;
>>>> +     }
>>>> +     *word = ret;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_prom_word);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_convert_and_read() - i2c ADC conversion & read function
>>>> + * @cli:     pointer on i2c client
>>>> + * @conv:    ADC conversion command. Depends on device in use
>>>> + * @rd:              ADC read command. Depends on device in use
>>>> + * @delay:   usleep minimal delay after conversion command is issued
>>>> + * @adc:     pointer on ADC destination value
>>>> + *
>>>> + * Generic i2c ADC conversion & read function for Measurement Specialties
>>>> + * devices.
>>>> + * The function will issue conversion command, sleep appopriate delay, and
>>>> + * issue command to read ADC
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>>> +                                 unsigned int delay, u32 *adc)
>>>> +{
>>>> +     int ret;
>>>> +     u32 buf = 0;
>>>> +     struct i2c_client *client = (struct i2c_client *)cli;
>>>> +
>>>> +     /* Trigger conversion */
>>>> +     ret = i2c_smbus_write_byte(client, conv);
>>>> +     if (ret)
>>>> +             goto err;
>>>> +     usleep_range(delay, delay + 1000);
>>>> +
>>>> +     /* Retrieve ADC value */
>>>> +     if (rd != MS_SENSORS_NO_READ_CMD)
>>>> +             ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
>>>> +     else
>>>> +             ret = i2c_master_recv(client, (u8 *)&buf, 3);
>>>> +     if (ret < 0)
>>>> +             goto err;
>>>> +
>>>> +     dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
>>>> +     *adc = be32_to_cpu(buf) >> 8;
>>>> +
>>>> +     return 0;
>>>> +err:
>>>> +     dev_err(&client->dev, "Unable to make sensor adc conversion\n");
>>>> +     return ret;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_convert_and_read);
>>>> +
>>>> +/**
>>>> + * ms_sensors_crc_valid() - CRC check function
>>>> + * @value:   input and CRC compare value
>>>> + *
>>>> + * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
>>>> + * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
>>>> + * The argument contains CRC value in LSB byte while the bytes 1 and 2
>>>> + * are used for CRC computation
>>>> + *
>>>> + * Return: 1 if CRC is valid, 0 otherwise.
>>>> + */
>>>> +static bool ms_sensors_crc_valid(u32 value)
>>>> +{
>>>> +     u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
>>>> +     u32 msb = 0x800000;
>>>> +     u32 mask = 0xFF8000;
>>>> +     u32 result = value & 0xFFFF00;
>>>> +     u8 crc = value & 0xFF;
>>>> +
>>>> +     while (msb != 0x80) {
>>>> +             if (result & msb)
>>>> +                     result = ((result ^ polynom) & mask)
>>>> +                             | (result & ~mask);
>>>> +             msb >>= 1;
>>>> +             mask >>= 1;
>>>> +             polynom >>= 1;
>>>> +     }
>>>> +
>>>> +     return result == crc;
>>>> +}
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>>>> + * @cli:     pointer on i2c client
>>>> + * @sn:              pointer on 64-bits destination value
>>>> + *
>>>> + * Generic i2c serial number read function for Measurement Specialties devices.
>>>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>>>> + * Refer to datasheet:
>>>> + *   http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
>>>> +{
>>>> +     u8 i;
>>>> +     u64 rcv_buf = 0;
>>>> +     u16 send_buf;
>>>> +     int ret;
>>>> +
>>>> +     struct i2c_msg msg[2] = {
>>>> +             {
>>>> +              .addr = client->addr,
>>>> +              .flags = client->flags,
>>>> +              .len = 2,
>>>> +              .buf = (char *)&send_buf,
>>> If you are going to type cast, please match the (__u8 *) from
>>> include/uapi/linux/i2c.h
>> I am trying to push similar function (i2c_addressed_read) to i2c interface and
>> since this driver has created its own instance of it, I would prefer
>> we put it into
>> i2c-core.c . Could you please support that debate [1] ? I think there are quite
>> many drivers out there using the same function in a various way and it is
>> about time to have it included in i2c to have more uniform control.
> 
> You should use: regmap_i2c_read (#include <linux/regmap.h>)
Whilst I'd be in favour of this driver switching over to regmap and
hence making this available, it is worth noting that is a much
bigger change than a simple function call!

Jonathan
> 
>>>> +              },
>>>> +             {
>>>> +              .addr = client->addr,
>>>> +              .flags = client->flags | I2C_M_RD,
>>>> +              .buf = (char *)&rcv_buf,
>>>> +              },
>>>> +     };
>>>> +
>>>> +     /* Read MSB part of serial number */
>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>>>> +     msg[1].len = 8;
>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>> +     if (ret < 0)
>>>> +             goto err;
>>>> +
>>>> +     rcv_buf = be64_to_cpu(rcv_buf);
>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>> +
>>>> +     for (i = 0; i < 64; i += 16) {
>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>>>> +                     return -ENODEV;
>>>> +     }
>>>> +
>>>> +     *sn = (((rcv_buf >> 32) & 0xFF000000) |
>>>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>>>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>>>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>>>> +
>>>> +     /* Read LSB part of serial number */
>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>>>> +     msg[1].len = 6;
>>>> +     rcv_buf = 0;
>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>> +     if (ret < 0)
>>>> +             goto err;
>>>> +
>>>> +     rcv_buf = be64_to_cpu(rcv_buf) >> 16;
>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>> +
>>>> +     for (i = 0; i < 48; i += 24) {
>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
>>>> +                     return -ENODEV;
>>>> +     }
>>>> +
>>>> +     *sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>>>> +
>>>> +     return 0;
>>>> +
>>>> +err:
>>> Put this inline and drop the goto
>>>> +     dev_err(&client->dev, "Unable to read device serial number");
>>>> +     return ret;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>>>> +
>>> What is meant by a user_reg as opposed to other regs?
>>>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
>>>> +                                     u8 *user_reg)
>>>> +{
>>>> +     int ret;
>>>> +
>>>> +     ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
>>>> +     if (ret)
>>>> +             goto err;
>>>> +
>>>> +     ret = i2c_master_recv(client, user_reg, 1);
>>>> +     if (ret < 0)
>>>> +             goto err;
>>>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>>>> +
>>>> +     return 0;
>>>> +err:
>>>> +     dev_err(&client->dev, "Unable to read user reg");
>>>> +     return ret;
>>>> +}
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @i:               resolution index to set
>>>> + *
>>>> + * That function will program the appropriate resolution based on the index
>>>> + * provided when user space will set samp_freq channel.
>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
>>>> +                                     u8 i)
>>>> +{
>>>> +     u8 user_reg;
>>>> +     int ret;
>>>> +
>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     user_reg &= 0x7E;
>>>> +     user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
>>>> +
>>>> +     return i2c_smbus_write_byte_data(dev_data->client,
>>>> +                                      MS_SENSORS_USER_REG_WRITE,
>>>> +                                      user_reg);
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @buf:     pointer on char buffer to write result
>>>> + *
>>>> + * That function will read battery indicator value in the device and
>>>> + * return 1 if the device voltage is below 2.25V.
>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>> + *
>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>> + */
>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
>>>> +                                     char *buf)
>>>> +{
>>>> +     int ret;
>>>> +     u8 user_reg;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_show_heater() - show device heater
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @buf:     pointer on char buffer to write result
>>>> + *
>>>> + * That function will read heater enable value in the device and
>>>> + * return 1 if the heater is enabled
>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>> + *
>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>> + */
>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>>>> +                                char *buf)
>>>> +{
>>>> +     u8 user_reg;
>>>> +     int ret;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_write_heater() - write device heater
>>> I'm not sure the _i2c_ bit is important in this function name...
>>>
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @buf:     pointer on char buffer from user space
>>>> + * @len:     length of buf
>>>> + *
>>>> + * That function will write 1 or 0 value in the device
>>>> + * to enable or disable heater
>>>> + * That function is used for HTU21 and MS8607 chipsets
>>> That->This
>>>> + *
>>>> + * Return: length of buffer, negative errno otherwise.
>>>> + */
>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>> +                                 const char *buf, size_t len)
>>>> +{
>>>> +     u8 val, user_reg;
>>>> +     int ret;
>>>> +
>>>> +     ret = kstrtou8(buf, 10, &val);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     if (val > 1)
>>>> +             return -EINVAL;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>> +     if (ret) {
>>>> +             mutex_unlock(&dev_data->lock);
>>>> +             return ret;
>>>> +     }
>>>> +
>>>> +     user_reg &= 0xFB;
>>>> +     user_reg |= val << 2;
>>>> +
>>>> +     ret = i2c_smbus_write_byte_data(dev_data->client,
>>>> +                                     MS_SENSORS_USER_REG_WRITE,
>>>> +                                     user_reg);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret) {
>>>> +             dev_err(&dev_data->client->dev, "Unable to write user reg\n");
>>>> +             return ret;
>>>> +     }
>>>> +
>>>> +     return len;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @temperature:pointer on temperature destination value
>>>> + *
>>>> + * That function will get temperature ADC value from the device,
>>>> + * check the CRC and compute the temperature value.
>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>> +                                    s32 *temperature)
>>>> +{
>>>> +     int ret;
>>>> +     u32 adc;
>>>> +     u16 delay;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>> +                                           MS_SENSORS_HT_T_CONVERSION_START,
>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>> +                                           delay, &adc);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>> +             dev_err(&dev_data->client->dev,
>>>> +                     "Temperature read crc check error\n");
>>>> +             return -ENODEV;
>>>> +     }
>>>> +
>>>> +     /* Temperature algorithm */
>>>> +     *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>>>> +
>>>> +/**
>>>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>> + * @humidity:        pointer on humidity destination value
>>>> + *
>>>> + * That function will get humidity ADC value from the device,
>>>> + * check the CRC and compute the temperature value.
>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>> +                                 u32 *humidity)
>>>> +{
>>>> +     int ret;
>>>> +     u32 adc;
>>>> +     u16 delay;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>> +                                           MS_SENSORS_HT_H_CONVERSION_START,
>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>> +                                           delay, &adc);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>> +             dev_err(&dev_data->client->dev,
>>>> +                     "Humidity read crc check error\n");
>>>> +             return -ENODEV;
>>>> +     }
>>>> +
>>>> +     /* Humidity algorithm */
>>>> +     *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>>>> +     if (*humidity >= 100000)
>>>> +             *humidity = 100000;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>>>> +
>>> Multiline comment syntax is
>>> /*
>>>  * CRC...
>>>  */
>>>  Or ideally use kernel-doc as you have for other functions below
>>>  (not required as not exported)
>>>
>>>> +/* CRC check function for Temperature and pressure devices
>>>> + * That function is only used when reading PROM coefficients */
>>>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>>>> +{
>>>> +     unsigned int cnt, n_bit;
>>>> +     u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
>>>> +
>>>> +     prom[len - 1] = 0;
>>>> +     prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
>>>> +
>>>> +     for (cnt = 0; cnt < len * 2; cnt++) {
>>>> +             if (cnt % 2 == 1)
>>>> +                     n_rem ^= prom[cnt >> 1] & 0x00FF;
>>>> +             else
>>>> +                     n_rem ^= prom[cnt >> 1] >> 8;
>>>> +
>>>> +             for (n_bit = 8; n_bit > 0; n_bit--) {
>>>> +                     if (n_rem & 0x8000)
>>>> +                             n_rem = (n_rem << 1) ^ 0x3000;
>>>> +                     else
>>>> +                             n_rem <<= 1;
>>>> +             }
>>>> +     }
>>>> +     n_rem >>= 12;
>>>> +     prom[0] = crc_read;
>>>> +
>>>> +     return n_rem == crc;
>>>> +}
>>>> +
>>>> +/**
>>>> + * ms_sensors_tp_read_prom() - prom coeff read function
>>>> + * @dev_data:        pointer on temperature/pressure device data
>>> pointer to temperature/... (fix throughout driver please)
>>>> + *
>>>> + * That function will read prom coefficients and check CRC
>>> That -> This (and add a full stop at the end of the sentence.
>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>>>> +{
>>>> +     int i, ret;
>>>> +
>>>> +     for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>>>> +             ret = ms_sensors_i2c_read_prom_word(
>>>> +                                     dev_data->client,
>>>> +                                     MS_SENSORS_TP_PROM_READ + (i << 1),
>>>> +                                     &dev_data->prom[i]);
>>>> +
>>>> +             if (ret)
>>>> +                     return ret;
>>>> +     }
>>>> +
>>>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>>>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
>>>> +             dev_err(&dev_data->client->dev,
>>>> +                     "Calibration coefficients crc check error\n");
>>>> +             return -ENODEV;
>>>> +     }
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>>>> +
>>>> +/**
>>>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>>>> + * @dev_data:        pointer on temperature/pressure device data
>>> pointer to
>>>> + * @temperature:pointer on temperature destination value
>>> pointer to (also missing tab?)
>>>> + * @pressure:        pointer on pressure destination value
>>>> + *
>>>> + * That function will read ADC and compute pressure and temperature value
>>> That->This and full stop at end of sentence.
>>>
>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>> + *
>>>> + * Return: 0 on success, negative errno otherwise.
>>>> + */
>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>> +                                   int *temperature,
>>>> +                                   unsigned int *pressure)
>>>> +{
>>>> +     int ret;
>>>> +     u32 t_adc, p_adc;
>>>> +     s32 dt, temp;
>>>> +     s64 off, sens, t2, off2, sens2;
>>>> +     u16 *prom = dev_data->prom, delay;
>>>> +     u8 i;
>>>> +
>>>> +     mutex_lock(&dev_data->lock);
>>>> +     i = dev_data->res_index * 2;
>>>> +     delay = ms_sensors_tp_conversion_time[dev_data->res_index];
>>> Blank line here would improve readability.
>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>> +                                     dev_data->client,
>>>> +                                     MS_SENSORS_TP_T_CONVERSION_START + i,
>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>> +                                     delay, &t_adc);
>>>> +     if (ret) {
>>>> +             mutex_unlock(&dev_data->lock);
>>>> +             return ret;
>>>> +     }
>>> blank line here.
>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>> +                                     dev_data->client,
>>>> +                                     MS_SENSORS_TP_P_CONVERSION_START + i,
>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>> +                                     delay, &p_adc);
>>>> +     mutex_unlock(&dev_data->lock);
>>>> +     if (ret)
>>>> +             return ret;
>>>> +
>>>> +     dt = (s32)t_adc - (prom[5] << 8);
>>>> +
>>>> +     /* Actual temperature = 2000 + dT * TEMPSENS */
>>>> +     temp = 2000 + (((s64)dt * prom[6]) >> 23);
>>>> +
>>>> +     /* Second order temperature compensation */
>>>> +     if (temp < 2000) {
>>>> +             s64 tmp = (s64)temp - 2000;
>>>> +
>>>> +             t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
>>>> +             off2 = (61 * tmp * tmp) >> 4;
>>>> +             sens2 = (29 * tmp * tmp) >> 4;
>>>> +
>>>> +             if (temp < -1500) {
>>>> +                     s64 tmp = (s64)temp + 1500;
>>>> +
>>>> +                     off2 += 17 * tmp * tmp;
>>>> +                     sens2 += 9 * tmp * tmp;
>>>> +             }
>>>> +     } else {
>>>> +             t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
>>>> +             off2 = 0;
>>>> +             sens2 = 0;
>>>> +     }
>>>> +
>>>> +     /* OFF = OFF_T1 + TCO * dT */
>>>> +     off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
>>>> +     off -= off2;
>>>> +
>>>> +     /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
>>>> +     sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
>>>> +     sens -= sens2;
>>>> +
>>>> +     /* Temperature compensated pressure = D1 * SENS - OFF */
>>>> +     *temperature = (temp - t2) * 10;
>>>> +     *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>>>> +
>>>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>>>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>>>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>>>> +MODULE_LICENSE("GPL v2");
>>>> +
>>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>> new file mode 100644
>>>> index 0000000..a521428
>>>> --- /dev/null
>>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>> @@ -0,0 +1,54 @@
>>>> +/*
>>>> + * Measurements Specialties common sensor driver
>>>> + *
>>>> + * Copyright (c) 2015 Measurement-Specialties
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>> Unnecesary blank line here.
>>>> + */
>>>> +
>>>> +#ifndef _MS_SENSORS_I2C_H
>>>> +#define _MS_SENSORS_I2C_H
>>>> +
>>>> +#include <linux/i2c.h>
>>>> +#include <linux/mutex.h>
>>>> +
>>>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>>>> +
>>>> +struct ms_ht_dev {
>>>> +     struct i2c_client *client;
>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>> +     u8 res_index;
>>>> +};
>>>> +
>>>> +struct ms_tp_dev {
>>>> +     struct i2c_client *client;
>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>> +     /* Added element for CRC computation */
>>>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>>>> +     u8 res_index;
>>>> +};
>>>> +
>>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>>> +                                 unsigned int delay, u32 *adc);
>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
>>>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>> +                                 const char *buf, size_t len);
>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>> +                                    s32 *temperature);
>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>> +                                 u32 *humidity);
>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>> +                                   int *temperature,
>>>> +                                   unsigned int *pressure);
>>>> +
>>>> +#endif /* _MS_SENSORS_I2C_H */
>>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> [1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-08-15 20:09         ` Jonathan Cameron
@ 2015-09-14 12:56           ` ludovic.tancerel
  2015-09-20 19:22             ` Jonathan Cameron
  0 siblings, 1 reply; 25+ messages in thread
From: ludovic.tancerel @ 2015-09-14 12:56 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Crt Mori, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	linux-iio, William.Markezana

Hello Jonathan, all,
Thank you for commenting the patchset.
I am sorry for the delay in looking in your feedback.

Most of the comments I had on different drivers are minor, and the =
patchset update I will provide will comply on the feedback.

The only item that needs clarification is about switching over to =
regmap.
I already considered using regmap previously, and my understanding was =
that this was not applicable for some of the i2c accesses that were done =
in my driver.
If there is no strong push from you on this, I will leave the code as it =
is and correct the casting comment.

Please, let me know if you disagree with this.
I plan on submitting the patchset update soon.

Thank you,
regards,
Ludovic


Le 15 ao=FBt 2015 =E0 22:09, Jonathan Cameron <jic23@kernel.org> a =E9crit=
 :

> On 10/08/15 12:07, Crt Mori wrote:
>> On 10 August 2015 at 09:43, Crt Mori <cmo@melexis.com> wrote:
>>> On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> =
wrote:
>>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>>>> Signed-off-by: Ludovic Tancerel =
<ludovic.tancerel@maplehightech.com>
>>>> A few bits inline.
>>>> Also, would prefer some basic description of the patch up here...
>>>>> ---
>>>>> drivers/iio/common/Kconfig                     |   1 +
>>>>> drivers/iio/common/Makefile                    |   1 +
>>>>> drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>>>> drivers/iio/common/ms_sensors/Makefile         |   5 +
>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 =
+++++++++++++++++++++++++
>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>>>> 6 files changed, 701 insertions(+)
>>>>> create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>>>> create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>=20
>>>>> diff --git a/drivers/iio/common/Kconfig =
b/drivers/iio/common/Kconfig
>>>>> index 790f106..26a6026 100644
>>>>> --- a/drivers/iio/common/Kconfig
>>>>> +++ b/drivers/iio/common/Kconfig
>>>>> @@ -3,5 +3,6 @@
>>>>> #
>>>>>=20
>>>>>=20

=85

>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>>>>> + * @cli:     pointer on i2c client
>>>>> + * @sn:              pointer on 64-bits destination value
>>>>> + *
>>>>> + * Generic i2c serial number read function for Measurement =
Specialties devices.
>>>>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>>>>> + * Refer to datasheet:
>>>>> + *   =
http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 =
*sn)
>>>>> +{
>>>>> +     u8 i;
>>>>> +     u64 rcv_buf =3D 0;
>>>>> +     u16 send_buf;
>>>>> +     int ret;
>>>>> +
>>>>> +     struct i2c_msg msg[2] =3D {
>>>>> +             {
>>>>> +              .addr =3D client->addr,
>>>>> +              .flags =3D client->flags,
>>>>> +              .len =3D 2,
>>>>> +              .buf =3D (char *)&send_buf,
>>>> If you are going to type cast, please match the (__u8 *) from
>>>> include/uapi/linux/i2c.h
>>> I am trying to push similar function (i2c_addressed_read) to i2c =
interface and
>>> since this driver has created its own instance of it, I would prefer
>>> we put it into
>>> i2c-core.c . Could you please support that debate [1] ? I think =
there are quite
>>> many drivers out there using the same function in a various way and =
it is
>>> about time to have it included in i2c to have more uniform control.
>>=20
>> You should use: regmap_i2c_read (#include <linux/regmap.h>)
> Whilst I'd be in favour of this driver switching over to regmap and
> hence making this available, it is worth noting that is a much
> bigger change than a simple function call!
>=20
> Jonathan
>>=20
>>>>> +              },
>>>>> +             {
>>>>> +              .addr =3D client->addr,
>>>>> +              .flags =3D client->flags | I2C_M_RD,
>>>>> +              .buf =3D (char *)&rcv_buf,
>>>>> +              },
>>>>> +     };
>>>>> +
>>>>> +     /* Read MSB part of serial number */
>>>>> +     send_buf =3D cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>>>>> +     msg[1].len =3D 8;
>>>>> +     ret =3D i2c_transfer(client->adapter, msg, 2);
>>>>> +     if (ret < 0)
>>>>> +             goto err;
>>>>> +
>>>>> +     rcv_buf =3D be64_to_cpu(rcv_buf);
>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>> +
>>>>> +     for (i =3D 0; i < 64; i +=3D 16) {
>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>>>>> +                     return -ENODEV;
>>>>> +     }
>>>>> +
>>>>> +     *sn =3D (((rcv_buf >> 32) & 0xFF000000) |
>>>>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>>>>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>>>>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>>>>> +
>>>>> +     /* Read LSB part of serial number */
>>>>> +     send_buf =3D cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>>>>> +     msg[1].len =3D 6;
>>>>> +     rcv_buf =3D 0;
>>>>> +     ret =3D i2c_transfer(client->adapter, msg, 2);
>>>>> +     if (ret < 0)
>>>>> +             goto err;
>>>>> +
>>>>> +     rcv_buf =3D be64_to_cpu(rcv_buf) >> 16;
>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>> +
>>>>> +     for (i =3D 0; i < 48; i +=3D 24) {
>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & =
0xFFFFFF))
>>>>> +                     return -ENODEV;
>>>>> +     }
>>>>> +
>>>>> +     *sn |=3D (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>>>>> +
>>>>> +     return 0;
>>>>> +
>>>>> +err:
>>>> Put this inline and drop the goto
>>>>> +     dev_err(&client->dev, "Unable to read device serial =
number");
>>>>> +     return ret;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>>>>> +
>>>> What is meant by a user_reg as opposed to other regs?
>>>>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client =
*client,
>>>>> +                                     u8 *user_reg)
>>>>> +{
>>>>> +     int ret;
>>>>> +
>>>>> +     ret =3D i2c_smbus_write_byte(client, =
MS_SENSORS_USER_REG_READ);
>>>>> +     if (ret)
>>>>> +             goto err;
>>>>> +
>>>>> +     ret =3D i2c_master_recv(client, user_reg, 1);
>>>>> +     if (ret < 0)
>>>>> +             goto err;
>>>>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>>>>> +
>>>>> +     return 0;
>>>>> +err:
>>>>> +     dev_err(&client->dev, "Unable to read user reg");
>>>>> +     return ret;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_write_resolution() - set resolution i2c =
function
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @i:               resolution index to set
>>>>> + *
>>>>> + * That function will program the appropriate resolution based on =
the index
>>>>> + * provided when user space will set samp_freq channel.
>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev =
*dev_data,
>>>>> +                                     u8 i)
>>>>> +{
>>>>> +     u8 user_reg;
>>>>> +     int ret;
>>>>> +
>>>>> +     ret =3D ms_sensors_i2c_read_user_reg(dev_data->client, =
&user_reg);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     user_reg &=3D 0x7E;
>>>>> +     user_reg |=3D ((i & 1) << 7) + ((i & 2) >> 1);
>>>>> +
>>>>> +     return i2c_smbus_write_byte_data(dev_data->client,
>>>>> +                                      MS_SENSORS_USER_REG_WRITE,
>>>>> +                                      user_reg);
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_show_battery_low() - show device battery low =
indicator
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @buf:     pointer on char buffer to write result
>>>>> + *
>>>>> + * That function will read battery indicator value in the device =
and
>>>>> + * return 1 if the device voltage is below 2.25V.
>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: length of sprintf on success, negative errno =
otherwise.
>>>>> + */
>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev =
*dev_data,
>>>>> +                                     char *buf)
>>>>> +{
>>>>> +     int ret;
>>>>> +     u8 user_reg;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     ret =3D ms_sensors_i2c_read_user_reg(dev_data->client, =
&user_reg);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_show_heater() - show device heater
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @buf:     pointer on char buffer to write result
>>>>> + *
>>>>> + * That function will read heater enable value in the device and
>>>>> + * return 1 if the heater is enabled
>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: length of sprintf on success, negative errno =
otherwise.
>>>>> + */
>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>>>>> +                                char *buf)
>>>>> +{
>>>>> +     u8 user_reg;
>>>>> +     int ret;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     ret =3D ms_sensors_i2c_read_user_reg(dev_data->client, =
&user_reg);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_write_heater() - write device heater
>>>> I'm not sure the _i2c_ bit is important in this function name...
>>>>=20
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @buf:     pointer on char buffer from user space
>>>>> + * @len:     length of buf
>>>>> + *
>>>>> + * That function will write 1 or 0 value in the device
>>>>> + * to enable or disable heater
>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>> That->This
>>>>> + *
>>>>> + * Return: length of buffer, negative errno otherwise.
>>>>> + */
>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>> +                                 const char *buf, size_t len)
>>>>> +{
>>>>> +     u8 val, user_reg;
>>>>> +     int ret;
>>>>> +
>>>>> +     ret =3D kstrtou8(buf, 10, &val);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     if (val > 1)
>>>>> +             return -EINVAL;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     ret =3D ms_sensors_i2c_read_user_reg(dev_data->client, =
&user_reg);
>>>>> +     if (ret) {
>>>>> +             mutex_unlock(&dev_data->lock);
>>>>> +             return ret;
>>>>> +     }
>>>>> +
>>>>> +     user_reg &=3D 0xFB;
>>>>> +     user_reg |=3D val << 2;
>>>>> +
>>>>> +     ret =3D i2c_smbus_write_byte_data(dev_data->client,
>>>>> +                                     MS_SENSORS_USER_REG_WRITE,
>>>>> +                                     user_reg);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret) {
>>>>> +             dev_err(&dev_data->client->dev, "Unable to write =
user reg\n");
>>>>> +             return ret;
>>>>> +     }
>>>>> +
>>>>> +     return len;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @temperature:pointer on temperature destination value
>>>>> + *
>>>>> + * That function will get temperature ADC value from the device,
>>>>> + * check the CRC and compute the temperature value.
>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev =
*dev_data,
>>>>> +                                    s32 *temperature)
>>>>> +{
>>>>> +     int ret;
>>>>> +     u32 adc;
>>>>> +     u16 delay;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     delay =3D =
ms_sensors_ht_t_conversion_time[dev_data->res_index];
>>>>> +     ret =3D ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>> +                                           =
MS_SENSORS_HT_T_CONVERSION_START,
>>>>> +                                           =
MS_SENSORS_NO_READ_CMD,
>>>>> +                                           delay, &adc);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>> +             dev_err(&dev_data->client->dev,
>>>>> +                     "Temperature read crc check error\n");
>>>>> +             return -ENODEV;
>>>>> +     }
>>>>> +
>>>>> +     /* Temperature algorithm */
>>>>> +     *temperature =3D (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>>>>> +
>>>>> +     return 0;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>> + * @humidity:        pointer on humidity destination value
>>>>> + *
>>>>> + * That function will get humidity ADC value from the device,
>>>>> + * check the CRC and compute the temperature value.
>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>> +                                 u32 *humidity)
>>>>> +{
>>>>> +     int ret;
>>>>> +     u32 adc;
>>>>> +     u16 delay;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     delay =3D =
ms_sensors_ht_h_conversion_time[dev_data->res_index];
>>>>> +     ret =3D ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>> +                                           =
MS_SENSORS_HT_H_CONVERSION_START,
>>>>> +                                           =
MS_SENSORS_NO_READ_CMD,
>>>>> +                                           delay, &adc);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>> +             dev_err(&dev_data->client->dev,
>>>>> +                     "Humidity read crc check error\n");
>>>>> +             return -ENODEV;
>>>>> +     }
>>>>> +
>>>>> +     /* Humidity algorithm */
>>>>> +     *humidity =3D (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>>>>> +     if (*humidity >=3D 100000)
>>>>> +             *humidity =3D 100000;
>>>>> +
>>>>> +     return 0;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>>>>> +
>>>> Multiline comment syntax is
>>>> /*
>>>> * CRC...
>>>> */
>>>> Or ideally use kernel-doc as you have for other functions below
>>>> (not required as not exported)
>>>>=20
>>>>> +/* CRC check function for Temperature and pressure devices
>>>>> + * That function is only used when reading PROM coefficients */
>>>>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>>>>> +{
>>>>> +     unsigned int cnt, n_bit;
>>>>> +     u16 n_rem =3D 0x0000, crc_read =3D prom[0], crc =3D (*prom & =
0xF000) >> 12;
>>>>> +
>>>>> +     prom[len - 1] =3D 0;
>>>>> +     prom[0] &=3D 0x0FFF;      /* Clear the CRC computation part =
*/
>>>>> +
>>>>> +     for (cnt =3D 0; cnt < len * 2; cnt++) {
>>>>> +             if (cnt % 2 =3D=3D 1)
>>>>> +                     n_rem ^=3D prom[cnt >> 1] & 0x00FF;
>>>>> +             else
>>>>> +                     n_rem ^=3D prom[cnt >> 1] >> 8;
>>>>> +
>>>>> +             for (n_bit =3D 8; n_bit > 0; n_bit--) {
>>>>> +                     if (n_rem & 0x8000)
>>>>> +                             n_rem =3D (n_rem << 1) ^ 0x3000;
>>>>> +                     else
>>>>> +                             n_rem <<=3D 1;
>>>>> +             }
>>>>> +     }
>>>>> +     n_rem >>=3D 12;
>>>>> +     prom[0] =3D crc_read;
>>>>> +
>>>>> +     return n_rem =3D=3D crc;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_tp_read_prom() - prom coeff read function
>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>> pointer to temperature/... (fix throughout driver please)
>>>>> + *
>>>>> + * That function will read prom coefficients and check CRC
>>>> That -> This (and add a full stop at the end of the sentence.
>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>>>>> +{
>>>>> +     int i, ret;
>>>>> +
>>>>> +     for (i =3D 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>>>>> +             ret =3D ms_sensors_i2c_read_prom_word(
>>>>> +                                     dev_data->client,
>>>>> +                                     MS_SENSORS_TP_PROM_READ + (i =
<< 1),
>>>>> +                                     &dev_data->prom[i]);
>>>>> +
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>> +     }
>>>>> +
>>>>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>>>>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + =
1)) {
>>>>> +             dev_err(&dev_data->client->dev,
>>>>> +                     "Calibration coefficients crc check =
error\n");
>>>>> +             return -ENODEV;
>>>>> +     }
>>>>> +
>>>>> +     return 0;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>>>>> +
>>>>> +/**
>>>>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>> pointer to
>>>>> + * @temperature:pointer on temperature destination value
>>>> pointer to (also missing tab?)
>>>>> + * @pressure:        pointer on pressure destination value
>>>>> + *
>>>>> + * That function will read ADC and compute pressure and =
temperature value
>>>> That->This and full stop at end of sentence.
>>>>=20
>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>> + *
>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>> + */
>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>> +                                   int *temperature,
>>>>> +                                   unsigned int *pressure)
>>>>> +{
>>>>> +     int ret;
>>>>> +     u32 t_adc, p_adc;
>>>>> +     s32 dt, temp;
>>>>> +     s64 off, sens, t2, off2, sens2;
>>>>> +     u16 *prom =3D dev_data->prom, delay;
>>>>> +     u8 i;
>>>>> +
>>>>> +     mutex_lock(&dev_data->lock);
>>>>> +     i =3D dev_data->res_index * 2;
>>>>> +     delay =3D =
ms_sensors_tp_conversion_time[dev_data->res_index];
>>>> Blank line here would improve readability.
>>>>> +     ret =3D ms_sensors_i2c_convert_and_read(
>>>>> +                                     dev_data->client,
>>>>> +                                     =
MS_SENSORS_TP_T_CONVERSION_START + i,
>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>> +                                     delay, &t_adc);
>>>>> +     if (ret) {
>>>>> +             mutex_unlock(&dev_data->lock);
>>>>> +             return ret;
>>>>> +     }
>>>> blank line here.
>>>>> +     ret =3D ms_sensors_i2c_convert_and_read(
>>>>> +                                     dev_data->client,
>>>>> +                                     =
MS_SENSORS_TP_P_CONVERSION_START + i,
>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>> +                                     delay, &p_adc);
>>>>> +     mutex_unlock(&dev_data->lock);
>>>>> +     if (ret)
>>>>> +             return ret;
>>>>> +
>>>>> +     dt =3D (s32)t_adc - (prom[5] << 8);
>>>>> +
>>>>> +     /* Actual temperature =3D 2000 + dT * TEMPSENS */
>>>>> +     temp =3D 2000 + (((s64)dt * prom[6]) >> 23);
>>>>> +
>>>>> +     /* Second order temperature compensation */
>>>>> +     if (temp < 2000) {
>>>>> +             s64 tmp =3D (s64)temp - 2000;
>>>>> +
>>>>> +             t2 =3D (3 * ((s64)dt * (s64)dt)) >> 33;
>>>>> +             off2 =3D (61 * tmp * tmp) >> 4;
>>>>> +             sens2 =3D (29 * tmp * tmp) >> 4;
>>>>> +
>>>>> +             if (temp < -1500) {
>>>>> +                     s64 tmp =3D (s64)temp + 1500;
>>>>> +
>>>>> +                     off2 +=3D 17 * tmp * tmp;
>>>>> +                     sens2 +=3D 9 * tmp * tmp;
>>>>> +             }
>>>>> +     } else {
>>>>> +             t2 =3D (5 * ((s64)dt * (s64)dt)) >> 38;
>>>>> +             off2 =3D 0;
>>>>> +             sens2 =3D 0;
>>>>> +     }
>>>>> +
>>>>> +     /* OFF =3D OFF_T1 + TCO * dT */
>>>>> +     off =3D (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) =
>> 6);
>>>>> +     off -=3D off2;
>>>>> +
>>>>> +     /* Sensitivity at actual temperature =3D SENS_T1 + TCS * dT =
*/
>>>>> +     sens =3D (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> =
7);
>>>>> +     sens -=3D sens2;
>>>>> +
>>>>> +     /* Temperature compensated pressure =3D D1 * SENS - OFF */
>>>>> +     *temperature =3D (temp - t2) * 10;
>>>>> +     *pressure =3D (u32)(((((s64)p_adc * sens) >> 21) - off) >> =
15);
>>>>> +
>>>>> +     return 0;
>>>>> +}
>>>>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>>>>> +
>>>>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>>>>> +MODULE_AUTHOR("William Markezana =
<william.markezana@meas-spec.com>");
>>>>> +MODULE_AUTHOR("Ludovic Tancerel =
<ludovic.tancerel@maplehightech.com>");
>>>>> +MODULE_LICENSE("GPL v2");
>>>>> +
>>>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h =
b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>> new file mode 100644
>>>>> index 0000000..a521428
>>>>> --- /dev/null
>>>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>> @@ -0,0 +1,54 @@
>>>>> +/*
>>>>> + * Measurements Specialties common sensor driver
>>>>> + *
>>>>> + * Copyright (c) 2015 Measurement-Specialties
>>>>> + *
>>>>> + * This program is free software; you can redistribute it and/or =
modify
>>>>> + * it under the terms of the GNU General Public License version 2 =
as
>>>>> + * published by the Free Software Foundation.
>>>>> + *
>>>> Unnecesary blank line here.
>>>>> + */
>>>>> +
>>>>> +#ifndef _MS_SENSORS_I2C_H
>>>>> +#define _MS_SENSORS_I2C_H
>>>>> +
>>>>> +#include <linux/i2c.h>
>>>>> +#include <linux/mutex.h>
>>>>> +
>>>>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>>>>> +
>>>>> +struct ms_ht_dev {
>>>>> +     struct i2c_client *client;
>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>> +     u8 res_index;
>>>>> +};
>>>>> +
>>>>> +struct ms_tp_dev {
>>>>> +     struct i2c_client *client;
>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>> +     /* Added element for CRC computation */
>>>>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>>>>> +     u8 res_index;
>>>>> +};
>>>>> +
>>>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>>>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>>>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>>>> +                                 unsigned int delay, u32 *adc);
>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 =
*sn);
>>>>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, =
char *buf);
>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev =
*dev_data, u8 i);
>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev =
*dev_data, char *buf);
>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, =
char *buf);
>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>> +                                 const char *buf, size_t len);
>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev =
*dev_data,
>>>>> +                                    s32 *temperature);
>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>> +                                 u32 *humidity);
>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>> +                                   int *temperature,
>>>>> +                                   unsigned int *pressure);
>>>>> +
>>>>> +#endif /* _MS_SENSORS_I2C_H */
>>>>>=20
>>>>=20
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe =
linux-iio" in
>>>> the body of a message to majordomo@vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>=20
>>> [1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906
>=20

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-09-14 12:56           ` ludovic.tancerel
@ 2015-09-20 19:22             ` Jonathan Cameron
  2015-09-23 20:55               ` ludovic.tancerel
  0 siblings, 1 reply; 25+ messages in thread
From: Jonathan Cameron @ 2015-09-20 19:22 UTC (permalink / raw)
  To: ludovic.tancerel@maplehightech.com
  Cc: Crt Mori, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	linux-iio, William.Markezana

On 14/09/15 13:56, ludovic.tancerel@maplehightech.com wrote:
> Hello Jonathan, all,
> Thank you for commenting the patchset.
> I am sorry for the delay in looking in your feedback.
> 
> Most of the comments I had on different drivers are minor, and the patchset update I will provide will comply on the feedback.
> 
> The only item that needs clarification is about switching over to regmap.
> I already considered using regmap previously, and my understanding was that this was not applicable for some of the i2c accesses that were done in my driver.
> If there is no strong push from you on this, I will leave the code as it is and correct the casting comment.
I'm not that bothered about moving over to regmap, though the addition of
a convenience function for the particular case you have in this driver
is an added reason to consider it.  

Entirely up to you as far as I'm concerned.

> 
> Please, let me know if you disagree with this.
> I plan on submitting the patchset update soon.
> 
> Thank you,
> regards,
> Ludovic
> 
> 
> Le 15 août 2015 à 22:09, Jonathan Cameron <jic23@kernel.org> a écrit :
> 
>> On 10/08/15 12:07, Crt Mori wrote:
>>> On 10 August 2015 at 09:43, Crt Mori <cmo@melexis.com> wrote:
>>>> On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> wrote:
>>>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>>>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>>>>> A few bits inline.
>>>>> Also, would prefer some basic description of the patch up here...
>>>>>> ---
>>>>>> drivers/iio/common/Kconfig                     |   1 +
>>>>>> drivers/iio/common/Makefile                    |   1 +
>>>>>> drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>>>>> drivers/iio/common/ms_sensors/Makefile         |   5 +
>>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>>>>> 6 files changed, 701 insertions(+)
>>>>>> create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>>>>> create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>>
>>>>>> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
>>>>>> index 790f106..26a6026 100644
>>>>>> --- a/drivers/iio/common/Kconfig
>>>>>> +++ b/drivers/iio/common/Kconfig
>>>>>> @@ -3,5 +3,6 @@
>>>>>> #
>>>>>>
>>>>>>
> 
> …
> 
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>>>>>> + * @cli:     pointer on i2c client
>>>>>> + * @sn:              pointer on 64-bits destination value
>>>>>> + *
>>>>>> + * Generic i2c serial number read function for Measurement Specialties devices.
>>>>>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>>>>>> + * Refer to datasheet:
>>>>>> + *   http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
>>>>>> +{
>>>>>> +     u8 i;
>>>>>> +     u64 rcv_buf = 0;
>>>>>> +     u16 send_buf;
>>>>>> +     int ret;
>>>>>> +
>>>>>> +     struct i2c_msg msg[2] = {
>>>>>> +             {
>>>>>> +              .addr = client->addr,
>>>>>> +              .flags = client->flags,
>>>>>> +              .len = 2,
>>>>>> +              .buf = (char *)&send_buf,
>>>>> If you are going to type cast, please match the (__u8 *) from
>>>>> include/uapi/linux/i2c.h
>>>> I am trying to push similar function (i2c_addressed_read) to i2c interface and
>>>> since this driver has created its own instance of it, I would prefer
>>>> we put it into
>>>> i2c-core.c . Could you please support that debate [1] ? I think there are quite
>>>> many drivers out there using the same function in a various way and it is
>>>> about time to have it included in i2c to have more uniform control.
>>>
>>> You should use: regmap_i2c_read (#include <linux/regmap.h>)
>> Whilst I'd be in favour of this driver switching over to regmap and
>> hence making this available, it is worth noting that is a much
>> bigger change than a simple function call!
>>
>> Jonathan
>>>
>>>>>> +              },
>>>>>> +             {
>>>>>> +              .addr = client->addr,
>>>>>> +              .flags = client->flags | I2C_M_RD,
>>>>>> +              .buf = (char *)&rcv_buf,
>>>>>> +              },
>>>>>> +     };
>>>>>> +
>>>>>> +     /* Read MSB part of serial number */
>>>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>>>>>> +     msg[1].len = 8;
>>>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>>>> +     if (ret < 0)
>>>>>> +             goto err;
>>>>>> +
>>>>>> +     rcv_buf = be64_to_cpu(rcv_buf);
>>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>>> +
>>>>>> +     for (i = 0; i < 64; i += 16) {
>>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>>>>>> +                     return -ENODEV;
>>>>>> +     }
>>>>>> +
>>>>>> +     *sn = (((rcv_buf >> 32) & 0xFF000000) |
>>>>>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>>>>>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>>>>>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>>>>>> +
>>>>>> +     /* Read LSB part of serial number */
>>>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>>>>>> +     msg[1].len = 6;
>>>>>> +     rcv_buf = 0;
>>>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>>>> +     if (ret < 0)
>>>>>> +             goto err;
>>>>>> +
>>>>>> +     rcv_buf = be64_to_cpu(rcv_buf) >> 16;
>>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>>> +
>>>>>> +     for (i = 0; i < 48; i += 24) {
>>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
>>>>>> +                     return -ENODEV;
>>>>>> +     }
>>>>>> +
>>>>>> +     *sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>>>>>> +
>>>>>> +     return 0;
>>>>>> +
>>>>>> +err:
>>>>> Put this inline and drop the goto
>>>>>> +     dev_err(&client->dev, "Unable to read device serial number");
>>>>>> +     return ret;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>>>>>> +
>>>>> What is meant by a user_reg as opposed to other regs?
>>>>>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
>>>>>> +                                     u8 *user_reg)
>>>>>> +{
>>>>>> +     int ret;
>>>>>> +
>>>>>> +     ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
>>>>>> +     if (ret)
>>>>>> +             goto err;
>>>>>> +
>>>>>> +     ret = i2c_master_recv(client, user_reg, 1);
>>>>>> +     if (ret < 0)
>>>>>> +             goto err;
>>>>>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>>>>>> +
>>>>>> +     return 0;
>>>>>> +err:
>>>>>> +     dev_err(&client->dev, "Unable to read user reg");
>>>>>> +     return ret;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @i:               resolution index to set
>>>>>> + *
>>>>>> + * That function will program the appropriate resolution based on the index
>>>>>> + * provided when user space will set samp_freq channel.
>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
>>>>>> +                                     u8 i)
>>>>>> +{
>>>>>> +     u8 user_reg;
>>>>>> +     int ret;
>>>>>> +
>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     user_reg &= 0x7E;
>>>>>> +     user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
>>>>>> +
>>>>>> +     return i2c_smbus_write_byte_data(dev_data->client,
>>>>>> +                                      MS_SENSORS_USER_REG_WRITE,
>>>>>> +                                      user_reg);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @buf:     pointer on char buffer to write result
>>>>>> + *
>>>>>> + * That function will read battery indicator value in the device and
>>>>>> + * return 1 if the device voltage is below 2.25V.
>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>>>> + */
>>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
>>>>>> +                                     char *buf)
>>>>>> +{
>>>>>> +     int ret;
>>>>>> +     u8 user_reg;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_show_heater() - show device heater
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @buf:     pointer on char buffer to write result
>>>>>> + *
>>>>>> + * That function will read heater enable value in the device and
>>>>>> + * return 1 if the heater is enabled
>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>>>> + */
>>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>>>>>> +                                char *buf)
>>>>>> +{
>>>>>> +     u8 user_reg;
>>>>>> +     int ret;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_write_heater() - write device heater
>>>>> I'm not sure the _i2c_ bit is important in this function name...
>>>>>
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @buf:     pointer on char buffer from user space
>>>>>> + * @len:     length of buf
>>>>>> + *
>>>>>> + * That function will write 1 or 0 value in the device
>>>>>> + * to enable or disable heater
>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>> That->This
>>>>>> + *
>>>>>> + * Return: length of buffer, negative errno otherwise.
>>>>>> + */
>>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>>> +                                 const char *buf, size_t len)
>>>>>> +{
>>>>>> +     u8 val, user_reg;
>>>>>> +     int ret;
>>>>>> +
>>>>>> +     ret = kstrtou8(buf, 10, &val);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     if (val > 1)
>>>>>> +             return -EINVAL;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>> +     if (ret) {
>>>>>> +             mutex_unlock(&dev_data->lock);
>>>>>> +             return ret;
>>>>>> +     }
>>>>>> +
>>>>>> +     user_reg &= 0xFB;
>>>>>> +     user_reg |= val << 2;
>>>>>> +
>>>>>> +     ret = i2c_smbus_write_byte_data(dev_data->client,
>>>>>> +                                     MS_SENSORS_USER_REG_WRITE,
>>>>>> +                                     user_reg);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret) {
>>>>>> +             dev_err(&dev_data->client->dev, "Unable to write user reg\n");
>>>>>> +             return ret;
>>>>>> +     }
>>>>>> +
>>>>>> +     return len;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @temperature:pointer on temperature destination value
>>>>>> + *
>>>>>> + * That function will get temperature ADC value from the device,
>>>>>> + * check the CRC and compute the temperature value.
>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>>>> +                                    s32 *temperature)
>>>>>> +{
>>>>>> +     int ret;
>>>>>> +     u32 adc;
>>>>>> +     u16 delay;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
>>>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>>> +                                           MS_SENSORS_HT_T_CONVERSION_START,
>>>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>>>> +                                           delay, &adc);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>> +                     "Temperature read crc check error\n");
>>>>>> +             return -ENODEV;
>>>>>> +     }
>>>>>> +
>>>>>> +     /* Temperature algorithm */
>>>>>> +     *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>>>>>> +
>>>>>> +     return 0;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>> + * @humidity:        pointer on humidity destination value
>>>>>> + *
>>>>>> + * That function will get humidity ADC value from the device,
>>>>>> + * check the CRC and compute the temperature value.
>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>>> +                                 u32 *humidity)
>>>>>> +{
>>>>>> +     int ret;
>>>>>> +     u32 adc;
>>>>>> +     u16 delay;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
>>>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>>> +                                           MS_SENSORS_HT_H_CONVERSION_START,
>>>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>>>> +                                           delay, &adc);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>> +                     "Humidity read crc check error\n");
>>>>>> +             return -ENODEV;
>>>>>> +     }
>>>>>> +
>>>>>> +     /* Humidity algorithm */
>>>>>> +     *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>>>>>> +     if (*humidity >= 100000)
>>>>>> +             *humidity = 100000;
>>>>>> +
>>>>>> +     return 0;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>>>>>> +
>>>>> Multiline comment syntax is
>>>>> /*
>>>>> * CRC...
>>>>> */
>>>>> Or ideally use kernel-doc as you have for other functions below
>>>>> (not required as not exported)
>>>>>
>>>>>> +/* CRC check function for Temperature and pressure devices
>>>>>> + * That function is only used when reading PROM coefficients */
>>>>>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>>>>>> +{
>>>>>> +     unsigned int cnt, n_bit;
>>>>>> +     u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
>>>>>> +
>>>>>> +     prom[len - 1] = 0;
>>>>>> +     prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
>>>>>> +
>>>>>> +     for (cnt = 0; cnt < len * 2; cnt++) {
>>>>>> +             if (cnt % 2 == 1)
>>>>>> +                     n_rem ^= prom[cnt >> 1] & 0x00FF;
>>>>>> +             else
>>>>>> +                     n_rem ^= prom[cnt >> 1] >> 8;
>>>>>> +
>>>>>> +             for (n_bit = 8; n_bit > 0; n_bit--) {
>>>>>> +                     if (n_rem & 0x8000)
>>>>>> +                             n_rem = (n_rem << 1) ^ 0x3000;
>>>>>> +                     else
>>>>>> +                             n_rem <<= 1;
>>>>>> +             }
>>>>>> +     }
>>>>>> +     n_rem >>= 12;
>>>>>> +     prom[0] = crc_read;
>>>>>> +
>>>>>> +     return n_rem == crc;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_tp_read_prom() - prom coeff read function
>>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>>> pointer to temperature/... (fix throughout driver please)
>>>>>> + *
>>>>>> + * That function will read prom coefficients and check CRC
>>>>> That -> This (and add a full stop at the end of the sentence.
>>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>>>>>> +{
>>>>>> +     int i, ret;
>>>>>> +
>>>>>> +     for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>>>>>> +             ret = ms_sensors_i2c_read_prom_word(
>>>>>> +                                     dev_data->client,
>>>>>> +                                     MS_SENSORS_TP_PROM_READ + (i << 1),
>>>>>> +                                     &dev_data->prom[i]);
>>>>>> +
>>>>>> +             if (ret)
>>>>>> +                     return ret;
>>>>>> +     }
>>>>>> +
>>>>>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>>>>>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>> +                     "Calibration coefficients crc check error\n");
>>>>>> +             return -ENODEV;
>>>>>> +     }
>>>>>> +
>>>>>> +     return 0;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>>>>>> +
>>>>>> +/**
>>>>>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>>> pointer to
>>>>>> + * @temperature:pointer on temperature destination value
>>>>> pointer to (also missing tab?)
>>>>>> + * @pressure:        pointer on pressure destination value
>>>>>> + *
>>>>>> + * That function will read ADC and compute pressure and temperature value
>>>>> That->This and full stop at end of sentence.
>>>>>
>>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>>> + *
>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>> + */
>>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>>> +                                   int *temperature,
>>>>>> +                                   unsigned int *pressure)
>>>>>> +{
>>>>>> +     int ret;
>>>>>> +     u32 t_adc, p_adc;
>>>>>> +     s32 dt, temp;
>>>>>> +     s64 off, sens, t2, off2, sens2;
>>>>>> +     u16 *prom = dev_data->prom, delay;
>>>>>> +     u8 i;
>>>>>> +
>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>> +     i = dev_data->res_index * 2;
>>>>>> +     delay = ms_sensors_tp_conversion_time[dev_data->res_index];
>>>>> Blank line here would improve readability.
>>>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>>>> +                                     dev_data->client,
>>>>>> +                                     MS_SENSORS_TP_T_CONVERSION_START + i,
>>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>>> +                                     delay, &t_adc);
>>>>>> +     if (ret) {
>>>>>> +             mutex_unlock(&dev_data->lock);
>>>>>> +             return ret;
>>>>>> +     }
>>>>> blank line here.
>>>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>>>> +                                     dev_data->client,
>>>>>> +                                     MS_SENSORS_TP_P_CONVERSION_START + i,
>>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>>> +                                     delay, &p_adc);
>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>> +     if (ret)
>>>>>> +             return ret;
>>>>>> +
>>>>>> +     dt = (s32)t_adc - (prom[5] << 8);
>>>>>> +
>>>>>> +     /* Actual temperature = 2000 + dT * TEMPSENS */
>>>>>> +     temp = 2000 + (((s64)dt * prom[6]) >> 23);
>>>>>> +
>>>>>> +     /* Second order temperature compensation */
>>>>>> +     if (temp < 2000) {
>>>>>> +             s64 tmp = (s64)temp - 2000;
>>>>>> +
>>>>>> +             t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
>>>>>> +             off2 = (61 * tmp * tmp) >> 4;
>>>>>> +             sens2 = (29 * tmp * tmp) >> 4;
>>>>>> +
>>>>>> +             if (temp < -1500) {
>>>>>> +                     s64 tmp = (s64)temp + 1500;
>>>>>> +
>>>>>> +                     off2 += 17 * tmp * tmp;
>>>>>> +                     sens2 += 9 * tmp * tmp;
>>>>>> +             }
>>>>>> +     } else {
>>>>>> +             t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
>>>>>> +             off2 = 0;
>>>>>> +             sens2 = 0;
>>>>>> +     }
>>>>>> +
>>>>>> +     /* OFF = OFF_T1 + TCO * dT */
>>>>>> +     off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
>>>>>> +     off -= off2;
>>>>>> +
>>>>>> +     /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
>>>>>> +     sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
>>>>>> +     sens -= sens2;
>>>>>> +
>>>>>> +     /* Temperature compensated pressure = D1 * SENS - OFF */
>>>>>> +     *temperature = (temp - t2) * 10;
>>>>>> +     *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
>>>>>> +
>>>>>> +     return 0;
>>>>>> +}
>>>>>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>>>>>> +
>>>>>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>>>>>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>>>>>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>>>>>> +MODULE_LICENSE("GPL v2");
>>>>>> +
>>>>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>> new file mode 100644
>>>>>> index 0000000..a521428
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>> @@ -0,0 +1,54 @@
>>>>>> +/*
>>>>>> + * Measurements Specialties common sensor driver
>>>>>> + *
>>>>>> + * Copyright (c) 2015 Measurement-Specialties
>>>>>> + *
>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>>> + * published by the Free Software Foundation.
>>>>>> + *
>>>>> Unnecesary blank line here.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef _MS_SENSORS_I2C_H
>>>>>> +#define _MS_SENSORS_I2C_H
>>>>>> +
>>>>>> +#include <linux/i2c.h>
>>>>>> +#include <linux/mutex.h>
>>>>>> +
>>>>>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>>>>>> +
>>>>>> +struct ms_ht_dev {
>>>>>> +     struct i2c_client *client;
>>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>>> +     u8 res_index;
>>>>>> +};
>>>>>> +
>>>>>> +struct ms_tp_dev {
>>>>>> +     struct i2c_client *client;
>>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>>> +     /* Added element for CRC computation */
>>>>>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>>>>>> +     u8 res_index;
>>>>>> +};
>>>>>> +
>>>>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>>>>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>>>>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>>>>> +                                 unsigned int delay, u32 *adc);
>>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
>>>>>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
>>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
>>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
>>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
>>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>>> +                                 const char *buf, size_t len);
>>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>>>> +                                    s32 *temperature);
>>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>>> +                                 u32 *humidity);
>>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>>> +                                   int *temperature,
>>>>>> +                                   unsigned int *pressure);
>>>>>> +
>>>>>> +#endif /* _MS_SENSORS_I2C_H */
>>>>>>
>>>>>
>>>>> --
>>>>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>>>>> the body of a message to majordomo@vger.kernel.org
>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>
>>>> [1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906
>>
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 1/6] iio: Add meas-spec sensors common part
  2015-09-20 19:22             ` Jonathan Cameron
@ 2015-09-23 20:55               ` ludovic.tancerel
  0 siblings, 0 replies; 25+ messages in thread
From: ludovic.tancerel @ 2015-09-23 20:55 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Crt Mori, Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald,
	linux-iio, William.Markezana

I will soon push patchset update.
This will not contain move to regmap.
Please, read a few notes on feedback that was given below.

Kind regards
Ludovic

Le 20 sept. 2015 à 21:22, Jonathan Cameron <jic23@kernel.org> a écrit :

> On 14/09/15 13:56, ludovic.tancerel@maplehightech.com wrote:
>> Hello Jonathan, all,
>> Thank you for commenting the patchset.
>> I am sorry for the delay in looking in your feedback.
>> 
>> Most of the comments I had on different drivers are minor, and the patchset update I will provide will comply on the feedback.
>> 
>> The only item that needs clarification is about switching over to regmap.
>> I already considered using regmap previously, and my understanding was that this was not applicable for some of the i2c accesses that were done in my driver.
>> If there is no strong push from you on this, I will leave the code as it is and correct the casting comment.
> I'm not that bothered about moving over to regmap, though the addition of
> a convenience function for the particular case you have in this driver
> is an added reason to consider it.  
> 
> Entirely up to you as far as I'm concerned.
> 
>> 
>> Please, let me know if you disagree with this.
>> I plan on submitting the patchset update soon.
>> 
>> Thank you,
>> regards,
>> Ludovic
>> 
>> 
>> Le 15 août 2015 à 22:09, Jonathan Cameron <jic23@kernel.org> a écrit :
>> 
>>> On 10/08/15 12:07, Crt Mori wrote:
>>>> On 10 August 2015 at 09:43, Crt Mori <cmo@melexis.com> wrote:
>>>>> On 8 August 2015 at 18:58, Jonathan Cameron <jic23@kernel.org> wrote:
>>>>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>>>>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>>>>>> A few bits inline.
>>>>>> Also, would prefer some basic description of the patch up here...
>>>>>>> ---
>>>>>>> drivers/iio/common/Kconfig                     |   1 +
>>>>>>> drivers/iio/common/Makefile                    |   1 +
>>>>>>> drivers/iio/common/ms_sensors/Kconfig          |   6 +
>>>>>>> drivers/iio/common/ms_sensors/Makefile         |   5 +
>>>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.c | 634 +++++++++++++++++++++++++
>>>>>>> drivers/iio/common/ms_sensors/ms_sensors_i2c.h |  54 +++
>>>>>>> 6 files changed, 701 insertions(+)
>>>>>>> create mode 100644 drivers/iio/common/ms_sensors/Kconfig
>>>>>>> create mode 100644 drivers/iio/common/ms_sensors/Makefile
>>>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.c
>>>>>>> create mode 100644 drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>>> 
>>>>>>> diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
>>>>>>> index 790f106..26a6026 100644
>>>>>>> --- a/drivers/iio/common/Kconfig
>>>>>>> +++ b/drivers/iio/common/Kconfig
>>>>>>> @@ -3,5 +3,6 @@
>>>>>>> #
>>>>>>> 
>>>>>>> 
>> 
>> …
>> 
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_read_serial() - i2c serial number read function
>>>>>>> + * @cli:     pointer on i2c client
>>>>>>> + * @sn:              pointer on 64-bits destination value
>>>>>>> + *
>>>>>>> + * Generic i2c serial number read function for Measurement Specialties devices.
>>>>>>> + * This function is used for TSYS02d, HTU21, MS8607 chipset.
>>>>>>> + * Refer to datasheet:
>>>>>>> + *   http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn)
>>>>>>> +{
>>>>>>> +     u8 i;
>>>>>>> +     u64 rcv_buf = 0;
>>>>>>> +     u16 send_buf;
>>>>>>> +     int ret;
>>>>>>> +
>>>>>>> +     struct i2c_msg msg[2] = {
>>>>>>> +             {
>>>>>>> +              .addr = client->addr,
>>>>>>> +              .flags = client->flags,
>>>>>>> +              .len = 2,
>>>>>>> +              .buf = (char *)&send_buf,
>>>>>> If you are going to type cast, please match the (__u8 *) from
>>>>>> include/uapi/linux/i2c.h
>>>>> I am trying to push similar function (i2c_addressed_read) to i2c interface and
>>>>> since this driver has created its own instance of it, I would prefer
>>>>> we put it into
>>>>> i2c-core.c . Could you please support that debate [1] ? I think there are quite
>>>>> many drivers out there using the same function in a various way and it is
>>>>> about time to have it included in i2c to have more uniform control.
>>>> 
>>>> You should use: regmap_i2c_read (#include <linux/regmap.h>)
>>> Whilst I'd be in favour of this driver switching over to regmap and
>>> hence making this available, it is worth noting that is a much
>>> bigger change than a simple function call!
>>> 
>>> Jonathan
>>>> 
>>>>>>> +              },
>>>>>>> +             {
>>>>>>> +              .addr = client->addr,
>>>>>>> +              .flags = client->flags | I2C_M_RD,
>>>>>>> +              .buf = (char *)&rcv_buf,
>>>>>>> +              },
>>>>>>> +     };
>>>>>>> +
>>>>>>> +     /* Read MSB part of serial number */
>>>>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
>>>>>>> +     msg[1].len = 8;
>>>>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>>>>> +     if (ret < 0)
>>>>>>> +             goto err;
>>>>>>> +
>>>>>>> +     rcv_buf = be64_to_cpu(rcv_buf);
>>>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>>>> +
>>>>>>> +     for (i = 0; i < 64; i += 16) {
>>>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFF))
>>>>>>> +                     return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     *sn = (((rcv_buf >> 32) & 0xFF000000) |
>>>>>>> +            ((rcv_buf >> 24) & 0x00FF0000) |
>>>>>>> +            ((rcv_buf >> 16) & 0x0000FF00) |
>>>>>>> +            ((rcv_buf >> 8) & 0x000000FF)) << 16;
>>>>>>> +
>>>>>>> +     /* Read LSB part of serial number */
>>>>>>> +     send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
>>>>>>> +     msg[1].len = 6;
>>>>>>> +     rcv_buf = 0;
>>>>>>> +     ret = i2c_transfer(client->adapter, msg, 2);
>>>>>>> +     if (ret < 0)
>>>>>>> +             goto err;
>>>>>>> +
>>>>>>> +     rcv_buf = be64_to_cpu(rcv_buf) >> 16;
>>>>>>> +     dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_buf);
>>>>>>> +
>>>>>>> +     for (i = 0; i < 48; i += 24) {
>>>>>>> +             if (!ms_sensors_crc_valid((rcv_buf >> i) & 0xFFFFFF))
>>>>>>> +                     return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     *sn |= (rcv_buf & 0xFFFF00) << 40 | (rcv_buf >> 32);
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +
>>>>>>> +err:
>>>>>> Put this inline and drop the goto
>>>>>>> +     dev_err(&client->dev, "Unable to read device serial number");
>>>>>>> +     return ret;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_read_serial);
>>>>>>> +
>>>>>> What is meant by a user_reg as opposed to other regs?
This register is the one available to configure some of meas chipset.
I changed the name to config_reg to avoid any confusion.

>>>>>>> +static int ms_sensors_i2c_read_user_reg(struct i2c_client *client,
>>>>>>> +                                     u8 *user_reg)
>>>>>>> +{
>>>>>>> +     int ret;
>>>>>>> +
>>>>>>> +     ret = i2c_smbus_write_byte(client, MS_SENSORS_USER_REG_READ);
>>>>>>> +     if (ret)
>>>>>>> +             goto err;
>>>>>>> +
>>>>>>> +     ret = i2c_master_recv(client, user_reg, 1);
>>>>>>> +     if (ret < 0)
>>>>>>> +             goto err;
>>>>>>> +     dev_dbg(&client->dev, "User register :%x\n", *user_reg);
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +err:
>>>>>>> +     dev_err(&client->dev, "Unable to read user reg");
>>>>>>> +     return ret;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_write_resolution() - set resolution i2c function
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @i:               resolution index to set
>>>>>>> + *
>>>>>>> + * That function will program the appropriate resolution based on the index
>>>>>>> + * provided when user space will set samp_freq channel.
>>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data,
>>>>>>> +                                     u8 i)
>>>>>>> +{
>>>>>>> +     u8 user_reg;
>>>>>>> +     int ret;
>>>>>>> +
>>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     user_reg &= 0x7E;
>>>>>>> +     user_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
>>>>>>> +
>>>>>>> +     return i2c_smbus_write_byte_data(dev_data->client,
>>>>>>> +                                      MS_SENSORS_USER_REG_WRITE,
>>>>>>> +                                      user_reg);
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_resolution);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_show_battery_low() - show device battery low indicator
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @buf:     pointer on char buffer to write result
>>>>>>> + *
>>>>>>> + * That function will read battery indicator value in the device and
>>>>>>> + * return 1 if the device voltage is below 2.25V.
>>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data,
>>>>>>> +                                     char *buf)
>>>>>>> +{
>>>>>>> +     int ret;
>>>>>>> +     u8 user_reg;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x40) >> 6);
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_battery_low);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_show_heater() - show device heater
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @buf:     pointer on char buffer to write result
>>>>>>> + *
>>>>>>> + * That function will read heater enable value in the device and
>>>>>>> + * return 1 if the heater is enabled
>>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: length of sprintf on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data,
>>>>>>> +                                char *buf)
>>>>>>> +{
>>>>>>> +     u8 user_reg;
>>>>>>> +     int ret;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     return sprintf(buf, "%d\n", (user_reg & 0x4) >> 2);
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_show_heater);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_write_heater() - write device heater
>>>>>> I’m not sure the _i2c_ bit is important in this function name...
If any other device from meas would use same function on a different interface,
the function would have to be different, so I prefer to keep i2c in the name.

>>>>>> 
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @buf:     pointer on char buffer from user space
>>>>>>> + * @len:     length of buf
>>>>>>> + *
>>>>>>> + * That function will write 1 or 0 value in the device
>>>>>>> + * to enable or disable heater
>>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>>> That->This
>>>>>>> + *
>>>>>>> + * Return: length of buffer, negative errno otherwise.
>>>>>>> + */
>>>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>>>> +                                 const char *buf, size_t len)
>>>>>>> +{
>>>>>>> +     u8 val, user_reg;
>>>>>>> +     int ret;
>>>>>>> +
>>>>>>> +     ret = kstrtou8(buf, 10, &val);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     if (val > 1)
>>>>>>> +             return -EINVAL;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     ret = ms_sensors_i2c_read_user_reg(dev_data->client, &user_reg);
>>>>>>> +     if (ret) {
>>>>>>> +             mutex_unlock(&dev_data->lock);
>>>>>>> +             return ret;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     user_reg &= 0xFB;
>>>>>>> +     user_reg |= val << 2;
>>>>>>> +
>>>>>>> +     ret = i2c_smbus_write_byte_data(dev_data->client,
>>>>>>> +                                     MS_SENSORS_USER_REG_WRITE,
>>>>>>> +                                     user_reg);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret) {
>>>>>>> +             dev_err(&dev_data->client->dev, "Unable to write user reg\n");
>>>>>>> +             return ret;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     return len;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_write_heater);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_ht_read_temperature() - i2c read temperature
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @temperature:pointer on temperature destination value
>>>>>>> + *
>>>>>>> + * That function will get temperature ADC value from the device,
>>>>>>> + * check the CRC and compute the temperature value.
>>>>>>> + * That function is used for TSYS02D, HTU21 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>>>>> +                                    s32 *temperature)
>>>>>>> +{
>>>>>>> +     int ret;
>>>>>>> +     u32 adc;
>>>>>>> +     u16 delay;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
>>>>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>>>> +                                           MS_SENSORS_HT_T_CONVERSION_START,
>>>>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>>>>> +                                           delay, &adc);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>>> +                     "Temperature read crc check error\n");
>>>>>>> +             return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     /* Temperature algorithm */
>>>>>>> +     *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_temperature);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_i2c_ht_read_humidity() - i2c read humidity
>>>>>>> + * @dev_data:        pointer on temperature/humidity device data
>>>>>>> + * @humidity:        pointer on humidity destination value
>>>>>>> + *
>>>>>>> + * That function will get humidity ADC value from the device,
>>>>>>> + * check the CRC and compute the temperature value.
>>>>>>> + * That function is used for HTU21 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>>>> +                                 u32 *humidity)
>>>>>>> +{
>>>>>>> +     int ret;
>>>>>>> +     u32 adc;
>>>>>>> +     u16 delay;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
>>>>>>> +     ret = ms_sensors_i2c_convert_and_read(dev_data->client,
>>>>>>> +                                           MS_SENSORS_HT_H_CONVERSION_START,
>>>>>>> +                                           MS_SENSORS_NO_READ_CMD,
>>>>>>> +                                           delay, &adc);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     if (!ms_sensors_crc_valid(adc)) {
>>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>>> +                     "Humidity read crc check error\n");
>>>>>>> +             return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     /* Humidity algorithm */
>>>>>>> +     *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
>>>>>>> +     if (*humidity >= 100000)
>>>>>>> +             *humidity = 100000;
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_i2c_ht_read_humidity);
>>>>>>> +
>>>>>> Multiline comment syntax is
>>>>>> /*
>>>>>> * CRC...
>>>>>> */
>>>>>> Or ideally use kernel-doc as you have for other functions below
>>>>>> (not required as not exported)
>>>>>> 
>>>>>>> +/* CRC check function for Temperature and pressure devices
>>>>>>> + * That function is only used when reading PROM coefficients */
>>>>>>> +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
>>>>>>> +{
>>>>>>> +     unsigned int cnt, n_bit;
>>>>>>> +     u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
>>>>>>> +
>>>>>>> +     prom[len - 1] = 0;
>>>>>>> +     prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
>>>>>>> +
>>>>>>> +     for (cnt = 0; cnt < len * 2; cnt++) {
>>>>>>> +             if (cnt % 2 == 1)
>>>>>>> +                     n_rem ^= prom[cnt >> 1] & 0x00FF;
>>>>>>> +             else
>>>>>>> +                     n_rem ^= prom[cnt >> 1] >> 8;
>>>>>>> +
>>>>>>> +             for (n_bit = 8; n_bit > 0; n_bit--) {
>>>>>>> +                     if (n_rem & 0x8000)
>>>>>>> +                             n_rem = (n_rem << 1) ^ 0x3000;
>>>>>>> +                     else
>>>>>>> +                             n_rem <<= 1;
>>>>>>> +             }
>>>>>>> +     }
>>>>>>> +     n_rem >>= 12;
>>>>>>> +     prom[0] = crc_read;
>>>>>>> +
>>>>>>> +     return n_rem == crc;
>>>>>>> +}
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_tp_read_prom() - prom coeff read function
>>>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>>>> pointer to temperature/... (fix throughout driver please)
>>>>>>> + *
>>>>>>> + * That function will read prom coefficients and check CRC
>>>>>> That -> This (and add a full stop at the end of the sentence.
>>>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
>>>>>>> +{
>>>>>>> +     int i, ret;
>>>>>>> +
>>>>>>> +     for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
>>>>>>> +             ret = ms_sensors_i2c_read_prom_word(
>>>>>>> +                                     dev_data->client,
>>>>>>> +                                     MS_SENSORS_TP_PROM_READ + (i << 1),
>>>>>>> +                                     &dev_data->prom[i]);
>>>>>>> +
>>>>>>> +             if (ret)
>>>>>>> +                     return ret;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     if (!ms_sensors_tp_crc_valid(dev_data->prom,
>>>>>>> +                                  MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
>>>>>>> +             dev_err(&dev_data->client->dev,
>>>>>>> +                     "Calibration coefficients crc check error\n");
>>>>>>> +             return -ENODEV;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_tp_read_prom);
>>>>>>> +
>>>>>>> +/**
>>>>>>> + * ms_sensors_read_temp_and_pressure() - read temp and pressure
>>>>>>> + * @dev_data:        pointer on temperature/pressure device data
>>>>>> pointer to
>>>>>>> + * @temperature:pointer on temperature destination value
>>>>>> pointer to (also missing tab?)
>>>>>>> + * @pressure:        pointer on pressure destination value
>>>>>>> + *
>>>>>>> + * That function will read ADC and compute pressure and temperature value
>>>>>> That->This and full stop at end of sentence.
>>>>>> 
>>>>>>> + * That function is used for MS5637 and MS8607 chipsets
>>>>>>> + *
>>>>>>> + * Return: 0 on success, negative errno otherwise.
>>>>>>> + */
>>>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>>>> +                                   int *temperature,
>>>>>>> +                                   unsigned int *pressure)
>>>>>>> +{
>>>>>>> +     int ret;
>>>>>>> +     u32 t_adc, p_adc;
>>>>>>> +     s32 dt, temp;
>>>>>>> +     s64 off, sens, t2, off2, sens2;
>>>>>>> +     u16 *prom = dev_data->prom, delay;
>>>>>>> +     u8 i;
>>>>>>> +
>>>>>>> +     mutex_lock(&dev_data->lock);
>>>>>>> +     i = dev_data->res_index * 2;
>>>>>>> +     delay = ms_sensors_tp_conversion_time[dev_data->res_index];
>>>>>> Blank line here would improve readability.
>>>>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>>>>> +                                     dev_data->client,
>>>>>>> +                                     MS_SENSORS_TP_T_CONVERSION_START + i,
>>>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>>>> +                                     delay, &t_adc);
>>>>>>> +     if (ret) {
>>>>>>> +             mutex_unlock(&dev_data->lock);
>>>>>>> +             return ret;
>>>>>>> +     }
>>>>>> blank line here.
>>>>>>> +     ret = ms_sensors_i2c_convert_and_read(
>>>>>>> +                                     dev_data->client,
>>>>>>> +                                     MS_SENSORS_TP_P_CONVERSION_START + i,
>>>>>>> +                                     MS_SENSORS_TP_ADC_READ,
>>>>>>> +                                     delay, &p_adc);
>>>>>>> +     mutex_unlock(&dev_data->lock);
>>>>>>> +     if (ret)
>>>>>>> +             return ret;
>>>>>>> +
>>>>>>> +     dt = (s32)t_adc - (prom[5] << 8);
>>>>>>> +
>>>>>>> +     /* Actual temperature = 2000 + dT * TEMPSENS */
>>>>>>> +     temp = 2000 + (((s64)dt * prom[6]) >> 23);
>>>>>>> +
>>>>>>> +     /* Second order temperature compensation */
>>>>>>> +     if (temp < 2000) {
>>>>>>> +             s64 tmp = (s64)temp - 2000;
>>>>>>> +
>>>>>>> +             t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
>>>>>>> +             off2 = (61 * tmp * tmp) >> 4;
>>>>>>> +             sens2 = (29 * tmp * tmp) >> 4;
>>>>>>> +
>>>>>>> +             if (temp < -1500) {
>>>>>>> +                     s64 tmp = (s64)temp + 1500;
>>>>>>> +
>>>>>>> +                     off2 += 17 * tmp * tmp;
>>>>>>> +                     sens2 += 9 * tmp * tmp;
>>>>>>> +             }
>>>>>>> +     } else {
>>>>>>> +             t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
>>>>>>> +             off2 = 0;
>>>>>>> +             sens2 = 0;
>>>>>>> +     }
>>>>>>> +
>>>>>>> +     /* OFF = OFF_T1 + TCO * dT */
>>>>>>> +     off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
>>>>>>> +     off -= off2;
>>>>>>> +
>>>>>>> +     /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
>>>>>>> +     sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
>>>>>>> +     sens -= sens2;
>>>>>>> +
>>>>>>> +     /* Temperature compensated pressure = D1 * SENS - OFF */
>>>>>>> +     *temperature = (temp - t2) * 10;
>>>>>>> +     *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
>>>>>>> +
>>>>>>> +     return 0;
>>>>>>> +}
>>>>>>> +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
>>>>>>> +
>>>>>>> +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
>>>>>>> +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
>>>>>>> +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
>>>>>>> +MODULE_LICENSE("GPL v2");
>>>>>>> +
>>>>>>> diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>>> new file mode 100644
>>>>>>> index 0000000..a521428
>>>>>>> --- /dev/null
>>>>>>> +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
>>>>>>> @@ -0,0 +1,54 @@
>>>>>>> +/*
>>>>>>> + * Measurements Specialties common sensor driver
>>>>>>> + *
>>>>>>> + * Copyright (c) 2015 Measurement-Specialties
>>>>>>> + *
>>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>>>> + * published by the Free Software Foundation.
>>>>>>> + *
>>>>>> Unnecesary blank line here.
>>>>>>> + */
>>>>>>> +
>>>>>>> +#ifndef _MS_SENSORS_I2C_H
>>>>>>> +#define _MS_SENSORS_I2C_H
>>>>>>> +
>>>>>>> +#include <linux/i2c.h>
>>>>>>> +#include <linux/mutex.h>
>>>>>>> +
>>>>>>> +#define MS_SENSORS_TP_PROM_WORDS_NB          7
>>>>>>> +
>>>>>>> +struct ms_ht_dev {
>>>>>>> +     struct i2c_client *client;
>>>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>>>> +     u8 res_index;
>>>>>>> +};
>>>>>>> +
>>>>>>> +struct ms_tp_dev {
>>>>>>> +     struct i2c_client *client;
>>>>>>> +     struct mutex lock; /* mutex protecting data structure */
>>>>>>> +     /* Added element for CRC computation */
>>>>>>> +     u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
>>>>>>> +     u8 res_index;
>>>>>>> +};
>>>>>>> +
>>>>>>> +int ms_sensors_i2c_reset(void *cli, u8 cmd, unsigned int delay);
>>>>>>> +int ms_sensors_i2c_read_prom_word(void *cli, int cmd, u16 *word);
>>>>>>> +int ms_sensors_i2c_convert_and_read(void *cli, u8 conv, u8 rd,
>>>>>>> +                                 unsigned int delay, u32 *adc);
>>>>>>> +int ms_sensors_i2c_read_serial(struct i2c_client *client, u64 *sn);
>>>>>>> +ssize_t ms_sensors_i2c_show_serial(struct ms_ht_dev *dev_data, char *buf);
>>>>>>> +ssize_t ms_sensors_i2c_write_resolution(struct ms_ht_dev *dev_data, u8 i);
>>>>>>> +ssize_t ms_sensors_i2c_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
>>>>>>> +ssize_t ms_sensors_i2c_show_heater(struct ms_ht_dev *dev_data, char *buf);
>>>>>>> +ssize_t ms_sensors_i2c_write_heater(struct ms_ht_dev *dev_data,
>>>>>>> +                                 const char *buf, size_t len);
>>>>>>> +int ms_sensors_i2c_ht_read_temperature(struct ms_ht_dev *dev_data,
>>>>>>> +                                    s32 *temperature);
>>>>>>> +int ms_sensors_i2c_ht_read_humidity(struct ms_ht_dev *dev_data,
>>>>>>> +                                 u32 *humidity);
>>>>>>> +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
>>>>>>> +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
>>>>>>> +                                   int *temperature,
>>>>>>> +                                   unsigned int *pressure);
>>>>>>> +
>>>>>>> +#endif /* _MS_SENSORS_I2C_H */
>>>>>>> 
>>>>>> 
>>>>>> --
>>>>>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>>>>>> the body of a message to majordomo@vger.kernel.org
>>>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>>> 
>>>>> [1] http://comments.gmane.org/gmane.linux.drivers.i2c/23906
>>> 
>> 
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 6/6] iio: Add ms8607 meas-spec driver support
  2015-08-08 17:22   ` Jonathan Cameron
@ 2015-09-25  9:25     ` ludovic.tancerel
  2015-09-25  9:31       ` ludovic.tancerel
  0 siblings, 1 reply; 25+ messages in thread
From: ludovic.tancerel @ 2015-09-25  9:25 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: knaack.h, lars, pmeerw, linux-iio, William.Markezana

[-- Attachment #1: Type: text/plain, Size: 6473 bytes --]

Jonathan,
some quick feedback on one of the comments below.

Please let me know if you disagree.

Regards,
Ludovic


Le 8 août 2015 à 19:22, Jonathan Cameron <jic23@kernel.org> a écrit :

> On 30/07/15 10:25, Ludovic Tancerel wrote:
>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
> Little bits inline.
> 
> A nice looking patch set.  I was unsure the division made sense between the
> core and the drivers, but it seems to work well.
> Will be interesting to see what other parts measurement specialties comes out
> with in the future!
> 
> Jonathan
>> ---
>> Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  1 +
>> drivers/iio/humidity/htu21.c                      | 32 ++++++++++++++++++++---
>> drivers/iio/pressure/Kconfig                      | 13 +++++++++
>> drivers/iio/pressure/ms5637.c                     |  6 ++++-
>> 4 files changed, 48 insertions(+), 4 deletions(-)
>> 
>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>> index 7b09d3a..df70dda6 100644
>> --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>> @@ -12,3 +12,4 @@ Description:
>>                 Enable or disable heater function by writing either
>> 		'1' or '0'.
>>                 Same reading values apply
>> +		This ABI is available for htu21, ms8607
>> diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
>> index 870b631..4720cbc 100644
>> --- a/drivers/iio/humidity/htu21.c
>> +++ b/drivers/iio/humidity/htu21.c
>> @@ -1,6 +1,7 @@
>> /*
>>  * htu21.c - Support for Measurement-Specialties
>>  *           htu21 temperature & humidity sensor
>> + *	     and humidity part of MS8607 sensor
>>  *
>>  * Copyright (c) 2014 Measurement-Specialties
>>  *
>> @@ -10,6 +11,8 @@
>>  *
>>  * Datasheet:
>>  *  http://www.meas-spec.com/downloads/HTU21D.pdf
>> + * Datasheet:
>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>  *
>>  */
>> 
>> @@ -25,6 +28,11 @@
>> 
>> #define HTU21_RESET				0xFE
>> 
>> +enum {
>> +	HTU21,
>> +	MS8607
>> +};
>> +
>> static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
>> /* String copy of the above const for readability purpose */
>> static const char htu21_show_samp_freq[] = "20 40 70 120";
>> @@ -107,6 +115,17 @@ static const struct iio_chan_spec htu21_channels[] = {
>> 	 }
>> };
>> 
>> +/* Meas Spec recommendation is to not read temperature
> /*
> * Meas
>> + * on this driver part for MS8607
>> + */
>> +static const struct iio_chan_spec ms8607_channels[] = {
>> +	{
>> +		.type = IIO_HUMIDITYRELATIVE,
>> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>> +	 }
>> +};
>> +
>> static ssize_t htu21_show_battery_low(struct device *dev,
>> 				      struct device_attribute *attr, char *buf)
>> {
>> @@ -189,8 +208,14 @@ int htu21_probe(struct i2c_client *client,
>> 	indio_dev->name = id->name;
>> 	indio_dev->dev.parent = &client->dev;
>> 	indio_dev->modes = INDIO_DIRECT_MODE;
>> -	indio_dev->channels = htu21_channels;
>> -	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>> +
>> +	if (id->driver_data == MS8607) {
>> +		indio_dev->channels = ms8607_channels;
>> +		indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
>> +	} else {
>> +		indio_dev->channels = htu21_channels;
>> +		indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>> +	}
>> 
>> 	i2c_set_clientdata(client, indio_dev);
>> 
>> @@ -207,7 +232,8 @@ int htu21_probe(struct i2c_client *client,
>> }
>> 
>> static const struct i2c_device_id htu21_id[] = {
>> -	{"htu21", 0},
>> +	{"htu21", HTU21},
>> +	{"ms8607-h", MS8607},
> perhaps -humidity for clarity if not already in use out in the field.

h stands for humidity
tp for temperature and pressure.

ms8607-temperaturepressure seems too long to me, so I prefer to keep ms8607-tp and keep ms8607-h for consistancy

>> 	{}
>> };
>> 
>> diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
>> index 8142cfe..e6a7fd5 100644
>> --- a/drivers/iio/pressure/Kconfig
>> +++ b/drivers/iio/pressure/Kconfig
>> @@ -90,6 +90,19 @@ config MS5637
>> 	  This driver can also be built as a module. If so, the module will
>> 	  be called ms5637.
>> 
>> +config MS8607
>> +	tristate "Measurement Specialties MS8607 pressure, temperature & humidity sensor"
>> +	depends on I2C
>> +        select IIO_MS_SENSORS_I2C
>> +        select HTU21
>> +        select MS5637
>> +	help
>> +	  If you say yes here you get support for the Measurement Specialties
>> +	  MS8607 pressure, temperature and humidity sensor.
>> +
>> +	  This is based on HTU21 and MS5637 drivers. If built as a module,
>> +	  modules to load will be htu21 and ms5637.
>> +
> Don't bother with the separate kconfig entry.  Just make sure the help texts for
> the other two make it clear that they also support part of this device.
> 
>> config IIO_ST_PRESS
>> 	tristate "STMicroelectronics pressure sensor Driver"
>> 	depends on (I2C || SPI_MASTER) && SYSFS
>> diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
>> index e2073fd..c185aa0 100644
>> --- a/drivers/iio/pressure/ms5637.c
>> +++ b/drivers/iio/pressure/ms5637.c
>> @@ -1,5 +1,5 @@
>> /*
>> - * ms5637.c - Support for Measurement-Specialties ms5637
>> + * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
>>  *            pressure & temperature sensor
>>  *
>>  * Copyright (c) 2015 Measurement-Specialties
>> @@ -10,8 +10,11 @@
>>  *
>>  * Datasheet:
>>  *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
>> + * Datasheet:
>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>  *
>>  */
>> +
>> #include <linux/init.h>
>> #include <linux/device.h>
>> #include <linux/kernel.h>
>> @@ -168,6 +171,7 @@ static int ms5637_probe(struct i2c_client *client,
>> 
>> static const struct i2c_device_id ms5637_id[] = {
>> 	{"ms5637", 0},
>> +	{"ms8607-tp", 1},
> Perhaps -temp for extra clarity (or are there devices out there already
> using this naming?)
>> 	{}
>> };
>> 
>> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


[-- Attachment #2: Type: text/html, Size: 13288 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 6/6] iio: Add ms8607 meas-spec driver support
  2015-09-25  9:25     ` ludovic.tancerel
@ 2015-09-25  9:31       ` ludovic.tancerel
  2015-09-27 16:01         ` Jonathan Cameron
  0 siblings, 1 reply; 25+ messages in thread
From: ludovic.tancerel @ 2015-09-25  9:31 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: knaack.h, lars, pmeerw, linux-iio, William.Markezana

[-- Attachment #1: Type: text/plain, Size: 6768 bytes --]

Resend as for some reason, there was a problem with mail server

Regards,
Ludovic

> Jonathan,
> some quick feedback on one of the comments below.
> 
> Please let me know if you disagree.
> 
> Regards,
> Ludovic
> 
> 
> Le 8 août 2015 à 19:22, Jonathan Cameron <jic23@kernel.org> a écrit :
> 
>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com>
>> Little bits inline.
>> 
>> A nice looking patch set.  I was unsure the division made sense between the
>> core and the drivers, but it seems to work well.
>> Will be interesting to see what other parts measurement specialties comes out
>> with in the future!
>> 
>> Jonathan
>>> ---
>>> Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  1 +
>>> drivers/iio/humidity/htu21.c                      | 32 ++++++++++++++++++++---
>>> drivers/iio/pressure/Kconfig                      | 13 +++++++++
>>> drivers/iio/pressure/ms5637.c                     |  6 ++++-
>>> 4 files changed, 48 insertions(+), 4 deletions(-)
>>> 
>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>> index 7b09d3a..df70dda6 100644
>>> --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>> @@ -12,3 +12,4 @@ Description:
>>>                 Enable or disable heater function by writing either
>>> 		'1' or '0'.
>>>                 Same reading values apply
>>> +		This ABI is available for htu21, ms8607
>>> diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
>>> index 870b631..4720cbc 100644
>>> --- a/drivers/iio/humidity/htu21.c
>>> +++ b/drivers/iio/humidity/htu21.c
>>> @@ -1,6 +1,7 @@
>>> /*
>>>  * htu21.c - Support for Measurement-Specialties
>>>  *           htu21 temperature & humidity sensor
>>> + *	     and humidity part of MS8607 sensor
>>>  *
>>>  * Copyright (c) 2014 Measurement-Specialties
>>>  *
>>> @@ -10,6 +11,8 @@
>>>  *
>>>  * Datasheet:
>>>  *  http://www.meas-spec.com/downloads/HTU21D.pdf
>>> + * Datasheet:
>>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>>  *
>>>  */
>>> 
>>> @@ -25,6 +28,11 @@
>>> 
>>> #define HTU21_RESET				0xFE
>>> 
>>> +enum {
>>> +	HTU21,
>>> +	MS8607
>>> +};
>>> +
>>> static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
>>> /* String copy of the above const for readability purpose */
>>> static const char htu21_show_samp_freq[] = "20 40 70 120";
>>> @@ -107,6 +115,17 @@ static const struct iio_chan_spec htu21_channels[] = {
>>> 	 }
>>> };
>>> 
>>> +/* Meas Spec recommendation is to not read temperature
>> /*
>> * Meas
>>> + * on this driver part for MS8607
>>> + */
>>> +static const struct iio_chan_spec ms8607_channels[] = {
>>> +	{
>>> +		.type = IIO_HUMIDITYRELATIVE,
>>> +		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>>> +		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>> +	 }
>>> +};
>>> +
>>> static ssize_t htu21_show_battery_low(struct device *dev,
>>> 				      struct device_attribute *attr, char *buf)
>>> {
>>> @@ -189,8 +208,14 @@ int htu21_probe(struct i2c_client *client,
>>> 	indio_dev->name = id->name;
>>> 	indio_dev->dev.parent = &client->dev;
>>> 	indio_dev->modes = INDIO_DIRECT_MODE;
>>> -	indio_dev->channels = htu21_channels;
>>> -	indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>>> +
>>> +	if (id->driver_data == MS8607) {
>>> +		indio_dev->channels = ms8607_channels;
>>> +		indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
>>> +	} else {
>>> +		indio_dev->channels = htu21_channels;
>>> +		indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>>> +	}
>>> 
>>> 	i2c_set_clientdata(client, indio_dev);
>>> 
>>> @@ -207,7 +232,8 @@ int htu21_probe(struct i2c_client *client,
>>> }
>>> 
>>> static const struct i2c_device_id htu21_id[] = {
>>> -	{"htu21", 0},
>>> +	{"htu21", HTU21},
>>> +	{"ms8607-h", MS8607},
>> perhaps -humidity for clarity if not already in use out in the field.
> 
> h stands for humidity
> tp for temperature and pressure.
> 
> ms8607-temperaturepressure seems too long to me, so I prefer to keep ms8607-tp and keep ms8607-h for consistancy
> 
>>> 	{}
>>> };
>>> 
>>> diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
>>> index 8142cfe..e6a7fd5 100644
>>> --- a/drivers/iio/pressure/Kconfig
>>> +++ b/drivers/iio/pressure/Kconfig
>>> @@ -90,6 +90,19 @@ config MS5637
>>> 	  This driver can also be built as a module. If so, the module will
>>> 	  be called ms5637.
>>> 
>>> +config MS8607
>>> +	tristate "Measurement Specialties MS8607 pressure, temperature & humidity sensor"
>>> +	depends on I2C
>>> +        select IIO_MS_SENSORS_I2C
>>> +        select HTU21
>>> +        select MS5637
>>> +	help
>>> +	  If you say yes here you get support for the Measurement Specialties
>>> +	  MS8607 pressure, temperature and humidity sensor.
>>> +
>>> +	  This is based on HTU21 and MS5637 drivers. If built as a module,
>>> +	  modules to load will be htu21 and ms5637.
>>> +
>> Don't bother with the separate kconfig entry.  Just make sure the help texts for
>> the other two make it clear that they also support part of this device.
>> 
>>> config IIO_ST_PRESS
>>> 	tristate "STMicroelectronics pressure sensor Driver"
>>> 	depends on (I2C || SPI_MASTER) && SYSFS
>>> diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
>>> index e2073fd..c185aa0 100644
>>> --- a/drivers/iio/pressure/ms5637.c
>>> +++ b/drivers/iio/pressure/ms5637.c
>>> @@ -1,5 +1,5 @@
>>> /*
>>> - * ms5637.c - Support for Measurement-Specialties ms5637
>>> + * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
>>>  *            pressure & temperature sensor
>>>  *
>>>  * Copyright (c) 2015 Measurement-Specialties
>>> @@ -10,8 +10,11 @@
>>>  *
>>>  * Datasheet:
>>>  *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
>>> + * Datasheet:
>>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>>  *
>>>  */
>>> +
>>> #include <linux/init.h>
>>> #include <linux/device.h>
>>> #include <linux/kernel.h>
>>> @@ -168,6 +171,7 @@ static int ms5637_probe(struct i2c_client *client,
>>> 
>>> static const struct i2c_device_id ms5637_id[] = {
>>> 	{"ms5637", 0},
>>> +	{"ms8607-tp", 1},
>> Perhaps -temp for extra clarity (or are there devices out there already
>> using this naming?)
>>> 	{}
>>> };
>>> 
>>> 
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html


[-- Attachment #2: Type: text/html, Size: 13868 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH V2 6/6] iio: Add ms8607 meas-spec driver support
  2015-09-25  9:31       ` ludovic.tancerel
@ 2015-09-27 16:01         ` Jonathan Cameron
  0 siblings, 0 replies; 25+ messages in thread
From: Jonathan Cameron @ 2015-09-27 16:01 UTC (permalink / raw)
  To: ludovic.tancerel@maplehightech.com
  Cc: knaack.h, lars, pmeerw, linux-iio, William.Markezana

On 25/09/15 10:31, ludovic.tancerel@maplehightech.com wrote:
> Resend as for some reason, there was a problem with mail server
> 
> Regards,
> Ludovic
> 
>> Jonathan,
>> some quick feedback on one of the comments below.
>>
>> Please let me know if you disagree.
>>
>> Regards,
>> Ludovic
>>
>>
>> Le 8 août 2015 à 19:22, Jonathan Cameron <jic23@kernel.org <mailto:jic23@kernel.org>> a écrit :
>>
>>> On 30/07/15 10:25, Ludovic Tancerel wrote:
>>>> Signed-off-by: Ludovic Tancerel <ludovic.tancerel@maplehightech.com <mailto:ludovic.tancerel@maplehightech.com>>
>>> Little bits inline.
>>>
>>> A nice looking patch set.  I was unsure the division made sense between the
>>> core and the drivers, but it seems to work well.
>>> Will be interesting to see what other parts measurement specialties comes out
>>> with in the future!
>>>
>>> Jonathan
>>>> ---
>>>> Documentation/ABI/testing/sysfs-bus-iio-meas-spec |  1 +
>>>> drivers/iio/humidity/htu21.c                      | 32 ++++++++++++++++++++---
>>>> drivers/iio/pressure/Kconfig                      | 13 +++++++++
>>>> drivers/iio/pressure/ms5637.c                     |  6 ++++-
>>>> 4 files changed, 48 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>>> index 7b09d3a..df70dda6 100644
>>>> --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
>>>> @@ -12,3 +12,4 @@ Description:
>>>>                 Enable or disable heater function by writing either
>>>> '1' or '0'.
>>>>                 Same reading values apply
>>>> +This ABI is available for htu21, ms8607
>>>> diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
>>>> index 870b631..4720cbc 100644
>>>> --- a/drivers/iio/humidity/htu21.c
>>>> +++ b/drivers/iio/humidity/htu21.c
>>>> @@ -1,6 +1,7 @@
>>>> /*
>>>>  * htu21.c - Support for Measurement-Specialties
>>>>  *           htu21 temperature & humidity sensor
>>>> + *     and humidity part of MS8607 sensor
>>>>  *
>>>>  * Copyright (c) 2014 Measurement-Specialties
>>>>  *
>>>> @@ -10,6 +11,8 @@
>>>>  *
>>>>  * Datasheet:
>>>>  *  http://www.meas-spec.com/downloads/HTU21D.pdf
>>>> + * Datasheet:
>>>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>>>  *
>>>>  */
>>>>
>>>> @@ -25,6 +28,11 @@
>>>>
>>>> #define HTU21_RESET0xFE
>>>>
>>>> +enum {
>>>> +HTU21,
>>>> +MS8607
>>>> +};
>>>> +
>>>> static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
>>>> /* String copy of the above const for readability purpose */
>>>> static const char htu21_show_samp_freq[] = "20 40 70 120";
>>>> @@ -107,6 +115,17 @@ static const struct iio_chan_spec htu21_channels[] = {
>>>>  }
>>>> };
>>>>
>>>> +/* Meas Spec recommendation is to not read temperature
>>> /*
>>> * Meas
>>>> + * on this driver part for MS8607
>>>> + */
>>>> +static const struct iio_chan_spec ms8607_channels[] = {
>>>> +{
>>>> +.type = IIO_HUMIDITYRELATIVE,
>>>> +.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
>>>> +.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
>>>> + }
>>>> +};
>>>> +
>>>> static ssize_t htu21_show_battery_low(struct device *dev,
>>>>       struct device_attribute *attr, char *buf)
>>>> {
>>>> @@ -189,8 +208,14 @@ int htu21_probe(struct i2c_client *client,
>>>> indio_dev->name = id->name;
>>>> indio_dev->dev.parent = &client->dev;
>>>> indio_dev->modes = INDIO_DIRECT_MODE;
>>>> -indio_dev->channels = htu21_channels;
>>>> -indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>>>> +
>>>> +if (id->driver_data == MS8607) {
>>>> +indio_dev->channels = ms8607_channels;
>>>> +indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
>>>> +} else {
>>>> +indio_dev->channels = htu21_channels;
>>>> +indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
>>>> +}
>>>>
>>>> i2c_set_clientdata(client, indio_dev);
>>>>
>>>> @@ -207,7 +232,8 @@ int htu21_probe(struct i2c_client *client,
>>>> }
>>>>
>>>> static const struct i2c_device_id htu21_id[] = {
>>>> -{"htu21", 0},
>>>> +{"htu21", HTU21},
>>>> +{"ms8607-h", MS8607},
>>> perhaps -humidity for clarity if not already in use out in the field.
>>
>> h stands for humidity
>> tp for temperature and pressure.
>>
>> ms8607-temperaturepressure seems too long to me, so I prefer to keep ms8607-tp and keep ms8607-h for consistancy
hmm. Rather feels like there might be a middle ground such as -temppres which still makes it more obvious than the
single letter!
>>
>>>> {}
>>>> };
>>>>
>>>> diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
>>>> index 8142cfe..e6a7fd5 100644
>>>> --- a/drivers/iio/pressure/Kconfig
>>>> +++ b/drivers/iio/pressure/Kconfig
>>>> @@ -90,6 +90,19 @@ config MS5637
>>>>   This driver can also be built as a module. If so, the module will
>>>>   be called ms5637.
>>>>
>>>> +config MS8607
>>>> +tristate "Measurement Specialties MS8607 pressure, temperature & humidity sensor"
>>>> +depends on I2C
>>>> +        select IIO_MS_SENSORS_I2C
>>>> +        select HTU21
>>>> +        select MS5637
>>>> +help
>>>> +  If you say yes here you get support for the Measurement Specialties
>>>> +  MS8607 pressure, temperature and humidity sensor.
>>>> +
>>>> +  This is based on HTU21 and MS5637 drivers. If built as a module,
>>>> +  modules to load will be htu21 and ms5637.
>>>> +
>>> Don't bother with the separate kconfig entry.  Just make sure the help texts for
>>> the other two make it clear that they also support part of this device.
>>>
>>>> config IIO_ST_PRESS
>>>> tristate "STMicroelectronics pressure sensor Driver"
>>>> depends on (I2C || SPI_MASTER) && SYSFS
>>>> diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
>>>> index e2073fd..c185aa0 100644
>>>> --- a/drivers/iio/pressure/ms5637.c
>>>> +++ b/drivers/iio/pressure/ms5637.c
>>>> @@ -1,5 +1,5 @@
>>>> /*
>>>> - * ms5637.c - Support for Measurement-Specialties ms5637
>>>> + * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
>>>>  *            pressure & temperature sensor
>>>>  *
>>>>  * Copyright (c) 2015 Measurement-Specialties
>>>> @@ -10,8 +10,11 @@
>>>>  *
>>>>  * Datasheet:
>>>>  *  http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
>>>> + * Datasheet:
>>>> + *  http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
>>>>  *
>>>>  */
>>>> +
>>>> #include <linux/init.h>
>>>> #include <linux/device.h>
>>>> #include <linux/kernel.h>
>>>> @@ -168,6 +171,7 @@ static int ms5637_probe(struct i2c_client *client,
>>>>
>>>> static const struct i2c_device_id ms5637_id[] = {
>>>> {"ms5637", 0},
>>>> +{"ms8607-tp", 1},
>>> Perhaps -temp for extra clarity (or are there devices out there already
>>> using this naming?)
>>>> {}
>>>> };
>>>>
>>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>>> the body of a message to majordomo@vger.kernel.org <mailto:majordomo@vger.kernel.org>
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2015-09-27 16:01 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-30  9:25 [PATCH V2 0/6] iio: TSYS01, TSYS02D, HTU21, MS5637, MS8607 Measurement Specialties driver development Ludovic Tancerel
2015-07-30  9:25 ` [PATCH V2 1/6] iio: Add meas-spec sensors common part Ludovic Tancerel
2015-08-08 16:58   ` Jonathan Cameron
2015-08-10  7:43     ` Crt Mori
2015-08-10 11:07       ` Crt Mori
2015-08-15 20:09         ` Jonathan Cameron
2015-09-14 12:56           ` ludovic.tancerel
2015-09-20 19:22             ` Jonathan Cameron
2015-09-23 20:55               ` ludovic.tancerel
2015-07-30  9:25 ` [PATCH V2 2/6] iio: Add tsys01 meas-spec driver support Ludovic Tancerel
2015-08-08 17:03   ` Jonathan Cameron
2015-08-08 17:04     ` Jonathan Cameron
2015-07-30  9:25 ` [PATCH V2 3/6] iio: Add tsys02d " Ludovic Tancerel
2015-08-08 17:15   ` Jonathan Cameron
2015-08-09 12:33     ` Guenter Roeck
2015-08-09 20:13       ` Hartmut Knaack
2015-08-09 20:21         ` Guenter Roeck
2015-07-30  9:25 ` [PATCH V2 4/6] iio: Add htu21 " Ludovic Tancerel
2015-08-08 17:17   ` Jonathan Cameron
2015-07-30  9:25 ` [PATCH V2 5/6] iio: Add ms5637 " Ludovic Tancerel
2015-07-30  9:25 ` [PATCH V2 6/6] iio: Add ms8607 " Ludovic Tancerel
2015-08-08 17:22   ` Jonathan Cameron
2015-09-25  9:25     ` ludovic.tancerel
2015-09-25  9:31       ` ludovic.tancerel
2015-09-27 16:01         ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.