rtc-pcap.c (4599B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * pcap rtc code for Motorola EZX phones 4 * 5 * Copyright (c) 2008 guiming zhuo <gmzhuo@gmail.com> 6 * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com> 7 * 8 * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola 9 */ 10 11#include <linux/kernel.h> 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/mfd/ezx-pcap.h> 15#include <linux/rtc.h> 16#include <linux/slab.h> 17#include <linux/platform_device.h> 18 19struct pcap_rtc { 20 struct pcap_chip *pcap; 21 struct rtc_device *rtc; 22}; 23 24static irqreturn_t pcap_rtc_irq(int irq, void *_pcap_rtc) 25{ 26 struct pcap_rtc *pcap_rtc = _pcap_rtc; 27 unsigned long rtc_events; 28 29 if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ)) 30 rtc_events = RTC_IRQF | RTC_UF; 31 else if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA)) 32 rtc_events = RTC_IRQF | RTC_AF; 33 else 34 rtc_events = 0; 35 36 rtc_update_irq(pcap_rtc->rtc, 1, rtc_events); 37 return IRQ_HANDLED; 38} 39 40static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 41{ 42 struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); 43 struct rtc_time *tm = &alrm->time; 44 unsigned long secs; 45 u32 tod; /* time of day, seconds since midnight */ 46 u32 days; /* days since 1/1/1970 */ 47 48 ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TODA, &tod); 49 secs = tod & PCAP_RTC_TOD_MASK; 50 51 ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, &days); 52 secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; 53 54 rtc_time64_to_tm(secs, tm); 55 56 return 0; 57} 58 59static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 60{ 61 struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); 62 unsigned long secs = rtc_tm_to_time64(&alrm->time); 63 u32 tod, days; 64 65 tod = secs % SEC_PER_DAY; 66 ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TODA, tod); 67 68 days = secs / SEC_PER_DAY; 69 ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, days); 70 71 return 0; 72} 73 74static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm) 75{ 76 struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); 77 unsigned long secs; 78 u32 tod, days; 79 80 ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TOD, &tod); 81 secs = tod & PCAP_RTC_TOD_MASK; 82 83 ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAY, &days); 84 secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY; 85 86 rtc_time64_to_tm(secs, tm); 87 88 return 0; 89} 90 91static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm) 92{ 93 struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); 94 unsigned long secs = rtc_tm_to_time64(tm); 95 u32 tod, days; 96 97 tod = secs % SEC_PER_DAY; 98 ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TOD, tod); 99 100 days = secs / SEC_PER_DAY; 101 ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAY, days); 102 103 return 0; 104} 105 106static int pcap_rtc_irq_enable(struct device *dev, int pirq, unsigned int en) 107{ 108 struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev); 109 110 if (en) 111 enable_irq(pcap_to_irq(pcap_rtc->pcap, pirq)); 112 else 113 disable_irq(pcap_to_irq(pcap_rtc->pcap, pirq)); 114 115 return 0; 116} 117 118static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en) 119{ 120 return pcap_rtc_irq_enable(dev, PCAP_IRQ_TODA, en); 121} 122 123static const struct rtc_class_ops pcap_rtc_ops = { 124 .read_time = pcap_rtc_read_time, 125 .set_time = pcap_rtc_set_time, 126 .read_alarm = pcap_rtc_read_alarm, 127 .set_alarm = pcap_rtc_set_alarm, 128 .alarm_irq_enable = pcap_rtc_alarm_irq_enable, 129}; 130 131static int __init pcap_rtc_probe(struct platform_device *pdev) 132{ 133 struct pcap_rtc *pcap_rtc; 134 int timer_irq, alarm_irq; 135 int err = -ENOMEM; 136 137 pcap_rtc = devm_kzalloc(&pdev->dev, sizeof(struct pcap_rtc), 138 GFP_KERNEL); 139 if (!pcap_rtc) 140 return err; 141 142 pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent); 143 144 platform_set_drvdata(pdev, pcap_rtc); 145 146 pcap_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); 147 if (IS_ERR(pcap_rtc->rtc)) 148 return PTR_ERR(pcap_rtc->rtc); 149 150 pcap_rtc->rtc->ops = &pcap_rtc_ops; 151 pcap_rtc->rtc->range_max = (1 << 14) * 86400ULL - 1; 152 153 timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ); 154 alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA); 155 156 err = devm_request_irq(&pdev->dev, timer_irq, pcap_rtc_irq, 0, 157 "RTC Timer", pcap_rtc); 158 if (err) 159 return err; 160 161 err = devm_request_irq(&pdev->dev, alarm_irq, pcap_rtc_irq, 0, 162 "RTC Alarm", pcap_rtc); 163 if (err) 164 return err; 165 166 return devm_rtc_register_device(pcap_rtc->rtc); 167} 168 169static int __exit pcap_rtc_remove(struct platform_device *pdev) 170{ 171 return 0; 172} 173 174static struct platform_driver pcap_rtc_driver = { 175 .remove = __exit_p(pcap_rtc_remove), 176 .driver = { 177 .name = "pcap-rtc", 178 }, 179}; 180 181module_platform_driver_probe(pcap_rtc_driver, pcap_rtc_probe); 182 183MODULE_DESCRIPTION("Motorola pcap rtc driver"); 184MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>"); 185MODULE_LICENSE("GPL");