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