1/* $NetBSD: at24cxx.c,v 1.11 2008/05/04 15:26:29 xtraeme 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.11 2008/05/04 15:26:29 xtraeme 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/* 57 * AT24Cxx EEPROM I2C address: 58 * 101 0xxx 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. 63 */ 64#define AT24CXX_ADDRMASK 0x78 65#define AT24CXX_ADDR 0x50 66 67#define AT24CXX_WRITE_CYCLE_MS 10 68#define AT24CXX_ADDR_HI(a) (((a) >> 8) & 0x1f) 69#define AT24CXX_ADDR_LO(a) ((a) & 0xff) 70 71#include "seeprom.h" 72 73#if NSEEPROM > 0 74 75struct seeprom_softc { 76 device_t sc_dev; 77 i2c_tag_t sc_tag; 78 int sc_address; 79 int sc_size; 80 int sc_cmdlen; 81 int sc_open; 82}; 83 84static int seeprom_match(device_t, cfdata_t, void *); 85static void seeprom_attach(device_t, device_t, void *); 86 87CFATTACH_DECL_NEW(seeprom, sizeof(struct seeprom_softc), 88 seeprom_match, seeprom_attach, NULL, NULL); 89extern struct cfdriver seeprom_cd; 90 91dev_type_open(seeprom_open); 92dev_type_close(seeprom_close); 93dev_type_read(seeprom_read); 94dev_type_write(seeprom_write); 95 96const struct cdevsw seeprom_cdevsw = { 97 seeprom_open, seeprom_close, seeprom_read, seeprom_write, noioctl, 98 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER 99}; 100 101static int seeprom_wait_idle(struct seeprom_softc *); 102 103 104static int 105seeprom_match(device_t parent, cfdata_t cf, void *aux) 106{ 107 struct i2c_attach_args *ia = aux; 108 109 if ((ia->ia_addr & AT24CXX_ADDRMASK) == AT24CXX_ADDR) 110 return (1); 111 112 return (0); 113} 114 115static void 116seeprom_attach(device_t parent, device_t self, void *aux) 117{ 118 struct seeprom_softc *sc = device_private(self); 119 struct i2c_attach_args *ia = aux; 120 121 sc->sc_tag = ia->ia_tag; 122 sc->sc_address = ia->ia_addr; 123 sc->sc_dev = self; 124 125 aprint_naive(": EEPROM\n"); 126 aprint_normal(": AT24Cxx EEPROM\n"); 127 128 /* 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 133 * super-page. 134 * 135 * The AT24C32/64/128/256/512 EEPROMs use a 2 byte command 136 * word and decode all of the i2c address bits. 137 * 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. 141 */ 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 */ 149 sc->sc_cmdlen = 1; 150 break; 151 152 case 4096: /* 32Kbit */ 153 case 8192: /* 64Kbit */ 154 case 16384: /* 128Kbit */ 155 case 32768: /* 256Kbit */ 156 case 65536: /* 512Kbit */ 157 sc->sc_cmdlen = 2; 158 break; 159 160 default: 161 /* 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. 167 * 168 * Obviously this will not work for 4KB or 8KB 169 * EEPROMs, but them's the breaks. 170 */ 171 aprint_error_dev(self, "invalid size specified; " 172 "assuming 2KB (16Kb)\n"); 173 sc->sc_size = 2048; 174 sc->sc_cmdlen = 1; 175 } 176 177 sc->sc_open = 0; 178} 179 180/*ARGSUSED*/ 181int 182seeprom_open(dev_t dev, int flag, int fmt, struct lwp *l) 183{ 184 struct seeprom_softc *sc; 185 186 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL) 187 return (ENXIO); 188 189 /* XXX: Locking */ 190 191 if (sc->sc_open) 192 return (EBUSY); 193 194 sc->sc_open = 1; 195 return (0); 196} 197 198/*ARGSUSED*/ 199int 200seeprom_close(dev_t dev, int flag, int fmt, struct lwp *l) 201{ 202 struct seeprom_softc *sc; 203 204 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL) 205 return (ENXIO); 206 207 sc->sc_open = 0; 208 return (0); 209} 210 211/*ARGSUSED*/ 212int 213seeprom_read(dev_t dev, struct uio *uio, int flags) 214{ 215 struct seeprom_softc *sc; 216 i2c_addr_t addr; 217 u_int8_t ch, cmdbuf[2]; 218 int a, error; 219 220 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL) 221 return (ENXIO); 222 223 if (uio->uio_offset >= sc->sc_size) 224 return (EINVAL); 225 226 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 227 return (error); 228 229 /* 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. 234 */ 235 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; 241 } else { 242 addr = sc->sc_address; 243 cmdbuf[0] = AT24CXX_ADDR_HI(a); 244 cmdbuf[1] = AT24CXX_ADDR_LO(a); 245 } 246 if ((error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 247 addr, cmdbuf, sc->sc_cmdlen, 248 &ch, 1, 0)) != 0) { 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); 252 return (error); 253 } 254 if ((error = uiomove(&ch, 1, uio)) != 0) { 255 iic_release_bus(sc->sc_tag, 0); 256 return (error); 257 } 258 } 259 260 iic_release_bus(sc->sc_tag, 0); 261 262 return (0); 263} 264 265/*ARGSUSED*/ 266int 267seeprom_write(dev_t dev, struct uio *uio, int flags) 268{ 269 struct seeprom_softc *sc; 270 i2c_addr_t addr; 271 u_int8_t ch, cmdbuf[2]; 272 int a, error; 273 274 if ((sc = device_lookup_private(&seeprom_cd, minor(dev))) == NULL) 275 return (ENXIO); 276 277 if (uio->uio_offset >= sc->sc_size) 278 return (EINVAL); 279 280 if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) 281 return (error); 282 283 /* 284 * See seeprom_read() for why we don't use sequential 285 * writes within a page. 286 */ 287 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; 293 } else { 294 addr = sc->sc_address; 295 cmdbuf[0] = AT24CXX_ADDR_HI(a); 296 cmdbuf[1] = AT24CXX_ADDR_LO(a); 297 } 298 if ((error = uiomove(&ch, 1, uio)) != 0) { 299 iic_release_bus(sc->sc_tag, 0); 300 return (error); 301 } 302 if ((error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 303 addr, cmdbuf, sc->sc_cmdlen, 304 &ch, 1, 0)) != 0) { 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); 308 return (error); 309 } 310 311 /* Wait until the device commits the byte. */ 312 if ((error = seeprom_wait_idle(sc)) != 0) { 313 iic_release_bus(sc->sc_tag, 0); 314 return (error); 315 } 316 } 317 318 iic_release_bus(sc->sc_tag, 0); 319 320 return (0); 321} 322 323static int 324seeprom_wait_idle(struct seeprom_softc *sc) 325{ 326 uint8_t cmdbuf[2] = { 0, 0 }; 327 int rv, timeout; 328 u_int8_t dummy; 329 330 timeout = (1000 / hz) / AT24CXX_WRITE_CYCLE_MS; 331 if (timeout == 0) 332 timeout = 1; 333 334 delay(10); 335 336 /* 337 * Read the byte at address 0. This is just a dummy 338 * read to wait for the EEPROM's write cycle to complete. 339 */ 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) 344 return (rv); 345 } 346 347 return (0); 348} 349 350#endif /* NSEEPROM > 0 */ 351 352int 353seeprom_bootstrap_read(i2c_tag_t tag, int i2caddr, int offset, int devsize, 354 u_int8_t *rvp, size_t len) 355{ 356 i2c_addr_t addr; 357 int cmdlen; 358 uint8_t cmdbuf[2]; 359 360 if (len == 0) 361 return (0); 362 363 /* We are very forgiving about devsize during bootstrap. */ 364 cmdlen = (devsize >= 4096) ? 2 : 1; 365 366 if (iic_acquire_bus(tag, I2C_F_POLL) != 0) 367 return (-1); 368 369 while (len) { 370 if (cmdlen == 1) { 371 addr = i2caddr + (offset >> 8); 372 cmdbuf[0] = offset & 0xff; 373 } else { 374 addr = i2caddr; 375 cmdbuf[0] = AT24CXX_ADDR_HI(offset); 376 cmdbuf[1] = AT24CXX_ADDR_LO(offset); 377 } 378 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); 383 return (-1); 384 } 385 386 len--; 387 rvp++; 388 offset++; 389 } 390 391 iic_release_bus(tag, I2C_F_POLL); 392 return (0); 393} 394