rtc-sun6i.c (fb61bb82cb46a932ef2fc62e1c731c8e7e6640d5) rtc-sun6i.c (3855c2c3e5461ab5ece9c1578650fcc23dd248c2)
1/*
2 * An RTC driver for Allwinner A31/A23
3 *
4 * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
5 *
6 * based on rtc-sunxi.c
7 *
8 * An RTC driver for Allwinner A10/A20

--- 6 unchanged lines hidden (view full) ---

15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * more details.
21 */
22
1/*
2 * An RTC driver for Allwinner A31/A23
3 *
4 * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
5 *
6 * based on rtc-sunxi.c
7 *
8 * An RTC driver for Allwinner A10/A20

--- 6 unchanged lines hidden (view full) ---

15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 * more details.
21 */
22
23#include <linux/clk.h>
24#include <linux/clk-provider.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/fs.h>
26#include <linux/init.h>
27#include <linux/interrupt.h>
28#include <linux/io.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/of.h>
32#include <linux/of_address.h>
33#include <linux/of_device.h>
34#include <linux/platform_device.h>
35#include <linux/rtc.h>
25#include <linux/delay.h>
26#include <linux/err.h>
27#include <linux/fs.h>
28#include <linux/init.h>
29#include <linux/interrupt.h>
30#include <linux/io.h>
31#include <linux/kernel.h>
32#include <linux/module.h>
33#include <linux/of.h>
34#include <linux/of_address.h>
35#include <linux/of_device.h>
36#include <linux/platform_device.h>
37#include <linux/rtc.h>
38#include <linux/slab.h>
36#include <linux/types.h>
37
38/* Control register */
39#define SUN6I_LOSC_CTRL 0x0000
40#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
41#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
42#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
43#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
44#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
45#define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
46
39#include <linux/types.h>
40
41/* Control register */
42#define SUN6I_LOSC_CTRL 0x0000
43#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
44#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
45#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
46#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
47#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
48#define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
49
50#define SUN6I_LOSC_CLK_PRESCAL 0x0008
51
47/* RTC */
48#define SUN6I_RTC_YMD 0x0010
49#define SUN6I_RTC_HMS 0x0014
50
51/* Alarm 0 (counter) */
52#define SUN6I_ALRM_COUNTER 0x0020
53#define SUN6I_ALRM_CUR_VAL 0x0024
54#define SUN6I_ALRM_EN 0x0028

--- 57 unchanged lines hidden (view full) ---

112
113struct sun6i_rtc_dev {
114 struct rtc_device *rtc;
115 struct device *dev;
116 void __iomem *base;
117 int irq;
118 unsigned long alarm;
119
52/* RTC */
53#define SUN6I_RTC_YMD 0x0010
54#define SUN6I_RTC_HMS 0x0014
55
56/* Alarm 0 (counter) */
57#define SUN6I_ALRM_COUNTER 0x0020
58#define SUN6I_ALRM_CUR_VAL 0x0024
59#define SUN6I_ALRM_EN 0x0028

--- 57 unchanged lines hidden (view full) ---

117
118struct sun6i_rtc_dev {
119 struct rtc_device *rtc;
120 struct device *dev;
121 void __iomem *base;
122 int irq;
123 unsigned long alarm;
124
125 struct clk_hw hw;
126 struct clk_hw *int_osc;
127 struct clk *losc;
128
120 spinlock_t lock;
121};
122
129 spinlock_t lock;
130};
131
132static struct sun6i_rtc_dev *sun6i_rtc;
133
134static unsigned long sun6i_rtc_osc_recalc_rate(struct clk_hw *hw,
135 unsigned long parent_rate)
136{
137 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
138 u32 val;
139
140 val = readl(rtc->base + SUN6I_LOSC_CTRL);
141 if (val & SUN6I_LOSC_CTRL_EXT_OSC)
142 return parent_rate;
143
144 val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL);
145 val &= GENMASK(4, 0);
146
147 return parent_rate / (val + 1);
148}
149
150static u8 sun6i_rtc_osc_get_parent(struct clk_hw *hw)
151{
152 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
153
154 return readl(rtc->base + SUN6I_LOSC_CTRL) & SUN6I_LOSC_CTRL_EXT_OSC;
155}
156
157static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index)
158{
159 struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
160 unsigned long flags;
161 u32 val;
162
163 if (index > 1)
164 return -EINVAL;
165
166 spin_lock_irqsave(&rtc->lock, flags);
167 val = readl(rtc->base + SUN6I_LOSC_CTRL);
168 val &= ~SUN6I_LOSC_CTRL_EXT_OSC;
169 val |= SUN6I_LOSC_CTRL_KEY;
170 val |= index ? SUN6I_LOSC_CTRL_EXT_OSC : 0;
171 writel(val, rtc->base + SUN6I_LOSC_CTRL);
172 spin_unlock_irqrestore(&rtc->lock, flags);
173
174 return 0;
175}
176
177static const struct clk_ops sun6i_rtc_osc_ops = {
178 .recalc_rate = sun6i_rtc_osc_recalc_rate,
179
180 .get_parent = sun6i_rtc_osc_get_parent,
181 .set_parent = sun6i_rtc_osc_set_parent,
182};
183
184static void __init sun6i_rtc_clk_init(struct device_node *node)
185{
186 struct clk_hw_onecell_data *clk_data;
187 struct sun6i_rtc_dev *rtc;
188 struct clk_init_data init = {
189 .ops = &sun6i_rtc_osc_ops,
190 };
191 const char *parents[2];
192
193 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
194 if (!rtc)
195 return;
196 spin_lock_init(&rtc->lock);
197
198 clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws),
199 GFP_KERNEL);
200 if (!clk_data)
201 return;
202 spin_lock_init(&rtc->lock);
203
204 rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node));
205 if (!rtc->base) {
206 pr_crit("Can't map RTC registers");
207 return;
208 }
209
210 /* Switch to the external, more precise, oscillator */
211 writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
212 rtc->base + SUN6I_LOSC_CTRL);
213
214 /* Deal with old DTs */
215 if (!of_get_property(node, "clocks", NULL))
216 return;
217
218 rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
219 "rtc-int-osc",
220 NULL, 0,
221 667000,
222 300000000);
223 if (IS_ERR(rtc->int_osc)) {
224 pr_crit("Couldn't register the internal oscillator\n");
225 return;
226 }
227
228 parents[0] = clk_hw_get_name(rtc->int_osc);
229 parents[1] = of_clk_get_parent_name(node, 0);
230
231 rtc->hw.init = &init;
232
233 init.parent_names = parents;
234 init.num_parents = of_clk_get_parent_count(node) + 1;
235 of_property_read_string(node, "clock-output-names", &init.name);
236
237 rtc->losc = clk_register(NULL, &rtc->hw);
238 if (IS_ERR(rtc->losc)) {
239 pr_crit("Couldn't register the LOSC clock\n");
240 return;
241 }
242
243 clk_data->num = 1;
244 clk_data->hws[0] = &rtc->hw;
245 of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
246
247 /* Yes, I know, this is ugly. */
248 sun6i_rtc = rtc;
249}
250CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc",
251 sun6i_rtc_clk_init);
252
123static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
124{
125 struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
126 irqreturn_t ret = IRQ_NONE;
127 u32 val;
128
129 spin_lock(&chip->lock);
130 val = readl(chip->base + SUN6I_ALRM_IRQ_STA);

--- 227 unchanged lines hidden (view full) ---

358 .set_time = sun6i_rtc_settime,
359 .read_alarm = sun6i_rtc_getalarm,
360 .set_alarm = sun6i_rtc_setalarm,
361 .alarm_irq_enable = sun6i_rtc_alarm_irq_enable
362};
363
364static int sun6i_rtc_probe(struct platform_device *pdev)
365{
253static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
254{
255 struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
256 irqreturn_t ret = IRQ_NONE;
257 u32 val;
258
259 spin_lock(&chip->lock);
260 val = readl(chip->base + SUN6I_ALRM_IRQ_STA);

--- 227 unchanged lines hidden (view full) ---

488 .set_time = sun6i_rtc_settime,
489 .read_alarm = sun6i_rtc_getalarm,
490 .set_alarm = sun6i_rtc_setalarm,
491 .alarm_irq_enable = sun6i_rtc_alarm_irq_enable
492};
493
494static int sun6i_rtc_probe(struct platform_device *pdev)
495{
366 struct sun6i_rtc_dev *chip;
367 struct resource *res;
496 struct sun6i_rtc_dev *chip = sun6i_rtc;
368 int ret;
369
497 int ret;
498
370 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
371 if (!chip)
499 if (!chip)
372 return -ENOMEM;
373 spin_lock_init(&chip->lock);
500 return -ENODEV;
374
375 platform_set_drvdata(pdev, chip);
376 chip->dev = &pdev->dev;
377
501
502 platform_set_drvdata(pdev, chip);
503 chip->dev = &pdev->dev;
504
378 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
379 chip->base = devm_ioremap_resource(&pdev->dev, res);
380 if (IS_ERR(chip->base))
381 return PTR_ERR(chip->base);
382
383 chip->irq = platform_get_irq(pdev, 0);
384 if (chip->irq < 0) {
385 dev_err(&pdev->dev, "No IRQ resource\n");
386 return chip->irq;
387 }
388
389 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
390 0, dev_name(&pdev->dev), chip);

--- 23 unchanged lines hidden (view full) ---

414
415 /* clear week alarm pending interrupts */
416 writel(SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND,
417 chip->base + SUN6I_ALRM1_IRQ_STA);
418
419 /* disable alarm wakeup */
420 writel(0, chip->base + SUN6I_ALARM_CONFIG);
421
505 chip->irq = platform_get_irq(pdev, 0);
506 if (chip->irq < 0) {
507 dev_err(&pdev->dev, "No IRQ resource\n");
508 return chip->irq;
509 }
510
511 ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
512 0, dev_name(&pdev->dev), chip);

--- 23 unchanged lines hidden (view full) ---

536
537 /* clear week alarm pending interrupts */
538 writel(SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND,
539 chip->base + SUN6I_ALRM1_IRQ_STA);
540
541 /* disable alarm wakeup */
542 writel(0, chip->base + SUN6I_ALARM_CONFIG);
543
422 /* switch to the external, more precise, oscillator */
423 writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
424 chip->base + SUN6I_LOSC_CTRL);
544 clk_prepare_enable(chip->losc);
425
426 chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
427 &sun6i_rtc_ops, THIS_MODULE);
428 if (IS_ERR(chip->rtc)) {
429 dev_err(&pdev->dev, "unable to register device\n");
430 return PTR_ERR(chip->rtc);
431 }
432

--- 29 unchanged lines hidden ---
545
546 chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
547 &sun6i_rtc_ops, THIS_MODULE);
548 if (IS_ERR(chip->rtc)) {
549 dev_err(&pdev->dev, "unable to register device\n");
550 return PTR_ERR(chip->rtc);
551 }
552

--- 29 unchanged lines hidden ---