brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · fd1199c Raw
196 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * RDA8810PL SoC timer driver4 *5 * Copyright RDA Microelectronics Company Limited6 * Copyright (c) 2017 Andreas Färber7 * Copyright (c) 2018 Manivannan Sadhasivam8 *9 * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).10 * Each timer provides optional interrupt support. In this driver, OSTIMER is11 * used for clockevents and HWTIMER is used for clocksource.12 */13 14#include <linux/init.h>15#include <linux/interrupt.h>16 17#include "timer-of.h"18 19#define RDA_OSTIMER_LOADVAL_L	0x00020#define RDA_OSTIMER_CTRL	0x00421#define RDA_HWTIMER_LOCKVAL_L	0x02422#define RDA_HWTIMER_LOCKVAL_H	0x02823#define RDA_TIMER_IRQ_MASK_SET	0x02c24#define RDA_TIMER_IRQ_MASK_CLR	0x03025#define RDA_TIMER_IRQ_CLR	0x03426 27#define RDA_OSTIMER_CTRL_ENABLE		BIT(24)28#define RDA_OSTIMER_CTRL_REPEAT		BIT(28)29#define RDA_OSTIMER_CTRL_LOAD		BIT(30)30 31#define RDA_TIMER_IRQ_MASK_OSTIMER	BIT(0)32 33#define RDA_TIMER_IRQ_CLR_OSTIMER	BIT(0)34 35static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)36{37	u32 ctrl, load_l;38 39	load_l = (u32)cycles;40	ctrl = ((cycles >> 32) & 0xffffff);41	ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;42	if (periodic)43		ctrl |= RDA_OSTIMER_CTRL_REPEAT;44 45	/* Enable ostimer interrupt first */46	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,47		       base + RDA_TIMER_IRQ_MASK_SET);48 49	/* Write low 32 bits first, high 24 bits are with ctrl */50	writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);51	writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);52 53	return 0;54}55 56static int rda_ostimer_stop(void __iomem *base)57{58	/* Disable ostimer interrupt first */59	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,60		       base + RDA_TIMER_IRQ_MASK_CLR);61 62	writel_relaxed(0, base + RDA_OSTIMER_CTRL);63 64	return 0;65}66 67static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)68{69	struct timer_of *to = to_timer_of(evt);70 71	rda_ostimer_stop(timer_of_base(to));72 73	return 0;74}75 76static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)77{78	struct timer_of *to = to_timer_of(evt);79 80	rda_ostimer_stop(timer_of_base(to));81 82	return 0;83}84 85static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)86{87	struct timer_of *to = to_timer_of(evt);88	unsigned long cycles_per_jiffy;89 90	rda_ostimer_stop(timer_of_base(to));91 92	cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *93			     evt->mult) >> evt->shift;94	rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);95 96	return 0;97}98 99static int rda_ostimer_tick_resume(struct clock_event_device *evt)100{101	return 0;102}103 104static int rda_ostimer_set_next_event(unsigned long evt,105				      struct clock_event_device *ev)106{107	struct timer_of *to = to_timer_of(ev);108 109	rda_ostimer_start(timer_of_base(to), false, evt);110 111	return 0;112}113 114static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)115{116	struct clock_event_device *evt = dev_id;117	struct timer_of *to = to_timer_of(evt);118 119	/* clear timer int */120	writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,121		       timer_of_base(to) + RDA_TIMER_IRQ_CLR);122 123	if (evt->event_handler)124		evt->event_handler(evt);125 126	return IRQ_HANDLED;127}128 129static struct timer_of rda_ostimer_of = {130	.flags = TIMER_OF_IRQ | TIMER_OF_BASE,131 132	.clkevt = {133		.name = "rda-ostimer",134		.rating = 250,135		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |136			    CLOCK_EVT_FEAT_DYNIRQ,137		.set_state_shutdown = rda_ostimer_set_state_shutdown,138		.set_state_oneshot = rda_ostimer_set_state_oneshot,139		.set_state_periodic = rda_ostimer_set_state_periodic,140		.tick_resume = rda_ostimer_tick_resume,141		.set_next_event	= rda_ostimer_set_next_event,142	},143 144	.of_base = {145		.name = "rda-timer",146		.index = 0,147	},148 149	.of_irq = {150		.name = "ostimer",151		.handler = rda_ostimer_interrupt,152		.flags = IRQF_TIMER,153	},154};155 156static u64 rda_hwtimer_read(struct clocksource *cs)157{158	void __iomem *base = timer_of_base(&rda_ostimer_of);159	u32 lo, hi;160 161	/* Always read low 32 bits first */162	do {163		lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);164		hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);165	} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));166 167	return ((u64)hi << 32) | lo;168}169 170static struct clocksource rda_hwtimer_clocksource = {171	.name           = "rda-timer",172	.rating         = 400,173	.read           = rda_hwtimer_read,174	.mask           = CLOCKSOURCE_MASK(64),175	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,176};177 178static int __init rda_timer_init(struct device_node *np)179{180	unsigned long rate = 2000000;181	int ret;182 183	ret = timer_of_init(np, &rda_ostimer_of);184	if (ret)185		return ret;186 187	clocksource_register_hz(&rda_hwtimer_clocksource, rate);188 189	clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,190					0x2, UINT_MAX);191 192	return 0;193}194 195TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);196