brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · fea8a4f Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Keystone broadcast clock-event4 *5 * Copyright 2013 Texas Instruments, Inc.6 *7 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>8 */9 10#include <linux/clk.h>11#include <linux/clockchips.h>12#include <linux/clocksource.h>13#include <linux/interrupt.h>14#include <linux/of_address.h>15#include <linux/of_irq.h>16 17#define TIMER_NAME			"timer-keystone"18 19/* Timer register offsets */20#define TIM12				0x1021#define TIM34				0x1422#define PRD12				0x1823#define PRD34				0x1c24#define TCR				0x2025#define TGCR				0x2426#define INTCTLSTAT			0x4427 28/* Timer register bitfields */29#define TCR_ENAMODE_MASK		0xC030#define TCR_ENAMODE_ONESHOT_MASK	0x4031#define TCR_ENAMODE_PERIODIC_MASK	0x8032 33#define TGCR_TIM_UNRESET_MASK		0x0334#define INTCTLSTAT_ENINT_MASK		0x0135 36/**37 * struct keystone_timer: holds timer's data38 * @base: timer memory base address39 * @hz_period: cycles per HZ period40 * @event_dev: event device based on timer41 */42static struct keystone_timer {43	void __iomem *base;44	unsigned long hz_period;45	struct clock_event_device event_dev;46} timer;47 48static inline u32 keystone_timer_readl(unsigned long rg)49{50	return readl_relaxed(timer.base + rg);51}52 53static inline void keystone_timer_writel(u32 val, unsigned long rg)54{55	writel_relaxed(val, timer.base + rg);56}57 58/**59 * keystone_timer_barrier: write memory barrier60 * use explicit barrier to avoid using readl/writel non relaxed function61 * variants, because in our case non relaxed variants hide the true places62 * where barrier is needed.63 */64static inline void keystone_timer_barrier(void)65{66	__iowmb();67}68 69/**70 * keystone_timer_config: configures timer to work in oneshot/periodic modes.71 * @ mask: mask of the mode to configure72 * @ period: cycles number to configure for73 */74static int keystone_timer_config(u64 period, int mask)75{76	u32 tcr;77	u32 off;78 79	tcr = keystone_timer_readl(TCR);80	off = tcr & ~(TCR_ENAMODE_MASK);81 82	/* set enable mode */83	tcr |= mask;84 85	/* disable timer */86	keystone_timer_writel(off, TCR);87	/* here we have to be sure the timer has been disabled */88	keystone_timer_barrier();89 90	/* reset counter to zero, set new period */91	keystone_timer_writel(0, TIM12);92	keystone_timer_writel(0, TIM34);93	keystone_timer_writel(period & 0xffffffff, PRD12);94	keystone_timer_writel(period >> 32, PRD34);95 96	/*97	 * enable timer98	 * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers99	 * have been written.100	 */101	keystone_timer_barrier();102	keystone_timer_writel(tcr, TCR);103	return 0;104}105 106static void keystone_timer_disable(void)107{108	u32 tcr;109 110	tcr = keystone_timer_readl(TCR);111 112	/* disable timer */113	tcr &= ~(TCR_ENAMODE_MASK);114	keystone_timer_writel(tcr, TCR);115}116 117static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)118{119	struct clock_event_device *evt = dev_id;120 121	evt->event_handler(evt);122	return IRQ_HANDLED;123}124 125static int keystone_set_next_event(unsigned long cycles,126				  struct clock_event_device *evt)127{128	return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK);129}130 131static int keystone_shutdown(struct clock_event_device *evt)132{133	keystone_timer_disable();134	return 0;135}136 137static int keystone_set_periodic(struct clock_event_device *evt)138{139	keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK);140	return 0;141}142 143static int __init keystone_timer_init(struct device_node *np)144{145	struct clock_event_device *event_dev = &timer.event_dev;146	unsigned long rate;147	struct clk *clk;148	int irq, error;149 150	irq  = irq_of_parse_and_map(np, 0);151	if (!irq) {152		pr_err("%s: failed to map interrupts\n", __func__);153		return -EINVAL;154	}155 156	timer.base = of_iomap(np, 0);157	if (!timer.base) {158		pr_err("%s: failed to map registers\n", __func__);159		return -ENXIO;160	}161 162	clk = of_clk_get(np, 0);163	if (IS_ERR(clk)) {164		pr_err("%s: failed to get clock\n", __func__);165		iounmap(timer.base);166		return PTR_ERR(clk);167	}168 169	error = clk_prepare_enable(clk);170	if (error) {171		pr_err("%s: failed to enable clock\n", __func__);172		goto err;173	}174 175	rate = clk_get_rate(clk);176 177	/* disable, use internal clock source */178	keystone_timer_writel(0, TCR);179	/* here we have to be sure the timer has been disabled */180	keystone_timer_barrier();181 182	/* reset timer as 64-bit, no pre-scaler, plus features are disabled */183	keystone_timer_writel(0, TGCR);184 185	/* unreset timer */186	keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR);187 188	/* init counter to zero */189	keystone_timer_writel(0, TIM12);190	keystone_timer_writel(0, TIM34);191 192	timer.hz_period = DIV_ROUND_UP(rate, HZ);193 194	/* enable timer interrupts */195	keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT);196 197	error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER,198			    TIMER_NAME, event_dev);199	if (error) {200		pr_err("%s: failed to setup irq\n", __func__);201		goto err;202	}203 204	/* setup clockevent */205	event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;206	event_dev->set_next_event = keystone_set_next_event;207	event_dev->set_state_shutdown = keystone_shutdown;208	event_dev->set_state_periodic = keystone_set_periodic;209	event_dev->set_state_oneshot = keystone_shutdown;210	event_dev->cpumask = cpu_possible_mask;211	event_dev->owner = THIS_MODULE;212	event_dev->name = TIMER_NAME;213	event_dev->irq = irq;214 215	clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);216 217	pr_info("keystone timer clock @%lu Hz\n", rate);218	return 0;219err:220	clk_put(clk);221	iounmap(timer.base);222	return error;223}224 225TIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer",226			   keystone_timer_init);227