xref: /linux/drivers/clocksource/timer-tegra186.c (revision 42cee19a9f839f2d60f1cd237d6905d8649127aa)
1*42cee19aSThierry Reding // SPDX-License-Identifier: GPL-2.0-only
2*42cee19aSThierry Reding /*
3*42cee19aSThierry Reding  * Copyright (c) 2019-2020 NVIDIA Corporation. All rights reserved.
4*42cee19aSThierry Reding  */
5*42cee19aSThierry Reding 
6*42cee19aSThierry Reding #include <linux/clocksource.h>
7*42cee19aSThierry Reding #include <linux/module.h>
8*42cee19aSThierry Reding #include <linux/interrupt.h>
9*42cee19aSThierry Reding #include <linux/io.h>
10*42cee19aSThierry Reding #include <linux/of.h>
11*42cee19aSThierry Reding #include <linux/of_device.h>
12*42cee19aSThierry Reding #include <linux/platform_device.h>
13*42cee19aSThierry Reding #include <linux/pm.h>
14*42cee19aSThierry Reding #include <linux/watchdog.h>
15*42cee19aSThierry Reding 
16*42cee19aSThierry Reding /* shared registers */
17*42cee19aSThierry Reding #define TKETSC0 0x000
18*42cee19aSThierry Reding #define TKETSC1 0x004
19*42cee19aSThierry Reding #define TKEUSEC 0x008
20*42cee19aSThierry Reding #define TKEOSC  0x00c
21*42cee19aSThierry Reding 
22*42cee19aSThierry Reding #define TKEIE(x) (0x100 + ((x) * 4))
23*42cee19aSThierry Reding #define  TKEIE_WDT_MASK(x, y) ((y) << (16 + 4 * (x)))
24*42cee19aSThierry Reding 
25*42cee19aSThierry Reding /* timer registers */
26*42cee19aSThierry Reding #define TMRCR 0x000
27*42cee19aSThierry Reding #define  TMRCR_ENABLE BIT(31)
28*42cee19aSThierry Reding #define  TMRCR_PERIODIC BIT(30)
29*42cee19aSThierry Reding #define  TMRCR_PTV(x) ((x) & 0x0fffffff)
30*42cee19aSThierry Reding 
31*42cee19aSThierry Reding #define TMRSR 0x004
32*42cee19aSThierry Reding #define  TMRSR_INTR_CLR BIT(30)
33*42cee19aSThierry Reding 
34*42cee19aSThierry Reding #define TMRCSSR 0x008
35*42cee19aSThierry Reding #define  TMRCSSR_SRC_USEC (0 << 0)
36*42cee19aSThierry Reding 
37*42cee19aSThierry Reding /* watchdog registers */
38*42cee19aSThierry Reding #define WDTCR 0x000
39*42cee19aSThierry Reding #define  WDTCR_SYSTEM_POR_RESET_ENABLE BIT(16)
40*42cee19aSThierry Reding #define  WDTCR_SYSTEM_DEBUG_RESET_ENABLE BIT(15)
41*42cee19aSThierry Reding #define  WDTCR_REMOTE_INT_ENABLE BIT(14)
42*42cee19aSThierry Reding #define  WDTCR_LOCAL_FIQ_ENABLE BIT(13)
43*42cee19aSThierry Reding #define  WDTCR_LOCAL_INT_ENABLE BIT(12)
44*42cee19aSThierry Reding #define  WDTCR_PERIOD_MASK (0xff << 4)
45*42cee19aSThierry Reding #define  WDTCR_PERIOD(x) (((x) & 0xff) << 4)
46*42cee19aSThierry Reding #define  WDTCR_TIMER_SOURCE_MASK 0xf
47*42cee19aSThierry Reding #define  WDTCR_TIMER_SOURCE(x) ((x) & 0xf)
48*42cee19aSThierry Reding 
49*42cee19aSThierry Reding #define WDTCMDR 0x008
50*42cee19aSThierry Reding #define  WDTCMDR_DISABLE_COUNTER BIT(1)
51*42cee19aSThierry Reding #define  WDTCMDR_START_COUNTER BIT(0)
52*42cee19aSThierry Reding 
53*42cee19aSThierry Reding #define WDTUR 0x00c
54*42cee19aSThierry Reding #define  WDTUR_UNLOCK_PATTERN 0x0000c45a
55*42cee19aSThierry Reding 
56*42cee19aSThierry Reding struct tegra186_timer_soc {
57*42cee19aSThierry Reding 	unsigned int num_timers;
58*42cee19aSThierry Reding 	unsigned int num_wdts;
59*42cee19aSThierry Reding };
60*42cee19aSThierry Reding 
61*42cee19aSThierry Reding struct tegra186_tmr {
62*42cee19aSThierry Reding 	struct tegra186_timer *parent;
63*42cee19aSThierry Reding 	void __iomem *regs;
64*42cee19aSThierry Reding 	unsigned int index;
65*42cee19aSThierry Reding 	unsigned int hwirq;
66*42cee19aSThierry Reding };
67*42cee19aSThierry Reding 
68*42cee19aSThierry Reding struct tegra186_wdt {
69*42cee19aSThierry Reding 	struct watchdog_device base;
70*42cee19aSThierry Reding 
71*42cee19aSThierry Reding 	void __iomem *regs;
72*42cee19aSThierry Reding 	unsigned int index;
73*42cee19aSThierry Reding 	bool locked;
74*42cee19aSThierry Reding 
75*42cee19aSThierry Reding 	struct tegra186_tmr *tmr;
76*42cee19aSThierry Reding };
77*42cee19aSThierry Reding 
78*42cee19aSThierry Reding static inline struct tegra186_wdt *to_tegra186_wdt(struct watchdog_device *wdd)
79*42cee19aSThierry Reding {
80*42cee19aSThierry Reding 	return container_of(wdd, struct tegra186_wdt, base);
81*42cee19aSThierry Reding }
82*42cee19aSThierry Reding 
83*42cee19aSThierry Reding struct tegra186_timer {
84*42cee19aSThierry Reding 	const struct tegra186_timer_soc *soc;
85*42cee19aSThierry Reding 	struct device *dev;
86*42cee19aSThierry Reding 	void __iomem *regs;
87*42cee19aSThierry Reding 
88*42cee19aSThierry Reding 	struct tegra186_wdt *wdt;
89*42cee19aSThierry Reding 	struct clocksource usec;
90*42cee19aSThierry Reding 	struct clocksource tsc;
91*42cee19aSThierry Reding 	struct clocksource osc;
92*42cee19aSThierry Reding };
93*42cee19aSThierry Reding 
94*42cee19aSThierry Reding static void tmr_writel(struct tegra186_tmr *tmr, u32 value, unsigned int offset)
95*42cee19aSThierry Reding {
96*42cee19aSThierry Reding 	writel_relaxed(value, tmr->regs + offset);
97*42cee19aSThierry Reding }
98*42cee19aSThierry Reding 
99*42cee19aSThierry Reding static void wdt_writel(struct tegra186_wdt *wdt, u32 value, unsigned int offset)
100*42cee19aSThierry Reding {
101*42cee19aSThierry Reding 	writel_relaxed(value, wdt->regs + offset);
102*42cee19aSThierry Reding }
103*42cee19aSThierry Reding 
104*42cee19aSThierry Reding static u32 wdt_readl(struct tegra186_wdt *wdt, unsigned int offset)
105*42cee19aSThierry Reding {
106*42cee19aSThierry Reding 	return readl_relaxed(wdt->regs + offset);
107*42cee19aSThierry Reding }
108*42cee19aSThierry Reding 
109*42cee19aSThierry Reding static struct tegra186_tmr *tegra186_tmr_create(struct tegra186_timer *tegra,
110*42cee19aSThierry Reding 						unsigned int index)
111*42cee19aSThierry Reding {
112*42cee19aSThierry Reding 	unsigned int offset = 0x10000 + index * 0x10000;
113*42cee19aSThierry Reding 	struct tegra186_tmr *tmr;
114*42cee19aSThierry Reding 
115*42cee19aSThierry Reding 	tmr = devm_kzalloc(tegra->dev, sizeof(*tmr), GFP_KERNEL);
116*42cee19aSThierry Reding 	if (!tmr)
117*42cee19aSThierry Reding 		return ERR_PTR(-ENOMEM);
118*42cee19aSThierry Reding 
119*42cee19aSThierry Reding 	tmr->parent = tegra;
120*42cee19aSThierry Reding 	tmr->regs = tegra->regs + offset;
121*42cee19aSThierry Reding 	tmr->index = index;
122*42cee19aSThierry Reding 	tmr->hwirq = 0;
123*42cee19aSThierry Reding 
124*42cee19aSThierry Reding 	return tmr;
125*42cee19aSThierry Reding }
126*42cee19aSThierry Reding 
127*42cee19aSThierry Reding static const struct watchdog_info tegra186_wdt_info = {
128*42cee19aSThierry Reding 	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
129*42cee19aSThierry Reding 	.identity = "NVIDIA Tegra186 WDT",
130*42cee19aSThierry Reding };
131*42cee19aSThierry Reding 
132*42cee19aSThierry Reding static void tegra186_wdt_disable(struct tegra186_wdt *wdt)
133*42cee19aSThierry Reding {
134*42cee19aSThierry Reding 	/* unlock and disable the watchdog */
135*42cee19aSThierry Reding 	wdt_writel(wdt, WDTUR_UNLOCK_PATTERN, WDTUR);
136*42cee19aSThierry Reding 	wdt_writel(wdt, WDTCMDR_DISABLE_COUNTER, WDTCMDR);
137*42cee19aSThierry Reding 
138*42cee19aSThierry Reding 	/* disable timer */
139*42cee19aSThierry Reding 	tmr_writel(wdt->tmr, 0, TMRCR);
140*42cee19aSThierry Reding }
141*42cee19aSThierry Reding 
142*42cee19aSThierry Reding static void tegra186_wdt_enable(struct tegra186_wdt *wdt)
143*42cee19aSThierry Reding {
144*42cee19aSThierry Reding 	struct tegra186_timer *tegra = wdt->tmr->parent;
145*42cee19aSThierry Reding 	u32 value;
146*42cee19aSThierry Reding 
147*42cee19aSThierry Reding 	/* unmask hardware IRQ, this may have been lost across powergate */
148*42cee19aSThierry Reding 	value = TKEIE_WDT_MASK(wdt->index, 1);
149*42cee19aSThierry Reding 	writel(value, tegra->regs + TKEIE(wdt->tmr->hwirq));
150*42cee19aSThierry Reding 
151*42cee19aSThierry Reding 	/* clear interrupt */
152*42cee19aSThierry Reding 	tmr_writel(wdt->tmr, TMRSR_INTR_CLR, TMRSR);
153*42cee19aSThierry Reding 
154*42cee19aSThierry Reding 	/* select microsecond source */
155*42cee19aSThierry Reding 	tmr_writel(wdt->tmr, TMRCSSR_SRC_USEC, TMRCSSR);
156*42cee19aSThierry Reding 
157*42cee19aSThierry Reding 	/* configure timer (system reset happens on the fifth expiration) */
158*42cee19aSThierry Reding 	value = TMRCR_PTV(wdt->base.timeout * USEC_PER_SEC / 5) |
159*42cee19aSThierry Reding 		TMRCR_PERIODIC | TMRCR_ENABLE;
160*42cee19aSThierry Reding 	tmr_writel(wdt->tmr, value, TMRCR);
161*42cee19aSThierry Reding 
162*42cee19aSThierry Reding 	if (!wdt->locked) {
163*42cee19aSThierry Reding 		value = wdt_readl(wdt, WDTCR);
164*42cee19aSThierry Reding 
165*42cee19aSThierry Reding 		/* select the proper timer source */
166*42cee19aSThierry Reding 		value &= ~WDTCR_TIMER_SOURCE_MASK;
167*42cee19aSThierry Reding 		value |= WDTCR_TIMER_SOURCE(wdt->tmr->index);
168*42cee19aSThierry Reding 
169*42cee19aSThierry Reding 		/* single timer period since that's already configured */
170*42cee19aSThierry Reding 		value &= ~WDTCR_PERIOD_MASK;
171*42cee19aSThierry Reding 		value |= WDTCR_PERIOD(1);
172*42cee19aSThierry Reding 
173*42cee19aSThierry Reding 		/* enable local interrupt for WDT petting */
174*42cee19aSThierry Reding 		value |= WDTCR_LOCAL_INT_ENABLE;
175*42cee19aSThierry Reding 
176*42cee19aSThierry Reding 		/* enable local FIQ and remote interrupt for debug dump */
177*42cee19aSThierry Reding 		if (0)
178*42cee19aSThierry Reding 			value |= WDTCR_REMOTE_INT_ENABLE |
179*42cee19aSThierry Reding 				 WDTCR_LOCAL_FIQ_ENABLE;
180*42cee19aSThierry Reding 
181*42cee19aSThierry Reding 		/* enable system debug reset (doesn't properly reboot) */
182*42cee19aSThierry Reding 		if (0)
183*42cee19aSThierry Reding 			value |= WDTCR_SYSTEM_DEBUG_RESET_ENABLE;
184*42cee19aSThierry Reding 
185*42cee19aSThierry Reding 		/* enable system POR reset */
186*42cee19aSThierry Reding 		value |= WDTCR_SYSTEM_POR_RESET_ENABLE;
187*42cee19aSThierry Reding 
188*42cee19aSThierry Reding 		wdt_writel(wdt, value, WDTCR);
189*42cee19aSThierry Reding 	}
190*42cee19aSThierry Reding 
191*42cee19aSThierry Reding 	wdt_writel(wdt, WDTCMDR_START_COUNTER, WDTCMDR);
192*42cee19aSThierry Reding }
193*42cee19aSThierry Reding 
194*42cee19aSThierry Reding static int tegra186_wdt_start(struct watchdog_device *wdd)
195*42cee19aSThierry Reding {
196*42cee19aSThierry Reding 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
197*42cee19aSThierry Reding 
198*42cee19aSThierry Reding 	tegra186_wdt_enable(wdt);
199*42cee19aSThierry Reding 
200*42cee19aSThierry Reding 	return 0;
201*42cee19aSThierry Reding }
202*42cee19aSThierry Reding 
203*42cee19aSThierry Reding static int tegra186_wdt_stop(struct watchdog_device *wdd)
204*42cee19aSThierry Reding {
205*42cee19aSThierry Reding 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
206*42cee19aSThierry Reding 
207*42cee19aSThierry Reding 	tegra186_wdt_disable(wdt);
208*42cee19aSThierry Reding 
209*42cee19aSThierry Reding 	return 0;
210*42cee19aSThierry Reding }
211*42cee19aSThierry Reding 
212*42cee19aSThierry Reding static int tegra186_wdt_ping(struct watchdog_device *wdd)
213*42cee19aSThierry Reding {
214*42cee19aSThierry Reding 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
215*42cee19aSThierry Reding 
216*42cee19aSThierry Reding 	tegra186_wdt_disable(wdt);
217*42cee19aSThierry Reding 	tegra186_wdt_enable(wdt);
218*42cee19aSThierry Reding 
219*42cee19aSThierry Reding 	return 0;
220*42cee19aSThierry Reding }
221*42cee19aSThierry Reding 
222*42cee19aSThierry Reding static int tegra186_wdt_set_timeout(struct watchdog_device *wdd,
223*42cee19aSThierry Reding 				    unsigned int timeout)
224*42cee19aSThierry Reding {
225*42cee19aSThierry Reding 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
226*42cee19aSThierry Reding 
227*42cee19aSThierry Reding 	if (watchdog_active(&wdt->base))
228*42cee19aSThierry Reding 		tegra186_wdt_disable(wdt);
229*42cee19aSThierry Reding 
230*42cee19aSThierry Reding 	wdt->base.timeout = timeout;
231*42cee19aSThierry Reding 
232*42cee19aSThierry Reding 	if (watchdog_active(&wdt->base))
233*42cee19aSThierry Reding 		tegra186_wdt_enable(wdt);
234*42cee19aSThierry Reding 
235*42cee19aSThierry Reding 	return 0;
236*42cee19aSThierry Reding }
237*42cee19aSThierry Reding 
238*42cee19aSThierry Reding static const struct watchdog_ops tegra186_wdt_ops = {
239*42cee19aSThierry Reding 	.owner = THIS_MODULE,
240*42cee19aSThierry Reding 	.start = tegra186_wdt_start,
241*42cee19aSThierry Reding 	.stop = tegra186_wdt_stop,
242*42cee19aSThierry Reding 	.ping = tegra186_wdt_ping,
243*42cee19aSThierry Reding 	.set_timeout = tegra186_wdt_set_timeout,
244*42cee19aSThierry Reding };
245*42cee19aSThierry Reding 
246*42cee19aSThierry Reding static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
247*42cee19aSThierry Reding 						unsigned int index)
248*42cee19aSThierry Reding {
249*42cee19aSThierry Reding 	unsigned int offset = 0x10000, source;
250*42cee19aSThierry Reding 	struct tegra186_wdt *wdt;
251*42cee19aSThierry Reding 	u32 value;
252*42cee19aSThierry Reding 	int err;
253*42cee19aSThierry Reding 
254*42cee19aSThierry Reding 	offset += tegra->soc->num_timers * 0x10000 + index * 0x10000;
255*42cee19aSThierry Reding 
256*42cee19aSThierry Reding 	wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL);
257*42cee19aSThierry Reding 	if (!wdt)
258*42cee19aSThierry Reding 		return ERR_PTR(-ENOMEM);
259*42cee19aSThierry Reding 
260*42cee19aSThierry Reding 	wdt->regs = tegra->regs + offset;
261*42cee19aSThierry Reding 	wdt->index = index;
262*42cee19aSThierry Reding 
263*42cee19aSThierry Reding 	/* read the watchdog configuration since it might be locked down */
264*42cee19aSThierry Reding 	value = wdt_readl(wdt, WDTCR);
265*42cee19aSThierry Reding 
266*42cee19aSThierry Reding 	if (value & WDTCR_LOCAL_INT_ENABLE)
267*42cee19aSThierry Reding 		wdt->locked = true;
268*42cee19aSThierry Reding 
269*42cee19aSThierry Reding 	source = value & WDTCR_TIMER_SOURCE_MASK;
270*42cee19aSThierry Reding 
271*42cee19aSThierry Reding 	wdt->tmr = tegra186_tmr_create(tegra, source);
272*42cee19aSThierry Reding 	if (IS_ERR(wdt->tmr))
273*42cee19aSThierry Reding 		return ERR_CAST(wdt->tmr);
274*42cee19aSThierry Reding 
275*42cee19aSThierry Reding 	wdt->base.info = &tegra186_wdt_info;
276*42cee19aSThierry Reding 	wdt->base.ops = &tegra186_wdt_ops;
277*42cee19aSThierry Reding 	wdt->base.min_timeout = 1;
278*42cee19aSThierry Reding 	wdt->base.max_timeout = 255;
279*42cee19aSThierry Reding 	wdt->base.parent = tegra->dev;
280*42cee19aSThierry Reding 
281*42cee19aSThierry Reding 	err = watchdog_init_timeout(&wdt->base, 5, tegra->dev);
282*42cee19aSThierry Reding 	if (err < 0) {
283*42cee19aSThierry Reding 		dev_err(tegra->dev, "failed to initialize timeout: %d\n", err);
284*42cee19aSThierry Reding 		return ERR_PTR(err);
285*42cee19aSThierry Reding 	}
286*42cee19aSThierry Reding 
287*42cee19aSThierry Reding 	err = devm_watchdog_register_device(tegra->dev, &wdt->base);
288*42cee19aSThierry Reding 	if (err < 0) {
289*42cee19aSThierry Reding 		dev_err(tegra->dev, "failed to register WDT: %d\n", err);
290*42cee19aSThierry Reding 		return ERR_PTR(err);
291*42cee19aSThierry Reding 	}
292*42cee19aSThierry Reding 
293*42cee19aSThierry Reding 	return wdt;
294*42cee19aSThierry Reding }
295*42cee19aSThierry Reding 
296*42cee19aSThierry Reding static u64 tegra186_timer_tsc_read(struct clocksource *cs)
297*42cee19aSThierry Reding {
298*42cee19aSThierry Reding 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
299*42cee19aSThierry Reding 						    tsc);
300*42cee19aSThierry Reding 	u32 hi, lo, ss;
301*42cee19aSThierry Reding 
302*42cee19aSThierry Reding 	hi = readl_relaxed(tegra->regs + TKETSC1);
303*42cee19aSThierry Reding 
304*42cee19aSThierry Reding 	/*
305*42cee19aSThierry Reding 	 * The 56-bit value of the TSC is spread across two registers that are
306*42cee19aSThierry Reding 	 * not synchronized. In order to read them atomically, ensure that the
307*42cee19aSThierry Reding 	 * high 24 bits match before and after reading the low 32 bits.
308*42cee19aSThierry Reding 	 */
309*42cee19aSThierry Reding 	do {
310*42cee19aSThierry Reding 		/* snapshot the high 24 bits */
311*42cee19aSThierry Reding 		ss = hi;
312*42cee19aSThierry Reding 
313*42cee19aSThierry Reding 		lo = readl_relaxed(tegra->regs + TKETSC0);
314*42cee19aSThierry Reding 		hi = readl_relaxed(tegra->regs + TKETSC1);
315*42cee19aSThierry Reding 	} while (hi != ss);
316*42cee19aSThierry Reding 
317*42cee19aSThierry Reding 	return (u64)hi << 32 | lo;
318*42cee19aSThierry Reding }
319*42cee19aSThierry Reding 
320*42cee19aSThierry Reding static int tegra186_timer_tsc_init(struct tegra186_timer *tegra)
321*42cee19aSThierry Reding {
322*42cee19aSThierry Reding 	tegra->tsc.name = "tsc";
323*42cee19aSThierry Reding 	tegra->tsc.rating = 300;
324*42cee19aSThierry Reding 	tegra->tsc.read = tegra186_timer_tsc_read;
325*42cee19aSThierry Reding 	tegra->tsc.mask = CLOCKSOURCE_MASK(56);
326*42cee19aSThierry Reding 	tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
327*42cee19aSThierry Reding 
328*42cee19aSThierry Reding 	return clocksource_register_hz(&tegra->tsc, 31250000);
329*42cee19aSThierry Reding }
330*42cee19aSThierry Reding 
331*42cee19aSThierry Reding static u64 tegra186_timer_osc_read(struct clocksource *cs)
332*42cee19aSThierry Reding {
333*42cee19aSThierry Reding 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
334*42cee19aSThierry Reding 						    osc);
335*42cee19aSThierry Reding 
336*42cee19aSThierry Reding 	return readl_relaxed(tegra->regs + TKEOSC);
337*42cee19aSThierry Reding }
338*42cee19aSThierry Reding 
339*42cee19aSThierry Reding static int tegra186_timer_osc_init(struct tegra186_timer *tegra)
340*42cee19aSThierry Reding {
341*42cee19aSThierry Reding 	tegra->osc.name = "osc";
342*42cee19aSThierry Reding 	tegra->osc.rating = 300;
343*42cee19aSThierry Reding 	tegra->osc.read = tegra186_timer_osc_read;
344*42cee19aSThierry Reding 	tegra->osc.mask = CLOCKSOURCE_MASK(32);
345*42cee19aSThierry Reding 	tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
346*42cee19aSThierry Reding 
347*42cee19aSThierry Reding 	return clocksource_register_hz(&tegra->osc, 38400000);
348*42cee19aSThierry Reding }
349*42cee19aSThierry Reding 
350*42cee19aSThierry Reding static u64 tegra186_timer_usec_read(struct clocksource *cs)
351*42cee19aSThierry Reding {
352*42cee19aSThierry Reding 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
353*42cee19aSThierry Reding 						    usec);
354*42cee19aSThierry Reding 
355*42cee19aSThierry Reding 	return readl_relaxed(tegra->regs + TKEUSEC);
356*42cee19aSThierry Reding }
357*42cee19aSThierry Reding 
358*42cee19aSThierry Reding static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
359*42cee19aSThierry Reding {
360*42cee19aSThierry Reding 	tegra->usec.name = "usec";
361*42cee19aSThierry Reding 	tegra->usec.rating = 300;
362*42cee19aSThierry Reding 	tegra->usec.read = tegra186_timer_usec_read;
363*42cee19aSThierry Reding 	tegra->usec.mask = CLOCKSOURCE_MASK(32);
364*42cee19aSThierry Reding 	tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS;
365*42cee19aSThierry Reding 
366*42cee19aSThierry Reding 	return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
367*42cee19aSThierry Reding }
368*42cee19aSThierry Reding 
369*42cee19aSThierry Reding static irqreturn_t tegra186_timer_irq(int irq, void *data)
370*42cee19aSThierry Reding {
371*42cee19aSThierry Reding 	struct tegra186_timer *tegra = data;
372*42cee19aSThierry Reding 
373*42cee19aSThierry Reding 	if (watchdog_active(&tegra->wdt->base)) {
374*42cee19aSThierry Reding 		tegra186_wdt_disable(tegra->wdt);
375*42cee19aSThierry Reding 		tegra186_wdt_enable(tegra->wdt);
376*42cee19aSThierry Reding 	}
377*42cee19aSThierry Reding 
378*42cee19aSThierry Reding 	return IRQ_HANDLED;
379*42cee19aSThierry Reding }
380*42cee19aSThierry Reding 
381*42cee19aSThierry Reding static int tegra186_timer_probe(struct platform_device *pdev)
382*42cee19aSThierry Reding {
383*42cee19aSThierry Reding 	struct device *dev = &pdev->dev;
384*42cee19aSThierry Reding 	struct tegra186_timer *tegra;
385*42cee19aSThierry Reding 	unsigned int irq;
386*42cee19aSThierry Reding 	int err;
387*42cee19aSThierry Reding 
388*42cee19aSThierry Reding 	tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL);
389*42cee19aSThierry Reding 	if (!tegra)
390*42cee19aSThierry Reding 		return -ENOMEM;
391*42cee19aSThierry Reding 
392*42cee19aSThierry Reding 	tegra->soc = of_device_get_match_data(dev);
393*42cee19aSThierry Reding 	dev_set_drvdata(dev, tegra);
394*42cee19aSThierry Reding 	tegra->dev = dev;
395*42cee19aSThierry Reding 
396*42cee19aSThierry Reding 	tegra->regs = devm_platform_ioremap_resource(pdev, 0);
397*42cee19aSThierry Reding 	if (IS_ERR(tegra->regs))
398*42cee19aSThierry Reding 		return PTR_ERR(tegra->regs);
399*42cee19aSThierry Reding 
400*42cee19aSThierry Reding 	err = platform_get_irq(pdev, 0);
401*42cee19aSThierry Reding 	if (err < 0)
402*42cee19aSThierry Reding 		return err;
403*42cee19aSThierry Reding 
404*42cee19aSThierry Reding 	irq = err;
405*42cee19aSThierry Reding 
406*42cee19aSThierry Reding 	/* create a watchdog using a preconfigured timer */
407*42cee19aSThierry Reding 	tegra->wdt = tegra186_wdt_create(tegra, 0);
408*42cee19aSThierry Reding 	if (IS_ERR(tegra->wdt)) {
409*42cee19aSThierry Reding 		err = PTR_ERR(tegra->wdt);
410*42cee19aSThierry Reding 		dev_err(dev, "failed to create WDT: %d\n", err);
411*42cee19aSThierry Reding 		return err;
412*42cee19aSThierry Reding 	}
413*42cee19aSThierry Reding 
414*42cee19aSThierry Reding 	err = tegra186_timer_tsc_init(tegra);
415*42cee19aSThierry Reding 	if (err < 0) {
416*42cee19aSThierry Reding 		dev_err(dev, "failed to register TSC counter: %d\n", err);
417*42cee19aSThierry Reding 		return err;
418*42cee19aSThierry Reding 	}
419*42cee19aSThierry Reding 
420*42cee19aSThierry Reding 	err = tegra186_timer_osc_init(tegra);
421*42cee19aSThierry Reding 	if (err < 0) {
422*42cee19aSThierry Reding 		dev_err(dev, "failed to register OSC counter: %d\n", err);
423*42cee19aSThierry Reding 		goto unregister_tsc;
424*42cee19aSThierry Reding 	}
425*42cee19aSThierry Reding 
426*42cee19aSThierry Reding 	err = tegra186_timer_usec_init(tegra);
427*42cee19aSThierry Reding 	if (err < 0) {
428*42cee19aSThierry Reding 		dev_err(dev, "failed to register USEC counter: %d\n", err);
429*42cee19aSThierry Reding 		goto unregister_osc;
430*42cee19aSThierry Reding 	}
431*42cee19aSThierry Reding 
432*42cee19aSThierry Reding 	err = devm_request_irq(dev, irq, tegra186_timer_irq, 0,
433*42cee19aSThierry Reding 			       "tegra186-timer", tegra);
434*42cee19aSThierry Reding 	if (err < 0) {
435*42cee19aSThierry Reding 		dev_err(dev, "failed to request IRQ#%u: %d\n", irq, err);
436*42cee19aSThierry Reding 		goto unregister_usec;
437*42cee19aSThierry Reding 	}
438*42cee19aSThierry Reding 
439*42cee19aSThierry Reding 	return 0;
440*42cee19aSThierry Reding 
441*42cee19aSThierry Reding unregister_usec:
442*42cee19aSThierry Reding 	clocksource_unregister(&tegra->usec);
443*42cee19aSThierry Reding unregister_osc:
444*42cee19aSThierry Reding 	clocksource_unregister(&tegra->osc);
445*42cee19aSThierry Reding unregister_tsc:
446*42cee19aSThierry Reding 	clocksource_unregister(&tegra->tsc);
447*42cee19aSThierry Reding 	return err;
448*42cee19aSThierry Reding }
449*42cee19aSThierry Reding 
450*42cee19aSThierry Reding static int tegra186_timer_remove(struct platform_device *pdev)
451*42cee19aSThierry Reding {
452*42cee19aSThierry Reding 	struct tegra186_timer *tegra = platform_get_drvdata(pdev);
453*42cee19aSThierry Reding 
454*42cee19aSThierry Reding 	clocksource_unregister(&tegra->usec);
455*42cee19aSThierry Reding 	clocksource_unregister(&tegra->osc);
456*42cee19aSThierry Reding 	clocksource_unregister(&tegra->tsc);
457*42cee19aSThierry Reding 
458*42cee19aSThierry Reding 	return 0;
459*42cee19aSThierry Reding }
460*42cee19aSThierry Reding 
461*42cee19aSThierry Reding static int __maybe_unused tegra186_timer_suspend(struct device *dev)
462*42cee19aSThierry Reding {
463*42cee19aSThierry Reding 	struct tegra186_timer *tegra = dev_get_drvdata(dev);
464*42cee19aSThierry Reding 
465*42cee19aSThierry Reding 	if (watchdog_active(&tegra->wdt->base))
466*42cee19aSThierry Reding 		tegra186_wdt_disable(tegra->wdt);
467*42cee19aSThierry Reding 
468*42cee19aSThierry Reding 	return 0;
469*42cee19aSThierry Reding }
470*42cee19aSThierry Reding 
471*42cee19aSThierry Reding static int __maybe_unused tegra186_timer_resume(struct device *dev)
472*42cee19aSThierry Reding {
473*42cee19aSThierry Reding 	struct tegra186_timer *tegra = dev_get_drvdata(dev);
474*42cee19aSThierry Reding 
475*42cee19aSThierry Reding 	if (watchdog_active(&tegra->wdt->base))
476*42cee19aSThierry Reding 		tegra186_wdt_enable(tegra->wdt);
477*42cee19aSThierry Reding 
478*42cee19aSThierry Reding 	return 0;
479*42cee19aSThierry Reding }
480*42cee19aSThierry Reding 
481*42cee19aSThierry Reding static SIMPLE_DEV_PM_OPS(tegra186_timer_pm_ops, tegra186_timer_suspend,
482*42cee19aSThierry Reding 			 tegra186_timer_resume);
483*42cee19aSThierry Reding 
484*42cee19aSThierry Reding static const struct tegra186_timer_soc tegra186_timer = {
485*42cee19aSThierry Reding 	.num_timers = 10,
486*42cee19aSThierry Reding 	.num_wdts = 3,
487*42cee19aSThierry Reding };
488*42cee19aSThierry Reding 
489*42cee19aSThierry Reding static const struct of_device_id tegra186_timer_of_match[] = {
490*42cee19aSThierry Reding 	{ .compatible = "nvidia,tegra186-timer", .data = &tegra186_timer },
491*42cee19aSThierry Reding 	{ }
492*42cee19aSThierry Reding };
493*42cee19aSThierry Reding MODULE_DEVICE_TABLE(of, tegra186_timer_of_match);
494*42cee19aSThierry Reding 
495*42cee19aSThierry Reding static struct platform_driver tegra186_wdt_driver = {
496*42cee19aSThierry Reding 	.driver = {
497*42cee19aSThierry Reding 		.name = "tegra186-timer",
498*42cee19aSThierry Reding 		.pm = &tegra186_timer_pm_ops,
499*42cee19aSThierry Reding 		.of_match_table = tegra186_timer_of_match,
500*42cee19aSThierry Reding 	},
501*42cee19aSThierry Reding 	.probe = tegra186_timer_probe,
502*42cee19aSThierry Reding 	.remove = tegra186_timer_remove,
503*42cee19aSThierry Reding };
504*42cee19aSThierry Reding module_platform_driver(tegra186_wdt_driver);
505*42cee19aSThierry Reding 
506*42cee19aSThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
507*42cee19aSThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver");
508*42cee19aSThierry Reding MODULE_LICENSE("GPL v2");
509