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/of_device.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16 #include <soc/at91/atmel_tcb.h>
18 #define ATMEL_TC_CMR_MASK (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
19 ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
22 #define ATMEL_TC_QDEN BIT(8)
23 #define ATMEL_TC_POSEN BIT(9)
26 const struct atmel_tcb_config
*tc_cfg
;
27 struct counter_device counter
;
28 struct regmap
*regmap
;
35 enum mchp_tc_count_function
{
36 MCHP_TC_FUNCTION_INCREASE
,
37 MCHP_TC_FUNCTION_QUADRATURE
,
40 static enum counter_count_function mchp_tc_count_functions
[] = {
41 [MCHP_TC_FUNCTION_INCREASE
] = COUNTER_COUNT_FUNCTION_INCREASE
,
42 [MCHP_TC_FUNCTION_QUADRATURE
] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4
,
45 enum mchp_tc_synapse_action
{
46 MCHP_TC_SYNAPSE_ACTION_NONE
= 0,
47 MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
,
48 MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
,
49 MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
52 static enum counter_synapse_action mchp_tc_synapse_actions
[] = {
53 [MCHP_TC_SYNAPSE_ACTION_NONE
] = COUNTER_SYNAPSE_ACTION_NONE
,
54 [MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
,
55 [MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE
,
56 [MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
,
59 static struct counter_signal mchp_tc_count_signals
[] = {
70 static struct counter_synapse mchp_tc_count_synapses
[] = {
72 .actions_list
= mchp_tc_synapse_actions
,
73 .num_actions
= ARRAY_SIZE(mchp_tc_synapse_actions
),
74 .signal
= &mchp_tc_count_signals
[0]
77 .actions_list
= mchp_tc_synapse_actions
,
78 .num_actions
= ARRAY_SIZE(mchp_tc_synapse_actions
),
79 .signal
= &mchp_tc_count_signals
[1]
83 static int mchp_tc_count_function_get(struct counter_device
*counter
,
84 struct counter_count
*count
,
87 struct mchp_tc_data
*const priv
= counter
->priv
;
90 *function
= MCHP_TC_FUNCTION_QUADRATURE
;
92 *function
= MCHP_TC_FUNCTION_INCREASE
;
97 static int mchp_tc_count_function_set(struct counter_device
*counter
,
98 struct counter_count
*count
,
101 struct mchp_tc_data
*const priv
= counter
->priv
;
104 regmap_read(priv
->regmap
, ATMEL_TC_BMR
, &bmr
);
105 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), &cmr
);
107 /* Set capture mode */
108 cmr
&= ~ATMEL_TC_WAVE
;
111 case MCHP_TC_FUNCTION_INCREASE
:
113 /* Set highest rate based on whether soc has gclk or not */
114 bmr
&= ~(ATMEL_TC_QDEN
| ATMEL_TC_POSEN
);
115 if (priv
->tc_cfg
->has_gclk
)
116 cmr
|= ATMEL_TC_TIMER_CLOCK2
;
118 cmr
|= ATMEL_TC_TIMER_CLOCK1
;
119 /* Setup the period capture mode */
120 cmr
|= ATMEL_TC_CMR_MASK
;
121 cmr
&= ~(ATMEL_TC_ABETRG
| ATMEL_TC_XC0
);
123 case MCHP_TC_FUNCTION_QUADRATURE
:
124 if (!priv
->tc_cfg
->has_qdec
)
126 /* In QDEC mode settings both channels 0 and 1 are required */
127 if (priv
->num_channels
< 2 || priv
->channel
[0] != 0 ||
128 priv
->channel
[1] != 1) {
129 pr_err("Invalid channels number or id for quadrature mode\n");
133 bmr
|= ATMEL_TC_QDEN
| ATMEL_TC_POSEN
;
134 cmr
|= ATMEL_TC_ETRGEDG_RISING
| ATMEL_TC_ABETRG
| ATMEL_TC_XC0
;
138 regmap_write(priv
->regmap
, ATMEL_TC_BMR
, bmr
);
139 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), cmr
);
141 /* Enable clock and trigger counter */
142 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CCR
),
143 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
145 if (priv
->qdec_mode
) {
146 regmap_write(priv
->regmap
,
147 ATMEL_TC_REG(priv
->channel
[1], CMR
), cmr
);
148 regmap_write(priv
->regmap
,
149 ATMEL_TC_REG(priv
->channel
[1], CCR
),
150 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
156 static int mchp_tc_count_signal_read(struct counter_device
*counter
,
157 struct counter_signal
*signal
,
158 enum counter_signal_value
*val
)
160 struct mchp_tc_data
*const priv
= counter
->priv
;
164 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], SR
), &sr
);
166 if (priv
->trig_inverted
)
167 sigstatus
= (sr
& ATMEL_TC_MTIOB
);
169 sigstatus
= (sr
& ATMEL_TC_MTIOA
);
171 *val
= sigstatus
? COUNTER_SIGNAL_HIGH
: COUNTER_SIGNAL_LOW
;
176 static int mchp_tc_count_action_get(struct counter_device
*counter
,
177 struct counter_count
*count
,
178 struct counter_synapse
*synapse
,
181 struct mchp_tc_data
*const priv
= counter
->priv
;
184 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), &cmr
);
186 switch (cmr
& ATMEL_TC_ETRGEDG
) {
188 *action
= MCHP_TC_SYNAPSE_ACTION_NONE
;
190 case ATMEL_TC_ETRGEDG_RISING
:
191 *action
= MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
;
193 case ATMEL_TC_ETRGEDG_FALLING
:
194 *action
= MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
;
196 case ATMEL_TC_ETRGEDG_BOTH
:
197 *action
= MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
;
204 static int mchp_tc_count_action_set(struct counter_device
*counter
,
205 struct counter_count
*count
,
206 struct counter_synapse
*synapse
,
209 struct mchp_tc_data
*const priv
= counter
->priv
;
210 u32 edge
= ATMEL_TC_ETRGEDG_NONE
;
212 /* QDEC mode is rising edge only */
217 case MCHP_TC_SYNAPSE_ACTION_NONE
:
218 edge
= ATMEL_TC_ETRGEDG_NONE
;
220 case MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
:
221 edge
= ATMEL_TC_ETRGEDG_RISING
;
223 case MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
:
224 edge
= ATMEL_TC_ETRGEDG_FALLING
;
226 case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
:
227 edge
= ATMEL_TC_ETRGEDG_BOTH
;
231 return regmap_write_bits(priv
->regmap
,
232 ATMEL_TC_REG(priv
->channel
[0], CMR
),
233 ATMEL_TC_ETRGEDG
, edge
);
236 static int mchp_tc_count_read(struct counter_device
*counter
,
237 struct counter_count
*count
,
240 struct mchp_tc_data
*const priv
= counter
->priv
;
243 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CV
), &cnt
);
249 static struct counter_count mchp_tc_counts
[] = {
252 .name
= "Timer Counter",
253 .functions_list
= mchp_tc_count_functions
,
254 .num_functions
= ARRAY_SIZE(mchp_tc_count_functions
),
255 .synapses
= mchp_tc_count_synapses
,
256 .num_synapses
= ARRAY_SIZE(mchp_tc_count_synapses
),
260 static const struct counter_ops mchp_tc_ops
= {
261 .signal_read
= mchp_tc_count_signal_read
,
262 .count_read
= mchp_tc_count_read
,
263 .function_get
= mchp_tc_count_function_get
,
264 .function_set
= mchp_tc_count_function_set
,
265 .action_get
= mchp_tc_count_action_get
,
266 .action_set
= mchp_tc_count_action_set
269 static const struct atmel_tcb_config tcb_rm9200_config
= {
273 static const struct atmel_tcb_config tcb_sam9x5_config
= {
277 static const struct atmel_tcb_config tcb_sama5d2_config
= {
283 static const struct atmel_tcb_config tcb_sama5d3_config
= {
288 static const struct of_device_id atmel_tc_of_match
[] = {
289 { .compatible
= "atmel,at91rm9200-tcb", .data
= &tcb_rm9200_config
, },
290 { .compatible
= "atmel,at91sam9x5-tcb", .data
= &tcb_sam9x5_config
, },
291 { .compatible
= "atmel,sama5d2-tcb", .data
= &tcb_sama5d2_config
, },
292 { .compatible
= "atmel,sama5d3-tcb", .data
= &tcb_sama5d3_config
, },
296 static void mchp_tc_clk_remove(void *ptr
)
298 clk_disable_unprepare((struct clk
*)ptr
);
301 static int mchp_tc_probe(struct platform_device
*pdev
)
303 struct device_node
*np
= pdev
->dev
.of_node
;
304 const struct atmel_tcb_config
*tcb_config
;
305 const struct of_device_id
*match
;
306 struct mchp_tc_data
*priv
;
308 struct regmap
*regmap
;
313 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
317 platform_set_drvdata(pdev
, priv
);
319 match
= of_match_node(atmel_tc_of_match
, np
->parent
);
320 tcb_config
= match
->data
;
322 dev_err(&pdev
->dev
, "No matching parent node found\n");
326 regmap
= syscon_node_to_regmap(np
->parent
);
328 return PTR_ERR(regmap
);
330 /* max. channels number is 2 when in QDEC mode */
331 priv
->num_channels
= of_property_count_u32_elems(np
, "reg");
332 if (priv
->num_channels
< 0) {
333 dev_err(&pdev
->dev
, "Invalid or missing channel\n");
337 /* Register channels and initialize clocks */
338 for (i
= 0; i
< priv
->num_channels
; i
++) {
339 ret
= of_property_read_u32_index(np
, "reg", i
, &channel
);
340 if (ret
< 0 || channel
> 2)
343 priv
->channel
[i
] = channel
;
345 snprintf(clk_name
, sizeof(clk_name
), "t%d_clk", channel
);
347 clk
[i
] = of_clk_get_by_name(np
->parent
, clk_name
);
348 if (IS_ERR(clk
[i
])) {
349 /* Fallback to t0_clk */
350 clk
[i
] = of_clk_get_by_name(np
->parent
, "t0_clk");
352 return PTR_ERR(clk
[i
]);
355 ret
= clk_prepare_enable(clk
[i
]);
359 ret
= devm_add_action_or_reset(&pdev
->dev
,
366 "Initialized capture mode on channel %d\n",
370 priv
->tc_cfg
= tcb_config
;
371 priv
->regmap
= regmap
;
372 priv
->counter
.name
= dev_name(&pdev
->dev
);
373 priv
->counter
.parent
= &pdev
->dev
;
374 priv
->counter
.ops
= &mchp_tc_ops
;
375 priv
->counter
.num_counts
= ARRAY_SIZE(mchp_tc_counts
);
376 priv
->counter
.counts
= mchp_tc_counts
;
377 priv
->counter
.num_signals
= ARRAY_SIZE(mchp_tc_count_signals
);
378 priv
->counter
.signals
= mchp_tc_count_signals
;
379 priv
->counter
.priv
= priv
;
381 return devm_counter_register(&pdev
->dev
, &priv
->counter
);
384 static const struct of_device_id mchp_tc_dt_ids
[] = {
385 { .compatible
= "microchip,tcb-capture", },
388 MODULE_DEVICE_TABLE(of
, mchp_tc_dt_ids
);
390 static struct platform_driver mchp_tc_driver
= {
391 .probe
= mchp_tc_probe
,
393 .name
= "microchip-tcb-capture",
394 .of_match_table
= mchp_tc_dt_ids
,
397 module_platform_driver(mchp_tc_driver
);
399 MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
400 MODULE_DESCRIPTION("Microchip TCB Capture driver");
401 MODULE_LICENSE("GPL v2");