mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
588 lines
20 KiB
Diff
588 lines
20 KiB
Diff
|
From e6585a1d299375740f95f30027b8b3f4b34e7548 Mon Sep 17 00:00:00 2001
|
||
|
From: Akira Shimahara <akira215corp@gmail.com>
|
||
|
Date: Mon, 11 May 2020 22:38:20 +0200
|
||
|
Subject: [PATCH] w1_therm: adding bulk read support to trigger
|
||
|
multiple conversion on bus
|
||
|
|
||
|
commit 57c76221d5af648c8355a55c09b050c5d8d38189 upstream.
|
||
|
|
||
|
Adding bulk read support:
|
||
|
Sending a 'trigger' command in the dedicated sysfs entry of bus master
|
||
|
device send a conversion command for all the slaves on the bus. The sysfs
|
||
|
entry is added as soon as at least one device supporting this feature
|
||
|
is detected on the bus.
|
||
|
|
||
|
The behavior of the sysfs reading temperature on the device is as follow:
|
||
|
* If no bulk read pending, trigger a conversion on the device, wait for
|
||
|
the conversion to be done, read the temperature in device RAM
|
||
|
* If a bulk read has been trigger, access directly the device RAM
|
||
|
This behavior is the same on the 2 sysfs entries ('temperature' and
|
||
|
'w1_slave').
|
||
|
|
||
|
Reading the therm_bulk_read sysfs give the status of bulk operations:
|
||
|
* '-1': conversion in progress on at least 1 sensor
|
||
|
* '1': conversion complete but at least one sensor has not been read yet
|
||
|
* '0': no bulk operation. Reading temperature on ecah device will trigger
|
||
|
a conversion
|
||
|
|
||
|
As not all devices support bulk read feature, it has been added in device
|
||
|
family structure.
|
||
|
|
||
|
The attribute is set at master level as soon as a supporting device is
|
||
|
discover. It is removed when the last supported device leave the bus.
|
||
|
The count of supported device is kept with the static counter
|
||
|
bulk_read_device_counter.
|
||
|
|
||
|
A strong pull up is apply on the line if at least one device required it.
|
||
|
The duration of the pull up is the max time required by a device on the
|
||
|
line, which depends on the resolution settings of each device. The strong
|
||
|
pull up could be adjust with the a module parameter.
|
||
|
|
||
|
Updating documentation in Documentation/ABI/testing/sysfs-driver-w1_therm
|
||
|
and Documentation/w1/slaves/w1_therm.rst accordingly.
|
||
|
|
||
|
Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
|
||
|
Link: https://lore.kernel.org/r/20200511203820.411483-1-akira215corp@gmail.com
|
||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||
|
---
|
||
|
.../ABI/testing/sysfs-driver-w1_therm | 36 ++-
|
||
|
Documentation/w1/slaves/w1_therm.rst | 50 +++-
|
||
|
drivers/w1/slaves/w1_therm.c | 251 +++++++++++++++++-
|
||
|
3 files changed, 322 insertions(+), 15 deletions(-)
|
||
|
|
||
|
--- a/Documentation/ABI/testing/sysfs-driver-w1_therm
|
||
|
+++ b/Documentation/ABI/testing/sysfs-driver-w1_therm
|
||
|
@@ -62,9 +62,16 @@ Date: May 2020
|
||
|
Contact: Akira Shimahara <akira215corp@gmail.com>
|
||
|
Description:
|
||
|
(RO) return the temperature in 1/1000 degC.
|
||
|
- Note that the conversion duration depend on the resolution (if
|
||
|
- device support this feature). It takes 94ms in 9bits
|
||
|
- resolution, 750ms for 12bits.
|
||
|
+ * If a bulk read has been triggered, it will directly
|
||
|
+ return the temperature computed when the bulk read
|
||
|
+ occurred, if available. If not yet available, nothing
|
||
|
+ is returned (a debug kernel message is sent), you
|
||
|
+ should retry later on.
|
||
|
+ * If no bulk read has been triggered, it will trigger
|
||
|
+ a conversion and send the result. Note that the
|
||
|
+ conversion duration depend on the resolution (if
|
||
|
+ device support this feature). It takes 94ms in 9bits
|
||
|
+ resolution, 750ms for 12bits.
|
||
|
Users: any user space application which wants to communicate with
|
||
|
w1_term device
|
||
|
|
||
|
@@ -85,4 +92,25 @@ Description:
|
||
|
refer to Documentation/w1/slaves/w1_therm.rst for detailed
|
||
|
information.
|
||
|
Users: any user space application which wants to communicate with
|
||
|
- w1_term device
|
||
|
\ No newline at end of file
|
||
|
+ w1_term device
|
||
|
+
|
||
|
+
|
||
|
+What: /sys/bus/w1/devices/w1_bus_masterXX/therm_bulk_read
|
||
|
+Date: May 2020
|
||
|
+Contact: Akira Shimahara <akira215corp@gmail.com>
|
||
|
+Description:
|
||
|
+ (RW) trigger a bulk read conversion. read the status
|
||
|
+ *read*:
|
||
|
+ * '-1': conversion in progress on at least 1 sensor
|
||
|
+ * '1' : conversion complete but at least one sensor
|
||
|
+ value has not been read yet
|
||
|
+ * '0' : no bulk operation. Reading temperature will
|
||
|
+ trigger a conversion on each device
|
||
|
+ *write*: 'trigger': trigger a bulk read on all supporting
|
||
|
+ devices on the bus
|
||
|
+ Note that if a bulk read is sent but one sensor is not read
|
||
|
+ immediately, the next access to temperature on this device
|
||
|
+ will return the temperature measured at the time of issue
|
||
|
+ of the bulk read command (not the current temperature).
|
||
|
+Users: any user space application which wants to communicate with
|
||
|
+ w1_term device
|
||
|
--- a/Documentation/w1/slaves/w1_therm.rst
|
||
|
+++ b/Documentation/w1/slaves/w1_therm.rst
|
||
|
@@ -26,20 +26,31 @@ W1_THERM_DS1825 0x3B
|
||
|
W1_THERM_DS28EA00 0x42
|
||
|
==================== ====
|
||
|
|
||
|
-Support is provided through the sysfs w1_slave file. Each open and
|
||
|
+Support is provided through the sysfs w1_slave file. Each open and
|
||
|
read sequence will initiate a temperature conversion then provide two
|
||
|
-lines of ASCII output. The first line contains the nine hex bytes
|
||
|
+lines of ASCII output. The first line contains the nine hex bytes
|
||
|
read along with a calculated crc value and YES or NO if it matched.
|
||
|
-If the crc matched the returned values are retained. The second line
|
||
|
+If the crc matched the returned values are retained. The second line
|
||
|
displays the retained values along with a temperature in millidegrees
|
||
|
Centigrade after t=.
|
||
|
|
||
|
-Parasite powered devices are limited to one slave performing a
|
||
|
-temperature conversion at a time. If none of the devices are parasite
|
||
|
-powered it would be possible to convert all the devices at the same
|
||
|
-time and then go back to read individual sensors. That isn't
|
||
|
-currently supported. The driver also doesn't support reduced
|
||
|
-precision (which would also reduce the conversion time) when reading values.
|
||
|
+Alternatively, temperature can be read using temperature sysfs, it
|
||
|
+return only temperature in millidegrees Centigrade.
|
||
|
+
|
||
|
+A bulk read of all devices on the bus could be done writing 'trigger'
|
||
|
+in the therm_bulk_read sysfs entry at w1_bus_master level. This will
|
||
|
+sent the convert command on all devices on the bus, and if parasite
|
||
|
+powered devices are detected on the bus (and strong pullup is enable
|
||
|
+in the module), it will drive the line high during the longer conversion
|
||
|
+time required by parasited powered device on the line. Reading
|
||
|
+therm_bulk_read will return 0 if no bulk conversion pending,
|
||
|
+-1 if at least one sensor still in conversion, 1 if conversion is complete
|
||
|
+but at least one sensor value has not been read yet. Result temperature is
|
||
|
+then accessed by reading the temperature sysfs entry of each device, which
|
||
|
+may return empty if conversion is still in progress. Note that if a bulk
|
||
|
+read is sent but one sensor is not read immediately, the next access to
|
||
|
+temperature on this device will return the temperature measured at the
|
||
|
+time of issue of the bulk read command (not the current temperature).
|
||
|
|
||
|
Writing a value between 9 and 12 to the sysfs w1_slave file will change the
|
||
|
precision of the sensor for the next readings. This value is in (volatile)
|
||
|
@@ -49,6 +60,27 @@ To store the current precision configura
|
||
|
has to be written to the sysfs w1_slave file. Since the EEPROM has a limited
|
||
|
amount of writes (>50k), this command should be used wisely.
|
||
|
|
||
|
+Alternatively, resolution can be set or read (value from 9 to 12) using the
|
||
|
+dedicated resolution sysfs entry on each device. This sysfs entry is not
|
||
|
+present for devices not supporting this feature. Driver will adjust the
|
||
|
+correct conversion time for each device regarding to its resolution setting.
|
||
|
+In particular, strong pullup will be applied if required during the conversion
|
||
|
+duration.
|
||
|
+
|
||
|
+The write-only sysfs entry eeprom is an alternative for EEPROM operations:
|
||
|
+ * 'save': will save device RAM to EEPROM
|
||
|
+ * 'restore': will restore EEPROM data in device RAM.
|
||
|
+
|
||
|
+ext_power syfs entry allow tho check the power status of each device.
|
||
|
+ * '0': device parasite powered
|
||
|
+ * '1': device externally powered
|
||
|
+
|
||
|
+sysfs alarms allow read or write TH and TL (Temperature High an Low) alarms.
|
||
|
+Values shall be space separated and in the device range (typical -55 degC
|
||
|
+to 125 degC). Values are integer as they are store in a 8bit register in
|
||
|
+the device. Lowest value is automatically put to TL.Once set, alarms could
|
||
|
+be search at master level.
|
||
|
+
|
||
|
The module parameter strong_pullup can be set to 0 to disable the
|
||
|
strong pullup, 1 to enable autodetection or 2 to force strong pullup.
|
||
|
In case of autodetection, the driver will use the "READ POWER SUPPLY"
|
||
|
--- a/drivers/w1/slaves/w1_therm.c
|
||
|
+++ b/drivers/w1/slaves/w1_therm.c
|
||
|
@@ -43,6 +43,9 @@
|
||
|
static int w1_strong_pullup = 1;
|
||
|
module_param_named(strong_pullup, w1_strong_pullup, int, 0);
|
||
|
|
||
|
+/* Counter for devices supporting bulk reading */
|
||
|
+static u16 bulk_read_device_counter; /* =0 as per C standard */
|
||
|
+
|
||
|
/* This command should be in public header w1.h but is not */
|
||
|
#define W1_RECALL_EEPROM 0xB8
|
||
|
|
||
|
@@ -57,6 +60,7 @@ module_param_named(strong_pullup, w1_str
|
||
|
|
||
|
#define EEPROM_CMD_WRITE "save" /* cmd for write eeprom sysfs */
|
||
|
#define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */
|
||
|
+#define BULK_TRIGGER_CMD "trigger" /* cmd to trigger a bulk read */
|
||
|
|
||
|
#define MIN_TEMP -55 /* min temperature that can be mesured */
|
||
|
#define MAX_TEMP 125 /* max temperature that can be mesured */
|
||
|
@@ -84,6 +88,15 @@ module_param_named(strong_pullup, w1_str
|
||
|
#define SLAVE_RESOLUTION(sl) \
|
||
|
(((struct w1_therm_family_data *)(sl->family_data))->resolution)
|
||
|
|
||
|
+/*
|
||
|
+ * return whether or not a converT command has been issued to the slave
|
||
|
+ * * 0: no bulk read is pending
|
||
|
+ * * -1: conversion is in progress
|
||
|
+ * * 1: conversion done, result to be read
|
||
|
+ */
|
||
|
+#define SLAVE_CONVERT_TRIGGERED(sl) \
|
||
|
+ (((struct w1_therm_family_data *)(sl->family_data))->convert_triggered)
|
||
|
+
|
||
|
/* return the address of the refcnt in the family data */
|
||
|
#define THERM_REFCNT(family_data) \
|
||
|
(&((struct w1_therm_family_data *)family_data)->refcnt)
|
||
|
@@ -100,6 +113,7 @@ module_param_named(strong_pullup, w1_str
|
||
|
* @set_resolution: pointer to the device set_resolution function
|
||
|
* @get_resolution: pointer to the device get_resolution function
|
||
|
* @write_data: pointer to the device writing function (2 or 3 bytes)
|
||
|
+ * @bulk_read: true if device family support bulk read, false otherwise
|
||
|
*/
|
||
|
struct w1_therm_family_converter {
|
||
|
u8 broken;
|
||
|
@@ -110,6 +124,7 @@ struct w1_therm_family_converter {
|
||
|
int (*set_resolution)(struct w1_slave *sl, int val);
|
||
|
int (*get_resolution)(struct w1_slave *sl);
|
||
|
int (*write_data)(struct w1_slave *sl, const u8 *data);
|
||
|
+ bool bulk_read;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
@@ -120,6 +135,7 @@ struct w1_therm_family_converter {
|
||
|
* 0 device parasite powered,
|
||
|
* -x error or undefined
|
||
|
* @resolution: current device resolution
|
||
|
+ * @convert_triggered: conversion state of the device
|
||
|
* @specific_functions: pointer to struct of device specific function
|
||
|
*/
|
||
|
struct w1_therm_family_data {
|
||
|
@@ -127,6 +143,7 @@ struct w1_therm_family_data {
|
||
|
atomic_t refcnt;
|
||
|
int external_powered;
|
||
|
int resolution;
|
||
|
+ int convert_triggered;
|
||
|
struct w1_therm_family_converter *specific_functions;
|
||
|
};
|
||
|
|
||
|
@@ -218,6 +235,18 @@ static int recall_eeprom(struct w1_slave
|
||
|
*/
|
||
|
static int read_powermode(struct w1_slave *sl);
|
||
|
|
||
|
+/**
|
||
|
+ * trigger_bulk_read() - function to trigger a bulk read on the bus
|
||
|
+ * @dev_master: the device master of the bus
|
||
|
+ *
|
||
|
+ * Send a SKIP ROM follow by a CONVERT T commmand on the bus.
|
||
|
+ * It also set the status flag in each slave &struct w1_therm_family_data
|
||
|
+ * to signal that a conversion is in progress.
|
||
|
+ *
|
||
|
+ * Return: 0 if success, -kernel error code otherwise
|
||
|
+ */
|
||
|
+static int trigger_bulk_read(struct w1_master *dev_master);
|
||
|
+
|
||
|
/* Sysfs interface declaration */
|
||
|
|
||
|
static ssize_t w1_slave_show(struct device *device,
|
||
|
@@ -250,6 +279,12 @@ static ssize_t alarms_store(struct devic
|
||
|
static ssize_t alarms_show(struct device *device,
|
||
|
struct device_attribute *attr, char *buf);
|
||
|
|
||
|
+static ssize_t therm_bulk_read_store(struct device *device,
|
||
|
+ struct device_attribute *attr, const char *buf, size_t size);
|
||
|
+
|
||
|
+static ssize_t therm_bulk_read_show(struct device *device,
|
||
|
+ struct device_attribute *attr, char *buf);
|
||
|
+
|
||
|
/* Attributes declarations */
|
||
|
|
||
|
static DEVICE_ATTR_RW(w1_slave);
|
||
|
@@ -260,6 +295,8 @@ static DEVICE_ATTR_RW(resolution);
|
||
|
static DEVICE_ATTR_WO(eeprom);
|
||
|
static DEVICE_ATTR_RW(alarms);
|
||
|
|
||
|
+static DEVICE_ATTR_RW(therm_bulk_read); /* attribut at master level */
|
||
|
+
|
||
|
/* Interface Functions declaration */
|
||
|
|
||
|
/**
|
||
|
@@ -572,6 +609,7 @@ static struct w1_therm_family_converter
|
||
|
.set_resolution = NULL, /* no config register */
|
||
|
.get_resolution = NULL, /* no config register */
|
||
|
.write_data = w1_DS18S20_write_data,
|
||
|
+ .bulk_read = true
|
||
|
},
|
||
|
{
|
||
|
.f = &w1_therm_family_DS1822,
|
||
|
@@ -580,6 +618,7 @@ static struct w1_therm_family_converter
|
||
|
.set_resolution = w1_DS18B20_set_resolution,
|
||
|
.get_resolution = w1_DS18B20_get_resolution,
|
||
|
.write_data = w1_DS18B20_write_data,
|
||
|
+ .bulk_read = true
|
||
|
},
|
||
|
{
|
||
|
.f = &w1_therm_family_DS18B20,
|
||
|
@@ -588,6 +627,7 @@ static struct w1_therm_family_converter
|
||
|
.set_resolution = w1_DS18B20_set_resolution,
|
||
|
.get_resolution = w1_DS18B20_get_resolution,
|
||
|
.write_data = w1_DS18B20_write_data,
|
||
|
+ .bulk_read = true
|
||
|
},
|
||
|
{
|
||
|
.f = &w1_therm_family_DS28EA00,
|
||
|
@@ -596,6 +636,7 @@ static struct w1_therm_family_converter
|
||
|
.set_resolution = w1_DS18B20_set_resolution,
|
||
|
.get_resolution = w1_DS18B20_get_resolution,
|
||
|
.write_data = w1_DS18B20_write_data,
|
||
|
+ .bulk_read = false
|
||
|
},
|
||
|
{
|
||
|
.f = &w1_therm_family_DS1825,
|
||
|
@@ -604,6 +645,7 @@ static struct w1_therm_family_converter
|
||
|
.set_resolution = w1_DS18B20_set_resolution,
|
||
|
.get_resolution = w1_DS18B20_get_resolution,
|
||
|
.write_data = w1_DS18B20_write_data,
|
||
|
+ .bulk_read = true
|
||
|
}
|
||
|
};
|
||
|
|
||
|
@@ -658,6 +700,23 @@ static inline bool bus_mutex_lock(struct
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+ * support_bulk_read() - check if slave support bulk read
|
||
|
+ * @sl: device to check the ability
|
||
|
+ *
|
||
|
+ * Return: true if bulk read is supported, false if not or error
|
||
|
+ */
|
||
|
+static inline bool bulk_read_support(struct w1_slave *sl)
|
||
|
+{
|
||
|
+ if (SLAVE_SPECIFIC_FUNC(sl))
|
||
|
+ return SLAVE_SPECIFIC_FUNC(sl)->bulk_read;
|
||
|
+
|
||
|
+ dev_info(&sl->dev,
|
||
|
+ "%s: Device not supported by the driver\n", __func__);
|
||
|
+
|
||
|
+ return false; /* No device family */
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
* conversion_time() - get the Tconv for the slave
|
||
|
* @sl: device to get the conversion time
|
||
|
*
|
||
|
@@ -741,6 +800,24 @@ static int w1_therm_add_slave(struct w1_
|
||
|
/* save this pointer to the device structure */
|
||
|
SLAVE_SPECIFIC_FUNC(sl) = sl_family_conv;
|
||
|
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ /*
|
||
|
+ * add the sys entry to trigger bulk_read
|
||
|
+ * at master level only the 1st time
|
||
|
+ */
|
||
|
+ if (!bulk_read_device_counter) {
|
||
|
+ int err = device_create_file(&sl->master->dev,
|
||
|
+ &dev_attr_therm_bulk_read);
|
||
|
+
|
||
|
+ if (err)
|
||
|
+ dev_warn(&sl->dev,
|
||
|
+ "%s: Device has been added, but bulk read is unavailable. err=%d\n",
|
||
|
+ __func__, err);
|
||
|
+ }
|
||
|
+ /* Increment the counter */
|
||
|
+ bulk_read_device_counter++;
|
||
|
+ }
|
||
|
+
|
||
|
/* Getting the power mode of the device {external, parasite} */
|
||
|
SLAVE_POWERMODE(sl) = read_powermode(sl);
|
||
|
|
||
|
@@ -763,6 +840,9 @@ static int w1_therm_add_slave(struct w1_
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ /* Finally initialize convert_triggered flag */
|
||
|
+ SLAVE_CONVERT_TRIGGERED(sl) = 0;
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -770,6 +850,14 @@ static void w1_therm_remove_slave(struct
|
||
|
{
|
||
|
int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
|
||
|
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ bulk_read_device_counter--;
|
||
|
+ /* Delete the entry if no more device support the feature */
|
||
|
+ if (!bulk_read_device_counter)
|
||
|
+ device_remove_file(&sl->master->dev,
|
||
|
+ &dev_attr_therm_bulk_read);
|
||
|
+ }
|
||
|
+
|
||
|
while (refcnt) {
|
||
|
msleep(1000);
|
||
|
refcnt = atomic_read(THERM_REFCNT(sl->family_data));
|
||
|
@@ -1084,6 +1172,96 @@ error:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+static int trigger_bulk_read(struct w1_master *dev_master)
|
||
|
+{
|
||
|
+ struct w1_slave *sl = NULL; /* used to iterate through slaves */
|
||
|
+ int max_trying = W1_THERM_MAX_TRY;
|
||
|
+ int t_conv = 0;
|
||
|
+ int ret = -ENODEV;
|
||
|
+ bool strong_pullup = false;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Check whether there are parasite powered device on the bus,
|
||
|
+ * and compute duration of conversion for these devices
|
||
|
+ * so we can apply a strong pullup if required
|
||
|
+ */
|
||
|
+ list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
|
||
|
+ if (!sl->family_data)
|
||
|
+ goto error;
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ int t_cur = conversion_time(sl);
|
||
|
+
|
||
|
+ t_conv = t_cur > t_conv ? t_cur : t_conv;
|
||
|
+ strong_pullup = strong_pullup ||
|
||
|
+ (w1_strong_pullup == 2 ||
|
||
|
+ (!SLAVE_POWERMODE(sl) &&
|
||
|
+ w1_strong_pullup));
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * t_conv is the max conversion time required on the bus
|
||
|
+ * If its 0, no device support the bulk read feature
|
||
|
+ */
|
||
|
+ if (!t_conv)
|
||
|
+ goto error;
|
||
|
+
|
||
|
+ if (!bus_mutex_lock(&dev_master->bus_mutex)) {
|
||
|
+ ret = -EAGAIN; /* Didn't acquire the mutex */
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+
|
||
|
+ while ((max_trying--) && (ret < 0)) { /* ret should be either 0 */
|
||
|
+
|
||
|
+ if (!w1_reset_bus(dev_master)) { /* Just reset the bus */
|
||
|
+ unsigned long sleep_rem;
|
||
|
+
|
||
|
+ w1_write_8(dev_master, W1_SKIP_ROM);
|
||
|
+
|
||
|
+ if (strong_pullup) /* Apply pullup if required */
|
||
|
+ w1_next_pullup(dev_master, t_conv);
|
||
|
+
|
||
|
+ w1_write_8(dev_master, W1_CONVERT_TEMP);
|
||
|
+
|
||
|
+ /* set a flag to instruct that converT pending */
|
||
|
+ list_for_each_entry(sl,
|
||
|
+ &dev_master->slist, w1_slave_entry) {
|
||
|
+ if (bulk_read_support(sl))
|
||
|
+ SLAVE_CONVERT_TRIGGERED(sl) = -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (strong_pullup) { /* some device need pullup */
|
||
|
+ sleep_rem = msleep_interruptible(t_conv);
|
||
|
+ if (sleep_rem != 0) {
|
||
|
+ ret = -EINTR;
|
||
|
+ goto mt_unlock;
|
||
|
+ }
|
||
|
+ mutex_unlock(&dev_master->bus_mutex);
|
||
|
+ } else {
|
||
|
+ mutex_unlock(&dev_master->bus_mutex);
|
||
|
+ sleep_rem = msleep_interruptible(t_conv);
|
||
|
+ if (sleep_rem != 0) {
|
||
|
+ ret = -EINTR;
|
||
|
+ goto set_flag;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ ret = 0;
|
||
|
+ goto set_flag;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+mt_unlock:
|
||
|
+ mutex_unlock(&dev_master->bus_mutex);
|
||
|
+set_flag:
|
||
|
+ /* set a flag to register convsersion is done */
|
||
|
+ list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
|
||
|
+ if (bulk_read_support(sl))
|
||
|
+ SLAVE_CONVERT_TRIGGERED(sl) = 1;
|
||
|
+ }
|
||
|
+error:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
/* Sysfs Interface definition */
|
||
|
|
||
|
static ssize_t w1_slave_show(struct device *device,
|
||
|
@@ -1095,7 +1273,20 @@ static ssize_t w1_slave_show(struct devi
|
||
|
int ret, i;
|
||
|
ssize_t c = PAGE_SIZE;
|
||
|
|
||
|
- ret = convert_t(sl, &info);
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
|
||
|
+ dev_dbg(device,
|
||
|
+ "%s: Conversion in progress, retry later\n",
|
||
|
+ __func__);
|
||
|
+ return 0;
|
||
|
+ } else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
|
||
|
+ /* A bulk read has been issued, read the device RAM */
|
||
|
+ ret = read_scratchpad(sl, &info);
|
||
|
+ SLAVE_CONVERT_TRIGGERED(sl) = 0;
|
||
|
+ } else
|
||
|
+ ret = convert_t(sl, &info);
|
||
|
+ } else
|
||
|
+ ret = convert_t(sl, &info);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
dev_dbg(device,
|
||
|
@@ -1176,7 +1367,20 @@ static ssize_t temperature_show(struct d
|
||
|
return 0; /* No device family */
|
||
|
}
|
||
|
|
||
|
- ret = convert_t(sl, &info);
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
|
||
|
+ dev_dbg(device,
|
||
|
+ "%s: Conversion in progress, retry later\n",
|
||
|
+ __func__);
|
||
|
+ return 0;
|
||
|
+ } else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
|
||
|
+ /* A bulk read has been issued, read the device RAM */
|
||
|
+ ret = read_scratchpad(sl, &info);
|
||
|
+ SLAVE_CONVERT_TRIGGERED(sl) = 0;
|
||
|
+ } else
|
||
|
+ ret = convert_t(sl, &info);
|
||
|
+ } else
|
||
|
+ ret = convert_t(sl, &info);
|
||
|
|
||
|
if (ret < 0) {
|
||
|
dev_dbg(device,
|
||
|
@@ -1412,6 +1616,49 @@ free_m:
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
+static ssize_t therm_bulk_read_store(struct device *device,
|
||
|
+ struct device_attribute *attr, const char *buf, size_t size)
|
||
|
+{
|
||
|
+ struct w1_master *dev_master = dev_to_w1_master(device);
|
||
|
+ int ret = -EINVAL; /* Invalid argument */
|
||
|
+
|
||
|
+ if (size == sizeof(BULK_TRIGGER_CMD))
|
||
|
+ if (!strncmp(buf, BULK_TRIGGER_CMD,
|
||
|
+ sizeof(BULK_TRIGGER_CMD)-1))
|
||
|
+ ret = trigger_bulk_read(dev_master);
|
||
|
+
|
||
|
+ if (ret)
|
||
|
+ dev_info(device,
|
||
|
+ "%s: unable to trigger a bulk read on the bus. err=%d\n",
|
||
|
+ __func__, ret);
|
||
|
+
|
||
|
+ return size;
|
||
|
+}
|
||
|
+
|
||
|
+static ssize_t therm_bulk_read_show(struct device *device,
|
||
|
+ struct device_attribute *attr, char *buf)
|
||
|
+{
|
||
|
+ struct w1_master *dev_master = dev_to_w1_master(device);
|
||
|
+ struct w1_slave *sl = NULL;
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
|
||
|
+ if (sl->family_data) {
|
||
|
+ if (bulk_read_support(sl)) {
|
||
|
+ if (SLAVE_CONVERT_TRIGGERED(sl) == -1) {
|
||
|
+ ret = -1;
|
||
|
+ goto show_result;
|
||
|
+ }
|
||
|
+ if (SLAVE_CONVERT_TRIGGERED(sl) == 1)
|
||
|
+ /* continue to check other slaves */
|
||
|
+ ret = 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+show_result:
|
||
|
+ return sprintf(buf, "%d\n", ret);
|
||
|
+}
|
||
|
+
|
||
|
#if IS_REACHABLE(CONFIG_HWMON)
|
||
|
static int w1_read_temp(struct device *device, u32 attr, int channel,
|
||
|
long *val)
|