w1: ds2438: support for writing to offset register

Added a sysfs entry to support writing to the offset register on page1.
This register is used to calibrate the chip canceling offset errors in the
current ADC. This means that, over time, reading the IAD register will not
return the correct current measurement, it will have an offset. Writing to
the offset register if the two's complement of the current register while
passing zero current to the load will calibrate the measurements. This
change was tested on real hardware and it was able to calibrate the chip
correctly.

Signed-off-by: Luiz Sampaio <sampaio.ime@gmail.com>
Link: https://lore.kernel.org/r/20210519223046.13798-7-sampaio.ime@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Luiz Sampaio 2021-05-19 19:30:46 -03:00 committed by Greg Kroah-Hartman
parent fd6ec5d795
commit c999fbbdcf
3 changed files with 66 additions and 1 deletions

View File

@ -4,3 +4,10 @@ Contact: Luiz Sampaio <sampaio.ime@gmail.com>
Description: read the contents of the page1 of the DS2438 Description: read the contents of the page1 of the DS2438
see Documentation/w1/slaves/w1_ds2438.rst for detailed information see Documentation/w1/slaves/w1_ds2438.rst for detailed information
Users: any user space application which wants to communicate with DS2438 Users: any user space application which wants to communicate with DS2438
What: /sys/bus/w1/devices/.../offset
Date: April 2021
Contact: Luiz Sampaio <sampaio.ime@gmail.com>
Description: write the contents to the offset register of the DS2438
see Documentation/w1/slaves/w1_ds2438.rst for detailed information
Users: any user space application which wants to communicate with DS2438

View File

@ -22,7 +22,7 @@ is also often used in weather stations and applications such as: rain gauge,
wind speed/direction measuring, humidity sensing, etc. wind speed/direction measuring, humidity sensing, etc.
Current support is provided through the following sysfs files (all files Current support is provided through the following sysfs files (all files
except "iad" are readonly): except "iad" and "offset" are readonly):
"iad" "iad"
----- -----
@ -52,6 +52,15 @@ Internally when this file is read, the additional CRC byte is also obtained
from the slave device. If it is correct, the 8 bytes page data are passed from the slave device. If it is correct, the 8 bytes page data are passed
to userspace, otherwise an I/O error is returned. to userspace, otherwise an I/O error is returned.
"offset"
-------
This file controls the 2-byte Offset Register of the chip.
Writing a 2-byte value will change the Offset Register, which changes the
current measurement done by the chip. Changing this register to the two's complement
of the current register while forcing zero current through the load will calibrate
the chip, canceling offset errors in the current ADC.
"temperature" "temperature"
------------- -------------
Opening and reading this file initiates the CONVERT_T (temperature conversion) Opening and reading this file initiates the CONVERT_T (temperature conversion)

View File

@ -193,6 +193,34 @@ static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value)
return -1; return -1;
} }
static int w1_ds2438_change_offset_register(struct w1_slave *sl, u8 *value)
{
unsigned int retries = W1_DS2438_RETRIES;
u8 w1_buf[9];
u8 w1_page1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/];
if (w1_ds2438_get_page(sl, 1, w1_page1_buf) == 0) {
memcpy(&w1_buf[2], w1_page1_buf, DS2438_PAGE_SIZE - 1); /* last register reserved */
w1_buf[7] = value[0]; /* change only offset register */
w1_buf[8] = value[1];
while (retries--) {
if (w1_reset_select_slave(sl))
continue;
w1_buf[0] = W1_DS2438_WRITE_SCRATCH;
w1_buf[1] = 0x01; /* write to page 1 */
w1_write_block(sl->master, w1_buf, 9);
if (w1_reset_select_slave(sl))
continue;
w1_buf[0] = W1_DS2438_COPY_SCRATCH;
w1_buf[1] = 0x01;
w1_write_block(sl->master, w1_buf, 2);
return 0;
}
}
return -1;
}
static int w1_ds2438_get_voltage(struct w1_slave *sl, static int w1_ds2438_get_voltage(struct w1_slave *sl,
int adc_input, uint16_t *voltage) int adc_input, uint16_t *voltage)
{ {
@ -364,6 +392,25 @@ static ssize_t page1_read(struct file *filp, struct kobject *kobj,
return ret; return ret;
} }
static ssize_t offset_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int ret;
mutex_lock(&sl->master->bus_mutex);
if (w1_ds2438_change_offset_register(sl, buf) == 0)
ret = count;
else
ret = -EIO;
mutex_unlock(&sl->master->bus_mutex);
return ret;
}
static ssize_t temperature_read(struct file *filp, struct kobject *kobj, static ssize_t temperature_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf, struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count) loff_t off, size_t count)
@ -430,6 +477,7 @@ static ssize_t vdd_read(struct file *filp, struct kobject *kobj,
static BIN_ATTR_RW(iad, 0); static BIN_ATTR_RW(iad, 0);
static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE); static BIN_ATTR_RO(page0, DS2438_PAGE_SIZE);
static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE); static BIN_ATTR_RO(page1, DS2438_PAGE_SIZE);
static BIN_ATTR_WO(offset, 2);
static BIN_ATTR_RO(temperature, 0/* real length varies */); static BIN_ATTR_RO(temperature, 0/* real length varies */);
static BIN_ATTR_RO(vad, 0/* real length varies */); static BIN_ATTR_RO(vad, 0/* real length varies */);
static BIN_ATTR_RO(vdd, 0/* real length varies */); static BIN_ATTR_RO(vdd, 0/* real length varies */);
@ -438,6 +486,7 @@ static struct bin_attribute *w1_ds2438_bin_attrs[] = {
&bin_attr_iad, &bin_attr_iad,
&bin_attr_page0, &bin_attr_page0,
&bin_attr_page1, &bin_attr_page1,
&bin_attr_offset,
&bin_attr_temperature, &bin_attr_temperature,
&bin_attr_vad, &bin_attr_vad,
&bin_attr_vdd, &bin_attr_vdd,