diff options
Diffstat (limited to 'drivers/rtc/rtc-sh.c')
-rw-r--r-- | drivers/rtc/rtc-sh.c | 285 |
1 files changed, 51 insertions, 234 deletions
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9ea40f40188f..f15ef3aa82a0 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -5,6 +5,7 @@ * Copyright (C) 2006 - 2009 Paul Mundt * Copyright (C) 2006 Jamie Lenehan * Copyright (C) 2008 Angelo Castello + * Copyright (C) 2025 Wolfram Sang, Renesas Electronics Corporation * * Based on the old arch/sh/kernel/cpu/rtc.c by: * @@ -31,7 +32,7 @@ /* Default values for RZ/A RTC */ #define rtc_reg_size sizeof(u16) #define RTC_BIT_INVERTED 0 /* no chip bugs */ -#define RTC_CAP_4_DIGIT_YEAR (1 << 0) +#define RTC_CAP_4_DIGIT_YEAR BIT(0) #define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR #endif @@ -70,62 +71,35 @@ */ /* ALARM Bits - or with BCD encoded value */ -#define AR_ENB 0x80 /* Enable for alarm cmp */ - -/* Period Bits */ -#define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */ -#define PF_COUNT 0x200 /* Half periodic counter */ -#define PF_OXS 0x400 /* Periodic One x Second */ -#define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */ -#define PF_MASK 0xf00 +#define AR_ENB BIT(7) /* Enable for alarm cmp */ /* RCR1 Bits */ -#define RCR1_CF 0x80 /* Carry Flag */ -#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ -#define RCR1_AF 0x01 /* Alarm Flag */ +#define RCR1_CF BIT(7) /* Carry Flag */ +#define RCR1_CIE BIT(4) /* Carry Interrupt Enable */ +#define RCR1_AIE BIT(3) /* Alarm Interrupt Enable */ +#define RCR1_AF BIT(0) /* Alarm Flag */ /* RCR2 Bits */ -#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */ -#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */ -#define RCR2_RTCEN 0x08 /* ENable RTC */ -#define RCR2_ADJ 0x04 /* ADJustment (30-second) */ -#define RCR2_RESET 0x02 /* Reset bit */ -#define RCR2_START 0x01 /* Start bit */ +#define RCR2_RTCEN BIT(3) /* ENable RTC */ +#define RCR2_ADJ BIT(2) /* ADJustment (30-second) */ +#define RCR2_RESET BIT(1) /* Reset bit */ +#define RCR2_START BIT(0) /* Start bit */ struct sh_rtc { void __iomem *regbase; - unsigned long regsize; - struct resource *res; int alarm_irq; - int periodic_irq; - int carry_irq; struct clk *clk; struct rtc_device *rtc_dev; - spinlock_t lock; + spinlock_t lock; /* protecting register access */ unsigned long capabilities; /* See asm/rtc.h for cap bits */ - unsigned short periodic_freq; }; -static int __sh_rtc_interrupt(struct sh_rtc *rtc) +static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) { + struct sh_rtc *rtc = dev_id; unsigned int tmp, pending; - tmp = readb(rtc->regbase + RCR1); - pending = tmp & RCR1_CF; - tmp &= ~RCR1_CF; - writeb(tmp, rtc->regbase + RCR1); - - /* Users have requested One x Second IRQ */ - if (pending && rtc->periodic_freq & PF_OXS) - rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); - - return pending; -} - -static int __sh_rtc_alarm(struct sh_rtc *rtc) -{ - unsigned int tmp, pending; + spin_lock(&rtc->lock); tmp = readb(rtc->regbase + RCR1); pending = tmp & RCR1_AF; @@ -135,84 +109,12 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc) if (pending) rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); - return pending; -} - -static int __sh_rtc_periodic(struct sh_rtc *rtc) -{ - unsigned int tmp, pending; - - tmp = readb(rtc->regbase + RCR2); - pending = tmp & RCR2_PEF; - tmp &= ~RCR2_PEF; - writeb(tmp, rtc->regbase + RCR2); - - if (!pending) - return 0; - - /* Half period enabled than one skipped and the next notified */ - if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) - rtc->periodic_freq &= ~PF_COUNT; - else { - if (rtc->periodic_freq & PF_HP) - rtc->periodic_freq |= PF_COUNT; - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); - } - - return pending; -} - -static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_interrupt(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); -} - -static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_alarm(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); -} - -static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_periodic(rtc); - spin_unlock(&rtc->lock); - - return IRQ_RETVAL(ret); -} - -static irqreturn_t sh_rtc_shared(int irq, void *dev_id) -{ - struct sh_rtc *rtc = dev_id; - int ret; - - spin_lock(&rtc->lock); - ret = __sh_rtc_interrupt(rtc); - ret |= __sh_rtc_alarm(rtc); - ret |= __sh_rtc_periodic(rtc); spin_unlock(&rtc->lock); - return IRQ_RETVAL(ret); + return IRQ_RETVAL(pending); } -static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) +static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int tmp; @@ -229,45 +131,7 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) writeb(tmp, rtc->regbase + RCR1); spin_unlock_irq(&rtc->lock); -} - -static int sh_rtc_proc(struct device *dev, struct seq_file *seq) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - tmp = readb(rtc->regbase + RCR1); - seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no"); - - tmp = readb(rtc->regbase + RCR2); - seq_printf(seq, "periodic_IRQ\t: %s\n", - (tmp & RCR2_PESMASK) ? "yes" : "no"); - - return 0; -} - -static inline void sh_rtc_setcie(struct device *dev, unsigned int enable) -{ - struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; - - spin_lock_irq(&rtc->lock); - - tmp = readb(rtc->regbase + RCR1); - - if (!enable) - tmp &= ~RCR1_CIE; - else - tmp |= RCR1_CIE; - - writeb(tmp, rtc->regbase + RCR1); - - spin_unlock_irq(&rtc->lock); -} -static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - sh_rtc_setaie(dev, enabled); return 0; } @@ -320,14 +184,8 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec--; #endif - /* only keep the carry interrupt enabled if UIE is on */ - if (!(rtc->periodic_freq & PF_OXS)) - sh_rtc_setcie(dev, 0); - - dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", - __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); return 0; @@ -461,16 +319,17 @@ static const struct rtc_class_ops sh_rtc_ops = { .set_time = sh_rtc_set_time, .read_alarm = sh_rtc_read_alarm, .set_alarm = sh_rtc_set_alarm, - .proc = sh_rtc_proc, .alarm_irq_enable = sh_rtc_alarm_irq_enable, }; static int __init sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; - struct resource *res; + struct resource *res, *req_res; char clk_name[14]; int clk_id, ret; + unsigned int tmp; + resource_size_t regsize; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) @@ -478,34 +337,32 @@ static int __init sh_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); - /* get periodic/carry/alarm irqs */ ret = platform_get_irq(pdev, 0); if (unlikely(ret <= 0)) { dev_err(&pdev->dev, "No IRQ resource\n"); return -ENOENT; } - rtc->periodic_irq = ret; - rtc->carry_irq = platform_get_irq(pdev, 1); - rtc->alarm_irq = platform_get_irq(pdev, 2); + if (!pdev->dev.of_node) + rtc->alarm_irq = platform_get_irq(pdev, 2); + else + rtc->alarm_irq = ret; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(res == NULL)) { + if (!res) { dev_err(&pdev->dev, "No IO resource\n"); return -ENOENT; } - rtc->regsize = resource_size(res); - - rtc->res = devm_request_mem_region(&pdev->dev, res->start, - rtc->regsize, pdev->name); - if (unlikely(!rtc->res)) + regsize = resource_size(res); + req_res = devm_request_mem_region(&pdev->dev, res->start, regsize, pdev->name); + if (!req_res) return -EBUSY; - rtc->regbase = devm_ioremap(&pdev->dev, rtc->res->start, rtc->regsize); - if (unlikely(!rtc->regbase)) + rtc->regbase = devm_ioremap(&pdev->dev, req_res->start, regsize); + if (!rtc->regbase) return -EINVAL; if (!pdev->dev.of_node) { @@ -515,8 +372,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev) clk_id = 0; snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id); - } else + } else { snprintf(clk_name, sizeof(clk_name), "fck"); + } rtc->clk = devm_clk_get(&pdev->dev, clk_name); if (IS_ERR(rtc->clk)) { @@ -550,51 +408,19 @@ static int __init sh_rtc_probe(struct platform_device *pdev) } #endif - if (rtc->carry_irq <= 0) { - /* register shared periodic/carry/alarm irq */ - ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, - sh_rtc_shared, 0, "sh-rtc", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request IRQ failed with %d, IRQ %d\n", ret, - rtc->periodic_irq); - goto err_unmap; - } - } else { - /* register periodic/carry/alarm irqs */ - ret = devm_request_irq(&pdev->dev, rtc->periodic_irq, - sh_rtc_periodic, 0, "sh-rtc period", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request period IRQ failed with %d, IRQ %d\n", - ret, rtc->periodic_irq); - goto err_unmap; - } - - ret = devm_request_irq(&pdev->dev, rtc->carry_irq, - sh_rtc_interrupt, 0, "sh-rtc carry", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request carry IRQ failed with %d, IRQ %d\n", - ret, rtc->carry_irq); - goto err_unmap; - } - - ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, - sh_rtc_alarm, 0, "sh-rtc alarm", rtc); - if (unlikely(ret)) { - dev_err(&pdev->dev, - "request alarm IRQ failed with %d, IRQ %d\n", - ret, rtc->alarm_irq); - goto err_unmap; - } + ret = devm_request_irq(&pdev->dev, rtc->alarm_irq, sh_rtc_alarm, 0, "sh-rtc", rtc); + if (ret) { + dev_err(&pdev->dev, "request alarm IRQ failed with %d, IRQ %d\n", + ret, rtc->alarm_irq); + goto err_unmap; } platform_set_drvdata(pdev, rtc); /* everything disabled by default */ - sh_rtc_setaie(&pdev->dev, 0); - sh_rtc_setcie(&pdev->dev, 0); + tmp = readb(rtc->regbase + RCR1); + tmp &= ~(RCR1_CIE | RCR1_AIE); + writeb(tmp, rtc->regbase + RCR1); rtc->rtc_dev->ops = &sh_rtc_ops; rtc->rtc_dev->max_user_freq = 256; @@ -624,36 +450,27 @@ static void __exit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - sh_rtc_setaie(&pdev->dev, 0); - sh_rtc_setcie(&pdev->dev, 0); + sh_rtc_alarm_irq_enable(&pdev->dev, 0); clk_disable(rtc->clk); } -static void sh_rtc_set_irq_wake(struct device *dev, int enabled) +static int __maybe_unused sh_rtc_suspend(struct device *dev) { struct sh_rtc *rtc = dev_get_drvdata(dev); - irq_set_irq_wake(rtc->periodic_irq, enabled); - - if (rtc->carry_irq > 0) { - irq_set_irq_wake(rtc->carry_irq, enabled); - irq_set_irq_wake(rtc->alarm_irq, enabled); - } -} - -static int __maybe_unused sh_rtc_suspend(struct device *dev) -{ if (device_may_wakeup(dev)) - sh_rtc_set_irq_wake(dev, 1); + irq_set_irq_wake(rtc->alarm_irq, 1); return 0; } static int __maybe_unused sh_rtc_resume(struct device *dev) { + struct sh_rtc *rtc = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) - sh_rtc_set_irq_wake(dev, 0); + irq_set_irq_wake(rtc->alarm_irq, 0); return 0; } @@ -684,8 +501,8 @@ static struct platform_driver sh_rtc_platform_driver __refdata = { module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe); MODULE_DESCRIPTION("SuperH on-chip RTC driver"); -MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, " - "Jamie Lenehan <lenehan@twibble.org>, " - "Angelo Castello <angelo.castello@st.com>"); +MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); +MODULE_AUTHOR("Jamie Lenehan <lenehan@twibble.org>"); +MODULE_AUTHOR("Angelo Castello <angelo.castello@st.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); |