Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* NXP PCF50633 RTC Driver
0003  *
0004  * (C) 2006-2008 by Openmoko, Inc.
0005  * Author: Balaji Rao <balajirrao@openmoko.org>
0006  * All rights reserved.
0007  *
0008  * Broken down from monstrous PCF50633 driver mainly by
0009  * Harald Welte, Andy Green and Werner Almesberger
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/device.h>
0016 #include <linux/slab.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/rtc.h>
0019 #include <linux/bcd.h>
0020 #include <linux/err.h>
0021 
0022 #include <linux/mfd/pcf50633/core.h>
0023 
0024 #define PCF50633_REG_RTCSC  0x59 /* Second */
0025 #define PCF50633_REG_RTCMN  0x5a /* Minute */
0026 #define PCF50633_REG_RTCHR  0x5b /* Hour */
0027 #define PCF50633_REG_RTCWD  0x5c /* Weekday */
0028 #define PCF50633_REG_RTCDT  0x5d /* Day */
0029 #define PCF50633_REG_RTCMT  0x5e /* Month */
0030 #define PCF50633_REG_RTCYR  0x5f /* Year */
0031 #define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */
0032 #define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */
0033 #define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */
0034 #define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */
0035 #define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */
0036 #define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */
0037 #define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */
0038 
0039 enum pcf50633_time_indexes {
0040     PCF50633_TI_SEC,
0041     PCF50633_TI_MIN,
0042     PCF50633_TI_HOUR,
0043     PCF50633_TI_WKDAY,
0044     PCF50633_TI_DAY,
0045     PCF50633_TI_MONTH,
0046     PCF50633_TI_YEAR,
0047     PCF50633_TI_EXTENT /* always last */
0048 };
0049 
0050 struct pcf50633_time {
0051     u_int8_t time[PCF50633_TI_EXTENT];
0052 };
0053 
0054 struct pcf50633_rtc {
0055     int alarm_enabled;
0056     int alarm_pending;
0057 
0058     struct pcf50633 *pcf;
0059     struct rtc_device *rtc_dev;
0060 };
0061 
0062 static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
0063 {
0064     rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]);
0065     rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]);
0066     rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
0067     rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
0068     rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
0069     rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
0070     rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
0071 }
0072 
0073 static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
0074 {
0075     pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec);
0076     pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min);
0077     pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
0078     pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
0079     pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
0080     pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
0081     pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
0082 }
0083 
0084 static int
0085 pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
0086 {
0087     struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
0088     int err;
0089 
0090     if (enabled)
0091         err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
0092     else
0093         err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
0094 
0095     if (err < 0)
0096         return err;
0097 
0098     rtc->alarm_enabled = enabled;
0099 
0100     return 0;
0101 }
0102 
0103 static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
0104 {
0105     struct pcf50633_rtc *rtc;
0106     struct pcf50633_time pcf_tm;
0107     int ret;
0108 
0109     rtc = dev_get_drvdata(dev);
0110 
0111     ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
0112                         PCF50633_TI_EXTENT,
0113                         &pcf_tm.time[0]);
0114     if (ret != PCF50633_TI_EXTENT) {
0115         dev_err(dev, "Failed to read time\n");
0116         return -EIO;
0117     }
0118 
0119     dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
0120         pcf_tm.time[PCF50633_TI_DAY],
0121         pcf_tm.time[PCF50633_TI_MONTH],
0122         pcf_tm.time[PCF50633_TI_YEAR],
0123         pcf_tm.time[PCF50633_TI_HOUR],
0124         pcf_tm.time[PCF50633_TI_MIN],
0125         pcf_tm.time[PCF50633_TI_SEC]);
0126 
0127     pcf2rtc_time(tm, &pcf_tm);
0128 
0129     dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
0130 
0131     return 0;
0132 }
0133 
0134 static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
0135 {
0136     struct pcf50633_rtc *rtc;
0137     struct pcf50633_time pcf_tm;
0138     int alarm_masked, ret = 0;
0139 
0140     rtc = dev_get_drvdata(dev);
0141 
0142     dev_dbg(dev, "RTC_TIME: %ptRr\n", tm);
0143 
0144     rtc2pcf_time(&pcf_tm, tm);
0145 
0146     dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
0147         pcf_tm.time[PCF50633_TI_DAY],
0148         pcf_tm.time[PCF50633_TI_MONTH],
0149         pcf_tm.time[PCF50633_TI_YEAR],
0150         pcf_tm.time[PCF50633_TI_HOUR],
0151         pcf_tm.time[PCF50633_TI_MIN],
0152         pcf_tm.time[PCF50633_TI_SEC]);
0153 
0154 
0155     alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
0156 
0157     if (!alarm_masked)
0158         pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
0159 
0160     /* Returns 0 on success */
0161     ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC,
0162                          PCF50633_TI_EXTENT,
0163                          &pcf_tm.time[0]);
0164 
0165     if (!alarm_masked)
0166         pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
0167 
0168     return ret;
0169 }
0170 
0171 static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
0172 {
0173     struct pcf50633_rtc *rtc;
0174     struct pcf50633_time pcf_tm;
0175     int ret = 0;
0176 
0177     rtc = dev_get_drvdata(dev);
0178 
0179     alrm->enabled = rtc->alarm_enabled;
0180     alrm->pending = rtc->alarm_pending;
0181 
0182     ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
0183                 PCF50633_TI_EXTENT, &pcf_tm.time[0]);
0184     if (ret != PCF50633_TI_EXTENT) {
0185         dev_err(dev, "Failed to read time\n");
0186         return -EIO;
0187     }
0188 
0189     pcf2rtc_time(&alrm->time, &pcf_tm);
0190 
0191     return rtc_valid_tm(&alrm->time);
0192 }
0193 
0194 static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
0195 {
0196     struct pcf50633_rtc *rtc;
0197     struct pcf50633_time pcf_tm;
0198     int alarm_masked, ret = 0;
0199 
0200     rtc = dev_get_drvdata(dev);
0201 
0202     rtc2pcf_time(&pcf_tm, &alrm->time);
0203 
0204     /* do like mktime does and ignore tm_wday */
0205     pcf_tm.time[PCF50633_TI_WKDAY] = 7;
0206 
0207     alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
0208 
0209     /* disable alarm interrupt */
0210     if (!alarm_masked)
0211         pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
0212 
0213     /* Returns 0 on success */
0214     ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
0215                 PCF50633_TI_EXTENT, &pcf_tm.time[0]);
0216     if (!alrm->enabled)
0217         rtc->alarm_pending = 0;
0218 
0219     if (!alarm_masked || alrm->enabled)
0220         pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
0221     rtc->alarm_enabled = alrm->enabled;
0222 
0223     return ret;
0224 }
0225 
0226 static const struct rtc_class_ops pcf50633_rtc_ops = {
0227     .read_time      = pcf50633_rtc_read_time,
0228     .set_time       = pcf50633_rtc_set_time,
0229     .read_alarm     = pcf50633_rtc_read_alarm,
0230     .set_alarm      = pcf50633_rtc_set_alarm,
0231     .alarm_irq_enable   = pcf50633_rtc_alarm_irq_enable,
0232 };
0233 
0234 static void pcf50633_rtc_irq(int irq, void *data)
0235 {
0236     struct pcf50633_rtc *rtc = data;
0237 
0238     rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
0239     rtc->alarm_pending = 1;
0240 }
0241 
0242 static int pcf50633_rtc_probe(struct platform_device *pdev)
0243 {
0244     struct pcf50633_rtc *rtc;
0245 
0246     rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
0247     if (!rtc)
0248         return -ENOMEM;
0249 
0250     rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
0251     platform_set_drvdata(pdev, rtc);
0252     rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "pcf50633-rtc",
0253                 &pcf50633_rtc_ops, THIS_MODULE);
0254 
0255     if (IS_ERR(rtc->rtc_dev))
0256         return PTR_ERR(rtc->rtc_dev);
0257 
0258     pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
0259                     pcf50633_rtc_irq, rtc);
0260     return 0;
0261 }
0262 
0263 static int pcf50633_rtc_remove(struct platform_device *pdev)
0264 {
0265     struct pcf50633_rtc *rtc;
0266 
0267     rtc = platform_get_drvdata(pdev);
0268     pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
0269 
0270     return 0;
0271 }
0272 
0273 static struct platform_driver pcf50633_rtc_driver = {
0274     .driver = {
0275         .name = "pcf50633-rtc",
0276     },
0277     .probe = pcf50633_rtc_probe,
0278     .remove = pcf50633_rtc_remove,
0279 };
0280 
0281 module_platform_driver(pcf50633_rtc_driver);
0282 
0283 MODULE_DESCRIPTION("PCF50633 RTC driver");
0284 MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
0285 MODULE_LICENSE("GPL");
0286