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/*
  32 * struct device dev.platform_data is used to store our private data
  33 * because struct rtc_device does not have a variable to hold it.
  34 */
  35struct ep93xx_rtc {
  36        void __iomem    *mmio_base;
  37        struct rtc_device *rtc;
  38};
  39
  40static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
  41                                unsigned short *delete)
  42{
  43        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  44        unsigned long comp;
  45
  46        comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
  47
  48        if (preload)
  49                *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
  50                                >> EP93XX_RTC_SWCOMP_INT_SHIFT;
  51
  52        if (delete)
  53                *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
  54                                >> EP93XX_RTC_SWCOMP_DEL_SHIFT;
  55
  56        return 0;
  57}
  58
  59static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
  60{
  61        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  62        unsigned long time;
  63
  64         time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
  65
  66        rtc_time_to_tm(time, tm);
  67        return 0;
  68}
  69
  70static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
  71{
  72        struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
  73
  74        writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
  75        return 0;
  76}
  77
  78static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
  79{
  80        unsigned short preload, delete;
  81
  82        ep93xx_rtc_get_swcomp(dev, &preload, &delete);
  83
  84        seq_printf(seq, "preload\t\t: %d\n", preload);
  85        seq_printf(seq, "delete\t\t: %d\n", delete);
  86
  87        return 0;
  88}
  89
  90static const struct rtc_class_ops ep93xx_rtc_ops = {
  91        .read_time      = ep93xx_rtc_read_time,
  92        .set_mmss       = ep93xx_rtc_set_mmss,
  93        .proc           = ep93xx_rtc_proc,
  94};
  95
  96static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev,
  97                        struct device_attribute *attr, char *buf)
  98{
  99        unsigned short preload;
 100
 101        ep93xx_rtc_get_swcomp(dev, &preload, NULL);
 102
 103        return sprintf(buf, "%d\n", preload);
 104}
 105static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL);
 106
 107static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,
 108                        struct device_attribute *attr, char *buf)
 109{
 110        unsigned short delete;
 111
 112        ep93xx_rtc_get_swcomp(dev, NULL, &delete);
 113
 114        return sprintf(buf, "%d\n", delete);
 115}
 116static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL);
 117
 118static struct attribute *ep93xx_rtc_attrs[] = {
 119        &dev_attr_comp_preload.attr,
 120        &dev_attr_comp_delete.attr,
 121        NULL
 122};
 123
 124static const struct attribute_group ep93xx_rtc_sysfs_files = {
 125        .attrs  = ep93xx_rtc_attrs,
 126};
 127
 128static int ep93xx_rtc_probe(struct platform_device *pdev)
 129{
 130        struct ep93xx_rtc *ep93xx_rtc;
 131        struct resource *res;
 132        int err;
 133
 134        ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
 135        if (!ep93xx_rtc)
 136                return -ENOMEM;
 137
 138        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 139        ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res);
 140        if (IS_ERR(ep93xx_rtc->mmio_base))
 141                return PTR_ERR(ep93xx_rtc->mmio_base);
 142
 143        pdev->dev.platform_data = ep93xx_rtc;
 144        platform_set_drvdata(pdev, ep93xx_rtc);
 145
 146        ep93xx_rtc->rtc = devm_rtc_device_register(&pdev->dev,
 147                                pdev->name, &ep93xx_rtc_ops, THIS_MODULE);
 148        if (IS_ERR(ep93xx_rtc->rtc)) {
 149                err = PTR_ERR(ep93xx_rtc->rtc);
 150                goto exit;
 151        }
 152
 153        err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
 154        if (err)
 155                goto exit;
 156
 157        return 0;
 158
 159exit:
 160        pdev->dev.platform_data = NULL;
 161        return err;
 162}
 163
 164static int ep93xx_rtc_remove(struct platform_device *pdev)
 165{
 166        sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
 167        pdev->dev.platform_data = NULL;
 168
 169        return 0;
 170}
 171
 172static struct platform_driver ep93xx_rtc_driver = {
 173        .driver         = {
 174                .name   = "ep93xx-rtc",
 175        },
 176        .probe          = ep93xx_rtc_probe,
 177        .remove         = ep93xx_rtc_remove,
 178};
 179
 180module_platform_driver(ep93xx_rtc_driver);
 181
 182MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 183MODULE_DESCRIPTION("EP93XX RTC driver");
 184MODULE_LICENSE("GPL");
 185MODULE_ALIAS("platform:ep93xx-rtc");
 186