linux/drivers/rtc/rtc-ep93xx.c
<<
>>
Prefs
   1/*
   2 * A driver for the RTC embedded in the Cirrus Logic EP93XX processors
   3 * Copyright (c) 2006 Tower Technologies
   4 *
   5 * Author: Alessandro Zummo <a.zummo@towertech.it>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/rtc.h>
  14#include <linux/platform_device.h>
  15#include <linux/io.h>
  16#include <linux/gfp.h>
  17
  18#define EP93XX_RTC_DATA                 0x000
  19#define EP93XX_RTC_MATCH                0x004
  20#define EP93XX_RTC_STATUS               0x008
  21#define  EP93XX_RTC_STATUS_INTR          (1<<0)
  22#define EP93XX_RTC_LOAD                 0x00C
  23#define EP93XX_RTC_CONTROL              0x010
  24#define  EP93XX_RTC_CONTROL_MIE          (1<<0)
  25#define EP93XX_RTC_SWCOMP               0x108
  26#define  EP93XX_RTC_SWCOMP_DEL_MASK      0x001f0000
  27#define  EP93XX_RTC_SWCOMP_DEL_SHIFT     16
  28#define  EP93XX_RTC_SWCOMP_INT_MASK      0x0000ffff
  29#define  EP93XX_RTC_SWCOMP_INT_SHIFT     0
  30
  31#define DRV_VERSION "0.3"
  32
  33/*
  34 * struct device dev.platform_data is used to store our private data
  35 * because struct rtc_device does not have a variable to hold it.
  36 */
  37struct ep93xx_rtc {
  38        void __iomem    *mmio_base;
  39        struct rtc_device *rtc;
  40};
  41
  42static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
  43                                unsigned short *delete)
  44{
  45        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  46        unsigned long comp;
  47
  48        comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
  49
  50        if (preload)
  51                *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
  52                                >> EP93XX_RTC_SWCOMP_INT_SHIFT;
  53
  54        if (delete)
  55                *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
  56                                >> EP93XX_RTC_SWCOMP_DEL_SHIFT;
  57
  58        return 0;
  59}
  60
  61static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
  62{
  63        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  64        unsigned long time;
  65
  66         time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
  67
  68        rtc_time_to_tm(time, tm);
  69        return 0;
  70}
  71
  72static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
  73{
  74        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  75
  76        writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
  77        return 0;
  78}
  79
  80static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
  81{
  82        unsigned short preload, delete;
  83
  84        ep93xx_rtc_get_swcomp(dev, &preload, &delete);
  85
  86        seq_printf(seq, "preload\t\t: %d\n", preload);
  87        seq_printf(seq, "delete\t\t: %d\n", delete);
  88
  89        return 0;
  90}
  91
  92static const struct rtc_class_ops ep93xx_rtc_ops = {
  93        .read_time      = ep93xx_rtc_read_time,
  94        .set_mmss       = ep93xx_rtc_set_mmss,
  95        .proc           = ep93xx_rtc_proc,
  96};
  97
  98static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev,
  99                        struct device_attribute *attr, char *buf)
 100{
 101        unsigned short preload;
 102
 103        ep93xx_rtc_get_swcomp(dev, &preload, NULL);
 104
 105        return sprintf(buf, "%d\n", preload);
 106}
 107static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL);
 108
 109static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
 110                        struct device_attribute *attr, char *buf)
 111{
 112        unsigned short delete;
 113
 114        ep93xx_rtc_get_swcomp(dev, NULL, &delete);
 115
 116        return sprintf(buf, "%d\n", delete);
 117}
 118static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
 119
 120static struct attribute *ep93xx_rtc_attrs[] = {
 121        &dev_attr_comp_preload.attr,
 122        &dev_attr_comp_delete.attr,
 123        NULL
 124};
 125
 126static const struct attribute_group ep93xx_rtc_sysfs_files = {
 127        .attrs  = ep93xx_rtc_attrs,
 128};
 129
 130static int ep93xx_rtc_probe(struct platform_device *pdev)
 131{
 132        struct ep93xx_rtc *ep93xx_rtc;
 133        struct resource *res;
 134        int err;
 135
 136        ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
 137        if (!ep93xx_rtc)
 138                return -ENOMEM;
 139
 140        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 141        ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res);
 142        if (IS_ERR(ep93xx_rtc->mmio_base))
 143                return PTR_ERR(ep93xx_rtc->mmio_base);
 144
 145        pdev->dev.platform_data = ep93xx_rtc;
 146        platform_set_drvdata(pdev, ep93xx_rtc);
 147
 148        ep93xx_rtc->rtc = devm_rtc_device_register(&pdev->dev,
 149                                pdev->name, &ep93xx_rtc_ops, THIS_MODULE);
 150        if (IS_ERR(ep93xx_rtc->rtc)) {
 151                err = PTR_ERR(ep93xx_rtc->rtc);
 152                goto exit;
 153        }
 154
 155        err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
 156        if (err)
 157                goto exit;
 158
 159        return 0;
 160
 161exit:
 162        pdev->dev.platform_data = NULL;
 163        return err;
 164}
 165
 166static int ep93xx_rtc_remove(struct platform_device *pdev)
 167{
 168        sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
 169        pdev->dev.platform_data = NULL;
 170
 171        return 0;
 172}
 173
 174static struct platform_driver ep93xx_rtc_driver = {
 175        .driver         = {
 176                .name   = "ep93xx-rtc",
 177        },
 178        .probe          = ep93xx_rtc_probe,
 179        .remove         = ep93xx_rtc_remove,
 180};
 181
 182module_platform_driver(ep93xx_rtc_driver);
 183
 184MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 185MODULE_DESCRIPTION("EP93XX RTC driver");
 186MODULE_LICENSE("GPL");
 187MODULE_VERSION(DRV_VERSION);
 188MODULE_ALIAS("platform:ep93xx-rtc");
 189