0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/rtc.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/bcd.h>
0013 #include <linux/slab.h>
0014
0015 struct ds1216_regs {
0016 u8 tsec;
0017 u8 sec;
0018 u8 min;
0019 u8 hour;
0020 u8 wday;
0021 u8 mday;
0022 u8 month;
0023 u8 year;
0024 };
0025
0026 #define DS1216_HOUR_1224 (1 << 7)
0027 #define DS1216_HOUR_AMPM (1 << 5)
0028
0029 struct ds1216_priv {
0030 struct rtc_device *rtc;
0031 void __iomem *ioaddr;
0032 };
0033
0034 static const u8 magic[] = {
0035 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
0036 };
0037
0038
0039
0040
0041
0042
0043 static void ds1216_read(u8 __iomem *ioaddr, u8 *buf)
0044 {
0045 unsigned char c;
0046 int i, j;
0047
0048 for (i = 0; i < 8; i++) {
0049 c = 0;
0050 for (j = 0; j < 8; j++)
0051 c |= (readb(ioaddr) & 0x1) << j;
0052 buf[i] = c;
0053 }
0054 }
0055
0056 static void ds1216_write(u8 __iomem *ioaddr, const u8 *buf)
0057 {
0058 unsigned char c;
0059 int i, j;
0060
0061 for (i = 0; i < 8; i++) {
0062 c = buf[i];
0063 for (j = 0; j < 8; j++) {
0064 writeb(c, ioaddr);
0065 c = c >> 1;
0066 }
0067 }
0068 }
0069
0070 static void ds1216_switch_ds_to_clock(u8 __iomem *ioaddr)
0071 {
0072
0073 readb(ioaddr);
0074
0075 ds1216_write(ioaddr, magic);
0076 }
0077
0078 static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm)
0079 {
0080 struct ds1216_priv *priv = dev_get_drvdata(dev);
0081 struct ds1216_regs regs;
0082
0083 ds1216_switch_ds_to_clock(priv->ioaddr);
0084 ds1216_read(priv->ioaddr, (u8 *)®s);
0085
0086 tm->tm_sec = bcd2bin(regs.sec);
0087 tm->tm_min = bcd2bin(regs.min);
0088 if (regs.hour & DS1216_HOUR_1224) {
0089
0090 tm->tm_hour = bcd2bin(regs.hour & 0x1f);
0091 if (regs.hour & DS1216_HOUR_AMPM)
0092 tm->tm_hour += 12;
0093 } else
0094 tm->tm_hour = bcd2bin(regs.hour & 0x3f);
0095 tm->tm_wday = (regs.wday & 7) - 1;
0096 tm->tm_mday = bcd2bin(regs.mday & 0x3f);
0097 tm->tm_mon = bcd2bin(regs.month & 0x1f);
0098 tm->tm_year = bcd2bin(regs.year);
0099 if (tm->tm_year < 70)
0100 tm->tm_year += 100;
0101
0102 return 0;
0103 }
0104
0105 static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm)
0106 {
0107 struct ds1216_priv *priv = dev_get_drvdata(dev);
0108 struct ds1216_regs regs;
0109
0110 ds1216_switch_ds_to_clock(priv->ioaddr);
0111 ds1216_read(priv->ioaddr, (u8 *)®s);
0112
0113 regs.tsec = 0;
0114 regs.sec = bin2bcd(tm->tm_sec);
0115 regs.min = bin2bcd(tm->tm_min);
0116 regs.hour &= DS1216_HOUR_1224;
0117 if (regs.hour && tm->tm_hour > 12) {
0118 regs.hour |= DS1216_HOUR_AMPM;
0119 tm->tm_hour -= 12;
0120 }
0121 regs.hour |= bin2bcd(tm->tm_hour);
0122 regs.wday &= ~7;
0123 regs.wday |= tm->tm_wday;
0124 regs.mday = bin2bcd(tm->tm_mday);
0125 regs.month = bin2bcd(tm->tm_mon);
0126 regs.year = bin2bcd(tm->tm_year % 100);
0127
0128 ds1216_switch_ds_to_clock(priv->ioaddr);
0129 ds1216_write(priv->ioaddr, (u8 *)®s);
0130 return 0;
0131 }
0132
0133 static const struct rtc_class_ops ds1216_rtc_ops = {
0134 .read_time = ds1216_rtc_read_time,
0135 .set_time = ds1216_rtc_set_time,
0136 };
0137
0138 static int __init ds1216_rtc_probe(struct platform_device *pdev)
0139 {
0140 struct ds1216_priv *priv;
0141 u8 dummy[8];
0142
0143 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0144 if (!priv)
0145 return -ENOMEM;
0146
0147 platform_set_drvdata(pdev, priv);
0148
0149 priv->ioaddr = devm_platform_ioremap_resource(pdev, 0);
0150 if (IS_ERR(priv->ioaddr))
0151 return PTR_ERR(priv->ioaddr);
0152
0153 priv->rtc = devm_rtc_device_register(&pdev->dev, "ds1216",
0154 &ds1216_rtc_ops, THIS_MODULE);
0155 if (IS_ERR(priv->rtc))
0156 return PTR_ERR(priv->rtc);
0157
0158
0159 ds1216_read(priv->ioaddr, dummy);
0160 return 0;
0161 }
0162
0163 static struct platform_driver ds1216_rtc_platform_driver = {
0164 .driver = {
0165 .name = "rtc-ds1216",
0166 },
0167 };
0168
0169 module_platform_driver_probe(ds1216_rtc_platform_driver, ds1216_rtc_probe);
0170
0171 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
0172 MODULE_DESCRIPTION("DS1216 RTC driver");
0173 MODULE_LICENSE("GPL");
0174 MODULE_ALIAS("platform:rtc-ds1216");