1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 *	w1_ds2408.c - w1 family 29 (DS2408) driver
4 *
5 * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com>
6 */
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/moduleparam.h>
11#include <linux/device.h>
12#include <linux/types.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15
16#include <linux/w1.h>
17
18#define W1_FAMILY_DS2408	0x29
19
20#define W1_F29_RETRIES		3
21
22#define W1_F29_REG_LOGIG_STATE             0x88 /* R */
23#define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */
24#define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */
25#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
26#define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */
27#define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */
28
29#define W1_F29_FUNC_READ_PIO_REGS          0xF0
30#define W1_F29_FUNC_CHANN_ACCESS_READ      0xF5
31#define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A
32/* also used to write the control/status reg (0x8D): */
33#define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC
34#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
35
36#define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA
37
38static int _read_reg(struct w1_slave *sl, u8 address, unsigned char *buf)
39{
40	u8 wrbuf[3];
41
42	dev_dbg(&sl->dev, "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
43		sl, (unsigned int)address, buf);
44
45	if (!buf)
46		return -EINVAL;
47
48	mutex_lock(&sl->master->bus_mutex);
49	dev_dbg(&sl->dev, "mutex locked");
50
51	if (w1_reset_select_slave(sl)) {
52		mutex_unlock(&sl->master->bus_mutex);
53		return -EIO;
54	}
55
56	wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
57	wrbuf[1] = address;
58	wrbuf[2] = 0;
59	w1_write_block(sl->master, wrbuf, 3);
60	*buf = w1_read_8(sl->master);
61
62	mutex_unlock(&sl->master->bus_mutex);
63	dev_dbg(&sl->dev, "mutex unlocked");
64	return 1;
65}
66
67static ssize_t state_read(struct file *filp, struct kobject *kobj,
68			  struct bin_attribute *bin_attr, char *buf, loff_t off,
69			  size_t count)
70{
71	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
72		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
73		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
74	if (count != 1 || off != 0)
75		return -EFAULT;
76	return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
77}
78
79static ssize_t output_read(struct file *filp, struct kobject *kobj,
80			   struct bin_attribute *bin_attr, char *buf,
81			   loff_t off, size_t count)
82{
83	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
84		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
85		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
86	if (count != 1 || off != 0)
87		return -EFAULT;
88	return _read_reg(kobj_to_w1_slave(kobj),
89					 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
90}
91
92static ssize_t activity_read(struct file *filp, struct kobject *kobj,
93			     struct bin_attribute *bin_attr, char *buf,
94			     loff_t off, size_t count)
95{
96	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
97		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
98		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
99	if (count != 1 || off != 0)
100		return -EFAULT;
101	return _read_reg(kobj_to_w1_slave(kobj),
102					 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
103}
104
105static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
106				     struct bin_attribute *bin_attr, char *buf,
107				     loff_t off, size_t count)
108{
109	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
110		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
111		bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
112	if (count != 1 || off != 0)
113		return -EFAULT;
114	return _read_reg(kobj_to_w1_slave(kobj),
115		W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
116}
117
118static ssize_t cond_search_polarity_read(struct file *filp,
119					 struct kobject *kobj,
120					 struct bin_attribute *bin_attr,
121					 char *buf, loff_t off, size_t count)
122{
123	if (count != 1 || off != 0)
124		return -EFAULT;
125	return _read_reg(kobj_to_w1_slave(kobj),
126		W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
127}
128
129static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
130				   struct bin_attribute *bin_attr, char *buf,
131				   loff_t off, size_t count)
132{
133	if (count != 1 || off != 0)
134		return -EFAULT;
135	return _read_reg(kobj_to_w1_slave(kobj),
136		W1_F29_REG_CONTROL_AND_STATUS, buf);
137}
138
139#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
140static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
141{
142	u8 w1_buf[3];
143
144	if (w1_reset_resume_command(sl->master))
145		return false;
146
147	w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
148	w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
149	w1_buf[2] = 0;
150
151	w1_write_block(sl->master, w1_buf, 3);
152
153	return (w1_read_8(sl->master) == expected);
154}
155#else
156static bool optional_read_back_valid(struct w1_slave *sl, u8 expected)
157{
158	return true;
159}
160#endif
161
162static ssize_t output_write(struct file *filp, struct kobject *kobj,
163			    struct bin_attribute *bin_attr, char *buf,
164			    loff_t off, size_t count)
165{
166	struct w1_slave *sl = kobj_to_w1_slave(kobj);
167	u8 w1_buf[3];
168	unsigned int retries = W1_F29_RETRIES;
169	ssize_t bytes_written = -EIO;
170
171	if (count != 1 || off != 0)
172		return -EFAULT;
173
174	dev_dbg(&sl->dev, "locking mutex for write_output");
175	mutex_lock(&sl->master->bus_mutex);
176	dev_dbg(&sl->dev, "mutex locked");
177
178	if (w1_reset_select_slave(sl))
179		goto out;
180
181	do {
182		w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
183		w1_buf[1] = *buf;
184		w1_buf[2] = ~(*buf);
185
186		w1_write_block(sl->master, w1_buf, 3);
187
188		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE &&
189		    optional_read_back_valid(sl, *buf)) {
190			bytes_written = 1;
191			goto out;
192		}
193
194		if (w1_reset_resume_command(sl->master))
195			goto out; /* unrecoverable error */
196		/* try again, the slave is ready for a command */
197	} while (--retries);
198
199out:
200	mutex_unlock(&sl->master->bus_mutex);
201
202	dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n",
203		(bytes_written > 0) ? "succeeded" : "error", retries);
204
205	return bytes_written;
206}
207
208
209/*
210 * Writing to the activity file resets the activity latches.
211 */
212static ssize_t activity_write(struct file *filp, struct kobject *kobj,
213			      struct bin_attribute *bin_attr, char *buf,
214			      loff_t off, size_t count)
215{
216	struct w1_slave *sl = kobj_to_w1_slave(kobj);
217	unsigned int retries = W1_F29_RETRIES;
218
219	if (count != 1 || off != 0)
220		return -EFAULT;
221
222	mutex_lock(&sl->master->bus_mutex);
223
224	if (w1_reset_select_slave(sl))
225		goto error;
226
227	while (retries--) {
228		w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
229		if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
230			mutex_unlock(&sl->master->bus_mutex);
231			return 1;
232		}
233		if (w1_reset_resume_command(sl->master))
234			goto error;
235	}
236
237error:
238	mutex_unlock(&sl->master->bus_mutex);
239	return -EIO;
240}
241
242static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
243				    struct bin_attribute *bin_attr, char *buf,
244				    loff_t off, size_t count)
245{
246	struct w1_slave *sl = kobj_to_w1_slave(kobj);
247	u8 w1_buf[4];
248	unsigned int retries = W1_F29_RETRIES;
249
250	if (count != 1 || off != 0)
251		return -EFAULT;
252
253	mutex_lock(&sl->master->bus_mutex);
254
255	if (w1_reset_select_slave(sl))
256		goto error;
257
258	while (retries--) {
259		w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
260		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
261		w1_buf[2] = 0;
262		w1_buf[3] = *buf;
263
264		w1_write_block(sl->master, w1_buf, 4);
265		if (w1_reset_resume_command(sl->master))
266			goto error;
267
268		w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
269		w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
270		w1_buf[2] = 0;
271
272		w1_write_block(sl->master, w1_buf, 3);
273		if (w1_read_8(sl->master) == *buf) {
274			/* success! */
275			mutex_unlock(&sl->master->bus_mutex);
276			return 1;
277		}
278	}
279error:
280	mutex_unlock(&sl->master->bus_mutex);
281
282	return -EIO;
283}
284
285/*
286 * This is a special sequence we must do to ensure the P0 output is not stuck
287 * in test mode. This is described in rev 2 of the ds2408's datasheet
288 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
289 * "APPLICATION INFORMATION/Power-up timing".
290 */
291static int w1_f29_disable_test_mode(struct w1_slave *sl)
292{
293	int res;
294	u8 magic[10] = {0x96, };
295	u64 rn = le64_to_cpu(*((u64 *)&sl->reg_num));
296
297	memcpy(&magic[1], &rn, 8);
298	magic[9] = 0x3C;
299
300	mutex_lock(&sl->master->bus_mutex);
301
302	res = w1_reset_bus(sl->master);
303	if (res)
304		goto out;
305	w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
306
307	res = w1_reset_bus(sl->master);
308out:
309	mutex_unlock(&sl->master->bus_mutex);
310	return res;
311}
312
313static BIN_ATTR_RO(state, 1);
314static BIN_ATTR_RW(output, 1);
315static BIN_ATTR_RW(activity, 1);
316static BIN_ATTR_RO(cond_search_mask, 1);
317static BIN_ATTR_RO(cond_search_polarity, 1);
318static BIN_ATTR_RW(status_control, 1);
319
320static struct bin_attribute *w1_f29_bin_attrs[] = {
321	&bin_attr_state,
322	&bin_attr_output,
323	&bin_attr_activity,
324	&bin_attr_cond_search_mask,
325	&bin_attr_cond_search_polarity,
326	&bin_attr_status_control,
327	NULL,
328};
329
330static const struct attribute_group w1_f29_group = {
331	.bin_attrs = w1_f29_bin_attrs,
332};
333
334static const struct attribute_group *w1_f29_groups[] = {
335	&w1_f29_group,
336	NULL,
337};
338
339static const struct w1_family_ops w1_f29_fops = {
340	.add_slave      = w1_f29_disable_test_mode,
341	.groups		= w1_f29_groups,
342};
343
344static struct w1_family w1_family_29 = {
345	.fid = W1_FAMILY_DS2408,
346	.fops = &w1_f29_fops,
347};
348module_w1_family(w1_family_29);
349
350MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
351MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
352MODULE_LICENSE("GPL");
353MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408));
354