xref: /linux/drivers/clocksource/timer-sun5i.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1a74dfa43SThomas Gleixner // SPDX-License-Identifier: GPL-2.0
267905540SMaxime Ripard /*
367905540SMaxime Ripard  * Allwinner SoCs hstimer driver.
467905540SMaxime Ripard  *
567905540SMaxime Ripard  * Copyright (C) 2013 Maxime Ripard
667905540SMaxime Ripard  *
767905540SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
867905540SMaxime Ripard  */
967905540SMaxime Ripard 
1067905540SMaxime Ripard #include <linux/clk.h>
1167905540SMaxime Ripard #include <linux/clockchips.h>
12459fa246SStephen Rothwell #include <linux/clocksource.h>
1367905540SMaxime Ripard #include <linux/delay.h>
1467905540SMaxime Ripard #include <linux/interrupt.h>
1567905540SMaxime Ripard #include <linux/irq.h>
1667905540SMaxime Ripard #include <linux/irqreturn.h>
17e50a00beSMaxime Ripard #include <linux/reset.h>
184a59058fSMaxime Ripard #include <linux/slab.h>
197e5bac61SMans Rullgard #include <linux/platform_device.h>
2067905540SMaxime Ripard 
2167905540SMaxime Ripard #define TIMER_IRQ_EN_REG		0x00
2267905540SMaxime Ripard #define TIMER_IRQ_EN(val)			BIT(val)
2367905540SMaxime Ripard #define TIMER_IRQ_ST_REG		0x04
2467905540SMaxime Ripard #define TIMER_CTL_REG(val)		(0x20 * (val) + 0x10)
2567905540SMaxime Ripard #define TIMER_CTL_ENABLE			BIT(0)
2667905540SMaxime Ripard #define TIMER_CTL_RELOAD			BIT(1)
2767905540SMaxime Ripard #define TIMER_CTL_CLK_PRES(val)			(((val) & 0x7) << 4)
2867905540SMaxime Ripard #define TIMER_CTL_ONESHOT			BIT(7)
2967905540SMaxime Ripard #define TIMER_INTVAL_LO_REG(val)	(0x20 * (val) + 0x14)
3067905540SMaxime Ripard #define TIMER_INTVAL_HI_REG(val)	(0x20 * (val) + 0x18)
3167905540SMaxime Ripard #define TIMER_CNTVAL_LO_REG(val)	(0x20 * (val) + 0x1c)
3267905540SMaxime Ripard #define TIMER_CNTVAL_HI_REG(val)	(0x20 * (val) + 0x20)
3367905540SMaxime Ripard 
3467905540SMaxime Ripard #define TIMER_SYNC_TICKS	3
3567905540SMaxime Ripard 
360b38dd17SMans Rullgard struct sun5i_timer {
374a59058fSMaxime Ripard 	void __iomem		*base;
384a59058fSMaxime Ripard 	struct clk		*clk;
393071efa4SMaxime Ripard 	struct notifier_block	clk_rate_cb;
404a59058fSMaxime Ripard 	u32			ticks_per_jiffy;
414a59058fSMaxime Ripard 	struct clocksource	clksrc;
424a59058fSMaxime Ripard 	struct clock_event_device	clkevt;
434a59058fSMaxime Ripard };
444a59058fSMaxime Ripard 
457ded8038SMans Rullgard #define nb_to_sun5i_timer(x) \
460b38dd17SMans Rullgard 	container_of(x, struct sun5i_timer, clk_rate_cb)
477ded8038SMans Rullgard #define clksrc_to_sun5i_timer(x) \
487ded8038SMans Rullgard 	container_of(x, struct sun5i_timer, clksrc)
497ded8038SMans Rullgard #define clkevt_to_sun5i_timer(x) \
507ded8038SMans Rullgard 	container_of(x, struct sun5i_timer, clkevt)
5167905540SMaxime Ripard 
5267905540SMaxime Ripard /*
5367905540SMaxime Ripard  * When we disable a timer, we need to wait at least for 2 cycles of
5467905540SMaxime Ripard  * the timer source clock. We will use for that the clocksource timer
5567905540SMaxime Ripard  * that is already setup and runs at the same frequency than the other
5667905540SMaxime Ripard  * timers, and we never will be disabled.
5767905540SMaxime Ripard  */
sun5i_clkevt_sync(struct sun5i_timer * ce)587ded8038SMans Rullgard static void sun5i_clkevt_sync(struct sun5i_timer *ce)
5967905540SMaxime Ripard {
600b38dd17SMans Rullgard 	u32 old = readl(ce->base + TIMER_CNTVAL_LO_REG(1));
6167905540SMaxime Ripard 
620b38dd17SMans Rullgard 	while ((old - readl(ce->base + TIMER_CNTVAL_LO_REG(1))) < TIMER_SYNC_TICKS)
6367905540SMaxime Ripard 		cpu_relax();
6467905540SMaxime Ripard }
6567905540SMaxime Ripard 
sun5i_clkevt_time_stop(struct sun5i_timer * ce,u8 timer)667ded8038SMans Rullgard static void sun5i_clkevt_time_stop(struct sun5i_timer *ce, u8 timer)
6767905540SMaxime Ripard {
680b38dd17SMans Rullgard 	u32 val = readl(ce->base + TIMER_CTL_REG(timer));
690b38dd17SMans Rullgard 	writel(val & ~TIMER_CTL_ENABLE, ce->base + TIMER_CTL_REG(timer));
7067905540SMaxime Ripard 
714a59058fSMaxime Ripard 	sun5i_clkevt_sync(ce);
7267905540SMaxime Ripard }
7367905540SMaxime Ripard 
sun5i_clkevt_time_setup(struct sun5i_timer * ce,u8 timer,u32 delay)747ded8038SMans Rullgard static void sun5i_clkevt_time_setup(struct sun5i_timer *ce, u8 timer, u32 delay)
7567905540SMaxime Ripard {
760b38dd17SMans Rullgard 	writel(delay, ce->base + TIMER_INTVAL_LO_REG(timer));
7767905540SMaxime Ripard }
7867905540SMaxime Ripard 
sun5i_clkevt_time_start(struct sun5i_timer * ce,u8 timer,bool periodic)797ded8038SMans Rullgard static void sun5i_clkevt_time_start(struct sun5i_timer *ce, u8 timer, bool periodic)
8067905540SMaxime Ripard {
810b38dd17SMans Rullgard 	u32 val = readl(ce->base + TIMER_CTL_REG(timer));
8267905540SMaxime Ripard 
8367905540SMaxime Ripard 	if (periodic)
8467905540SMaxime Ripard 		val &= ~TIMER_CTL_ONESHOT;
8567905540SMaxime Ripard 	else
8667905540SMaxime Ripard 		val |= TIMER_CTL_ONESHOT;
8767905540SMaxime Ripard 
8867905540SMaxime Ripard 	writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
890b38dd17SMans Rullgard 	       ce->base + TIMER_CTL_REG(timer));
9067905540SMaxime Ripard }
9167905540SMaxime Ripard 
sun5i_clkevt_shutdown(struct clock_event_device * clkevt)927486f5adSViresh Kumar static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt)
9367905540SMaxime Ripard {
947ded8038SMans Rullgard 	struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt);
954a59058fSMaxime Ripard 
967486f5adSViresh Kumar 	sun5i_clkevt_time_stop(ce, 0);
977486f5adSViresh Kumar 	return 0;
987486f5adSViresh Kumar }
997486f5adSViresh Kumar 
sun5i_clkevt_set_oneshot(struct clock_event_device * clkevt)1007486f5adSViresh Kumar static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt)
1017486f5adSViresh Kumar {
1027ded8038SMans Rullgard 	struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt);
1037486f5adSViresh Kumar 
1047486f5adSViresh Kumar 	sun5i_clkevt_time_stop(ce, 0);
1057486f5adSViresh Kumar 	sun5i_clkevt_time_start(ce, 0, false);
1067486f5adSViresh Kumar 	return 0;
1077486f5adSViresh Kumar }
1087486f5adSViresh Kumar 
sun5i_clkevt_set_periodic(struct clock_event_device * clkevt)1097486f5adSViresh Kumar static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt)
1107486f5adSViresh Kumar {
1117ded8038SMans Rullgard 	struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt);
1127486f5adSViresh Kumar 
1134a59058fSMaxime Ripard 	sun5i_clkevt_time_stop(ce, 0);
1140b38dd17SMans Rullgard 	sun5i_clkevt_time_setup(ce, 0, ce->ticks_per_jiffy);
1154a59058fSMaxime Ripard 	sun5i_clkevt_time_start(ce, 0, true);
1167486f5adSViresh Kumar 	return 0;
11767905540SMaxime Ripard }
11867905540SMaxime Ripard 
sun5i_clkevt_next_event(unsigned long evt,struct clock_event_device * clkevt)11967905540SMaxime Ripard static int sun5i_clkevt_next_event(unsigned long evt,
1204a59058fSMaxime Ripard 				   struct clock_event_device *clkevt)
12167905540SMaxime Ripard {
1227ded8038SMans Rullgard 	struct sun5i_timer *ce = clkevt_to_sun5i_timer(clkevt);
1234a59058fSMaxime Ripard 
1244a59058fSMaxime Ripard 	sun5i_clkevt_time_stop(ce, 0);
1254a59058fSMaxime Ripard 	sun5i_clkevt_time_setup(ce, 0, evt - TIMER_SYNC_TICKS);
1264a59058fSMaxime Ripard 	sun5i_clkevt_time_start(ce, 0, false);
12767905540SMaxime Ripard 
12867905540SMaxime Ripard 	return 0;
12967905540SMaxime Ripard }
13067905540SMaxime Ripard 
sun5i_timer_interrupt(int irq,void * dev_id)13167905540SMaxime Ripard static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
13267905540SMaxime Ripard {
1337ded8038SMans Rullgard 	struct sun5i_timer *ce = dev_id;
13467905540SMaxime Ripard 
1350b38dd17SMans Rullgard 	writel(0x1, ce->base + TIMER_IRQ_ST_REG);
1364a59058fSMaxime Ripard 	ce->clkevt.event_handler(&ce->clkevt);
13767905540SMaxime Ripard 
13867905540SMaxime Ripard 	return IRQ_HANDLED;
13967905540SMaxime Ripard }
14067905540SMaxime Ripard 
sun5i_clksrc_read(struct clocksource * clksrc)141a5a1d1c2SThomas Gleixner static u64 sun5i_clksrc_read(struct clocksource *clksrc)
14259387683SChen-Yu Tsai {
1437ded8038SMans Rullgard 	struct sun5i_timer *cs = clksrc_to_sun5i_timer(clksrc);
14459387683SChen-Yu Tsai 
1450b38dd17SMans Rullgard 	return ~readl(cs->base + TIMER_CNTVAL_LO_REG(1));
14659387683SChen-Yu Tsai }
14759387683SChen-Yu Tsai 
sun5i_rate_cb(struct notifier_block * nb,unsigned long event,void * data)1487ded8038SMans Rullgard static int sun5i_rate_cb(struct notifier_block *nb,
1493071efa4SMaxime Ripard 			 unsigned long event, void *data)
1503071efa4SMaxime Ripard {
1513071efa4SMaxime Ripard 	struct clk_notifier_data *ndata = data;
1527ded8038SMans Rullgard 	struct sun5i_timer *cs = nb_to_sun5i_timer(nb);
1533071efa4SMaxime Ripard 
1543071efa4SMaxime Ripard 	switch (event) {
1553071efa4SMaxime Ripard 	case PRE_RATE_CHANGE:
1563071efa4SMaxime Ripard 		clocksource_unregister(&cs->clksrc);
1573071efa4SMaxime Ripard 		break;
1583071efa4SMaxime Ripard 
1593071efa4SMaxime Ripard 	case POST_RATE_CHANGE:
1603071efa4SMaxime Ripard 		clocksource_register_hz(&cs->clksrc, ndata->new_rate);
1617ded8038SMans Rullgard 		clockevents_update_freq(&cs->clkevt, ndata->new_rate);
1620b38dd17SMans Rullgard 		cs->ticks_per_jiffy = DIV_ROUND_UP(ndata->new_rate, HZ);
1633071efa4SMaxime Ripard 		break;
1643071efa4SMaxime Ripard 
1653071efa4SMaxime Ripard 	default:
1663071efa4SMaxime Ripard 		break;
1673071efa4SMaxime Ripard 	}
1683071efa4SMaxime Ripard 
1693071efa4SMaxime Ripard 	return NOTIFY_DONE;
1703071efa4SMaxime Ripard }
1713071efa4SMaxime Ripard 
sun5i_setup_clocksource(struct platform_device * pdev,unsigned long rate)1727e5bac61SMans Rullgard static int sun5i_setup_clocksource(struct platform_device *pdev,
1737ded8038SMans Rullgard 				   unsigned long rate)
1744a59058fSMaxime Ripard {
1757e5bac61SMans Rullgard 	struct sun5i_timer *cs = platform_get_drvdata(pdev);
1760b38dd17SMans Rullgard 	void __iomem *base = cs->base;
1774a59058fSMaxime Ripard 	int ret;
1784a59058fSMaxime Ripard 
1794a59058fSMaxime Ripard 	writel(~0, base + TIMER_INTVAL_LO_REG(1));
1804a59058fSMaxime Ripard 	writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
1814a59058fSMaxime Ripard 	       base + TIMER_CTL_REG(1));
1824a59058fSMaxime Ripard 
1837e5bac61SMans Rullgard 	cs->clksrc.name = pdev->dev.of_node->name;
18459387683SChen-Yu Tsai 	cs->clksrc.rating = 340;
18559387683SChen-Yu Tsai 	cs->clksrc.read = sun5i_clksrc_read;
18659387683SChen-Yu Tsai 	cs->clksrc.mask = CLOCKSOURCE_MASK(32);
18759387683SChen-Yu Tsai 	cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
18859387683SChen-Yu Tsai 
18959387683SChen-Yu Tsai 	ret = clocksource_register_hz(&cs->clksrc, rate);
1904a59058fSMaxime Ripard 	if (ret) {
1917e5bac61SMans Rullgard 		dev_err(&pdev->dev, "Couldn't register clock source.\n");
1924a59058fSMaxime Ripard 		return ret;
1934a59058fSMaxime Ripard 	}
1944a59058fSMaxime Ripard 
1957ded8038SMans Rullgard 	return 0;
1963071efa4SMaxime Ripard }
1973071efa4SMaxime Ripard 
sun5i_setup_clockevent(struct platform_device * pdev,unsigned long rate,int irq)1987e5bac61SMans Rullgard static int sun5i_setup_clockevent(struct platform_device *pdev,
1997ded8038SMans Rullgard 				  unsigned long rate, int irq)
2004a59058fSMaxime Ripard {
2017e5bac61SMans Rullgard 	struct device *dev = &pdev->dev;
2027e5bac61SMans Rullgard 	struct sun5i_timer *ce = platform_get_drvdata(pdev);
2030b38dd17SMans Rullgard 	void __iomem *base = ce->base;
2044a59058fSMaxime Ripard 	int ret;
2054a59058fSMaxime Ripard 	u32 val;
2064a59058fSMaxime Ripard 
2077e5bac61SMans Rullgard 	ce->clkevt.name = dev->of_node->name;
2084a59058fSMaxime Ripard 	ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
2094a59058fSMaxime Ripard 	ce->clkevt.set_next_event = sun5i_clkevt_next_event;
2107486f5adSViresh Kumar 	ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown;
2117486f5adSViresh Kumar 	ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic;
2127486f5adSViresh Kumar 	ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot;
2137486f5adSViresh Kumar 	ce->clkevt.tick_resume = sun5i_clkevt_shutdown;
2144a59058fSMaxime Ripard 	ce->clkevt.rating = 340;
2154a59058fSMaxime Ripard 	ce->clkevt.irq = irq;
2164a59058fSMaxime Ripard 	ce->clkevt.cpumask = cpu_possible_mask;
2174a59058fSMaxime Ripard 
2184a59058fSMaxime Ripard 	/* Enable timer0 interrupt */
2194a59058fSMaxime Ripard 	val = readl(base + TIMER_IRQ_EN_REG);
2204a59058fSMaxime Ripard 	writel(val | TIMER_IRQ_EN(0), base + TIMER_IRQ_EN_REG);
2214a59058fSMaxime Ripard 
2224a59058fSMaxime Ripard 	clockevents_config_and_register(&ce->clkevt, rate,
2234a59058fSMaxime Ripard 					TIMER_SYNC_TICKS, 0xffffffff);
2244a59058fSMaxime Ripard 
2257e5bac61SMans Rullgard 	ret = devm_request_irq(dev, irq, sun5i_timer_interrupt,
2267e5bac61SMans Rullgard 			       IRQF_TIMER | IRQF_IRQPOLL,
2274a59058fSMaxime Ripard 			       "sun5i_timer0", ce);
2284a59058fSMaxime Ripard 	if (ret) {
2297e5bac61SMans Rullgard 		dev_err(dev, "Unable to register interrupt\n");
2307ded8038SMans Rullgard 		return ret;
2314a59058fSMaxime Ripard 	}
2324a59058fSMaxime Ripard 
2334a59058fSMaxime Ripard 	return 0;
2344a59058fSMaxime Ripard }
2354a59058fSMaxime Ripard 
sun5i_timer_probe(struct platform_device * pdev)2367e5bac61SMans Rullgard static int sun5i_timer_probe(struct platform_device *pdev)
23767905540SMaxime Ripard {
2387e5bac61SMans Rullgard 	struct device *dev = &pdev->dev;
2397ded8038SMans Rullgard 	struct sun5i_timer *st;
240e50a00beSMaxime Ripard 	struct reset_control *rstc;
2414a59058fSMaxime Ripard 	void __iomem *timer_base;
24267905540SMaxime Ripard 	struct clk *clk;
2437ded8038SMans Rullgard 	unsigned long rate;
244e4d9f2eeSDaniel Lezcano 	int irq, ret;
24567905540SMaxime Ripard 
2467e5bac61SMans Rullgard 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
2477ded8038SMans Rullgard 	if (!st)
2487ded8038SMans Rullgard 		return -ENOMEM;
2497ded8038SMans Rullgard 
2507e5bac61SMans Rullgard 	platform_set_drvdata(pdev, st);
2517e5bac61SMans Rullgard 
2527e5bac61SMans Rullgard 	timer_base = devm_platform_ioremap_resource(pdev, 0);
253e4d9f2eeSDaniel Lezcano 	if (IS_ERR(timer_base)) {
2547e5bac61SMans Rullgard 		dev_err(dev, "Can't map registers\n");
255ed7158baSIngo Molnar 		return PTR_ERR(timer_base);
256e4d9f2eeSDaniel Lezcano 	}
25767905540SMaxime Ripard 
2587e5bac61SMans Rullgard 	irq = platform_get_irq(pdev, 0);
259*fd73c011SYang Li 	if (irq < 0)
2607e5bac61SMans Rullgard 		return irq;
26167905540SMaxime Ripard 
2627e5bac61SMans Rullgard 	clk = devm_clk_get_enabled(dev, NULL);
263e4d9f2eeSDaniel Lezcano 	if (IS_ERR(clk)) {
2647e5bac61SMans Rullgard 		dev_err(dev, "Can't get timer clock\n");
265e4d9f2eeSDaniel Lezcano 		return PTR_ERR(clk);
266e4d9f2eeSDaniel Lezcano 	}
26767905540SMaxime Ripard 
2687ded8038SMans Rullgard 	rate = clk_get_rate(clk);
2697ded8038SMans Rullgard 	if (!rate) {
2707e5bac61SMans Rullgard 		dev_err(dev, "Couldn't get parent clock rate\n");
2717e5bac61SMans Rullgard 		return -EINVAL;
2727ded8038SMans Rullgard 	}
2737ded8038SMans Rullgard 
2740b38dd17SMans Rullgard 	st->base = timer_base;
2750b38dd17SMans Rullgard 	st->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
2760b38dd17SMans Rullgard 	st->clk = clk;
2770b38dd17SMans Rullgard 	st->clk_rate_cb.notifier_call = sun5i_rate_cb;
2780b38dd17SMans Rullgard 	st->clk_rate_cb.next = NULL;
2797ded8038SMans Rullgard 
2807e5bac61SMans Rullgard 	ret = devm_clk_notifier_register(dev, clk, &st->clk_rate_cb);
2817ded8038SMans Rullgard 	if (ret) {
2827e5bac61SMans Rullgard 		dev_err(dev, "Unable to register clock notifier.\n");
2837ded8038SMans Rullgard 		return ret;
28467905540SMaxime Ripard 	}
2857e5bac61SMans Rullgard 
2867e5bac61SMans Rullgard 	rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
2877e5bac61SMans Rullgard 	if (rstc)
2887e5bac61SMans Rullgard 		reset_control_deassert(rstc);
2897e5bac61SMans Rullgard 
2907e5bac61SMans Rullgard 	ret = sun5i_setup_clocksource(pdev, rate);
2917e5bac61SMans Rullgard 	if (ret)
2927e5bac61SMans Rullgard 		return ret;
2937e5bac61SMans Rullgard 
2947e5bac61SMans Rullgard 	ret = sun5i_setup_clockevent(pdev, rate, irq);
2957e5bac61SMans Rullgard 	if (ret)
2967e5bac61SMans Rullgard 		goto err_unreg_clocksource;
2977e5bac61SMans Rullgard 
2987e5bac61SMans Rullgard 	return 0;
2997e5bac61SMans Rullgard 
3007e5bac61SMans Rullgard err_unreg_clocksource:
3017e5bac61SMans Rullgard 	clocksource_unregister(&st->clksrc);
3027e5bac61SMans Rullgard 	return ret;
3037e5bac61SMans Rullgard }
3047e5bac61SMans Rullgard 
sun5i_timer_remove(struct platform_device * pdev)3057e5bac61SMans Rullgard static void sun5i_timer_remove(struct platform_device *pdev)
3067e5bac61SMans Rullgard {
3077e5bac61SMans Rullgard 	struct sun5i_timer *st = platform_get_drvdata(pdev);
3087e5bac61SMans Rullgard 
3097e5bac61SMans Rullgard 	clocksource_unregister(&st->clksrc);
3107e5bac61SMans Rullgard }
3117e5bac61SMans Rullgard 
3127e5bac61SMans Rullgard static const struct of_device_id sun5i_timer_of_match[] = {
3137e5bac61SMans Rullgard 	{ .compatible = "allwinner,sun5i-a13-hstimer" },
3147e5bac61SMans Rullgard 	{ .compatible = "allwinner,sun7i-a20-hstimer" },
3157e5bac61SMans Rullgard 	{},
3167e5bac61SMans Rullgard };
3177e5bac61SMans Rullgard MODULE_DEVICE_TABLE(of, sun5i_timer_of_match);
3187e5bac61SMans Rullgard 
3197e5bac61SMans Rullgard static struct platform_driver sun5i_timer_driver = {
3207e5bac61SMans Rullgard 	.probe		= sun5i_timer_probe,
3217e5bac61SMans Rullgard 	.remove_new	= sun5i_timer_remove,
3227e5bac61SMans Rullgard 	.driver	= {
3237e5bac61SMans Rullgard 		.name	= "sun5i-timer",
3247e5bac61SMans Rullgard 		.of_match_table = sun5i_timer_of_match,
3257e5bac61SMans Rullgard 		.suppress_bind_attrs = true,
3267e5bac61SMans Rullgard 	},
3277e5bac61SMans Rullgard };
3287e5bac61SMans Rullgard module_platform_driver(sun5i_timer_driver);
329