root/drivers/rtc/rtc-fsl-ftm-alarm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtc_readl
  2. rtc_writel
  3. ftm_counter_enable
  4. ftm_counter_disable
  5. ftm_irq_acknowledge
  6. ftm_irq_enable
  7. ftm_irq_disable
  8. ftm_reset_counter
  9. ftm_clean_alarm
  10. ftm_rtc_alarm_interrupt
  11. ftm_rtc_alarm_irq_enable
  12. ftm_rtc_read_time
  13. ftm_rtc_read_alarm
  14. ftm_rtc_set_alarm
  15. ftm_rtc_probe
  16. ftm_alarm_init

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Freescale FlexTimer Module (FTM) alarm device driver.
   4  *
   5  * Copyright 2014 Freescale Semiconductor, Inc.
   6  * Copyright 2019 NXP
   7  *
   8  */
   9 
  10 #include <linux/device.h>
  11 #include <linux/err.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/io.h>
  14 #include <linux/of_address.h>
  15 #include <linux/of_irq.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/of.h>
  18 #include <linux/of_device.h>
  19 #include <linux/module.h>
  20 #include <linux/fsl/ftm.h>
  21 #include <linux/rtc.h>
  22 #include <linux/time.h>
  23 
  24 #define FTM_SC_CLK(c)           ((c) << FTM_SC_CLK_MASK_SHIFT)
  25 
  26 /*
  27  * Select Fixed frequency clock (32KHz) as clock source
  28  * of FlexTimer Module
  29  */
  30 #define FTM_SC_CLKS_FIXED_FREQ  0x02
  31 #define FIXED_FREQ_CLK          32000
  32 
  33 /* Select 128 (2^7) as divider factor */
  34 #define MAX_FREQ_DIV            (1 << FTM_SC_PS_MASK)
  35 
  36 /* Maximum counter value in FlexTimer's CNT registers */
  37 #define MAX_COUNT_VAL           0xffff
  38 
  39 struct ftm_rtc {
  40         struct rtc_device *rtc_dev;
  41         void __iomem *base;
  42         bool big_endian;
  43         u32 alarm_freq;
  44 };
  45 
  46 static inline u32 rtc_readl(struct ftm_rtc *dev, u32 reg)
  47 {
  48         if (dev->big_endian)
  49                 return ioread32be(dev->base + reg);
  50         else
  51                 return ioread32(dev->base + reg);
  52 }
  53 
  54 static inline void rtc_writel(struct ftm_rtc *dev, u32 reg, u32 val)
  55 {
  56         if (dev->big_endian)
  57                 iowrite32be(val, dev->base + reg);
  58         else
  59                 iowrite32(val, dev->base + reg);
  60 }
  61 
  62 static inline void ftm_counter_enable(struct ftm_rtc *rtc)
  63 {
  64         u32 val;
  65 
  66         /* select and enable counter clock source */
  67         val = rtc_readl(rtc, FTM_SC);
  68         val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  69         val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
  70         rtc_writel(rtc, FTM_SC, val);
  71 }
  72 
  73 static inline void ftm_counter_disable(struct ftm_rtc *rtc)
  74 {
  75         u32 val;
  76 
  77         /* disable counter clock source */
  78         val = rtc_readl(rtc, FTM_SC);
  79         val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
  80         rtc_writel(rtc, FTM_SC, val);
  81 }
  82 
  83 static inline void ftm_irq_acknowledge(struct ftm_rtc *rtc)
  84 {
  85         unsigned int timeout = 100;
  86 
  87         /*
  88          *Fix errata A-007728 for flextimer
  89          *      If the FTM counter reaches the FTM_MOD value between
  90          *      the reading of the TOF bit and the writing of 0 to
  91          *      the TOF bit, the process of clearing the TOF bit
  92          *      does not work as expected when FTMx_CONF[NUMTOF] != 0
  93          *      and the current TOF count is less than FTMx_CONF[NUMTOF].
  94          *      If the above condition is met, the TOF bit remains set.
  95          *      If the TOF interrupt is enabled (FTMx_SC[TOIE] = 1),the
  96          *      TOF interrupt also remains asserted.
  97          *
  98          *      Above is the errata discription
  99          *
 100          *      In one word: software clearing TOF bit not works when
 101          *      FTMx_CONF[NUMTOF] was seted as nonzero and FTM counter
 102          *      reaches the FTM_MOD value.
 103          *
 104          *      The workaround is clearing TOF bit until it works
 105          *      (FTM counter doesn't always reache the FTM_MOD anyway),
 106          *      which may cost some cycles.
 107          */
 108         while ((FTM_SC_TOF & rtc_readl(rtc, FTM_SC)) && timeout--)
 109                 rtc_writel(rtc, FTM_SC, rtc_readl(rtc, FTM_SC) & (~FTM_SC_TOF));
 110 }
 111 
 112 static inline void ftm_irq_enable(struct ftm_rtc *rtc)
 113 {
 114         u32 val;
 115 
 116         val = rtc_readl(rtc, FTM_SC);
 117         val |= FTM_SC_TOIE;
 118         rtc_writel(rtc, FTM_SC, val);
 119 }
 120 
 121 static inline void ftm_irq_disable(struct ftm_rtc *rtc)
 122 {
 123         u32 val;
 124 
 125         val = rtc_readl(rtc, FTM_SC);
 126         val &= ~FTM_SC_TOIE;
 127         rtc_writel(rtc, FTM_SC, val);
 128 }
 129 
 130 static inline void ftm_reset_counter(struct ftm_rtc *rtc)
 131 {
 132         /*
 133          * The CNT register contains the FTM counter value.
 134          * Reset clears the CNT register. Writing any value to COUNT
 135          * updates the counter with its initial value, CNTIN.
 136          */
 137         rtc_writel(rtc, FTM_CNT, 0x00);
 138 }
 139 
 140 static void ftm_clean_alarm(struct ftm_rtc *rtc)
 141 {
 142         ftm_counter_disable(rtc);
 143 
 144         rtc_writel(rtc, FTM_CNTIN, 0x00);
 145         rtc_writel(rtc, FTM_MOD, ~0U);
 146 
 147         ftm_reset_counter(rtc);
 148 }
 149 
 150 static irqreturn_t ftm_rtc_alarm_interrupt(int irq, void *dev)
 151 {
 152         struct ftm_rtc *rtc = dev;
 153 
 154         ftm_irq_acknowledge(rtc);
 155         ftm_irq_disable(rtc);
 156         ftm_clean_alarm(rtc);
 157 
 158         return IRQ_HANDLED;
 159 }
 160 
 161 static int ftm_rtc_alarm_irq_enable(struct device *dev,
 162                 unsigned int enabled)
 163 {
 164         struct ftm_rtc *rtc = dev_get_drvdata(dev);
 165 
 166         if (enabled)
 167                 ftm_irq_enable(rtc);
 168         else
 169                 ftm_irq_disable(rtc);
 170 
 171         return 0;
 172 }
 173 
 174 /*
 175  * Note:
 176  *      The function is not really getting time from the RTC
 177  *      since FlexTimer is not a RTC device, but we need to
 178  *      get time to setup alarm, so we are using system time
 179  *      for now.
 180  */
 181 static int ftm_rtc_read_time(struct device *dev, struct rtc_time *tm)
 182 {
 183         struct timespec64 ts64;
 184 
 185         ktime_get_real_ts64(&ts64);
 186         rtc_time_to_tm(ts64.tv_sec, tm);
 187 
 188         return 0;
 189 }
 190 
 191 static int ftm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 192 {
 193         return 0;
 194 }
 195 
 196 /*
 197  * 1. Select fixed frequency clock (32KHz) as clock source;
 198  * 2. Select 128 (2^7) as divider factor;
 199  * So clock is 250 Hz (32KHz/128).
 200  *
 201  * 3. FlexTimer's CNT register is a 32bit register,
 202  * but the register's 16 bit as counter value,it's other 16 bit
 203  * is reserved.So minimum counter value is 0x0,maximum counter
 204  * value is 0xffff.
 205  * So max alarm value is 262 (65536 / 250) seconds
 206  */
 207 static int ftm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 208 {
 209         struct rtc_time tm;
 210         unsigned long now, alm_time, cycle;
 211         struct ftm_rtc *rtc = dev_get_drvdata(dev);
 212 
 213         ftm_rtc_read_time(dev, &tm);
 214         rtc_tm_to_time(&tm, &now);
 215         rtc_tm_to_time(&alm->time, &alm_time);
 216 
 217         ftm_clean_alarm(rtc);
 218         cycle = (alm_time - now) * rtc->alarm_freq;
 219         if (cycle > MAX_COUNT_VAL) {
 220                 pr_err("Out of alarm range {0~262} seconds.\n");
 221                 return -ERANGE;
 222         }
 223 
 224         ftm_irq_disable(rtc);
 225 
 226         /*
 227          * The counter increments until the value of MOD is reached,
 228          * at which point the counter is reloaded with the value of CNTIN.
 229          * The TOF (the overflow flag) bit is set when the FTM counter
 230          * changes from MOD to CNTIN. So we should using the cycle - 1.
 231          */
 232         rtc_writel(rtc, FTM_MOD, cycle - 1);
 233 
 234         ftm_counter_enable(rtc);
 235         ftm_irq_enable(rtc);
 236 
 237         return 0;
 238 
 239 }
 240 
 241 static const struct rtc_class_ops ftm_rtc_ops = {
 242         .read_time              = ftm_rtc_read_time,
 243         .read_alarm             = ftm_rtc_read_alarm,
 244         .set_alarm              = ftm_rtc_set_alarm,
 245         .alarm_irq_enable       = ftm_rtc_alarm_irq_enable,
 246 };
 247 
 248 static int ftm_rtc_probe(struct platform_device *pdev)
 249 {
 250         struct device_node *np = pdev->dev.of_node;
 251         struct resource *r;
 252         int irq;
 253         int ret;
 254         struct ftm_rtc *rtc;
 255 
 256         rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 257         if (unlikely(!rtc)) {
 258                 dev_err(&pdev->dev, "cannot alloc memory for rtc\n");
 259                 return -ENOMEM;
 260         }
 261 
 262         platform_set_drvdata(pdev, rtc);
 263 
 264         rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
 265         if (IS_ERR(rtc->rtc_dev))
 266                 return PTR_ERR(rtc->rtc_dev);
 267 
 268         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 269         if (!r) {
 270                 dev_err(&pdev->dev, "cannot get resource for rtc\n");
 271                 return -ENODEV;
 272         }
 273 
 274         rtc->base = devm_ioremap_resource(&pdev->dev, r);
 275         if (IS_ERR(rtc->base)) {
 276                 dev_err(&pdev->dev, "cannot ioremap resource for rtc\n");
 277                 return PTR_ERR(rtc->base);
 278         }
 279 
 280         irq = irq_of_parse_and_map(np, 0);
 281         if (irq <= 0) {
 282                 dev_err(&pdev->dev, "unable to get IRQ from DT, %d\n", irq);
 283                 return -EINVAL;
 284         }
 285 
 286         ret = devm_request_irq(&pdev->dev, irq, ftm_rtc_alarm_interrupt,
 287                                IRQF_NO_SUSPEND, dev_name(&pdev->dev), rtc);
 288         if (ret < 0) {
 289                 dev_err(&pdev->dev, "failed to request irq\n");
 290                 return ret;
 291         }
 292 
 293         rtc->big_endian = of_property_read_bool(np, "big-endian");
 294         rtc->alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
 295         rtc->rtc_dev->ops = &ftm_rtc_ops;
 296 
 297         device_init_wakeup(&pdev->dev, true);
 298 
 299         ret = rtc_register_device(rtc->rtc_dev);
 300         if (ret) {
 301                 dev_err(&pdev->dev, "can't register rtc device\n");
 302                 return ret;
 303         }
 304 
 305         return 0;
 306 }
 307 
 308 static const struct of_device_id ftm_rtc_match[] = {
 309         { .compatible = "fsl,ls1012a-ftm-alarm", },
 310         { .compatible = "fsl,ls1021a-ftm-alarm", },
 311         { .compatible = "fsl,ls1028a-ftm-alarm", },
 312         { .compatible = "fsl,ls1043a-ftm-alarm", },
 313         { .compatible = "fsl,ls1046a-ftm-alarm", },
 314         { .compatible = "fsl,ls1088a-ftm-alarm", },
 315         { .compatible = "fsl,ls208xa-ftm-alarm", },
 316         { .compatible = "fsl,lx2160a-ftm-alarm", },
 317         { },
 318 };
 319 
 320 static struct platform_driver ftm_rtc_driver = {
 321         .probe          = ftm_rtc_probe,
 322         .driver         = {
 323                 .name   = "ftm-alarm",
 324                 .of_match_table = ftm_rtc_match,
 325         },
 326 };
 327 
 328 static int __init ftm_alarm_init(void)
 329 {
 330         return platform_driver_register(&ftm_rtc_driver);
 331 }
 332 
 333 device_initcall(ftm_alarm_init);
 334 
 335 MODULE_DESCRIPTION("NXP/Freescale FlexTimer alarm driver");
 336 MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>");
 337 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */