bcm27xx: import latest patches from the RPi foundation
[openwrt/staging/ynezz.git] / target / linux / bcm27xx / patches-5.4 / 950-0770-w1_therm-adding-eeprom-sysfs-entry.patch
1 From 855a8d82506c7c2428e13beebe8dbf7739ea6176 Mon Sep 17 00:00:00 2001
2 From: Akira Shimahara <akira215corp@gmail.com>
3 Date: Mon, 11 May 2020 22:37:25 +0200
4 Subject: [PATCH] w1_therm: adding eeprom sysfs entry
5
6 commit 45d457a4cf24455eefd076a01a3d86414fc2ff1e upstream.
7
8 The driver implement 2 hardware functions to access device RAM:
9 * copy_scratchpad
10 * recall_scratchpad
11 They act according to device specifications.
12
13 As EEPROM operations are not device dependent (all w1_therm can perform
14 EEPROM read/write operation following the same protocol), it is removed
15 from device families structures.
16
17 Updating Documentation/ABI/testing/sysfs-driver-w1_therm accordingly.
18
19 Signed-off-by: Akira Shimahara <akira215corp@gmail.com>
20 Link: https://lore.kernel.org/r/20200511203725.410844-1-akira215corp@gmail.com
21 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
22 ---
23 .../ABI/testing/sysfs-driver-w1_therm | 14 ++
24 drivers/w1/slaves/w1_therm.c | 175 ++++++++++++------
25 2 files changed, 132 insertions(+), 57 deletions(-)
26
27 --- a/Documentation/ABI/testing/sysfs-driver-w1_therm
28 +++ b/Documentation/ABI/testing/sysfs-driver-w1_therm
29 @@ -1,3 +1,17 @@
30 +What: /sys/bus/w1/devices/.../eeprom
31 +Date: May 2020
32 +Contact: Akira Shimahara <akira215corp@gmail.com>
33 +Description:
34 + (WO) writing that file will either trigger a save of the
35 + device data to its embedded EEPROM, either restore data
36 + embedded in device EEPROM. Be aware that devices support
37 + limited EEPROM writing cycles (typical 50k)
38 + * 'save': save device RAM to EEPROM
39 + * 'restore': restore EEPROM data in device RAM
40 +Users: any user space application which wants to communicate with
41 + w1_term device
42 +
43 +
44 What: /sys/bus/w1/devices/.../ext_power
45 Date: May 2020
46 Contact: Akira Shimahara <akira215corp@gmail.com>
47 --- a/drivers/w1/slaves/w1_therm.c
48 +++ b/drivers/w1/slaves/w1_therm.c
49 @@ -43,12 +43,21 @@
50 static int w1_strong_pullup = 1;
51 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
52
53 +/* This command should be in public header w1.h but is not */
54 +#define W1_RECALL_EEPROM 0xB8
55 +
56 /* Nb of try for an operation */
57 #define W1_THERM_MAX_TRY 5
58
59 /* ms delay to retry bus mutex */
60 #define W1_THERM_RETRY_DELAY 20
61
62 +/* delay in ms to write in EEPROM */
63 +#define W1_THERM_EEPROM_WRITE_DELAY 10
64 +
65 +#define EEPROM_CMD_WRITE "save" /* cmd for write eeprom sysfs */
66 +#define EEPROM_CMD_READ "restore" /* cmd for read eeprom sysfs */
67 +
68 /* Helpers Macros */
69
70 /*
71 @@ -86,7 +95,6 @@ module_param_named(strong_pullup, w1_str
72 * @convert: pointer to the device conversion function
73 * @set_resolution: pointer to the device set_resolution function
74 * @get_resolution: pointer to the device get_resolution function
75 - * @eeprom: pointer to eeprom function
76 */
77 struct w1_therm_family_converter {
78 u8 broken;
79 @@ -95,7 +103,6 @@ struct w1_therm_family_converter {
80 int (*convert)(u8 rom[9]);
81 int (*set_resolution)(struct w1_slave *sl, int val);
82 int (*get_resolution)(struct w1_slave *sl);
83 - int (*eeprom)(struct device *device);
84 };
85
86 /**
87 @@ -166,6 +173,22 @@ static int read_scratchpad(struct w1_sla
88 static int write_scratchpad(struct w1_slave *sl, const u8 *data, u8 nb_bytes);
89
90 /**
91 + * copy_scratchpad() - Copy the content of scratchpad in device EEPROM
92 + * @sl: slave involved
93 + *
94 + * Return: 0 if success, -kernel error code otherwise
95 + */
96 +static int copy_scratchpad(struct w1_slave *sl);
97 +
98 +/**
99 + * recall_eeprom() - Restore EEPROM data to device RAM
100 + * @sl: slave involved
101 + *
102 + * Return: 0 if success, -kernel error code otherwise
103 + */
104 +static int recall_eeprom(struct w1_slave *sl);
105 +
106 +/**
107 * read_powermode() - Query the power mode of the slave
108 * @sl: slave to retrieve the power mode
109 *
110 @@ -199,12 +222,16 @@ static ssize_t resolution_show(struct de
111 static ssize_t resolution_store(struct device *device,
112 struct device_attribute *attr, const char *buf, size_t size);
113
114 +static ssize_t eeprom_store(struct device *device,
115 + struct device_attribute *attr, const char *buf, size_t size);
116 +
117 /* Attributes declarations */
118
119 static DEVICE_ATTR_RW(w1_slave);
120 static DEVICE_ATTR_RO(w1_seq);
121 static DEVICE_ATTR_RO(ext_power);
122 static DEVICE_ATTR_RW(resolution);
123 +static DEVICE_ATTR_WO(eeprom);
124
125 /* Interface Functions declaration */
126
127 @@ -234,12 +261,14 @@ static struct attribute *w1_therm_attrs[
128 &dev_attr_w1_slave.attr,
129 &dev_attr_ext_power.attr,
130 &dev_attr_resolution.attr,
131 + &dev_attr_eeprom.attr,
132 NULL,
133 };
134
135 static struct attribute *w1_ds18s20_attrs[] = {
136 &dev_attr_w1_slave.attr,
137 &dev_attr_ext_power.attr,
138 + &dev_attr_eeprom.attr,
139 NULL,
140 };
141
142 @@ -248,6 +277,7 @@ static struct attribute *w1_ds28ea00_att
143 &dev_attr_w1_seq.attr,
144 &dev_attr_ext_power.attr,
145 &dev_attr_resolution.attr,
146 + &dev_attr_eeprom.attr,
147 NULL,
148 };
149
150 @@ -359,9 +389,6 @@ static struct w1_family w1_therm_family_
151
152 /* Device dependent func */
153
154 -/* write configuration to eeprom */
155 -static inline int w1_therm_eeprom(struct device *device);
156 -
157 static inline int w1_DS18B20_write_data(struct w1_slave *sl,
158 const u8 *data)
159 {
160 @@ -477,35 +504,30 @@ static struct w1_therm_family_converter
161 .convert = w1_DS18S20_convert_temp,
162 .set_resolution = NULL, /* no config register */
163 .get_resolution = NULL, /* no config register */
164 - .eeprom = w1_therm_eeprom
165 },
166 {
167 .f = &w1_therm_family_DS1822,
168 .convert = w1_DS18B20_convert_temp,
169 .set_resolution = w1_DS18B20_set_resolution,
170 .get_resolution = w1_DS18B20_get_resolution,
171 - .eeprom = w1_therm_eeprom
172 },
173 {
174 .f = &w1_therm_family_DS18B20,
175 .convert = w1_DS18B20_convert_temp,
176 .set_resolution = w1_DS18B20_set_resolution,
177 .get_resolution = w1_DS18B20_get_resolution,
178 - .eeprom = w1_therm_eeprom
179 },
180 {
181 .f = &w1_therm_family_DS28EA00,
182 .convert = w1_DS18B20_convert_temp,
183 .set_resolution = w1_DS18B20_set_resolution,
184 .get_resolution = w1_DS18B20_get_resolution,
185 - .eeprom = w1_therm_eeprom
186 },
187 {
188 .f = &w1_therm_family_DS1825,
189 .convert = w1_DS18B20_convert_temp,
190 .set_resolution = w1_DS18B20_set_resolution,
191 .get_resolution = w1_DS18B20_get_resolution,
192 - .eeprom = w1_therm_eeprom
193 }
194 };
195
196 @@ -838,75 +860,94 @@ error:
197 return ret;
198 }
199
200 -static inline int w1_therm_eeprom(struct device *device)
201 +static int copy_scratchpad(struct w1_slave *sl)
202 {
203 - struct w1_slave *sl = dev_to_w1_slave(device);
204 - struct w1_master *dev = sl->master;
205 - u8 rom[9], external_power;
206 - int ret, max_trying = 10;
207 - u8 *family_data = sl->family_data;
208 + struct w1_master *dev_master = sl->master;
209 + int max_trying = W1_THERM_MAX_TRY;
210 + int t_write, ret = -ENODEV;
211 + bool strong_pullup;
212
213 - if (!sl->family_data) {
214 - ret = -ENODEV;
215 + if (!sl->family_data)
216 goto error;
217 - }
218 +
219 + t_write = W1_THERM_EEPROM_WRITE_DELAY;
220 + strong_pullup = (w1_strong_pullup == 2 ||
221 + (!SLAVE_POWERMODE(sl) &&
222 + w1_strong_pullup));
223
224 /* prevent the slave from going away in sleep */
225 - atomic_inc(THERM_REFCNT(family_data));
226 + atomic_inc(THERM_REFCNT(sl->family_data));
227
228 - ret = mutex_lock_interruptible(&dev->bus_mutex);
229 - if (ret != 0)
230 + if (!bus_mutex_lock(&dev_master->bus_mutex)) {
231 + ret = -EAGAIN; /* Didn't acquire the mutex */
232 goto dec_refcnt;
233 + }
234
235 - memset(rom, 0, sizeof(rom));
236 -
237 - while (max_trying--) {
238 + while (max_trying-- && ret) { /* ret should be 0 */
239 + /* safe version to select slave */
240 if (!reset_select_slave(sl)) {
241 - unsigned int tm = 10;
242 unsigned long sleep_rem;
243
244 - /* check if in parasite mode */
245 - w1_write_8(dev, W1_READ_PSUPPLY);
246 - external_power = w1_read_8(dev);
247 -
248 - if (reset_select_slave(sl))
249 - continue;
250 -
251 - /* 10ms strong pullup/delay after the copy command */
252 - if (w1_strong_pullup == 2 ||
253 - (!external_power && w1_strong_pullup))
254 - w1_next_pullup(dev, tm);
255 -
256 - w1_write_8(dev, W1_COPY_SCRATCHPAD);
257 -
258 - if (external_power) {
259 - mutex_unlock(&dev->bus_mutex);
260 + /* 10ms strong pullup (or delay) after the convert */
261 + if (strong_pullup)
262 + w1_next_pullup(dev_master, t_write);
263
264 - sleep_rem = msleep_interruptible(tm);
265 - if (sleep_rem != 0) {
266 - ret = -EINTR;
267 - goto dec_refcnt;
268 - }
269 + w1_write_8(dev_master, W1_COPY_SCRATCHPAD);
270
271 - ret = mutex_lock_interruptible(&dev->bus_mutex);
272 - if (ret != 0)
273 - goto dec_refcnt;
274 - } else if (!w1_strong_pullup) {
275 - sleep_rem = msleep_interruptible(tm);
276 + if (strong_pullup) {
277 + sleep_rem = msleep_interruptible(t_write);
278 if (sleep_rem != 0) {
279 ret = -EINTR;
280 goto mt_unlock;
281 }
282 }
283 -
284 - break;
285 + ret = 0;
286 }
287 +
288 }
289
290 mt_unlock:
291 - mutex_unlock(&dev->bus_mutex);
292 + mutex_unlock(&dev_master->bus_mutex);
293 dec_refcnt:
294 - atomic_dec(THERM_REFCNT(family_data));
295 + atomic_dec(THERM_REFCNT(sl->family_data));
296 +error:
297 + return ret;
298 +}
299 +
300 +static int recall_eeprom(struct w1_slave *sl)
301 +{
302 + struct w1_master *dev_master = sl->master;
303 + int max_trying = W1_THERM_MAX_TRY;
304 + int ret = -ENODEV;
305 +
306 + if (!sl->family_data)
307 + goto error;
308 +
309 + /* prevent the slave from going away in sleep */
310 + atomic_inc(THERM_REFCNT(sl->family_data));
311 +
312 + if (!bus_mutex_lock(&dev_master->bus_mutex)) {
313 + ret = -EAGAIN; /* Didn't acquire the mutex */
314 + goto dec_refcnt;
315 + }
316 +
317 + while (max_trying-- && ret) { /* ret should be 0 */
318 + /* safe version to select slave */
319 + if (!reset_select_slave(sl)) {
320 +
321 + w1_write_8(dev_master, W1_RECALL_EEPROM);
322 +
323 + ret = 1; /* Slave will pull line to 0 */
324 + while (ret)
325 + ret = 1 - w1_touch_bit(dev_master, 1);
326 + }
327 +
328 + }
329 +
330 + mutex_unlock(&dev_master->bus_mutex);
331 +
332 +dec_refcnt:
333 + atomic_dec(THERM_REFCNT(sl->family_data));
334 error:
335 return ret;
336 }
337 @@ -1006,7 +1047,7 @@ static ssize_t w1_slave_store(struct dev
338 }
339
340 if (val == 0) /* val=0 : trigger a EEPROM save */
341 - ret = SLAVE_SPECIFIC_FUNC(sl)->eeprom(device);
342 + ret = copy_scratchpad(sl);
343 else {
344 if (SLAVE_SPECIFIC_FUNC(sl)->set_resolution)
345 ret = SLAVE_SPECIFIC_FUNC(sl)->set_resolution(sl, val);
346 @@ -1104,6 +1145,26 @@ static ssize_t resolution_store(struct d
347
348 return size;
349 }
350 +
351 +static ssize_t eeprom_store(struct device *device,
352 + struct device_attribute *attr, const char *buf, size_t size)
353 +{
354 + struct w1_slave *sl = dev_to_w1_slave(device);
355 + int ret = -EINVAL; /* Invalid argument */
356 +
357 + if (size == sizeof(EEPROM_CMD_WRITE)) {
358 + if (!strncmp(buf, EEPROM_CMD_WRITE, sizeof(EEPROM_CMD_WRITE)-1))
359 + ret = copy_scratchpad(sl);
360 + } else if (size == sizeof(EEPROM_CMD_READ)) {
361 + if (!strncmp(buf, EEPROM_CMD_READ, sizeof(EEPROM_CMD_READ)-1))
362 + ret = recall_eeprom(sl);
363 + }
364 +
365 + if (ret)
366 + dev_info(device, "%s: error in process %d\n", __func__, ret);
367 +
368 + return size;
369 +}
370
371 #if IS_REACHABLE(CONFIG_HWMON)
372 static int w1_read_temp(struct device *device, u32 attr, int channel,