linux/drivers/rtc/rtc-ds3234.c
<<
>>
Prefs
   1/* rtc-ds3234.c
   2 *
   3 * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
   4 * and SRAM.
   5 *
   6 * Copyright (C) 2008 MIMOMax Wireless Ltd.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/device.h>
  17#include <linux/platform_device.h>
  18#include <linux/rtc.h>
  19#include <linux/spi/spi.h>
  20#include <linux/bcd.h>
  21
  22#define DS3234_REG_SECONDS      0x00
  23#define DS3234_REG_MINUTES      0x01
  24#define DS3234_REG_HOURS        0x02
  25#define DS3234_REG_DAY          0x03
  26#define DS3234_REG_DATE         0x04
  27#define DS3234_REG_MONTH        0x05
  28#define DS3234_REG_YEAR         0x06
  29#define DS3234_REG_CENTURY      (1 << 7) /* Bit 7 of the Month register */
  30
  31#define DS3234_REG_CONTROL      0x0E
  32#define DS3234_REG_CONT_STAT    0x0F
  33
  34static int ds3234_set_reg(struct device *dev, unsigned char address,
  35                                unsigned char data)
  36{
  37        struct spi_device *spi = to_spi_device(dev);
  38        unsigned char buf[2];
  39
  40        /* MSB must be '1' to indicate write */
  41        buf[0] = address | 0x80;
  42        buf[1] = data;
  43
  44        return spi_write_then_read(spi, buf, 2, NULL, 0);
  45}
  46
  47static int ds3234_get_reg(struct device *dev, unsigned char address,
  48                                unsigned char *data)
  49{
  50        struct spi_device *spi = to_spi_device(dev);
  51
  52        *data = address & 0x7f;
  53
  54        return spi_write_then_read(spi, data, 1, data, 1);
  55}
  56
  57static int ds3234_read_time(struct device *dev, struct rtc_time *dt)
  58{
  59        int err;
  60        unsigned char buf[8];
  61        struct spi_device *spi = to_spi_device(dev);
  62
  63        buf[0] = 0x00; /* Start address */
  64
  65        err = spi_write_then_read(spi, buf, 1, buf, 8);
  66        if (err != 0)
  67                return err;
  68
  69        /* Seconds, Minutes, Hours, Day, Date, Month, Year */
  70        dt->tm_sec      = bcd2bin(buf[0]);
  71        dt->tm_min      = bcd2bin(buf[1]);
  72        dt->tm_hour     = bcd2bin(buf[2] & 0x3f);
  73        dt->tm_wday     = bcd2bin(buf[3]) - 1; /* 0 = Sun */
  74        dt->tm_mday     = bcd2bin(buf[4]);
  75        dt->tm_mon      = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */
  76        dt->tm_year     = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
  77
  78        return rtc_valid_tm(dt);
  79}
  80
  81static int ds3234_set_time(struct device *dev, struct rtc_time *dt)
  82{
  83        ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
  84        ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
  85        ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
  86
  87        /* 0 = Sun */
  88        ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
  89        ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
  90
  91        /* 0 = Jan */
  92        ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
  93
  94        /* Assume 20YY although we just want to make sure not to go negative. */
  95        if (dt->tm_year > 100)
  96                dt->tm_year -= 100;
  97
  98        ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
  99
 100        return 0;
 101}
 102
 103static const struct rtc_class_ops ds3234_rtc_ops = {
 104        .read_time      = ds3234_read_time,
 105        .set_time       = ds3234_set_time,
 106};
 107
 108static int ds3234_probe(struct spi_device *spi)
 109{
 110        struct rtc_device *rtc;
 111        unsigned char tmp;
 112        int res;
 113
 114        spi->mode = SPI_MODE_3;
 115        spi->bits_per_word = 8;
 116        spi_setup(spi);
 117
 118        res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
 119        if (res != 0)
 120                return res;
 121
 122        /* Control settings
 123         *
 124         * CONTROL_REG
 125         * BIT 7        6       5       4       3       2       1       0
 126         *     EOSC     BBSQW   CONV    RS2     RS1     INTCN   A2IE    A1IE
 127         *
 128         *     0        0       0       1       1       1       0       0
 129         *
 130         * CONTROL_STAT_REG
 131         * BIT 7        6       5       4       3       2       1       0
 132         *     OSF      BB32kHz CRATE1  CRATE0  EN32kHz BSY     A2F     A1F
 133         *
 134         *     1        0       0       0       1       0       0       0
 135         */
 136        ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
 137        ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
 138
 139        ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
 140        ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
 141
 142        /* Print our settings */
 143        ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
 144        dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
 145
 146        ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
 147        dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
 148
 149        rtc = rtc_device_register("ds3234",
 150                                &spi->dev, &ds3234_rtc_ops, THIS_MODULE);
 151        if (IS_ERR(rtc))
 152                return PTR_ERR(rtc);
 153
 154        dev_set_drvdata(&spi->dev, rtc);
 155
 156        return 0;
 157}
 158
 159static int ds3234_remove(struct spi_device *spi)
 160{
 161        struct rtc_device *rtc = spi_get_drvdata(spi);
 162
 163        rtc_device_unregister(rtc);
 164        return 0;
 165}
 166
 167static struct spi_driver ds3234_driver = {
 168        .driver = {
 169                .name    = "ds3234",
 170                .owner  = THIS_MODULE,
 171        },
 172        .probe   = ds3234_probe,
 173        .remove = ds3234_remove,
 174};
 175
 176module_spi_driver(ds3234_driver);
 177
 178MODULE_DESCRIPTION("DS3234 SPI RTC driver");
 179MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
 180MODULE_LICENSE("GPL");
 181MODULE_ALIAS("spi:ds3234");
 182