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