1// SPDX-License-Identifier: GPL-2.0-only
2/**
3 * Copyright (C) 2020 Microchip
4 *
5 * Author: Kamel Bouhara <kamel.bouhara@bootlin.com>
6 */
7#include <linux/clk.h>
8#include <linux/counter.h>
9#include <linux/mfd/syscon.h>
10#include <linux/module.h>
11#include <linux/mutex.h>
12#include <linux/of.h>
13#include <linux/of_device.h>
14#include <linux/platform_device.h>
15#include <linux/regmap.h>
16#include <soc/at91/atmel_tcb.h>
17
18#define ATMEL_TC_CMR_MASK	(ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
19				 ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
20				 ATMEL_TC_LDBSTOP)
21
22#define ATMEL_TC_QDEN			BIT(8)
23#define ATMEL_TC_POSEN			BIT(9)
24
25struct mchp_tc_data {
26	const struct atmel_tcb_config *tc_cfg;
27	struct counter_device counter;
28	struct regmap *regmap;
29	int qdec_mode;
30	int num_channels;
31	int channel[2];
32};
33
34enum mchp_tc_count_function {
35	MCHP_TC_FUNCTION_INCREASE,
36	MCHP_TC_FUNCTION_QUADRATURE,
37};
38
39static enum counter_count_function mchp_tc_count_functions[] = {
40	[MCHP_TC_FUNCTION_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
41	[MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
42};
43
44enum mchp_tc_synapse_action {
45	MCHP_TC_SYNAPSE_ACTION_NONE = 0,
46	MCHP_TC_SYNAPSE_ACTION_RISING_EDGE,
47	MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE,
48	MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
49};
50
51static enum counter_synapse_action mchp_tc_synapse_actions[] = {
52	[MCHP_TC_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
53	[MCHP_TC_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
54	[MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
55	[MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
56};
57
58static struct counter_signal mchp_tc_count_signals[] = {
59	{
60		.id = 0,
61		.name = "Channel A",
62	},
63	{
64		.id = 1,
65		.name = "Channel B",
66	}
67};
68
69static struct counter_synapse mchp_tc_count_synapses[] = {
70	{
71		.actions_list = mchp_tc_synapse_actions,
72		.num_actions = ARRAY_SIZE(mchp_tc_synapse_actions),
73		.signal = &mchp_tc_count_signals[0]
74	},
75	{
76		.actions_list = mchp_tc_synapse_actions,
77		.num_actions = ARRAY_SIZE(mchp_tc_synapse_actions),
78		.signal = &mchp_tc_count_signals[1]
79	}
80};
81
82static int mchp_tc_count_function_get(struct counter_device *counter,
83				      struct counter_count *count,
84				      size_t *function)
85{
86	struct mchp_tc_data *const priv = counter->priv;
87
88	if (priv->qdec_mode)
89		*function = MCHP_TC_FUNCTION_QUADRATURE;
90	else
91		*function = MCHP_TC_FUNCTION_INCREASE;
92
93	return 0;
94}
95
96static int mchp_tc_count_function_set(struct counter_device *counter,
97				      struct counter_count *count,
98				      size_t function)
99{
100	struct mchp_tc_data *const priv = counter->priv;
101	u32 bmr, cmr;
102
103	regmap_read(priv->regmap, ATMEL_TC_BMR, &bmr);
104	regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), &cmr);
105
106	/* Set capture mode */
107	cmr &= ~ATMEL_TC_WAVE;
108
109	switch (function) {
110	case MCHP_TC_FUNCTION_INCREASE:
111		priv->qdec_mode = 0;
112		/* Set highest rate based on whether soc has gclk or not */
113		bmr &= ~(ATMEL_TC_QDEN | ATMEL_TC_POSEN);
114		if (!priv->tc_cfg->has_gclk)
115			cmr |= ATMEL_TC_TIMER_CLOCK2;
116		else
117			cmr |= ATMEL_TC_TIMER_CLOCK1;
118		/* Setup the period capture mode */
119		cmr |=  ATMEL_TC_CMR_MASK;
120		cmr &= ~(ATMEL_TC_ABETRG | ATMEL_TC_XC0);
121		break;
122	case MCHP_TC_FUNCTION_QUADRATURE:
123		if (!priv->tc_cfg->has_qdec)
124			return -EINVAL;
125		/* In QDEC mode settings both channels 0 and 1 are required */
126		if (priv->num_channels < 2 || priv->channel[0] != 0 ||
127		    priv->channel[1] != 1) {
128			pr_err("Invalid channels number or id for quadrature mode\n");
129			return -EINVAL;
130		}
131		priv->qdec_mode = 1;
132		bmr |= ATMEL_TC_QDEN | ATMEL_TC_POSEN;
133		cmr |= ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_ABETRG | ATMEL_TC_XC0;
134		break;
135	}
136
137	regmap_write(priv->regmap, ATMEL_TC_BMR, bmr);
138	regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), cmr);
139
140	/* Enable clock and trigger counter */
141	regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], CCR),
142		     ATMEL_TC_CLKEN | ATMEL_TC_SWTRG);
143
144	if (priv->qdec_mode) {
145		regmap_write(priv->regmap,
146			     ATMEL_TC_REG(priv->channel[1], CMR), cmr);
147		regmap_write(priv->regmap,
148			     ATMEL_TC_REG(priv->channel[1], CCR),
149			     ATMEL_TC_CLKEN | ATMEL_TC_SWTRG);
150	}
151
152	return 0;
153}
154
155static int mchp_tc_count_signal_read(struct counter_device *counter,
156				     struct counter_signal *signal,
157				     enum counter_signal_value *val)
158{
159	struct mchp_tc_data *const priv = counter->priv;
160	bool sigstatus;
161	u32 sr;
162
163	regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], SR), &sr);
164
165	if (signal->id == 1)
166		sigstatus = (sr & ATMEL_TC_MTIOB);
167	else
168		sigstatus = (sr & ATMEL_TC_MTIOA);
169
170	*val = sigstatus ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
171
172	return 0;
173}
174
175static int mchp_tc_count_action_get(struct counter_device *counter,
176				    struct counter_count *count,
177				    struct counter_synapse *synapse,
178				    size_t *action)
179{
180	struct mchp_tc_data *const priv = counter->priv;
181	u32 cmr;
182
183	if (priv->qdec_mode) {
184		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
185		return 0;
186	}
187
188	/* Only TIOA signal is evaluated in non-QDEC mode */
189	if (synapse->signal->id != 0) {
190		*action = COUNTER_SYNAPSE_ACTION_NONE;
191		return 0;
192	}
193
194	regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CMR), &cmr);
195
196	switch (cmr & ATMEL_TC_ETRGEDG) {
197	default:
198		*action = MCHP_TC_SYNAPSE_ACTION_NONE;
199		break;
200	case ATMEL_TC_ETRGEDG_RISING:
201		*action = MCHP_TC_SYNAPSE_ACTION_RISING_EDGE;
202		break;
203	case ATMEL_TC_ETRGEDG_FALLING:
204		*action = MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE;
205		break;
206	case ATMEL_TC_ETRGEDG_BOTH:
207		*action = MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE;
208		break;
209	}
210
211	return 0;
212}
213
214static int mchp_tc_count_action_set(struct counter_device *counter,
215				    struct counter_count *count,
216				    struct counter_synapse *synapse,
217				    size_t action)
218{
219	struct mchp_tc_data *const priv = counter->priv;
220	u32 edge = ATMEL_TC_ETRGEDG_NONE;
221
222	/* QDEC mode is rising edge only; only TIOA handled in non-QDEC mode */
223	if (priv->qdec_mode || synapse->signal->id != 0)
224		return -EINVAL;
225
226	switch (action) {
227	case MCHP_TC_SYNAPSE_ACTION_NONE:
228		edge = ATMEL_TC_ETRGEDG_NONE;
229		break;
230	case MCHP_TC_SYNAPSE_ACTION_RISING_EDGE:
231		edge = ATMEL_TC_ETRGEDG_RISING;
232		break;
233	case MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE:
234		edge = ATMEL_TC_ETRGEDG_FALLING;
235		break;
236	case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:
237		edge = ATMEL_TC_ETRGEDG_BOTH;
238		break;
239	}
240
241	return regmap_write_bits(priv->regmap,
242				ATMEL_TC_REG(priv->channel[0], CMR),
243				ATMEL_TC_ETRGEDG, edge);
244}
245
246static int mchp_tc_count_read(struct counter_device *counter,
247			      struct counter_count *count,
248			      unsigned long *val)
249{
250	struct mchp_tc_data *const priv = counter->priv;
251	u32 cnt;
252
253	regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], CV), &cnt);
254	*val = cnt;
255
256	return 0;
257}
258
259static struct counter_count mchp_tc_counts[] = {
260	{
261		.id = 0,
262		.name = "Timer Counter",
263		.functions_list = mchp_tc_count_functions,
264		.num_functions = ARRAY_SIZE(mchp_tc_count_functions),
265		.synapses = mchp_tc_count_synapses,
266		.num_synapses = ARRAY_SIZE(mchp_tc_count_synapses),
267	},
268};
269
270static const struct counter_ops mchp_tc_ops = {
271	.signal_read  = mchp_tc_count_signal_read,
272	.count_read   = mchp_tc_count_read,
273	.function_get = mchp_tc_count_function_get,
274	.function_set = mchp_tc_count_function_set,
275	.action_get   = mchp_tc_count_action_get,
276	.action_set   = mchp_tc_count_action_set
277};
278
279static const struct atmel_tcb_config tcb_rm9200_config = {
280		.counter_width = 16,
281};
282
283static const struct atmel_tcb_config tcb_sam9x5_config = {
284		.counter_width = 32,
285};
286
287static const struct atmel_tcb_config tcb_sama5d2_config = {
288		.counter_width = 32,
289		.has_gclk = true,
290		.has_qdec = true,
291};
292
293static const struct atmel_tcb_config tcb_sama5d3_config = {
294		.counter_width = 32,
295		.has_qdec = true,
296};
297
298static const struct of_device_id atmel_tc_of_match[] = {
299	{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, },
300	{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, },
301	{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, },
302	{ .compatible = "atmel,sama5d3-tcb", .data = &tcb_sama5d3_config, },
303	{ /* sentinel */ }
304};
305
306static void mchp_tc_clk_remove(void *ptr)
307{
308	clk_disable_unprepare((struct clk *)ptr);
309}
310
311static int mchp_tc_probe(struct platform_device *pdev)
312{
313	struct device_node *np = pdev->dev.of_node;
314	const struct atmel_tcb_config *tcb_config;
315	const struct of_device_id *match;
316	struct mchp_tc_data *priv;
317	char clk_name[7];
318	struct regmap *regmap;
319	struct clk *clk[3];
320	int channel;
321	int ret, i;
322
323	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
324	if (!priv)
325		return -ENOMEM;
326
327	platform_set_drvdata(pdev, priv);
328
329	match = of_match_node(atmel_tc_of_match, np->parent);
330	tcb_config = match->data;
331	if (!tcb_config) {
332		dev_err(&pdev->dev, "No matching parent node found\n");
333		return -ENODEV;
334	}
335
336	regmap = syscon_node_to_regmap(np->parent);
337	if (IS_ERR(regmap))
338		return PTR_ERR(regmap);
339
340	/* max. channels number is 2 when in QDEC mode */
341	priv->num_channels = of_property_count_u32_elems(np, "reg");
342	if (priv->num_channels < 0) {
343		dev_err(&pdev->dev, "Invalid or missing channel\n");
344		return -EINVAL;
345	}
346
347	/* Register channels and initialize clocks */
348	for (i = 0; i < priv->num_channels; i++) {
349		ret = of_property_read_u32_index(np, "reg", i, &channel);
350		if (ret < 0 || channel > 2)
351			return -ENODEV;
352
353		priv->channel[i] = channel;
354
355		snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
356
357		clk[i] = of_clk_get_by_name(np->parent, clk_name);
358		if (IS_ERR(clk[i])) {
359			/* Fallback to t0_clk */
360			clk[i] = of_clk_get_by_name(np->parent, "t0_clk");
361			if (IS_ERR(clk[i]))
362				return PTR_ERR(clk[i]);
363		}
364
365		ret = clk_prepare_enable(clk[i]);
366		if (ret)
367			return ret;
368
369		ret = devm_add_action_or_reset(&pdev->dev,
370					       mchp_tc_clk_remove,
371					       clk[i]);
372		if (ret)
373			return ret;
374
375		dev_dbg(&pdev->dev,
376			"Initialized capture mode on channel %d\n",
377			channel);
378	}
379
380	priv->tc_cfg = tcb_config;
381	priv->regmap = regmap;
382	priv->counter.name = dev_name(&pdev->dev);
383	priv->counter.parent = &pdev->dev;
384	priv->counter.ops = &mchp_tc_ops;
385	priv->counter.num_counts = ARRAY_SIZE(mchp_tc_counts);
386	priv->counter.counts = mchp_tc_counts;
387	priv->counter.num_signals = ARRAY_SIZE(mchp_tc_count_signals);
388	priv->counter.signals = mchp_tc_count_signals;
389	priv->counter.priv = priv;
390
391	return devm_counter_register(&pdev->dev, &priv->counter);
392}
393
394static const struct of_device_id mchp_tc_dt_ids[] = {
395	{ .compatible = "microchip,tcb-capture", },
396	{ /* sentinel */ },
397};
398MODULE_DEVICE_TABLE(of, mchp_tc_dt_ids);
399
400static struct platform_driver mchp_tc_driver = {
401	.probe = mchp_tc_probe,
402	.driver = {
403		.name = "microchip-tcb-capture",
404		.of_match_table = mchp_tc_dt_ids,
405	},
406};
407module_platform_driver(mchp_tc_driver);
408
409MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
410MODULE_DESCRIPTION("Microchip TCB Capture driver");
411MODULE_LICENSE("GPL v2");
412