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