Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Dallas DS1216 RTC driver
0004  *
0005  * Copyright (c) 2007 Thomas Bogendoerfer
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  * Read the 64 bit we'd like to have - It a series
0040  * of 64 bits showing up in the LSB of the base register.
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     /* Reset magic pointer */
0073     readb(ioaddr);
0074     /* Write 64 bit magic to DS1216 */
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 *)&regs);
0085 
0086     tm->tm_sec = bcd2bin(regs.sec);
0087     tm->tm_min = bcd2bin(regs.min);
0088     if (regs.hour & DS1216_HOUR_1224) {
0089         /* AM/PM mode */
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 *)&regs);
0112 
0113     regs.tsec = 0; /* clear 0.1 and 0.01 seconds */
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 *)&regs);
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     /* dummy read to get clock into a known state */
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");