brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 9af30af Raw
224 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com4 * All rights reserved.5 *6 * Copyright 2017 Google, Inc.7 */8 9#include <linux/kernel.h>10#include <linux/sched.h>11#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/err.h>14#include <linux/clk.h>15#include <linux/io.h>16#include <linux/clockchips.h>17#include <linux/of_irq.h>18#include <linux/of_address.h>19#include "timer-of.h"20 21/* Timers registers */22#define NPCM7XX_REG_TCSR0	0x0 /* Timer 0 Control and Status Register */23#define NPCM7XX_REG_TICR0	0x8 /* Timer 0 Initial Count Register */24#define NPCM7XX_REG_TCSR1	0x4 /* Timer 1 Control and Status Register */25#define NPCM7XX_REG_TICR1	0xc /* Timer 1 Initial Count Register */26#define NPCM7XX_REG_TDR1	0x14 /* Timer 1 Data Register */27#define NPCM7XX_REG_TISR	0x18 /* Timer Interrupt Status Register */28 29/* Timers control */30#define NPCM7XX_Tx_RESETINT		0x1f31#define NPCM7XX_Tx_PERIOD		BIT(27)32#define NPCM7XX_Tx_INTEN		BIT(29)33#define NPCM7XX_Tx_COUNTEN		BIT(30)34#define NPCM7XX_Tx_ONESHOT		0x035#define NPCM7XX_Tx_OPER			GENMASK(28, 27)36#define NPCM7XX_Tx_MIN_PRESCALE		0x137#define NPCM7XX_Tx_TDR_MASK_BITS	2438#define NPCM7XX_Tx_MAX_CNT		0xFFFFFF39#define NPCM7XX_T0_CLR_INT		0x140#define NPCM7XX_Tx_CLR_CSR		0x041 42/* Timers operating mode */43#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \44					NPCM7XX_Tx_INTEN | \45					NPCM7XX_Tx_MIN_PRESCALE)46 47#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \48					NPCM7XX_Tx_INTEN | \49					NPCM7XX_Tx_MIN_PRESCALE)50 51#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \52				NPCM7XX_Tx_MIN_PRESCALE)53 54#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE)55 56static int npcm7xx_timer_resume(struct clock_event_device *evt)57{58	struct timer_of *to = to_timer_of(evt);59	u32 val;60 61	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);62	val |= NPCM7XX_Tx_COUNTEN;63	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);64 65	return 0;66}67 68static int npcm7xx_timer_shutdown(struct clock_event_device *evt)69{70	struct timer_of *to = to_timer_of(evt);71	u32 val;72 73	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);74	val &= ~NPCM7XX_Tx_COUNTEN;75	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);76 77	return 0;78}79 80static int npcm7xx_timer_oneshot(struct clock_event_device *evt)81{82	struct timer_of *to = to_timer_of(evt);83	u32 val;84 85	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);86	val &= ~NPCM7XX_Tx_OPER;87	val |= NPCM7XX_START_ONESHOT_Tx;88	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);89 90	return 0;91}92 93static int npcm7xx_timer_periodic(struct clock_event_device *evt)94{95	struct timer_of *to = to_timer_of(evt);96	u32 val;97 98	writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);99 100	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);101	val &= ~NPCM7XX_Tx_OPER;102	val |= NPCM7XX_START_PERIODIC_Tx;103	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);104 105	return 0;106}107 108static int npcm7xx_clockevent_set_next_event(unsigned long evt,109		struct clock_event_device *clk)110{111	struct timer_of *to = to_timer_of(clk);112	u32 val;113 114	writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);115	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);116	val |= NPCM7XX_START_Tx;117	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);118 119	return 0;120}121 122static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)123{124	struct clock_event_device *evt = (struct clock_event_device *)dev_id;125	struct timer_of *to = to_timer_of(evt);126 127	writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);128 129	evt->event_handler(evt);130 131	return IRQ_HANDLED;132}133 134static struct timer_of npcm7xx_to = {135	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,136 137	.clkevt = {138		.name		    = "npcm7xx-timer0",139		.features	    = CLOCK_EVT_FEAT_PERIODIC |140				      CLOCK_EVT_FEAT_ONESHOT,141		.set_next_event	    = npcm7xx_clockevent_set_next_event,142		.set_state_shutdown = npcm7xx_timer_shutdown,143		.set_state_periodic = npcm7xx_timer_periodic,144		.set_state_oneshot  = npcm7xx_timer_oneshot,145		.tick_resume	    = npcm7xx_timer_resume,146		.rating		    = 300,147	},148 149	.of_irq = {150		.handler = npcm7xx_timer0_interrupt,151		.flags = IRQF_TIMER | IRQF_IRQPOLL,152	},153};154 155static void __init npcm7xx_clockevents_init(void)156{157	writel(NPCM7XX_DEFAULT_CSR,158		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);159 160	writel(NPCM7XX_Tx_RESETINT,161		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);162 163	npcm7xx_to.clkevt.cpumask = cpumask_of(0);164	clockevents_config_and_register(&npcm7xx_to.clkevt,165					timer_of_rate(&npcm7xx_to),166					0x1, NPCM7XX_Tx_MAX_CNT);167}168 169static void __init npcm7xx_clocksource_init(void)170{171	u32 val;172 173	writel(NPCM7XX_DEFAULT_CSR,174		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);175	writel(NPCM7XX_Tx_MAX_CNT,176		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);177 178	val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);179	val |= NPCM7XX_START_Tx;180	writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);181 182	clocksource_mmio_init(timer_of_base(&npcm7xx_to) +183				NPCM7XX_REG_TDR1,184				"npcm7xx-timer1", timer_of_rate(&npcm7xx_to),185				200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,186				clocksource_mmio_readl_down);187}188 189static int __init npcm7xx_timer_init(struct device_node *np)190{191	struct clk *clk;192	int ret;193 194	ret = timer_of_init(np, &npcm7xx_to);195	if (ret)196		return ret;197 198	/* Clock input is divided by PRESCALE + 1 before it is fed */199	/* to the counter */200	npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /201		(NPCM7XX_Tx_MIN_PRESCALE + 1);202 203	/* Enable the clock for timer1, if it exists */204	clk = of_clk_get(np, 1);205	if (clk) {206		if (!IS_ERR(clk))207			clk_prepare_enable(clk);208		else209			pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk);210	}211 212	npcm7xx_clocksource_init();213	npcm7xx_clockevents_init();214 215	pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",216		timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));217 218	return 0;219}220 221TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init);222TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);223 224