1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Xicor RTC/EEPROM driver File: dev_smbus_x1240eeprom.c 5 * 6 * This module contains a CFE driver for a Xicor X1240 SMBus 7 * real-time-clock & EEPROM module. The only functionality 8 * we currently export is the EEPROM, for use as environment 9 * storage. 10 * 11 * Author: Mitch Lichtenberg 12 * 13 ********************************************************************* 14 * 15 * Copyright 2000,2001,2002,2003 16 * Broadcom Corporation. All rights reserved. 17 * 18 * This software is furnished under license and may be used and 19 * copied only in accordance with the following terms and 20 * conditions. Subject to these conditions, you may download, 21 * copy, install, use, modify and distribute modified or unmodified 22 * copies of this software in source and/or binary form. No title 23 * or ownership is transferred hereby. 24 * 25 * 1) Any source code used, modified or distributed must reproduce 26 * and retain this copyright notice and list of conditions 27 * as they appear in the source file. 28 * 29 * 2) No right is granted to use any trade name, trademark, or 30 * logo of Broadcom Corporation. The "Broadcom Corporation" 31 * name may not be used to endorse or promote products derived 32 * from this software without the prior written permission of 33 * Broadcom Corporation. 34 * 35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 47 * THE POSSIBILITY OF SUCH DAMAGE. 48 ********************************************************************* */ 49 50 51#include "cfe.h" 52#include "cfe_smbus.h" 53 54 55/* ********************************************************************* 56 * Xicor X1241 RTC constants 57 ********************************************************************* */ 58 59/* 60 * Register bits 61 */ 62 63#define X1241REG_SR_BAT 0x80 /* currently on battery power */ 64#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ 65#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ 66#define X1241REG_SR_RTCF 0x01 /* clock failed */ 67#define X1241REG_BL_BP2 0x80 /* block protect 2 */ 68#define X1241REG_BL_BP1 0x40 /* block protect 1 */ 69#define X1241REG_BL_BP0 0x20 /* block protect 0 */ 70#define X1241REG_BL_WD1 0x10 71#define X1241REG_BL_WD0 0x08 72#define X1241REG_HR_MIL 0x80 /* military time format */ 73 74/* 75 * Register numbers 76 */ 77 78#define X1241REG_BL 0x10 /* block protect bits */ 79#define X1241REG_INT 0x11 /* */ 80#define X1241REG_SC 0x30 /* Seconds */ 81#define X1241REG_MN 0x31 /* Minutes */ 82#define X1241REG_HR 0x32 /* Hours */ 83#define X1241REG_DT 0x33 /* Day of month */ 84#define X1241REG_MO 0x34 /* Month */ 85#define X1241REG_YR 0x35 /* Year */ 86#define X1241REG_DW 0x36 /* Day of Week */ 87#define X1241REG_Y2K 0x37 /* Year 2K */ 88#define X1241REG_SR 0x3F /* Status register */ 89 90#define X1241_CCR_ADDRESS 0x6F 91#define X1241_ARRAY_ADDRESS 0x57 92 93#define X1241_EEPROM_SIZE 2048 94 95/* ********************************************************************* 96 * Forward Declarations 97 ********************************************************************* */ 98 99static void sb1250_x1240eeprom_probe(cfe_driver_t *drv, 100 unsigned long probe_a, unsigned long probe_b, 101 void *probe_ptr); 102 103 104static int sb1250_x1240eeprom_open(cfe_devctx_t *ctx); 105static int sb1250_x1240eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 106static int sb1250_x1240eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 107static int sb1250_x1240eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 108static int sb1250_x1240eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 109static int sb1250_x1240eeprom_close(cfe_devctx_t *ctx); 110 111/* ********************************************************************* 112 * Dispatch tables 113 ********************************************************************* */ 114 115const static cfe_devdisp_t sb1250_x1240eeprom_dispatch = { 116 sb1250_x1240eeprom_open, 117 sb1250_x1240eeprom_read, 118 sb1250_x1240eeprom_inpstat, 119 sb1250_x1240eeprom_write, 120 sb1250_x1240eeprom_ioctl, 121 sb1250_x1240eeprom_close, 122 NULL, 123 NULL 124}; 125 126const cfe_driver_t smbus_x1240eeprom = { 127 "Xicor X1241 EEPROM", 128 "eeprom", 129 CFE_DEV_NVRAM, 130 &sb1250_x1240eeprom_dispatch, 131 sb1250_x1240eeprom_probe 132}; 133 134typedef struct sb1250_x1240eeprom_s { 135 cfe_smbus_channel_t *smbus_channel; 136 int env_offset; 137 int env_size; 138} sb1250_x1240eeprom_t; 139 140 141 142 143/* ********************************************************************* 144 * smbus_readrtc(chan,slaveaddr,devaddr) 145 * 146 * Read a byte from the chip. The 'slaveaddr' parameter determines 147 * whether we're reading from the RTC section or the EEPROM section. 148 * 149 * Input parameters: 150 * chan - SMBus channel 151 * slaveaddr - SMBus slave address 152 * devaddr - byte with in the X1240 device to read 153 * 154 * Return value: 155 * 0 if ok 156 * else -1 157 ********************************************************************* */ 158 159static int smbus_readrtc(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr) 160{ 161 uint8_t buf[2]; 162 int err; 163 164 /* 165 * Write the device address to the controller. There are two 166 * parts, the high part goes in the "CMD" field, and the 167 * low part is the data field. 168 */ 169 170 buf[0] = (devaddr >> 8) & 0x07; 171 buf[1] = (devaddr & 0xFF); 172 173 err = SMBUS_WRITE(chan,slaveaddr,buf,2); 174 if (err < 0) return err; 175 176 /* 177 * Read the data byte 178 */ 179 180 err = SMBUS_READ(chan,slaveaddr,buf,1); 181 if (err < 0) return err; 182 183 return (buf[0]); 184} 185 186/* ********************************************************************* 187 * smbus_writertc(chan,slaveaddr,devaddr,b) 188 * 189 * write a byte from the chip. The 'slaveaddr' parameter determines 190 * whethe we're writing to the RTC section or the EEPROM section. 191 * 192 * Input parameters: 193 * chan - SMBus channel 194 * slaveaddr - SMBus slave address 195 * devaddr - byte with in the X1240 device to read 196 * b - byte to write 197 * 198 * Return value: 199 * 0 if ok 200 * else -1 201 ********************************************************************* */ 202 203 204static int smbus_writertc(cfe_smbus_channel_t *chan,int slaveaddr,int devaddr,int b) 205{ 206 uint8_t buf[3]; 207 int err; 208 int64_t timer; 209 210 211 /* 212 * Write the data to the controller 213 */ 214 215 216 buf[0] = (devaddr >> 8) & 0x07; 217 buf[1] = (devaddr & 0xFF); 218 buf[2] = b; 219 220 err = SMBUS_WRITE(chan,slaveaddr,buf,3); 221 if (err < 0) return err; 222 223 /* 224 * Pound on the device with a current address read 225 * to poll for the write complete 226 */ 227 228 TIMER_SET(timer,50); 229 err = -1; 230 231 while (!TIMER_EXPIRED(timer)) { 232 POLL(); 233 234 err = SMBUS_READ(chan,slaveaddr,buf,1); 235 if (err == 0) break; 236 } 237 238 return err; 239} 240 241 242/* ********************************************************************* 243 * sb1250_x1240eeprom_probe(drv,a,b,ptr) 244 * 245 * Probe routine for this driver. This routine creates the 246 * local device context and attaches it to the driver list 247 * within CFE. 248 * 249 * Input parameters: 250 * drv - driver handle 251 * a,b - probe hints (longs) 252 * ptr - probe hint (pointer) 253 * 254 * Return value: 255 * nothing 256 ********************************************************************* */ 257 258static void sb1250_x1240eeprom_probe(cfe_driver_t *drv, 259 unsigned long probe_a, unsigned long probe_b, 260 void *probe_ptr) 261{ 262 sb1250_x1240eeprom_t *softc; 263 char descr[80]; 264 265 softc = (sb1250_x1240eeprom_t *) KMALLOC(sizeof(sb1250_x1240eeprom_t),0); 266 267 /* 268 * Probe_a is the SMBus channel number 269 * Probe_b is the SMBus device offset 270 * Probe_ptr is unused. 271 */ 272 273 softc->smbus_channel = SMBUS_CHANNEL((int)probe_a); 274 softc->env_offset = 0; 275 softc->env_size = X1241_EEPROM_SIZE; 276 277 xsprintf(descr,"%s on SMBus channel %d dev 0x%02X", 278 drv->drv_description,probe_a,X1241_ARRAY_ADDRESS); 279 cfe_attach(drv,softc,NULL,descr); 280} 281 282 283 284/* ********************************************************************* 285 * sb1250_x1240eeprom_open(ctx) 286 * 287 * Open this device. For the X1240, we do a quick test 288 * read to be sure the device is out there. 289 * 290 * Input parameters: 291 * ctx - device context (can obtain our softc here) 292 * 293 * Return value: 294 * 0 if ok 295 * else error code 296 ********************************************************************* */ 297 298static int sb1250_x1240eeprom_open(cfe_devctx_t *ctx) 299{ 300 sb1250_x1240eeprom_t *softc = ctx->dev_softc; 301 int b; 302 int64_t timer; 303 304 /* 305 * Try to read byte 0 from the device. If it does not 306 * respond, fail the open. We may need to do this for 307 * up to 300ms in case the X1240 is busy wiggling its 308 * RESET line. 309 */ 310 311 TIMER_SET(timer,300); 312 while (!TIMER_EXPIRED(timer)) { 313 POLL(); 314 b = smbus_readrtc(softc->smbus_channel, 315 X1241_ARRAY_ADDRESS, 316 0); 317 if (b >= 0) break; /* read is ok */ 318 } 319 320 /* 321 * See if the watchdog is enabled. If it is, turn it off. 322 */ 323 324 b = smbus_readrtc(softc->smbus_channel, 325 X1241_CCR_ADDRESS, 326 X1241REG_BL); 327 328 if (b != (X1241REG_BL_WD1 | X1241REG_BL_WD0)) { 329 330 smbus_writertc(softc->smbus_channel, 331 X1241_CCR_ADDRESS, 332 X1241REG_SR, 333 X1241REG_SR_WEL); 334 335 smbus_writertc(softc->smbus_channel, 336 X1241_CCR_ADDRESS, 337 X1241REG_SR, 338 X1241REG_SR_WEL | X1241REG_SR_RWEL); 339 340 smbus_writertc(softc->smbus_channel, 341 X1241_CCR_ADDRESS, 342 X1241REG_BL, 343 (X1241REG_BL_WD1 | X1241REG_BL_WD0)); 344 345 smbus_writertc(softc->smbus_channel, 346 X1241_CCR_ADDRESS, 347 X1241REG_SR, 348 0); 349 } 350 351 352 353 return (b < 0) ? -1 : 0; 354} 355 356/* ********************************************************************* 357 * sb1250_x1240eeprom_read(ctx,buffer) 358 * 359 * Read bytes from the device. 360 * 361 * Input parameters: 362 * ctx - device context (can obtain our softc here) 363 * buffer - buffer descriptor (target buffer, length, offset) 364 * 365 * Return value: 366 * number of bytes read 367 * -1 if an error occured 368 ********************************************************************* */ 369 370static int sb1250_x1240eeprom_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 371{ 372 sb1250_x1240eeprom_t *softc = ctx->dev_softc; 373 hsaddr_t bptr; 374 int blen; 375 int idx; 376 int b = 0; 377 378 bptr = buffer->buf_ptr; 379 blen = buffer->buf_length; 380 381 if ((buffer->buf_offset + blen) > X1241_EEPROM_SIZE) return -1; 382 383 idx = (int) buffer->buf_offset; 384 385 while (blen > 0) { 386 b = smbus_readrtc(softc->smbus_channel, 387 X1241_ARRAY_ADDRESS, 388 idx); 389 if (b < 0) break; 390 hs_write8(bptr,(unsigned char)b); 391 bptr++; 392 blen--; 393 idx++; 394 } 395 396 buffer->buf_retlen = bptr - buffer->buf_ptr; 397 return (b < 0) ? -1 : 0; 398} 399 400/* ********************************************************************* 401 * sb1250_x1240eeprom_inpstat(ctx,inpstat) 402 * 403 * Test input (read) status for the device 404 * 405 * Input parameters: 406 * ctx - device context (can obtain our softc here) 407 * inpstat - input status descriptor to receive value 408 * 409 * Return value: 410 * 0 if ok 411 * -1 if an error occured 412 ********************************************************************* */ 413 414static int sb1250_x1240eeprom_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 415{ 416 inpstat->inp_status = 1; 417 418 return 0; 419} 420 421/* ********************************************************************* 422 * sb1250_x1240eeprom_write(ctx,buffer) 423 * 424 * Write bytes from the device. 425 * 426 * Input parameters: 427 * ctx - device context (can obtain our softc here) 428 * buffer - buffer descriptor (target buffer, length, offset) 429 * 430 * Return value: 431 * number of bytes read 432 * -1 if an error occured 433 ********************************************************************* */ 434 435static int sb1250_x1240eeprom_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 436{ 437 sb1250_x1240eeprom_t *softc = ctx->dev_softc; 438 hsaddr_t bptr; 439 int blen; 440 int idx; 441 int b = 0; 442 443 bptr = buffer->buf_ptr; 444 blen = buffer->buf_length; 445 446 if ((buffer->buf_offset + blen) > X1241_EEPROM_SIZE) return -1; 447 448 idx = (int) buffer->buf_offset; 449 450 smbus_writertc(softc->smbus_channel, 451 X1241_CCR_ADDRESS, 452 X1241REG_SR, 453 X1241REG_SR_WEL); 454 455 456 while (blen > 0) { 457 b = hs_read8(bptr); 458 bptr++; 459 b = smbus_writertc(softc->smbus_channel, 460 X1241_ARRAY_ADDRESS, 461 idx, 462 b); 463 if (b < 0) break; 464 blen--; 465 idx++; 466 } 467 468 smbus_writertc(softc->smbus_channel, 469 X1241_CCR_ADDRESS, 470 X1241REG_SR, 471 0); 472 473 buffer->buf_retlen = bptr - buffer->buf_ptr; 474 return (b < 0) ? -1 : 0; 475} 476 477/* ********************************************************************* 478 * sb1250_x1240eeprom_ioctl(ctx,buffer) 479 * 480 * Perform miscellaneous I/O control operations on the device. 481 * 482 * Input parameters: 483 * ctx - device context (can obtain our softc here) 484 * buffer - buffer descriptor (target buffer, length, offset) 485 * 486 * Return value: 487 * number of bytes read 488 * -1 if an error occured 489 ********************************************************************* */ 490 491static int sb1250_x1240eeprom_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 492{ 493 sb1250_x1240eeprom_t *softc = ctx->dev_softc; 494 nvram_info_t info; 495 496 switch ((int)buffer->buf_ioctlcmd) { 497 case IOCTL_NVRAM_GETINFO: 498 if (buffer->buf_length != sizeof(nvram_info_t)) return -1; 499 info.nvram_offset = softc->env_offset; 500 info.nvram_size = softc->env_size; 501 info.nvram_eraseflg = FALSE; 502 buffer->buf_retlen = sizeof(nvram_info_t); 503 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info)); 504 return 0; 505 default: 506 return -1; 507 } 508} 509 510/* ********************************************************************* 511 * sb1250_x1240eeprom_close(ctx,buffer) 512 * 513 * Close the device. 514 * 515 * Input parameters: 516 * ctx - device context (can obtain our softc here) 517 * 518 * Return value: 519 * 0 if ok 520 * -1 if an error occured 521 ********************************************************************* */ 522 523static int sb1250_x1240eeprom_close(cfe_devctx_t *ctx) 524{ 525 return 0; 526} 527 528 529