Blame view
drivers/rtc/rtc-ds1390.c
4.92 KB
06de18085 rtc: add Dallas D... |
1 |
/* |
7b9b2ef1b rtc: rtc-ds1390 p... |
2 |
* rtc-ds1390.c -- driver for the Dallas/Maxim DS1390/93/94 SPI RTC |
06de18085 rtc: add Dallas D... |
3 4 5 6 7 8 9 10 |
* * Copyright (C) 2008 Mercury IMC Ltd * Written by Mark Jackson <mpfj@mimc.co.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * |
7b9b2ef1b rtc: rtc-ds1390 p... |
11 12 |
* NOTE: Currently this driver only supports the bare minimum for read * and write the RTC. The extra features provided by the chip family |
06de18085 rtc: add Dallas D... |
13 14 |
* (alarms, trickle charger, different control registers) are unavailable. */ |
7b9b2ef1b rtc: rtc-ds1390 p... |
15 16 |
#include <linux/init.h> #include <linux/module.h> |
06de18085 rtc: add Dallas D... |
17 18 19 20 |
#include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/spi/spi.h> #include <linux/bcd.h> |
5a0e3ad6a include cleanup: ... |
21 |
#include <linux/slab.h> |
06de18085 rtc: add Dallas D... |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#define DS1390_REG_100THS 0x00 #define DS1390_REG_SECONDS 0x01 #define DS1390_REG_MINUTES 0x02 #define DS1390_REG_HOURS 0x03 #define DS1390_REG_DAY 0x04 #define DS1390_REG_DATE 0x05 #define DS1390_REG_MONTH_CENT 0x06 #define DS1390_REG_YEAR 0x07 #define DS1390_REG_ALARM_100THS 0x08 #define DS1390_REG_ALARM_SECONDS 0x09 #define DS1390_REG_ALARM_MINUTES 0x0A #define DS1390_REG_ALARM_HOURS 0x0B #define DS1390_REG_ALARM_DAY_DATE 0x0C #define DS1390_REG_CONTROL 0x0D #define DS1390_REG_STATUS 0x0E #define DS1390_REG_TRICKLE 0x0F struct ds1390 { struct rtc_device *rtc; u8 txrx_buf[9]; /* cmd + 8 registers */ }; |
06de18085 rtc: add Dallas D... |
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
static int ds1390_get_reg(struct device *dev, unsigned char address, unsigned char *data) { struct spi_device *spi = to_spi_device(dev); struct ds1390 *chip = dev_get_drvdata(dev); int status; if (!data) return -EINVAL; /* Clear MSB to indicate read */ chip->txrx_buf[0] = address & 0x7f; /* do the i/o */ status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 1); if (status != 0) return status; *data = chip->txrx_buf[1]; return 0; } |
7b9b2ef1b rtc: rtc-ds1390 p... |
67 |
static int ds1390_read_time(struct device *dev, struct rtc_time *dt) |
06de18085 rtc: add Dallas D... |
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
{ struct spi_device *spi = to_spi_device(dev); struct ds1390 *chip = dev_get_drvdata(dev); int status; /* build the message */ chip->txrx_buf[0] = DS1390_REG_SECONDS; /* do the i/o */ status = spi_write_then_read(spi, chip->txrx_buf, 1, chip->txrx_buf, 8); if (status != 0) return status; /* The chip sends data in this order: * Seconds, Minutes, Hours, Day, Date, Month / Century, Year */ dt->tm_sec = bcd2bin(chip->txrx_buf[0]); dt->tm_min = bcd2bin(chip->txrx_buf[1]); dt->tm_hour = bcd2bin(chip->txrx_buf[2]); dt->tm_wday = bcd2bin(chip->txrx_buf[3]); dt->tm_mday = bcd2bin(chip->txrx_buf[4]); /* mask off century bit */ dt->tm_mon = bcd2bin(chip->txrx_buf[5] & 0x7f) - 1; /* adjust for century bit */ dt->tm_year = bcd2bin(chip->txrx_buf[6]) + ((chip->txrx_buf[5] & 0x80) ? 100 : 0); return rtc_valid_tm(dt); } |
7b9b2ef1b rtc: rtc-ds1390 p... |
95 |
static int ds1390_set_time(struct device *dev, struct rtc_time *dt) |
06de18085 rtc: add Dallas D... |
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
{ struct spi_device *spi = to_spi_device(dev); struct ds1390 *chip = dev_get_drvdata(dev); /* build the message */ chip->txrx_buf[0] = DS1390_REG_SECONDS | 0x80; chip->txrx_buf[1] = bin2bcd(dt->tm_sec); chip->txrx_buf[2] = bin2bcd(dt->tm_min); chip->txrx_buf[3] = bin2bcd(dt->tm_hour); chip->txrx_buf[4] = bin2bcd(dt->tm_wday); chip->txrx_buf[5] = bin2bcd(dt->tm_mday); chip->txrx_buf[6] = bin2bcd(dt->tm_mon + 1) | ((dt->tm_year > 99) ? 0x80 : 0x00); chip->txrx_buf[7] = bin2bcd(dt->tm_year % 100); /* do the i/o */ return spi_write_then_read(spi, chip->txrx_buf, 8, NULL, 0); } |
06de18085 rtc: add Dallas D... |
114 115 116 117 118 119 120 |
static const struct rtc_class_ops ds1390_rtc_ops = { .read_time = ds1390_read_time, .set_time = ds1390_set_time, }; static int __devinit ds1390_probe(struct spi_device *spi) { |
06de18085 rtc: add Dallas D... |
121 122 123 |
unsigned char tmp; struct ds1390 *chip; int res; |
06de18085 rtc: add Dallas D... |
124 125 126 127 128 129 |
spi->mode = SPI_MODE_3; spi->bits_per_word = 8; spi_setup(spi); chip = kzalloc(sizeof *chip, GFP_KERNEL); if (!chip) { |
7b9b2ef1b rtc: rtc-ds1390 p... |
130 131 |
dev_err(&spi->dev, "unable to allocate device memory "); |
06de18085 rtc: add Dallas D... |
132 133 |
return -ENOMEM; } |
06de18085 rtc: add Dallas D... |
134 135 136 |
dev_set_drvdata(&spi->dev, chip); res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp); |
7b9b2ef1b rtc: rtc-ds1390 p... |
137 138 139 140 |
if (res != 0) { dev_err(&spi->dev, "unable to read device "); kfree(chip); |
06de18085 rtc: add Dallas D... |
141 142 |
return res; } |
7b9b2ef1b rtc: rtc-ds1390 p... |
143 144 145 146 147 148 149 150 151 152 |
chip->rtc = rtc_device_register("ds1390", &spi->dev, &ds1390_rtc_ops, THIS_MODULE); if (IS_ERR(chip->rtc)) { dev_err(&spi->dev, "unable to register device "); res = PTR_ERR(chip->rtc); kfree(chip); } return res; |
06de18085 rtc: add Dallas D... |
153 154 155 156 |
} static int __devexit ds1390_remove(struct spi_device *spi) { |
42fea15d6 spi/rtc-{ds1390,d... |
157 |
struct ds1390 *chip = spi_get_drvdata(spi); |
06de18085 rtc: add Dallas D... |
158 |
|
7b9b2ef1b rtc: rtc-ds1390 p... |
159 |
rtc_device_unregister(chip->rtc); |
06de18085 rtc: add Dallas D... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
kfree(chip); return 0; } static struct spi_driver ds1390_driver = { .driver = { .name = "rtc-ds1390", .owner = THIS_MODULE, }, .probe = ds1390_probe, .remove = __devexit_p(ds1390_remove), }; static __init int ds1390_init(void) { return spi_register_driver(&ds1390_driver); } module_init(ds1390_init); static __exit void ds1390_exit(void) { spi_unregister_driver(&ds1390_driver); } module_exit(ds1390_exit); |
7b9b2ef1b rtc: rtc-ds1390 p... |
185 |
MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver"); |
06de18085 rtc: add Dallas D... |
186 187 |
MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>"); MODULE_LICENSE("GPL"); |
e0626e384 spi: prefix modal... |
188 |
MODULE_ALIAS("spi:rtc-ds1390"); |