brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · 313b914 Raw
563 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2019 David Lechner <david@lechnology.com>4 *5 * Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)6 */7 8#include <linux/bitops.h>9#include <linux/clk.h>10#include <linux/counter.h>11#include <linux/interrupt.h>12#include <linux/kernel.h>13#include <linux/mod_devicetable.h>14#include <linux/module.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17#include <linux/regmap.h>18#include <linux/types.h>19 20/* 32-bit registers */21#define QPOSCNT		0x022#define QPOSINIT	0x423#define QPOSMAX		0x824#define QPOSCMP		0xc25#define QPOSILAT	0x1026#define QPOSSLAT	0x1427#define QPOSLAT		0x1828#define QUTMR		0x1c29#define QUPRD		0x2030 31/* 16-bit registers */32#define QWDTMR		0x0	/* 0x24 */33#define QWDPRD		0x2	/* 0x26 */34#define QDECCTL		0x4	/* 0x28 */35#define QEPCTL		0x6	/* 0x2a */36#define QCAPCTL		0x8	/* 0x2c */37#define QPOSCTL		0xa	/* 0x2e */38#define QEINT		0xc	/* 0x30 */39#define QFLG		0xe	/* 0x32 */40#define QCLR		0x10	/* 0x34 */41#define QFRC		0x12	/* 0x36 */42#define QEPSTS		0x14	/* 0x38 */43#define QCTMR		0x16	/* 0x3a */44#define QCPRD		0x18	/* 0x3c */45#define QCTMRLAT	0x1a	/* 0x3e */46#define QCPRDLAT	0x1c	/* 0x40 */47 48#define QDECCTL_QSRC_SHIFT	1449#define QDECCTL_QSRC		GENMASK(15, 14)50#define QDECCTL_SOEN		BIT(13)51#define QDECCTL_SPSEL		BIT(12)52#define QDECCTL_XCR		BIT(11)53#define QDECCTL_SWAP		BIT(10)54#define QDECCTL_IGATE		BIT(9)55#define QDECCTL_QAP		BIT(8)56#define QDECCTL_QBP		BIT(7)57#define QDECCTL_QIP		BIT(6)58#define QDECCTL_QSP		BIT(5)59 60#define QEPCTL_FREE_SOFT	GENMASK(15, 14)61#define QEPCTL_PCRM		GENMASK(13, 12)62#define QEPCTL_SEI		GENMASK(11, 10)63#define QEPCTL_IEI		GENMASK(9, 8)64#define QEPCTL_SWI		BIT(7)65#define QEPCTL_SEL		BIT(6)66#define QEPCTL_IEL		GENMASK(5, 4)67#define QEPCTL_PHEN		BIT(3)68#define QEPCTL_QCLM		BIT(2)69#define QEPCTL_UTE		BIT(1)70#define QEPCTL_WDE		BIT(0)71 72#define QEINT_UTO		BIT(11)73#define QEINT_IEL		BIT(10)74#define QEINT_SEL		BIT(9)75#define QEINT_PCM		BIT(8)76#define QEINT_PCR		BIT(7)77#define QEINT_PCO		BIT(6)78#define QEINT_PCU		BIT(5)79#define QEINT_WTO		BIT(4)80#define QEINT_QDC		BIT(3)81#define QEINT_PHE		BIT(2)82#define QEINT_PCE		BIT(1)83 84#define QFLG_UTO		BIT(11)85#define QFLG_IEL		BIT(10)86#define QFLG_SEL		BIT(9)87#define QFLG_PCM		BIT(8)88#define QFLG_PCR		BIT(7)89#define QFLG_PCO		BIT(6)90#define QFLG_PCU		BIT(5)91#define QFLG_WTO		BIT(4)92#define QFLG_QDC		BIT(3)93#define QFLG_PHE		BIT(2)94#define QFLG_PCE		BIT(1)95#define QFLG_INT		BIT(0)96 97#define QCLR_UTO		BIT(11)98#define QCLR_IEL		BIT(10)99#define QCLR_SEL		BIT(9)100#define QCLR_PCM		BIT(8)101#define QCLR_PCR		BIT(7)102#define QCLR_PCO		BIT(6)103#define QCLR_PCU		BIT(5)104#define QCLR_WTO		BIT(4)105#define QCLR_QDC		BIT(3)106#define QCLR_PHE		BIT(2)107#define QCLR_PCE		BIT(1)108#define QCLR_INT		BIT(0)109 110/* EQEP Inputs */111enum {112	TI_EQEP_SIGNAL_QEPA,	/* QEPA/XCLK */113	TI_EQEP_SIGNAL_QEPB,	/* QEPB/XDIR */114};115 116/* Position Counter Input Modes */117enum ti_eqep_count_func {118	TI_EQEP_COUNT_FUNC_QUAD_COUNT,119	TI_EQEP_COUNT_FUNC_DIR_COUNT,120	TI_EQEP_COUNT_FUNC_UP_COUNT,121	TI_EQEP_COUNT_FUNC_DOWN_COUNT,122};123 124struct ti_eqep_cnt {125	struct regmap *regmap32;126	struct regmap *regmap16;127};128 129static int ti_eqep_count_read(struct counter_device *counter,130			      struct counter_count *count, u64 *val)131{132	struct ti_eqep_cnt *priv = counter_priv(counter);133	u32 cnt;134 135	regmap_read(priv->regmap32, QPOSCNT, &cnt);136	*val = cnt;137 138	return 0;139}140 141static int ti_eqep_count_write(struct counter_device *counter,142			       struct counter_count *count, u64 val)143{144	struct ti_eqep_cnt *priv = counter_priv(counter);145	u32 max;146 147	regmap_read(priv->regmap32, QPOSMAX, &max);148	if (val > max)149		return -EINVAL;150 151	return regmap_write(priv->regmap32, QPOSCNT, val);152}153 154static int ti_eqep_function_read(struct counter_device *counter,155				 struct counter_count *count,156				 enum counter_function *function)157{158	struct ti_eqep_cnt *priv = counter_priv(counter);159	u32 qdecctl;160 161	regmap_read(priv->regmap16, QDECCTL, &qdecctl);162 163	switch ((qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT) {164	case TI_EQEP_COUNT_FUNC_QUAD_COUNT:165		*function = COUNTER_FUNCTION_QUADRATURE_X4;166		break;167	case TI_EQEP_COUNT_FUNC_DIR_COUNT:168		*function = COUNTER_FUNCTION_PULSE_DIRECTION;169		break;170	case TI_EQEP_COUNT_FUNC_UP_COUNT:171		*function = COUNTER_FUNCTION_INCREASE;172		break;173	case TI_EQEP_COUNT_FUNC_DOWN_COUNT:174		*function = COUNTER_FUNCTION_DECREASE;175		break;176	}177 178	return 0;179}180 181static int ti_eqep_function_write(struct counter_device *counter,182				  struct counter_count *count,183				  enum counter_function function)184{185	struct ti_eqep_cnt *priv = counter_priv(counter);186	enum ti_eqep_count_func qsrc;187 188	switch (function) {189	case COUNTER_FUNCTION_QUADRATURE_X4:190		qsrc = TI_EQEP_COUNT_FUNC_QUAD_COUNT;191		break;192	case COUNTER_FUNCTION_PULSE_DIRECTION:193		qsrc = TI_EQEP_COUNT_FUNC_DIR_COUNT;194		break;195	case COUNTER_FUNCTION_INCREASE:196		qsrc = TI_EQEP_COUNT_FUNC_UP_COUNT;197		break;198	case COUNTER_FUNCTION_DECREASE:199		qsrc = TI_EQEP_COUNT_FUNC_DOWN_COUNT;200		break;201	default:202		/* should never reach this path */203		return -EINVAL;204	}205 206	return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,207				 qsrc << QDECCTL_QSRC_SHIFT);208}209 210static int ti_eqep_action_read(struct counter_device *counter,211			       struct counter_count *count,212			       struct counter_synapse *synapse,213			       enum counter_synapse_action *action)214{215	struct ti_eqep_cnt *priv = counter_priv(counter);216	enum counter_function function;217	u32 qdecctl;218	int err;219 220	err = ti_eqep_function_read(counter, count, &function);221	if (err)222		return err;223 224	switch (function) {225	case COUNTER_FUNCTION_QUADRATURE_X4:226		/* In quadrature mode, the rising and falling edge of both227		 * QEPA and QEPB trigger QCLK.228		 */229		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;230		return 0;231	case COUNTER_FUNCTION_PULSE_DIRECTION:232		/* In direction-count mode only rising edge of QEPA is counted233		 * and QEPB gives direction.234		 */235		switch (synapse->signal->id) {236		case TI_EQEP_SIGNAL_QEPA:237			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;238			return 0;239		case TI_EQEP_SIGNAL_QEPB:240			*action = COUNTER_SYNAPSE_ACTION_NONE;241			return 0;242		default:243			/* should never reach this path */244			return -EINVAL;245		}246	case COUNTER_FUNCTION_INCREASE:247	case COUNTER_FUNCTION_DECREASE:248		/* In up/down-count modes only QEPA is counted and QEPB is not249		 * used.250		 */251		switch (synapse->signal->id) {252		case TI_EQEP_SIGNAL_QEPA:253			err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);254			if (err)255				return err;256 257			if (qdecctl & QDECCTL_XCR)258				*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;259			else260				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;261			return 0;262		case TI_EQEP_SIGNAL_QEPB:263			*action = COUNTER_SYNAPSE_ACTION_NONE;264			return 0;265		default:266			/* should never reach this path */267			return -EINVAL;268		}269	default:270		/* should never reach this path */271		return -EINVAL;272	}273}274 275static int ti_eqep_events_configure(struct counter_device *counter)276{277	struct ti_eqep_cnt *priv = counter_priv(counter);278	struct counter_event_node *event_node;279	u32 qeint = 0;280 281	list_for_each_entry(event_node, &counter->events_list, l) {282		switch (event_node->event) {283		case COUNTER_EVENT_OVERFLOW:284			qeint |= QEINT_PCO;285			break;286		case COUNTER_EVENT_UNDERFLOW:287			qeint |= QEINT_PCU;288			break;289		}290	}291 292	return regmap_write(priv->regmap16, QEINT, qeint);293}294 295static int ti_eqep_watch_validate(struct counter_device *counter,296				  const struct counter_watch *watch)297{298	switch (watch->event) {299	case COUNTER_EVENT_OVERFLOW:300	case COUNTER_EVENT_UNDERFLOW:301		if (watch->channel != 0)302			return -EINVAL;303 304		return 0;305	default:306		return -EINVAL;307	}308}309 310static const struct counter_ops ti_eqep_counter_ops = {311	.count_read	= ti_eqep_count_read,312	.count_write	= ti_eqep_count_write,313	.function_read	= ti_eqep_function_read,314	.function_write	= ti_eqep_function_write,315	.action_read	= ti_eqep_action_read,316	.events_configure = ti_eqep_events_configure,317	.watch_validate	= ti_eqep_watch_validate,318};319 320static int ti_eqep_position_ceiling_read(struct counter_device *counter,321					 struct counter_count *count,322					 u64 *ceiling)323{324	struct ti_eqep_cnt *priv = counter_priv(counter);325	u32 qposmax;326 327	regmap_read(priv->regmap32, QPOSMAX, &qposmax);328 329	*ceiling = qposmax;330 331	return 0;332}333 334static int ti_eqep_position_ceiling_write(struct counter_device *counter,335					  struct counter_count *count,336					  u64 ceiling)337{338	struct ti_eqep_cnt *priv = counter_priv(counter);339 340	if (ceiling != (u32)ceiling)341		return -ERANGE;342 343	regmap_write(priv->regmap32, QPOSMAX, ceiling);344 345	return 0;346}347 348static int ti_eqep_position_enable_read(struct counter_device *counter,349					struct counter_count *count, u8 *enable)350{351	struct ti_eqep_cnt *priv = counter_priv(counter);352	u32 qepctl;353 354	regmap_read(priv->regmap16, QEPCTL, &qepctl);355 356	*enable = !!(qepctl & QEPCTL_PHEN);357 358	return 0;359}360 361static int ti_eqep_position_enable_write(struct counter_device *counter,362					 struct counter_count *count, u8 enable)363{364	struct ti_eqep_cnt *priv = counter_priv(counter);365 366	regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, enable ? -1 : 0);367 368	return 0;369}370 371static struct counter_comp ti_eqep_position_ext[] = {372	COUNTER_COMP_CEILING(ti_eqep_position_ceiling_read,373			     ti_eqep_position_ceiling_write),374	COUNTER_COMP_ENABLE(ti_eqep_position_enable_read,375			    ti_eqep_position_enable_write),376};377 378static struct counter_signal ti_eqep_signals[] = {379	[TI_EQEP_SIGNAL_QEPA] = {380		.id = TI_EQEP_SIGNAL_QEPA,381		.name = "QEPA"382	},383	[TI_EQEP_SIGNAL_QEPB] = {384		.id = TI_EQEP_SIGNAL_QEPB,385		.name = "QEPB"386	},387};388 389static const enum counter_function ti_eqep_position_functions[] = {390	COUNTER_FUNCTION_QUADRATURE_X4,391	COUNTER_FUNCTION_PULSE_DIRECTION,392	COUNTER_FUNCTION_INCREASE,393	COUNTER_FUNCTION_DECREASE,394};395 396static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {397	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,398	COUNTER_SYNAPSE_ACTION_RISING_EDGE,399	COUNTER_SYNAPSE_ACTION_NONE,400};401 402static struct counter_synapse ti_eqep_position_synapses[] = {403	{404		.actions_list	= ti_eqep_position_synapse_actions,405		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),406		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],407	},408	{409		.actions_list	= ti_eqep_position_synapse_actions,410		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),411		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],412	},413};414 415static struct counter_count ti_eqep_counts[] = {416	{417		.id		= 0,418		.name		= "QPOSCNT",419		.functions_list	= ti_eqep_position_functions,420		.num_functions	= ARRAY_SIZE(ti_eqep_position_functions),421		.synapses	= ti_eqep_position_synapses,422		.num_synapses	= ARRAY_SIZE(ti_eqep_position_synapses),423		.ext		= ti_eqep_position_ext,424		.num_ext	= ARRAY_SIZE(ti_eqep_position_ext),425	},426};427 428static irqreturn_t ti_eqep_irq_handler(int irq, void *dev_id)429{430	struct counter_device *counter = dev_id;431	struct ti_eqep_cnt *priv = counter_priv(counter);432	u32 qflg;433 434	regmap_read(priv->regmap16, QFLG, &qflg);435 436	if (qflg & QFLG_PCO)437		counter_push_event(counter, COUNTER_EVENT_OVERFLOW, 0);438 439	if (qflg & QFLG_PCU)440		counter_push_event(counter, COUNTER_EVENT_UNDERFLOW, 0);441 442	regmap_write(priv->regmap16, QCLR, qflg);443 444	return IRQ_HANDLED;445}446 447static const struct regmap_config ti_eqep_regmap32_config = {448	.name = "32-bit",449	.reg_bits = 32,450	.val_bits = 32,451	.reg_stride = 4,452	.max_register = QUPRD,453};454 455static const struct regmap_config ti_eqep_regmap16_config = {456	.name = "16-bit",457	.reg_bits = 16,458	.val_bits = 16,459	.reg_stride = 2,460	.max_register = QCPRDLAT,461};462 463static int ti_eqep_probe(struct platform_device *pdev)464{465	struct device *dev = &pdev->dev;466	struct counter_device *counter;467	struct ti_eqep_cnt *priv;468	void __iomem *base;469	struct clk *clk;470	int err, irq;471 472	counter = devm_counter_alloc(dev, sizeof(*priv));473	if (!counter)474		return -ENOMEM;475	priv = counter_priv(counter);476 477	base = devm_platform_ioremap_resource(pdev, 0);478	if (IS_ERR(base))479		return PTR_ERR(base);480 481	priv->regmap32 = devm_regmap_init_mmio(dev, base,482					       &ti_eqep_regmap32_config);483	if (IS_ERR(priv->regmap32))484		return PTR_ERR(priv->regmap32);485 486	priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,487					       &ti_eqep_regmap16_config);488	if (IS_ERR(priv->regmap16))489		return PTR_ERR(priv->regmap16);490 491	irq = platform_get_irq(pdev, 0);492	if (irq < 0)493		return irq;494 495	err = devm_request_threaded_irq(dev, irq, NULL, ti_eqep_irq_handler,496					IRQF_ONESHOT, dev_name(dev), counter);497	if (err < 0)498		return dev_err_probe(dev, err, "failed to request IRQ\n");499 500	counter->name = dev_name(dev);501	counter->parent = dev;502	counter->ops = &ti_eqep_counter_ops;503	counter->counts = ti_eqep_counts;504	counter->num_counts = ARRAY_SIZE(ti_eqep_counts);505	counter->signals = ti_eqep_signals;506	counter->num_signals = ARRAY_SIZE(ti_eqep_signals);507 508	platform_set_drvdata(pdev, counter);509 510	/*511	 * Need to make sure power is turned on. On AM33xx, this comes from the512	 * parent PWMSS bus driver. On AM17xx, this comes from the PSC power513	 * domain.514	 */515	pm_runtime_enable(dev);516	pm_runtime_get_sync(dev);517 518	clk = devm_clk_get_enabled(dev, NULL);519	if (IS_ERR(clk))520		return dev_err_probe(dev, PTR_ERR(clk), "failed to enable clock\n");521 522	err = counter_add(counter);523	if (err < 0) {524		pm_runtime_put_sync(dev);525		pm_runtime_disable(dev);526		return err;527	}528 529	return 0;530}531 532static void ti_eqep_remove(struct platform_device *pdev)533{534	struct counter_device *counter = platform_get_drvdata(pdev);535	struct device *dev = &pdev->dev;536 537	counter_unregister(counter);538	pm_runtime_put_sync(dev);539	pm_runtime_disable(dev);540}541 542static const struct of_device_id ti_eqep_of_match[] = {543	{ .compatible = "ti,am3352-eqep", },544	{ .compatible = "ti,am62-eqep", },545	{ },546};547MODULE_DEVICE_TABLE(of, ti_eqep_of_match);548 549static struct platform_driver ti_eqep_driver = {550	.probe = ti_eqep_probe,551	.remove_new = ti_eqep_remove,552	.driver = {553		.name = "ti-eqep-cnt",554		.of_match_table = ti_eqep_of_match,555	},556};557module_platform_driver(ti_eqep_driver);558 559MODULE_AUTHOR("David Lechner <david@lechnology.com>");560MODULE_DESCRIPTION("TI eQEP counter driver");561MODULE_LICENSE("GPL v2");562MODULE_IMPORT_NS(COUNTER);563