b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From 7c49e87acd0412ff1fb2490c4ac6fcb5471afd9b Mon Sep 17 00:00:00 2001 |
| 2 | From: Akira Shimahara <akira215corp@gmail.com> |
| 3 | Date: Mon, 11 May 2020 22:35:35 +0200 |
| 4 | Subject: [PATCH] w1_therm: adding code comments and code reordering |
| 5 | |
| 6 | commit 92b8d2724464bc1d2e735a84c0da5741dce33485 upstream. |
| 7 | |
| 8 | Adding code comments to split code in dedicated parts. After the global |
| 9 | declarations (defines, macros and function declarations), code is organized |
| 10 | as follow : |
| 11 | - Device and family dependent structures and functions |
| 12 | - Interfaces functions |
| 13 | - Helpers functions |
| 14 | - Hardware functions |
| 15 | - Sysfs interface functions |
| 16 | |
| 17 | Signed-off-by: Akira Shimahara <akira215corp@gmail.com> |
| 18 | Link: https://lore.kernel.org/r/20200511203535.409599-1-akira215corp@gmail.com |
| 19 | Signed-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; |