1180811Sstas/*- 2180811Sstas * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>, 3181602Sraj * Rafal Jaworowski <raj@FreeBSD.org>, 4181602Sraj * Piotr Ziecik <kosmo@semihalf.com>. 5180811Sstas * All rights reserved. 6180811Sstas * 7180811Sstas * Redistribution and use in source and binary forms, with or without 8180811Sstas * modification, are permitted provided that the following conditions 9180811Sstas * are met: 10180811Sstas * 1. Redistributions of source code must retain the above copyright 11180811Sstas * notice, this list of conditions and the following disclaimer. 12180811Sstas * 2. Redistributions in binary form must reproduce the above copyright 13180811Sstas * notice, this list of conditions and the following disclaimer in the 14180811Sstas * documentation and/or other materials provided with the distribution. 15180811Sstas * 16180811Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17180811Sstas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18180811Sstas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19180811Sstas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20180811Sstas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21180811Sstas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22180811Sstas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23180811Sstas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24180811Sstas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25180811Sstas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26180811Sstas */ 27180811Sstas 28180811Sstas#include <sys/cdefs.h> 29180811Sstas__FBSDID("$FreeBSD$"); 30180811Sstas/* 31181602Sraj * Dallas Semiconductor DS133X RTC sitting on the I2C bus. 32180811Sstas */ 33180811Sstas#include <sys/param.h> 34180811Sstas#include <sys/systm.h> 35180811Sstas#include <sys/kernel.h> 36180811Sstas#include <sys/module.h> 37180811Sstas#include <sys/clock.h> 38180811Sstas#include <sys/time.h> 39180811Sstas#include <sys/bus.h> 40180811Sstas#include <sys/resource.h> 41180811Sstas#include <sys/rman.h> 42180811Sstas 43180811Sstas#include <dev/iicbus/iicbus.h> 44180811Sstas#include <dev/iicbus/iiconf.h> 45180811Sstas 46180811Sstas#include "iicbus_if.h" 47180811Sstas#include "clock_if.h" 48180811Sstas 49191369Sstas#define DS133X_DEVNAME "ds133x_rtc" 50182870Sraj 51181602Sraj#define DS133X_ADDR 0xd0 /* slave address */ 52181602Sraj#define DS133X_DATE_REG 0x0 53181602Sraj#define DS133X_CTRL_REG 0x0e 54181602Sraj#define DS133X_OSCD_FLAG 0x80 55181602Sraj#define DS133X_OSF_FLAG 0x80 56180811Sstas 57181602Sraj#define DS133X_24H_FLAG 0x40 /* 24 hours mode. */ 58181602Sraj#define DS133X_PM_FLAG 0x20 /* AM/PM bit. */ 59181602Sraj#define DS133X_CENT_FLAG 0x80 /* Century selector. */ 60181602Sraj#define DS133X_CENT_SHIFT 7 61180811Sstas 62181602Sraj#define DS1338_REG_CLOCK_HALT 0x00 63181602Sraj#define DS1338_REG_CONTROL 0x07 64181602Sraj#define DS1338_CLOCK_HALT (1 << 7) 65181602Sraj#define DS1338_OSC_STOP (1 << 5) 66180811Sstas 67181602Sraj#define DS1339_REG_CONTROL 0x0E 68181602Sraj#define DS1339_REG_STATUS 0x0F 69181602Sraj#define DS1339_OSC_STOP (1 << 7) 70181602Sraj#define DS1339_ENABLE_OSC (1 << 7) 71181602Sraj#define DS1339_BBSQI (1 << 5) 72181602Sraj 73181602Sraj#define HALFSEC 500000000 /* 1/2 of second. */ 74181602Sraj 75181602Sraj#define MAX_IIC_DATA_SIZE 7 76181602Sraj 77181602Srajenum { 78181602Sraj DS1337, 79181602Sraj DS1338, 80181602Sraj DS1339, 81180811Sstas}; 82180811Sstas 83181602Srajstruct ds133x_softc { 84181602Sraj int sc_type; 85181602Sraj device_t sc_dev; 86181602Sraj}; 87181602Sraj 88180811Sstasstatic int 89181602Srajds133x_read(device_t dev, uint8_t address, uint8_t *data, uint8_t size) 90180811Sstas{ 91181602Sraj struct iic_msg msg[] = { 92181602Sraj { DS133X_ADDR, IIC_M_WR, 1, &address }, 93181602Sraj { DS133X_ADDR, IIC_M_RD, size, data }, 94181602Sraj }; 95180811Sstas 96181602Sraj return (iicbus_transfer(dev, msg, 2)); 97181602Sraj} 98181602Sraj 99181602Srajstatic int 100181602Srajds133x_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size) 101181602Sraj{ 102181602Sraj uint8_t buffer[MAX_IIC_DATA_SIZE + 1]; 103181602Sraj struct iic_msg msg[] = { 104181602Sraj { DS133X_ADDR, IIC_M_WR, size + 1, buffer }, 105181602Sraj }; 106181602Sraj 107181602Sraj if (size > MAX_IIC_DATA_SIZE) 108181602Sraj return (ENOMEM); 109181602Sraj 110181602Sraj buffer[0] = address; 111181602Sraj memcpy(buffer + 1, data, size); 112181602Sraj 113181602Sraj return (iicbus_transfer(dev, msg, 1)); 114181602Sraj} 115181602Sraj 116181602Srajstatic int 117181602Srajds133x_detect(device_t dev, int *sc_type) 118181602Sraj{ 119181602Sraj int error; 120181602Sraj uint8_t reg, orig; 121181602Sraj 122181602Sraj /* 123181602Sraj * Check for DS1338. At address 0x0F this chip has RAM, however 124181602Sraj * DS1337 and DS1339 have status register. Bits 6-2 in status 125181602Sraj * register will be always read as 0. 126181602Sraj */ 127181602Sraj 128181602Sraj if ((error = ds133x_read(dev, DS1339_REG_STATUS, ®, 1))) 129181602Sraj return (error); 130181602Sraj 131181602Sraj orig = reg; 132181602Sraj reg |= 0x7C; 133181602Sraj 134181602Sraj if ((error = ds133x_write(dev, DS1339_REG_STATUS, ®, 1))) 135181602Sraj return (error); 136181602Sraj 137181602Sraj if ((error = ds133x_read(dev, DS1339_REG_STATUS, ®, 1))) 138181602Sraj return (error); 139181602Sraj 140181602Sraj if ((reg & 0x7C) != 0) { 141181602Sraj /* This is DS1338 */ 142181602Sraj 143181602Sraj if ((error = ds133x_write(dev, DS1339_REG_STATUS, &orig, 1))) 144181602Sraj return (error); 145181602Sraj 146181602Sraj *sc_type = DS1338; 147181602Sraj 148181602Sraj return (0); 149180811Sstas } 150181602Sraj 151181602Sraj /* 152181602Sraj * Now Check for DS1337. Bit 5 in control register of this chip will be 153181602Sraj * allways read as 0. In DS1339 changing of this bit is safe until 154181602Sraj * chip is powered up. 155181602Sraj */ 156181602Sraj 157181602Sraj if ((error = ds133x_read(dev, DS1339_REG_CONTROL, ®, 1))) 158181602Sraj return (error); 159181602Sraj 160181602Sraj orig = reg; 161181602Sraj reg |= DS1339_BBSQI; 162181602Sraj 163181602Sraj if ((error = ds133x_write(dev, DS1339_REG_CONTROL, ®, 1))) 164181602Sraj return (error); 165181602Sraj 166181602Sraj if ((error = ds133x_read(dev, DS1339_REG_CONTROL, ®, 1))) 167181602Sraj return (error); 168181602Sraj 169181602Sraj if ((reg & DS1339_BBSQI) != 0) { 170181602Sraj /* This is DS1339 */ 171181602Sraj 172181602Sraj if ((error = ds133x_write(dev, DS1339_REG_CONTROL, &orig, 1))) 173181602Sraj return (error); 174181602Sraj 175181602Sraj *sc_type = DS1339; 176181602Sraj return (0); 177181602Sraj } 178181602Sraj 179181602Sraj /* This is DS1337 */ 180181602Sraj *sc_type = DS1337; 181181602Sraj 182180811Sstas return (0); 183180811Sstas} 184180811Sstas 185180811Sstasstatic int 186181602Srajds133x_init(device_t dev, uint8_t cs_reg, uint8_t cs_bit, uint8_t osf_reg, 187181602Sraj uint8_t osf_bit) 188180811Sstas{ 189180811Sstas int error; 190181602Sraj uint8_t reg; 191180811Sstas 192181602Sraj if ((error = ds133x_read(dev, cs_reg, ®, 1))) 193181602Sraj return (error); 194180811Sstas 195181602Sraj if (reg & cs_bit) { /* If clock is stopped - start it */ 196181602Sraj reg &= ~cs_bit; 197181602Sraj if ((error = ds133x_write(dev, cs_reg, ®, 1))) 198181602Sraj return (error); 199181602Sraj } 200180811Sstas 201181602Sraj if ((error = ds133x_read(dev, osf_reg, ®, 1))) 202181602Sraj return (error); 203181602Sraj 204181602Sraj if (reg & osf_bit) { /* Clear oscillator stop flag */ 205181602Sraj device_printf(dev, "RTC oscillator was stopped. Check system" 206181602Sraj " time and RTC battery.\n"); 207181602Sraj reg &= ~osf_bit; 208181602Sraj if ((error = ds133x_write(dev, osf_reg, ®, 1))) 209181602Sraj return (error); 210180811Sstas } 211180811Sstas 212181602Sraj return (0); 213181602Sraj} 214180811Sstas 215182870Sraj 216182870Srajstatic void 217182870Srajds133x_identify(driver_t *driver, device_t parent) 218182870Sraj{ 219182870Sraj 220182870Sraj if (device_find_child(parent, DS133X_DEVNAME, -1) == NULL) 221182870Sraj BUS_ADD_CHILD(parent, 0, DS133X_DEVNAME, -1); 222182870Sraj} 223182870Sraj 224181602Srajstatic int 225181602Srajds133x_probe(device_t dev) 226181602Sraj{ 227181602Sraj struct ds133x_softc *sc; 228181602Sraj int error; 229180811Sstas 230181602Sraj sc = device_get_softc(dev); 231180811Sstas 232181602Sraj if ((error = ds133x_detect(dev, &sc->sc_type))) 233181602Sraj return (error); 234181602Sraj 235181602Sraj switch (sc->sc_type) { 236181602Sraj case DS1337: 237181602Sraj device_set_desc(dev, "Dallas Semiconductor DS1337 RTC"); 238181602Sraj break; 239181602Sraj case DS1338: 240181602Sraj device_set_desc(dev, "Dallas Semiconductor DS1338 RTC"); 241181602Sraj break; 242181602Sraj case DS1339: 243181602Sraj device_set_desc(dev, "Dallas Semiconductor DS1339 RTC"); 244181602Sraj break; 245181602Sraj default: 246181602Sraj break; 247180811Sstas } 248180811Sstas 249181602Sraj return (0); 250181602Sraj} 251180811Sstas 252181602Srajstatic int 253181602Srajds133x_attach(device_t dev) 254181602Sraj{ 255181602Sraj struct ds133x_softc *sc = device_get_softc(dev); 256181602Sraj 257181602Sraj sc->sc_dev = dev; 258181602Sraj 259181602Sraj if (sc->sc_type == DS1338) 260181602Sraj ds133x_init(dev, DS1338_REG_CLOCK_HALT, DS1338_CLOCK_HALT, 261181602Sraj DS1338_REG_CONTROL, DS1338_OSC_STOP); 262181602Sraj else 263181602Sraj ds133x_init(dev, DS1339_REG_CONTROL, DS1339_ENABLE_OSC, 264181602Sraj DS1339_REG_STATUS, DS1339_OSC_STOP); 265181602Sraj 266180811Sstas clock_register(dev, 1000000); 267181602Sraj 268180811Sstas return (0); 269180811Sstas} 270180811Sstas 271180811Sstasstatic uint8_t 272181602Srajds133x_get_hours(uint8_t val) 273180811Sstas{ 274180811Sstas uint8_t ret; 275180811Sstas 276181602Sraj if (!(val & DS133X_24H_FLAG)) 277180811Sstas ret = FROMBCD(val & 0x3f); 278181602Sraj else if (!(val & DS133X_PM_FLAG)) 279180811Sstas ret = FROMBCD(val & 0x1f); 280180811Sstas else 281180811Sstas ret = FROMBCD(val & 0x1f) + 12; 282180811Sstas 283180811Sstas return (ret); 284180811Sstas} 285180811Sstas 286180811Sstasstatic int 287181602Srajds133x_gettime(device_t dev, struct timespec *ts) 288180811Sstas{ 289181602Sraj struct ds133x_softc *sc = device_get_softc(dev); 290181602Sraj struct clocktime ct; 291180811Sstas uint8_t date[7]; 292180811Sstas int error; 293180811Sstas 294181602Sraj error = ds133x_read(dev, DS133X_DATE_REG, date, 7); 295180811Sstas if (error == 0) { 296180811Sstas ct.nsec = 0; 297180811Sstas ct.sec = FROMBCD(date[0] & 0x7f); 298180811Sstas ct.min = FROMBCD(date[1] & 0x7f); 299181602Sraj ct.hour = ds133x_get_hours(date[2]); 300180811Sstas ct.dow = FROMBCD(date[3] & 0x07) - 1; 301180811Sstas ct.day = FROMBCD(date[4] & 0x3f); 302180811Sstas ct.mon = FROMBCD(date[5] & 0x1f); 303180811Sstas 304181602Sraj if (sc->sc_type == DS1338) 305181602Sraj ct.year = 2000 + FROMBCD(date[6]); 306181602Sraj else 307181602Sraj ct.year = 1900 + FROMBCD(date[6]) + 308181602Sraj ((date[5] & DS133X_CENT_FLAG) >> DS133X_CENT_SHIFT) * 100; 309181602Sraj 310180811Sstas error = clock_ct_to_ts(&ct, ts); 311180811Sstas } 312180811Sstas 313181602Sraj return (error); 314180811Sstas} 315180811Sstas 316180811Sstasstatic int 317181602Srajds133x_settime(device_t dev, struct timespec *ts) 318180811Sstas{ 319181602Sraj struct ds133x_softc *sc = device_get_softc(dev); 320180811Sstas struct clocktime ct; 321181602Sraj uint8_t date[7]; 322180811Sstas 323180811Sstas clock_ts_to_ct(ts, &ct); 324180811Sstas 325181602Sraj date[0] = TOBCD(ct.nsec >= HALFSEC ? ct.sec + 1 : ct.sec) & 0x7f; 326181602Sraj date[1] = TOBCD(ct.min) & 0x7f; 327181602Sraj date[2] = TOBCD(ct.hour) & 0x3f; /* We use 24-hours mode. */ 328181602Sraj date[3] = TOBCD(ct.dow + 1) & 0x07; 329181602Sraj date[4] = TOBCD(ct.day) & 0x3f; 330181602Sraj date[5] = TOBCD(ct.mon) & 0x1f; 331181602Sraj if (sc->sc_type == DS1338) 332181602Sraj date[6] = TOBCD(ct.year - 2000); 333181602Sraj else if (ct.year >= 2000) { 334181602Sraj date[5] |= DS133X_CENT_FLAG; 335181602Sraj date[6] = TOBCD(ct.year - 2000); 336180811Sstas } else 337181602Sraj date[6] = TOBCD(ct.year - 1900); 338180811Sstas 339181602Sraj return (ds133x_write(dev, DS133X_DATE_REG, date, 7)); 340180811Sstas} 341180811Sstas 342181602Srajstatic device_method_t ds133x_methods[] = { 343182870Sraj DEVMETHOD(device_identify, ds133x_identify), 344181602Sraj DEVMETHOD(device_probe, ds133x_probe), 345181602Sraj DEVMETHOD(device_attach, ds133x_attach), 346180811Sstas 347181602Sraj DEVMETHOD(clock_gettime, ds133x_gettime), 348181602Sraj DEVMETHOD(clock_settime, ds133x_settime), 349180811Sstas 350246128Ssbz DEVMETHOD_END 351180811Sstas}; 352180811Sstas 353181602Srajstatic driver_t ds133x_driver = { 354182870Sraj DS133X_DEVNAME, 355181602Sraj ds133x_methods, 356181602Sraj sizeof(struct ds133x_softc), 357180811Sstas}; 358180811Sstas 359181602Srajstatic devclass_t ds133x_devclass; 360181602Sraj 361181602SrajDRIVER_MODULE(ds133x, iicbus, ds133x_driver, ds133x_devclass, 0, 0); 362181602SrajMODULE_VERSION(ds133x, 1); 363181602SrajMODULE_DEPEND(ds133x, iicbus, 1, 1, 1); 364