1 /* $NetBSD: at24cxx.c,v 1.41 2021/01/28 14:57:43 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2003 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: at24cxx.c,v 1.41 2021/01/28 14:57:43 thorpej Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/kernel.h>
45 #include <sys/fcntl.h>
46 #include <sys/uio.h>
47 #include <sys/conf.h>
48 #include <sys/proc.h>
49 #include <sys/event.h>
50
51 #include <sys/bus.h>
52
53 #include <dev/i2c/i2cvar.h>
54 #include <dev/i2c/at24cxxvar.h>
55
56 #include "ioconf.h"
57
58 /*
59 * AT24Cxx EEPROM I2C address:
60 * 101 0xxx
61 * (and others depending on the exact model) The bigger 8-bit parts
62 * decode multiple addresses. The bigger 16-bit parts do too (those
63 * larger than 512kb). Be sure to check the datasheet of your EEPROM
64 * because there's much variation between models.
65 */
66 #define AT24CXX_ADDRMASK 0x3f8
67 #define AT24CXX_ADDR 0x50
68
69 #define AT24CXX_WRITE_CYCLE_MS 10
70 #define AT24CXX_ADDR_HI(a) (((a) >> 8) & 0xff)
71 #define AT24CXX_ADDR_LO(a) ((a) & 0xff)
72
73 #include "seeprom.h"
74
75 #if NSEEPROM > 0
76
77 struct seeprom_softc {
78 device_t sc_dev;
79 i2c_tag_t sc_tag;
80 int sc_address;
81 int sc_size;
82 int sc_cmdlen;
83 int sc_open;
84 };
85
86 static int seeprom_match(device_t, cfdata_t, void *);
87 static void seeprom_attach(device_t, device_t, void *);
88
89 CFATTACH_DECL_NEW(seeprom, sizeof(struct seeprom_softc),
90 seeprom_match, seeprom_attach, NULL, NULL);
91
92 dev_type_open(seeprom_open);
93 dev_type_close(seeprom_close);
94 dev_type_read(seeprom_read);
95 dev_type_write(seeprom_write);
96
97 const struct cdevsw seeprom_cdevsw = {
98 .d_open = seeprom_open,
99 .d_close = seeprom_close,
100 .d_read = seeprom_read,
101 .d_write = seeprom_write,
102 .d_ioctl = noioctl,
103 .d_stop = nostop,
104 .d_tty = notty,
105 .d_poll = nopoll,
106 .d_mmap = nommap,
107 .d_kqfilter = nokqfilter,
108 .d_discard = nodiscard,
109 .d_flag = D_OTHER
110 };
111
112 static int seeprom_wait_idle(struct seeprom_softc *);
113
114 static const struct device_compatible_entry compat_data[] = {
115 { .compat = "i2c-at24c01", .value = 128 },
116 { .compat = "i2c-at24c02", .value = 256 },
117 { .compat = "i2c-at24c04", .value = 512 },
118 { .compat = "i2c-at24c08", .value = 1024 },
119 { .compat = "i2c-at24c16", .value = 2048 },
120 { .compat = "i2c-at24c32", .value = 4096 },
121 { .compat = "i2c-at24c64", .value = 8192 },
122 { .compat = "i2c-at24c128", .value = 16384 },
123 { .compat = "i2c-at24c256", .value = 32768 },
124 { .compat = "i2c-at24c512", .value = 65536 },
125 { .compat = "i2c-at34c02", .value = 256 },
126 { .compat = "atmel,24c02", .value = 256 },
127 { .compat = "atmel,24c16", .value = 2048 },
128 { .compat = "atmel,24c256", .value = 32768 },
129 DEVICE_COMPAT_EOL
130 };
131
132 static int
seeprom_match(device_t parent,cfdata_t cf,void * aux)133 seeprom_match(device_t parent, cfdata_t cf, void *aux)
134 {
135 struct i2c_attach_args *ia = aux;
136 int match_result;
137
138 if (iic_use_direct_match(ia, cf, compat_data, &match_result))
139 return match_result;
140
141 if ((ia->ia_addr & AT24CXX_ADDRMASK) == AT24CXX_ADDR)
142 return I2C_MATCH_ADDRESS_ONLY;
143
144 return 0;
145 }
146
147 static void
seeprom_attach(device_t parent,device_t self,void * aux)148 seeprom_attach(device_t parent, device_t self, void *aux)
149 {
150 struct seeprom_softc *sc = device_private(self);
151 struct i2c_attach_args *ia = aux;
152 const struct device_compatible_entry *dce;
153
154 sc->sc_tag = ia->ia_tag;
155 sc->sc_address = ia->ia_addr;
156 sc->sc_dev = self;
157
158 if (ia->ia_name != NULL) {
159 aprint_naive(": %s", ia->ia_name);
160 aprint_normal(": %s", ia->ia_name);
161 } else {
162 aprint_naive(": EEPROM");
163 aprint_normal(": AT24Cxx or compatible EEPROM");
164 }
165
166 /*
167 * The AT24C01A/02/04/08/16 EEPROMs use a 1 byte command
168 * word to select the offset into the EEPROM page. The
169 * AT24C04/08/16 decode fewer of the i2c address bits,
170 * using the bottom 1, 2, or 3 to select the 256-byte
171 * super-page.
172 *
173 * The AT24C32/64/128/256/512 EEPROMs use a 2 byte command
174 * word and decode all of the i2c address bits.
175 *
176 * The AT24C1024 EEPROMs use a 2 byte command and also do bank
177 * switching to select the proper super-page. This isn't
178 * supported by this driver.
179 */
180 if (device_cfdata(self)->cf_flags)
181 sc->sc_size = (device_cfdata(self)->cf_flags << 7);
182
183 if (sc->sc_size <= 0) {
184 if ((dce = iic_compatible_lookup(ia, compat_data)) != NULL)
185 sc->sc_size = dce->value;
186 }
187
188 switch (sc->sc_size) {
189 case 128: /* 1Kbit */
190 case 256: /* 2Kbit */
191 case 512: /* 4Kbit */
192 case 1024: /* 8Kbit */
193 case 2048: /* 16Kbit */
194 sc->sc_cmdlen = 1;
195 aprint_normal(": size %d\n", sc->sc_size);
196 break;
197
198 case 4096: /* 32Kbit */
199 case 8192: /* 64Kbit */
200 case 16384: /* 128Kbit */
201 case 32768: /* 256Kbit */
202 case 65536: /* 512Kbit */
203 sc->sc_cmdlen = 2;
204 aprint_normal(": size %d\n", sc->sc_size);
205 break;
206
207 default:
208 /*
209 * Default to 2KB. If we happen to have a 2KB
210 * EEPROM this will allow us to access it. If we
211 * have a smaller one, the worst that can happen
212 * is that we end up trying to read a different
213 * EEPROM on the bus when accessing it.
214 *
215 * Obviously this will not work for 4KB or 8KB
216 * EEPROMs, but them's the breaks.
217 */
218 aprint_normal("\n");
219 aprint_error_dev(self, "invalid size specified; "
220 "assuming 2KB (16Kb)\n");
221 sc->sc_size = 2048;
222 sc->sc_cmdlen = 1;
223 }
224
225 sc->sc_open = 0;
226 }
227
228 /*ARGSUSED*/
229 int
seeprom_open(dev_t dev,int flag,int fmt,struct lwp * l)230 seeprom_open(dev_t dev, int flag, int fmt, struct lwp *l)
231 {
232 struct seeprom_softc *sc;
233
234 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL)
235 return (ENXIO);
236
237 /* XXX: Locking */
238
239 if (sc->sc_open)
240 return (EBUSY);
241
242 sc->sc_open = 1;
243 return (0);
244 }
245
246 /*ARGSUSED*/
247 int
seeprom_close(dev_t dev,int flag,int fmt,struct lwp * l)248 seeprom_close(dev_t dev, int flag, int fmt, struct lwp *l)
249 {
250 struct seeprom_softc *sc;
251
252 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL)
253 return (ENXIO);
254
255 sc->sc_open = 0;
256 return (0);
257 }
258
259 /*ARGSUSED*/
260 int
seeprom_read(dev_t dev,struct uio * uio,int flags)261 seeprom_read(dev_t dev, struct uio *uio, int flags)
262 {
263 struct seeprom_softc *sc;
264 i2c_addr_t addr;
265 u_int8_t ch, cmdbuf[2];
266 int a, error;
267
268 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL)
269 return (ENXIO);
270
271 if (uio->uio_offset >= sc->sc_size)
272 return (EINVAL);
273
274 /*
275 * Even though the AT24Cxx EEPROMs support sequential
276 * reads within a page, some I2C controllers do not
277 * support anything other than single-byte transfers,
278 * so we're stuck with this lowest-common-denominator.
279 */
280
281 while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) {
282 a = (int)uio->uio_offset;
283 if (sc->sc_cmdlen == 1) {
284 addr = sc->sc_address + (a >> 8);
285 cmdbuf[0] = a & 0xff;
286 } else {
287 addr = sc->sc_address;
288 cmdbuf[0] = AT24CXX_ADDR_HI(a);
289 cmdbuf[1] = AT24CXX_ADDR_LO(a);
290 }
291
292 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
293 return (error);
294 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
295 addr, cmdbuf, sc->sc_cmdlen,
296 &ch, 1, 0)) != 0) {
297 iic_release_bus(sc->sc_tag, 0);
298 aprint_error_dev(sc->sc_dev,
299 "seeprom_read: byte read failed at 0x%x\n", a);
300 return (error);
301 }
302 iic_release_bus(sc->sc_tag, 0);
303
304 if ((error = uiomove(&ch, 1, uio)) != 0) {
305 return (error);
306 }
307 }
308
309 return (0);
310 }
311
312 /*ARGSUSED*/
313 int
seeprom_write(dev_t dev,struct uio * uio,int flags)314 seeprom_write(dev_t dev, struct uio *uio, int flags)
315 {
316 struct seeprom_softc *sc;
317 i2c_addr_t addr;
318 u_int8_t ch, cmdbuf[2];
319 int a, error;
320
321 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL)
322 return (ENXIO);
323
324 if (uio->uio_offset >= sc->sc_size)
325 return (EINVAL);
326
327 /*
328 * See seeprom_read() for why we don't use sequential
329 * writes within a page.
330 */
331
332 while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) {
333 a = (int)uio->uio_offset;
334 if (sc->sc_cmdlen == 1) {
335 addr = sc->sc_address + (a >> 8);
336 cmdbuf[0] = a & 0xff;
337 } else {
338 addr = sc->sc_address;
339 cmdbuf[0] = AT24CXX_ADDR_HI(a);
340 cmdbuf[1] = AT24CXX_ADDR_LO(a);
341 }
342 if ((error = uiomove(&ch, 1, uio)) != 0) {
343 iic_release_bus(sc->sc_tag, 0);
344 return (error);
345 }
346
347 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
348 return (error);
349 if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
350 addr, cmdbuf, sc->sc_cmdlen,
351 &ch, 1, 0)) != 0) {
352 iic_release_bus(sc->sc_tag, 0);
353 aprint_error_dev(sc->sc_dev,
354 "seeprom_write: byte write failed at 0x%x\n", a);
355 return (error);
356 }
357 iic_release_bus(sc->sc_tag, 0);
358
359 /* Wait until the device commits the byte. */
360 if ((error = seeprom_wait_idle(sc)) != 0) {
361 return (error);
362 }
363 }
364
365 return (0);
366 }
367
368 static int
seeprom_wait_idle(struct seeprom_softc * sc)369 seeprom_wait_idle(struct seeprom_softc *sc)
370 {
371 uint8_t cmdbuf[2] = { 0, 0 };
372 int rv, timeout;
373 u_int8_t dummy;
374 int error;
375
376 timeout = (1000 / hz) / AT24CXX_WRITE_CYCLE_MS;
377 if (timeout == 0)
378 timeout = 1;
379
380 delay(10);
381
382 /*
383 * Read the byte at address 0. This is just a dummy
384 * read to wait for the EEPROM's write cycle to complete.
385 */
386 for (;;) {
387 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0)
388 return error;
389 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
390 sc->sc_address, cmdbuf, sc->sc_cmdlen, &dummy, 1, 0);
391 iic_release_bus(sc->sc_tag, 0);
392 if (error == 0)
393 break;
394
395 rv = kpause("seepromwr", true, timeout, NULL);
396 if (rv != EWOULDBLOCK && rv != 0)
397 return (rv);
398 }
399
400 return (0);
401 }
402
403 #endif /* NSEEPROM > 0 */
404
405 int
seeprom_bootstrap_read(i2c_tag_t tag,int i2caddr,int offset,int devsize,u_int8_t * rvp,size_t len)406 seeprom_bootstrap_read(i2c_tag_t tag, int i2caddr, int offset, int devsize,
407 u_int8_t *rvp, size_t len)
408 {
409 i2c_addr_t addr;
410 int cmdlen;
411 uint8_t cmdbuf[2];
412
413 if (len == 0)
414 return (0);
415
416 /* We are very forgiving about devsize during bootstrap. */
417 cmdlen = (devsize >= 4096) ? 2 : 1;
418
419 if (iic_acquire_bus(tag, 0) != 0)
420 return (-1);
421
422 while (len) {
423 if (cmdlen == 1) {
424 addr = i2caddr + (offset >> 8);
425 cmdbuf[0] = offset & 0xff;
426 } else {
427 addr = i2caddr;
428 cmdbuf[0] = AT24CXX_ADDR_HI(offset);
429 cmdbuf[1] = AT24CXX_ADDR_LO(offset);
430 }
431
432 /* Read a single byte. */
433 if (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr,
434 cmdbuf, cmdlen, rvp, 1, 0)) {
435 iic_release_bus(tag, 0);
436 return (-1);
437 }
438
439 len--;
440 rvp++;
441 offset++;
442 }
443
444 iic_release_bus(tag, 0);
445 return (0);
446 }
447