1 /* $NetBSD: at24cxx.c,v 1.8 2007/10/19 11:59:43 ad 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/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/kernel.h> 42 #include <sys/fcntl.h> 43 #include <sys/uio.h> 44 #include <sys/conf.h> 45 #include <sys/proc.h> 46 #include <sys/event.h> 47 48 #include <sys/bus.h> 49 50 #include <dev/i2c/i2cvar.h> 51 #include <dev/i2c/at24cxxvar.h> 52 53 /* 54 * AT24Cxx EEPROM I2C address: 55 * 101 0xxx 56 * (and others depending on the exact model) The bigger 8-bit parts 57 * decode multiple addresses. The bigger 16-bit parts do too (those 58 * larger than 512kb). Be sure to check the datasheet of your EEPROM 59 * because there's much variation between models. 60 */ 61 #define AT24CXX_ADDRMASK 0x78 62 #define AT24CXX_ADDR 0x50 63 64 #define AT24CXX_WRITE_CYCLE_MS 10 65 #define AT24CXX_ADDR_HI(a) (((a) >> 8) & 0x1f) 66 #define AT24CXX_ADDR_LO(a) ((a) & 0xff) 67 68 #include "seeprom.h" 69 70 #if NSEEPROM > 0 71 72 struct seeprom_softc { 73 struct device sc_dev; 74 i2c_tag_t sc_tag; 75 int sc_address; 76 int sc_size; 77 int sc_cmdlen; 78 int sc_open; 79 }; 80 81 static int seeprom_match(struct device *, struct cfdata *, void *); 82 static void seeprom_attach(struct device *, struct device *, void *); 83 84 CFATTACH_DECL(seeprom, sizeof(struct seeprom_softc), 85 seeprom_match, seeprom_attach, NULL, NULL); 86 extern struct cfdriver seeprom_cd; 87 88 dev_type_open(seeprom_open); 89 dev_type_close(seeprom_close); 90 dev_type_read(seeprom_read); 91 dev_type_write(seeprom_write); 92 93 const struct cdevsw seeprom_cdevsw = { 94 seeprom_open, seeprom_close, seeprom_read, seeprom_write, noioctl, 95 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER 96 }; 97 98 static int seeprom_wait_idle(struct seeprom_softc *); 99 100 101 static int 102 seeprom_match(struct device *parent, struct cfdata *cf, void *aux) 103 { 104 struct i2c_attach_args *ia = aux; 105 106 if ((ia->ia_addr & AT24CXX_ADDRMASK) == AT24CXX_ADDR) 107 return (1); 108 109 return (0); 110 } 111 112 static void 113 seeprom_attach(struct device *parent, struct device *self, void *aux) 114 { 115 struct seeprom_softc *sc = device_private(self); 116 struct i2c_attach_args *ia = aux; 117 118 sc->sc_tag = ia->ia_tag; 119 sc->sc_address = ia->ia_addr; 120 121 aprint_naive(": EEPROM\n"); 122 aprint_normal(": AT24Cxx EEPROM\n"); 123 124 /* 125 * The AT24C01A/02/04/08/16 EEPROMs use a 1 byte command 126 * word to select the offset into the EEPROM page. The 127 * AT24C04/08/16 decode fewer of the i2c address bits, 128 * using the bottom 1, 2, or 3 to select the 256-byte 129 * super-page. 130 * 131 * The AT24C32/64/128/256/512 EEPROMs use a 2 byte command 132 * word and decode all of the i2c address bits. 133 * 134 * The AT24C1024 EEPROMs use a 2 byte command and also do bank 135 * switching to select the proper super-page. This isn't 136 * supported by this driver. 137 */ 138 sc->sc_size = ia->ia_size; 139 switch (sc->sc_size) { 140 case 128: /* 1Kbit */ 141 case 256: /* 2Kbit */ 142 case 512: /* 4Kbit */ 143 case 1024: /* 8Kbit */ 144 case 2048: /* 16Kbit */ 145 sc->sc_cmdlen = 1; 146 break; 147 148 case 4096: /* 32Kbit */ 149 case 8192: /* 64Kbit */ 150 case 16384: /* 128Kbit */ 151 case 32768: /* 256Kbit */ 152 case 65536: /* 512Kbit */ 153 sc->sc_cmdlen = 2; 154 break; 155 156 default: 157 /* 158 * Default to 2KB. If we happen to have a 2KB 159 * EEPROM this will allow us to access it. If we 160 * have a smaller one, the worst that can happen 161 * is that we end up trying to read a different 162 * EEPROM on the bus when accessing it. 163 * 164 * Obviously this will not work for 4KB or 8KB 165 * EEPROMs, but them's the breaks. 166 */ 167 aprint_error("%s: invalid size specified; " 168 "assuming 2KB (16Kb)\n", sc->sc_dev.dv_xname); 169 sc->sc_size = 2048; 170 sc->sc_cmdlen = 1; 171 } 172 173 sc->sc_open = 0; 174 } 175 176 /*ARGSUSED*/ 177 int 178 seeprom_open(dev_t dev, int flag, int fmt, struct lwp *l) 179 { 180 struct seeprom_softc *sc; 181 182 if ((sc = device_lookup(&seeprom_cd, minor(dev))) == NULL) 183 return (ENXIO); 184 185 /* XXX: Locking */ 186 187 if (sc->sc_open) 188 return (EBUSY); 189 190 sc->sc_open = 1; 191 return (0); 192 } 193 194 /*ARGSUSED*/ 195 int 196 seeprom_close(dev_t dev, int flag, int fmt, struct lwp *l) 197 { 198 struct seeprom_softc *sc; 199 200 if ((sc = device_lookup(&seeprom_cd, minor(dev))) == NULL) 201 return (ENXIO); 202 203 sc->sc_open = 0; 204 return (0); 205 } 206 207 /*ARGSUSED*/ 208 int 209 seeprom_read(dev_t dev, struct uio *uio, int flags) 210 { 211 struct seeprom_softc *sc; 212 i2c_addr_t addr; 213 u_int8_t ch, cmdbuf[2]; 214 int a, error; 215 216 if ((sc = device_lookup(&seeprom_cd, minor(dev))) == NULL) 217 return (ENXIO); 218 219 if (uio->uio_offset >= sc->sc_size) 220 return (EINVAL); 221 222 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 223 return (error); 224 225 /* 226 * Even though the AT24Cxx EEPROMs support sequential 227 * reads within a page, some I2C controllers do not 228 * support anything other than single-byte transfers, 229 * so we're stuck with this lowest-common-denominator. 230 */ 231 232 while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) { 233 a = (int)uio->uio_offset; 234 if (sc->sc_cmdlen == 1) { 235 addr = sc->sc_address + (a >> 8); 236 cmdbuf[0] = a & 0xff; 237 } else { 238 addr = sc->sc_address; 239 cmdbuf[0] = AT24CXX_ADDR_HI(a); 240 cmdbuf[1] = AT24CXX_ADDR_LO(a); 241 } 242 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 243 addr, cmdbuf, sc->sc_cmdlen, 244 &ch, 1, 0)) != 0) { 245 iic_release_bus(sc->sc_tag, 0); 246 printf("%s: seeprom_read: byte read failed at 0x%x\n", 247 sc->sc_dev.dv_xname, a); 248 return (error); 249 } 250 if ((error = uiomove(&ch, 1, uio)) != 0) { 251 iic_release_bus(sc->sc_tag, 0); 252 return (error); 253 } 254 } 255 256 iic_release_bus(sc->sc_tag, 0); 257 258 return (0); 259 } 260 261 /*ARGSUSED*/ 262 int 263 seeprom_write(dev_t dev, struct uio *uio, int flags) 264 { 265 struct seeprom_softc *sc; 266 i2c_addr_t addr; 267 u_int8_t ch, cmdbuf[2]; 268 int a, error; 269 270 if ((sc = device_lookup(&seeprom_cd, minor(dev))) == NULL) 271 return (ENXIO); 272 273 if (uio->uio_offset >= sc->sc_size) 274 return (EINVAL); 275 276 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 277 return (error); 278 279 /* 280 * See seeprom_read() for why we don't use sequential 281 * writes within a page. 282 */ 283 284 while (uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) { 285 a = (int)uio->uio_offset; 286 if (sc->sc_cmdlen == 1) { 287 addr = sc->sc_address + (a >> 8); 288 cmdbuf[0] = a & 0xff; 289 } else { 290 addr = sc->sc_address; 291 cmdbuf[0] = AT24CXX_ADDR_HI(a); 292 cmdbuf[1] = AT24CXX_ADDR_LO(a); 293 } 294 if ((error = uiomove(&ch, 1, uio)) != 0) { 295 iic_release_bus(sc->sc_tag, 0); 296 return (error); 297 } 298 if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 299 addr, cmdbuf, sc->sc_cmdlen, 300 &ch, 1, 0)) != 0) { 301 iic_release_bus(sc->sc_tag, 0); 302 printf("%s: seeprom_write: byte write failed at 0x%x\n", 303 sc->sc_dev.dv_xname, a); 304 return (error); 305 } 306 307 /* Wait until the device commits the byte. */ 308 if ((error = seeprom_wait_idle(sc)) != 0) { 309 iic_release_bus(sc->sc_tag, 0); 310 return (error); 311 } 312 } 313 314 iic_release_bus(sc->sc_tag, 0); 315 316 return (0); 317 } 318 319 static int 320 seeprom_wait_idle(struct seeprom_softc *sc) 321 { 322 uint8_t cmdbuf[2] = { 0, 0 }; 323 int rv, timeout; 324 u_int8_t dummy; 325 326 timeout = (1000 / hz) / AT24CXX_WRITE_CYCLE_MS; 327 if (timeout == 0) 328 timeout = 1; 329 330 delay(10); 331 332 /* 333 * Read the byte at address 0. This is just a dummy 334 * read to wait for the EEPROM's write cycle to complete. 335 */ 336 while (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_address, 337 cmdbuf, sc->sc_cmdlen, &dummy, 1, 0)) { 338 rv = tsleep(sc, PRIBIO | PCATCH, "seepromwr", timeout); 339 if (rv != EWOULDBLOCK) 340 return (rv); 341 } 342 343 return (0); 344 } 345 346 #endif /* NSEEPROM > 0 */ 347 348 int 349 seeprom_bootstrap_read(i2c_tag_t tag, int i2caddr, int offset, int devsize, 350 u_int8_t *rvp, size_t len) 351 { 352 i2c_addr_t addr; 353 int cmdlen; 354 uint8_t cmdbuf[2]; 355 356 if (len == 0) 357 return (0); 358 359 /* We are very forgiving about devsize during bootstrap. */ 360 cmdlen = (devsize >= 4096) ? 2 : 1; 361 362 if (iic_acquire_bus(tag, I2C_F_POLL) != 0) 363 return (-1); 364 365 while (len) { 366 if (cmdlen == 1) { 367 addr = i2caddr + (offset >> 8); 368 cmdbuf[0] = offset & 0xff; 369 } else { 370 addr = i2caddr; 371 cmdbuf[0] = AT24CXX_ADDR_HI(offset); 372 cmdbuf[1] = AT24CXX_ADDR_LO(offset); 373 } 374 375 /* Read a single byte. */ 376 if (iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, 377 cmdbuf, cmdlen, rvp, 1, I2C_F_POLL)) { 378 iic_release_bus(tag, I2C_F_POLL); 379 return (-1); 380 } 381 382 len--; 383 rvp++; 384 offset++; 385 } 386 387 iic_release_bus(tag, I2C_F_POLL); 388 return (0); 389 } 390