bcm27xx: import latest patches from the RPi foundation
[openwrt/staging/ynezz.git] / target / linux / bcm27xx / patches-5.4 / 950-0769-w1_therm-adding-resolution-sysfs-entry.patch
1 From feffc2efed02adda00c6c5480292db012663e6e8 Mon Sep 17 00:00:00 2001
2 From: Akira Shimahara <akira215corp@gmail.com>
3 Date: Mon, 11 May 2020 22:37:08 +0200
4 Subject: [PATCH] w1_therm: adding resolution sysfs entry
5
6 commit 308bdb94de0c1abe7eac5193f58638b8aeaddf4b upstream.
7
8 Adding resolution sysfs entry (RW) to get or set the device resolution
9 Write values are managed as follow:
10 * '9..12': resolution to set in bit
11 * Anything else: do nothing
12 Read values are :
13 * '9..12': device resolution in bit
14 * '-xx': xx is kernel error when reading the resolution
15
16 Only supported devices will show the sysfs entry. A new family has been
17 created for DS18S20 devices as they do not implement resolution feature.
18
19 The resolution of each device is check when the device is
20 discover by the bus master, in 'w1_therm_add_slave(struct w1_slave *)'.
21 The status is stored in the device structure w1_therm_family_data so
22 that the driver always knows the resolution of each device, which could
23 be used later to determine the required conversion duration (resolution
24 dependent).
25
26 The resolution is re evaluate each time a user read or write the sysfs
27 entry.
28
29 To avoid looping through the w1_therm_families at run time, the pointer
30 'specific_functions' is set up to the correct 'w1_therm_family_converter'
31 when the slave is added (which mean when it is discovered by the master).
32 This initialization is done by a helper function
33 'device_family(struct w1_slave *sl)', and a dedicated macro
34 'SLAVE_SPECIFIC_FUNC(sl)' allow the access to the specific function of the
35 slave device.
36
37 'read_scratchpad' and 'write_scratchpad' are the hardware functions to
38 access the device RAM, as per protocol specification.
39
40 It cancel the former 'precision' functions, which was only set and never
41 read (so not stored in the device struct).
42
43 Updating Documentation/ABI/testing/sysfs-driver-w1_therm accordingly.
44
45 Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
46 Link: https://lore.kernel.org/r/20200511203708.410649-1-akira215corp@gmail.com
47 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
48 ---
49 .../ABI/testing/sysfs-driver-w1_therm | 17 +
50 drivers/w1/slaves/w1_therm.c | 442 ++++++++++++++----
51 2 files changed, 361 insertions(+), 98 deletions(-)
52
53 --- a/Documentation/ABI/testing/sysfs-driver-w1_therm
54 +++ b/Documentation/ABI/testing/sysfs-driver-w1_therm
55 @@ -10,6 +10,23 @@ Users: any user space application which
56 w1_term device
57
58
59 +What: /sys/bus/w1/devices/.../resolution
60 +Date: May 2020
61 +Contact: Akira Shimahara <akira215corp@gmail.com>
62 +Description:
63 + (RW) get or set the device resolution (on supported devices,
64 + if not, this entry is not present). Note that the resolution
65 + will be changed only in device RAM, so it will be cleared when
66 + power is lost. Trigger a 'save' to EEPROM command to keep
67 + values after power-on. Read or write are :
68 + * '9..12': device resolution in bit
69 + or resolution to set in bit
70 + * '-xx': xx is kernel error when reading the resolution
71 + * Anything else: do nothing
72 +Users: any user space application which wants to communicate with
73 + w1_term device
74 +
75 +
76 What: /sys/bus/w1/devices/.../w1_slave
77 Date: May 2020
78 Contact: Akira Shimahara <akira215corp@gmail.com>
79 --- a/drivers/w1/slaves/w1_therm.c
80 +++ b/drivers/w1/slaves/w1_therm.c
81 @@ -52,12 +52,26 @@ module_param_named(strong_pullup, w1_str
82 /* Helpers Macros */
83
84 /*
85 + * return a pointer on the slave w1_therm_family_converter struct:
86 + * always test family data existence before using this macro
87 + */
88 +#define SLAVE_SPECIFIC_FUNC(sl) \
89 + (((struct w1_therm_family_data *)(sl->family_data))->specific_functions)
90 +
91 +/*
92 * return the power mode of the sl slave : 1-ext, 0-parasite, <0 unknown
93 * always test family data existence before using this macro
94 */
95 #define SLAVE_POWERMODE(sl) \
96 (((struct w1_therm_family_data *)(sl->family_data))->external_powered)
97
98 +/*
99 + * return the resolution in bit of the sl slave : <0 unknown
100 + * always test family data existence before using this macro
101 + */
102 +#define SLAVE_RESOLUTION(sl) \
103 + (((struct w1_therm_family_data *)(sl->family_data))->resolution)
104 +
105 /* return the address of the refcnt in the family data */
106 #define THERM_REFCNT(family_data) \
107 (&((struct w1_therm_family_data *)family_data)->refcnt)
108 @@ -70,7 +84,8 @@ module_param_named(strong_pullup, w1_str
109 * @reserved: not used here
110 * @f: pointer to the device binding structure
111 * @convert: pointer to the device conversion function
112 - * @precision: pointer to the device precision function
113 + * @set_resolution: pointer to the device set_resolution function
114 + * @get_resolution: pointer to the device get_resolution function
115 * @eeprom: pointer to eeprom function
116 */
117 struct w1_therm_family_converter {
118 @@ -78,7 +93,8 @@ struct w1_therm_family_converter {
119 u16 reserved;
120 struct w1_family *f;
121 int (*convert)(u8 rom[9]);
122 - int (*precision)(struct device *device, int val);
123 + int (*set_resolution)(struct w1_slave *sl, int val);
124 + int (*get_resolution)(struct w1_slave *sl);
125 int (*eeprom)(struct device *device);
126 };
127
128 @@ -89,11 +105,15 @@ struct w1_therm_family_converter {
129 * @external_powered: 1 device powered externally,
130 * 0 device parasite powered,
131 * -x error or undefined
132 + * @resolution: current device resolution
133 + * @specific_functions: pointer to struct of device specific function
134 */
135 struct w1_therm_family_data {
136 uint8_t rom[9];
137 atomic_t refcnt;
138 int external_powered;
139 + int resolution;
140 + struct w1_therm_family_converter *specific_functions;
141 };
142
143 /**
144 @@ -127,6 +147,25 @@ struct therm_info {
145 static int reset_select_slave(struct w1_slave *sl);
146
147 /**
148 + * read_scratchpad() - read the data in device RAM
149 + * @sl: pointer to the slave to read
150 + * @info: pointer to a structure to store the read results
151 + *
152 + * Return: 0 if success, -kernel error code otherwise
153 + */
154 +static int read_scratchpad(struct w1_slave *sl, struct therm_info *info);
155 +
156 +/**
157 + * write_scratchpad() - write nb_bytes in the device RAM
158 + * @sl: pointer to the slave to write in
159 + * @data: pointer to an array of 3 bytes, as 3 bytes MUST be written
160 + * @nb_bytes: number of bytes to be written (2 for DS18S20, 3 otherwise)
161 + *
162 + * Return: 0 if success, -kernel error code otherwise
163 + */
164 +static int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes);
165 +
166 +/**
167 * read_powermode() - Query the power mode of the slave
168 * @sl: slave to retrieve the power mode
169 *
170 @@ -154,11 +193,18 @@ static ssize_t w1_seq_show(struct device
171 static ssize_t ext_power_show(struct device *device,
172 struct device_attribute *attr, char *buf);
173
174 +static ssize_t resolution_show(struct device *device,
175 + struct device_attribute *attr, char *buf);
176 +
177 +static ssize_t resolution_store(struct device *device,
178 + struct device_attribute *attr, const char *buf, size_t size);
179 +
180 /* Attributes declarations */
181
182 static DEVICE_ATTR_RW(w1_slave);
183 static DEVICE_ATTR_RO(w1_seq);
184 static DEVICE_ATTR_RO(ext_power);
185 +static DEVICE_ATTR_RW(resolution);
186
187 /* Interface Functions declaration */
188
189 @@ -187,6 +233,13 @@ static void w1_therm_remove_slave(struct
190 static struct attribute *w1_therm_attrs[] = {
191 &dev_attr_w1_slave.attr,
192 &dev_attr_ext_power.attr,
193 + &dev_attr_resolution.attr,
194 + NULL,
195 +};
196 +
197 +static struct attribute *w1_ds18s20_attrs[] = {
198 + &dev_attr_w1_slave.attr,
199 + &dev_attr_ext_power.attr,
200 NULL,
201 };
202
203 @@ -194,12 +247,14 @@ static struct attribute *w1_ds28ea00_att
204 &dev_attr_w1_slave.attr,
205 &dev_attr_w1_seq.attr,
206 &dev_attr_ext_power.attr,
207 + &dev_attr_resolution.attr,
208 NULL,
209 };
210
211 /* Attribute groups */
212
213 ATTRIBUTE_GROUPS(w1_therm);
214 +ATTRIBUTE_GROUPS(w1_ds18s20);
215 ATTRIBUTE_GROUPS(w1_ds28ea00);
216
217 #if IS_REACHABLE(CONFIG_HWMON)
218 @@ -261,6 +316,13 @@ static struct w1_family_ops w1_therm_fop
219 .chip_info = W1_CHIPINFO,
220 };
221
222 +static struct w1_family_ops w1_ds18s20_fops = {
223 + .add_slave = w1_therm_add_slave,
224 + .remove_slave = w1_therm_remove_slave,
225 + .groups = w1_ds18s20_groups,
226 + .chip_info = W1_CHIPINFO,
227 +};
228 +
229 static struct w1_family_ops w1_ds28ea00_fops = {
230 .add_slave = w1_therm_add_slave,
231 .remove_slave = w1_therm_remove_slave,
232 @@ -272,7 +334,7 @@ static struct w1_family_ops w1_ds28ea00_
233
234 static struct w1_family w1_therm_family_DS18S20 = {
235 .fid = W1_THERM_DS18S20,
236 - .fops = &w1_therm_fops,
237 + .fops = &w1_ds18s20_fops,
238 };
239
240 static struct w1_family w1_therm_family_DS18B20 = {
241 @@ -300,92 +362,67 @@ static struct w1_family w1_therm_family_
242 /* write configuration to eeprom */
243 static inline int w1_therm_eeprom(struct device *device);
244
245 -/* DS18S20 does not feature configuration register */
246 -static inline int w1_DS18S20_precision(struct device *device, int val)
247 +static inline int w1_DS18B20_write_data(struct w1_slave *sl,
248 + const u8 *data)
249 {
250 - return 0;
251 + return write_scratchpad(sl, data, 3);
252 }
253
254 -/* Set precision for conversion */
255 -static inline int w1_DS18B20_precision(struct device *device, int val)
256 +static inline int w1_DS18S20_write_data(struct w1_slave *sl,
257 + const u8 *data)
258 {
259 - struct w1_slave *sl = dev_to_w1_slave(device);
260 - struct w1_master *dev = sl->master;
261 - u8 rom[9], crc;
262 - int ret, max_trying = 10;
263 - u8 *family_data = sl->family_data;
264 - uint8_t precision_bits;
265 - uint8_t mask = 0x60;
266 -
267 - if (val > 12 || val < 9) {
268 - pr_warn("Unsupported precision\n");
269 - ret = -EINVAL;
270 - goto error;
271 - }
272 -
273 - if (!sl->family_data) {
274 - ret = -ENODEV;
275 - goto error;
276 - }
277 -
278 - /* prevent the slave from going away in sleep */
279 - atomic_inc(THERM_REFCNT(family_data));
280 + /* No config register */
281 + return write_scratchpad(sl, data, 2);
282 +}
283
284 - ret = mutex_lock_interruptible(&dev->bus_mutex);
285 - if (ret != 0)
286 - goto dec_refcnt;
287 +static inline int w1_DS18B20_set_resolution(struct w1_slave *sl, int val)
288 +{
289 + int ret = -ENODEV;
290 + u8 new_config_register[3]; /* array of data to be written */
291 + struct therm_info info;
292
293 - memset(rom, 0, sizeof(rom));
294 + /* resolution of DS18B20 is in the range [9..12] bits */
295 + if (val < 9 || val > 12)
296 + return -EINVAL;
297 +
298 + val -= 9; /* soustract 9 the lowest resolution in bit */
299 + val = (val << 5); /* shift to position bit 5 & bit 6 */
300 +
301 + /*
302 + * Read the scratchpad to change only the required bits
303 + * (bit5 & bit 6 from byte 4)
304 + */
305 + ret = read_scratchpad(sl, &info);
306 + if (!ret) {
307 + new_config_register[0] = info.rom[2];
308 + new_config_register[1] = info.rom[3];
309 + /* config register is byte 4 & mask 0b10011111*/
310 + new_config_register[2] = (info.rom[4] & 0x9F) |
311 + (u8) val;
312 + } else
313 + return ret;
314
315 - /* translate precision to bitmask (see datasheet page 9) */
316 - switch (val) {
317 - case 9:
318 - precision_bits = 0x00;
319 - break;
320 - case 10:
321 - precision_bits = 0x20;
322 - break;
323 - case 11:
324 - precision_bits = 0x40;
325 - break;
326 - case 12:
327 - default:
328 - precision_bits = 0x60;
329 - break;
330 - }
331 + /* Write data in the device RAM */
332 + ret = w1_DS18B20_write_data(sl, new_config_register);
333
334 - while (max_trying--) {
335 - crc = 0;
336 + return ret;
337 +}
338
339 - if (!reset_select_slave(sl)) {
340 - int count = 0;
341 +static inline int w1_DS18B20_get_resolution(struct w1_slave *sl)
342 +{
343 + int ret = -ENODEV;
344 + u8 config_register;
345 + struct therm_info info;
346
347 - /* read values to only alter precision bits */
348 - w1_write_8(dev, W1_READ_SCRATCHPAD);
349 - count = w1_read_block(dev, rom, 9);
350 - if (count != 9)
351 - dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count);
352 -
353 - crc = w1_calc_crc8(rom, 8);
354 - if (rom[8] == crc) {
355 - rom[4] = (rom[4] & ~mask) | (precision_bits & mask);
356 -
357 - if (!reset_select_slave(sl)) {
358 - w1_write_8(dev, W1_WRITE_SCRATCHPAD);
359 - w1_write_8(dev, rom[2]);
360 - w1_write_8(dev, rom[3]);
361 - w1_write_8(dev, rom[4]);
362 + ret = read_scratchpad(sl, &info);
363
364 - break;
365 - }
366 - }
367 - }
368 + if (!ret) {
369 + config_register = info.rom[4]; /* config register is byte 4 */
370 + config_register &= 0x60; /* 0b01100000 keep only bit 5 & 6 */
371 + config_register = (config_register >> 5); /* shift */
372 + config_register += 9; /* add 9 the lowest resolution in bit */
373 + ret = (int) config_register;
374 }
375 -
376 - mutex_unlock(&dev->bus_mutex);
377 -dec_refcnt:
378 - atomic_dec(THERM_REFCNT(family_data));
379 -error:
380 return ret;
381 }
382
383 @@ -438,31 +475,36 @@ static struct w1_therm_family_converter
384 {
385 .f = &w1_therm_family_DS18S20,
386 .convert = w1_DS18S20_convert_temp,
387 - .precision = w1_DS18S20_precision,
388 + .set_resolution = NULL, /* no config register */
389 + .get_resolution = NULL, /* no config register */
390 .eeprom = w1_therm_eeprom
391 },
392 {
393 .f = &w1_therm_family_DS1822,
394 .convert = w1_DS18B20_convert_temp,
395 - .precision = w1_DS18S20_precision,
396 + .set_resolution = w1_DS18B20_set_resolution,
397 + .get_resolution = w1_DS18B20_get_resolution,
398 .eeprom = w1_therm_eeprom
399 },
400 {
401 .f = &w1_therm_family_DS18B20,
402 .convert = w1_DS18B20_convert_temp,
403 - .precision = w1_DS18B20_precision,
404 + .set_resolution = w1_DS18B20_set_resolution,
405 + .get_resolution = w1_DS18B20_get_resolution,
406 .eeprom = w1_therm_eeprom
407 },
408 {
409 .f = &w1_therm_family_DS28EA00,
410 .convert = w1_DS18B20_convert_temp,
411 - .precision = w1_DS18S20_precision,
412 + .set_resolution = w1_DS18B20_set_resolution,
413 + .get_resolution = w1_DS18B20_get_resolution,
414 .eeprom = w1_therm_eeprom
415 },
416 {
417 .f = &w1_therm_family_DS1825,
418 .convert = w1_DS18B20_convert_temp,
419 - .precision = w1_DS18S20_precision,
420 + .set_resolution = w1_DS18B20_set_resolution,
421 + .get_resolution = w1_DS18B20_get_resolution,
422 .eeprom = w1_therm_eeprom
423 }
424 };
425 @@ -470,6 +512,26 @@ static struct w1_therm_family_converter
426 /* Helpers Functions */
427
428 /**
429 + * device_family() - Retrieve a pointer on &struct w1_therm_family_converter
430 + * @sl: slave to retrieve the device specific structure
431 + *
432 + * Return: pointer to the slaves's family converter, NULL if not known
433 + */
434 +static struct w1_therm_family_converter *device_family(struct w1_slave *sl)
435 +{
436 + struct w1_therm_family_converter *ret = NULL;
437 + int i;
438 +
439 + for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
440 + if (w1_therm_families[i].f->fid == sl->family->fid) {
441 + ret = &w1_therm_families[i];
442 + break;
443 + }
444 + }
445 + return ret;
446 +}
447 +
448 +/**
449 * bus_mutex_lock() - Acquire the mutex
450 * @lock: w1 bus mutex to acquire
451 *
452 @@ -522,6 +584,9 @@ static inline int w1_convert_temp(u8 rom
453
454 static int w1_therm_add_slave(struct w1_slave *sl)
455 {
456 + struct w1_therm_family_converter *sl_family_conv;
457 +
458 + /* Allocate memory */
459 sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
460 GFP_KERNEL);
461 if (!sl->family_data)
462 @@ -529,6 +594,15 @@ static int w1_therm_add_slave(struct w1_
463
464 atomic_set(THERM_REFCNT(sl->family_data), 1);
465
466 + /* Get a pointer to the device specific function struct */
467 + sl_family_conv = device_family(sl);
468 + if (!sl_family_conv) {
469 + kfree(sl->family_data);
470 + return -ENODEV;
471 + }
472 + /* save this pointer to the device structure */
473 + SLAVE_SPECIFIC_FUNC(sl) = sl_family_conv;
474 +
475 /* Getting the power mode of the device {external, parasite} */
476 SLAVE_POWERMODE(sl) = read_powermode(sl);
477
478 @@ -539,6 +613,18 @@ static int w1_therm_add_slave(struct w1_
479 __func__, SLAVE_POWERMODE(sl));
480 }
481
482 + /* Getting the resolution of the device */
483 + if (SLAVE_SPECIFIC_FUNC(sl)->get_resolution) {
484 + SLAVE_RESOLUTION(sl) =
485 + SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl);
486 + if (SLAVE_RESOLUTION(sl) < 0) {
487 + /* no error returned as device has been added */
488 + dev_warn(&sl->dev,
489 + "%s:Device has been added, but resolution may be corrupted. err=%d\n",
490 + __func__, SLAVE_RESOLUTION(sl));
491 + }
492 + }
493 +
494 return 0;
495 }
496
497 @@ -665,6 +751,93 @@ error:
498 return ret;
499 }
500
501 +static int read_scratchpad(struct w1_slave *sl, struct therm_info *info)
502 +{
503 + struct w1_master *dev_master = sl->master;
504 + int max_trying = W1_THERM_MAX_TRY;
505 + int ret = -ENODEV;
506 +
507 + info->verdict = 0;
508 +
509 + if (!sl->family_data)
510 + goto error;
511 +
512 + memset(info->rom, 0, sizeof(info->rom));
513 +
514 + /* prevent the slave from going away in sleep */
515 + atomic_inc(THERM_REFCNT(sl->family_data));
516 +
517 + if (!bus_mutex_lock(&dev_master->bus_mutex)) {
518 + ret = -EAGAIN; /* Didn't acquire the mutex */
519 + goto dec_refcnt;
520 + }
521 +
522 + while (max_trying-- && ret) { /* ret should be 0 */
523 + /* safe version to select slave */
524 + if (!reset_select_slave(sl)) {
525 + u8 nb_bytes_read;
526 +
527 + w1_write_8(dev_master, W1_READ_SCRATCHPAD);
528 +
529 + nb_bytes_read = w1_read_block(dev_master, info->rom, 9);
530 + if (nb_bytes_read != 9) {
531 + dev_warn(&sl->dev,
532 + "w1_read_block(): returned %u instead of 9.\n",
533 + nb_bytes_read);
534 + ret = -EIO;
535 + }
536 +
537 + info->crc = w1_calc_crc8(info->rom, 8);
538 +
539 + if (info->rom[8] == info->crc) {
540 + info->verdict = 1;
541 + ret = 0;
542 + } else
543 + ret = -EIO; /* CRC not checked */
544 + }
545 +
546 + }
547 + mutex_unlock(&dev_master->bus_mutex);
548 +
549 +dec_refcnt:
550 + atomic_dec(THERM_REFCNT(sl->family_data));
551 +error:
552 + return ret;
553 +}
554 +
555 +static int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes)
556 +{
557 + struct w1_master *dev_master = sl->master;
558 + int max_trying = W1_THERM_MAX_TRY;
559 + int ret = -ENODEV;
560 +
561 + if (!sl->family_data)
562 + goto error;
563 +
564 + /* prevent the slave from going away in sleep */
565 + atomic_inc(THERM_REFCNT(sl->family_data));
566 +
567 + if (!bus_mutex_lock(&dev_master->bus_mutex)) {
568 + ret = -EAGAIN; /* Didn't acquire the mutex */
569 + goto dec_refcnt;
570 + }
571 +
572 + while (max_trying-- && ret) { /* ret should be 0 */
573 + /* safe version to select slave */
574 + if (!reset_select_slave(sl)) {
575 + w1_write_8(dev_master, W1_WRITE_SCRATCHPAD);
576 + w1_write_block(dev_master, data, nb_bytes);
577 + ret = 0;
578 + }
579 + }
580 + mutex_unlock(&dev_master->bus_mutex);
581 +
582 +dec_refcnt:
583 + atomic_dec(THERM_REFCNT(sl->family_data));
584 +error:
585 + return ret;
586 +}
587 +
588 static inline int w1_therm_eeprom(struct device *device)
589 {
590 struct w1_slave *sl = dev_to_w1_slave(device);
591 @@ -815,26 +988,38 @@ static ssize_t w1_slave_store(struct dev
592 struct device_attribute *attr, const char *buf,
593 size_t size)
594 {
595 - int val, ret;
596 + int val, ret = 0;
597 struct w1_slave *sl = dev_to_w1_slave(device);
598 - int i;
599
600 - ret = kstrtoint(buf, 0, &val);
601 - if (ret)
602 - return ret;
603 + ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
604
605 - for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
606 - if (w1_therm_families[i].f->fid == sl->family->fid) {
607 - /* zero value indicates to write current configuration to eeprom */
608 - if (val == 0)
609 - ret = w1_therm_families[i].eeprom(device);
610 - else
611 - ret = w1_therm_families[i].precision(device,
612 - val);
613 - break;
614 - }
615 + if (ret) { /* conversion error */
616 + dev_info(device,
617 + "%s: conversion error. err= %d\n", __func__, ret);
618 + return size; /* return size to avoid call back again */
619 + }
620 +
621 + if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
622 + dev_info(device,
623 + "%s: Device not supported by the driver\n", __func__);
624 + return size; /* No device family */
625 + }
626 +
627 + if (val == 0) /* val=0 : trigger a EEPROM save */
628 + ret = SLAVE_SPECIFIC_FUNC(sl)->eeprom(device);
629 + else {
630 + if (SLAVE_SPECIFIC_FUNC(sl)->set_resolution)
631 + ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
632 }
633 - return ret ? : size;
634 +
635 + if (ret) {
636 + dev_info(device,
637 + "%s: writing error %d\n", __func__, ret);
638 + /* return size to avoid call back again */
639 + } else
640 + SLAVE_RESOLUTION(sl) = val;
641 +
642 + return size; /* always return size to avoid infinite calling */
643 }
644
645 static ssize_t ext_power_show(struct device *device,
646 @@ -859,6 +1044,67 @@ static ssize_t ext_power_show(struct dev
647 return sprintf(buf, "%d\n", SLAVE_POWERMODE(sl));
648 }
649
650 +static ssize_t resolution_show(struct device *device,
651 + struct device_attribute *attr, char *buf)
652 +{
653 + struct w1_slave *sl = dev_to_w1_slave(device);
654 +
655 + if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
656 + dev_info(device,
657 + "%s: Device not supported by the driver\n", __func__);
658 + return 0; /* No device family */
659 + }
660 +
661 + /* get the correct function depending on the device */
662 + SLAVE_RESOLUTION(sl) = SLAVE_SPECIFIC_FUNC(sl)->get_resolution(sl);
663 + if (SLAVE_RESOLUTION(sl) < 0) {
664 + dev_dbg(device,
665 + "%s: Resolution may be corrupted. err=%d\n",
666 + __func__, SLAVE_RESOLUTION(sl));
667 + }
668 +
669 + return sprintf(buf, "%d\n", SLAVE_RESOLUTION(sl));
670 +}
671 +
672 +static ssize_t resolution_store(struct device *device,
673 + struct device_attribute *attr, const char *buf, size_t size)
674 +{
675 + struct w1_slave *sl = dev_to_w1_slave(device);
676 + int val;
677 + int ret = 0;
678 +
679 + ret = kstrtoint(buf, 10, &val); /* converting user entry to int */
680 +
681 + if (ret) { /* conversion error */
682 + dev_info(device,
683 + "%s: conversion error. err= %d\n", __func__, ret);
684 + return size; /* return size to avoid call back again */
685 + }
686 +
687 + if ((!sl->family_data) || (!SLAVE_SPECIFIC_FUNC(sl))) {
688 + dev_info(device,
689 + "%s: Device not supported by the driver\n", __func__);
690 + return size; /* No device family */
691 + }
692 +
693 + /*
694 + * Don't deal with the val enterd by user,
695 + * only device knows what is correct or not
696 + */
697 +
698 + /* get the correct function depending on the device */
699 + ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
700 +
701 + if (ret) {
702 + dev_info(device,
703 + "%s: writing error %d\n", __func__, ret);
704 + /* return size to avoid call back again */
705 + } else
706 + SLAVE_RESOLUTION(sl) = val;
707 +
708 + return size;
709 +}
710 +
711 #if IS_REACHABLE(CONFIG_HWMON)
712 static int w1_read_temp(struct device *device, u32 attr, int channel,
713 long *val)