^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* drivers/rtc/rtc-s3c.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2010 Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * http://www.samsung.com/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2004,2006 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Ben Dooks, <ben@simtec.co.uk>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * http://armlinux.simtec.co.uk/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * S3C2410/S3C2440/S3C24XX Internal RTC Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/rtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/bcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "rtc-s3c.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct s3c_rtc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct rtc_device *rtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct clk *rtc_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct clk *rtc_src_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bool alarm_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) const struct s3c_rtc_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int irq_alarm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int irq_tick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) spinlock_t pie_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) spinlock_t alarm_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int ticnt_save;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int ticnt_en_save;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) bool wake_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct s3c_rtc_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int max_user_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) bool needs_src_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) void (*irq_handler) (struct s3c_rtc *info, int mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) void (*set_freq) (struct s3c_rtc *info, int freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) void (*select_tick_clk) (struct s3c_rtc *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void (*save_tick_cnt) (struct s3c_rtc *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) void (*restore_tick_cnt) (struct s3c_rtc *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) void (*enable) (struct s3c_rtc *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) void (*disable) (struct s3c_rtc *info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int s3c_rtc_enable_clk(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = clk_enable(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (info->data->needs_src_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ret = clk_enable(info->rtc_src_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) clk_disable(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void s3c_rtc_disable_clk(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (info->data->needs_src_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) clk_disable(info->rtc_src_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) clk_disable(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* IRQ Handlers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct s3c_rtc *info = (struct s3c_rtc *)id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (info->data->irq_handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) info->data->irq_handler(info, S3C2410_INTP_TIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct s3c_rtc *info = (struct s3c_rtc *)id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (info->data->irq_handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) info->data->irq_handler(info, S3C2410_INTP_ALM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* Update control registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) unsigned int tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) tmp |= S3C2410_RTCALM_ALMEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) writeb(tmp, info->base + S3C2410_RTCALM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) spin_lock_irqsave(&info->alarm_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (info->alarm_enabled && !enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) else if (!info->alarm_enabled && enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) info->alarm_enabled = enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) spin_unlock_irqrestore(&info->alarm_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Set RTC frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (!is_power_of_2(freq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) spin_lock_irq(&info->pie_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (info->data->set_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) info->data->set_freq(info, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) spin_unlock_irq(&info->pie_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* Time read/write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) unsigned int have_retried = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) retry_get_time:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* the only way to work out whether the system was mid-update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * when we read it is to check the second counter, and if it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * is zero, then we re-try the entire read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (rtc_tm->tm_sec == 0 && !have_retried) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) have_retried = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto retry_get_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) rtc_tm->tm_year += 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) rtc_tm->tm_mon -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) dev_dbg(dev, "read time %ptR\n", rtc_tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int year = tm->tm_year - 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) dev_dbg(dev, "set time %ptR\n", tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* we get around y2k by simply not supporting it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (year < 0 || year >= 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) dev_err(dev, "rtc only supports 100 years\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct rtc_time *alm_tm = &alrm->time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) unsigned int alm_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) alm_en = readb(info->base + S3C2410_RTCALM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* decode the alarm enable field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (alm_en & S3C2410_RTCALM_SECEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (alm_en & S3C2410_RTCALM_MINEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (alm_en & S3C2410_RTCALM_HOUREN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (alm_en & S3C2410_RTCALM_DAYEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (alm_en & S3C2410_RTCALM_MONEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) alm_tm->tm_mon -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (alm_en & S3C2410_RTCALM_YEAREN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct rtc_time *tm = &alrm->time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) unsigned int alrm_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) writeb(0x00, info->base + S3C2410_RTCALM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) alrm_en |= S3C2410_RTCALM_SECEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (tm->tm_min < 60 && tm->tm_min >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) alrm_en |= S3C2410_RTCALM_MINEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) alrm_en |= S3C2410_RTCALM_HOUREN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) alrm_en |= S3C2410_RTCALM_MONEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) alrm_en |= S3C2410_RTCALM_DAYEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) writeb(alrm_en, info->base + S3C2410_RTCALM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) s3c_rtc_setaie(dev, alrm->enabled);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (info->data->enable_tick)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) info->data->enable_tick(info, seq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static const struct rtc_class_ops s3c_rtcops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) .read_time = s3c_rtc_gettime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .set_time = s3c_rtc_settime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) .read_alarm = s3c_rtc_getalarm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) .set_alarm = s3c_rtc_setalarm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) .proc = s3c_rtc_proc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .alarm_irq_enable = s3c_rtc_setaie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static void s3c24xx_rtc_enable(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) unsigned int con, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) con = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* re-enable the device, and check it is ok */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if ((con & S3C2410_RTCCON_RTCEN) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) dev_info(info->dev, "rtc disabled, re-enabling\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) tmp = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (con & S3C2410_RTCCON_CNTSEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) dev_info(info->dev, "removing RTCCON_CNTSEL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) tmp = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) writew(tmp & ~S3C2410_RTCCON_CNTSEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (con & S3C2410_RTCCON_CLKRST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) dev_info(info->dev, "removing RTCCON_CLKRST\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) tmp = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) writew(tmp & ~S3C2410_RTCCON_CLKRST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static void s3c24xx_rtc_disable(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) unsigned int con;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) con = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) con &= ~S3C2410_RTCCON_RTCEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) writew(con, info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) con = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) con &= ~S3C2410_TICNT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) writeb(con, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static void s3c6410_rtc_disable(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) unsigned int con;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) con = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) con &= ~S3C64XX_RTCCON_TICEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) con &= ~S3C2410_RTCCON_RTCEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) writew(con, info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static int s3c_rtc_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) struct s3c_rtc *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) s3c_rtc_setaie(info->dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (info->data->needs_src_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) clk_unprepare(info->rtc_src_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) clk_unprepare(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static int s3c_rtc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct s3c_rtc *info = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct rtc_time rtc_tm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /* find the IRQs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) info->irq_tick = platform_get_irq(pdev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (info->irq_tick < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return info->irq_tick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) info->data = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (!info->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) spin_lock_init(&info->pie_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) spin_lock_init(&info->alarm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) info->irq_alarm = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (info->irq_alarm < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return info->irq_alarm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) info->irq_tick, info->irq_alarm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /* get the memory region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) info->base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (IS_ERR(info->base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return PTR_ERR(info->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (IS_ERR(info->rtc_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) ret = PTR_ERR(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) dev_err(&pdev->dev, "failed to find rtc clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) ret = clk_prepare_enable(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (info->data->needs_src_clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (IS_ERR(info->rtc_src_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) "failed to find rtc source clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) goto err_src_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) ret = clk_prepare_enable(info->rtc_src_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) goto err_src_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) /* check to see if everything is setup correctly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (info->data->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) info->data->enable(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) readw(info->base + S3C2410_RTCCON));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) device_init_wakeup(&pdev->dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) /* Check RTC Time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) rtc_tm.tm_year = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) rtc_tm.tm_mon = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) rtc_tm.tm_mday = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) rtc_tm.tm_hour = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) rtc_tm.tm_min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) rtc_tm.tm_sec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) s3c_rtc_settime(&pdev->dev, &rtc_tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /* register RTC and exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) THIS_MODULE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (IS_ERR(info->rtc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) dev_err(&pdev->dev, "cannot attach rtc\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) ret = PTR_ERR(info->rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) goto err_nortc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 0, "s3c2410-rtc alarm", info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) goto err_nortc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 0, "s3c2410-rtc tick", info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) goto err_nortc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (info->data->select_tick_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) info->data->select_tick_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) s3c_rtc_setfreq(info, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) err_nortc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (info->data->disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) info->data->disable(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (info->data->needs_src_clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) clk_disable_unprepare(info->rtc_src_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) err_src_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) clk_disable_unprepare(info->rtc_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) static int s3c_rtc_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) ret = s3c_rtc_enable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) /* save TICNT for anyone using periodic interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (info->data->save_tick_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) info->data->save_tick_cnt(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (info->data->disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) info->data->disable(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (device_may_wakeup(dev) && !info->wake_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (enable_irq_wake(info->irq_alarm) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) info->wake_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) dev_err(dev, "enable_irq_wake failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) static int s3c_rtc_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct s3c_rtc *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (info->data->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) info->data->enable(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (info->data->restore_tick_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) info->data->restore_tick_cnt(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) s3c_rtc_disable_clk(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (device_may_wakeup(dev) && info->wake_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) disable_irq_wake(info->irq_alarm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) info->wake_en = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) writeb(mask, info->base + S3C2410_INTP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) unsigned int tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) tmp = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) tmp &= S3C2410_TICNT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) val = (info->rtc->max_user_freq / freq) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) tmp |= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) writel(tmp, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) unsigned int tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) tmp = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) tmp &= S3C2410_TICNT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) val = (info->rtc->max_user_freq / freq) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) tmp |= S3C2443_TICNT_PART(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) writel(tmp, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) unsigned int tmp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) tmp = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) tmp &= S3C2410_TICNT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) val = (info->rtc->max_user_freq / freq) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) tmp |= S3C2443_TICNT_PART(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) writel(tmp, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) val = (info->rtc->max_user_freq / freq) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) writel(val, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) unsigned int ticnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) ticnt = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) ticnt &= S3C2410_TICNT_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) unsigned int con;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) con = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) con |= S3C2443_RTCCON_TICSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) writew(con, info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) unsigned int ticnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) ticnt = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) ticnt &= S3C64XX_RTCCON_TICEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) info->ticnt_save = readb(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) writeb(info->ticnt_save, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) info->ticnt_save = readl(info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) unsigned int con;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) writel(info->ticnt_save, info->base + S3C2410_TICNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (info->ticnt_en_save) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) con = readw(info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) static struct s3c_rtc_data const s3c2410_rtc_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) .max_user_freq = 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) .irq_handler = s3c24xx_rtc_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) .set_freq = s3c2410_rtc_setfreq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) .enable_tick = s3c24xx_rtc_enable_tick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) .enable = s3c24xx_rtc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) .disable = s3c24xx_rtc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) static struct s3c_rtc_data const s3c2416_rtc_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) .max_user_freq = 32768,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) .irq_handler = s3c24xx_rtc_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) .set_freq = s3c2416_rtc_setfreq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) .enable_tick = s3c24xx_rtc_enable_tick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) .select_tick_clk = s3c2416_rtc_select_tick_clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) .enable = s3c24xx_rtc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) .disable = s3c24xx_rtc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static struct s3c_rtc_data const s3c2443_rtc_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) .max_user_freq = 32768,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) .irq_handler = s3c24xx_rtc_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) .set_freq = s3c2443_rtc_setfreq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) .enable_tick = s3c24xx_rtc_enable_tick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) .select_tick_clk = s3c2416_rtc_select_tick_clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) .enable = s3c24xx_rtc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) .disable = s3c24xx_rtc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static struct s3c_rtc_data const s3c6410_rtc_data = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) .max_user_freq = 32768,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) .needs_src_clk = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) .irq_handler = s3c6410_rtc_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) .set_freq = s3c6410_rtc_setfreq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) .enable_tick = s3c6410_rtc_enable_tick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) .save_tick_cnt = s3c6410_rtc_save_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) .enable = s3c24xx_rtc_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) .disable = s3c6410_rtc_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) static const struct of_device_id s3c_rtc_dt_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) .compatible = "samsung,s3c2410-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) .data = &s3c2410_rtc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) .compatible = "samsung,s3c2416-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) .data = &s3c2416_rtc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) .compatible = "samsung,s3c2443-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) .data = &s3c2443_rtc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) .compatible = "samsung,s3c6410-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) .data = &s3c6410_rtc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .compatible = "samsung,exynos3250-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .data = &s3c6410_rtc_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) { /* sentinel */ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) static struct platform_driver s3c_rtc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) .probe = s3c_rtc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) .remove = s3c_rtc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) .name = "s3c-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) .pm = &s3c_rtc_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) .of_match_table = of_match_ptr(s3c_rtc_dt_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) module_platform_driver(s3c_rtc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) MODULE_DESCRIPTION("Samsung S3C RTC Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) MODULE_ALIAS("platform:s3c2410-rtc");