Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / clocksource / timer-digicolor.c
1 /*
2  * Conexant Digicolor timer driver
3  *
4  * Author: Baruch Siach <baruch@tkos.co.il>
5  *
6  * Copyright (C) 2014 Paradox Innovation Ltd.
7  *
8  * Based on:
9  *      Allwinner SoCs hstimer driver
10  *
11  * Copyright (C) 2013 Maxime Ripard
12  *
13  * Maxime Ripard <maxime.ripard@free-electrons.com>
14  *
15  * This file is licensed under the terms of the GNU General Public
16  * License version 2.  This program is licensed "as is" without any
17  * warranty of any kind, whether express or implied.
18  */
19
20 /*
21  * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to
22  * "Timer H". Timer A is the only one with watchdog support, so it is dedicated
23  * to the watchdog driver. This driver uses Timer B for sched_clock(), and
24  * Timer C for clockevents.
25  */
26
27 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
29 #include <linux/clk.h>
30 #include <linux/clockchips.h>
31 #include <linux/interrupt.h>
32 #include <linux/irq.h>
33 #include <linux/irqreturn.h>
34 #include <linux/sched/clock.h>
35 #include <linux/sched_clock.h>
36 #include <linux/of.h>
37 #include <linux/of_address.h>
38 #include <linux/of_irq.h>
39
40 enum {
41         TIMER_A,
42         TIMER_B,
43         TIMER_C,
44         TIMER_D,
45         TIMER_E,
46         TIMER_F,
47         TIMER_G,
48         TIMER_H,
49 };
50
51 #define CONTROL(t)      ((t)*8)
52 #define COUNT(t)        ((t)*8 + 4)
53
54 #define CONTROL_DISABLE         0
55 #define CONTROL_ENABLE          BIT(0)
56 #define CONTROL_MODE(m)         ((m) << 4)
57 #define CONTROL_MODE_ONESHOT    CONTROL_MODE(1)
58 #define CONTROL_MODE_PERIODIC   CONTROL_MODE(2)
59
60 struct digicolor_timer {
61         struct clock_event_device ce;
62         void __iomem *base;
63         u32 ticks_per_jiffy;
64         int timer_id; /* one of TIMER_* */
65 };
66
67 static struct digicolor_timer *dc_timer(struct clock_event_device *ce)
68 {
69         return container_of(ce, struct digicolor_timer, ce);
70 }
71
72 static inline void dc_timer_disable(struct clock_event_device *ce)
73 {
74         struct digicolor_timer *dt = dc_timer(ce);
75         writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id));
76 }
77
78 static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode)
79 {
80         struct digicolor_timer *dt = dc_timer(ce);
81         writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id));
82 }
83
84 static inline void dc_timer_set_count(struct clock_event_device *ce,
85                                       unsigned long count)
86 {
87         struct digicolor_timer *dt = dc_timer(ce);
88         writel(count, dt->base + COUNT(dt->timer_id));
89 }
90
91 static int digicolor_clkevt_shutdown(struct clock_event_device *ce)
92 {
93         dc_timer_disable(ce);
94         return 0;
95 }
96
97 static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce)
98 {
99         dc_timer_disable(ce);
100         dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
101         return 0;
102 }
103
104 static int digicolor_clkevt_set_periodic(struct clock_event_device *ce)
105 {
106         struct digicolor_timer *dt = dc_timer(ce);
107
108         dc_timer_disable(ce);
109         dc_timer_set_count(ce, dt->ticks_per_jiffy);
110         dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
111         return 0;
112 }
113
114 static int digicolor_clkevt_next_event(unsigned long evt,
115                                        struct clock_event_device *ce)
116 {
117         dc_timer_disable(ce);
118         dc_timer_set_count(ce, evt);
119         dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
120
121         return 0;
122 }
123
124 static struct digicolor_timer dc_timer_dev = {
125         .ce = {
126                 .name = "digicolor_tick",
127                 .rating = 340,
128                 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
129                 .set_state_shutdown = digicolor_clkevt_shutdown,
130                 .set_state_periodic = digicolor_clkevt_set_periodic,
131                 .set_state_oneshot = digicolor_clkevt_set_oneshot,
132                 .tick_resume = digicolor_clkevt_shutdown,
133                 .set_next_event = digicolor_clkevt_next_event,
134         },
135         .timer_id = TIMER_C,
136 };
137
138 static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id)
139 {
140         struct clock_event_device *evt = dev_id;
141
142         evt->event_handler(evt);
143
144         return IRQ_HANDLED;
145 }
146
147 static u64 notrace digicolor_timer_sched_read(void)
148 {
149         return ~readl(dc_timer_dev.base + COUNT(TIMER_B));
150 }
151
152 static int __init digicolor_timer_init(struct device_node *node)
153 {
154         unsigned long rate;
155         struct clk *clk;
156         int ret, irq;
157
158         /*
159          * timer registers are shared with the watchdog timer;
160          * don't map exclusively
161          */
162         dc_timer_dev.base = of_iomap(node, 0);
163         if (!dc_timer_dev.base) {
164                 pr_err("Can't map registers\n");
165                 return -ENXIO;
166         }
167
168         irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
169         if (irq <= 0) {
170                 pr_err("Can't parse IRQ\n");
171                 return -EINVAL;
172         }
173
174         clk = of_clk_get(node, 0);
175         if (IS_ERR(clk)) {
176                 pr_err("Can't get timer clock\n");
177                 return PTR_ERR(clk);
178         }
179         clk_prepare_enable(clk);
180         rate = clk_get_rate(clk);
181         dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
182
183         writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B));
184         writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B));
185         writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B));
186
187         sched_clock_register(digicolor_timer_sched_read, 32, rate);
188         clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name,
189                               rate, 340, 32, clocksource_mmio_readl_down);
190
191         ret = request_irq(irq, digicolor_timer_interrupt,
192                           IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC",
193                           &dc_timer_dev.ce);
194         if (ret) {
195                 pr_warn("request of timer irq %d failed (%d)\n", irq, ret);
196                 return ret;
197         }
198
199         dc_timer_dev.ce.cpumask = cpu_possible_mask;
200         dc_timer_dev.ce.irq = irq;
201
202         clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff);
203
204         return 0;
205 }
206 TIMER_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
207                        digicolor_timer_init);