0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0012
0013 #include <linux/delay.h>
0014 #include <linux/io.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/rtc.h>
0019 #include <linux/slab.h>
0020
0021
0022 enum {
0023 MSM6242_SECOND1 = 0x0,
0024 MSM6242_SECOND10 = 0x1,
0025 MSM6242_MINUTE1 = 0x2,
0026 MSM6242_MINUTE10 = 0x3,
0027 MSM6242_HOUR1 = 0x4,
0028 MSM6242_HOUR10 = 0x5,
0029 MSM6242_DAY1 = 0x6,
0030 MSM6242_DAY10 = 0x7,
0031 MSM6242_MONTH1 = 0x8,
0032 MSM6242_MONTH10 = 0x9,
0033 MSM6242_YEAR1 = 0xa,
0034 MSM6242_YEAR10 = 0xb,
0035 MSM6242_WEEK = 0xc,
0036 MSM6242_CD = 0xd,
0037 MSM6242_CE = 0xe,
0038 MSM6242_CF = 0xf,
0039 };
0040
0041 #define MSM6242_HOUR10_AM (0 << 2)
0042 #define MSM6242_HOUR10_PM (1 << 2)
0043 #define MSM6242_HOUR10_HR_MASK (3 << 0)
0044
0045 #define MSM6242_WEEK_SUNDAY 0
0046 #define MSM6242_WEEK_MONDAY 1
0047 #define MSM6242_WEEK_TUESDAY 2
0048 #define MSM6242_WEEK_WEDNESDAY 3
0049 #define MSM6242_WEEK_THURSDAY 4
0050 #define MSM6242_WEEK_FRIDAY 5
0051 #define MSM6242_WEEK_SATURDAY 6
0052
0053 #define MSM6242_CD_30_S_ADJ (1 << 3)
0054 #define MSM6242_CD_IRQ_FLAG (1 << 2)
0055 #define MSM6242_CD_BUSY (1 << 1)
0056 #define MSM6242_CD_HOLD (1 << 0)
0057
0058 #define MSM6242_CE_T_MASK (3 << 2)
0059 #define MSM6242_CE_T_64HZ (0 << 2)
0060 #define MSM6242_CE_T_1HZ (1 << 2)
0061 #define MSM6242_CE_T_1MINUTE (2 << 2)
0062 #define MSM6242_CE_T_1HOUR (3 << 2)
0063
0064 #define MSM6242_CE_ITRPT_STND (1 << 1)
0065 #define MSM6242_CE_MASK (1 << 0)
0066
0067 #define MSM6242_CF_TEST (1 << 3)
0068 #define MSM6242_CF_12H (0 << 2)
0069 #define MSM6242_CF_24H (1 << 2)
0070 #define MSM6242_CF_STOP (1 << 1)
0071 #define MSM6242_CF_REST (1 << 0)
0072
0073
0074 struct msm6242_priv {
0075 u32 __iomem *regs;
0076 struct rtc_device *rtc;
0077 };
0078
0079 static inline unsigned int msm6242_read(struct msm6242_priv *priv,
0080 unsigned int reg)
0081 {
0082 return __raw_readl(&priv->regs[reg]) & 0xf;
0083 }
0084
0085 static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
0086 unsigned int reg)
0087 {
0088 __raw_writel(val, &priv->regs[reg]);
0089 }
0090
0091 static void msm6242_lock(struct msm6242_priv *priv)
0092 {
0093 int cnt = 5;
0094
0095 msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);
0096
0097 while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) {
0098 msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
0099 udelay(70);
0100 msm6242_write(priv, MSM6242_CD_HOLD|MSM6242_CD_IRQ_FLAG, MSM6242_CD);
0101 cnt--;
0102 }
0103
0104 if (!cnt)
0105 pr_warn("timed out waiting for RTC (0x%x)\n",
0106 msm6242_read(priv, MSM6242_CD));
0107 }
0108
0109 static void msm6242_unlock(struct msm6242_priv *priv)
0110 {
0111 msm6242_write(priv, MSM6242_CD_IRQ_FLAG, MSM6242_CD);
0112 }
0113
0114 static int msm6242_read_time(struct device *dev, struct rtc_time *tm)
0115 {
0116 struct msm6242_priv *priv = dev_get_drvdata(dev);
0117
0118 msm6242_lock(priv);
0119
0120 tm->tm_sec = msm6242_read(priv, MSM6242_SECOND10) * 10 +
0121 msm6242_read(priv, MSM6242_SECOND1);
0122 tm->tm_min = msm6242_read(priv, MSM6242_MINUTE10) * 10 +
0123 msm6242_read(priv, MSM6242_MINUTE1);
0124 tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) &
0125 MSM6242_HOUR10_HR_MASK) * 10 +
0126 msm6242_read(priv, MSM6242_HOUR1);
0127 tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 +
0128 msm6242_read(priv, MSM6242_DAY1);
0129 tm->tm_wday = msm6242_read(priv, MSM6242_WEEK);
0130 tm->tm_mon = msm6242_read(priv, MSM6242_MONTH10) * 10 +
0131 msm6242_read(priv, MSM6242_MONTH1) - 1;
0132 tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 +
0133 msm6242_read(priv, MSM6242_YEAR1);
0134 if (tm->tm_year <= 69)
0135 tm->tm_year += 100;
0136
0137 if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) {
0138 unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) &
0139 MSM6242_HOUR10_PM;
0140 if (!pm && tm->tm_hour == 12)
0141 tm->tm_hour = 0;
0142 else if (pm && tm->tm_hour != 12)
0143 tm->tm_hour += 12;
0144 }
0145
0146 msm6242_unlock(priv);
0147
0148 return 0;
0149 }
0150
0151 static int msm6242_set_time(struct device *dev, struct rtc_time *tm)
0152 {
0153 struct msm6242_priv *priv = dev_get_drvdata(dev);
0154
0155 msm6242_lock(priv);
0156
0157 msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10);
0158 msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1);
0159 msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10);
0160 msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1);
0161 if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)
0162 msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
0163 else if (tm->tm_hour >= 12)
0164 msm6242_write(priv, MSM6242_HOUR10_PM + (tm->tm_hour - 12) / 10,
0165 MSM6242_HOUR10);
0166 else
0167 msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10);
0168 msm6242_write(priv, tm->tm_hour % 10, MSM6242_HOUR1);
0169 msm6242_write(priv, tm->tm_mday / 10, MSM6242_DAY10);
0170 msm6242_write(priv, tm->tm_mday % 10, MSM6242_DAY1);
0171 if (tm->tm_wday != -1)
0172 msm6242_write(priv, tm->tm_wday, MSM6242_WEEK);
0173 msm6242_write(priv, (tm->tm_mon + 1) / 10, MSM6242_MONTH10);
0174 msm6242_write(priv, (tm->tm_mon + 1) % 10, MSM6242_MONTH1);
0175 if (tm->tm_year >= 100)
0176 tm->tm_year -= 100;
0177 msm6242_write(priv, tm->tm_year / 10, MSM6242_YEAR10);
0178 msm6242_write(priv, tm->tm_year % 10, MSM6242_YEAR1);
0179
0180 msm6242_unlock(priv);
0181 return 0;
0182 }
0183
0184 static const struct rtc_class_ops msm6242_rtc_ops = {
0185 .read_time = msm6242_read_time,
0186 .set_time = msm6242_set_time,
0187 };
0188
0189 static int __init msm6242_rtc_probe(struct platform_device *pdev)
0190 {
0191 struct resource *res;
0192 struct msm6242_priv *priv;
0193 struct rtc_device *rtc;
0194
0195 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0196 if (!res)
0197 return -ENODEV;
0198
0199 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0200 if (!priv)
0201 return -ENOMEM;
0202
0203 priv->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
0204 if (!priv->regs)
0205 return -ENOMEM;
0206 platform_set_drvdata(pdev, priv);
0207
0208 rtc = devm_rtc_device_register(&pdev->dev, "rtc-msm6242",
0209 &msm6242_rtc_ops, THIS_MODULE);
0210 if (IS_ERR(rtc))
0211 return PTR_ERR(rtc);
0212
0213 priv->rtc = rtc;
0214 return 0;
0215 }
0216
0217 static struct platform_driver msm6242_rtc_driver = {
0218 .driver = {
0219 .name = "rtc-msm6242",
0220 },
0221 };
0222
0223 module_platform_driver_probe(msm6242_rtc_driver, msm6242_rtc_probe);
0224
0225 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
0226 MODULE_LICENSE("GPL");
0227 MODULE_DESCRIPTION("Oki MSM6242 RTC driver");
0228 MODULE_ALIAS("platform:rtc-msm6242");