1 /* $NetBSD: at24cxx.c,v 1.11 2008/05/04 15:26:29 xtraeme Exp $ */
4 * Copyright (c) 2003 Wasabi Systems, Inc.
7 * Written by Steve C. Woodford and Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: at24cxx.c,v 1.11 2008/05/04 15:26:29 xtraeme Exp $");
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>
49 #include <sys/event.h>
53 #include <dev/i2c/i2cvar.h>
54 #include <dev/i2c/at24cxxvar.h>
57 * AT24Cxx EEPROM I2C address:
59 * (and others depending on the exact model) The bigger 8-bit parts
60 * decode multiple addresses. The bigger 16-bit parts do too (those
61 * larger than 512kb). Be sure to check the datasheet of your EEPROM
62 * because there's much variation between models.
64 #define AT24CXX_ADDRMASK 0x78
65 #define AT24CXX_ADDR 0x50
67 #define AT24CXX_WRITE_CYCLE_MS 10
68 #define AT24CXX_ADDR_HI(a) (((a) >> 8) & 0x1f)
69 #define AT24CXX_ADDR_LO(a) ((a) & 0xff)
75 struct seeprom_softc
{
84 static int seeprom_match(device_t
, cfdata_t
, void *);
85 static void seeprom_attach(device_t
, device_t
, void *);
87 CFATTACH_DECL_NEW(seeprom
, sizeof(struct seeprom_softc
),
88 seeprom_match
, seeprom_attach
, NULL
, NULL
);
89 extern struct cfdriver seeprom_cd
;
91 dev_type_open(seeprom_open
);
92 dev_type_close(seeprom_close
);
93 dev_type_read(seeprom_read
);
94 dev_type_write(seeprom_write
);
96 const struct cdevsw seeprom_cdevsw
= {
97 seeprom_open
, seeprom_close
, seeprom_read
, seeprom_write
, noioctl
,
98 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
101 static int seeprom_wait_idle(struct seeprom_softc
*);
105 seeprom_match(device_t parent
, cfdata_t cf
, void *aux
)
107 struct i2c_attach_args
*ia
= aux
;
109 if ((ia
->ia_addr
& AT24CXX_ADDRMASK
) == AT24CXX_ADDR
)
116 seeprom_attach(device_t parent
, device_t self
, void *aux
)
118 struct seeprom_softc
*sc
= device_private(self
);
119 struct i2c_attach_args
*ia
= aux
;
121 sc
->sc_tag
= ia
->ia_tag
;
122 sc
->sc_address
= ia
->ia_addr
;
125 aprint_naive(": EEPROM\n");
126 aprint_normal(": AT24Cxx EEPROM\n");
129 * The AT24C01A/02/04/08/16 EEPROMs use a 1 byte command
130 * word to select the offset into the EEPROM page. The
131 * AT24C04/08/16 decode fewer of the i2c address bits,
132 * using the bottom 1, 2, or 3 to select the 256-byte
135 * The AT24C32/64/128/256/512 EEPROMs use a 2 byte command
136 * word and decode all of the i2c address bits.
138 * The AT24C1024 EEPROMs use a 2 byte command and also do bank
139 * switching to select the proper super-page. This isn't
140 * supported by this driver.
142 sc
->sc_size
= ia
->ia_size
;
143 switch (sc
->sc_size
) {
144 case 128: /* 1Kbit */
145 case 256: /* 2Kbit */
146 case 512: /* 4Kbit */
147 case 1024: /* 8Kbit */
148 case 2048: /* 16Kbit */
152 case 4096: /* 32Kbit */
153 case 8192: /* 64Kbit */
154 case 16384: /* 128Kbit */
155 case 32768: /* 256Kbit */
156 case 65536: /* 512Kbit */
162 * Default to 2KB. If we happen to have a 2KB
163 * EEPROM this will allow us to access it. If we
164 * have a smaller one, the worst that can happen
165 * is that we end up trying to read a different
166 * EEPROM on the bus when accessing it.
168 * Obviously this will not work for 4KB or 8KB
169 * EEPROMs, but them's the breaks.
171 aprint_error_dev(self
, "invalid size specified; "
172 "assuming 2KB (16Kb)\n");
182 seeprom_open(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
184 struct seeprom_softc
*sc
;
186 if ((sc
= device_lookup_private(&seeprom_cd
, minor(dev
))) == NULL
)
200 seeprom_close(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
202 struct seeprom_softc
*sc
;
204 if ((sc
= device_lookup_private(&seeprom_cd
, minor(dev
))) == NULL
)
213 seeprom_read(dev_t dev
, struct uio
*uio
, int flags
)
215 struct seeprom_softc
*sc
;
217 u_int8_t ch
, cmdbuf
[2];
220 if ((sc
= device_lookup_private(&seeprom_cd
, minor(dev
))) == NULL
)
223 if (uio
->uio_offset
>= sc
->sc_size
)
226 if ((error
= iic_acquire_bus(sc
->sc_tag
, 0)) != 0)
230 * Even though the AT24Cxx EEPROMs support sequential
231 * reads within a page, some I2C controllers do not
232 * support anything other than single-byte transfers,
233 * so we're stuck with this lowest-common-denominator.
236 while (uio
->uio_resid
> 0 && uio
->uio_offset
< sc
->sc_size
) {
237 a
= (int)uio
->uio_offset
;
238 if (sc
->sc_cmdlen
== 1) {
239 addr
= sc
->sc_address
+ (a
>> 8);
240 cmdbuf
[0] = a
& 0xff;
242 addr
= sc
->sc_address
;
243 cmdbuf
[0] = AT24CXX_ADDR_HI(a
);
244 cmdbuf
[1] = AT24CXX_ADDR_LO(a
);
246 if ((error
= iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
,
247 addr
, cmdbuf
, sc
->sc_cmdlen
,
249 iic_release_bus(sc
->sc_tag
, 0);
250 aprint_error_dev(sc
->sc_dev
,
251 "seeprom_read: byte read failed at 0x%x\n", a
);
254 if ((error
= uiomove(&ch
, 1, uio
)) != 0) {
255 iic_release_bus(sc
->sc_tag
, 0);
260 iic_release_bus(sc
->sc_tag
, 0);
267 seeprom_write(dev_t dev
, struct uio
*uio
, int flags
)
269 struct seeprom_softc
*sc
;
271 u_int8_t ch
, cmdbuf
[2];
274 if ((sc
= device_lookup_private(&seeprom_cd
, minor(dev
))) == NULL
)
277 if (uio
->uio_offset
>= sc
->sc_size
)
280 if ((error
= iic_acquire_bus(sc
->sc_tag
, 0)) != 0)
284 * See seeprom_read() for why we don't use sequential
285 * writes within a page.
288 while (uio
->uio_resid
> 0 && uio
->uio_offset
< sc
->sc_size
) {
289 a
= (int)uio
->uio_offset
;
290 if (sc
->sc_cmdlen
== 1) {
291 addr
= sc
->sc_address
+ (a
>> 8);
292 cmdbuf
[0] = a
& 0xff;
294 addr
= sc
->sc_address
;
295 cmdbuf
[0] = AT24CXX_ADDR_HI(a
);
296 cmdbuf
[1] = AT24CXX_ADDR_LO(a
);
298 if ((error
= uiomove(&ch
, 1, uio
)) != 0) {
299 iic_release_bus(sc
->sc_tag
, 0);
302 if ((error
= iic_exec(sc
->sc_tag
, I2C_OP_WRITE_WITH_STOP
,
303 addr
, cmdbuf
, sc
->sc_cmdlen
,
305 iic_release_bus(sc
->sc_tag
, 0);
306 aprint_error_dev(sc
->sc_dev
,
307 "seeprom_write: byte write failed at 0x%x\n", a
);
311 /* Wait until the device commits the byte. */
312 if ((error
= seeprom_wait_idle(sc
)) != 0) {
313 iic_release_bus(sc
->sc_tag
, 0);
318 iic_release_bus(sc
->sc_tag
, 0);
324 seeprom_wait_idle(struct seeprom_softc
*sc
)
326 uint8_t cmdbuf
[2] = { 0, 0 };
330 timeout
= (1000 / hz
) / AT24CXX_WRITE_CYCLE_MS
;
337 * Read the byte at address 0. This is just a dummy
338 * read to wait for the EEPROM's write cycle to complete.
340 while (iic_exec(sc
->sc_tag
, I2C_OP_READ_WITH_STOP
, sc
->sc_address
,
341 cmdbuf
, sc
->sc_cmdlen
, &dummy
, 1, 0)) {
342 rv
= tsleep(sc
, PRIBIO
| PCATCH
, "seepromwr", timeout
);
343 if (rv
!= EWOULDBLOCK
)
350 #endif /* NSEEPROM > 0 */
353 seeprom_bootstrap_read(i2c_tag_t tag
, int i2caddr
, int offset
, int devsize
,
354 u_int8_t
*rvp
, size_t len
)
363 /* We are very forgiving about devsize during bootstrap. */
364 cmdlen
= (devsize
>= 4096) ? 2 : 1;
366 if (iic_acquire_bus(tag
, I2C_F_POLL
) != 0)
371 addr
= i2caddr
+ (offset
>> 8);
372 cmdbuf
[0] = offset
& 0xff;
375 cmdbuf
[0] = AT24CXX_ADDR_HI(offset
);
376 cmdbuf
[1] = AT24CXX_ADDR_LO(offset
);
379 /* Read a single byte. */
380 if (iic_exec(tag
, I2C_OP_READ_WITH_STOP
, addr
,
381 cmdbuf
, cmdlen
, rvp
, 1, I2C_F_POLL
)) {
382 iic_release_bus(tag
, I2C_F_POLL
);
391 iic_release_bus(tag
, I2C_F_POLL
);