1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020 Microchip
5 * Author: Kamel Bouhara <kamel.bouhara@bootlin.com>
8 #include <linux/counter.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/mutex.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
15 #include <soc/at91/atmel_tcb.h>
17 #define ATMEL_TC_CMR_MASK (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
18 ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
21 #define ATMEL_TC_QDEN BIT(8)
22 #define ATMEL_TC_POSEN BIT(9)
25 const struct atmel_tcb_config
*tc_cfg
;
26 struct regmap
*regmap
;
32 static const enum counter_function mchp_tc_count_functions
[] = {
33 COUNTER_FUNCTION_INCREASE
,
34 COUNTER_FUNCTION_QUADRATURE_X4
,
37 static const enum counter_synapse_action mchp_tc_synapse_actions
[] = {
38 COUNTER_SYNAPSE_ACTION_NONE
,
39 COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
40 COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
41 COUNTER_SYNAPSE_ACTION_BOTH_EDGES
,
44 static struct counter_signal mchp_tc_count_signals
[] = {
55 static struct counter_synapse mchp_tc_count_synapses
[] = {
57 .actions_list
= mchp_tc_synapse_actions
,
58 .num_actions
= ARRAY_SIZE(mchp_tc_synapse_actions
),
59 .signal
= &mchp_tc_count_signals
[0]
62 .actions_list
= mchp_tc_synapse_actions
,
63 .num_actions
= ARRAY_SIZE(mchp_tc_synapse_actions
),
64 .signal
= &mchp_tc_count_signals
[1]
68 static int mchp_tc_count_function_read(struct counter_device
*counter
,
69 struct counter_count
*count
,
70 enum counter_function
*function
)
72 struct mchp_tc_data
*const priv
= counter_priv(counter
);
75 *function
= COUNTER_FUNCTION_QUADRATURE_X4
;
77 *function
= COUNTER_FUNCTION_INCREASE
;
82 static int mchp_tc_count_function_write(struct counter_device
*counter
,
83 struct counter_count
*count
,
84 enum counter_function function
)
86 struct mchp_tc_data
*const priv
= counter_priv(counter
);
89 regmap_read(priv
->regmap
, ATMEL_TC_BMR
, &bmr
);
90 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), &cmr
);
92 /* Set capture mode */
93 cmr
&= ~ATMEL_TC_WAVE
;
96 case COUNTER_FUNCTION_INCREASE
:
98 /* Set highest rate based on whether soc has gclk or not */
99 bmr
&= ~(ATMEL_TC_QDEN
| ATMEL_TC_POSEN
);
100 if (!priv
->tc_cfg
->has_gclk
)
101 cmr
|= ATMEL_TC_TIMER_CLOCK2
;
103 cmr
|= ATMEL_TC_TIMER_CLOCK1
;
104 /* Setup the period capture mode */
105 cmr
|= ATMEL_TC_CMR_MASK
;
106 cmr
&= ~(ATMEL_TC_ABETRG
| ATMEL_TC_XC0
);
108 case COUNTER_FUNCTION_QUADRATURE_X4
:
109 if (!priv
->tc_cfg
->has_qdec
)
111 /* In QDEC mode settings both channels 0 and 1 are required */
112 if (priv
->num_channels
< 2 || priv
->channel
[0] != 0 ||
113 priv
->channel
[1] != 1) {
114 pr_err("Invalid channels number or id for quadrature mode\n");
118 bmr
|= ATMEL_TC_QDEN
| ATMEL_TC_POSEN
;
119 cmr
|= ATMEL_TC_ETRGEDG_RISING
| ATMEL_TC_ABETRG
| ATMEL_TC_XC0
;
122 /* should never reach this path */
126 regmap_write(priv
->regmap
, ATMEL_TC_BMR
, bmr
);
127 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), cmr
);
129 /* Enable clock and trigger counter */
130 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CCR
),
131 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
133 if (priv
->qdec_mode
) {
134 regmap_write(priv
->regmap
,
135 ATMEL_TC_REG(priv
->channel
[1], CMR
), cmr
);
136 regmap_write(priv
->regmap
,
137 ATMEL_TC_REG(priv
->channel
[1], CCR
),
138 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
144 static int mchp_tc_count_signal_read(struct counter_device
*counter
,
145 struct counter_signal
*signal
,
146 enum counter_signal_level
*lvl
)
148 struct mchp_tc_data
*const priv
= counter_priv(counter
);
152 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], SR
), &sr
);
155 sigstatus
= (sr
& ATMEL_TC_MTIOB
);
157 sigstatus
= (sr
& ATMEL_TC_MTIOA
);
159 *lvl
= sigstatus
? COUNTER_SIGNAL_LEVEL_HIGH
: COUNTER_SIGNAL_LEVEL_LOW
;
164 static int mchp_tc_count_action_read(struct counter_device
*counter
,
165 struct counter_count
*count
,
166 struct counter_synapse
*synapse
,
167 enum counter_synapse_action
*action
)
169 struct mchp_tc_data
*const priv
= counter_priv(counter
);
172 if (priv
->qdec_mode
) {
173 *action
= COUNTER_SYNAPSE_ACTION_BOTH_EDGES
;
177 /* Only TIOA signal is evaluated in non-QDEC mode */
178 if (synapse
->signal
->id
!= 0) {
179 *action
= COUNTER_SYNAPSE_ACTION_NONE
;
183 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), &cmr
);
185 switch (cmr
& ATMEL_TC_ETRGEDG
) {
187 *action
= COUNTER_SYNAPSE_ACTION_NONE
;
189 case ATMEL_TC_ETRGEDG_RISING
:
190 *action
= COUNTER_SYNAPSE_ACTION_RISING_EDGE
;
192 case ATMEL_TC_ETRGEDG_FALLING
:
193 *action
= COUNTER_SYNAPSE_ACTION_FALLING_EDGE
;
195 case ATMEL_TC_ETRGEDG_BOTH
:
196 *action
= COUNTER_SYNAPSE_ACTION_BOTH_EDGES
;
203 static int mchp_tc_count_action_write(struct counter_device
*counter
,
204 struct counter_count
*count
,
205 struct counter_synapse
*synapse
,
206 enum counter_synapse_action action
)
208 struct mchp_tc_data
*const priv
= counter_priv(counter
);
209 u32 edge
= ATMEL_TC_ETRGEDG_NONE
;
211 /* QDEC mode is rising edge only; only TIOA handled in non-QDEC mode */
212 if (priv
->qdec_mode
|| synapse
->signal
->id
!= 0)
216 case COUNTER_SYNAPSE_ACTION_NONE
:
217 edge
= ATMEL_TC_ETRGEDG_NONE
;
219 case COUNTER_SYNAPSE_ACTION_RISING_EDGE
:
220 edge
= ATMEL_TC_ETRGEDG_RISING
;
222 case COUNTER_SYNAPSE_ACTION_FALLING_EDGE
:
223 edge
= ATMEL_TC_ETRGEDG_FALLING
;
225 case COUNTER_SYNAPSE_ACTION_BOTH_EDGES
:
226 edge
= ATMEL_TC_ETRGEDG_BOTH
;
229 /* should never reach this path */
233 return regmap_write_bits(priv
->regmap
,
234 ATMEL_TC_REG(priv
->channel
[0], CMR
),
235 ATMEL_TC_ETRGEDG
, edge
);
238 static int mchp_tc_count_read(struct counter_device
*counter
,
239 struct counter_count
*count
, u64
*val
)
241 struct mchp_tc_data
*const priv
= counter_priv(counter
);
244 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CV
), &cnt
);
250 static struct counter_count mchp_tc_counts
[] = {
253 .name
= "Timer Counter",
254 .functions_list
= mchp_tc_count_functions
,
255 .num_functions
= ARRAY_SIZE(mchp_tc_count_functions
),
256 .synapses
= mchp_tc_count_synapses
,
257 .num_synapses
= ARRAY_SIZE(mchp_tc_count_synapses
),
261 static const struct counter_ops mchp_tc_ops
= {
262 .signal_read
= mchp_tc_count_signal_read
,
263 .count_read
= mchp_tc_count_read
,
264 .function_read
= mchp_tc_count_function_read
,
265 .function_write
= mchp_tc_count_function_write
,
266 .action_read
= mchp_tc_count_action_read
,
267 .action_write
= mchp_tc_count_action_write
270 static const struct atmel_tcb_config tcb_rm9200_config
= {
274 static const struct atmel_tcb_config tcb_sam9x5_config
= {
278 static const struct atmel_tcb_config tcb_sama5d2_config
= {
284 static const struct atmel_tcb_config tcb_sama5d3_config
= {
289 static const struct of_device_id atmel_tc_of_match
[] = {
290 { .compatible
= "atmel,at91rm9200-tcb", .data
= &tcb_rm9200_config
, },
291 { .compatible
= "atmel,at91sam9x5-tcb", .data
= &tcb_sam9x5_config
, },
292 { .compatible
= "atmel,sama5d2-tcb", .data
= &tcb_sama5d2_config
, },
293 { .compatible
= "atmel,sama5d3-tcb", .data
= &tcb_sama5d3_config
, },
297 static void mchp_tc_clk_remove(void *ptr
)
299 clk_disable_unprepare((struct clk
*)ptr
);
302 static int mchp_tc_probe(struct platform_device
*pdev
)
304 struct device_node
*np
= pdev
->dev
.of_node
;
305 const struct atmel_tcb_config
*tcb_config
;
306 const struct of_device_id
*match
;
307 struct counter_device
*counter
;
308 struct mchp_tc_data
*priv
;
310 struct regmap
*regmap
;
315 counter
= devm_counter_alloc(&pdev
->dev
, sizeof(*priv
));
318 priv
= counter_priv(counter
);
320 match
= of_match_node(atmel_tc_of_match
, np
->parent
);
321 tcb_config
= match
->data
;
323 dev_err(&pdev
->dev
, "No matching parent node found\n");
327 regmap
= syscon_node_to_regmap(np
->parent
);
329 return PTR_ERR(regmap
);
331 /* max. channels number is 2 when in QDEC mode */
332 priv
->num_channels
= of_property_count_u32_elems(np
, "reg");
333 if (priv
->num_channels
< 0) {
334 dev_err(&pdev
->dev
, "Invalid or missing channel\n");
338 /* Register channels and initialize clocks */
339 for (i
= 0; i
< priv
->num_channels
; i
++) {
340 ret
= of_property_read_u32_index(np
, "reg", i
, &channel
);
341 if (ret
< 0 || channel
> 2)
344 priv
->channel
[i
] = channel
;
346 snprintf(clk_name
, sizeof(clk_name
), "t%d_clk", channel
);
348 clk
[i
] = of_clk_get_by_name(np
->parent
, clk_name
);
349 if (IS_ERR(clk
[i
])) {
350 /* Fallback to t0_clk */
351 clk
[i
] = of_clk_get_by_name(np
->parent
, "t0_clk");
353 return PTR_ERR(clk
[i
]);
356 ret
= clk_prepare_enable(clk
[i
]);
360 ret
= devm_add_action_or_reset(&pdev
->dev
,
367 "Initialized capture mode on channel %d\n",
371 priv
->tc_cfg
= tcb_config
;
372 priv
->regmap
= regmap
;
373 counter
->name
= dev_name(&pdev
->dev
);
374 counter
->parent
= &pdev
->dev
;
375 counter
->ops
= &mchp_tc_ops
;
376 counter
->num_counts
= ARRAY_SIZE(mchp_tc_counts
);
377 counter
->counts
= mchp_tc_counts
;
378 counter
->num_signals
= ARRAY_SIZE(mchp_tc_count_signals
);
379 counter
->signals
= mchp_tc_count_signals
;
381 ret
= devm_counter_add(&pdev
->dev
, counter
);
383 return dev_err_probe(&pdev
->dev
, ret
, "Failed to add counter\n");
388 static const struct of_device_id mchp_tc_dt_ids
[] = {
389 { .compatible
= "microchip,tcb-capture", },
392 MODULE_DEVICE_TABLE(of
, mchp_tc_dt_ids
);
394 static struct platform_driver mchp_tc_driver
= {
395 .probe
= mchp_tc_probe
,
397 .name
= "microchip-tcb-capture",
398 .of_match_table
= mchp_tc_dt_ids
,
401 module_platform_driver(mchp_tc_driver
);
403 MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
404 MODULE_DESCRIPTION("Microchip TCB Capture driver");
405 MODULE_LICENSE("GPL v2");
406 MODULE_IMPORT_NS("COUNTER");