Lines Matching +full:cs +full:- +full:to +full:- +full:clk

1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2011-2013 Xilinx
10 #include <linux/clk.h>
23 * This driver configures the 2 16/32-bit count-up timers as follows:
29 * The input frequency to the timer module for emulation is 2.5MHz which is
30 * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
33 * The input frequency to the timer module in silicon is configurable and
34 * obtained from device tree. The pre-scaler of 32 is used.
55 * Setup the timers to use pre-scaling, using a fixed value for now that will
56 * work across most input frequency, but it may need to be more dynamic
60 #define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1)
67 * struct ttc_timer - This definition defines local timer structure
71 * @clk: Associated clock source
77 struct clk *clk; member
88 struct clocksource cs; member
92 container_of(x, struct ttc_timer_clocksource, cs)
105 * ttc_set_interval - Set the timer interval value
107 * @timer: Pointer to the timer instance
115 /* Disable the counter, set the counter value and re-enable counter */ in ttc_set_interval()
116 ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_set_interval()
118 writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_set_interval()
120 writel_relaxed(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET); in ttc_set_interval()
123 * Reset the counter (0x10) so that it starts from 0, one-shot in ttc_set_interval()
124 * mode makes this needed for timing to be right. in ttc_set_interval()
128 writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_set_interval()
132 * ttc_clock_event_interrupt - Clock event timer interrupt handler
135 * @dev_id: void pointer to the ttc_timer instance
137 * returns: Always IRQ_HANDLED - success
142 struct ttc_timer *timer = &ttce->ttc; in ttc_clock_event_interrupt()
145 readl_relaxed(timer->base_addr + TTC_ISR_OFFSET); in ttc_clock_event_interrupt()
147 ttce->ce.event_handler(&ttce->ce); in ttc_clock_event_interrupt()
153 * __ttc_clocksource_read - Reads the timer counter register
157 static u64 __ttc_clocksource_read(struct clocksource *cs) in __ttc_clocksource_read() argument
159 struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc; in __ttc_clocksource_read()
161 return (u64)readl_relaxed(timer->base_addr + in __ttc_clocksource_read()
171 * ttc_set_next_event - Sets the time interval for next event
176 * returns: Always 0 - success
182 struct ttc_timer *timer = &ttce->ttc; in ttc_set_next_event()
189 * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer
196 struct ttc_timer *timer = &ttce->ttc; in ttc_shutdown()
199 ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_shutdown()
201 writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_shutdown()
208 struct ttc_timer *timer = &ttce->ttc; in ttc_set_periodic()
211 DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ)); in ttc_set_periodic()
218 struct ttc_timer *timer = &ttce->ttc; in ttc_resume()
221 ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_resume()
223 writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_resume()
241 if (ndata->new_rate > ndata->old_rate) { in ttc_rate_change_clocksource_cb()
242 factor = DIV_ROUND_CLOSEST(ndata->new_rate, in ttc_rate_change_clocksource_cb()
243 ndata->old_rate); in ttc_rate_change_clocksource_cb()
244 rate_low = ndata->old_rate; in ttc_rate_change_clocksource_cb()
245 rate_high = ndata->new_rate; in ttc_rate_change_clocksource_cb()
247 factor = DIV_ROUND_CLOSEST(ndata->old_rate, in ttc_rate_change_clocksource_cb()
248 ndata->new_rate); in ttc_rate_change_clocksource_cb()
249 rate_low = ndata->new_rate; in ttc_rate_change_clocksource_cb()
250 rate_high = ndata->old_rate; in ttc_rate_change_clocksource_cb()
256 if (abs(rate_high - (factor * rate_low)) > MAX_F_ERR) in ttc_rate_change_clocksource_cb()
265 ttccs->scale_clk_ctrl_reg_old = in ttc_rate_change_clocksource_cb()
266 readl_relaxed(ttccs->ttc.base_addr + in ttc_rate_change_clocksource_cb()
269 psv = (ttccs->scale_clk_ctrl_reg_old & in ttc_rate_change_clocksource_cb()
272 if (ndata->new_rate < ndata->old_rate) in ttc_rate_change_clocksource_cb()
273 psv -= factor; in ttc_rate_change_clocksource_cb()
281 ttccs->scale_clk_ctrl_reg_new = ttccs->scale_clk_ctrl_reg_old & in ttc_rate_change_clocksource_cb()
283 ttccs->scale_clk_ctrl_reg_new |= psv << TTC_CLK_CNTRL_PSV_SHIFT; in ttc_rate_change_clocksource_cb()
286 /* scale down: adjust divider in post-change notification */ in ttc_rate_change_clocksource_cb()
287 if (ndata->new_rate < ndata->old_rate) in ttc_rate_change_clocksource_cb()
290 /* scale up: adjust divider now - before frequency change */ in ttc_rate_change_clocksource_cb()
291 writel_relaxed(ttccs->scale_clk_ctrl_reg_new, in ttc_rate_change_clocksource_cb()
292 ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); in ttc_rate_change_clocksource_cb()
296 /* scale up: pre-change notification did the adjustment */ in ttc_rate_change_clocksource_cb()
297 if (ndata->new_rate > ndata->old_rate) in ttc_rate_change_clocksource_cb()
300 /* scale down: adjust divider now - after frequency change */ in ttc_rate_change_clocksource_cb()
301 writel_relaxed(ttccs->scale_clk_ctrl_reg_new, in ttc_rate_change_clocksource_cb()
302 ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); in ttc_rate_change_clocksource_cb()
306 /* we have to undo the adjustment in case we scale up */ in ttc_rate_change_clocksource_cb()
307 if (ndata->new_rate < ndata->old_rate) in ttc_rate_change_clocksource_cb()
311 writel_relaxed(ttccs->scale_clk_ctrl_reg_old, in ttc_rate_change_clocksource_cb()
312 ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); in ttc_rate_change_clocksource_cb()
321 static int __init ttc_setup_clocksource(struct clk *clk, void __iomem *base, in ttc_setup_clocksource() argument
329 return -ENOMEM; in ttc_setup_clocksource()
331 ttccs->ttc.clk = clk; in ttc_setup_clocksource()
333 err = clk_prepare_enable(ttccs->ttc.clk); in ttc_setup_clocksource()
339 ttccs->ttc.freq = clk_get_rate(ttccs->ttc.clk); in ttc_setup_clocksource()
341 ttccs->ttc.clk_rate_change_nb.notifier_call = in ttc_setup_clocksource()
343 ttccs->ttc.clk_rate_change_nb.next = NULL; in ttc_setup_clocksource()
345 err = clk_notifier_register(ttccs->ttc.clk, in ttc_setup_clocksource()
346 &ttccs->ttc.clk_rate_change_nb); in ttc_setup_clocksource()
348 pr_warn("Unable to register clock notifier.\n"); in ttc_setup_clocksource()
350 ttccs->ttc.base_addr = base; in ttc_setup_clocksource()
351 ttccs->cs.name = "ttc_clocksource"; in ttc_setup_clocksource()
352 ttccs->cs.rating = 200; in ttc_setup_clocksource()
353 ttccs->cs.read = __ttc_clocksource_read; in ttc_setup_clocksource()
354 ttccs->cs.mask = CLOCKSOURCE_MASK(timer_width); in ttc_setup_clocksource()
355 ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; in ttc_setup_clocksource()
358 * Setup the clock source counter to be an incrementing counter in ttc_setup_clocksource()
359 * with no interrupt and it rolls over at 0xFFFF. Pre-scale in ttc_setup_clocksource()
362 writel_relaxed(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET); in ttc_setup_clocksource()
364 ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); in ttc_setup_clocksource()
366 ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_setup_clocksource()
368 err = clocksource_register_hz(&ttccs->cs, ttccs->ttc.freq / PRESCALE); in ttc_setup_clocksource()
376 ttccs->ttc.freq / PRESCALE); in ttc_setup_clocksource()
392 ttc->freq = ndata->new_rate; in ttc_rate_change_clockevent_cb()
394 clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE); in ttc_rate_change_clockevent_cb()
404 static int __init ttc_setup_clockevent(struct clk *clk, in ttc_setup_clockevent() argument
412 return -ENOMEM; in ttc_setup_clockevent()
414 ttcce->ttc.clk = clk; in ttc_setup_clockevent()
416 err = clk_prepare_enable(ttcce->ttc.clk); in ttc_setup_clockevent()
420 ttcce->ttc.clk_rate_change_nb.notifier_call = in ttc_setup_clockevent()
422 ttcce->ttc.clk_rate_change_nb.next = NULL; in ttc_setup_clockevent()
424 err = clk_notifier_register(ttcce->ttc.clk, in ttc_setup_clockevent()
425 &ttcce->ttc.clk_rate_change_nb); in ttc_setup_clockevent()
427 pr_warn("Unable to register clock notifier.\n"); in ttc_setup_clockevent()
431 ttcce->ttc.freq = clk_get_rate(ttcce->ttc.clk); in ttc_setup_clockevent()
433 ttcce->ttc.base_addr = base; in ttc_setup_clockevent()
434 ttcce->ce.name = "ttc_clockevent"; in ttc_setup_clockevent()
435 ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; in ttc_setup_clockevent()
436 ttcce->ce.set_next_event = ttc_set_next_event; in ttc_setup_clockevent()
437 ttcce->ce.set_state_shutdown = ttc_shutdown; in ttc_setup_clockevent()
438 ttcce->ce.set_state_periodic = ttc_set_periodic; in ttc_setup_clockevent()
439 ttcce->ce.set_state_oneshot = ttc_shutdown; in ttc_setup_clockevent()
440 ttcce->ce.tick_resume = ttc_resume; in ttc_setup_clockevent()
441 ttcce->ce.rating = 200; in ttc_setup_clockevent()
442 ttcce->ce.irq = irq; in ttc_setup_clockevent()
443 ttcce->ce.cpumask = cpu_possible_mask; in ttc_setup_clockevent()
446 * Setup the clock event timer to be an interval timer which in ttc_setup_clockevent()
450 writel_relaxed(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); in ttc_setup_clockevent()
452 ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); in ttc_setup_clockevent()
453 writel_relaxed(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET); in ttc_setup_clockevent()
456 IRQF_TIMER, ttcce->ce.name, ttcce); in ttc_setup_clockevent()
460 clockevents_config_and_register(&ttcce->ce, in ttc_setup_clockevent()
461 ttcce->ttc.freq / PRESCALE, 1, 0xfffe); in ttc_setup_clockevent()
474 struct clk *clk_cs, *clk_ce; in ttc_timer_probe()
478 struct device_node *timer = pdev->dev.of_node; in ttc_timer_probe()
490 timer_baseaddr = devm_of_iomap(&pdev->dev, timer, 0, NULL); in ttc_timer_probe()
499 return -EINVAL; in ttc_timer_probe()
502 of_property_read_u32(timer, "timer-width", &timer_width); in ttc_timer_probe()