162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2019 David Lechner <david@lechnology.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitops.h>
962306a36Sopenharmony_ci#include <linux/counter.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1562306a36Sopenharmony_ci#include <linux/regmap.h>
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* 32-bit registers */
1962306a36Sopenharmony_ci#define QPOSCNT		0x0
2062306a36Sopenharmony_ci#define QPOSINIT	0x4
2162306a36Sopenharmony_ci#define QPOSMAX		0x8
2262306a36Sopenharmony_ci#define QPOSCMP		0xc
2362306a36Sopenharmony_ci#define QPOSILAT	0x10
2462306a36Sopenharmony_ci#define QPOSSLAT	0x14
2562306a36Sopenharmony_ci#define QPOSLAT		0x18
2662306a36Sopenharmony_ci#define QUTMR		0x1c
2762306a36Sopenharmony_ci#define QUPRD		0x20
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* 16-bit registers */
3062306a36Sopenharmony_ci#define QWDTMR		0x0	/* 0x24 */
3162306a36Sopenharmony_ci#define QWDPRD		0x2	/* 0x26 */
3262306a36Sopenharmony_ci#define QDECCTL		0x4	/* 0x28 */
3362306a36Sopenharmony_ci#define QEPCTL		0x6	/* 0x2a */
3462306a36Sopenharmony_ci#define QCAPCTL		0x8	/* 0x2c */
3562306a36Sopenharmony_ci#define QPOSCTL		0xa	/* 0x2e */
3662306a36Sopenharmony_ci#define QEINT		0xc	/* 0x30 */
3762306a36Sopenharmony_ci#define QFLG		0xe	/* 0x32 */
3862306a36Sopenharmony_ci#define QCLR		0x10	/* 0x34 */
3962306a36Sopenharmony_ci#define QFRC		0x12	/* 0x36 */
4062306a36Sopenharmony_ci#define QEPSTS		0x14	/* 0x38 */
4162306a36Sopenharmony_ci#define QCTMR		0x16	/* 0x3a */
4262306a36Sopenharmony_ci#define QCPRD		0x18	/* 0x3c */
4362306a36Sopenharmony_ci#define QCTMRLAT	0x1a	/* 0x3e */
4462306a36Sopenharmony_ci#define QCPRDLAT	0x1c	/* 0x40 */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define QDECCTL_QSRC_SHIFT	14
4762306a36Sopenharmony_ci#define QDECCTL_QSRC		GENMASK(15, 14)
4862306a36Sopenharmony_ci#define QDECCTL_SOEN		BIT(13)
4962306a36Sopenharmony_ci#define QDECCTL_SPSEL		BIT(12)
5062306a36Sopenharmony_ci#define QDECCTL_XCR		BIT(11)
5162306a36Sopenharmony_ci#define QDECCTL_SWAP		BIT(10)
5262306a36Sopenharmony_ci#define QDECCTL_IGATE		BIT(9)
5362306a36Sopenharmony_ci#define QDECCTL_QAP		BIT(8)
5462306a36Sopenharmony_ci#define QDECCTL_QBP		BIT(7)
5562306a36Sopenharmony_ci#define QDECCTL_QIP		BIT(6)
5662306a36Sopenharmony_ci#define QDECCTL_QSP		BIT(5)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define QEPCTL_FREE_SOFT	GENMASK(15, 14)
5962306a36Sopenharmony_ci#define QEPCTL_PCRM		GENMASK(13, 12)
6062306a36Sopenharmony_ci#define QEPCTL_SEI		GENMASK(11, 10)
6162306a36Sopenharmony_ci#define QEPCTL_IEI		GENMASK(9, 8)
6262306a36Sopenharmony_ci#define QEPCTL_SWI		BIT(7)
6362306a36Sopenharmony_ci#define QEPCTL_SEL		BIT(6)
6462306a36Sopenharmony_ci#define QEPCTL_IEL		GENMASK(5, 4)
6562306a36Sopenharmony_ci#define QEPCTL_PHEN		BIT(3)
6662306a36Sopenharmony_ci#define QEPCTL_QCLM		BIT(2)
6762306a36Sopenharmony_ci#define QEPCTL_UTE		BIT(1)
6862306a36Sopenharmony_ci#define QEPCTL_WDE		BIT(0)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* EQEP Inputs */
7162306a36Sopenharmony_cienum {
7262306a36Sopenharmony_ci	TI_EQEP_SIGNAL_QEPA,	/* QEPA/XCLK */
7362306a36Sopenharmony_ci	TI_EQEP_SIGNAL_QEPB,	/* QEPB/XDIR */
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Position Counter Input Modes */
7762306a36Sopenharmony_cienum ti_eqep_count_func {
7862306a36Sopenharmony_ci	TI_EQEP_COUNT_FUNC_QUAD_COUNT,
7962306a36Sopenharmony_ci	TI_EQEP_COUNT_FUNC_DIR_COUNT,
8062306a36Sopenharmony_ci	TI_EQEP_COUNT_FUNC_UP_COUNT,
8162306a36Sopenharmony_ci	TI_EQEP_COUNT_FUNC_DOWN_COUNT,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct ti_eqep_cnt {
8562306a36Sopenharmony_ci	struct counter_device counter;
8662306a36Sopenharmony_ci	struct regmap *regmap32;
8762306a36Sopenharmony_ci	struct regmap *regmap16;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic struct ti_eqep_cnt *ti_eqep_count_from_counter(struct counter_device *counter)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return counter_priv(counter);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int ti_eqep_count_read(struct counter_device *counter,
9662306a36Sopenharmony_ci			      struct counter_count *count, u64 *val)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
9962306a36Sopenharmony_ci	u32 cnt;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	regmap_read(priv->regmap32, QPOSCNT, &cnt);
10262306a36Sopenharmony_ci	*val = cnt;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int ti_eqep_count_write(struct counter_device *counter,
10862306a36Sopenharmony_ci			       struct counter_count *count, u64 val)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
11162306a36Sopenharmony_ci	u32 max;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	regmap_read(priv->regmap32, QPOSMAX, &max);
11462306a36Sopenharmony_ci	if (val > max)
11562306a36Sopenharmony_ci		return -EINVAL;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return regmap_write(priv->regmap32, QPOSCNT, val);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic int ti_eqep_function_read(struct counter_device *counter,
12162306a36Sopenharmony_ci				 struct counter_count *count,
12262306a36Sopenharmony_ci				 enum counter_function *function)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
12562306a36Sopenharmony_ci	u32 qdecctl;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	regmap_read(priv->regmap16, QDECCTL, &qdecctl);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	switch ((qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT) {
13062306a36Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_QUAD_COUNT:
13162306a36Sopenharmony_ci		*function = COUNTER_FUNCTION_QUADRATURE_X4;
13262306a36Sopenharmony_ci		break;
13362306a36Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_DIR_COUNT:
13462306a36Sopenharmony_ci		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_UP_COUNT:
13762306a36Sopenharmony_ci		*function = COUNTER_FUNCTION_INCREASE;
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
14062306a36Sopenharmony_ci		*function = COUNTER_FUNCTION_DECREASE;
14162306a36Sopenharmony_ci		break;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int ti_eqep_function_write(struct counter_device *counter,
14862306a36Sopenharmony_ci				  struct counter_count *count,
14962306a36Sopenharmony_ci				  enum counter_function function)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
15262306a36Sopenharmony_ci	enum ti_eqep_count_func qsrc;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	switch (function) {
15562306a36Sopenharmony_ci	case COUNTER_FUNCTION_QUADRATURE_X4:
15662306a36Sopenharmony_ci		qsrc = TI_EQEP_COUNT_FUNC_QUAD_COUNT;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case COUNTER_FUNCTION_PULSE_DIRECTION:
15962306a36Sopenharmony_ci		qsrc = TI_EQEP_COUNT_FUNC_DIR_COUNT;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case COUNTER_FUNCTION_INCREASE:
16262306a36Sopenharmony_ci		qsrc = TI_EQEP_COUNT_FUNC_UP_COUNT;
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case COUNTER_FUNCTION_DECREASE:
16562306a36Sopenharmony_ci		qsrc = TI_EQEP_COUNT_FUNC_DOWN_COUNT;
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	default:
16862306a36Sopenharmony_ci		/* should never reach this path */
16962306a36Sopenharmony_ci		return -EINVAL;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,
17362306a36Sopenharmony_ci				 qsrc << QDECCTL_QSRC_SHIFT);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int ti_eqep_action_read(struct counter_device *counter,
17762306a36Sopenharmony_ci			       struct counter_count *count,
17862306a36Sopenharmony_ci			       struct counter_synapse *synapse,
17962306a36Sopenharmony_ci			       enum counter_synapse_action *action)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
18262306a36Sopenharmony_ci	enum counter_function function;
18362306a36Sopenharmony_ci	u32 qdecctl;
18462306a36Sopenharmony_ci	int err;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	err = ti_eqep_function_read(counter, count, &function);
18762306a36Sopenharmony_ci	if (err)
18862306a36Sopenharmony_ci		return err;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	switch (function) {
19162306a36Sopenharmony_ci	case COUNTER_FUNCTION_QUADRATURE_X4:
19262306a36Sopenharmony_ci		/* In quadrature mode, the rising and falling edge of both
19362306a36Sopenharmony_ci		 * QEPA and QEPB trigger QCLK.
19462306a36Sopenharmony_ci		 */
19562306a36Sopenharmony_ci		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
19662306a36Sopenharmony_ci		return 0;
19762306a36Sopenharmony_ci	case COUNTER_FUNCTION_PULSE_DIRECTION:
19862306a36Sopenharmony_ci		/* In direction-count mode only rising edge of QEPA is counted
19962306a36Sopenharmony_ci		 * and QEPB gives direction.
20062306a36Sopenharmony_ci		 */
20162306a36Sopenharmony_ci		switch (synapse->signal->id) {
20262306a36Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPA:
20362306a36Sopenharmony_ci			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
20462306a36Sopenharmony_ci			return 0;
20562306a36Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPB:
20662306a36Sopenharmony_ci			*action = COUNTER_SYNAPSE_ACTION_NONE;
20762306a36Sopenharmony_ci			return 0;
20862306a36Sopenharmony_ci		default:
20962306a36Sopenharmony_ci			/* should never reach this path */
21062306a36Sopenharmony_ci			return -EINVAL;
21162306a36Sopenharmony_ci		}
21262306a36Sopenharmony_ci	case COUNTER_FUNCTION_INCREASE:
21362306a36Sopenharmony_ci	case COUNTER_FUNCTION_DECREASE:
21462306a36Sopenharmony_ci		/* In up/down-count modes only QEPA is counted and QEPB is not
21562306a36Sopenharmony_ci		 * used.
21662306a36Sopenharmony_ci		 */
21762306a36Sopenharmony_ci		switch (synapse->signal->id) {
21862306a36Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPA:
21962306a36Sopenharmony_ci			err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);
22062306a36Sopenharmony_ci			if (err)
22162306a36Sopenharmony_ci				return err;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci			if (qdecctl & QDECCTL_XCR)
22462306a36Sopenharmony_ci				*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
22562306a36Sopenharmony_ci			else
22662306a36Sopenharmony_ci				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
22762306a36Sopenharmony_ci			return 0;
22862306a36Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPB:
22962306a36Sopenharmony_ci			*action = COUNTER_SYNAPSE_ACTION_NONE;
23062306a36Sopenharmony_ci			return 0;
23162306a36Sopenharmony_ci		default:
23262306a36Sopenharmony_ci			/* should never reach this path */
23362306a36Sopenharmony_ci			return -EINVAL;
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci	default:
23662306a36Sopenharmony_ci		/* should never reach this path */
23762306a36Sopenharmony_ci		return -EINVAL;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic const struct counter_ops ti_eqep_counter_ops = {
24262306a36Sopenharmony_ci	.count_read	= ti_eqep_count_read,
24362306a36Sopenharmony_ci	.count_write	= ti_eqep_count_write,
24462306a36Sopenharmony_ci	.function_read	= ti_eqep_function_read,
24562306a36Sopenharmony_ci	.function_write	= ti_eqep_function_write,
24662306a36Sopenharmony_ci	.action_read	= ti_eqep_action_read,
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int ti_eqep_position_ceiling_read(struct counter_device *counter,
25062306a36Sopenharmony_ci					 struct counter_count *count,
25162306a36Sopenharmony_ci					 u64 *ceiling)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
25462306a36Sopenharmony_ci	u32 qposmax;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	regmap_read(priv->regmap32, QPOSMAX, &qposmax);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	*ceiling = qposmax;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return 0;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int ti_eqep_position_ceiling_write(struct counter_device *counter,
26462306a36Sopenharmony_ci					  struct counter_count *count,
26562306a36Sopenharmony_ci					  u64 ceiling)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (ceiling != (u32)ceiling)
27062306a36Sopenharmony_ci		return -ERANGE;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	regmap_write(priv->regmap32, QPOSMAX, ceiling);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int ti_eqep_position_enable_read(struct counter_device *counter,
27862306a36Sopenharmony_ci					struct counter_count *count, u8 *enable)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
28162306a36Sopenharmony_ci	u32 qepctl;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	regmap_read(priv->regmap16, QEPCTL, &qepctl);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	*enable = !!(qepctl & QEPCTL_PHEN);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int ti_eqep_position_enable_write(struct counter_device *counter,
29162306a36Sopenharmony_ci					 struct counter_count *count, u8 enable)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, enable ? -1 : 0);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic struct counter_comp ti_eqep_position_ext[] = {
30162306a36Sopenharmony_ci	COUNTER_COMP_CEILING(ti_eqep_position_ceiling_read,
30262306a36Sopenharmony_ci			     ti_eqep_position_ceiling_write),
30362306a36Sopenharmony_ci	COUNTER_COMP_ENABLE(ti_eqep_position_enable_read,
30462306a36Sopenharmony_ci			    ti_eqep_position_enable_write),
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic struct counter_signal ti_eqep_signals[] = {
30862306a36Sopenharmony_ci	[TI_EQEP_SIGNAL_QEPA] = {
30962306a36Sopenharmony_ci		.id = TI_EQEP_SIGNAL_QEPA,
31062306a36Sopenharmony_ci		.name = "QEPA"
31162306a36Sopenharmony_ci	},
31262306a36Sopenharmony_ci	[TI_EQEP_SIGNAL_QEPB] = {
31362306a36Sopenharmony_ci		.id = TI_EQEP_SIGNAL_QEPB,
31462306a36Sopenharmony_ci		.name = "QEPB"
31562306a36Sopenharmony_ci	},
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic const enum counter_function ti_eqep_position_functions[] = {
31962306a36Sopenharmony_ci	COUNTER_FUNCTION_QUADRATURE_X4,
32062306a36Sopenharmony_ci	COUNTER_FUNCTION_PULSE_DIRECTION,
32162306a36Sopenharmony_ci	COUNTER_FUNCTION_INCREASE,
32262306a36Sopenharmony_ci	COUNTER_FUNCTION_DECREASE,
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
32662306a36Sopenharmony_ci	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
32762306a36Sopenharmony_ci	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
32862306a36Sopenharmony_ci	COUNTER_SYNAPSE_ACTION_NONE,
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic struct counter_synapse ti_eqep_position_synapses[] = {
33262306a36Sopenharmony_ci	{
33362306a36Sopenharmony_ci		.actions_list	= ti_eqep_position_synapse_actions,
33462306a36Sopenharmony_ci		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
33562306a36Sopenharmony_ci		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],
33662306a36Sopenharmony_ci	},
33762306a36Sopenharmony_ci	{
33862306a36Sopenharmony_ci		.actions_list	= ti_eqep_position_synapse_actions,
33962306a36Sopenharmony_ci		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
34062306a36Sopenharmony_ci		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic struct counter_count ti_eqep_counts[] = {
34562306a36Sopenharmony_ci	{
34662306a36Sopenharmony_ci		.id		= 0,
34762306a36Sopenharmony_ci		.name		= "QPOSCNT",
34862306a36Sopenharmony_ci		.functions_list	= ti_eqep_position_functions,
34962306a36Sopenharmony_ci		.num_functions	= ARRAY_SIZE(ti_eqep_position_functions),
35062306a36Sopenharmony_ci		.synapses	= ti_eqep_position_synapses,
35162306a36Sopenharmony_ci		.num_synapses	= ARRAY_SIZE(ti_eqep_position_synapses),
35262306a36Sopenharmony_ci		.ext		= ti_eqep_position_ext,
35362306a36Sopenharmony_ci		.num_ext	= ARRAY_SIZE(ti_eqep_position_ext),
35462306a36Sopenharmony_ci	},
35562306a36Sopenharmony_ci};
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic const struct regmap_config ti_eqep_regmap32_config = {
35862306a36Sopenharmony_ci	.name = "32-bit",
35962306a36Sopenharmony_ci	.reg_bits = 32,
36062306a36Sopenharmony_ci	.val_bits = 32,
36162306a36Sopenharmony_ci	.reg_stride = 4,
36262306a36Sopenharmony_ci	.max_register = QUPRD,
36362306a36Sopenharmony_ci};
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic const struct regmap_config ti_eqep_regmap16_config = {
36662306a36Sopenharmony_ci	.name = "16-bit",
36762306a36Sopenharmony_ci	.reg_bits = 16,
36862306a36Sopenharmony_ci	.val_bits = 16,
36962306a36Sopenharmony_ci	.reg_stride = 2,
37062306a36Sopenharmony_ci	.max_register = QCPRDLAT,
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic int ti_eqep_probe(struct platform_device *pdev)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
37662306a36Sopenharmony_ci	struct counter_device *counter;
37762306a36Sopenharmony_ci	struct ti_eqep_cnt *priv;
37862306a36Sopenharmony_ci	void __iomem *base;
37962306a36Sopenharmony_ci	int err;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	counter = devm_counter_alloc(dev, sizeof(*priv));
38262306a36Sopenharmony_ci	if (!counter)
38362306a36Sopenharmony_ci		return -ENOMEM;
38462306a36Sopenharmony_ci	priv = counter_priv(counter);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
38762306a36Sopenharmony_ci	if (IS_ERR(base))
38862306a36Sopenharmony_ci		return PTR_ERR(base);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	priv->regmap32 = devm_regmap_init_mmio(dev, base,
39162306a36Sopenharmony_ci					       &ti_eqep_regmap32_config);
39262306a36Sopenharmony_ci	if (IS_ERR(priv->regmap32))
39362306a36Sopenharmony_ci		return PTR_ERR(priv->regmap32);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,
39662306a36Sopenharmony_ci					       &ti_eqep_regmap16_config);
39762306a36Sopenharmony_ci	if (IS_ERR(priv->regmap16))
39862306a36Sopenharmony_ci		return PTR_ERR(priv->regmap16);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	counter->name = dev_name(dev);
40162306a36Sopenharmony_ci	counter->parent = dev;
40262306a36Sopenharmony_ci	counter->ops = &ti_eqep_counter_ops;
40362306a36Sopenharmony_ci	counter->counts = ti_eqep_counts;
40462306a36Sopenharmony_ci	counter->num_counts = ARRAY_SIZE(ti_eqep_counts);
40562306a36Sopenharmony_ci	counter->signals = ti_eqep_signals;
40662306a36Sopenharmony_ci	counter->num_signals = ARRAY_SIZE(ti_eqep_signals);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	platform_set_drvdata(pdev, counter);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/*
41162306a36Sopenharmony_ci	 * Need to make sure power is turned on. On AM33xx, this comes from the
41262306a36Sopenharmony_ci	 * parent PWMSS bus driver. On AM17xx, this comes from the PSC power
41362306a36Sopenharmony_ci	 * domain.
41462306a36Sopenharmony_ci	 */
41562306a36Sopenharmony_ci	pm_runtime_enable(dev);
41662306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	err = counter_add(counter);
41962306a36Sopenharmony_ci	if (err < 0) {
42062306a36Sopenharmony_ci		pm_runtime_put_sync(dev);
42162306a36Sopenharmony_ci		pm_runtime_disable(dev);
42262306a36Sopenharmony_ci		return err;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	return 0;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int ti_eqep_remove(struct platform_device *pdev)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct counter_device *counter = platform_get_drvdata(pdev);
43162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	counter_unregister(counter);
43462306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
43562306a36Sopenharmony_ci	pm_runtime_disable(dev);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	return 0;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic const struct of_device_id ti_eqep_of_match[] = {
44162306a36Sopenharmony_ci	{ .compatible = "ti,am3352-eqep", },
44262306a36Sopenharmony_ci	{ },
44362306a36Sopenharmony_ci};
44462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_eqep_of_match);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic struct platform_driver ti_eqep_driver = {
44762306a36Sopenharmony_ci	.probe = ti_eqep_probe,
44862306a36Sopenharmony_ci	.remove = ti_eqep_remove,
44962306a36Sopenharmony_ci	.driver = {
45062306a36Sopenharmony_ci		.name = "ti-eqep-cnt",
45162306a36Sopenharmony_ci		.of_match_table = ti_eqep_of_match,
45262306a36Sopenharmony_ci	},
45362306a36Sopenharmony_ci};
45462306a36Sopenharmony_cimodule_platform_driver(ti_eqep_driver);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ciMODULE_AUTHOR("David Lechner <david@lechnology.com>");
45762306a36Sopenharmony_ciMODULE_DESCRIPTION("TI eQEP counter driver");
45862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
45962306a36Sopenharmony_ciMODULE_IMPORT_NS(COUNTER);
460