blob: 5db05123da2e7fb85120f3923bc47deb9e38353a [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 7c49e87acd0412ff1fb2490c4ac6fcb5471afd9b Mon Sep 17 00:00:00 2001
2From: Akira Shimahara <akira215corp@gmail.com>
3Date: Mon, 11 May 2020 22:35:35 +0200
4Subject: [PATCH] w1_therm: adding code comments and code reordering
5
6commit 92b8d2724464bc1d2e735a84c0da5741dce33485 upstream.
7
8Adding code comments to split code in dedicated parts. After the global
9declarations (defines, macros and function declarations), code is organized
10as follow :
11 - Device and family dependent structures and functions
12 - Interfaces functions
13 - Helpers functions
14 - Hardware functions
15 - Sysfs interface functions
16
17Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
18Link: https://lore.kernel.org/r/20200511203535.409599-1-akira215corp@gmail.com
19Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20---
21 drivers/w1/slaves/w1_therm.c | 427 +++++++++++++++++++++--------------
22 1 file changed, 259 insertions(+), 168 deletions(-)
23
24--- a/drivers/w1/slaves/w1_therm.c
25+++ b/drivers/w1/slaves/w1_therm.c
26@@ -25,7 +25,8 @@
27 #define W1_THERM_DS1825 0x3B
28 #define W1_THERM_DS28EA00 0x42
29
30-/* Allow the strong pullup to be disabled, but default to enabled.
31+/*
32+ * Allow the strong pullup to be disabled, but default to enabled.
33 * If it was disabled a parasite powered device might not get the require
34 * current to do a temperature conversion. If it is enabled parasite powered
35 * devices have a better chance of getting the current required.
36@@ -41,42 +42,55 @@
37 static int w1_strong_pullup = 1;
38 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
39
40+/* Helpers Macros */
41+
42+/* return the address of the refcnt in the family data */
43+#define THERM_REFCNT(family_data) \
44+ (&((struct w1_therm_family_data *)family_data)->refcnt)
45+
46+/* Structs definition */
47+
48+/**
49+ * struct w1_therm_family_converter - bind device specific functions
50+ * @broken: flag for non-registred families
51+ * @reserved: not used here
52+ * @f: pointer to the device binding structure
53+ * @convert: pointer to the device conversion function
54+ * @precision: pointer to the device precision function
55+ * @eeprom: pointer to eeprom function
56+ */
57+struct w1_therm_family_converter {
58+ u8 broken;
59+ u16 reserved;
60+ struct w1_family *f;
61+ int (*convert)(u8 rom[9]);
62+ int (*precision)(struct device *device, int val);
63+ int (*eeprom)(struct device *device);
64+};
65+
66+/**
67+ * struct w1_therm_family_data - device data
68+ * @rom: ROM device id (64bit Lasered ROM code + 1 CRC byte)
69+ * @refcnt: ref count
70+ */
71 struct w1_therm_family_data {
72 uint8_t rom[9];
73 atomic_t refcnt;
74 };
75
76+/**
77+ * struct therm_info - store temperature reading
78+ * @rom: read device data (8 data bytes + 1 CRC byte)
79+ * @crc: computed crc from rom
80+ * @verdict: 1 crc checked, 0 crc not matching
81+ */
82 struct therm_info {
83 u8 rom[9];
84 u8 crc;
85 u8 verdict;
86 };
87
88-/* return the address of the refcnt in the family data */
89-#define THERM_REFCNT(family_data) \
90- (&((struct w1_therm_family_data *)family_data)->refcnt)
91-
92-static int w1_therm_add_slave(struct w1_slave *sl)
93-{
94- sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
95- GFP_KERNEL);
96- if (!sl->family_data)
97- return -ENOMEM;
98- atomic_set(THERM_REFCNT(sl->family_data), 1);
99- return 0;
100-}
101-
102-static void w1_therm_remove_slave(struct w1_slave *sl)
103-{
104- int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
105-
106- while (refcnt) {
107- msleep(1000);
108- refcnt = atomic_read(THERM_REFCNT(sl->family_data));
109- }
110- kfree(sl->family_data);
111- sl->family_data = NULL;
112-}
113+/* Sysfs interface declaration */
114
115 static ssize_t w1_slave_show(struct device *device,
116 struct device_attribute *attr, char *buf);
117@@ -87,9 +101,35 @@ static ssize_t w1_slave_store(struct dev
118 static ssize_t w1_seq_show(struct device *device,
119 struct device_attribute *attr, char *buf);
120
121+/* Attributes declarations */
122+
123 static DEVICE_ATTR_RW(w1_slave);
124 static DEVICE_ATTR_RO(w1_seq);
125
126+/* Interface Functions declaration */
127+
128+/**
129+ * w1_therm_add_slave() - Called when a new slave is discovered
130+ * @sl: slave just discovered by the master.
131+ *
132+ * Called by the master when the slave is discovered on the bus. Used to
133+ * initialize slave state before the beginning of any communication.
134+ *
135+ * Return: 0 - If success, negative kernel code otherwise
136+ */
137+static int w1_therm_add_slave(struct w1_slave *sl);
138+
139+/**
140+ * w1_therm_remove_slave() - Called when a slave is removed
141+ * @sl: slave to be removed.
142+ *
143+ * Called by the master when the slave is considered not to be on the bus
144+ * anymore. Used to free memory.
145+ */
146+static void w1_therm_remove_slave(struct w1_slave *sl);
147+
148+/* Family attributes */
149+
150 static struct attribute *w1_therm_attrs[] = {
151 &dev_attr_w1_slave.attr,
152 NULL,
153@@ -101,6 +141,8 @@ static struct attribute *w1_ds28ea00_att
154 NULL,
155 };
156
157+/* Attribute groups */
158+
159 ATTRIBUTE_GROUPS(w1_therm);
160 ATTRIBUTE_GROUPS(w1_ds28ea00);
161
162@@ -154,6 +196,8 @@ static const struct hwmon_chip_info w1_c
163 #define W1_CHIPINFO NULL
164 #endif
165
166+/* Family operations */
167+
168 static struct w1_family_ops w1_therm_fops = {
169 .add_slave = w1_therm_add_slave,
170 .remove_slave = w1_therm_remove_slave,
171@@ -168,6 +212,8 @@ static struct w1_family_ops w1_ds28ea00_
172 .chip_info = W1_CHIPINFO,
173 };
174
175+/* Family binding operations struct */
176+
177 static struct w1_family w1_therm_family_DS18S20 = {
178 .fid = W1_THERM_DS18S20,
179 .fops = &w1_therm_fops,
180@@ -193,138 +239,18 @@ static struct w1_family w1_therm_family_
181 .fops = &w1_therm_fops,
182 };
183
184-struct w1_therm_family_converter {
185- u8 broken;
186- u16 reserved;
187- struct w1_family *f;
188- int (*convert)(u8 rom[9]);
189- int (*precision)(struct device *device, int val);
190- int (*eeprom)(struct device *device);
191-};
192+/* Device dependent func */
193
194 /* write configuration to eeprom */
195 static inline int w1_therm_eeprom(struct device *device);
196
197-/* Set precision for conversion */
198-static inline int w1_DS18B20_precision(struct device *device, int val);
199-static inline int w1_DS18S20_precision(struct device *device, int val);
200-
201-/* The return value is millidegrees Centigrade. */
202-static inline int w1_DS18B20_convert_temp(u8 rom[9]);
203-static inline int w1_DS18S20_convert_temp(u8 rom[9]);
204-
205-static struct w1_therm_family_converter w1_therm_families[] = {
206- {
207- .f = &w1_therm_family_DS18S20,
208- .convert = w1_DS18S20_convert_temp,
209- .precision = w1_DS18S20_precision,
210- .eeprom = w1_therm_eeprom
211- },
212- {
213- .f = &w1_therm_family_DS1822,
214- .convert = w1_DS18B20_convert_temp,
215- .precision = w1_DS18S20_precision,
216- .eeprom = w1_therm_eeprom
217- },
218- {
219- .f = &w1_therm_family_DS18B20,
220- .convert = w1_DS18B20_convert_temp,
221- .precision = w1_DS18B20_precision,
222- .eeprom = w1_therm_eeprom
223- },
224- {
225- .f = &w1_therm_family_DS28EA00,
226- .convert = w1_DS18B20_convert_temp,
227- .precision = w1_DS18S20_precision,
228- .eeprom = w1_therm_eeprom
229- },
230- {
231- .f = &w1_therm_family_DS1825,
232- .convert = w1_DS18B20_convert_temp,
233- .precision = w1_DS18S20_precision,
234- .eeprom = w1_therm_eeprom
235- }
236-};
237-
238-static inline int w1_therm_eeprom(struct device *device)
239-{
240- struct w1_slave *sl = dev_to_w1_slave(device);
241- struct w1_master *dev = sl->master;
242- u8 rom[9], external_power;
243- int ret, max_trying = 10;
244- u8 *family_data = sl->family_data;
245-
246- if (!sl->family_data) {
247- ret = -ENODEV;
248- goto error;
249- }
250-
251- /* prevent the slave from going away in sleep */
252- atomic_inc(THERM_REFCNT(family_data));
253-
254- ret = mutex_lock_interruptible(&dev->bus_mutex);
255- if (ret != 0)
256- goto dec_refcnt;
257-
258- memset(rom, 0, sizeof(rom));
259-
260- while (max_trying--) {
261- if (!w1_reset_select_slave(sl)) {
262- unsigned int tm = 10;
263- unsigned long sleep_rem;
264-
265- /* check if in parasite mode */
266- w1_write_8(dev, W1_READ_PSUPPLY);
267- external_power = w1_read_8(dev);
268-
269- if (w1_reset_select_slave(sl))
270- continue;
271-
272- /* 10ms strong pullup/delay after the copy command */
273- if (w1_strong_pullup == 2 ||
274- (!external_power && w1_strong_pullup))
275- w1_next_pullup(dev, tm);
276-
277- w1_write_8(dev, W1_COPY_SCRATCHPAD);
278-
279- if (external_power) {
280- mutex_unlock(&dev->bus_mutex);
281-
282- sleep_rem = msleep_interruptible(tm);
283- if (sleep_rem != 0) {
284- ret = -EINTR;
285- goto dec_refcnt;
286- }
287-
288- ret = mutex_lock_interruptible(&dev->bus_mutex);
289- if (ret != 0)
290- goto dec_refcnt;
291- } else if (!w1_strong_pullup) {
292- sleep_rem = msleep_interruptible(tm);
293- if (sleep_rem != 0) {
294- ret = -EINTR;
295- goto mt_unlock;
296- }
297- }
298-
299- break;
300- }
301- }
302-
303-mt_unlock:
304- mutex_unlock(&dev->bus_mutex);
305-dec_refcnt:
306- atomic_dec(THERM_REFCNT(family_data));
307-error:
308- return ret;
309-}
310-
311 /* DS18S20 does not feature configuration register */
312 static inline int w1_DS18S20_precision(struct device *device, int val)
313 {
314 return 0;
315 }
316
317+/* Set precision for conversion */
318 static inline int w1_DS18B20_precision(struct device *device, int val)
319 {
320 struct w1_slave *sl = dev_to_w1_slave(device);
321@@ -407,6 +333,14 @@ error:
322 return ret;
323 }
324
325+/**
326+ * w1_DS18B20_convert_temp() - temperature computation for DS18B20
327+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
328+ *
329+ * Can be called for any DS18B20 compliant device.
330+ *
331+ * Return: value in millidegrees Celsius.
332+ */
333 static inline int w1_DS18B20_convert_temp(u8 rom[9])
334 {
335 s16 t = le16_to_cpup((__le16 *)rom);
336@@ -414,6 +348,14 @@ static inline int w1_DS18B20_convert_tem
337 return t*1000/16;
338 }
339
340+/**
341+ * w1_DS18S20_convert_temp() - temperature computation for DS18S20
342+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
343+ *
344+ * Can be called for any DS18S20 compliant device.
345+ *
346+ * Return: value in millidegrees Celsius.
347+ */
348 static inline int w1_DS18S20_convert_temp(u8 rom[9])
349 {
350 int t, h;
351@@ -434,6 +376,53 @@ static inline int w1_DS18S20_convert_tem
352 return t;
353 }
354
355+/* Device capability description */
356+
357+static struct w1_therm_family_converter w1_therm_families[] = {
358+ {
359+ .f = &w1_therm_family_DS18S20,
360+ .convert = w1_DS18S20_convert_temp,
361+ .precision = w1_DS18S20_precision,
362+ .eeprom = w1_therm_eeprom
363+ },
364+ {
365+ .f = &w1_therm_family_DS1822,
366+ .convert = w1_DS18B20_convert_temp,
367+ .precision = w1_DS18S20_precision,
368+ .eeprom = w1_therm_eeprom
369+ },
370+ {
371+ .f = &w1_therm_family_DS18B20,
372+ .convert = w1_DS18B20_convert_temp,
373+ .precision = w1_DS18B20_precision,
374+ .eeprom = w1_therm_eeprom
375+ },
376+ {
377+ .f = &w1_therm_family_DS28EA00,
378+ .convert = w1_DS18B20_convert_temp,
379+ .precision = w1_DS18S20_precision,
380+ .eeprom = w1_therm_eeprom
381+ },
382+ {
383+ .f = &w1_therm_family_DS1825,
384+ .convert = w1_DS18B20_convert_temp,
385+ .precision = w1_DS18S20_precision,
386+ .eeprom = w1_therm_eeprom
387+ }
388+};
389+
390+/* Helpers Functions */
391+
392+/**
393+ * w1_convert_temp() - temperature conversion binding function
394+ * @rom: data read from device RAM (8 data bytes + 1 CRC byte)
395+ * @fid: device family id
396+ *
397+ * The function call the temperature computation function according to
398+ * device family.
399+ *
400+ * Return: value in millidegrees Celsius.
401+ */
402 static inline int w1_convert_temp(u8 rom[9], u8 fid)
403 {
404 int i;
405@@ -445,31 +434,32 @@ static inline int w1_convert_temp(u8 rom
406 return 0;
407 }
408
409-static ssize_t w1_slave_store(struct device *device,
410- struct device_attribute *attr, const char *buf,
411- size_t size)
412+/* Interface Functions */
413+
414+static int w1_therm_add_slave(struct w1_slave *sl)
415 {
416- int val, ret;
417- struct w1_slave *sl = dev_to_w1_slave(device);
418- int i;
419+ sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
420+ GFP_KERNEL);
421+ if (!sl->family_data)
422+ return -ENOMEM;
423+ atomic_set(THERM_REFCNT(sl->family_data), 1);
424+ return 0;
425+}
426
427- ret = kstrtoint(buf, 0, &val);
428- if (ret)
429- return ret;
430+static void w1_therm_remove_slave(struct w1_slave *sl)
431+{
432+ int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
433
434- for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
435- if (w1_therm_families[i].f->fid == sl->family->fid) {
436- /* zero value indicates to write current configuration to eeprom */
437- if (val == 0)
438- ret = w1_therm_families[i].eeprom(device);
439- else
440- ret = w1_therm_families[i].precision(device, val);
441- break;
442- }
443+ while (refcnt) {
444+ msleep(1000);
445+ refcnt = atomic_read(THERM_REFCNT(sl->family_data));
446 }
447- return ret ? : size;
448+ kfree(sl->family_data);
449+ sl->family_data = NULL;
450 }
451
452+/* Hardware Functions */
453+
454 static ssize_t read_therm(struct device *device,
455 struct w1_slave *sl, struct therm_info *info)
456 {
457@@ -564,6 +554,81 @@ error:
458 return ret;
459 }
460
461+static inline int w1_therm_eeprom(struct device *device)
462+{
463+ struct w1_slave *sl = dev_to_w1_slave(device);
464+ struct w1_master *dev = sl->master;
465+ u8 rom[9], external_power;
466+ int ret, max_trying = 10;
467+ u8 *family_data = sl->family_data;
468+
469+ if (!sl->family_data) {
470+ ret = -ENODEV;
471+ goto error;
472+ }
473+
474+ /* prevent the slave from going away in sleep */
475+ atomic_inc(THERM_REFCNT(family_data));
476+
477+ ret = mutex_lock_interruptible(&dev->bus_mutex);
478+ if (ret != 0)
479+ goto dec_refcnt;
480+
481+ memset(rom, 0, sizeof(rom));
482+
483+ while (max_trying--) {
484+ if (!w1_reset_select_slave(sl)) {
485+ unsigned int tm = 10;
486+ unsigned long sleep_rem;
487+
488+ /* check if in parasite mode */
489+ w1_write_8(dev, W1_READ_PSUPPLY);
490+ external_power = w1_read_8(dev);
491+
492+ if (w1_reset_select_slave(sl))
493+ continue;
494+
495+ /* 10ms strong pullup/delay after the copy command */
496+ if (w1_strong_pullup == 2 ||
497+ (!external_power && w1_strong_pullup))
498+ w1_next_pullup(dev, tm);
499+
500+ w1_write_8(dev, W1_COPY_SCRATCHPAD);
501+
502+ if (external_power) {
503+ mutex_unlock(&dev->bus_mutex);
504+
505+ sleep_rem = msleep_interruptible(tm);
506+ if (sleep_rem != 0) {
507+ ret = -EINTR;
508+ goto dec_refcnt;
509+ }
510+
511+ ret = mutex_lock_interruptible(&dev->bus_mutex);
512+ if (ret != 0)
513+ goto dec_refcnt;
514+ } else if (!w1_strong_pullup) {
515+ sleep_rem = msleep_interruptible(tm);
516+ if (sleep_rem != 0) {
517+ ret = -EINTR;
518+ goto mt_unlock;
519+ }
520+ }
521+
522+ break;
523+ }
524+ }
525+
526+mt_unlock:
527+ mutex_unlock(&dev->bus_mutex);
528+dec_refcnt:
529+ atomic_dec(THERM_REFCNT(family_data));
530+error:
531+ return ret;
532+}
533+
534+/* Sysfs Interface definition */
535+
536 static ssize_t w1_slave_show(struct device *device,
537 struct device_attribute *attr, char *buf)
538 {
539@@ -597,6 +662,32 @@ static ssize_t w1_slave_show(struct devi
540 return ret;
541 }
542
543+static ssize_t w1_slave_store(struct device *device,
544+ struct device_attribute *attr, const char *buf,
545+ size_t size)
546+{
547+ int val, ret;
548+ struct w1_slave *sl = dev_to_w1_slave(device);
549+ int i;
550+
551+ ret = kstrtoint(buf, 0, &val);
552+ if (ret)
553+ return ret;
554+
555+ for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
556+ if (w1_therm_families[i].f->fid == sl->family->fid) {
557+ /* zero value indicates to write current configuration to eeprom */
558+ if (val == 0)
559+ ret = w1_therm_families[i].eeprom(device);
560+ else
561+ ret = w1_therm_families[i].precision(device,
562+ val);
563+ break;
564+ }
565+ }
566+ return ret ? : size;
567+}
568+
569 #if IS_REACHABLE(CONFIG_HWMON)
570 static int w1_read_temp(struct device *device, u32 attr, int channel,
571 long *val)
572@@ -666,7 +757,7 @@ static ssize_t w1_seq_show(struct device
573 if (ack != W1_42_SUCCESS_CONFIRM_BYTE)
574 goto error;
575
576- /* In case the bus fails to send 0xFF, limit*/
577+ /* In case the bus fails to send 0xFF, limit */
578 for (i = 0; i <= 64; i++) {
579 if (w1_reset_bus(sl->master))
580 goto error;