linux/drivers/rtc/rtc-ep93xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * A driver for the RTC embedded in the Cirrus Logic EP93XX processors
   4 * Copyright (c) 2006 Tower Technologies
   5 *
   6 * Author: Alessandro Zummo <a.zummo@towertech.it>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/rtc.h>
  11#include <linux/platform_device.h>
  12#include <linux/io.h>
  13#include <linux/gfp.h>
  14
  15#define EP93XX_RTC_DATA                 0x000
  16#define EP93XX_RTC_MATCH                0x004
  17#define EP93XX_RTC_STATUS               0x008
  18#define  EP93XX_RTC_STATUS_INTR          BIT(0)
  19#define EP93XX_RTC_LOAD                 0x00C
  20#define EP93XX_RTC_CONTROL              0x010
  21#define  EP93XX_RTC_CONTROL_MIE          BIT(0)
  22#define EP93XX_RTC_SWCOMP               0x108
  23#define  EP93XX_RTC_SWCOMP_DEL_MASK      0x001f0000
  24#define  EP93XX_RTC_SWCOMP_DEL_SHIFT     16
  25#define  EP93XX_RTC_SWCOMP_INT_MASK      0x0000ffff
  26#define  EP93XX_RTC_SWCOMP_INT_SHIFT     0
  27
  28struct ep93xx_rtc {
  29        void __iomem    *mmio_base;
  30        struct rtc_device *rtc;
  31};
  32
  33static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
  34                                 unsigned short *delete)
  35{
  36        struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
  37        unsigned long comp;
  38
  39        comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
  40
  41        if (preload)
  42                *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
  43                                >> EP93XX_RTC_SWCOMP_INT_SHIFT;
  44
  45        if (delete)
  46                *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
  47                                >> EP93XX_RTC_SWCOMP_DEL_SHIFT;
  48
  49        return 0;
  50}
  51
  52static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
  53{
  54        struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
  55        unsigned long time;
  56
  57        time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
  58
  59        rtc_time64_to_tm(time, tm);
  60        return 0;
  61}
  62
  63static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
  64{
  65        struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
  66        unsigned long secs = rtc_tm_to_time64(tm);
  67
  68        writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
  69        return 0;
  70}
  71
  72static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
  73{
  74        unsigned short preload, delete;
  75
  76        ep93xx_rtc_get_swcomp(dev, &preload, &delete);
  77
  78        seq_printf(seq, "preload\t\t: %d\n", preload);
  79        seq_printf(seq, "delete\t\t: %d\n", delete);
  80
  81        return 0;
  82}
  83
  84static const struct rtc_class_ops ep93xx_rtc_ops = {
  85        .read_time      = ep93xx_rtc_read_time,
  86        .set_time       = ep93xx_rtc_set_time,
  87        .proc           = ep93xx_rtc_proc,
  88};
  89
  90static ssize_t comp_preload_show(struct device *dev,
  91                                 struct device_attribute *attr, char *buf)
  92{
  93        unsigned short preload;
  94
  95        ep93xx_rtc_get_swcomp(dev->parent, &preload, NULL);
  96
  97        return sprintf(buf, "%d\n", preload);
  98}
  99static DEVICE_ATTR_RO(comp_preload);
 100
 101static ssize_t comp_delete_show(struct device *dev,
 102                                struct device_attribute *attr, char *buf)
 103{
 104        unsigned short delete;
 105
 106        ep93xx_rtc_get_swcomp(dev->parent, NULL, &delete);
 107
 108        return sprintf(buf, "%d\n", delete);
 109}
 110static DEVICE_ATTR_RO(comp_delete);
 111
 112static struct attribute *ep93xx_rtc_attrs[] = {
 113        &dev_attr_comp_preload.attr,
 114        &dev_attr_comp_delete.attr,
 115        NULL
 116};
 117
 118static const struct attribute_group ep93xx_rtc_sysfs_files = {
 119        .attrs  = ep93xx_rtc_attrs,
 120};
 121
 122static int ep93xx_rtc_probe(struct platform_device *pdev)
 123{
 124        struct ep93xx_rtc *ep93xx_rtc;
 125        int err;
 126
 127        ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
 128        if (!ep93xx_rtc)
 129                return -ENOMEM;
 130
 131        ep93xx_rtc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 132        if (IS_ERR(ep93xx_rtc->mmio_base))
 133                return PTR_ERR(ep93xx_rtc->mmio_base);
 134
 135        platform_set_drvdata(pdev, ep93xx_rtc);
 136
 137        ep93xx_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
 138        if (IS_ERR(ep93xx_rtc->rtc))
 139                return PTR_ERR(ep93xx_rtc->rtc);
 140
 141        ep93xx_rtc->rtc->ops = &ep93xx_rtc_ops;
 142        ep93xx_rtc->rtc->range_max = U32_MAX;
 143
 144        err = rtc_add_group(ep93xx_rtc->rtc, &ep93xx_rtc_sysfs_files);
 145        if (err)
 146                return err;
 147
 148        return devm_rtc_register_device(ep93xx_rtc->rtc);
 149}
 150
 151static struct platform_driver ep93xx_rtc_driver = {
 152        .driver         = {
 153                .name   = "ep93xx-rtc",
 154        },
 155        .probe          = ep93xx_rtc_probe,
 156};
 157
 158module_platform_driver(ep93xx_rtc_driver);
 159
 160MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 161MODULE_DESCRIPTION("EP93XX RTC driver");
 162MODULE_LICENSE("GPL");
 163MODULE_ALIAS("platform:ep93xx-rtc");
 164