1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Microchip 24lc128 EEPROM driver File: dev_smbus_24lc128.c 5 * 6 * This module contains a CFE driver for a Microchip 24LC128 EEPROM 7 * 8 * Author: Mitch Lichtenberg 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 smbus_24lc128_probe(cfe_driver_t *drv, 56 unsigned long probe_a, unsigned long probe_b, 57 void *probe_ptr); 58 59 60static int smbus_24lc128_open(cfe_devctx_t *ctx); 61static int smbus_24lc128_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 62static int smbus_24lc128_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 63static int smbus_24lc128_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 64static int smbus_24lc128_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 65static int smbus_24lc128_close(cfe_devctx_t *ctx); 66 67/* ********************************************************************* 68 * Dispatch tables 69 ********************************************************************* */ 70 71#define M24LC128_EEPROM_SIZE 16384 72 73const static cfe_devdisp_t smbus_24lc128_dispatch = { 74 smbus_24lc128_open, 75 smbus_24lc128_read, 76 smbus_24lc128_inpstat, 77 smbus_24lc128_write, 78 smbus_24lc128_ioctl, 79 smbus_24lc128_close, 80 NULL, 81 NULL 82}; 83 84const cfe_driver_t smbus_24lc128 = { 85 "Microchip 24LC128 EEPROM", 86 "eeprom", 87 CFE_DEV_NVRAM, 88 &smbus_24lc128_dispatch, 89 smbus_24lc128_probe 90}; 91 92typedef struct smbus_24lc128_s { 93 cfe_smbus_channel_t *smbus_channel; 94 int smbus_address; 95 int env_offset; 96 int env_size; 97} smbus_24lc128_t; 98 99 100 101/* ********************************************************************* 102 * smbus_readbyte(chan,slaveaddr,devaddr) 103 * 104 * Read a byte from the chip. The 'slaveaddr' parameter determines 105 * whether we're reading from the RTC section or the EEPROM section. 106 * 107 * Input parameters: 108 * chan - SMBus channel 109 * slaveaddr - SMBus slave address 110 * devaddr - byte with in the device to read 111 * 112 * Return value: 113 * 0 if ok 114 * else -1 115 ********************************************************************* */ 116 117static int smbus_readbyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr) 118{ 119 uint8_t buf[2]; 120 int err; 121 122 buf[0] = (devaddr >> 8) & 0x3F; 123 buf[1] = (devaddr & 0xFF); 124 125 /* 126 * Write the device address to the controller. 127 */ 128 129 err = SMBUS_WRITE(chan,slaveaddr,buf,2); 130 if (err < 0) return err; 131 132 /* 133 * Read the data byte 134 */ 135 136 err = SMBUS_READ(chan,slaveaddr,buf,1); 137 if (err < 0) return err; 138 139 return buf[0]; 140} 141 142/* ********************************************************************* 143 * smbus_writebyte(chan,slaveaddr,devaddr,b) 144 * 145 * write a byte from the chip. The 'slaveaddr' parameter determines 146 * whethe we're writing to the RTC section or the EEPROM section. 147 * 148 * Input parameters: 149 * chan - SMBus channel 150 * slaveaddr - SMBus slave address 151 * devaddr - byte with in the device to read 152 * b - byte to write 153 * 154 * Return value: 155 * 0 if ok 156 * else -1 157 ********************************************************************* */ 158 159 160static int smbus_writebyte(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b) 161{ 162 int err; 163 int64_t timer; 164 uint8_t buf[3]; 165 166 167 buf[0] = (devaddr >> 8) & 0x3F; 168 buf[1] = (devaddr & 0xFF); 169 buf[2] = (uint8_t) b; 170 171 err = SMBUS_WRITE(chan,slaveaddr,buf,3); 172 if (err < 0) return err; 173 174 /* 175 * Pound on the device with a quick command (R/W=0) 176 * to poll for the write complete. See sect 7.0 of the 177 * 24LC128 manual. 178 */ 179 180 TIMER_SET(timer,50); 181 err = -1; 182 183 while (!TIMER_EXPIRED(timer)) { 184 POLL(); 185 186 err = SMBUS_QCMD(chan,slaveaddr,0); 187 if (err == 0) break; 188 } 189 190 return err; 191} 192 193 194/* ********************************************************************* 195 * smbus_24lc128_probe(drv,a,b,ptr) 196 * 197 * Probe routine for this driver. This routine creates the 198 * local device context and attaches it to the driver list 199 * within CFE. 200 * 201 * Input parameters: 202 * drv - driver handle 203 * a,b - probe hints (longs) 204 * ptr - probe hint (pointer) 205 * 206 * Return value: 207 * nothing 208 ********************************************************************* */ 209 210static void smbus_24lc128_probe(cfe_driver_t *drv, 211 unsigned long probe_a, unsigned long probe_b, 212 void *probe_ptr) 213{ 214 smbus_24lc128_t *softc; 215 char descr[80]; 216 217 softc = (smbus_24lc128_t *) KMALLOC(sizeof(smbus_24lc128_t),0); 218 219 /* 220 * Probe_a is the SMBus channel number 221 * Probe_b is the SMBus device offset 222 * Probe_ptr is unused. 223 */ 224 225 softc->smbus_channel = SMBUS_CHANNEL((int)probe_a); 226 softc->smbus_address = (int)probe_b; 227 softc->env_offset = 0; 228 softc->env_size = M24LC128_EEPROM_SIZE; 229 230 xsprintf(descr,"%s on SMBus channel %d dev 0x%02X", 231 drv->drv_description,(int)probe_a,(int)probe_b); 232 cfe_attach(drv,softc,NULL,descr); 233} 234 235 236 237/* ********************************************************************* 238 * smbus_24lc128_open(ctx) 239 * 240 * Open this device. For the X1240, we do a quick test 241 * read to be sure the device is out there. 242 * 243 * Input parameters: 244 * ctx - device context (can obtain our softc here) 245 * 246 * Return value: 247 * 0 if ok 248 * else error code 249 ********************************************************************* */ 250 251static int smbus_24lc128_open(cfe_devctx_t *ctx) 252{ 253 smbus_24lc128_t *softc = ctx->dev_softc; 254 int b; 255 256 b = smbus_readbyte(softc->smbus_channel, 257 softc->smbus_address, 258 0); 259 260 return (b < 0) ? -1 : 0; 261} 262 263/* ********************************************************************* 264 * smbus_24lc128_read(ctx,buffer) 265 * 266 * Read bytes from the device. 267 * 268 * Input parameters: 269 * ctx - device context (can obtain our softc here) 270 * buffer - buffer descriptor (target buffer, length, offset) 271 * 272 * Return value: 273 * number of bytes read 274 * -1 if an error occured 275 ********************************************************************* */ 276 277static int smbus_24lc128_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 278{ 279 smbus_24lc128_t *softc = ctx->dev_softc; 280 hsaddr_t bptr; 281 int blen; 282 int idx; 283 int b = 0; 284 285 bptr = buffer->buf_ptr; 286 blen = buffer->buf_length; 287 288 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1; 289 290 idx = (int) buffer->buf_offset; 291 292 while (blen > 0) { 293 b = smbus_readbyte(softc->smbus_channel, 294 softc->smbus_address, 295 idx); 296 if (b < 0) break; 297 hs_write8(bptr,b); 298 bptr++; 299 blen--; 300 idx++; 301 } 302 303 buffer->buf_retlen = bptr - buffer->buf_ptr; 304 return (b < 0) ? -1 : 0; 305} 306 307/* ********************************************************************* 308 * smbus_24lc128_inpstat(ctx,inpstat) 309 * 310 * Test input (read) status for the device 311 * 312 * Input parameters: 313 * ctx - device context (can obtain our softc here) 314 * inpstat - input status descriptor to receive value 315 * 316 * Return value: 317 * 0 if ok 318 * -1 if an error occured 319 ********************************************************************* */ 320 321static int smbus_24lc128_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 322{ 323 inpstat->inp_status = 1; 324 325 return 0; 326} 327 328/* ********************************************************************* 329 * smbus_24lc128_write(ctx,buffer) 330 * 331 * Write bytes from the device. 332 * 333 * Input parameters: 334 * ctx - device context (can obtain our softc here) 335 * buffer - buffer descriptor (target buffer, length, offset) 336 * 337 * Return value: 338 * number of bytes read 339 * -1 if an error occured 340 ********************************************************************* */ 341 342static int smbus_24lc128_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 343{ 344 smbus_24lc128_t *softc = ctx->dev_softc; 345 hsaddr_t bptr; 346 int blen; 347 int idx; 348 int b = 0; 349 350 bptr = buffer->buf_ptr; 351 blen = buffer->buf_length; 352 353 if ((buffer->buf_offset + blen) > M24LC128_EEPROM_SIZE) return -1; 354 355 idx = (int) buffer->buf_offset; 356 357 while (blen > 0) { 358 b = hs_read8(bptr); 359 bptr++; 360 b = smbus_writebyte(softc->smbus_channel, 361 softc->smbus_address, 362 idx, 363 b); 364 if (b < 0) break; 365 blen--; 366 idx++; 367 } 368 369 buffer->buf_retlen = bptr - buffer->buf_ptr; 370 return (b < 0) ? -1 : 0; 371} 372 373/* ********************************************************************* 374 * smbus_24lc128_ioctl(ctx,buffer) 375 * 376 * Perform miscellaneous I/O control operations on the device. 377 * 378 * Input parameters: 379 * ctx - device context (can obtain our softc here) 380 * buffer - buffer descriptor (target buffer, length, offset) 381 * 382 * Return value: 383 * number of bytes read 384 * -1 if an error occured 385 ********************************************************************* */ 386 387static int smbus_24lc128_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 388{ 389 smbus_24lc128_t *softc = ctx->dev_softc; 390 nvram_info_t info; 391 392 switch ((int)buffer->buf_ioctlcmd) { 393 case IOCTL_NVRAM_GETINFO: 394 if (buffer->buf_length != sizeof(nvram_info_t)) return -1; 395 info.nvram_offset = softc->env_offset; 396 info.nvram_size = softc->env_size; 397 info.nvram_eraseflg = FALSE; 398 buffer->buf_retlen = sizeof(nvram_info_t); 399 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info)); 400 return 0; 401 default: 402 return -1; 403 } 404} 405 406/* ********************************************************************* 407 * smbus_24lc128_close(ctx,buffer) 408 * 409 * Close the device. 410 * 411 * Input parameters: 412 * ctx - device context (can obtain our softc here) 413 * 414 * Return value: 415 * 0 if ok 416 * -1 if an error occured 417 ********************************************************************* */ 418 419static int smbus_24lc128_close(cfe_devctx_t *ctx) 420{ 421 return 0; 422} 423 424 425