162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SuperH Timer Support - CMT
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2008 Magnus Damm
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/clockchips.h>
1062306a36Sopenharmony_ci#include <linux/clocksource.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/iopoll.h>
1762306a36Sopenharmony_ci#include <linux/ioport.h>
1862306a36Sopenharmony_ci#include <linux/irq.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/pm_domain.h>
2362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2462306a36Sopenharmony_ci#include <linux/sh_timer.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci#include <linux/spinlock.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#ifdef CONFIG_SUPERH
2962306a36Sopenharmony_ci#include <asm/platform_early.h>
3062306a36Sopenharmony_ci#endif
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct sh_cmt_device;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * The CMT comes in 5 different identified flavours, depending not only on the
3662306a36Sopenharmony_ci * SoC but also on the particular instance. The following table lists the main
3762306a36Sopenharmony_ci * characteristics of those flavours.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci *			16B	32B	32B-F	48B	R-Car Gen2
4062306a36Sopenharmony_ci * -----------------------------------------------------------------------------
4162306a36Sopenharmony_ci * Channels		2	1/4	1	6	2/8
4262306a36Sopenharmony_ci * Control Width	16	16	16	16	32
4362306a36Sopenharmony_ci * Counter Width	16	32	32	32/48	32/48
4462306a36Sopenharmony_ci * Shared Start/Stop	Y	Y	Y	Y	N
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * The r8a73a4 / R-Car Gen2 version has a per-channel start/stop register
4762306a36Sopenharmony_ci * located in the channel registers block. All other versions have a shared
4862306a36Sopenharmony_ci * start/stop register located in the global space.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * Channels are indexed from 0 to N-1 in the documentation. The channel index
5162306a36Sopenharmony_ci * infers the start/stop bit position in the control register and the channel
5262306a36Sopenharmony_ci * registers block address. Some CMT instances have a subset of channels
5362306a36Sopenharmony_ci * available, in which case the index in the documentation doesn't match the
5462306a36Sopenharmony_ci * "real" index as implemented in hardware. This is for instance the case with
5562306a36Sopenharmony_ci * CMT0 on r8a7740, which is a 32-bit variant with a single channel numbered 0
5662306a36Sopenharmony_ci * in the documentation but using start/stop bit 5 and having its registers
5762306a36Sopenharmony_ci * block at 0x60.
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Similarly CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit
6062306a36Sopenharmony_ci * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum sh_cmt_model {
6462306a36Sopenharmony_ci	SH_CMT_16BIT,
6562306a36Sopenharmony_ci	SH_CMT_32BIT,
6662306a36Sopenharmony_ci	SH_CMT_48BIT,
6762306a36Sopenharmony_ci	SH_CMT0_RCAR_GEN2,
6862306a36Sopenharmony_ci	SH_CMT1_RCAR_GEN2,
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct sh_cmt_info {
7262306a36Sopenharmony_ci	enum sh_cmt_model model;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	unsigned int channels_mask;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	unsigned long width; /* 16 or 32 bit version of hardware block */
7762306a36Sopenharmony_ci	u32 overflow_bit;
7862306a36Sopenharmony_ci	u32 clear_bits;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* callbacks for CMSTR and CMCSR access */
8162306a36Sopenharmony_ci	u32 (*read_control)(void __iomem *base, unsigned long offs);
8262306a36Sopenharmony_ci	void (*write_control)(void __iomem *base, unsigned long offs,
8362306a36Sopenharmony_ci			      u32 value);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/* callbacks for CMCNT and CMCOR access */
8662306a36Sopenharmony_ci	u32 (*read_count)(void __iomem *base, unsigned long offs);
8762306a36Sopenharmony_ci	void (*write_count)(void __iomem *base, unsigned long offs, u32 value);
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct sh_cmt_channel {
9162306a36Sopenharmony_ci	struct sh_cmt_device *cmt;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	unsigned int index;	/* Index in the documentation */
9462306a36Sopenharmony_ci	unsigned int hwidx;	/* Real hardware index */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	void __iomem *iostart;
9762306a36Sopenharmony_ci	void __iomem *ioctrl;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	unsigned int timer_bit;
10062306a36Sopenharmony_ci	unsigned long flags;
10162306a36Sopenharmony_ci	u32 match_value;
10262306a36Sopenharmony_ci	u32 next_match_value;
10362306a36Sopenharmony_ci	u32 max_match_value;
10462306a36Sopenharmony_ci	raw_spinlock_t lock;
10562306a36Sopenharmony_ci	struct clock_event_device ced;
10662306a36Sopenharmony_ci	struct clocksource cs;
10762306a36Sopenharmony_ci	u64 total_cycles;
10862306a36Sopenharmony_ci	bool cs_enabled;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct sh_cmt_device {
11262306a36Sopenharmony_ci	struct platform_device *pdev;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	const struct sh_cmt_info *info;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	void __iomem *mapbase;
11762306a36Sopenharmony_ci	struct clk *clk;
11862306a36Sopenharmony_ci	unsigned long rate;
11962306a36Sopenharmony_ci	unsigned int reg_delay;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	raw_spinlock_t lock; /* Protect the shared start/stop register */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	struct sh_cmt_channel *channels;
12462306a36Sopenharmony_ci	unsigned int num_channels;
12562306a36Sopenharmony_ci	unsigned int hw_channels;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	bool has_clockevent;
12862306a36Sopenharmony_ci	bool has_clocksource;
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CMF		(1 << 7)
13262306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CMIE		(1 << 6)
13362306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CKS8		(0 << 0)
13462306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CKS32		(1 << 0)
13562306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CKS128		(2 << 0)
13662306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CKS512		(3 << 0)
13762306a36Sopenharmony_ci#define SH_CMT16_CMCSR_CKS_MASK		(3 << 0)
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMF		(1 << 15)
14062306a36Sopenharmony_ci#define SH_CMT32_CMCSR_OVF		(1 << 14)
14162306a36Sopenharmony_ci#define SH_CMT32_CMCSR_WRFLG		(1 << 13)
14262306a36Sopenharmony_ci#define SH_CMT32_CMCSR_STTF		(1 << 12)
14362306a36Sopenharmony_ci#define SH_CMT32_CMCSR_STPF		(1 << 11)
14462306a36Sopenharmony_ci#define SH_CMT32_CMCSR_SSIE		(1 << 10)
14562306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMS		(1 << 9)
14662306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMM		(1 << 8)
14762306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMTOUT_IE	(1 << 7)
14862306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMR_NONE		(0 << 4)
14962306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMR_DMA		(1 << 4)
15062306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMR_IRQ		(2 << 4)
15162306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CMR_MASK		(3 << 4)
15262306a36Sopenharmony_ci#define SH_CMT32_CMCSR_DBGIVD		(1 << 3)
15362306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CKS_RCLK8	(4 << 0)
15462306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CKS_RCLK32	(5 << 0)
15562306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CKS_RCLK128	(6 << 0)
15662306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CKS_RCLK1	(7 << 0)
15762306a36Sopenharmony_ci#define SH_CMT32_CMCSR_CKS_MASK		(7 << 0)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic u32 sh_cmt_read16(void __iomem *base, unsigned long offs)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	return ioread16(base + (offs << 1));
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic u32 sh_cmt_read32(void __iomem *base, unsigned long offs)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	return ioread32(base + (offs << 2));
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void sh_cmt_write16(void __iomem *base, unsigned long offs, u32 value)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	iowrite16(value, base + (offs << 1));
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void sh_cmt_write32(void __iomem *base, unsigned long offs, u32 value)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	iowrite32(value, base + (offs << 2));
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic const struct sh_cmt_info sh_cmt_info[] = {
18062306a36Sopenharmony_ci	[SH_CMT_16BIT] = {
18162306a36Sopenharmony_ci		.model = SH_CMT_16BIT,
18262306a36Sopenharmony_ci		.width = 16,
18362306a36Sopenharmony_ci		.overflow_bit = SH_CMT16_CMCSR_CMF,
18462306a36Sopenharmony_ci		.clear_bits = ~SH_CMT16_CMCSR_CMF,
18562306a36Sopenharmony_ci		.read_control = sh_cmt_read16,
18662306a36Sopenharmony_ci		.write_control = sh_cmt_write16,
18762306a36Sopenharmony_ci		.read_count = sh_cmt_read16,
18862306a36Sopenharmony_ci		.write_count = sh_cmt_write16,
18962306a36Sopenharmony_ci	},
19062306a36Sopenharmony_ci	[SH_CMT_32BIT] = {
19162306a36Sopenharmony_ci		.model = SH_CMT_32BIT,
19262306a36Sopenharmony_ci		.width = 32,
19362306a36Sopenharmony_ci		.overflow_bit = SH_CMT32_CMCSR_CMF,
19462306a36Sopenharmony_ci		.clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
19562306a36Sopenharmony_ci		.read_control = sh_cmt_read16,
19662306a36Sopenharmony_ci		.write_control = sh_cmt_write16,
19762306a36Sopenharmony_ci		.read_count = sh_cmt_read32,
19862306a36Sopenharmony_ci		.write_count = sh_cmt_write32,
19962306a36Sopenharmony_ci	},
20062306a36Sopenharmony_ci	[SH_CMT_48BIT] = {
20162306a36Sopenharmony_ci		.model = SH_CMT_48BIT,
20262306a36Sopenharmony_ci		.channels_mask = 0x3f,
20362306a36Sopenharmony_ci		.width = 32,
20462306a36Sopenharmony_ci		.overflow_bit = SH_CMT32_CMCSR_CMF,
20562306a36Sopenharmony_ci		.clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
20662306a36Sopenharmony_ci		.read_control = sh_cmt_read32,
20762306a36Sopenharmony_ci		.write_control = sh_cmt_write32,
20862306a36Sopenharmony_ci		.read_count = sh_cmt_read32,
20962306a36Sopenharmony_ci		.write_count = sh_cmt_write32,
21062306a36Sopenharmony_ci	},
21162306a36Sopenharmony_ci	[SH_CMT0_RCAR_GEN2] = {
21262306a36Sopenharmony_ci		.model = SH_CMT0_RCAR_GEN2,
21362306a36Sopenharmony_ci		.channels_mask = 0x60,
21462306a36Sopenharmony_ci		.width = 32,
21562306a36Sopenharmony_ci		.overflow_bit = SH_CMT32_CMCSR_CMF,
21662306a36Sopenharmony_ci		.clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
21762306a36Sopenharmony_ci		.read_control = sh_cmt_read32,
21862306a36Sopenharmony_ci		.write_control = sh_cmt_write32,
21962306a36Sopenharmony_ci		.read_count = sh_cmt_read32,
22062306a36Sopenharmony_ci		.write_count = sh_cmt_write32,
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci	[SH_CMT1_RCAR_GEN2] = {
22362306a36Sopenharmony_ci		.model = SH_CMT1_RCAR_GEN2,
22462306a36Sopenharmony_ci		.channels_mask = 0xff,
22562306a36Sopenharmony_ci		.width = 32,
22662306a36Sopenharmony_ci		.overflow_bit = SH_CMT32_CMCSR_CMF,
22762306a36Sopenharmony_ci		.clear_bits = ~(SH_CMT32_CMCSR_CMF | SH_CMT32_CMCSR_OVF),
22862306a36Sopenharmony_ci		.read_control = sh_cmt_read32,
22962306a36Sopenharmony_ci		.write_control = sh_cmt_write32,
23062306a36Sopenharmony_ci		.read_count = sh_cmt_read32,
23162306a36Sopenharmony_ci		.write_count = sh_cmt_write32,
23262306a36Sopenharmony_ci	},
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define CMCSR 0 /* channel register */
23662306a36Sopenharmony_ci#define CMCNT 1 /* channel register */
23762306a36Sopenharmony_ci#define CMCOR 2 /* channel register */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#define CMCLKE	0x1000	/* CLK Enable Register (R-Car Gen2) */
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	if (ch->iostart)
24462306a36Sopenharmony_ci		return ch->cmt->info->read_control(ch->iostart, 0);
24562306a36Sopenharmony_ci	else
24662306a36Sopenharmony_ci		return ch->cmt->info->read_control(ch->cmt->mapbase, 0);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, u32 value)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	u32 old_value = sh_cmt_read_cmstr(ch);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (value != old_value) {
25462306a36Sopenharmony_ci		if (ch->iostart) {
25562306a36Sopenharmony_ci			ch->cmt->info->write_control(ch->iostart, 0, value);
25662306a36Sopenharmony_ci			udelay(ch->cmt->reg_delay);
25762306a36Sopenharmony_ci		} else {
25862306a36Sopenharmony_ci			ch->cmt->info->write_control(ch->cmt->mapbase, 0, value);
25962306a36Sopenharmony_ci			udelay(ch->cmt->reg_delay);
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic inline u32 sh_cmt_read_cmcsr(struct sh_cmt_channel *ch)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	return ch->cmt->info->read_control(ch->ioctrl, CMCSR);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, u32 value)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	u32 old_value = sh_cmt_read_cmcsr(ch);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (value != old_value) {
27462306a36Sopenharmony_ci		ch->cmt->info->write_control(ch->ioctrl, CMCSR, value);
27562306a36Sopenharmony_ci		udelay(ch->cmt->reg_delay);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic inline u32 sh_cmt_read_cmcnt(struct sh_cmt_channel *ch)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	return ch->cmt->info->read_count(ch->ioctrl, CMCNT);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic inline int sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, u32 value)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	/* Tests showed that we need to wait 3 clocks here */
28762306a36Sopenharmony_ci	unsigned int cmcnt_delay = DIV_ROUND_UP(3 * ch->cmt->reg_delay, 2);
28862306a36Sopenharmony_ci	u32 reg;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (ch->cmt->info->model > SH_CMT_16BIT) {
29162306a36Sopenharmony_ci		int ret = read_poll_timeout_atomic(sh_cmt_read_cmcsr, reg,
29262306a36Sopenharmony_ci						   !(reg & SH_CMT32_CMCSR_WRFLG),
29362306a36Sopenharmony_ci						   1, cmcnt_delay, false, ch);
29462306a36Sopenharmony_ci		if (ret < 0)
29562306a36Sopenharmony_ci			return ret;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ch->cmt->info->write_count(ch->ioctrl, CMCNT, value);
29962306a36Sopenharmony_ci	udelay(cmcnt_delay);
30062306a36Sopenharmony_ci	return 0;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, u32 value)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	u32 old_value = ch->cmt->info->read_count(ch->ioctrl, CMCOR);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (value != old_value) {
30862306a36Sopenharmony_ci		ch->cmt->info->write_count(ch->ioctrl, CMCOR, value);
30962306a36Sopenharmony_ci		udelay(ch->cmt->reg_delay);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic u32 sh_cmt_get_counter(struct sh_cmt_channel *ch, u32 *has_wrapped)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	u32 v1, v2, v3;
31662306a36Sopenharmony_ci	u32 o1, o2;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Make sure the timer value is stable. Stolen from acpi_pm.c */
32162306a36Sopenharmony_ci	do {
32262306a36Sopenharmony_ci		o2 = o1;
32362306a36Sopenharmony_ci		v1 = sh_cmt_read_cmcnt(ch);
32462306a36Sopenharmony_ci		v2 = sh_cmt_read_cmcnt(ch);
32562306a36Sopenharmony_ci		v3 = sh_cmt_read_cmcnt(ch);
32662306a36Sopenharmony_ci		o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit;
32762306a36Sopenharmony_ci	} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
32862306a36Sopenharmony_ci			  || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	*has_wrapped = o1;
33162306a36Sopenharmony_ci	return v2;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	unsigned long flags;
33762306a36Sopenharmony_ci	u32 value;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* start stop register shared by multiple timer channels */
34062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&ch->cmt->lock, flags);
34162306a36Sopenharmony_ci	value = sh_cmt_read_cmstr(ch);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (start)
34462306a36Sopenharmony_ci		value |= 1 << ch->timer_bit;
34562306a36Sopenharmony_ci	else
34662306a36Sopenharmony_ci		value &= ~(1 << ch->timer_bit);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	sh_cmt_write_cmstr(ch, value);
34962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&ch->cmt->lock, flags);
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int sh_cmt_enable(struct sh_cmt_channel *ch)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	int ret;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	dev_pm_syscore_device(&ch->cmt->pdev->dev, true);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* enable clock */
35962306a36Sopenharmony_ci	ret = clk_enable(ch->cmt->clk);
36062306a36Sopenharmony_ci	if (ret) {
36162306a36Sopenharmony_ci		dev_err(&ch->cmt->pdev->dev, "ch%u: cannot enable clock\n",
36262306a36Sopenharmony_ci			ch->index);
36362306a36Sopenharmony_ci		goto err0;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* make sure channel is disabled */
36762306a36Sopenharmony_ci	sh_cmt_start_stop_ch(ch, 0);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* configure channel, periodic mode and maximum timeout */
37062306a36Sopenharmony_ci	if (ch->cmt->info->width == 16) {
37162306a36Sopenharmony_ci		sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
37262306a36Sopenharmony_ci				   SH_CMT16_CMCSR_CKS512);
37362306a36Sopenharmony_ci	} else {
37462306a36Sopenharmony_ci		u32 cmtout = ch->cmt->info->model <= SH_CMT_48BIT ?
37562306a36Sopenharmony_ci			      SH_CMT32_CMCSR_CMTOUT_IE : 0;
37662306a36Sopenharmony_ci		sh_cmt_write_cmcsr(ch, cmtout | SH_CMT32_CMCSR_CMM |
37762306a36Sopenharmony_ci				   SH_CMT32_CMCSR_CMR_IRQ |
37862306a36Sopenharmony_ci				   SH_CMT32_CMCSR_CKS_RCLK8);
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	sh_cmt_write_cmcor(ch, 0xffffffff);
38262306a36Sopenharmony_ci	ret = sh_cmt_write_cmcnt(ch, 0);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (ret || sh_cmt_read_cmcnt(ch)) {
38562306a36Sopenharmony_ci		dev_err(&ch->cmt->pdev->dev, "ch%u: cannot clear CMCNT\n",
38662306a36Sopenharmony_ci			ch->index);
38762306a36Sopenharmony_ci		ret = -ETIMEDOUT;
38862306a36Sopenharmony_ci		goto err1;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* enable channel */
39262306a36Sopenharmony_ci	sh_cmt_start_stop_ch(ch, 1);
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci err1:
39562306a36Sopenharmony_ci	/* stop clock */
39662306a36Sopenharmony_ci	clk_disable(ch->cmt->clk);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci err0:
39962306a36Sopenharmony_ci	return ret;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void sh_cmt_disable(struct sh_cmt_channel *ch)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	/* disable channel */
40562306a36Sopenharmony_ci	sh_cmt_start_stop_ch(ch, 0);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* disable interrupts in CMT block */
40862306a36Sopenharmony_ci	sh_cmt_write_cmcsr(ch, 0);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* stop clock */
41162306a36Sopenharmony_ci	clk_disable(ch->cmt->clk);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	dev_pm_syscore_device(&ch->cmt->pdev->dev, false);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/* private flags */
41762306a36Sopenharmony_ci#define FLAG_CLOCKEVENT (1 << 0)
41862306a36Sopenharmony_ci#define FLAG_CLOCKSOURCE (1 << 1)
41962306a36Sopenharmony_ci#define FLAG_REPROGRAM (1 << 2)
42062306a36Sopenharmony_ci#define FLAG_SKIPEVENT (1 << 3)
42162306a36Sopenharmony_ci#define FLAG_IRQCONTEXT (1 << 4)
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void sh_cmt_clock_event_program_verify(struct sh_cmt_channel *ch,
42462306a36Sopenharmony_ci					      int absolute)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	u32 value = ch->next_match_value;
42762306a36Sopenharmony_ci	u32 new_match;
42862306a36Sopenharmony_ci	u32 delay = 0;
42962306a36Sopenharmony_ci	u32 now = 0;
43062306a36Sopenharmony_ci	u32 has_wrapped;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	now = sh_cmt_get_counter(ch, &has_wrapped);
43362306a36Sopenharmony_ci	ch->flags |= FLAG_REPROGRAM; /* force reprogram */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (has_wrapped) {
43662306a36Sopenharmony_ci		/* we're competing with the interrupt handler.
43762306a36Sopenharmony_ci		 *  -> let the interrupt handler reprogram the timer.
43862306a36Sopenharmony_ci		 *  -> interrupt number two handles the event.
43962306a36Sopenharmony_ci		 */
44062306a36Sopenharmony_ci		ch->flags |= FLAG_SKIPEVENT;
44162306a36Sopenharmony_ci		return;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (absolute)
44562306a36Sopenharmony_ci		now = 0;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	do {
44862306a36Sopenharmony_ci		/* reprogram the timer hardware,
44962306a36Sopenharmony_ci		 * but don't save the new match value yet.
45062306a36Sopenharmony_ci		 */
45162306a36Sopenharmony_ci		new_match = now + value + delay;
45262306a36Sopenharmony_ci		if (new_match > ch->max_match_value)
45362306a36Sopenharmony_ci			new_match = ch->max_match_value;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		sh_cmt_write_cmcor(ch, new_match);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		now = sh_cmt_get_counter(ch, &has_wrapped);
45862306a36Sopenharmony_ci		if (has_wrapped && (new_match > ch->match_value)) {
45962306a36Sopenharmony_ci			/* we are changing to a greater match value,
46062306a36Sopenharmony_ci			 * so this wrap must be caused by the counter
46162306a36Sopenharmony_ci			 * matching the old value.
46262306a36Sopenharmony_ci			 * -> first interrupt reprograms the timer.
46362306a36Sopenharmony_ci			 * -> interrupt number two handles the event.
46462306a36Sopenharmony_ci			 */
46562306a36Sopenharmony_ci			ch->flags |= FLAG_SKIPEVENT;
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci		}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		if (has_wrapped) {
47062306a36Sopenharmony_ci			/* we are changing to a smaller match value,
47162306a36Sopenharmony_ci			 * so the wrap must be caused by the counter
47262306a36Sopenharmony_ci			 * matching the new value.
47362306a36Sopenharmony_ci			 * -> save programmed match value.
47462306a36Sopenharmony_ci			 * -> let isr handle the event.
47562306a36Sopenharmony_ci			 */
47662306a36Sopenharmony_ci			ch->match_value = new_match;
47762306a36Sopenharmony_ci			break;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/* be safe: verify hardware settings */
48162306a36Sopenharmony_ci		if (now < new_match) {
48262306a36Sopenharmony_ci			/* timer value is below match value, all good.
48362306a36Sopenharmony_ci			 * this makes sure we won't miss any match events.
48462306a36Sopenharmony_ci			 * -> save programmed match value.
48562306a36Sopenharmony_ci			 * -> let isr handle the event.
48662306a36Sopenharmony_ci			 */
48762306a36Sopenharmony_ci			ch->match_value = new_match;
48862306a36Sopenharmony_ci			break;
48962306a36Sopenharmony_ci		}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		/* the counter has reached a value greater
49262306a36Sopenharmony_ci		 * than our new match value. and since the
49362306a36Sopenharmony_ci		 * has_wrapped flag isn't set we must have
49462306a36Sopenharmony_ci		 * programmed a too close event.
49562306a36Sopenharmony_ci		 * -> increase delay and retry.
49662306a36Sopenharmony_ci		 */
49762306a36Sopenharmony_ci		if (delay)
49862306a36Sopenharmony_ci			delay <<= 1;
49962306a36Sopenharmony_ci		else
50062306a36Sopenharmony_ci			delay = 1;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		if (!delay)
50362306a36Sopenharmony_ci			dev_warn(&ch->cmt->pdev->dev, "ch%u: too long delay\n",
50462306a36Sopenharmony_ci				 ch->index);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	} while (delay);
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic void __sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	if (delta > ch->max_match_value)
51262306a36Sopenharmony_ci		dev_warn(&ch->cmt->pdev->dev, "ch%u: delta out of range\n",
51362306a36Sopenharmony_ci			 ch->index);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	ch->next_match_value = delta;
51662306a36Sopenharmony_ci	sh_cmt_clock_event_program_verify(ch, 0);
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void sh_cmt_set_next(struct sh_cmt_channel *ch, unsigned long delta)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	unsigned long flags;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	raw_spin_lock_irqsave(&ch->lock, flags);
52462306a36Sopenharmony_ci	__sh_cmt_set_next(ch, delta);
52562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&ch->lock, flags);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic irqreturn_t sh_cmt_interrupt(int irq, void *dev_id)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct sh_cmt_channel *ch = dev_id;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* clear flags */
53362306a36Sopenharmony_ci	sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) &
53462306a36Sopenharmony_ci			   ch->cmt->info->clear_bits);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* update clock source counter to begin with if enabled
53762306a36Sopenharmony_ci	 * the wrap flag should be cleared by the timer specific
53862306a36Sopenharmony_ci	 * isr before we end up here.
53962306a36Sopenharmony_ci	 */
54062306a36Sopenharmony_ci	if (ch->flags & FLAG_CLOCKSOURCE)
54162306a36Sopenharmony_ci		ch->total_cycles += ch->match_value + 1;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if (!(ch->flags & FLAG_REPROGRAM))
54462306a36Sopenharmony_ci		ch->next_match_value = ch->max_match_value;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	ch->flags |= FLAG_IRQCONTEXT;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (ch->flags & FLAG_CLOCKEVENT) {
54962306a36Sopenharmony_ci		if (!(ch->flags & FLAG_SKIPEVENT)) {
55062306a36Sopenharmony_ci			if (clockevent_state_oneshot(&ch->ced)) {
55162306a36Sopenharmony_ci				ch->next_match_value = ch->max_match_value;
55262306a36Sopenharmony_ci				ch->flags |= FLAG_REPROGRAM;
55362306a36Sopenharmony_ci			}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci			ch->ced.event_handler(&ch->ced);
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ch->flags &= ~FLAG_SKIPEVENT;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	if (ch->flags & FLAG_REPROGRAM) {
56262306a36Sopenharmony_ci		ch->flags &= ~FLAG_REPROGRAM;
56362306a36Sopenharmony_ci		sh_cmt_clock_event_program_verify(ch, 1);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		if (ch->flags & FLAG_CLOCKEVENT)
56662306a36Sopenharmony_ci			if ((clockevent_state_shutdown(&ch->ced))
56762306a36Sopenharmony_ci			    || (ch->match_value == ch->next_match_value))
56862306a36Sopenharmony_ci				ch->flags &= ~FLAG_REPROGRAM;
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	ch->flags &= ~FLAG_IRQCONTEXT;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return IRQ_HANDLED;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	int ret = 0;
57962306a36Sopenharmony_ci	unsigned long flags;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (flag & FLAG_CLOCKSOURCE)
58262306a36Sopenharmony_ci		pm_runtime_get_sync(&ch->cmt->pdev->dev);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&ch->lock, flags);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
58762306a36Sopenharmony_ci		if (flag & FLAG_CLOCKEVENT)
58862306a36Sopenharmony_ci			pm_runtime_get_sync(&ch->cmt->pdev->dev);
58962306a36Sopenharmony_ci		ret = sh_cmt_enable(ch);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (ret)
59362306a36Sopenharmony_ci		goto out;
59462306a36Sopenharmony_ci	ch->flags |= flag;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* setup timeout if no clockevent */
59762306a36Sopenharmony_ci	if (ch->cmt->num_channels == 1 &&
59862306a36Sopenharmony_ci	    flag == FLAG_CLOCKSOURCE && (!(ch->flags & FLAG_CLOCKEVENT)))
59962306a36Sopenharmony_ci		__sh_cmt_set_next(ch, ch->max_match_value);
60062306a36Sopenharmony_ci out:
60162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&ch->lock, flags);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return ret;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic void sh_cmt_stop(struct sh_cmt_channel *ch, unsigned long flag)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	unsigned long flags;
60962306a36Sopenharmony_ci	unsigned long f;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	raw_spin_lock_irqsave(&ch->lock, flags);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	f = ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE);
61462306a36Sopenharmony_ci	ch->flags &= ~flag;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (f && !(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) {
61762306a36Sopenharmony_ci		sh_cmt_disable(ch);
61862306a36Sopenharmony_ci		if (flag & FLAG_CLOCKEVENT)
61962306a36Sopenharmony_ci			pm_runtime_put(&ch->cmt->pdev->dev);
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* adjust the timeout to maximum if only clocksource left */
62362306a36Sopenharmony_ci	if ((flag == FLAG_CLOCKEVENT) && (ch->flags & FLAG_CLOCKSOURCE))
62462306a36Sopenharmony_ci		__sh_cmt_set_next(ch, ch->max_match_value);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&ch->lock, flags);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (flag & FLAG_CLOCKSOURCE)
62962306a36Sopenharmony_ci		pm_runtime_put(&ch->cmt->pdev->dev);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	return container_of(cs, struct sh_cmt_channel, cs);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic u64 sh_cmt_clocksource_read(struct clocksource *cs)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
64062306a36Sopenharmony_ci	u32 has_wrapped;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (ch->cmt->num_channels == 1) {
64362306a36Sopenharmony_ci		unsigned long flags;
64462306a36Sopenharmony_ci		u64 value;
64562306a36Sopenharmony_ci		u32 raw;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		raw_spin_lock_irqsave(&ch->lock, flags);
64862306a36Sopenharmony_ci		value = ch->total_cycles;
64962306a36Sopenharmony_ci		raw = sh_cmt_get_counter(ch, &has_wrapped);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (unlikely(has_wrapped))
65262306a36Sopenharmony_ci			raw += ch->match_value + 1;
65362306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&ch->lock, flags);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		return value + raw;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return sh_cmt_get_counter(ch, &has_wrapped);
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int sh_cmt_clocksource_enable(struct clocksource *cs)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int ret;
66462306a36Sopenharmony_ci	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	WARN_ON(ch->cs_enabled);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	ch->total_cycles = 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
67162306a36Sopenharmony_ci	if (!ret)
67262306a36Sopenharmony_ci		ch->cs_enabled = true;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return ret;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic void sh_cmt_clocksource_disable(struct clocksource *cs)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	WARN_ON(!ch->cs_enabled);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
68462306a36Sopenharmony_ci	ch->cs_enabled = false;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic void sh_cmt_clocksource_suspend(struct clocksource *cs)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (!ch->cs_enabled)
69262306a36Sopenharmony_ci		return;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	sh_cmt_stop(ch, FLAG_CLOCKSOURCE);
69562306a36Sopenharmony_ci	dev_pm_genpd_suspend(&ch->cmt->pdev->dev);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic void sh_cmt_clocksource_resume(struct clocksource *cs)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (!ch->cs_enabled)
70362306a36Sopenharmony_ci		return;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	dev_pm_genpd_resume(&ch->cmt->pdev->dev);
70662306a36Sopenharmony_ci	sh_cmt_start(ch, FLAG_CLOCKSOURCE);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
71062306a36Sopenharmony_ci				       const char *name)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct clocksource *cs = &ch->cs;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	cs->name = name;
71562306a36Sopenharmony_ci	cs->rating = 125;
71662306a36Sopenharmony_ci	cs->read = sh_cmt_clocksource_read;
71762306a36Sopenharmony_ci	cs->enable = sh_cmt_clocksource_enable;
71862306a36Sopenharmony_ci	cs->disable = sh_cmt_clocksource_disable;
71962306a36Sopenharmony_ci	cs->suspend = sh_cmt_clocksource_suspend;
72062306a36Sopenharmony_ci	cs->resume = sh_cmt_clocksource_resume;
72162306a36Sopenharmony_ci	cs->mask = CLOCKSOURCE_MASK(ch->cmt->info->width);
72262306a36Sopenharmony_ci	cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
72562306a36Sopenharmony_ci		 ch->index);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	clocksource_register_hz(cs, ch->cmt->rate);
72862306a36Sopenharmony_ci	return 0;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	return container_of(ced, struct sh_cmt_channel, ced);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	sh_cmt_start(ch, FLAG_CLOCKEVENT);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (periodic)
74162306a36Sopenharmony_ci		sh_cmt_set_next(ch, ((ch->cmt->rate + HZ/2) / HZ) - 1);
74262306a36Sopenharmony_ci	else
74362306a36Sopenharmony_ci		sh_cmt_set_next(ch, ch->max_match_value);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int sh_cmt_clock_event_shutdown(struct clock_event_device *ced)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	sh_cmt_stop(ch, FLAG_CLOCKEVENT);
75162306a36Sopenharmony_ci	return 0;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic int sh_cmt_clock_event_set_state(struct clock_event_device *ced,
75562306a36Sopenharmony_ci					int periodic)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/* deal with old setting first */
76062306a36Sopenharmony_ci	if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced))
76162306a36Sopenharmony_ci		sh_cmt_stop(ch, FLAG_CLOCKEVENT);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	dev_info(&ch->cmt->pdev->dev, "ch%u: used for %s clock events\n",
76462306a36Sopenharmony_ci		 ch->index, periodic ? "periodic" : "oneshot");
76562306a36Sopenharmony_ci	sh_cmt_clock_event_start(ch, periodic);
76662306a36Sopenharmony_ci	return 0;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int sh_cmt_clock_event_set_oneshot(struct clock_event_device *ced)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	return sh_cmt_clock_event_set_state(ced, 0);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int sh_cmt_clock_event_set_periodic(struct clock_event_device *ced)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	return sh_cmt_clock_event_set_state(ced, 1);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic int sh_cmt_clock_event_next(unsigned long delta,
78062306a36Sopenharmony_ci				   struct clock_event_device *ced)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	BUG_ON(!clockevent_state_oneshot(ced));
78562306a36Sopenharmony_ci	if (likely(ch->flags & FLAG_IRQCONTEXT))
78662306a36Sopenharmony_ci		ch->next_match_value = delta - 1;
78762306a36Sopenharmony_ci	else
78862306a36Sopenharmony_ci		sh_cmt_set_next(ch, delta - 1);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	return 0;
79162306a36Sopenharmony_ci}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	dev_pm_genpd_suspend(&ch->cmt->pdev->dev);
79862306a36Sopenharmony_ci	clk_unprepare(ch->cmt->clk);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic void sh_cmt_clock_event_resume(struct clock_event_device *ced)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct sh_cmt_channel *ch = ced_to_sh_cmt(ced);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	clk_prepare(ch->cmt->clk);
80662306a36Sopenharmony_ci	dev_pm_genpd_resume(&ch->cmt->pdev->dev);
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cistatic int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
81062306a36Sopenharmony_ci				      const char *name)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct clock_event_device *ced = &ch->ced;
81362306a36Sopenharmony_ci	int irq;
81462306a36Sopenharmony_ci	int ret;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	irq = platform_get_irq(ch->cmt->pdev, ch->index);
81762306a36Sopenharmony_ci	if (irq < 0)
81862306a36Sopenharmony_ci		return irq;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	ret = request_irq(irq, sh_cmt_interrupt,
82162306a36Sopenharmony_ci			  IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
82262306a36Sopenharmony_ci			  dev_name(&ch->cmt->pdev->dev), ch);
82362306a36Sopenharmony_ci	if (ret) {
82462306a36Sopenharmony_ci		dev_err(&ch->cmt->pdev->dev, "ch%u: failed to request irq %d\n",
82562306a36Sopenharmony_ci			ch->index, irq);
82662306a36Sopenharmony_ci		return ret;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	ced->name = name;
83062306a36Sopenharmony_ci	ced->features = CLOCK_EVT_FEAT_PERIODIC;
83162306a36Sopenharmony_ci	ced->features |= CLOCK_EVT_FEAT_ONESHOT;
83262306a36Sopenharmony_ci	ced->rating = 125;
83362306a36Sopenharmony_ci	ced->cpumask = cpu_possible_mask;
83462306a36Sopenharmony_ci	ced->set_next_event = sh_cmt_clock_event_next;
83562306a36Sopenharmony_ci	ced->set_state_shutdown = sh_cmt_clock_event_shutdown;
83662306a36Sopenharmony_ci	ced->set_state_periodic = sh_cmt_clock_event_set_periodic;
83762306a36Sopenharmony_ci	ced->set_state_oneshot = sh_cmt_clock_event_set_oneshot;
83862306a36Sopenharmony_ci	ced->suspend = sh_cmt_clock_event_suspend;
83962306a36Sopenharmony_ci	ced->resume = sh_cmt_clock_event_resume;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	/* TODO: calculate good shift from rate and counter bit width */
84262306a36Sopenharmony_ci	ced->shift = 32;
84362306a36Sopenharmony_ci	ced->mult = div_sc(ch->cmt->rate, NSEC_PER_SEC, ced->shift);
84462306a36Sopenharmony_ci	ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
84562306a36Sopenharmony_ci	ced->max_delta_ticks = ch->max_match_value;
84662306a36Sopenharmony_ci	ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
84762306a36Sopenharmony_ci	ced->min_delta_ticks = 0x1f;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
85062306a36Sopenharmony_ci		 ch->index);
85162306a36Sopenharmony_ci	clockevents_register_device(ced);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int sh_cmt_register(struct sh_cmt_channel *ch, const char *name,
85762306a36Sopenharmony_ci			   bool clockevent, bool clocksource)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	int ret;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	if (clockevent) {
86262306a36Sopenharmony_ci		ch->cmt->has_clockevent = true;
86362306a36Sopenharmony_ci		ret = sh_cmt_register_clockevent(ch, name);
86462306a36Sopenharmony_ci		if (ret < 0)
86562306a36Sopenharmony_ci			return ret;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (clocksource) {
86962306a36Sopenharmony_ci		ch->cmt->has_clocksource = true;
87062306a36Sopenharmony_ci		sh_cmt_register_clocksource(ch, name);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	return 0;
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cistatic int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
87762306a36Sopenharmony_ci				unsigned int hwidx, bool clockevent,
87862306a36Sopenharmony_ci				bool clocksource, struct sh_cmt_device *cmt)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	u32 value;
88162306a36Sopenharmony_ci	int ret;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* Skip unused channels. */
88462306a36Sopenharmony_ci	if (!clockevent && !clocksource)
88562306a36Sopenharmony_ci		return 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	ch->cmt = cmt;
88862306a36Sopenharmony_ci	ch->index = index;
88962306a36Sopenharmony_ci	ch->hwidx = hwidx;
89062306a36Sopenharmony_ci	ch->timer_bit = hwidx;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/*
89362306a36Sopenharmony_ci	 * Compute the address of the channel control register block. For the
89462306a36Sopenharmony_ci	 * timers with a per-channel start/stop register, compute its address
89562306a36Sopenharmony_ci	 * as well.
89662306a36Sopenharmony_ci	 */
89762306a36Sopenharmony_ci	switch (cmt->info->model) {
89862306a36Sopenharmony_ci	case SH_CMT_16BIT:
89962306a36Sopenharmony_ci		ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6;
90062306a36Sopenharmony_ci		break;
90162306a36Sopenharmony_ci	case SH_CMT_32BIT:
90262306a36Sopenharmony_ci	case SH_CMT_48BIT:
90362306a36Sopenharmony_ci		ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10;
90462306a36Sopenharmony_ci		break;
90562306a36Sopenharmony_ci	case SH_CMT0_RCAR_GEN2:
90662306a36Sopenharmony_ci	case SH_CMT1_RCAR_GEN2:
90762306a36Sopenharmony_ci		ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
90862306a36Sopenharmony_ci		ch->ioctrl = ch->iostart + 0x10;
90962306a36Sopenharmony_ci		ch->timer_bit = 0;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		/* Enable the clock supply to the channel */
91262306a36Sopenharmony_ci		value = ioread32(cmt->mapbase + CMCLKE);
91362306a36Sopenharmony_ci		value |= BIT(hwidx);
91462306a36Sopenharmony_ci		iowrite32(value, cmt->mapbase + CMCLKE);
91562306a36Sopenharmony_ci		break;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (cmt->info->width == (sizeof(ch->max_match_value) * 8))
91962306a36Sopenharmony_ci		ch->max_match_value = ~0;
92062306a36Sopenharmony_ci	else
92162306a36Sopenharmony_ci		ch->max_match_value = (1 << cmt->info->width) - 1;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	ch->match_value = ch->max_match_value;
92462306a36Sopenharmony_ci	raw_spin_lock_init(&ch->lock);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev),
92762306a36Sopenharmony_ci			      clockevent, clocksource);
92862306a36Sopenharmony_ci	if (ret) {
92962306a36Sopenharmony_ci		dev_err(&cmt->pdev->dev, "ch%u: registration failed\n",
93062306a36Sopenharmony_ci			ch->index);
93162306a36Sopenharmony_ci		return ret;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci	ch->cs_enabled = false;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int sh_cmt_map_memory(struct sh_cmt_device *cmt)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct resource *mem;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	mem = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0);
94362306a36Sopenharmony_ci	if (!mem) {
94462306a36Sopenharmony_ci		dev_err(&cmt->pdev->dev, "failed to get I/O memory\n");
94562306a36Sopenharmony_ci		return -ENXIO;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	cmt->mapbase = ioremap(mem->start, resource_size(mem));
94962306a36Sopenharmony_ci	if (cmt->mapbase == NULL) {
95062306a36Sopenharmony_ci		dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n");
95162306a36Sopenharmony_ci		return -ENXIO;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	return 0;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic const struct platform_device_id sh_cmt_id_table[] = {
95862306a36Sopenharmony_ci	{ "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] },
95962306a36Sopenharmony_ci	{ "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] },
96062306a36Sopenharmony_ci	{ }
96162306a36Sopenharmony_ci};
96262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sh_cmt_id_table);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic const struct of_device_id sh_cmt_of_table[] __maybe_unused = {
96562306a36Sopenharmony_ci	{
96662306a36Sopenharmony_ci		/* deprecated, preserved for backward compatibility */
96762306a36Sopenharmony_ci		.compatible = "renesas,cmt-48",
96862306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT_48BIT]
96962306a36Sopenharmony_ci	},
97062306a36Sopenharmony_ci	{
97162306a36Sopenharmony_ci		/* deprecated, preserved for backward compatibility */
97262306a36Sopenharmony_ci		.compatible = "renesas,cmt-48-gen2",
97362306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
97462306a36Sopenharmony_ci	},
97562306a36Sopenharmony_ci	{
97662306a36Sopenharmony_ci		.compatible = "renesas,r8a7740-cmt1",
97762306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT_48BIT]
97862306a36Sopenharmony_ci	},
97962306a36Sopenharmony_ci	{
98062306a36Sopenharmony_ci		.compatible = "renesas,sh73a0-cmt1",
98162306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT_48BIT]
98262306a36Sopenharmony_ci	},
98362306a36Sopenharmony_ci	{
98462306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen2-cmt0",
98562306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
98662306a36Sopenharmony_ci	},
98762306a36Sopenharmony_ci	{
98862306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen2-cmt1",
98962306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
99062306a36Sopenharmony_ci	},
99162306a36Sopenharmony_ci	{
99262306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen3-cmt0",
99362306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
99462306a36Sopenharmony_ci	},
99562306a36Sopenharmony_ci	{
99662306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen3-cmt1",
99762306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
99862306a36Sopenharmony_ci	},
99962306a36Sopenharmony_ci	{
100062306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen4-cmt0",
100162306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT0_RCAR_GEN2]
100262306a36Sopenharmony_ci	},
100362306a36Sopenharmony_ci	{
100462306a36Sopenharmony_ci		.compatible = "renesas,rcar-gen4-cmt1",
100562306a36Sopenharmony_ci		.data = &sh_cmt_info[SH_CMT1_RCAR_GEN2]
100662306a36Sopenharmony_ci	},
100762306a36Sopenharmony_ci	{ }
100862306a36Sopenharmony_ci};
100962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_cmt_of_table);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	unsigned int mask, i;
101462306a36Sopenharmony_ci	unsigned long rate;
101562306a36Sopenharmony_ci	int ret;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	cmt->pdev = pdev;
101862306a36Sopenharmony_ci	raw_spin_lock_init(&cmt->lock);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
102162306a36Sopenharmony_ci		cmt->info = of_device_get_match_data(&pdev->dev);
102262306a36Sopenharmony_ci		cmt->hw_channels = cmt->info->channels_mask;
102362306a36Sopenharmony_ci	} else if (pdev->dev.platform_data) {
102462306a36Sopenharmony_ci		struct sh_timer_config *cfg = pdev->dev.platform_data;
102562306a36Sopenharmony_ci		const struct platform_device_id *id = pdev->id_entry;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci		cmt->info = (const struct sh_cmt_info *)id->driver_data;
102862306a36Sopenharmony_ci		cmt->hw_channels = cfg->channels_mask;
102962306a36Sopenharmony_ci	} else {
103062306a36Sopenharmony_ci		dev_err(&cmt->pdev->dev, "missing platform data\n");
103162306a36Sopenharmony_ci		return -ENXIO;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/* Get hold of clock. */
103562306a36Sopenharmony_ci	cmt->clk = clk_get(&cmt->pdev->dev, "fck");
103662306a36Sopenharmony_ci	if (IS_ERR(cmt->clk)) {
103762306a36Sopenharmony_ci		dev_err(&cmt->pdev->dev, "cannot get clock\n");
103862306a36Sopenharmony_ci		return PTR_ERR(cmt->clk);
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	ret = clk_prepare(cmt->clk);
104262306a36Sopenharmony_ci	if (ret < 0)
104362306a36Sopenharmony_ci		goto err_clk_put;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* Determine clock rate. */
104662306a36Sopenharmony_ci	ret = clk_enable(cmt->clk);
104762306a36Sopenharmony_ci	if (ret < 0)
104862306a36Sopenharmony_ci		goto err_clk_unprepare;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	rate = clk_get_rate(cmt->clk);
105162306a36Sopenharmony_ci	if (!rate) {
105262306a36Sopenharmony_ci		ret = -EINVAL;
105362306a36Sopenharmony_ci		goto err_clk_disable;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/* We shall wait 2 input clks after register writes */
105762306a36Sopenharmony_ci	if (cmt->info->model >= SH_CMT_48BIT)
105862306a36Sopenharmony_ci		cmt->reg_delay = DIV_ROUND_UP(2UL * USEC_PER_SEC, rate);
105962306a36Sopenharmony_ci	cmt->rate = rate / (cmt->info->width == 16 ? 512 : 8);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	/* Map the memory resource(s). */
106262306a36Sopenharmony_ci	ret = sh_cmt_map_memory(cmt);
106362306a36Sopenharmony_ci	if (ret < 0)
106462306a36Sopenharmony_ci		goto err_clk_disable;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/* Allocate and setup the channels. */
106762306a36Sopenharmony_ci	cmt->num_channels = hweight8(cmt->hw_channels);
106862306a36Sopenharmony_ci	cmt->channels = kcalloc(cmt->num_channels, sizeof(*cmt->channels),
106962306a36Sopenharmony_ci				GFP_KERNEL);
107062306a36Sopenharmony_ci	if (cmt->channels == NULL) {
107162306a36Sopenharmony_ci		ret = -ENOMEM;
107262306a36Sopenharmony_ci		goto err_unmap;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/*
107662306a36Sopenharmony_ci	 * Use the first channel as a clock event device and the second channel
107762306a36Sopenharmony_ci	 * as a clock source. If only one channel is available use it for both.
107862306a36Sopenharmony_ci	 */
107962306a36Sopenharmony_ci	for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) {
108062306a36Sopenharmony_ci		unsigned int hwidx = ffs(mask) - 1;
108162306a36Sopenharmony_ci		bool clocksource = i == 1 || cmt->num_channels == 1;
108262306a36Sopenharmony_ci		bool clockevent = i == 0;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx,
108562306a36Sopenharmony_ci					   clockevent, clocksource, cmt);
108662306a36Sopenharmony_ci		if (ret < 0)
108762306a36Sopenharmony_ci			goto err_unmap;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci		mask &= ~(1 << hwidx);
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	clk_disable(cmt->clk);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	platform_set_drvdata(pdev, cmt);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return 0;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cierr_unmap:
109962306a36Sopenharmony_ci	kfree(cmt->channels);
110062306a36Sopenharmony_ci	iounmap(cmt->mapbase);
110162306a36Sopenharmony_cierr_clk_disable:
110262306a36Sopenharmony_ci	clk_disable(cmt->clk);
110362306a36Sopenharmony_cierr_clk_unprepare:
110462306a36Sopenharmony_ci	clk_unprepare(cmt->clk);
110562306a36Sopenharmony_cierr_clk_put:
110662306a36Sopenharmony_ci	clk_put(cmt->clk);
110762306a36Sopenharmony_ci	return ret;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic int sh_cmt_probe(struct platform_device *pdev)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
111362306a36Sopenharmony_ci	int ret;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (!is_sh_early_platform_device(pdev)) {
111662306a36Sopenharmony_ci		pm_runtime_set_active(&pdev->dev);
111762306a36Sopenharmony_ci		pm_runtime_enable(&pdev->dev);
111862306a36Sopenharmony_ci	}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (cmt) {
112162306a36Sopenharmony_ci		dev_info(&pdev->dev, "kept as earlytimer\n");
112262306a36Sopenharmony_ci		goto out;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	cmt = kzalloc(sizeof(*cmt), GFP_KERNEL);
112662306a36Sopenharmony_ci	if (cmt == NULL)
112762306a36Sopenharmony_ci		return -ENOMEM;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	ret = sh_cmt_setup(cmt, pdev);
113062306a36Sopenharmony_ci	if (ret) {
113162306a36Sopenharmony_ci		kfree(cmt);
113262306a36Sopenharmony_ci		pm_runtime_idle(&pdev->dev);
113362306a36Sopenharmony_ci		return ret;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci	if (is_sh_early_platform_device(pdev))
113662306a36Sopenharmony_ci		return 0;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci out:
113962306a36Sopenharmony_ci	if (cmt->has_clockevent || cmt->has_clocksource)
114062306a36Sopenharmony_ci		pm_runtime_irq_safe(&pdev->dev);
114162306a36Sopenharmony_ci	else
114262306a36Sopenharmony_ci		pm_runtime_idle(&pdev->dev);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	return 0;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic struct platform_driver sh_cmt_device_driver = {
114862306a36Sopenharmony_ci	.probe		= sh_cmt_probe,
114962306a36Sopenharmony_ci	.driver		= {
115062306a36Sopenharmony_ci		.name	= "sh_cmt",
115162306a36Sopenharmony_ci		.of_match_table = of_match_ptr(sh_cmt_of_table),
115262306a36Sopenharmony_ci		.suppress_bind_attrs = true,
115362306a36Sopenharmony_ci	},
115462306a36Sopenharmony_ci	.id_table	= sh_cmt_id_table,
115562306a36Sopenharmony_ci};
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_cistatic int __init sh_cmt_init(void)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	return platform_driver_register(&sh_cmt_device_driver);
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_cistatic void __exit sh_cmt_exit(void)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	platform_driver_unregister(&sh_cmt_device_driver);
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci#ifdef CONFIG_SUPERH
116862306a36Sopenharmony_cish_early_platform_init("earlytimer", &sh_cmt_device_driver);
116962306a36Sopenharmony_ci#endif
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cisubsys_initcall(sh_cmt_init);
117262306a36Sopenharmony_cimodule_exit(sh_cmt_exit);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ciMODULE_AUTHOR("Magnus Damm");
117562306a36Sopenharmony_ciMODULE_DESCRIPTION("SuperH CMT Timer Driver");
1176