18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2019 David Lechner <david@lechnology.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitops.h>
98c2ecf20Sopenharmony_ci#include <linux/counter.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
158c2ecf20Sopenharmony_ci#include <linux/regmap.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* 32-bit registers */
188c2ecf20Sopenharmony_ci#define QPOSCNT		0x0
198c2ecf20Sopenharmony_ci#define QPOSINIT	0x4
208c2ecf20Sopenharmony_ci#define QPOSMAX		0x8
218c2ecf20Sopenharmony_ci#define QPOSCMP		0xc
228c2ecf20Sopenharmony_ci#define QPOSILAT	0x10
238c2ecf20Sopenharmony_ci#define QPOSSLAT	0x14
248c2ecf20Sopenharmony_ci#define QPOSLAT		0x18
258c2ecf20Sopenharmony_ci#define QUTMR		0x1c
268c2ecf20Sopenharmony_ci#define QUPRD		0x20
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* 16-bit registers */
298c2ecf20Sopenharmony_ci#define QWDTMR		0x0	/* 0x24 */
308c2ecf20Sopenharmony_ci#define QWDPRD		0x2	/* 0x26 */
318c2ecf20Sopenharmony_ci#define QDECCTL		0x4	/* 0x28 */
328c2ecf20Sopenharmony_ci#define QEPCTL		0x6	/* 0x2a */
338c2ecf20Sopenharmony_ci#define QCAPCTL		0x8	/* 0x2c */
348c2ecf20Sopenharmony_ci#define QPOSCTL		0xa	/* 0x2e */
358c2ecf20Sopenharmony_ci#define QEINT		0xc	/* 0x30 */
368c2ecf20Sopenharmony_ci#define QFLG		0xe	/* 0x32 */
378c2ecf20Sopenharmony_ci#define QCLR		0x10	/* 0x34 */
388c2ecf20Sopenharmony_ci#define QFRC		0x12	/* 0x36 */
398c2ecf20Sopenharmony_ci#define QEPSTS		0x14	/* 0x38 */
408c2ecf20Sopenharmony_ci#define QCTMR		0x16	/* 0x3a */
418c2ecf20Sopenharmony_ci#define QCPRD		0x18	/* 0x3c */
428c2ecf20Sopenharmony_ci#define QCTMRLAT	0x1a	/* 0x3e */
438c2ecf20Sopenharmony_ci#define QCPRDLAT	0x1c	/* 0x40 */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define QDECCTL_QSRC_SHIFT	14
468c2ecf20Sopenharmony_ci#define QDECCTL_QSRC		GENMASK(15, 14)
478c2ecf20Sopenharmony_ci#define QDECCTL_SOEN		BIT(13)
488c2ecf20Sopenharmony_ci#define QDECCTL_SPSEL		BIT(12)
498c2ecf20Sopenharmony_ci#define QDECCTL_XCR		BIT(11)
508c2ecf20Sopenharmony_ci#define QDECCTL_SWAP		BIT(10)
518c2ecf20Sopenharmony_ci#define QDECCTL_IGATE		BIT(9)
528c2ecf20Sopenharmony_ci#define QDECCTL_QAP		BIT(8)
538c2ecf20Sopenharmony_ci#define QDECCTL_QBP		BIT(7)
548c2ecf20Sopenharmony_ci#define QDECCTL_QIP		BIT(6)
558c2ecf20Sopenharmony_ci#define QDECCTL_QSP		BIT(5)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define QEPCTL_FREE_SOFT	GENMASK(15, 14)
588c2ecf20Sopenharmony_ci#define QEPCTL_PCRM		GENMASK(13, 12)
598c2ecf20Sopenharmony_ci#define QEPCTL_SEI		GENMASK(11, 10)
608c2ecf20Sopenharmony_ci#define QEPCTL_IEI		GENMASK(9, 8)
618c2ecf20Sopenharmony_ci#define QEPCTL_SWI		BIT(7)
628c2ecf20Sopenharmony_ci#define QEPCTL_SEL		BIT(6)
638c2ecf20Sopenharmony_ci#define QEPCTL_IEL		GENMASK(5, 4)
648c2ecf20Sopenharmony_ci#define QEPCTL_PHEN		BIT(3)
658c2ecf20Sopenharmony_ci#define QEPCTL_QCLM		BIT(2)
668c2ecf20Sopenharmony_ci#define QEPCTL_UTE		BIT(1)
678c2ecf20Sopenharmony_ci#define QEPCTL_WDE		BIT(0)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* EQEP Inputs */
708c2ecf20Sopenharmony_cienum {
718c2ecf20Sopenharmony_ci	TI_EQEP_SIGNAL_QEPA,	/* QEPA/XCLK */
728c2ecf20Sopenharmony_ci	TI_EQEP_SIGNAL_QEPB,	/* QEPB/XDIR */
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* Position Counter Input Modes */
768c2ecf20Sopenharmony_cienum {
778c2ecf20Sopenharmony_ci	TI_EQEP_COUNT_FUNC_QUAD_COUNT,
788c2ecf20Sopenharmony_ci	TI_EQEP_COUNT_FUNC_DIR_COUNT,
798c2ecf20Sopenharmony_ci	TI_EQEP_COUNT_FUNC_UP_COUNT,
808c2ecf20Sopenharmony_ci	TI_EQEP_COUNT_FUNC_DOWN_COUNT,
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cienum {
848c2ecf20Sopenharmony_ci	TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES,
858c2ecf20Sopenharmony_ci	TI_EQEP_SYNAPSE_ACTION_RISING_EDGE,
868c2ecf20Sopenharmony_ci	TI_EQEP_SYNAPSE_ACTION_NONE,
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct ti_eqep_cnt {
908c2ecf20Sopenharmony_ci	struct counter_device counter;
918c2ecf20Sopenharmony_ci	struct regmap *regmap32;
928c2ecf20Sopenharmony_ci	struct regmap *regmap16;
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int ti_eqep_count_read(struct counter_device *counter,
968c2ecf20Sopenharmony_ci			      struct counter_count *count, unsigned long *val)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
998c2ecf20Sopenharmony_ci	u32 cnt;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	regmap_read(priv->regmap32, QPOSCNT, &cnt);
1028c2ecf20Sopenharmony_ci	*val = cnt;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int ti_eqep_count_write(struct counter_device *counter,
1088c2ecf20Sopenharmony_ci			       struct counter_count *count, unsigned long val)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
1118c2ecf20Sopenharmony_ci	u32 max;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	regmap_read(priv->regmap32, QPOSMAX, &max);
1148c2ecf20Sopenharmony_ci	if (val > max)
1158c2ecf20Sopenharmony_ci		return -EINVAL;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return regmap_write(priv->regmap32, QPOSCNT, val);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int ti_eqep_function_get(struct counter_device *counter,
1218c2ecf20Sopenharmony_ci				struct counter_count *count, size_t *function)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
1248c2ecf20Sopenharmony_ci	u32 qdecctl;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	regmap_read(priv->regmap16, QDECCTL, &qdecctl);
1278c2ecf20Sopenharmony_ci	*function = (qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int ti_eqep_function_set(struct counter_device *counter,
1338c2ecf20Sopenharmony_ci				struct counter_count *count, size_t function)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,
1388c2ecf20Sopenharmony_ci				 function << QDECCTL_QSRC_SHIFT);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int ti_eqep_action_get(struct counter_device *counter,
1428c2ecf20Sopenharmony_ci			      struct counter_count *count,
1438c2ecf20Sopenharmony_ci			      struct counter_synapse *synapse, size_t *action)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
1468c2ecf20Sopenharmony_ci	size_t function;
1478c2ecf20Sopenharmony_ci	u32 qdecctl;
1488c2ecf20Sopenharmony_ci	int err;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	err = ti_eqep_function_get(counter, count, &function);
1518c2ecf20Sopenharmony_ci	if (err)
1528c2ecf20Sopenharmony_ci		return err;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	switch (function) {
1558c2ecf20Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_QUAD_COUNT:
1568c2ecf20Sopenharmony_ci		/* In quadrature mode, the rising and falling edge of both
1578c2ecf20Sopenharmony_ci		 * QEPA and QEPB trigger QCLK.
1588c2ecf20Sopenharmony_ci		 */
1598c2ecf20Sopenharmony_ci		*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_DIR_COUNT:
1628c2ecf20Sopenharmony_ci		/* In direction-count mode only rising edge of QEPA is counted
1638c2ecf20Sopenharmony_ci		 * and QEPB gives direction.
1648c2ecf20Sopenharmony_ci		 */
1658c2ecf20Sopenharmony_ci		switch (synapse->signal->id) {
1668c2ecf20Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPA:
1678c2ecf20Sopenharmony_ci			*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
1688c2ecf20Sopenharmony_ci			break;
1698c2ecf20Sopenharmony_ci		default:
1708c2ecf20Sopenharmony_ci			*action = TI_EQEP_SYNAPSE_ACTION_NONE;
1718c2ecf20Sopenharmony_ci			break;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_UP_COUNT:
1758c2ecf20Sopenharmony_ci	case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
1768c2ecf20Sopenharmony_ci		/* In up/down-count modes only QEPA is counted and QEPB is not
1778c2ecf20Sopenharmony_ci		 * used.
1788c2ecf20Sopenharmony_ci		 */
1798c2ecf20Sopenharmony_ci		switch (synapse->signal->id) {
1808c2ecf20Sopenharmony_ci		case TI_EQEP_SIGNAL_QEPA:
1818c2ecf20Sopenharmony_ci			err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);
1828c2ecf20Sopenharmony_ci			if (err)
1838c2ecf20Sopenharmony_ci				return err;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci			if (qdecctl & QDECCTL_XCR)
1868c2ecf20Sopenharmony_ci				*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
1878c2ecf20Sopenharmony_ci			else
1888c2ecf20Sopenharmony_ci				*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
1898c2ecf20Sopenharmony_ci			break;
1908c2ecf20Sopenharmony_ci		default:
1918c2ecf20Sopenharmony_ci			*action = TI_EQEP_SYNAPSE_ACTION_NONE;
1928c2ecf20Sopenharmony_ci			break;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci		break;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const struct counter_ops ti_eqep_counter_ops = {
2018c2ecf20Sopenharmony_ci	.count_read	= ti_eqep_count_read,
2028c2ecf20Sopenharmony_ci	.count_write	= ti_eqep_count_write,
2038c2ecf20Sopenharmony_ci	.function_get	= ti_eqep_function_get,
2048c2ecf20Sopenharmony_ci	.function_set	= ti_eqep_function_set,
2058c2ecf20Sopenharmony_ci	.action_get	= ti_eqep_action_get,
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic ssize_t ti_eqep_position_ceiling_read(struct counter_device *counter,
2098c2ecf20Sopenharmony_ci					     struct counter_count *count,
2108c2ecf20Sopenharmony_ci					     void *ext_priv, char *buf)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
2138c2ecf20Sopenharmony_ci	u32 qposmax;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	regmap_read(priv->regmap32, QPOSMAX, &qposmax);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", qposmax);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic ssize_t ti_eqep_position_ceiling_write(struct counter_device *counter,
2218c2ecf20Sopenharmony_ci					      struct counter_count *count,
2228c2ecf20Sopenharmony_ci					      void *ext_priv, const char *buf,
2238c2ecf20Sopenharmony_ci					      size_t len)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
2268c2ecf20Sopenharmony_ci	int err;
2278c2ecf20Sopenharmony_ci	u32 res;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	err = kstrtouint(buf, 0, &res);
2308c2ecf20Sopenharmony_ci	if (err < 0)
2318c2ecf20Sopenharmony_ci		return err;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	regmap_write(priv->regmap32, QPOSMAX, res);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return len;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic ssize_t ti_eqep_position_enable_read(struct counter_device *counter,
2398c2ecf20Sopenharmony_ci					    struct counter_count *count,
2408c2ecf20Sopenharmony_ci					    void *ext_priv, char *buf)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
2438c2ecf20Sopenharmony_ci	u32 qepctl;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	regmap_read(priv->regmap16, QEPCTL, &qepctl);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", !!(qepctl & QEPCTL_PHEN));
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic ssize_t ti_eqep_position_enable_write(struct counter_device *counter,
2518c2ecf20Sopenharmony_ci					     struct counter_count *count,
2528c2ecf20Sopenharmony_ci					     void *ext_priv, const char *buf,
2538c2ecf20Sopenharmony_ci					     size_t len)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = counter->priv;
2568c2ecf20Sopenharmony_ci	int err;
2578c2ecf20Sopenharmony_ci	bool res;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	err = kstrtobool(buf, &res);
2608c2ecf20Sopenharmony_ci	if (err < 0)
2618c2ecf20Sopenharmony_ci		return err;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, res ? -1 : 0);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return len;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic struct counter_count_ext ti_eqep_position_ext[] = {
2698c2ecf20Sopenharmony_ci	{
2708c2ecf20Sopenharmony_ci		.name	= "ceiling",
2718c2ecf20Sopenharmony_ci		.read	= ti_eqep_position_ceiling_read,
2728c2ecf20Sopenharmony_ci		.write	= ti_eqep_position_ceiling_write,
2738c2ecf20Sopenharmony_ci	},
2748c2ecf20Sopenharmony_ci	{
2758c2ecf20Sopenharmony_ci		.name	= "enable",
2768c2ecf20Sopenharmony_ci		.read	= ti_eqep_position_enable_read,
2778c2ecf20Sopenharmony_ci		.write	= ti_eqep_position_enable_write,
2788c2ecf20Sopenharmony_ci	},
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic struct counter_signal ti_eqep_signals[] = {
2828c2ecf20Sopenharmony_ci	[TI_EQEP_SIGNAL_QEPA] = {
2838c2ecf20Sopenharmony_ci		.id = TI_EQEP_SIGNAL_QEPA,
2848c2ecf20Sopenharmony_ci		.name = "QEPA"
2858c2ecf20Sopenharmony_ci	},
2868c2ecf20Sopenharmony_ci	[TI_EQEP_SIGNAL_QEPB] = {
2878c2ecf20Sopenharmony_ci		.id = TI_EQEP_SIGNAL_QEPB,
2888c2ecf20Sopenharmony_ci		.name = "QEPB"
2898c2ecf20Sopenharmony_ci	},
2908c2ecf20Sopenharmony_ci};
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic const enum counter_count_function ti_eqep_position_functions[] = {
2938c2ecf20Sopenharmony_ci	[TI_EQEP_COUNT_FUNC_QUAD_COUNT]	= COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
2948c2ecf20Sopenharmony_ci	[TI_EQEP_COUNT_FUNC_DIR_COUNT]	= COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
2958c2ecf20Sopenharmony_ci	[TI_EQEP_COUNT_FUNC_UP_COUNT]	= COUNTER_COUNT_FUNCTION_INCREASE,
2968c2ecf20Sopenharmony_ci	[TI_EQEP_COUNT_FUNC_DOWN_COUNT]	= COUNTER_COUNT_FUNCTION_DECREASE,
2978c2ecf20Sopenharmony_ci};
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
3008c2ecf20Sopenharmony_ci	[TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES]	= COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
3018c2ecf20Sopenharmony_ci	[TI_EQEP_SYNAPSE_ACTION_RISING_EDGE]	= COUNTER_SYNAPSE_ACTION_RISING_EDGE,
3028c2ecf20Sopenharmony_ci	[TI_EQEP_SYNAPSE_ACTION_NONE]		= COUNTER_SYNAPSE_ACTION_NONE,
3038c2ecf20Sopenharmony_ci};
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic struct counter_synapse ti_eqep_position_synapses[] = {
3068c2ecf20Sopenharmony_ci	{
3078c2ecf20Sopenharmony_ci		.actions_list	= ti_eqep_position_synapse_actions,
3088c2ecf20Sopenharmony_ci		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
3098c2ecf20Sopenharmony_ci		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],
3108c2ecf20Sopenharmony_ci	},
3118c2ecf20Sopenharmony_ci	{
3128c2ecf20Sopenharmony_ci		.actions_list	= ti_eqep_position_synapse_actions,
3138c2ecf20Sopenharmony_ci		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
3148c2ecf20Sopenharmony_ci		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],
3158c2ecf20Sopenharmony_ci	},
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic struct counter_count ti_eqep_counts[] = {
3198c2ecf20Sopenharmony_ci	{
3208c2ecf20Sopenharmony_ci		.id		= 0,
3218c2ecf20Sopenharmony_ci		.name		= "QPOSCNT",
3228c2ecf20Sopenharmony_ci		.functions_list	= ti_eqep_position_functions,
3238c2ecf20Sopenharmony_ci		.num_functions	= ARRAY_SIZE(ti_eqep_position_functions),
3248c2ecf20Sopenharmony_ci		.synapses	= ti_eqep_position_synapses,
3258c2ecf20Sopenharmony_ci		.num_synapses	= ARRAY_SIZE(ti_eqep_position_synapses),
3268c2ecf20Sopenharmony_ci		.ext		= ti_eqep_position_ext,
3278c2ecf20Sopenharmony_ci		.num_ext	= ARRAY_SIZE(ti_eqep_position_ext),
3288c2ecf20Sopenharmony_ci	},
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic const struct regmap_config ti_eqep_regmap32_config = {
3328c2ecf20Sopenharmony_ci	.name = "32-bit",
3338c2ecf20Sopenharmony_ci	.reg_bits = 32,
3348c2ecf20Sopenharmony_ci	.val_bits = 32,
3358c2ecf20Sopenharmony_ci	.reg_stride = 4,
3368c2ecf20Sopenharmony_ci	.max_register = QUPRD,
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic const struct regmap_config ti_eqep_regmap16_config = {
3408c2ecf20Sopenharmony_ci	.name = "16-bit",
3418c2ecf20Sopenharmony_ci	.reg_bits = 16,
3428c2ecf20Sopenharmony_ci	.val_bits = 16,
3438c2ecf20Sopenharmony_ci	.reg_stride = 2,
3448c2ecf20Sopenharmony_ci	.max_register = QCPRDLAT,
3458c2ecf20Sopenharmony_ci};
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic int ti_eqep_probe(struct platform_device *pdev)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3508c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv;
3518c2ecf20Sopenharmony_ci	void __iomem *base;
3528c2ecf20Sopenharmony_ci	int err;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3558c2ecf20Sopenharmony_ci	if (!priv)
3568c2ecf20Sopenharmony_ci		return -ENOMEM;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
3598c2ecf20Sopenharmony_ci	if (IS_ERR(base))
3608c2ecf20Sopenharmony_ci		return PTR_ERR(base);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	priv->regmap32 = devm_regmap_init_mmio(dev, base,
3638c2ecf20Sopenharmony_ci					       &ti_eqep_regmap32_config);
3648c2ecf20Sopenharmony_ci	if (IS_ERR(priv->regmap32))
3658c2ecf20Sopenharmony_ci		return PTR_ERR(priv->regmap32);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,
3688c2ecf20Sopenharmony_ci					       &ti_eqep_regmap16_config);
3698c2ecf20Sopenharmony_ci	if (IS_ERR(priv->regmap16))
3708c2ecf20Sopenharmony_ci		return PTR_ERR(priv->regmap16);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	priv->counter.name = dev_name(dev);
3738c2ecf20Sopenharmony_ci	priv->counter.parent = dev;
3748c2ecf20Sopenharmony_ci	priv->counter.ops = &ti_eqep_counter_ops;
3758c2ecf20Sopenharmony_ci	priv->counter.counts = ti_eqep_counts;
3768c2ecf20Sopenharmony_ci	priv->counter.num_counts = ARRAY_SIZE(ti_eqep_counts);
3778c2ecf20Sopenharmony_ci	priv->counter.signals = ti_eqep_signals;
3788c2ecf20Sopenharmony_ci	priv->counter.num_signals = ARRAY_SIZE(ti_eqep_signals);
3798c2ecf20Sopenharmony_ci	priv->counter.priv = priv;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/*
3848c2ecf20Sopenharmony_ci	 * Need to make sure power is turned on. On AM33xx, this comes from the
3858c2ecf20Sopenharmony_ci	 * parent PWMSS bus driver. On AM17xx, this comes from the PSC power
3868c2ecf20Sopenharmony_ci	 * domain.
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
3898c2ecf20Sopenharmony_ci	pm_runtime_get_sync(dev);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	err = counter_register(&priv->counter);
3928c2ecf20Sopenharmony_ci	if (err < 0) {
3938c2ecf20Sopenharmony_ci		pm_runtime_put_sync(dev);
3948c2ecf20Sopenharmony_ci		pm_runtime_disable(dev);
3958c2ecf20Sopenharmony_ci		return err;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return 0;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic int ti_eqep_remove(struct platform_device *pdev)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct ti_eqep_cnt *priv = platform_get_drvdata(pdev);
4048c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	counter_unregister(&priv->counter);
4078c2ecf20Sopenharmony_ci	pm_runtime_put_sync(dev);
4088c2ecf20Sopenharmony_ci	pm_runtime_disable(dev);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	return 0;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic const struct of_device_id ti_eqep_of_match[] = {
4148c2ecf20Sopenharmony_ci	{ .compatible = "ti,am3352-eqep", },
4158c2ecf20Sopenharmony_ci	{ },
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ti_eqep_of_match);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic struct platform_driver ti_eqep_driver = {
4208c2ecf20Sopenharmony_ci	.probe = ti_eqep_probe,
4218c2ecf20Sopenharmony_ci	.remove = ti_eqep_remove,
4228c2ecf20Sopenharmony_ci	.driver = {
4238c2ecf20Sopenharmony_ci		.name = "ti-eqep-cnt",
4248c2ecf20Sopenharmony_ci		.of_match_table = ti_eqep_of_match,
4258c2ecf20Sopenharmony_ci	},
4268c2ecf20Sopenharmony_ci};
4278c2ecf20Sopenharmony_cimodule_platform_driver(ti_eqep_driver);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Lechner <david@lechnology.com>");
4308c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI eQEP counter driver");
4318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
432