ad641e1e9859cc4fd8335dae456616c86071c21a
[openwrt/openwrt.git] /
1 From e6585a1d299375740f95f30027b8b3f4b34e7548 Mon Sep 17 00:00:00 2001
2 From: Akira Shimahara <akira215corp@gmail.com>
3 Date: Mon, 11 May 2020 22:38:20 +0200
4 Subject: [PATCH] w1_therm: adding bulk read support to trigger
5 multiple conversion on bus
6
7 commit 57c76221d5af648c8355a55c09b050c5d8d38189 upstream.
8
9 Adding bulk read support:
10 Sending a 'trigger' command in the dedicated sysfs entry of bus master
11 device send a conversion command for all the slaves on the bus. The sysfs
12 entry is added as soon as at least one device supporting this feature
13 is detected on the bus.
14
15 The behavior of the sysfs reading temperature on the device is as follow:
16 * If no bulk read pending, trigger a conversion on the device, wait for
17 the conversion to be done, read the temperature in device RAM
18 * If a bulk read has been trigger, access directly the device RAM
19 This behavior is the same on the 2 sysfs entries ('temperature' and
20 'w1_slave').
21
22 Reading the therm_bulk_read sysfs give the status of bulk operations:
23 * '-1': conversion in progress on at least 1 sensor
24 * '1': conversion complete but at least one sensor has not been read yet
25 * '0': no bulk operation. Reading temperature on ecah device will trigger
26 a conversion
27
28 As not all devices support bulk read feature, it has been added in device
29 family structure.
30
31 The attribute is set at master level as soon as a supporting device is
32 discover. It is removed when the last supported device leave the bus.
33 The count of supported device is kept with the static counter
34 bulk_read_device_counter.
35
36 A strong pull up is apply on the line if at least one device required it.
37 The duration of the pull up is the max time required by a device on the
38 line, which depends on the resolution settings of each device. The strong
39 pull up could be adjust with the a module parameter.
40
41 Updating documentation in Documentation/ABI/testing/sysfs-driver-w1_therm
42 and Documentation/w1/slaves/w1_therm.rst accordingly.
43
44 Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
45 Link: https://lore.kernel.org/r/20200511203820.411483-1-akira215corp@gmail.com
46 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
47 ---
48 .../ABI/testing/sysfs-driver-w1_therm | 36 ++-
49 Documentation/w1/slaves/w1_therm.rst | 50 +++-
50 drivers/w1/slaves/w1_therm.c | 251 +++++++++++++++++-
51 3 files changed, 322 insertions(+), 15 deletions(-)
52
53 --- a/Documentation/ABI/testing/sysfs-driver-w1_therm
54 +++ b/Documentation/ABI/testing/sysfs-driver-w1_therm
55 @@ -62,9 +62,16 @@ Date: May 2020
56 Contact: Akira Shimahara <akira215corp@gmail.com>
57 Description:
58 (RO) return the temperature in 1/1000 degC.
59 - Note that the conversion duration depend on the resolution (if
60 - device support this feature). It takes 94ms in 9bits
61 - resolution, 750ms for 12bits.
62 + * If a bulk read has been triggered, it will directly
63 + return the temperature computed when the bulk read
64 + occurred, if available. If not yet available, nothing
65 + is returned (a debug kernel message is sent), you
66 + should retry later on.
67 + * If no bulk read has been triggered, it will trigger
68 + a conversion and send the result. Note that the
69 + conversion duration depend on the resolution (if
70 + device support this feature). It takes 94ms in 9bits
71 + resolution, 750ms for 12bits.
72 Users: any user space application which wants to communicate with
73 w1_term device
74
75 @@ -85,4 +92,25 @@ Description:
76 refer to Documentation/w1/slaves/w1_therm.rst for detailed
77 information.
78 Users: any user space application which wants to communicate with
79 - w1_term device
80 \ No newline at end of file
81 + w1_term device
82 +
83 +
84 +What: /sys/bus/w1/devices/w1_bus_masterXX/therm_bulk_read
85 +Date: May 2020
86 +Contact: Akira Shimahara <akira215corp@gmail.com>
87 +Description:
88 + (RW) trigger a bulk read conversion. read the status
89 + *read*:
90 + * '-1': conversion in progress on at least 1 sensor
91 + * '1' : conversion complete but at least one sensor
92 + value has not been read yet
93 + * '0' : no bulk operation. Reading temperature will
94 + trigger a conversion on each device
95 + *write*: 'trigger': trigger a bulk read on all supporting
96 + devices on the bus
97 + Note that if a bulk read is sent but one sensor is not read
98 + immediately, the next access to temperature on this device
99 + will return the temperature measured at the time of issue
100 + of the bulk read command (not the current temperature).
101 +Users: any user space application which wants to communicate with
102 + w1_term device
103 --- a/Documentation/w1/slaves/w1_therm.rst
104 +++ b/Documentation/w1/slaves/w1_therm.rst
105 @@ -26,20 +26,31 @@ W1_THERM_DS1825 0x3B
106 W1_THERM_DS28EA00 0x42
107 ==================== ====
108
109 -Support is provided through the sysfs w1_slave file. Each open and
110 +Support is provided through the sysfs w1_slave file. Each open and
111 read sequence will initiate a temperature conversion then provide two
112 -lines of ASCII output. The first line contains the nine hex bytes
113 +lines of ASCII output. The first line contains the nine hex bytes
114 read along with a calculated crc value and YES or NO if it matched.
115 -If the crc matched the returned values are retained. The second line
116 +If the crc matched the returned values are retained. The second line
117 displays the retained values along with a temperature in millidegrees
118 Centigrade after t=.
119
120 -Parasite powered devices are limited to one slave performing a
121 -temperature conversion at a time. If none of the devices are parasite
122 -powered it would be possible to convert all the devices at the same
123 -time and then go back to read individual sensors. That isn't
124 -currently supported. The driver also doesn't support reduced
125 -precision (which would also reduce the conversion time) when reading values.
126 +Alternatively, temperature can be read using temperature sysfs, it
127 +return only temperature in millidegrees Centigrade.
128 +
129 +A bulk read of all devices on the bus could be done writing 'trigger'
130 +in the therm_bulk_read sysfs entry at w1_bus_master level. This will
131 +sent the convert command on all devices on the bus, and if parasite
132 +powered devices are detected on the bus (and strong pullup is enable
133 +in the module), it will drive the line high during the longer conversion
134 +time required by parasited powered device on the line. Reading
135 +therm_bulk_read will return 0 if no bulk conversion pending,
136 +-1 if at least one sensor still in conversion, 1 if conversion is complete
137 +but at least one sensor value has not been read yet. Result temperature is
138 +then accessed by reading the temperature sysfs entry of each device, which
139 +may return empty if conversion is still in progress. Note that if a bulk
140 +read is sent but one sensor is not read immediately, the next access to
141 +temperature on this device will return the temperature measured at the
142 +time of issue of the bulk read command (not the current temperature).
143
144 Writing a value between 9 and 12 to the sysfs w1_slave file will change the
145 precision of the sensor for the next readings. This value is in (volatile)
146 @@ -49,6 +60,27 @@ To store the current precision configura
147 has to be written to the sysfs w1_slave file. Since the EEPROM has a limited
148 amount of writes (>50k), this command should be used wisely.
149
150 +Alternatively, resolution can be set or read (value from 9 to 12) using the
151 +dedicated resolution sysfs entry on each device. This sysfs entry is not
152 +present for devices not supporting this feature. Driver will adjust the
153 +correct conversion time for each device regarding to its resolution setting.
154 +In particular, strong pullup will be applied if required during the conversion
155 +duration.
156 +
157 +The write-only sysfs entry eeprom is an alternative for EEPROM operations:
158 + * 'save': will save device RAM to EEPROM
159 + * 'restore': will restore EEPROM data in device RAM.
160 +
161 +ext_power syfs entry allow tho check the power status of each device.
162 + * '0': device parasite powered
163 + * '1': device externally powered
164 +
165 +sysfs alarms allow read or write TH and TL (Temperature High an Low) alarms.
166 +Values shall be space separated and in the device range (typical -55 degC
167 +to 125 degC). Values are integer as they are store in a 8bit register in
168 +the device. Lowest value is automatically put to TL.Once set, alarms could
169 +be search at master level.
170 +
171 The module parameter strong_pullup can be set to 0 to disable the
172 strong pullup, 1 to enable autodetection or 2 to force strong pullup.
173 In case of autodetection, the driver will use the "READ POWER SUPPLY"
174 --- a/drivers/w1/slaves/w1_therm.c
175 +++ b/drivers/w1/slaves/w1_therm.c
176 @@ -43,6 +43,9 @@
177 static int w1_strong_pullup = 1;
178 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
179
180 +/* Counter for devices supporting bulk reading */
181 +static u16 bulk_read_device_counter; /* =0 as per C standard */
182 +
183 /* This command should be in public header w1.h but is not */
184 #define W1_RECALL_EEPROM 0xB8
185
186 @@ -57,6 +60,7 @@ module_param_named(strong_pullup, w1_str
187
188 #define EEPROM_CMD_WRITE "save" /* cmd for write eeprom sysfs */
189 #define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */
190 +#define BULK_TRIGGER_CMD "trigger" /* cmd to trigger a bulk read */
191
192 #define MIN_TEMP -55 /* min temperature that can be mesured */
193 #define MAX_TEMP 125 /* max temperature that can be mesured */
194 @@ -84,6 +88,15 @@ module_param_named(strong_pullup, w1_str
195 #define SLAVE_RESOLUTION(sl) \
196 (((struct w1_therm_family_data *)(sl->family_data))->resolution)
197
198 +/*
199 + * return whether or not a converT command has been issued to the slave
200 + * * 0: no bulk read is pending
201 + * * -1: conversion is in progress
202 + * * 1: conversion done, result to be read
203 + */
204 +#define SLAVE_CONVERT_TRIGGERED(sl) \
205 + (((struct w1_therm_family_data *)(sl->family_data))->convert_triggered)
206 +
207 /* return the address of the refcnt in the family data */
208 #define THERM_REFCNT(family_data) \
209 (&((struct w1_therm_family_data *)family_data)->refcnt)
210 @@ -100,6 +113,7 @@ module_param_named(strong_pullup, w1_str
211 * @set_resolution: pointer to the device set_resolution function
212 * @get_resolution: pointer to the device get_resolution function
213 * @write_data: pointer to the device writing function (2 or 3 bytes)
214 + * @bulk_read: true if device family support bulk read, false otherwise
215 */
216 struct w1_therm_family_converter {
217 u8 broken;
218 @@ -110,6 +124,7 @@ struct w1_therm_family_converter {
219 int (*set_resolution)(struct w1_slave *sl, int val);
220 int (*get_resolution)(struct w1_slave *sl);
221 int (*write_data)(struct w1_slave *sl, const u8 *data);
222 + bool bulk_read;
223 };
224
225 /**
226 @@ -120,6 +135,7 @@ struct w1_therm_family_converter {
227 * 0 device parasite powered,
228 * -x error or undefined
229 * @resolution: current device resolution
230 + * @convert_triggered: conversion state of the device
231 * @specific_functions: pointer to struct of device specific function
232 */
233 struct w1_therm_family_data {
234 @@ -127,6 +143,7 @@ struct w1_therm_family_data {
235 atomic_t refcnt;
236 int external_powered;
237 int resolution;
238 + int convert_triggered;
239 struct w1_therm_family_converter *specific_functions;
240 };
241
242 @@ -218,6 +235,18 @@ static int recall_eeprom(struct w1_slave
243 */
244 static int read_powermode(struct w1_slave *sl);
245
246 +/**
247 + * trigger_bulk_read() - function to trigger a bulk read on the bus
248 + * @dev_master: the device master of the bus
249 + *
250 + * Send a SKIP ROM follow by a CONVERT T commmand on the bus.
251 + * It also set the status flag in each slave &struct w1_therm_family_data
252 + * to signal that a conversion is in progress.
253 + *
254 + * Return: 0 if success, -kernel error code otherwise
255 + */
256 +static int trigger_bulk_read(struct w1_master *dev_master);
257 +
258 /* Sysfs interface declaration */
259
260 static ssize_t w1_slave_show(struct device *device,
261 @@ -250,6 +279,12 @@ static ssize_t alarms_store(struct devic
262 static ssize_t alarms_show(struct device *device,
263 struct device_attribute *attr, char *buf);
264
265 +static ssize_t therm_bulk_read_store(struct device *device,
266 + struct device_attribute *attr, const char *buf, size_t size);
267 +
268 +static ssize_t therm_bulk_read_show(struct device *device,
269 + struct device_attribute *attr, char *buf);
270 +
271 /* Attributes declarations */
272
273 static DEVICE_ATTR_RW(w1_slave);
274 @@ -260,6 +295,8 @@ static DEVICE_ATTR_RW(resolution);
275 static DEVICE_ATTR_WO(eeprom);
276 static DEVICE_ATTR_RW(alarms);
277
278 +static DEVICE_ATTR_RW(therm_bulk_read); /* attribut at master level */
279 +
280 /* Interface Functions declaration */
281
282 /**
283 @@ -572,6 +609,7 @@ static struct w1_therm_family_converter
284 .set_resolution = NULL, /* no config register */
285 .get_resolution = NULL, /* no config register */
286 .write_data = w1_DS18S20_write_data,
287 + .bulk_read = true
288 },
289 {
290 .f = &w1_therm_family_DS1822,
291 @@ -580,6 +618,7 @@ static struct w1_therm_family_converter
292 .set_resolution = w1_DS18B20_set_resolution,
293 .get_resolution = w1_DS18B20_get_resolution,
294 .write_data = w1_DS18B20_write_data,
295 + .bulk_read = true
296 },
297 {
298 .f = &w1_therm_family_DS18B20,
299 @@ -588,6 +627,7 @@ static struct w1_therm_family_converter
300 .set_resolution = w1_DS18B20_set_resolution,
301 .get_resolution = w1_DS18B20_get_resolution,
302 .write_data = w1_DS18B20_write_data,
303 + .bulk_read = true
304 },
305 {
306 .f = &w1_therm_family_DS28EA00,
307 @@ -596,6 +636,7 @@ static struct w1_therm_family_converter
308 .set_resolution = w1_DS18B20_set_resolution,
309 .get_resolution = w1_DS18B20_get_resolution,
310 .write_data = w1_DS18B20_write_data,
311 + .bulk_read = false
312 },
313 {
314 .f = &w1_therm_family_DS1825,
315 @@ -604,6 +645,7 @@ static struct w1_therm_family_converter
316 .set_resolution = w1_DS18B20_set_resolution,
317 .get_resolution = w1_DS18B20_get_resolution,
318 .write_data = w1_DS18B20_write_data,
319 + .bulk_read = true
320 }
321 };
322
323 @@ -658,6 +700,23 @@ static inline bool bus_mutex_lock(struct
324 }
325
326 /**
327 + * support_bulk_read() - check if slave support bulk read
328 + * @sl: device to check the ability
329 + *
330 + * Return: true if bulk read is supported, false if not or error
331 + */
332 +static inline bool bulk_read_support(struct w1_slave *sl)
333 +{
334 + if (SLAVE_SPECIFIC_FUNC(sl))
335 + return SLAVE_SPECIFIC_FUNC(sl)->bulk_read;
336 +
337 + dev_info(&sl->dev,
338 + "%s: Device not supported by the driver\n", __func__);
339 +
340 + return false; /* No device family */
341 +}
342 +
343 +/**
344 * conversion_time() - get the Tconv for the slave
345 * @sl: device to get the conversion time
346 *
347 @@ -741,6 +800,24 @@ static int w1_therm_add_slave(struct w1_
348 /* save this pointer to the device structure */
349 SLAVE_SPECIFIC_FUNC(sl) = sl_family_conv;
350
351 + if (bulk_read_support(sl)) {
352 + /*
353 + * add the sys entry to trigger bulk_read
354 + * at master level only the 1st time
355 + */
356 + if (!bulk_read_device_counter) {
357 + int err = device_create_file(&sl->master->dev,
358 + &dev_attr_therm_bulk_read);
359 +
360 + if (err)
361 + dev_warn(&sl->dev,
362 + "%s: Device has been added, but bulk read is unavailable. err=%d\n",
363 + __func__, err);
364 + }
365 + /* Increment the counter */
366 + bulk_read_device_counter++;
367 + }
368 +
369 /* Getting the power mode of the device {external, parasite} */
370 SLAVE_POWERMODE(sl) = read_powermode(sl);
371
372 @@ -763,6 +840,9 @@ static int w1_therm_add_slave(struct w1_
373 }
374 }
375
376 + /* Finally initialize convert_triggered flag */
377 + SLAVE_CONVERT_TRIGGERED(sl) = 0;
378 +
379 return 0;
380 }
381
382 @@ -770,6 +850,14 @@ static void w1_therm_remove_slave(struct
383 {
384 int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
385
386 + if (bulk_read_support(sl)) {
387 + bulk_read_device_counter--;
388 + /* Delete the entry if no more device support the feature */
389 + if (!bulk_read_device_counter)
390 + device_remove_file(&sl->master->dev,
391 + &dev_attr_therm_bulk_read);
392 + }
393 +
394 while (refcnt) {
395 msleep(1000);
396 refcnt = atomic_read(THERM_REFCNT(sl->family_data));
397 @@ -1084,6 +1172,96 @@ error:
398 return ret;
399 }
400
401 +static int trigger_bulk_read(struct w1_master *dev_master)
402 +{
403 + struct w1_slave *sl = NULL; /* used to iterate through slaves */
404 + int max_trying = W1_THERM_MAX_TRY;
405 + int t_conv = 0;
406 + int ret = -ENODEV;
407 + bool strong_pullup = false;
408 +
409 + /*
410 + * Check whether there are parasite powered device on the bus,
411 + * and compute duration of conversion for these devices
412 + * so we can apply a strong pullup if required
413 + */
414 + list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
415 + if (!sl->family_data)
416 + goto error;
417 + if (bulk_read_support(sl)) {
418 + int t_cur = conversion_time(sl);
419 +
420 + t_conv = t_cur > t_conv ? t_cur : t_conv;
421 + strong_pullup = strong_pullup ||
422 + (w1_strong_pullup == 2 ||
423 + (!SLAVE_POWERMODE(sl) &&
424 + w1_strong_pullup));
425 + }
426 + }
427 +
428 + /*
429 + * t_conv is the max conversion time required on the bus
430 + * If its 0, no device support the bulk read feature
431 + */
432 + if (!t_conv)
433 + goto error;
434 +
435 + if (!bus_mutex_lock(&dev_master->bus_mutex)) {
436 + ret = -EAGAIN; /* Didn't acquire the mutex */
437 + goto error;
438 + }
439 +
440 + while ((max_trying--) && (ret < 0)) { /* ret should be either 0 */
441 +
442 + if (!w1_reset_bus(dev_master)) { /* Just reset the bus */
443 + unsigned long sleep_rem;
444 +
445 + w1_write_8(dev_master, W1_SKIP_ROM);
446 +
447 + if (strong_pullup) /* Apply pullup if required */
448 + w1_next_pullup(dev_master, t_conv);
449 +
450 + w1_write_8(dev_master, W1_CONVERT_TEMP);
451 +
452 + /* set a flag to instruct that converT pending */
453 + list_for_each_entry(sl,
454 + &dev_master->slist, w1_slave_entry) {
455 + if (bulk_read_support(sl))
456 + SLAVE_CONVERT_TRIGGERED(sl) = -1;
457 + }
458 +
459 + if (strong_pullup) { /* some device need pullup */
460 + sleep_rem = msleep_interruptible(t_conv);
461 + if (sleep_rem != 0) {
462 + ret = -EINTR;
463 + goto mt_unlock;
464 + }
465 + mutex_unlock(&dev_master->bus_mutex);
466 + } else {
467 + mutex_unlock(&dev_master->bus_mutex);
468 + sleep_rem = msleep_interruptible(t_conv);
469 + if (sleep_rem != 0) {
470 + ret = -EINTR;
471 + goto set_flag;
472 + }
473 + }
474 + ret = 0;
475 + goto set_flag;
476 + }
477 + }
478 +
479 +mt_unlock:
480 + mutex_unlock(&dev_master->bus_mutex);
481 +set_flag:
482 + /* set a flag to register convsersion is done */
483 + list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
484 + if (bulk_read_support(sl))
485 + SLAVE_CONVERT_TRIGGERED(sl) = 1;
486 + }
487 +error:
488 + return ret;
489 +}
490 +
491 /* Sysfs Interface definition */
492
493 static ssize_t w1_slave_show(struct device *device,
494 @@ -1095,7 +1273,20 @@ static ssize_t w1_slave_show(struct devi
495 int ret, i;
496 ssize_t c = PAGE_SIZE;
497
498 - ret = convert_t(sl, &info);
499 + if (bulk_read_support(sl)) {
500 + if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
501 + dev_dbg(device,
502 + "%s: Conversion in progress, retry later\n",
503 + __func__);
504 + return 0;
505 + } else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
506 + /* A bulk read has been issued, read the device RAM */
507 + ret = read_scratchpad(sl, &info);
508 + SLAVE_CONVERT_TRIGGERED(sl) = 0;
509 + } else
510 + ret = convert_t(sl, &info);
511 + } else
512 + ret = convert_t(sl, &info);
513
514 if (ret < 0) {
515 dev_dbg(device,
516 @@ -1176,7 +1367,20 @@ static ssize_t temperature_show(struct d
517 return 0; /* No device family */
518 }
519
520 - ret = convert_t(sl, &info);
521 + if (bulk_read_support(sl)) {
522 + if (SLAVE_CONVERT_TRIGGERED(sl) < 0) {
523 + dev_dbg(device,
524 + "%s: Conversion in progress, retry later\n",
525 + __func__);
526 + return 0;
527 + } else if (SLAVE_CONVERT_TRIGGERED(sl) > 0) {
528 + /* A bulk read has been issued, read the device RAM */
529 + ret = read_scratchpad(sl, &info);
530 + SLAVE_CONVERT_TRIGGERED(sl) = 0;
531 + } else
532 + ret = convert_t(sl, &info);
533 + } else
534 + ret = convert_t(sl, &info);
535
536 if (ret < 0) {
537 dev_dbg(device,
538 @@ -1412,6 +1616,49 @@ free_m:
539 return size;
540 }
541
542 +static ssize_t therm_bulk_read_store(struct device *device,
543 + struct device_attribute *attr, const char *buf, size_t size)
544 +{
545 + struct w1_master *dev_master = dev_to_w1_master(device);
546 + int ret = -EINVAL; /* Invalid argument */
547 +
548 + if (size == sizeof(BULK_TRIGGER_CMD))
549 + if (!strncmp(buf, BULK_TRIGGER_CMD,
550 + sizeof(BULK_TRIGGER_CMD)-1))
551 + ret = trigger_bulk_read(dev_master);
552 +
553 + if (ret)
554 + dev_info(device,
555 + "%s: unable to trigger a bulk read on the bus. err=%d\n",
556 + __func__, ret);
557 +
558 + return size;
559 +}
560 +
561 +static ssize_t therm_bulk_read_show(struct device *device,
562 + struct device_attribute *attr, char *buf)
563 +{
564 + struct w1_master *dev_master = dev_to_w1_master(device);
565 + struct w1_slave *sl = NULL;
566 + int ret = 0;
567 +
568 + list_for_each_entry(sl, &dev_master->slist, w1_slave_entry) {
569 + if (sl->family_data) {
570 + if (bulk_read_support(sl)) {
571 + if (SLAVE_CONVERT_TRIGGERED(sl) == -1) {
572 + ret = -1;
573 + goto show_result;
574 + }
575 + if (SLAVE_CONVERT_TRIGGERED(sl) == 1)
576 + /* continue to check other slaves */
577 + ret = 1;
578 + }
579 + }
580 + }
581 +show_result:
582 + return sprintf(buf, "%d\n", ret);
583 +}
584 +
585 #if IS_REACHABLE(CONFIG_HWMON)
586 static int w1_read_temp(struct device *device, u32 attr, int channel,
587 long *val)