3 * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
6 * Copyright (C) 2008 MIMOMax Wireless Ltd.
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.
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>
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 */
31 #define DS3234_REG_CONTROL 0x0E
32 #define DS3234_REG_CONT_STAT 0x0F
34 static int ds3234_set_reg(struct device
*dev
, unsigned char address
,
37 struct spi_device
*spi
= to_spi_device(dev
);
40 /* MSB must be '1' to indicate write */
41 buf
[0] = address
| 0x80;
44 return spi_write_then_read(spi
, buf
, 2, NULL
, 0);
47 static int ds3234_get_reg(struct device
*dev
, unsigned char address
,
50 struct spi_device
*spi
= to_spi_device(dev
);
52 *data
= address
& 0x7f;
54 return spi_write_then_read(spi
, data
, 1, data
, 1);
57 static int ds3234_read_time(struct device
*dev
, struct rtc_time
*dt
)
61 struct spi_device
*spi
= to_spi_device(dev
);
63 buf
[0] = 0x00; /* Start address */
65 err
= spi_write_then_read(spi
, buf
, 1, buf
, 8);
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 */
78 return rtc_valid_tm(dt
);
81 static int ds3234_set_time(struct device
*dev
, struct rtc_time
*dt
)
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);
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
));
92 ds3234_set_reg(dev
, DS3234_REG_MONTH
, bin2bcd(dt
->tm_mon
+ 1));
94 /* Assume 20YY although we just want to make sure not to go negative. */
95 if (dt
->tm_year
> 100)
98 ds3234_set_reg(dev
, DS3234_REG_YEAR
, bin2bcd(dt
->tm_year
));
103 static const struct rtc_class_ops ds3234_rtc_ops
= {
104 .read_time
= ds3234_read_time
,
105 .set_time
= ds3234_set_time
,
108 static int ds3234_probe(struct spi_device
*spi
)
110 struct rtc_device
*rtc
;
114 spi
->mode
= SPI_MODE_3
;
115 spi
->bits_per_word
= 8;
118 res
= ds3234_get_reg(&spi
->dev
, DS3234_REG_SECONDS
, &tmp
);
125 * BIT 7 6 5 4 3 2 1 0
126 * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
131 * BIT 7 6 5 4 3 2 1 0
132 * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
136 ds3234_get_reg(&spi
->dev
, DS3234_REG_CONTROL
, &tmp
);
137 ds3234_set_reg(&spi
->dev
, DS3234_REG_CONTROL
, tmp
& 0x1c);
139 ds3234_get_reg(&spi
->dev
, DS3234_REG_CONT_STAT
, &tmp
);
140 ds3234_set_reg(&spi
->dev
, DS3234_REG_CONT_STAT
, tmp
& 0x88);
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
);
146 ds3234_get_reg(&spi
->dev
, DS3234_REG_CONT_STAT
, &tmp
);
147 dev_info(&spi
->dev
, "Ctrl/Stat Reg: 0x%02x\n", tmp
);
149 rtc
= devm_rtc_device_register(&spi
->dev
, "ds3234",
150 &ds3234_rtc_ops
, THIS_MODULE
);
154 spi_set_drvdata(spi
, rtc
);
159 static struct spi_driver ds3234_driver
= {
162 .owner
= THIS_MODULE
,
164 .probe
= ds3234_probe
,
167 module_spi_driver(ds3234_driver
);
169 MODULE_DESCRIPTION("DS3234 SPI RTC driver");
170 MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
171 MODULE_LICENSE("GPL");
172 MODULE_ALIAS("spi:ds3234");