1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * DS17887-3 RTC driver File: dev_sb1250_ds17887clock.c 5 * 6 * This module contains a CFE driver for a DS17887-3 generic bus 7 * real-time-clock. 8 * 9 * Author: Mitch Lichtenberg (mpl@broadcom.com) 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48#include "lib_types.h" 49#include "lib_malloc.h" 50#include "lib_printf.h" 51#include "cfe_iocb.h" 52#include "cfe_device.h" 53#include "cfe_ioctl.h" 54 55#include "lib_physio.h" 56 57 58/* ********************************************************************* 59 * Constants 60 ********************************************************************* */ 61 62/* 63 * Register bits 64 */ 65 66#define DS17887REGA_UIP 0x80 /* Update-in-progress */ 67#define DS17887REGA_DV2 0x40 /* Countdown chain */ 68#define DS17887REGA_DV1 0x20 /* Oscillator enable */ 69#define DS17887REGA_DV0 0x10 /* Bank Select */ 70#define DS17887REGA_RS3 0x08 /* Rate-selection bits */ 71#define DS17887REGA_RS2 0x04 72#define DS17887REGA_RS1 0x02 73#define DS17887REGA_RS0 0x01 74 75#define DS17887REGB_SET 0x80 /* Set bit */ 76#define DS17887REGB_PIE 0x40 /* Periodic Interrupt Enable */ 77#define DS17887REGB_AIE 0x20 /* Alarm Interrupt Enable */ 78#define DS17887REGB_UIE 0x10 /* Update-ended Interrupt Enable */ 79#define DS17887REGB_SQWE 0x08 /* Square-wave Enable */ 80#define DS17887REGB_DM 0x04 /* Data Mode (binary) */ 81#define DS17887REGB_24 0x02 /* 24-hour mode control bit */ 82#define DS17887REGB_DSE 0x01 /* Daylight Savings Enable */ 83 84#define DS17887REGC_IRQF 0x80 /* Interrupt request flag */ 85#define DS17887REGC_PF 0x40 /* Periodic interrupt flag */ 86#define DS17887REGC_AF 0x20 /* Alarm interrupt flag */ 87#define DS17887REGC_UF 0x10 /* Update ended interrupt flag */ 88 89#define DS17887REGD_VRT 0x80 /* Valid RAM and time */ 90 91/* 92 * Register numbers 93 */ 94 95#define DS17887REG_SC 0x00 /* seconds */ 96#define DS17887REG_SCA 0x01 /* seconds alarm */ 97#define DS17887REG_MN 0x02 /* minutes */ 98#define DS17887REG_MNA 0x03 /* minutes alarm */ 99#define DS17887REG_HR 0x04 /* hours */ 100#define DS17887REG_HRA 0x05 /* hours alarm */ 101#define DS17887REG_DW 0x06 /* day of week */ 102#define DS17887REG_DM 0x07 /* day of month */ 103#define DS17887REG_MO 0x08 /* month */ 104#define DS17887REG_YR 0x09 /* year */ 105#define DS17887REG_A 0x0A /* register A */ 106#define DS17887REG_B 0x0B /* register B */ 107#define DS17887REG_C 0x0C /* register C */ 108#define DS17887REG_D 0x0D /* register D */ 109 110#define DS17887REG_CE 0x48 /* century (bank 1 only) */ 111 112#define BCD(x) (((x) % 10) + (((x) / 10) << 4)) 113#define SET_TIME 0x00 114#define SET_DATE 0x01 115 116#define WRITECSR(p,v) phys_write8((p),(v)) 117#define READCSR(p) phys_read8((p)) 118 119/* ********************************************************************* 120 * Forward declarations 121 ********************************************************************* */ 122 123static void ds17887_clock_probe(cfe_driver_t *drv, 124 unsigned long probe_a, unsigned long probe_b, 125 void *probe_ptr); 126 127static int ds17887_clock_open(cfe_devctx_t *ctx); 128static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 129static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 130static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 131static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 132static int ds17887_clock_close(cfe_devctx_t *ctx); 133 134 135/* ********************************************************************* 136 * Device dispatch 137 ********************************************************************* */ 138 139const static cfe_devdisp_t ds17887_clock_dispatch = { 140 ds17887_clock_open, 141 ds17887_clock_read, 142 ds17887_clock_inpstat, 143 ds17887_clock_write, 144 ds17887_clock_ioctl, 145 ds17887_clock_close, 146 NULL, 147 NULL 148}; 149 150const cfe_driver_t ds17887_clock = { 151 "DS17887 RTC", 152 "clock", 153 CFE_DEV_CLOCK, 154 &ds17887_clock_dispatch, 155 ds17887_clock_probe 156}; 157 158 159/* ********************************************************************* 160 * Structures 161 ********************************************************************* */ 162typedef struct ds17887_clock_s { 163 physaddr_t clock_base; 164} ds17887_clock_t; 165 166/* ********************************************************************* 167 * ds17887_clock_probe(drv,a,b,ptr) 168 * 169 * Probe routine for this driver. This routine creates the 170 * local device context and attaches it to the driver list 171 * within CFE. 172 * 173 * Input parameters: 174 * drv - driver handle 175 * a,b - probe hints (longs) 176 * ptr - probe hint (pointer) 177 * 178 * Return value: 179 * nothing 180 ********************************************************************* */ 181 182static void ds17887_clock_probe(cfe_driver_t *drv, 183 unsigned long probe_a, unsigned long probe_b, 184 void *probe_ptr) 185{ 186 ds17887_clock_t *softc; 187 char descr[80]; 188 189 softc = (ds17887_clock_t *) KMALLOC(sizeof(ds17887_clock_t),0); 190 191 /* 192 * Probe_a is the clock base address 193 * Probe_b is unused. 194 * Probe_ptr is unused. 195 */ 196 197 softc->clock_base = probe_a; 198 199 xsprintf(descr,"%s at 0x%X", 200 drv->drv_description,(uint32_t)probe_a); 201 cfe_attach(drv,softc,NULL,descr); 202 203} 204 205/* ********************************************************************* 206 * ds17887_clock_open(ctx) 207 * 208 * Open this device. For the DS17887, we do a quick test 209 * read to be sure the device is out there. 210 * 211 * Input parameters: 212 * ctx - device context (can obtain our softc here) 213 * 214 * Return value: 215 * 0 if ok 216 * else error code 217 ********************************************************************* */ 218 219static int ds17887_clock_open(cfe_devctx_t *ctx) 220{ 221 ds17887_clock_t *softc = ctx->dev_softc; 222 uint8_t byte; 223 physaddr_t clockbase; 224 225 clockbase = softc->clock_base; 226 227 /* Make sure battery is still good and RTC valid */ 228 if ( !(READCSR(clockbase+DS17887REG_D) & DS17887REGD_VRT) ) { 229 printf("Warning: Battery has failed. Clock setting is not accurate.\n"); 230 } 231 232 /* Switch to bank 1. Mainly for century byte */ 233 byte = (uint8_t) (READCSR(clockbase+DS17887REG_A) & 0xFF); 234 WRITECSR(clockbase+DS17887REG_A,DS17887REGA_DV0 | DS17887REGA_DV1 | byte); 235 236 /* Set data mode to BCD, 24-hour mode, and enable daylight savings */ 237 byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); 238 byte &= (~DS17887REGB_DM & ~DS17887REGB_AIE); 239 WRITECSR(clockbase+DS17887REG_B, DS17887REGB_24 | DS17887REGB_DSE | byte ); 240 241 return 0; 242} 243 244/* ********************************************************************* 245 * ds17887_clock_read(ctx,buffer) 246 * 247 * Read time/date from the RTC. Read a total of 8 bytes in this format: 248 * hour-minute-second-month-day-year1-year2 249 * 250 * Input parameters: 251 * ctx - device context (can obtain our softc here) 252 * buffer - buffer descriptor (target buffer, length, offset) 253 * 254 * Return value: 255 * number of bytes read 256 * -1 if an error occured 257 ********************************************************************* */ 258 259static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 260{ 261 262 ds17887_clock_t *softc = ctx->dev_softc; 263 unsigned char *bptr; 264 physaddr_t clockbase; 265 266 clockbase = softc->clock_base; 267 268 bptr = buffer->buf_ptr; 269 270 *bptr++ = READCSR(clockbase+DS17887REG_HR); 271 *bptr++ = READCSR(clockbase+DS17887REG_MN); 272 *bptr++ = READCSR(clockbase+DS17887REG_SC); 273 *bptr++ = READCSR(clockbase+DS17887REG_MO); 274 *bptr++ = READCSR(clockbase+DS17887REG_DM); 275 *bptr++ = READCSR(clockbase+DS17887REG_YR); 276 *bptr++ = READCSR(clockbase+DS17887REG_CE); 277 278 buffer->buf_retlen = 8; 279 return 0; 280} 281 282/* ********************************************************************* 283 * ds17887_clock_write(ctx,buffer) 284 * 285 * Write time/date to the RTC. Write in this format: 286 * hour-minute-second-month-day-year1-year2-(time/date flag) 287 * 288 * Input parameters: 289 * ctx - device context (can obtain our softc here) 290 * buffer - buffer descriptor (target buffer, length, offset) 291 * 292 * Return value: 293 * number of bytes written 294 * -1 if an error occured 295 ********************************************************************* */ 296 297static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 298{ 299 ds17887_clock_t *softc = ctx->dev_softc; 300 uint8_t byte; 301 unsigned char *bptr; 302 uint8_t hr,min,sec; 303 uint8_t mo,day,yr,y2k; 304 uint8_t timeDateFlag; 305 physaddr_t clockbase; 306 307 clockbase = softc->clock_base; 308 309 bptr = buffer->buf_ptr; 310 311 /* Set SET bit */ 312 byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); 313 WRITECSR(clockbase+DS17887REG_B,DS17887REGB_SET | byte); 314 315 timeDateFlag = *(bptr + 7); 316 317 /* write time or date */ 318 if(timeDateFlag == SET_TIME) { 319 320 hr = (uint8_t) *bptr; 321 WRITECSR(clockbase+DS17887REG_HR,BCD(hr)); 322 323 min = (uint8_t) *(bptr+1); 324 WRITECSR(clockbase+DS17887REG_MN,BCD(min)); 325 326 sec = (uint8_t) *(bptr+2); 327 WRITECSR(clockbase+DS17887REG_SC,BCD(sec)); 328 329 buffer->buf_retlen = 3; 330 } 331 else if(timeDateFlag == SET_DATE) { 332 333 mo = (uint8_t) *(bptr+3); 334 WRITECSR(clockbase+DS17887REG_MO,BCD(mo)); 335 336 day = (uint8_t) *(bptr+4); 337 WRITECSR(clockbase+DS17887REG_DM,BCD(day)); 338 339 yr = (uint8_t) *(bptr+5); 340 WRITECSR(clockbase+DS17887REG_YR,BCD(yr)); 341 342 y2k = (uint8_t) *(bptr+6); 343 WRITECSR(clockbase+DS17887REG_CE,y2k); 344 345 buffer->buf_retlen = 4; 346 } 347 else { 348 return -1; 349 } 350 351 /* clear SET bit */ 352 byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF); 353 WRITECSR(clockbase+DS17887REG_B,~DS17887REGB_SET & byte); 354 355 return 0; 356} 357 358/* ********************************************************************* 359 * ds17887_clock_inpstat(ctx,inpstat) 360 * 361 * Test input (read) status for the device 362 * 363 * Input parameters: 364 * ctx - device context (can obtain our softc here) 365 * inpstat - input status descriptor to receive value 366 * 367 * Return value: 368 * 0 if ok 369 * -1 if an error occured 370 ********************************************************************* */ 371 372static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 373{ 374 inpstat->inp_status = 1; 375 376 return 0; 377} 378 379/* ********************************************************************* 380 * ds17887_clock_ioctl(ctx,buffer) 381 * 382 * Perform miscellaneous I/O control operations on the device. 383 * 384 * Input parameters: 385 * ctx - device context (can obtain our softc here) 386 * buffer - buffer descriptor (target buffer, length, offset) 387 * 388 * Return value: 389 * number of bytes read 390 * -1 if an error occured 391 ********************************************************************* */ 392 393static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 394{ 395 return 0; 396} 397 398/* ********************************************************************* 399 * ds17887_clock_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 ds17887_clock_close(cfe_devctx_t *ctx) 412{ 413 return 0; 414} 415 416 417 418 419 420 421 422 423