1// SPDX-License-Identifier: GPL-2.0
2/*
3 * w1_ds250x.c - w1 family 09/0b/89/91 (DS250x) driver
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/moduleparam.h>
9#include <linux/device.h>
10#include <linux/types.h>
11#include <linux/delay.h>
12#include <linux/slab.h>
13#include <linux/crc16.h>
14
15#include <linux/w1.h>
16#include <linux/nvmem-provider.h>
17
18#define W1_DS2501_UNW_FAMILY    0x91
19#define W1_DS2501_SIZE          64
20
21#define W1_DS2502_FAMILY        0x09
22#define W1_DS2502_UNW_FAMILY    0x89
23#define W1_DS2502_SIZE          128
24
25#define W1_DS2505_FAMILY	0x0b
26#define W1_DS2505_SIZE		2048
27
28#define W1_PAGE_SIZE		32
29
30#define W1_EXT_READ_MEMORY	0xA5
31#define W1_READ_DATA_CRC        0xC3
32
33#define OFF2PG(off)	((off) / W1_PAGE_SIZE)
34
35#define CRC16_INIT		0
36#define CRC16_VALID		0xb001
37
38struct w1_eprom_data {
39	size_t size;
40	int (*read)(struct w1_slave *sl, int pageno);
41	u8 eprom[W1_DS2505_SIZE];
42	DECLARE_BITMAP(page_present, W1_DS2505_SIZE / W1_PAGE_SIZE);
43	char nvmem_name[64];
44};
45
46static int w1_ds2502_read_page(struct w1_slave *sl, int pageno)
47{
48	struct w1_eprom_data *data = sl->family_data;
49	int pgoff = pageno * W1_PAGE_SIZE;
50	int ret = -EIO;
51	u8 buf[3];
52	u8 crc8;
53
54	if (test_bit(pageno, data->page_present))
55		return 0; /* page already present */
56
57	mutex_lock(&sl->master->bus_mutex);
58
59	if (w1_reset_select_slave(sl))
60		goto err;
61
62	buf[0] = W1_READ_DATA_CRC;
63	buf[1] = pgoff & 0xff;
64	buf[2] = pgoff >> 8;
65	w1_write_block(sl->master, buf, 3);
66
67	crc8 = w1_read_8(sl->master);
68	if (w1_calc_crc8(buf, 3) != crc8)
69		goto err;
70
71	w1_read_block(sl->master, &data->eprom[pgoff], W1_PAGE_SIZE);
72
73	crc8 = w1_read_8(sl->master);
74	if (w1_calc_crc8(&data->eprom[pgoff], W1_PAGE_SIZE) != crc8)
75		goto err;
76
77	set_bit(pageno, data->page_present); /* mark page present */
78	ret = 0;
79err:
80	mutex_unlock(&sl->master->bus_mutex);
81	return ret;
82}
83
84static int w1_ds2505_read_page(struct w1_slave *sl, int pageno)
85{
86	struct w1_eprom_data *data = sl->family_data;
87	int redir_retries = 16;
88	int pgoff, epoff;
89	int ret = -EIO;
90	u8 buf[6];
91	u8 redir;
92	u16 crc;
93
94	if (test_bit(pageno, data->page_present))
95		return 0; /* page already present */
96
97	epoff = pgoff = pageno * W1_PAGE_SIZE;
98	mutex_lock(&sl->master->bus_mutex);
99
100retry:
101	if (w1_reset_select_slave(sl))
102		goto err;
103
104	buf[0] = W1_EXT_READ_MEMORY;
105	buf[1] = pgoff & 0xff;
106	buf[2] = pgoff >> 8;
107	w1_write_block(sl->master, buf, 3);
108	w1_read_block(sl->master, buf + 3, 3); /* redir, crc16 */
109	redir = buf[3];
110	crc = crc16(CRC16_INIT, buf, 6);
111
112	if (crc != CRC16_VALID)
113		goto err;
114
115
116	if (redir != 0xff) {
117		redir_retries--;
118		if (redir_retries < 0)
119			goto err;
120
121		pgoff = (redir ^ 0xff) * W1_PAGE_SIZE;
122		goto retry;
123	}
124
125	w1_read_block(sl->master, &data->eprom[epoff], W1_PAGE_SIZE);
126	w1_read_block(sl->master, buf, 2); /* crc16 */
127	crc = crc16(CRC16_INIT, &data->eprom[epoff], W1_PAGE_SIZE);
128	crc = crc16(crc, buf, 2);
129
130	if (crc != CRC16_VALID)
131		goto err;
132
133	set_bit(pageno, data->page_present);
134	ret = 0;
135err:
136	mutex_unlock(&sl->master->bus_mutex);
137	return ret;
138}
139
140static int w1_nvmem_read(void *priv, unsigned int off, void *buf, size_t count)
141{
142	struct w1_slave *sl = priv;
143	struct w1_eprom_data *data = sl->family_data;
144	size_t eprom_size = data->size;
145	int ret;
146	int i;
147
148	if (off > eprom_size)
149		return -EINVAL;
150
151	if ((off + count) > eprom_size)
152		count = eprom_size - off;
153
154	i = OFF2PG(off);
155	do {
156		ret = data->read(sl, i++);
157		if (ret < 0)
158			return ret;
159	} while (i < OFF2PG(off + count));
160
161	memcpy(buf, &data->eprom[off], count);
162	return 0;
163}
164
165static int w1_eprom_add_slave(struct w1_slave *sl)
166{
167	struct w1_eprom_data *data;
168	struct nvmem_device *nvmem;
169	struct nvmem_config nvmem_cfg = {
170		.dev = &sl->dev,
171		.add_legacy_fixed_of_cells = true,
172		.reg_read = w1_nvmem_read,
173		.type = NVMEM_TYPE_OTP,
174		.read_only = true,
175		.word_size = 1,
176		.priv = sl,
177		.id = -1
178	};
179
180	data = devm_kzalloc(&sl->dev, sizeof(struct w1_eprom_data), GFP_KERNEL);
181	if (!data)
182		return -ENOMEM;
183
184	sl->family_data = data;
185	switch (sl->family->fid) {
186	case W1_DS2501_UNW_FAMILY:
187		data->size = W1_DS2501_SIZE;
188		data->read = w1_ds2502_read_page;
189		break;
190	case W1_DS2502_FAMILY:
191	case W1_DS2502_UNW_FAMILY:
192		data->size = W1_DS2502_SIZE;
193		data->read = w1_ds2502_read_page;
194		break;
195	case W1_DS2505_FAMILY:
196		data->size = W1_DS2505_SIZE;
197		data->read = w1_ds2505_read_page;
198		break;
199	}
200
201	if (sl->master->bus_master->dev_id)
202		snprintf(data->nvmem_name, sizeof(data->nvmem_name),
203			 "%s-%02x-%012llx",
204			 sl->master->bus_master->dev_id, sl->reg_num.family,
205			 (unsigned long long)sl->reg_num.id);
206	else
207		snprintf(data->nvmem_name, sizeof(data->nvmem_name),
208			 "%02x-%012llx",
209			 sl->reg_num.family,
210			 (unsigned long long)sl->reg_num.id);
211
212	nvmem_cfg.name = data->nvmem_name;
213	nvmem_cfg.size = data->size;
214
215	nvmem = devm_nvmem_register(&sl->dev, &nvmem_cfg);
216	return PTR_ERR_OR_ZERO(nvmem);
217}
218
219static const struct w1_family_ops w1_eprom_fops = {
220	.add_slave	= w1_eprom_add_slave,
221};
222
223static struct w1_family w1_family_09 = {
224	.fid = W1_DS2502_FAMILY,
225	.fops = &w1_eprom_fops,
226};
227
228static struct w1_family w1_family_0b = {
229	.fid = W1_DS2505_FAMILY,
230	.fops = &w1_eprom_fops,
231};
232
233static struct w1_family w1_family_89 = {
234	.fid = W1_DS2502_UNW_FAMILY,
235	.fops = &w1_eprom_fops,
236};
237
238static struct w1_family w1_family_91 = {
239	.fid = W1_DS2501_UNW_FAMILY,
240	.fops = &w1_eprom_fops,
241};
242
243static int __init w1_ds250x_init(void)
244{
245	int err;
246
247	err = w1_register_family(&w1_family_09);
248	if (err)
249		return err;
250
251	err = w1_register_family(&w1_family_0b);
252	if (err)
253		goto err_0b;
254
255	err = w1_register_family(&w1_family_89);
256	if (err)
257		goto err_89;
258
259	err = w1_register_family(&w1_family_91);
260	if (err)
261		goto err_91;
262
263	return 0;
264
265err_91:
266	w1_unregister_family(&w1_family_89);
267err_89:
268	w1_unregister_family(&w1_family_0b);
269err_0b:
270	w1_unregister_family(&w1_family_09);
271	return err;
272}
273
274static void __exit w1_ds250x_exit(void)
275{
276	w1_unregister_family(&w1_family_09);
277	w1_unregister_family(&w1_family_0b);
278	w1_unregister_family(&w1_family_89);
279	w1_unregister_family(&w1_family_91);
280}
281
282module_init(w1_ds250x_init);
283module_exit(w1_ds250x_exit);
284
285MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfe@suse.de>");
286MODULE_DESCRIPTION("w1 family driver for DS250x Add Only Memory");
287MODULE_LICENSE("GPL");
288MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_FAMILY));
289MODULE_ALIAS("w1-family-" __stringify(W1_DS2505_FAMILY));
290MODULE_ALIAS("w1-family-" __stringify(W1_DS2501_UNW_FAMILY));
291MODULE_ALIAS("w1-family-" __stringify(W1_DS2502_UNW_FAMILY));
292