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