18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Freescale General-purpose Timers Module
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) Freescale Semiconductor, Inc. 2006.
68c2ecf20Sopenharmony_ci *               Shlomi Gridish <gridish@freescale.com>
78c2ecf20Sopenharmony_ci *               Jerry Huang <Chang-Ming.Huang@freescale.com>
88c2ecf20Sopenharmony_ci * Copyright (c) MontaVista Software, Inc. 2008.
98c2ecf20Sopenharmony_ci *               Anton Vorontsov <avorontsov@ru.mvista.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/list.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_address.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
218c2ecf20Sopenharmony_ci#include <linux/bitops.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/export.h>
248c2ecf20Sopenharmony_ci#include <asm/fsl_gtm.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define GTCFR_STP(x)		((x) & 1 ? 1 << 5 : 1 << 1)
278c2ecf20Sopenharmony_ci#define GTCFR_RST(x)		((x) & 1 ? 1 << 4 : 1 << 0)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define GTMDR_ICLK_MASK		(3 << 1)
308c2ecf20Sopenharmony_ci#define GTMDR_ICLK_ICAS		(0 << 1)
318c2ecf20Sopenharmony_ci#define GTMDR_ICLK_ICLK		(1 << 1)
328c2ecf20Sopenharmony_ci#define GTMDR_ICLK_SLGO		(2 << 1)
338c2ecf20Sopenharmony_ci#define GTMDR_FRR		(1 << 3)
348c2ecf20Sopenharmony_ci#define GTMDR_ORI		(1 << 4)
358c2ecf20Sopenharmony_ci#define GTMDR_SPS(x)		((x) << 8)
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct gtm_timers_regs {
388c2ecf20Sopenharmony_ci	u8	gtcfr1;		/* Timer 1, Timer 2 global config register */
398c2ecf20Sopenharmony_ci	u8	res0[0x3];
408c2ecf20Sopenharmony_ci	u8	gtcfr2;		/* Timer 3, timer 4 global config register */
418c2ecf20Sopenharmony_ci	u8	res1[0xB];
428c2ecf20Sopenharmony_ci	__be16	gtmdr1;		/* Timer 1 mode register */
438c2ecf20Sopenharmony_ci	__be16	gtmdr2;		/* Timer 2 mode register */
448c2ecf20Sopenharmony_ci	__be16	gtrfr1;		/* Timer 1 reference register */
458c2ecf20Sopenharmony_ci	__be16	gtrfr2;		/* Timer 2 reference register */
468c2ecf20Sopenharmony_ci	__be16	gtcpr1;		/* Timer 1 capture register */
478c2ecf20Sopenharmony_ci	__be16	gtcpr2;		/* Timer 2 capture register */
488c2ecf20Sopenharmony_ci	__be16	gtcnr1;		/* Timer 1 counter */
498c2ecf20Sopenharmony_ci	__be16	gtcnr2;		/* Timer 2 counter */
508c2ecf20Sopenharmony_ci	__be16	gtmdr3;		/* Timer 3 mode register */
518c2ecf20Sopenharmony_ci	__be16	gtmdr4;		/* Timer 4 mode register */
528c2ecf20Sopenharmony_ci	__be16	gtrfr3;		/* Timer 3 reference register */
538c2ecf20Sopenharmony_ci	__be16	gtrfr4;		/* Timer 4 reference register */
548c2ecf20Sopenharmony_ci	__be16	gtcpr3;		/* Timer 3 capture register */
558c2ecf20Sopenharmony_ci	__be16	gtcpr4;		/* Timer 4 capture register */
568c2ecf20Sopenharmony_ci	__be16	gtcnr3;		/* Timer 3 counter */
578c2ecf20Sopenharmony_ci	__be16	gtcnr4;		/* Timer 4 counter */
588c2ecf20Sopenharmony_ci	__be16	gtevr1;		/* Timer 1 event register */
598c2ecf20Sopenharmony_ci	__be16	gtevr2;		/* Timer 2 event register */
608c2ecf20Sopenharmony_ci	__be16	gtevr3;		/* Timer 3 event register */
618c2ecf20Sopenharmony_ci	__be16	gtevr4;		/* Timer 4 event register */
628c2ecf20Sopenharmony_ci	__be16	gtpsr1;		/* Timer 1 prescale register */
638c2ecf20Sopenharmony_ci	__be16	gtpsr2;		/* Timer 2 prescale register */
648c2ecf20Sopenharmony_ci	__be16	gtpsr3;		/* Timer 3 prescale register */
658c2ecf20Sopenharmony_ci	__be16	gtpsr4;		/* Timer 4 prescale register */
668c2ecf20Sopenharmony_ci	u8 res2[0x40];
678c2ecf20Sopenharmony_ci} __attribute__ ((packed));
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct gtm {
708c2ecf20Sopenharmony_ci	unsigned int clock;
718c2ecf20Sopenharmony_ci	struct gtm_timers_regs __iomem *regs;
728c2ecf20Sopenharmony_ci	struct gtm_timer timers[4];
738c2ecf20Sopenharmony_ci	spinlock_t lock;
748c2ecf20Sopenharmony_ci	struct list_head list_node;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic LIST_HEAD(gtms);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/**
808c2ecf20Sopenharmony_ci * gtm_get_timer - request GTM timer to use it with the rest of GTM API
818c2ecf20Sopenharmony_ci * Context:	non-IRQ
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * This function reserves GTM timer for later use. It returns gtm_timer
848c2ecf20Sopenharmony_ci * structure to use with the rest of GTM API, you should use timer->irq
858c2ecf20Sopenharmony_ci * to manage timer interrupt.
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistruct gtm_timer *gtm_get_timer16(void)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct gtm *gtm;
908c2ecf20Sopenharmony_ci	int i;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	list_for_each_entry(gtm, &gtms, list_node) {
938c2ecf20Sopenharmony_ci		spin_lock_irq(&gtm->lock);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) {
968c2ecf20Sopenharmony_ci			if (!gtm->timers[i].requested) {
978c2ecf20Sopenharmony_ci				gtm->timers[i].requested = true;
988c2ecf20Sopenharmony_ci				spin_unlock_irq(&gtm->lock);
998c2ecf20Sopenharmony_ci				return &gtm->timers[i];
1008c2ecf20Sopenharmony_ci			}
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		spin_unlock_irq(&gtm->lock);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (!list_empty(&gtms))
1078c2ecf20Sopenharmony_ci		return ERR_PTR(-EBUSY);
1088c2ecf20Sopenharmony_ci	return ERR_PTR(-ENODEV);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_get_timer16);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/**
1138c2ecf20Sopenharmony_ci * gtm_get_specific_timer - request specific GTM timer
1148c2ecf20Sopenharmony_ci * @gtm:	specific GTM, pass here GTM's device_node->data
1158c2ecf20Sopenharmony_ci * @timer:	specific timer number, Timer1 is 0.
1168c2ecf20Sopenharmony_ci * Context:	non-IRQ
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci * This function reserves GTM timer for later use. It returns gtm_timer
1198c2ecf20Sopenharmony_ci * structure to use with the rest of GTM API, you should use timer->irq
1208c2ecf20Sopenharmony_ci * to manage timer interrupt.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_cistruct gtm_timer *gtm_get_specific_timer16(struct gtm *gtm,
1238c2ecf20Sopenharmony_ci					   unsigned int timer)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct gtm_timer *ret = ERR_PTR(-EBUSY);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (timer > 3)
1288c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	spin_lock_irq(&gtm->lock);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (gtm->timers[timer].requested)
1338c2ecf20Sopenharmony_ci		goto out;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ret = &gtm->timers[timer];
1368c2ecf20Sopenharmony_ci	ret->requested = true;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ciout:
1398c2ecf20Sopenharmony_ci	spin_unlock_irq(&gtm->lock);
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_get_specific_timer16);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * gtm_put_timer16 - release 16 bits GTM timer
1468c2ecf20Sopenharmony_ci * @tmr:	pointer to the gtm_timer structure obtained from gtm_get_timer
1478c2ecf20Sopenharmony_ci * Context:	any
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * This function releases GTM timer so others may request it.
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_civoid gtm_put_timer16(struct gtm_timer *tmr)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	gtm_stop_timer16(tmr);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	spin_lock_irq(&tmr->gtm->lock);
1568c2ecf20Sopenharmony_ci	tmr->requested = false;
1578c2ecf20Sopenharmony_ci	spin_unlock_irq(&tmr->gtm->lock);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_put_timer16);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/*
1628c2ecf20Sopenharmony_ci * This is back-end for the exported functions, it's used to reset single
1638c2ecf20Sopenharmony_ci * timer in reference mode.
1648c2ecf20Sopenharmony_ci */
1658c2ecf20Sopenharmony_cistatic int gtm_set_ref_timer16(struct gtm_timer *tmr, int frequency,
1668c2ecf20Sopenharmony_ci			       int reference_value, bool free_run)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct gtm *gtm = tmr->gtm;
1698c2ecf20Sopenharmony_ci	int num = tmr - &gtm->timers[0];
1708c2ecf20Sopenharmony_ci	unsigned int prescaler;
1718c2ecf20Sopenharmony_ci	u8 iclk = GTMDR_ICLK_ICLK;
1728c2ecf20Sopenharmony_ci	u8 psr;
1738c2ecf20Sopenharmony_ci	u8 sps;
1748c2ecf20Sopenharmony_ci	unsigned long flags;
1758c2ecf20Sopenharmony_ci	int max_prescaler = 256 * 256 * 16;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* CPM2 doesn't have primary prescaler */
1788c2ecf20Sopenharmony_ci	if (!tmr->gtpsr)
1798c2ecf20Sopenharmony_ci		max_prescaler /= 256;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	prescaler = gtm->clock / frequency;
1828c2ecf20Sopenharmony_ci	/*
1838c2ecf20Sopenharmony_ci	 * We have two 8 bit prescalers -- primary and secondary (psr, sps),
1848c2ecf20Sopenharmony_ci	 * plus "slow go" mode (clk / 16). So, total prescale value is
1858c2ecf20Sopenharmony_ci	 * 16 * (psr + 1) * (sps + 1). Though, for CPM2 GTMs we losing psr.
1868c2ecf20Sopenharmony_ci	 */
1878c2ecf20Sopenharmony_ci	if (prescaler > max_prescaler)
1888c2ecf20Sopenharmony_ci		return -EINVAL;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (prescaler > max_prescaler / 16) {
1918c2ecf20Sopenharmony_ci		iclk = GTMDR_ICLK_SLGO;
1928c2ecf20Sopenharmony_ci		prescaler /= 16;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (prescaler <= 256) {
1968c2ecf20Sopenharmony_ci		psr = 0;
1978c2ecf20Sopenharmony_ci		sps = prescaler - 1;
1988c2ecf20Sopenharmony_ci	} else {
1998c2ecf20Sopenharmony_ci		psr = 256 - 1;
2008c2ecf20Sopenharmony_ci		sps = prescaler / 256 - 1;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gtm->lock, flags);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * Properly reset timers: stop, reset, set up prescalers, reference
2078c2ecf20Sopenharmony_ci	 * value and clear event register.
2088c2ecf20Sopenharmony_ci	 */
2098c2ecf20Sopenharmony_ci	clrsetbits_8(tmr->gtcfr, ~(GTCFR_STP(num) | GTCFR_RST(num)),
2108c2ecf20Sopenharmony_ci				 GTCFR_STP(num) | GTCFR_RST(num));
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	setbits8(tmr->gtcfr, GTCFR_STP(num));
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (tmr->gtpsr)
2158c2ecf20Sopenharmony_ci		out_be16(tmr->gtpsr, psr);
2168c2ecf20Sopenharmony_ci	clrsetbits_be16(tmr->gtmdr, 0xFFFF, iclk | GTMDR_SPS(sps) |
2178c2ecf20Sopenharmony_ci			GTMDR_ORI | (free_run ? GTMDR_FRR : 0));
2188c2ecf20Sopenharmony_ci	out_be16(tmr->gtcnr, 0);
2198c2ecf20Sopenharmony_ci	out_be16(tmr->gtrfr, reference_value);
2208c2ecf20Sopenharmony_ci	out_be16(tmr->gtevr, 0xFFFF);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* Let it be. */
2238c2ecf20Sopenharmony_ci	clrbits8(tmr->gtcfr, GTCFR_STP(num));
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gtm->lock, flags);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/**
2318c2ecf20Sopenharmony_ci * gtm_set_timer16 - (re)set 16 bit timer with arbitrary precision
2328c2ecf20Sopenharmony_ci * @tmr:	pointer to the gtm_timer structure obtained from gtm_get_timer
2338c2ecf20Sopenharmony_ci * @usec:	timer interval in microseconds
2348c2ecf20Sopenharmony_ci * @reload:	if set, the timer will reset upon expiry rather than
2358c2ecf20Sopenharmony_ci *         	continue running free.
2368c2ecf20Sopenharmony_ci * Context:	any
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * This function (re)sets the GTM timer so that it counts up to the requested
2398c2ecf20Sopenharmony_ci * interval value, and fires the interrupt when the value is reached. This
2408c2ecf20Sopenharmony_ci * function will reduce the precision of the timer as needed in order for the
2418c2ecf20Sopenharmony_ci * requested timeout to fit in a 16-bit register.
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_ciint gtm_set_timer16(struct gtm_timer *tmr, unsigned long usec, bool reload)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	/* quite obvious, frequency which is enough for µSec precision */
2468c2ecf20Sopenharmony_ci	int freq = 1000000;
2478c2ecf20Sopenharmony_ci	unsigned int bit;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	bit = fls_long(usec);
2508c2ecf20Sopenharmony_ci	if (bit > 15) {
2518c2ecf20Sopenharmony_ci		freq >>= bit - 15;
2528c2ecf20Sopenharmony_ci		usec >>= bit - 15;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (!freq)
2568c2ecf20Sopenharmony_ci		return -EINVAL;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return gtm_set_ref_timer16(tmr, freq, usec, reload);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_set_timer16);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/**
2638c2ecf20Sopenharmony_ci * gtm_set_exact_utimer16 - (re)set 16 bits timer
2648c2ecf20Sopenharmony_ci * @tmr:	pointer to the gtm_timer structure obtained from gtm_get_timer
2658c2ecf20Sopenharmony_ci * @usec:	timer interval in microseconds
2668c2ecf20Sopenharmony_ci * @reload:	if set, the timer will reset upon expiry rather than
2678c2ecf20Sopenharmony_ci *         	continue running free.
2688c2ecf20Sopenharmony_ci * Context:	any
2698c2ecf20Sopenharmony_ci *
2708c2ecf20Sopenharmony_ci * This function (re)sets GTM timer so that it counts up to the requested
2718c2ecf20Sopenharmony_ci * interval value, and fires the interrupt when the value is reached. If reload
2728c2ecf20Sopenharmony_ci * flag was set, timer will also reset itself upon reference value, otherwise
2738c2ecf20Sopenharmony_ci * it continues to increment.
2748c2ecf20Sopenharmony_ci *
2758c2ecf20Sopenharmony_ci * The _exact_ bit in the function name states that this function will not
2768c2ecf20Sopenharmony_ci * crop precision of the "usec" argument, thus usec is limited to 16 bits
2778c2ecf20Sopenharmony_ci * (single timer width).
2788c2ecf20Sopenharmony_ci */
2798c2ecf20Sopenharmony_ciint gtm_set_exact_timer16(struct gtm_timer *tmr, u16 usec, bool reload)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	/* quite obvious, frequency which is enough for µSec precision */
2828c2ecf20Sopenharmony_ci	const int freq = 1000000;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/*
2858c2ecf20Sopenharmony_ci	 * We can lower the frequency (and probably power consumption) by
2868c2ecf20Sopenharmony_ci	 * dividing both frequency and usec by 2 until there is no remainder.
2878c2ecf20Sopenharmony_ci	 * But we won't bother with this unless savings are measured, so just
2888c2ecf20Sopenharmony_ci	 * run the timer as is.
2898c2ecf20Sopenharmony_ci	 */
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return gtm_set_ref_timer16(tmr, freq, usec, reload);
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_set_exact_timer16);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci/**
2968c2ecf20Sopenharmony_ci * gtm_stop_timer16 - stop single timer
2978c2ecf20Sopenharmony_ci * @tmr:	pointer to the gtm_timer structure obtained from gtm_get_timer
2988c2ecf20Sopenharmony_ci * Context:	any
2998c2ecf20Sopenharmony_ci *
3008c2ecf20Sopenharmony_ci * This function simply stops the GTM timer.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_civoid gtm_stop_timer16(struct gtm_timer *tmr)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct gtm *gtm = tmr->gtm;
3058c2ecf20Sopenharmony_ci	int num = tmr - &gtm->timers[0];
3068c2ecf20Sopenharmony_ci	unsigned long flags;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gtm->lock, flags);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	setbits8(tmr->gtcfr, GTCFR_STP(num));
3118c2ecf20Sopenharmony_ci	out_be16(tmr->gtevr, 0xFFFF);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gtm->lock, flags);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_stop_timer16);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/**
3188c2ecf20Sopenharmony_ci * gtm_ack_timer16 - acknowledge timer event (free-run timers only)
3198c2ecf20Sopenharmony_ci * @tmr:	pointer to the gtm_timer structure obtained from gtm_get_timer
3208c2ecf20Sopenharmony_ci * @events:	events mask to ack
3218c2ecf20Sopenharmony_ci * Context:	any
3228c2ecf20Sopenharmony_ci *
3238c2ecf20Sopenharmony_ci * Thus function used to acknowledge timer interrupt event, use it inside the
3248c2ecf20Sopenharmony_ci * interrupt handler.
3258c2ecf20Sopenharmony_ci */
3268c2ecf20Sopenharmony_civoid gtm_ack_timer16(struct gtm_timer *tmr, u16 events)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	out_be16(tmr->gtevr, events);
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(gtm_ack_timer16);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic void __init gtm_set_shortcuts(struct device_node *np,
3338c2ecf20Sopenharmony_ci				     struct gtm_timer *timers,
3348c2ecf20Sopenharmony_ci				     struct gtm_timers_regs __iomem *regs)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	/*
3378c2ecf20Sopenharmony_ci	 * Yeah, I don't like this either, but timers' registers a bit messed,
3388c2ecf20Sopenharmony_ci	 * so we have to provide shortcuts to write timer independent code.
3398c2ecf20Sopenharmony_ci	 * Alternative option is to create gt*() accessors, but that will be
3408c2ecf20Sopenharmony_ci	 * even uglier and cryptic.
3418c2ecf20Sopenharmony_ci	 */
3428c2ecf20Sopenharmony_ci	timers[0].gtcfr = &regs->gtcfr1;
3438c2ecf20Sopenharmony_ci	timers[0].gtmdr = &regs->gtmdr1;
3448c2ecf20Sopenharmony_ci	timers[0].gtcnr = &regs->gtcnr1;
3458c2ecf20Sopenharmony_ci	timers[0].gtrfr = &regs->gtrfr1;
3468c2ecf20Sopenharmony_ci	timers[0].gtevr = &regs->gtevr1;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	timers[1].gtcfr = &regs->gtcfr1;
3498c2ecf20Sopenharmony_ci	timers[1].gtmdr = &regs->gtmdr2;
3508c2ecf20Sopenharmony_ci	timers[1].gtcnr = &regs->gtcnr2;
3518c2ecf20Sopenharmony_ci	timers[1].gtrfr = &regs->gtrfr2;
3528c2ecf20Sopenharmony_ci	timers[1].gtevr = &regs->gtevr2;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	timers[2].gtcfr = &regs->gtcfr2;
3558c2ecf20Sopenharmony_ci	timers[2].gtmdr = &regs->gtmdr3;
3568c2ecf20Sopenharmony_ci	timers[2].gtcnr = &regs->gtcnr3;
3578c2ecf20Sopenharmony_ci	timers[2].gtrfr = &regs->gtrfr3;
3588c2ecf20Sopenharmony_ci	timers[2].gtevr = &regs->gtevr3;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	timers[3].gtcfr = &regs->gtcfr2;
3618c2ecf20Sopenharmony_ci	timers[3].gtmdr = &regs->gtmdr4;
3628c2ecf20Sopenharmony_ci	timers[3].gtcnr = &regs->gtcnr4;
3638c2ecf20Sopenharmony_ci	timers[3].gtrfr = &regs->gtrfr4;
3648c2ecf20Sopenharmony_ci	timers[3].gtevr = &regs->gtevr4;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/* CPM2 doesn't have primary prescaler */
3678c2ecf20Sopenharmony_ci	if (!of_device_is_compatible(np, "fsl,cpm2-gtm")) {
3688c2ecf20Sopenharmony_ci		timers[0].gtpsr = &regs->gtpsr1;
3698c2ecf20Sopenharmony_ci		timers[1].gtpsr = &regs->gtpsr2;
3708c2ecf20Sopenharmony_ci		timers[2].gtpsr = &regs->gtpsr3;
3718c2ecf20Sopenharmony_ci		timers[3].gtpsr = &regs->gtpsr4;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int __init fsl_gtm_init(void)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct device_node *np;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	for_each_compatible_node(np, NULL, "fsl,gtm") {
3808c2ecf20Sopenharmony_ci		int i;
3818c2ecf20Sopenharmony_ci		struct gtm *gtm;
3828c2ecf20Sopenharmony_ci		const u32 *clock;
3838c2ecf20Sopenharmony_ci		int size;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		gtm = kzalloc(sizeof(*gtm), GFP_KERNEL);
3868c2ecf20Sopenharmony_ci		if (!gtm) {
3878c2ecf20Sopenharmony_ci			pr_err("%pOF: unable to allocate memory\n",
3888c2ecf20Sopenharmony_ci				np);
3898c2ecf20Sopenharmony_ci			continue;
3908c2ecf20Sopenharmony_ci		}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		spin_lock_init(&gtm->lock);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		clock = of_get_property(np, "clock-frequency", &size);
3958c2ecf20Sopenharmony_ci		if (!clock || size != sizeof(*clock)) {
3968c2ecf20Sopenharmony_ci			pr_err("%pOF: no clock-frequency\n", np);
3978c2ecf20Sopenharmony_ci			goto err;
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci		gtm->clock = *clock;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(gtm->timers); i++) {
4028c2ecf20Sopenharmony_ci			unsigned int irq;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci			irq = irq_of_parse_and_map(np, i);
4058c2ecf20Sopenharmony_ci			if (!irq) {
4068c2ecf20Sopenharmony_ci				pr_err("%pOF: not enough interrupts specified\n",
4078c2ecf20Sopenharmony_ci				       np);
4088c2ecf20Sopenharmony_ci				goto err;
4098c2ecf20Sopenharmony_ci			}
4108c2ecf20Sopenharmony_ci			gtm->timers[i].irq = irq;
4118c2ecf20Sopenharmony_ci			gtm->timers[i].gtm = gtm;
4128c2ecf20Sopenharmony_ci		}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		gtm->regs = of_iomap(np, 0);
4158c2ecf20Sopenharmony_ci		if (!gtm->regs) {
4168c2ecf20Sopenharmony_ci			pr_err("%pOF: unable to iomap registers\n",
4178c2ecf20Sopenharmony_ci			       np);
4188c2ecf20Sopenharmony_ci			goto err;
4198c2ecf20Sopenharmony_ci		}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		gtm_set_shortcuts(np, gtm->timers, gtm->regs);
4228c2ecf20Sopenharmony_ci		list_add(&gtm->list_node, &gtms);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		/* We don't want to lose the node and its ->data */
4258c2ecf20Sopenharmony_ci		np->data = gtm;
4268c2ecf20Sopenharmony_ci		of_node_get(np);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		continue;
4298c2ecf20Sopenharmony_cierr:
4308c2ecf20Sopenharmony_ci		kfree(gtm);
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ciarch_initcall(fsl_gtm_init);
435