162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ECAP Capture driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2022 Julien Panis <jpanis@baylibre.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/atomic.h>
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/counter.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1662306a36Sopenharmony_ci#include <linux/mutex.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define ECAP_DRV_NAME "ecap"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* ECAP event IDs */
2462306a36Sopenharmony_ci#define ECAP_CEVT1		0
2562306a36Sopenharmony_ci#define ECAP_CEVT2		1
2662306a36Sopenharmony_ci#define ECAP_CEVT3		2
2762306a36Sopenharmony_ci#define ECAP_CEVT4		3
2862306a36Sopenharmony_ci#define ECAP_CNTOVF		4
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define ECAP_CEVT_LAST		ECAP_CEVT4
3162306a36Sopenharmony_ci#define ECAP_NB_CEVT		(ECAP_CEVT_LAST + 1)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define ECAP_EVT_LAST		ECAP_CNTOVF
3462306a36Sopenharmony_ci#define ECAP_NB_EVT		(ECAP_EVT_LAST + 1)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Registers */
3762306a36Sopenharmony_ci#define ECAP_TSCNT_REG			0x00
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define ECAP_CAP_REG(i)		(((i) << 2) + 0x08)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define ECAP_ECCTL_REG			0x28
4262306a36Sopenharmony_ci#define ECAP_CAPPOL_BIT(i)		BIT((i) << 1)
4362306a36Sopenharmony_ci#define ECAP_EV_MODE_MASK		GENMASK(7, 0)
4462306a36Sopenharmony_ci#define ECAP_CAPLDEN_BIT		BIT(8)
4562306a36Sopenharmony_ci#define ECAP_CONT_ONESHT_BIT		BIT(16)
4662306a36Sopenharmony_ci#define ECAP_STOPVALUE_MASK		GENMASK(18, 17)
4762306a36Sopenharmony_ci#define ECAP_TSCNTSTP_BIT		BIT(20)
4862306a36Sopenharmony_ci#define ECAP_SYNCO_DIS_MASK		GENMASK(23, 22)
4962306a36Sopenharmony_ci#define ECAP_CAP_APWM_BIT		BIT(25)
5062306a36Sopenharmony_ci#define ECAP_ECCTL_EN_MASK		(ECAP_CAPLDEN_BIT | ECAP_TSCNTSTP_BIT)
5162306a36Sopenharmony_ci#define ECAP_ECCTL_CFG_MASK		(ECAP_SYNCO_DIS_MASK | ECAP_STOPVALUE_MASK	\
5262306a36Sopenharmony_ci					| ECAP_ECCTL_EN_MASK | ECAP_CAP_APWM_BIT	\
5362306a36Sopenharmony_ci					| ECAP_CONT_ONESHT_BIT)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define ECAP_ECINT_EN_FLG_REG		0x2c
5662306a36Sopenharmony_ci#define ECAP_EVT_EN_MASK		GENMASK(ECAP_NB_EVT, ECAP_NB_CEVT)
5762306a36Sopenharmony_ci#define ECAP_EVT_FLG_BIT(i)		BIT((i) + 17)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define ECAP_ECINT_CLR_FRC_REG	0x30
6062306a36Sopenharmony_ci#define ECAP_INT_CLR_BIT		BIT(0)
6162306a36Sopenharmony_ci#define ECAP_EVT_CLR_BIT(i)		BIT((i) + 1)
6262306a36Sopenharmony_ci#define ECAP_EVT_CLR_MASK		GENMASK(ECAP_NB_EVT, 0)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define ECAP_PID_REG			0x5c
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* ECAP signals */
6762306a36Sopenharmony_ci#define ECAP_CLOCK_SIG 0
6862306a36Sopenharmony_ci#define ECAP_INPUT_SIG 1
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic const struct regmap_config ecap_cnt_regmap_config = {
7162306a36Sopenharmony_ci	.reg_bits = 32,
7262306a36Sopenharmony_ci	.reg_stride = 4,
7362306a36Sopenharmony_ci	.val_bits = 32,
7462306a36Sopenharmony_ci	.max_register = ECAP_PID_REG,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/**
7862306a36Sopenharmony_ci * struct ecap_cnt_dev - device private data structure
7962306a36Sopenharmony_ci * @enabled: device state
8062306a36Sopenharmony_ci * @lock:    synchronization lock to prevent I/O race conditions
8162306a36Sopenharmony_ci * @clk:     device clock
8262306a36Sopenharmony_ci * @regmap:  device register map
8362306a36Sopenharmony_ci * @nb_ovf:  number of overflows since capture start
8462306a36Sopenharmony_ci * @pm_ctx:  device context for PM operations
8562306a36Sopenharmony_ci * @pm_ctx.ev_mode:   event mode bits
8662306a36Sopenharmony_ci * @pm_ctx.time_cntr: timestamp counter value
8762306a36Sopenharmony_ci */
8862306a36Sopenharmony_cistruct ecap_cnt_dev {
8962306a36Sopenharmony_ci	bool enabled;
9062306a36Sopenharmony_ci	struct mutex lock;
9162306a36Sopenharmony_ci	struct clk *clk;
9262306a36Sopenharmony_ci	struct regmap *regmap;
9362306a36Sopenharmony_ci	atomic_t nb_ovf;
9462306a36Sopenharmony_ci	struct {
9562306a36Sopenharmony_ci		u8 ev_mode;
9662306a36Sopenharmony_ci		u32 time_cntr;
9762306a36Sopenharmony_ci	} pm_ctx;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic u8 ecap_cnt_capture_get_evmode(struct counter_device *counter)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
10362306a36Sopenharmony_ci	unsigned int regval;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
10662306a36Sopenharmony_ci	regmap_read(ecap_dev->regmap, ECAP_ECCTL_REG, &regval);
10762306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return regval;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void ecap_cnt_capture_set_evmode(struct counter_device *counter, u8 ev_mode)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
11762306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_EV_MODE_MASK, ev_mode);
11862306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void ecap_cnt_capture_enable(struct counter_device *counter)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Enable interrupts on events */
12862306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG,
12962306a36Sopenharmony_ci			   ECAP_EVT_EN_MASK, ECAP_EVT_EN_MASK);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Run counter */
13262306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_ECCTL_CFG_MASK,
13362306a36Sopenharmony_ci			   ECAP_SYNCO_DIS_MASK | ECAP_STOPVALUE_MASK | ECAP_ECCTL_EN_MASK);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void ecap_cnt_capture_disable(struct counter_device *counter)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Stop counter */
14162306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_ECCTL_EN_MASK, 0);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* Disable interrupts on events */
14462306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG, ECAP_EVT_EN_MASK, 0);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic u32 ecap_cnt_count_get_val(struct counter_device *counter, unsigned int reg)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
15262306a36Sopenharmony_ci	unsigned int regval;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
15562306a36Sopenharmony_ci	regmap_read(ecap_dev->regmap, reg, &regval);
15662306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return regval;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void ecap_cnt_count_set_val(struct counter_device *counter, unsigned int reg, u32 val)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
16662306a36Sopenharmony_ci	regmap_write(ecap_dev->regmap, reg, val);
16762306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int ecap_cnt_count_read(struct counter_device *counter,
17162306a36Sopenharmony_ci			       struct counter_count *count, u64 *val)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	*val = ecap_cnt_count_get_val(counter, ECAP_TSCNT_REG);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic int ecap_cnt_count_write(struct counter_device *counter,
17962306a36Sopenharmony_ci				struct counter_count *count, u64 val)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (val > U32_MAX)
18262306a36Sopenharmony_ci		return -ERANGE;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ecap_cnt_count_set_val(counter, ECAP_TSCNT_REG, val);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int ecap_cnt_function_read(struct counter_device *counter,
19062306a36Sopenharmony_ci				  struct counter_count *count,
19162306a36Sopenharmony_ci				  enum counter_function *function)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	*function = COUNTER_FUNCTION_INCREASE;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int ecap_cnt_action_read(struct counter_device *counter,
19962306a36Sopenharmony_ci				struct counter_count *count,
20062306a36Sopenharmony_ci				struct counter_synapse *synapse,
20162306a36Sopenharmony_ci				enum counter_synapse_action *action)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	*action = (synapse->signal->id == ECAP_CLOCK_SIG) ?
20462306a36Sopenharmony_ci		   COUNTER_SYNAPSE_ACTION_RISING_EDGE :
20562306a36Sopenharmony_ci		   COUNTER_SYNAPSE_ACTION_NONE;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int ecap_cnt_watch_validate(struct counter_device *counter,
21162306a36Sopenharmony_ci				   const struct counter_watch *watch)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	if (watch->channel > ECAP_CEVT_LAST)
21462306a36Sopenharmony_ci		return -EINVAL;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	switch (watch->event) {
21762306a36Sopenharmony_ci	case COUNTER_EVENT_CAPTURE:
21862306a36Sopenharmony_ci	case COUNTER_EVENT_OVERFLOW:
21962306a36Sopenharmony_ci		return 0;
22062306a36Sopenharmony_ci	default:
22162306a36Sopenharmony_ci		return -EINVAL;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int ecap_cnt_clk_get_freq(struct counter_device *counter,
22662306a36Sopenharmony_ci				 struct counter_signal *signal, u64 *freq)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	*freq = clk_get_rate(ecap_dev->clk);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int ecap_cnt_pol_read(struct counter_device *counter,
23662306a36Sopenharmony_ci			     struct counter_signal *signal,
23762306a36Sopenharmony_ci			     size_t idx, enum counter_signal_polarity *pol)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
24062306a36Sopenharmony_ci	int bitval;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
24362306a36Sopenharmony_ci	bitval = regmap_test_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_BIT(idx));
24462306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	*pol = bitval ? COUNTER_SIGNAL_POLARITY_NEGATIVE : COUNTER_SIGNAL_POLARITY_POSITIVE;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int ecap_cnt_pol_write(struct counter_device *counter,
25262306a36Sopenharmony_ci			      struct counter_signal *signal,
25362306a36Sopenharmony_ci			      size_t idx, enum counter_signal_polarity pol)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	pm_runtime_get_sync(counter->parent);
25862306a36Sopenharmony_ci	if (pol == COUNTER_SIGNAL_POLARITY_NEGATIVE)
25962306a36Sopenharmony_ci		regmap_set_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_BIT(idx));
26062306a36Sopenharmony_ci	else
26162306a36Sopenharmony_ci		regmap_clear_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_BIT(idx));
26262306a36Sopenharmony_ci	pm_runtime_put_sync(counter->parent);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int ecap_cnt_cap_read(struct counter_device *counter,
26862306a36Sopenharmony_ci			     struct counter_count *count,
26962306a36Sopenharmony_ci			     size_t idx, u64 *cap)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	*cap = ecap_cnt_count_get_val(counter, ECAP_CAP_REG(idx));
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int ecap_cnt_cap_write(struct counter_device *counter,
27762306a36Sopenharmony_ci			      struct counter_count *count,
27862306a36Sopenharmony_ci			      size_t idx, u64 cap)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	if (cap > U32_MAX)
28162306a36Sopenharmony_ci		return -ERANGE;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	ecap_cnt_count_set_val(counter, ECAP_CAP_REG(idx), cap);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int ecap_cnt_nb_ovf_read(struct counter_device *counter,
28962306a36Sopenharmony_ci				struct counter_count *count, u64 *val)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	*val = atomic_read(&ecap_dev->nb_ovf);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int ecap_cnt_nb_ovf_write(struct counter_device *counter,
29962306a36Sopenharmony_ci				 struct counter_count *count, u64 val)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (val > U32_MAX)
30462306a36Sopenharmony_ci		return -ERANGE;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	atomic_set(&ecap_dev->nb_ovf, val);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return 0;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int ecap_cnt_ceiling_read(struct counter_device *counter,
31262306a36Sopenharmony_ci				 struct counter_count *count, u64 *val)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	*val = U32_MAX;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int ecap_cnt_enable_read(struct counter_device *counter,
32062306a36Sopenharmony_ci				struct counter_count *count, u8 *enable)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	*enable = ecap_dev->enabled;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return 0;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic int ecap_cnt_enable_write(struct counter_device *counter,
33062306a36Sopenharmony_ci				 struct counter_count *count, u8 enable)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	mutex_lock(&ecap_dev->lock);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (enable == ecap_dev->enabled)
33762306a36Sopenharmony_ci		goto out;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (enable)
34062306a36Sopenharmony_ci		ecap_cnt_capture_enable(counter);
34162306a36Sopenharmony_ci	else
34262306a36Sopenharmony_ci		ecap_cnt_capture_disable(counter);
34362306a36Sopenharmony_ci	ecap_dev->enabled = enable;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ciout:
34662306a36Sopenharmony_ci	mutex_unlock(&ecap_dev->lock);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic const struct counter_ops ecap_cnt_ops = {
35262306a36Sopenharmony_ci	.count_read = ecap_cnt_count_read,
35362306a36Sopenharmony_ci	.count_write = ecap_cnt_count_write,
35462306a36Sopenharmony_ci	.function_read = ecap_cnt_function_read,
35562306a36Sopenharmony_ci	.action_read = ecap_cnt_action_read,
35662306a36Sopenharmony_ci	.watch_validate = ecap_cnt_watch_validate,
35762306a36Sopenharmony_ci};
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic const enum counter_function ecap_cnt_functions[] = {
36062306a36Sopenharmony_ci	COUNTER_FUNCTION_INCREASE,
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic const enum counter_synapse_action ecap_cnt_clock_actions[] = {
36462306a36Sopenharmony_ci	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic const enum counter_synapse_action ecap_cnt_input_actions[] = {
36862306a36Sopenharmony_ci	COUNTER_SYNAPSE_ACTION_NONE,
36962306a36Sopenharmony_ci};
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic struct counter_comp ecap_cnt_clock_ext[] = {
37262306a36Sopenharmony_ci	COUNTER_COMP_SIGNAL_U64("frequency", ecap_cnt_clk_get_freq, NULL),
37362306a36Sopenharmony_ci};
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic const enum counter_signal_polarity ecap_cnt_pol_avail[] = {
37662306a36Sopenharmony_ci	COUNTER_SIGNAL_POLARITY_POSITIVE,
37762306a36Sopenharmony_ci	COUNTER_SIGNAL_POLARITY_NEGATIVE,
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic DEFINE_COUNTER_AVAILABLE(ecap_cnt_pol_available, ecap_cnt_pol_avail);
38162306a36Sopenharmony_cistatic DEFINE_COUNTER_ARRAY_POLARITY(ecap_cnt_pol_array, ecap_cnt_pol_available, ECAP_NB_CEVT);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic struct counter_comp ecap_cnt_signal_ext[] = {
38462306a36Sopenharmony_ci	COUNTER_COMP_ARRAY_POLARITY(ecap_cnt_pol_read, ecap_cnt_pol_write, ecap_cnt_pol_array),
38562306a36Sopenharmony_ci};
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic struct counter_signal ecap_cnt_signals[] = {
38862306a36Sopenharmony_ci	{
38962306a36Sopenharmony_ci		.id = ECAP_CLOCK_SIG,
39062306a36Sopenharmony_ci		.name = "Clock Signal",
39162306a36Sopenharmony_ci		.ext = ecap_cnt_clock_ext,
39262306a36Sopenharmony_ci		.num_ext = ARRAY_SIZE(ecap_cnt_clock_ext),
39362306a36Sopenharmony_ci	},
39462306a36Sopenharmony_ci	{
39562306a36Sopenharmony_ci		.id = ECAP_INPUT_SIG,
39662306a36Sopenharmony_ci		.name = "Input Signal",
39762306a36Sopenharmony_ci		.ext = ecap_cnt_signal_ext,
39862306a36Sopenharmony_ci		.num_ext = ARRAY_SIZE(ecap_cnt_signal_ext),
39962306a36Sopenharmony_ci	},
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic struct counter_synapse ecap_cnt_synapses[] = {
40362306a36Sopenharmony_ci	{
40462306a36Sopenharmony_ci		.actions_list = ecap_cnt_clock_actions,
40562306a36Sopenharmony_ci		.num_actions = ARRAY_SIZE(ecap_cnt_clock_actions),
40662306a36Sopenharmony_ci		.signal = &ecap_cnt_signals[ECAP_CLOCK_SIG],
40762306a36Sopenharmony_ci	},
40862306a36Sopenharmony_ci	{
40962306a36Sopenharmony_ci		.actions_list = ecap_cnt_input_actions,
41062306a36Sopenharmony_ci		.num_actions = ARRAY_SIZE(ecap_cnt_input_actions),
41162306a36Sopenharmony_ci		.signal = &ecap_cnt_signals[ECAP_INPUT_SIG],
41262306a36Sopenharmony_ci	},
41362306a36Sopenharmony_ci};
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic DEFINE_COUNTER_ARRAY_CAPTURE(ecap_cnt_cap_array, ECAP_NB_CEVT);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic struct counter_comp ecap_cnt_count_ext[] = {
41862306a36Sopenharmony_ci	COUNTER_COMP_ARRAY_CAPTURE(ecap_cnt_cap_read, ecap_cnt_cap_write, ecap_cnt_cap_array),
41962306a36Sopenharmony_ci	COUNTER_COMP_COUNT_U64("num_overflows", ecap_cnt_nb_ovf_read, ecap_cnt_nb_ovf_write),
42062306a36Sopenharmony_ci	COUNTER_COMP_CEILING(ecap_cnt_ceiling_read, NULL),
42162306a36Sopenharmony_ci	COUNTER_COMP_ENABLE(ecap_cnt_enable_read, ecap_cnt_enable_write),
42262306a36Sopenharmony_ci};
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic struct counter_count ecap_cnt_counts[] = {
42562306a36Sopenharmony_ci	{
42662306a36Sopenharmony_ci		.name = "Timestamp Counter",
42762306a36Sopenharmony_ci		.functions_list = ecap_cnt_functions,
42862306a36Sopenharmony_ci		.num_functions = ARRAY_SIZE(ecap_cnt_functions),
42962306a36Sopenharmony_ci		.synapses = ecap_cnt_synapses,
43062306a36Sopenharmony_ci		.num_synapses = ARRAY_SIZE(ecap_cnt_synapses),
43162306a36Sopenharmony_ci		.ext = ecap_cnt_count_ext,
43262306a36Sopenharmony_ci		.num_ext = ARRAY_SIZE(ecap_cnt_count_ext),
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci};
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic irqreturn_t ecap_cnt_isr(int irq, void *dev_id)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct counter_device *counter_dev = dev_id;
43962306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev);
44062306a36Sopenharmony_ci	unsigned int clr = 0;
44162306a36Sopenharmony_ci	unsigned int flg;
44262306a36Sopenharmony_ci	int i;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	regmap_read(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG, &flg);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* Check capture events */
44762306a36Sopenharmony_ci	for (i = 0 ; i < ECAP_NB_CEVT ; i++) {
44862306a36Sopenharmony_ci		if (flg & ECAP_EVT_FLG_BIT(i)) {
44962306a36Sopenharmony_ci			counter_push_event(counter_dev, COUNTER_EVENT_CAPTURE, i);
45062306a36Sopenharmony_ci			clr |= ECAP_EVT_CLR_BIT(i);
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Check counter overflow */
45562306a36Sopenharmony_ci	if (flg & ECAP_EVT_FLG_BIT(ECAP_CNTOVF)) {
45662306a36Sopenharmony_ci		atomic_inc(&ecap_dev->nb_ovf);
45762306a36Sopenharmony_ci		for (i = 0 ; i < ECAP_NB_CEVT ; i++)
45862306a36Sopenharmony_ci			counter_push_event(counter_dev, COUNTER_EVENT_OVERFLOW, i);
45962306a36Sopenharmony_ci		clr |= ECAP_EVT_CLR_BIT(ECAP_CNTOVF);
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	clr |= ECAP_INT_CLR_BIT;
46362306a36Sopenharmony_ci	regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_CLR_FRC_REG, ECAP_EVT_CLR_MASK, clr);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	return IRQ_HANDLED;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void ecap_cnt_pm_disable(void *dev)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	pm_runtime_disable(dev);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int ecap_cnt_probe(struct platform_device *pdev)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
47662306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev;
47762306a36Sopenharmony_ci	struct counter_device *counter_dev;
47862306a36Sopenharmony_ci	void __iomem *mmio_base;
47962306a36Sopenharmony_ci	unsigned long clk_rate;
48062306a36Sopenharmony_ci	int ret;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	counter_dev = devm_counter_alloc(dev, sizeof(*ecap_dev));
48362306a36Sopenharmony_ci	if (!counter_dev)
48462306a36Sopenharmony_ci		return -ENOMEM;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	counter_dev->name = ECAP_DRV_NAME;
48762306a36Sopenharmony_ci	counter_dev->parent = dev;
48862306a36Sopenharmony_ci	counter_dev->ops = &ecap_cnt_ops;
48962306a36Sopenharmony_ci	counter_dev->signals = ecap_cnt_signals;
49062306a36Sopenharmony_ci	counter_dev->num_signals = ARRAY_SIZE(ecap_cnt_signals);
49162306a36Sopenharmony_ci	counter_dev->counts = ecap_cnt_counts;
49262306a36Sopenharmony_ci	counter_dev->num_counts = ARRAY_SIZE(ecap_cnt_counts);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	ecap_dev = counter_priv(counter_dev);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	mutex_init(&ecap_dev->lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	ecap_dev->clk = devm_clk_get_enabled(dev, "fck");
49962306a36Sopenharmony_ci	if (IS_ERR(ecap_dev->clk))
50062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(ecap_dev->clk), "failed to get clock\n");
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	clk_rate = clk_get_rate(ecap_dev->clk);
50362306a36Sopenharmony_ci	if (!clk_rate) {
50462306a36Sopenharmony_ci		dev_err(dev, "failed to get clock rate\n");
50562306a36Sopenharmony_ci		return -EINVAL;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	mmio_base = devm_platform_ioremap_resource(pdev, 0);
50962306a36Sopenharmony_ci	if (IS_ERR(mmio_base))
51062306a36Sopenharmony_ci		return PTR_ERR(mmio_base);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ecap_dev->regmap = devm_regmap_init_mmio(dev, mmio_base, &ecap_cnt_regmap_config);
51362306a36Sopenharmony_ci	if (IS_ERR(ecap_dev->regmap))
51462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(ecap_dev->regmap), "failed to init regmap\n");
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	ret = platform_get_irq(pdev, 0);
51762306a36Sopenharmony_ci	if (ret < 0)
51862306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to get irq\n");
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	ret = devm_request_irq(dev, ret, ecap_cnt_isr, 0, pdev->name, counter_dev);
52162306a36Sopenharmony_ci	if (ret)
52262306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to request irq\n");
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	platform_set_drvdata(pdev, counter_dev);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	pm_runtime_enable(dev);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/* Register a cleanup callback to care for disabling PM */
52962306a36Sopenharmony_ci	ret = devm_add_action_or_reset(dev, ecap_cnt_pm_disable, dev);
53062306a36Sopenharmony_ci	if (ret)
53162306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to add pm disable action\n");
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ret = devm_counter_add(dev, counter_dev);
53462306a36Sopenharmony_ci	if (ret)
53562306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to add counter\n");
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return 0;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int ecap_cnt_remove(struct platform_device *pdev)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct counter_device *counter_dev = platform_get_drvdata(pdev);
54362306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (ecap_dev->enabled)
54662306a36Sopenharmony_ci		ecap_cnt_capture_disable(counter_dev);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic int ecap_cnt_suspend(struct device *dev)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct counter_device *counter_dev = dev_get_drvdata(dev);
55462306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* If eCAP is running, stop capture then save timestamp counter */
55762306a36Sopenharmony_ci	if (ecap_dev->enabled) {
55862306a36Sopenharmony_ci		/*
55962306a36Sopenharmony_ci		 * Disabling capture has the following effects:
56062306a36Sopenharmony_ci		 * - interrupts are disabled
56162306a36Sopenharmony_ci		 * - loading of capture registers is disabled
56262306a36Sopenharmony_ci		 * - timebase counter is stopped
56362306a36Sopenharmony_ci		 */
56462306a36Sopenharmony_ci		ecap_cnt_capture_disable(counter_dev);
56562306a36Sopenharmony_ci		ecap_dev->pm_ctx.time_cntr = ecap_cnt_count_get_val(counter_dev, ECAP_TSCNT_REG);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	ecap_dev->pm_ctx.ev_mode = ecap_cnt_capture_get_evmode(counter_dev);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	clk_disable(ecap_dev->clk);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic int ecap_cnt_resume(struct device *dev)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	struct counter_device *counter_dev = dev_get_drvdata(dev);
57862306a36Sopenharmony_ci	struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	clk_enable(ecap_dev->clk);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	ecap_cnt_capture_set_evmode(counter_dev, ecap_dev->pm_ctx.ev_mode);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* If eCAP was running, restore timestamp counter then run capture */
58562306a36Sopenharmony_ci	if (ecap_dev->enabled) {
58662306a36Sopenharmony_ci		ecap_cnt_count_set_val(counter_dev, ECAP_TSCNT_REG, ecap_dev->pm_ctx.time_cntr);
58762306a36Sopenharmony_ci		ecap_cnt_capture_enable(counter_dev);
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(ecap_cnt_pm_ops, ecap_cnt_suspend, ecap_cnt_resume);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic const struct of_device_id ecap_cnt_of_match[] = {
59662306a36Sopenharmony_ci	{ .compatible	= "ti,am62-ecap-capture" },
59762306a36Sopenharmony_ci	{},
59862306a36Sopenharmony_ci};
59962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ecap_cnt_of_match);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic struct platform_driver ecap_cnt_driver = {
60262306a36Sopenharmony_ci	.probe = ecap_cnt_probe,
60362306a36Sopenharmony_ci	.remove = ecap_cnt_remove,
60462306a36Sopenharmony_ci	.driver = {
60562306a36Sopenharmony_ci		.name = "ecap-capture",
60662306a36Sopenharmony_ci		.of_match_table = ecap_cnt_of_match,
60762306a36Sopenharmony_ci		.pm = pm_sleep_ptr(&ecap_cnt_pm_ops),
60862306a36Sopenharmony_ci	},
60962306a36Sopenharmony_ci};
61062306a36Sopenharmony_cimodule_platform_driver(ecap_cnt_driver);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ciMODULE_DESCRIPTION("ECAP Capture driver");
61362306a36Sopenharmony_ciMODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
61462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
61562306a36Sopenharmony_ciMODULE_IMPORT_NS(COUNTER);
616