1 /* 2 * Freescale STMP37XX/STMP378X Real Time Clock driver 3 * 4 * Copyright (c) 2007 Sigmatel, Inc. 5 * Peter Hartley, <peter.hartley@sigmatel.com> 6 * 7 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. 8 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. 9 * Copyright 2011 Wolfram Sang, Pengutronix e.K. 10 */ 11 12 /* 13 * The code contained herein is licensed under the GNU General Public 14 * License. You may obtain a copy of the GNU General Public License 15 * Version 2 or later at the following locations: 16 * 17 * http://www.opensource.org/licenses/gpl-license.html 18 * http://www.gnu.org/copyleft/gpl.html 19 */ 20 #include <linux/kernel.h> 21 #include <linux/module.h> 22 #include <linux/io.h> 23 #include <linux/init.h> 24 #include <linux/platform_device.h> 25 #include <linux/interrupt.h> 26 #include <linux/rtc.h> 27 #include <linux/slab.h> 28 29 #include <mach/common.h> 30 31 #define STMP3XXX_RTC_CTRL 0x0 32 #define STMP3XXX_RTC_CTRL_SET 0x4 33 #define STMP3XXX_RTC_CTRL_CLR 0x8 34 #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 35 #define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 36 #define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 37 38 #define STMP3XXX_RTC_STAT 0x10 39 #define STMP3XXX_RTC_STAT_STALE_SHIFT 16 40 #define STMP3XXX_RTC_STAT_RTC_PRESENT 0x80000000 41 42 #define STMP3XXX_RTC_SECONDS 0x30 43 44 #define STMP3XXX_RTC_ALARM 0x40 45 46 #define STMP3XXX_RTC_PERSISTENT0 0x60 47 #define STMP3XXX_RTC_PERSISTENT0_SET 0x64 48 #define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 49 #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002 50 #define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 51 #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 52 53 struct stmp3xxx_rtc_data { 54 struct rtc_device *rtc; 55 void __iomem *io; 56 int irq_alarm; 57 }; 58 59 static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) 60 { 61 /* 62 * The datasheet doesn't say which way round the 63 * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, 64 * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS 65 */ 66 while (readl(rtc_data->io + STMP3XXX_RTC_STAT) & 67 (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) 68 cpu_relax(); 69 } 70 71 /* Time read/write */ 72 static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) 73 { 74 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); 75 76 stmp3xxx_wait_time(rtc_data); 77 rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); 78 return 0; 79 } 80 81 static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) 82 { 83 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); 84 85 writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); 86 stmp3xxx_wait_time(rtc_data); 87 return 0; 88 } 89 90 /* interrupt(s) handler */ 91 static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) 92 { 93 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev_id); 94 u32 status = readl(rtc_data->io + STMP3XXX_RTC_CTRL); 95 96 if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { 97 writel(STMP3XXX_RTC_CTRL_ALARM_IRQ, 98 rtc_data->io + STMP3XXX_RTC_CTRL_CLR); 99 rtc_update_irq(rtc_data->rtc, 1, RTC_AF | RTC_IRQF); 100 return IRQ_HANDLED; 101 } 102 103 return IRQ_NONE; 104 } 105 106 static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) 107 { 108 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); 109 110 if (enabled) { 111 writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | 112 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, 113 rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); 114 writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, 115 rtc_data->io + STMP3XXX_RTC_CTRL_SET); 116 } else { 117 writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | 118 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, 119 rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); 120 writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, 121 rtc_data->io + STMP3XXX_RTC_CTRL_CLR); 122 } 123 return 0; 124 } 125 126 static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) 127 { 128 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); 129 130 rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_ALARM), &alm->time); 131 return 0; 132 } 133 134 static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) 135 { 136 unsigned long t; 137 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); 138 139 rtc_tm_to_time(&alm->time, &t); 140 writel(t, rtc_data->io + STMP3XXX_RTC_ALARM); 141 142 stmp3xxx_alarm_irq_enable(dev, alm->enabled); 143 144 return 0; 145 } 146 147 static struct rtc_class_ops stmp3xxx_rtc_ops = { 148 .alarm_irq_enable = 149 stmp3xxx_alarm_irq_enable, 150 .read_time = stmp3xxx_rtc_gettime, 151 .set_mmss = stmp3xxx_rtc_set_mmss, 152 .read_alarm = stmp3xxx_rtc_read_alarm, 153 .set_alarm = stmp3xxx_rtc_set_alarm, 154 }; 155 156 static int stmp3xxx_rtc_remove(struct platform_device *pdev) 157 { 158 struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(pdev); 159 160 if (!rtc_data) 161 return 0; 162 163 writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, 164 rtc_data->io + STMP3XXX_RTC_CTRL_CLR); 165 free_irq(rtc_data->irq_alarm, &pdev->dev); 166 rtc_device_unregister(rtc_data->rtc); 167 platform_set_drvdata(pdev, NULL); 168 iounmap(rtc_data->io); 169 kfree(rtc_data); 170 171 return 0; 172 } 173 174 static int stmp3xxx_rtc_probe(struct platform_device *pdev) 175 { 176 struct stmp3xxx_rtc_data *rtc_data; 177 struct resource *r; 178 int err; 179 180 rtc_data = kzalloc(sizeof *rtc_data, GFP_KERNEL); 181 if (!rtc_data) 182 return -ENOMEM; 183 184 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 185 if (!r) { 186 dev_err(&pdev->dev, "failed to get resource\n"); 187 err = -ENXIO; 188 goto out_free; 189 } 190 191 rtc_data->io = ioremap(r->start, resource_size(r)); 192 if (!rtc_data->io) { 193 dev_err(&pdev->dev, "ioremap failed\n"); 194 err = -EIO; 195 goto out_free; 196 } 197 198 rtc_data->irq_alarm = platform_get_irq(pdev, 0); 199 200 if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) & 201 STMP3XXX_RTC_STAT_RTC_PRESENT)) { 202 dev_err(&pdev->dev, "no device onboard\n"); 203 err = -ENODEV; 204 goto out_remap; 205 } 206 207 platform_set_drvdata(pdev, rtc_data); 208 209 mxs_reset_block(rtc_data->io); 210 writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | 211 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | 212 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, 213 rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); 214 215 writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | 216 STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, 217 rtc_data->io + STMP3XXX_RTC_CTRL_CLR); 218 219 rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev, 220 &stmp3xxx_rtc_ops, THIS_MODULE); 221 if (IS_ERR(rtc_data->rtc)) { 222 err = PTR_ERR(rtc_data->rtc); 223 goto out_remap; 224 } 225 226 err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0, 227 "RTC alarm", &pdev->dev); 228 if (err) { 229 dev_err(&pdev->dev, "Cannot claim IRQ%d\n", 230 rtc_data->irq_alarm); 231 goto out_irq_alarm; 232 } 233 234 return 0; 235 236 out_irq_alarm: 237 rtc_device_unregister(rtc_data->rtc); 238 out_remap: 239 platform_set_drvdata(pdev, NULL); 240 iounmap(rtc_data->io); 241 out_free: 242 kfree(rtc_data); 243 return err; 244 } 245 246 #ifdef CONFIG_PM 247 static int stmp3xxx_rtc_suspend(struct platform_device *dev, pm_message_t state) 248 { 249 return 0; 250 } 251 252 static int stmp3xxx_rtc_resume(struct platform_device *dev) 253 { 254 struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev); 255 256 mxs_reset_block(rtc_data->io); 257 writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | 258 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | 259 STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, 260 rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); 261 return 0; 262 } 263 #else 264 #define stmp3xxx_rtc_suspend NULL 265 #define stmp3xxx_rtc_resume NULL 266 #endif 267 268 static struct platform_driver stmp3xxx_rtcdrv = { 269 .probe = stmp3xxx_rtc_probe, 270 .remove = stmp3xxx_rtc_remove, 271 .suspend = stmp3xxx_rtc_suspend, 272 .resume = stmp3xxx_rtc_resume, 273 .driver = { 274 .name = "stmp3xxx-rtc", 275 .owner = THIS_MODULE, 276 }, 277 }; 278 279 module_platform_driver(stmp3xxx_rtcdrv); 280 281 MODULE_DESCRIPTION("STMP3xxx RTC Driver"); 282 MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com> and " 283 "Wolfram Sang <w.sang@pengutronix.de>"); 284 MODULE_LICENSE("GPL"); 285