Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: add device driver for Dallas DS3234 SPI RTC chip

Add support for the Dallas DS3234 chip - extremely accurate SPI bus RTC
with integrated crystal and SRAM.

[akpm@linux-foundation.org: don't use BIN2BCD/BCD2BIN]
Signed-off-by: Dennis Aberilla <denzzzhome@yahoo.com>
Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dennis Aberilla and committed by
Linus Torvalds
2f9b75e0 986e36a5

+300
+9
drivers/rtc/Kconfig
··· 319 319 This driver can also be built as a module. If so, the module 320 320 will be called rtc-rs5c348. 321 321 322 + config RTC_DRV_DS3234 323 + tristate "Maxim/Dallas DS3234" 324 + help 325 + If you say yes here you get support for the 326 + Maxim/Dallas DS3234 SPI RTC chip. 327 + 328 + This driver can also be built as a module. If so, the module 329 + will be called rtc-ds3234. 330 + 322 331 endif # SPI_MASTER 323 332 324 333 comment "Platform RTC drivers"
+1
drivers/rtc/Makefile
··· 32 32 obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o 33 33 obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o 34 34 obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o 35 + obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o 35 36 obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o 36 37 obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o 37 38 obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
+290
drivers/rtc/rtc-ds3234.c
··· 1 + /* drivers/rtc/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 + * Changelog: 13 + * 14 + * 07-May-2008: Dennis Aberilla <denzzzhome@yahoo.com> 15 + * - Created based on the max6902 code. Only implements the 16 + * date/time keeping functions; no SRAM yet. 17 + */ 18 + 19 + #include <linux/device.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/rtc.h> 22 + #include <linux/spi/spi.h> 23 + #include <linux/bcd.h> 24 + 25 + #define DS3234_REG_SECONDS 0x00 26 + #define DS3234_REG_MINUTES 0x01 27 + #define DS3234_REG_HOURS 0x02 28 + #define DS3234_REG_DAY 0x03 29 + #define DS3234_REG_DATE 0x04 30 + #define DS3234_REG_MONTH 0x05 31 + #define DS3234_REG_YEAR 0x06 32 + #define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */ 33 + 34 + #define DS3234_REG_CONTROL 0x0E 35 + #define DS3234_REG_CONT_STAT 0x0F 36 + 37 + #undef DS3234_DEBUG 38 + 39 + struct ds3234 { 40 + struct rtc_device *rtc; 41 + u8 buf[8]; /* Burst read: addr + 7 regs */ 42 + u8 tx_buf[2]; 43 + u8 rx_buf[2]; 44 + }; 45 + 46 + static void ds3234_set_reg(struct device *dev, unsigned char address, 47 + unsigned char data) 48 + { 49 + struct spi_device *spi = to_spi_device(dev); 50 + unsigned char buf[2]; 51 + 52 + /* MSB must be '1' to indicate write */ 53 + buf[0] = address | 0x80; 54 + buf[1] = data; 55 + 56 + spi_write(spi, buf, 2); 57 + } 58 + 59 + static int ds3234_get_reg(struct device *dev, unsigned char address, 60 + unsigned char *data) 61 + { 62 + struct spi_device *spi = to_spi_device(dev); 63 + struct ds3234 *chip = dev_get_drvdata(dev); 64 + struct spi_message message; 65 + struct spi_transfer xfer; 66 + int status; 67 + 68 + if (!data) 69 + return -EINVAL; 70 + 71 + /* Build our spi message */ 72 + spi_message_init(&message); 73 + memset(&xfer, 0, sizeof(xfer)); 74 + 75 + /* Address + dummy tx byte */ 76 + xfer.len = 2; 77 + xfer.tx_buf = chip->tx_buf; 78 + xfer.rx_buf = chip->rx_buf; 79 + 80 + chip->tx_buf[0] = address; 81 + chip->tx_buf[1] = 0xff; 82 + 83 + spi_message_add_tail(&xfer, &message); 84 + 85 + /* do the i/o */ 86 + status = spi_sync(spi, &message); 87 + if (status == 0) 88 + status = message.status; 89 + else 90 + return status; 91 + 92 + *data = chip->rx_buf[1]; 93 + 94 + return status; 95 + } 96 + 97 + static int ds3234_get_datetime(struct device *dev, struct rtc_time *dt) 98 + { 99 + struct spi_device *spi = to_spi_device(dev); 100 + struct ds3234 *chip = dev_get_drvdata(dev); 101 + struct spi_message message; 102 + struct spi_transfer xfer; 103 + int status; 104 + 105 + /* build the message */ 106 + spi_message_init(&message); 107 + memset(&xfer, 0, sizeof(xfer)); 108 + xfer.len = 1 + 7; /* Addr + 7 registers */ 109 + xfer.tx_buf = chip->buf; 110 + xfer.rx_buf = chip->buf; 111 + chip->buf[0] = 0x00; /* Start address */ 112 + spi_message_add_tail(&xfer, &message); 113 + 114 + /* do the i/o */ 115 + status = spi_sync(spi, &message); 116 + if (status == 0) 117 + status = message.status; 118 + else 119 + return status; 120 + 121 + /* Seconds, Minutes, Hours, Day, Date, Month, Year */ 122 + dt->tm_sec = bcd2bin(chip->buf[1]); 123 + dt->tm_min = bcd2bin(chip->buf[2]); 124 + dt->tm_hour = bcd2bin(chip->buf[3] & 0x3f); 125 + dt->tm_wday = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */ 126 + dt->tm_mday = bcd2bin(chip->buf[5]); 127 + dt->tm_mon = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */ 128 + dt->tm_year = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */ 129 + 130 + #ifdef DS3234_DEBUG 131 + dev_dbg(dev, "\n%s : Read RTC values\n", __func__); 132 + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); 133 + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); 134 + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); 135 + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); 136 + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); 137 + dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); 138 + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); 139 + #endif 140 + 141 + return 0; 142 + } 143 + 144 + static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt) 145 + { 146 + #ifdef DS3234_DEBUG 147 + dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); 148 + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); 149 + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); 150 + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); 151 + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); 152 + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); 153 + dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); 154 + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); 155 + #endif 156 + 157 + ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec)); 158 + ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min)); 159 + ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f); 160 + 161 + /* 0 = Sun */ 162 + ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1)); 163 + ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday)); 164 + 165 + /* 0 = Jan */ 166 + ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1)); 167 + 168 + /* Assume 20YY although we just want to make sure not to go negative. */ 169 + if (dt->tm_year > 100) 170 + dt->tm_year -= 100; 171 + 172 + ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year)); 173 + 174 + return 0; 175 + } 176 + 177 + static int ds3234_read_time(struct device *dev, struct rtc_time *tm) 178 + { 179 + return ds3234_get_datetime(dev, tm); 180 + } 181 + 182 + static int ds3234_set_time(struct device *dev, struct rtc_time *tm) 183 + { 184 + return ds3234_set_datetime(dev, tm); 185 + } 186 + 187 + static const struct rtc_class_ops ds3234_rtc_ops = { 188 + .read_time = ds3234_read_time, 189 + .set_time = ds3234_set_time, 190 + }; 191 + 192 + static int ds3234_probe(struct spi_device *spi) 193 + { 194 + struct rtc_device *rtc; 195 + unsigned char tmp; 196 + struct ds3234 *chip; 197 + int res; 198 + 199 + rtc = rtc_device_register("ds3234", 200 + &spi->dev, &ds3234_rtc_ops, THIS_MODULE); 201 + if (IS_ERR(rtc)) 202 + return PTR_ERR(rtc); 203 + 204 + spi->mode = SPI_MODE_3; 205 + spi->bits_per_word = 8; 206 + spi_setup(spi); 207 + 208 + chip = kzalloc(sizeof(struct ds3234), GFP_KERNEL); 209 + if (!chip) { 210 + rtc_device_unregister(rtc); 211 + return -ENOMEM; 212 + } 213 + chip->rtc = rtc; 214 + dev_set_drvdata(&spi->dev, chip); 215 + 216 + res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp); 217 + if (res) { 218 + rtc_device_unregister(rtc); 219 + return res; 220 + } 221 + 222 + /* Control settings 223 + * 224 + * CONTROL_REG 225 + * BIT 7 6 5 4 3 2 1 0 226 + * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE 227 + * 228 + * 0 0 0 1 1 1 0 0 229 + * 230 + * CONTROL_STAT_REG 231 + * BIT 7 6 5 4 3 2 1 0 232 + * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F 233 + * 234 + * 1 0 0 0 1 0 0 0 235 + */ 236 + ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); 237 + ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c); 238 + 239 + ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); 240 + ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88); 241 + 242 + /* Print our settings */ 243 + ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp); 244 + dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp); 245 + 246 + ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp); 247 + dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp); 248 + 249 + return 0; 250 + } 251 + 252 + static int __exit ds3234_remove(struct spi_device *spi) 253 + { 254 + struct ds3234 *chip = platform_get_drvdata(spi); 255 + struct rtc_device *rtc = chip->rtc; 256 + 257 + if (rtc) 258 + rtc_device_unregister(rtc); 259 + 260 + kfree(chip); 261 + 262 + return 0; 263 + } 264 + 265 + static struct spi_driver ds3234_driver = { 266 + .driver = { 267 + .name = "ds3234", 268 + .bus = &spi_bus_type, 269 + .owner = THIS_MODULE, 270 + }, 271 + .probe = ds3234_probe, 272 + .remove = __devexit_p(ds3234_remove), 273 + }; 274 + 275 + static __init int ds3234_init(void) 276 + { 277 + printk(KERN_INFO "DS3234 SPI RTC Driver\n"); 278 + return spi_register_driver(&ds3234_driver); 279 + } 280 + module_init(ds3234_init); 281 + 282 + static __exit void ds3234_exit(void) 283 + { 284 + spi_unregister_driver(&ds3234_driver); 285 + } 286 + module_exit(ds3234_exit); 287 + 288 + MODULE_DESCRIPTION("DS3234 SPI RTC driver"); 289 + MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>"); 290 + MODULE_LICENSE("GPL");