1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * ATMEL AT24C02 EEPROM driver File: dev_smbus_at24c02.c 5 * 6 * This module contains a CFE driver for a ATMEL AT24C02 EEPROM 7 * 8 * Author: Binh Vo 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47#include "cfe.h" 48#include "cfe_smbus.h" 49 50 51/* ********************************************************************* 52 * Forward Declarations 53 ********************************************************************* */ 54 55static void sb1250_at24c02eeprom_probe(cfe_driver_t *drv, 56 unsigned long probe_a, unsigned long probe_b, 57 void *probe_ptr); 58 59 60static int sb1250_at24c02eeprom_open(cfe_devctx_t *ctx); 61static int sb1250_at24c02eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 62static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 63static int sb1250_at24c02eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 64static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 65static int sb1250_at24c02eeprom_close(cfe_devctx_t *ctx); 66 67/* ********************************************************************* 68 * Dispatch tables 69 ********************************************************************* */ 70 71#define AT24C02_EEPROM_SIZE 256 72 73const static cfe_devdisp_t sb1250_at24c02eeprom_dispatch = { 74 sb1250_at24c02eeprom_open, 75 sb1250_at24c02eeprom_read, 76 sb1250_at24c02eeprom_inpstat, 77 sb1250_at24c02eeprom_write, 78 sb1250_at24c02eeprom_ioctl, 79 sb1250_at24c02eeprom_close, 80 NULL, 81 NULL 82}; 83 84const cfe_driver_t smbus_at24c02 = { 85 "ATMEL AT24C02 SPD EEPROM", 86 "eeprom", 87 CFE_DEV_NVRAM, 88 &sb1250_at24c02eeprom_dispatch, 89 sb1250_at24c02eeprom_probe 90}; 91 92typedef struct sb1250_at24c02eeprom_s { 93 cfe_smbus_channel_t *smbus_channel; 94 int smbus_address; 95 int env_offset; 96 int env_size; 97} sb1250_at24c02eeprom_t; 98 99 100/* ********************************************************************* 101 * smbus_readbyte(chan,slaveaddr,devaddr) 102 * 103 * Read a byte from the chip. 104 * 105 * Input parameters: 106 * chan - SMBus channel 107 * slaveaddr - SMBus slave address 108 * devaddr - byte within the at24c02 device to read 109 * 110 * Return value: 111 * 0 if ok 112 * else -1 113 ********************************************************************* */ 114 115static int smbus_readbyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr) 116{ 117 uint8_t buf[1]; 118 int err; 119 120 /* 121 * Start the command 122 */ 123 124 buf[0] = devaddr; 125 err = SMBUS_WRITE(chan,slaveaddr,buf,1); 126 if (err < 0) return err; 127 128 /* 129 * Read the data byte 130 */ 131 132 err = SMBUS_READ(chan,slaveaddr,buf,1); 133 if (err < 0) return err; 134 135 return buf[0]; 136} 137 138/* ********************************************************************* 139 * smbus_writebyte(chan,slaveaddr,devaddr,b) 140 * 141 * write a byte from the chip. 142 * 143 * Input parameters: 144 * chan - SMBus channel 145 * slaveaddr - SMBus slave address 146 * devaddr - byte within the at24c02 device to read 147 * b - byte to write 148 * 149 * Return value: 150 * 0 if ok 151 * else -1 152 ********************************************************************* */ 153 154static int smbus_writebyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b) 155{ 156 uint8_t buf[2]; 157 int err; 158 int64_t timer; 159 160 /* 161 * Write the data to the controller 162 */ 163 164 buf[0] = devaddr; 165 buf[1] = b; 166 167 err = SMBUS_WRITE(chan,slaveaddr,buf,2); 168 169 /* 170 * Pound on the device with a current address read 171 * to poll for the write complete 172 */ 173 174 TIMER_SET(timer,50); 175 err = -1; 176 177 while (!TIMER_EXPIRED(timer)) { 178 POLL(); 179 180 err = SMBUS_READ(chan,slaveaddr,buf,1); 181 if (err == 0) break; 182 } 183 184 return err; 185} 186 187/* ********************************************************************* 188 * sb1250_at24c02eeprom_probe(drv,a,b,ptr) 189 * 190 * Probe routine for this driver. This routine creates the 191 * local device context and attaches it to the driver list 192 * within CFE. 193 * 194 * Input parameters: 195 * drv - driver handle 196 * a,b - probe hints (longs) 197 * ptr - probe hint (pointer) 198 * 199 * Return value: 200 * nothing 201 ********************************************************************* */ 202 203static void sb1250_at24c02eeprom_probe(cfe_driver_t *drv, 204 unsigned long probe_a, unsigned long probe_b, 205 void *probe_ptr) 206{ 207 sb1250_at24c02eeprom_t *softc; 208 char descr[80]; 209 210 softc = (sb1250_at24c02eeprom_t *) KMALLOC(sizeof(sb1250_at24c02eeprom_t),0); 211 212 /* 213 * Probe_a is the SMBus channel number 214 * Probe_b is the SMBus device offset 215 * Probe_ptr is unused. 216 */ 217 218 softc->smbus_channel = SMBUS_CHANNEL((int)probe_a); 219 softc->smbus_address = (int)probe_b; 220 softc->env_offset = 0; 221 softc->env_size = AT24C02_EEPROM_SIZE; 222 223 xsprintf(descr,"%s on SMBus channel %d dev 0x%02X", 224 drv->drv_description,(int)probe_a,(int)probe_b); 225 cfe_attach(drv,softc,NULL,descr); 226} 227 228 229 230/* ********************************************************************* 231 * sb1250_at24c02eeprom_open(ctx) 232 * 233 * Open this device. 234 * 235 * Input parameters: 236 * ctx - device context (can obtain our softc here) 237 * 238 * Return value: 239 * 0 if ok 240 * else error code 241 ********************************************************************* */ 242 243static int sb1250_at24c02eeprom_open(cfe_devctx_t *ctx) 244{ 245 sb1250_at24c02eeprom_t *softc = ctx->dev_softc; 246 int b; 247 248 b = smbus_readbyte(softc->smbus_channel, 249 softc->smbus_address, 250 0); 251 252 return (b < 0) ? -1 : 0; 253} 254 255/* ********************************************************************* 256 * sb1250_at24c02eeprom_read(ctx,buffer) 257 * 258 * Read bytes from the device. 259 * 260 * Input parameters: 261 * ctx - device context (can obtain our softc here) 262 * buffer - buffer descriptor (target buffer, length, offset) 263 * 264 * Return value: 265 * number of bytes read 266 * -1 if an error occured 267 ********************************************************************* */ 268 269static int sb1250_at24c02eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 270{ 271 sb1250_at24c02eeprom_t *softc = ctx->dev_softc; 272 hsaddr_t bptr; 273 int blen; 274 int idx; 275 int b = 0; 276 277 bptr = buffer->buf_ptr; 278 blen = buffer->buf_length; 279 280 if ((buffer->buf_offset + blen) > AT24C02_EEPROM_SIZE) return -1; 281 282 idx = (int) buffer->buf_offset; 283 284 while (blen > 0) { 285 b = smbus_readbyte(softc->smbus_channel, 286 softc->smbus_address, 287 idx); 288 if (b < 0) break; 289 hs_write8(bptr,(unsigned char)b); 290 bptr++; 291 blen--; 292 idx++; 293 } 294 295 buffer->buf_retlen = bptr - buffer->buf_ptr; 296 return (b < 0) ? -1 : 0; 297} 298 299/* ********************************************************************* 300 * sb1250_at24c02eeprom_inpstat(ctx,inpstat) 301 * 302 * Test input (read) status for the device 303 * 304 * Input parameters: 305 * ctx - device context (can obtain our softc here) 306 * inpstat - input status descriptor to receive value 307 * 308 * Return value: 309 * 0 if ok 310 * -1 if an error occured 311 ********************************************************************* */ 312 313static int sb1250_at24c02eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 314{ 315 inpstat->inp_status = 1; 316 317 return 0; 318} 319 320/* ********************************************************************* 321 * sb1250_at24c02eeprom_write(ctx,buffer) 322 * 323 * Write bytes from the device. 324 * 325 * Input parameters: 326 * ctx - device context (can obtain our softc here) 327 * buffer - buffer descriptor (target buffer, length, offset) 328 * 329 * Return value: 330 * number of bytes read 331 * -1 if an error occured 332 ********************************************************************* */ 333 334static int sb1250_at24c02eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 335{ 336 sb1250_at24c02eeprom_t *softc = ctx->dev_softc; 337 hsaddr_t bptr; 338 int blen; 339 int idx; 340 int b = 0; 341 342 bptr = buffer->buf_ptr; 343 blen = buffer->buf_length; 344 345 if ((buffer->buf_offset + blen) > AT24C02_EEPROM_SIZE) return -1; 346 347 idx = (int) buffer->buf_offset; 348 349 while (blen > 0) { 350 b = hs_read8(bptr); 351 bptr++; 352 b = smbus_writebyte(softc->smbus_channel, 353 softc->smbus_address, 354 idx, 355 b); 356 if (b < 0) break; 357 blen--; 358 idx++; 359 } 360 361 buffer->buf_retlen = bptr - buffer->buf_ptr; 362 return (b < 0) ? -1 : 0; 363} 364 365/* ********************************************************************* 366 * sb1250_at24c02eeprom_ioctl(ctx,buffer) 367 * 368 * Perform miscellaneous I/O control operations on the device. 369 * 370 * Input parameters: 371 * ctx - device context (can obtain our softc here) 372 * buffer - buffer descriptor (target buffer, length, offset) 373 * 374 * Return value: 375 * number of bytes read 376 * -1 if an error occured 377 ********************************************************************* */ 378 379static int sb1250_at24c02eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 380{ 381 sb1250_at24c02eeprom_t *softc = ctx->dev_softc; 382 nvram_info_t info; 383 384 switch ((int)buffer->buf_ioctlcmd) { 385 case IOCTL_NVRAM_GETINFO: 386 if (buffer->buf_length != sizeof(nvram_info_t)) return -1; 387 info.nvram_offset = softc->env_offset; 388 info.nvram_size = softc->env_size; 389 info.nvram_eraseflg = FALSE; 390 buffer->buf_retlen = sizeof(nvram_info_t); 391 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info)); 392 return 0; 393 default: 394 return -1; 395 } 396} 397 398/* ********************************************************************* 399 * sb1250_at24c02eeprom_close(ctx,buffer) 400 * 401 * Close the device. 402 * 403 * Input parameters: 404 * ctx - device context (can obtain our softc here) 405 * 406 * Return value: 407 * 0 if ok 408 * -1 if an error occured 409 ********************************************************************* */ 410 411static int sb1250_at24c02eeprom_close(cfe_devctx_t *ctx) 412{ 413 return 0; 414} 415 416 417