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 const enum counter_function mchp_tc_count_functions
[] = {
41 [MCHP_TC_FUNCTION_INCREASE
] = COUNTER_FUNCTION_INCREASE
,
42 [MCHP_TC_FUNCTION_QUADRATURE
] = COUNTER_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 const 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
;
137 /* should never reach this path */
141 regmap_write(priv
->regmap
, ATMEL_TC_BMR
, bmr
);
142 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), cmr
);
144 /* Enable clock and trigger counter */
145 regmap_write(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CCR
),
146 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
148 if (priv
->qdec_mode
) {
149 regmap_write(priv
->regmap
,
150 ATMEL_TC_REG(priv
->channel
[1], CMR
), cmr
);
151 regmap_write(priv
->regmap
,
152 ATMEL_TC_REG(priv
->channel
[1], CCR
),
153 ATMEL_TC_CLKEN
| ATMEL_TC_SWTRG
);
159 static int mchp_tc_count_signal_read(struct counter_device
*counter
,
160 struct counter_signal
*signal
,
161 enum counter_signal_level
*lvl
)
163 struct mchp_tc_data
*const priv
= counter
->priv
;
167 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], SR
), &sr
);
169 if (priv
->trig_inverted
)
170 sigstatus
= (sr
& ATMEL_TC_MTIOB
);
172 sigstatus
= (sr
& ATMEL_TC_MTIOA
);
174 *lvl
= sigstatus
? COUNTER_SIGNAL_LEVEL_HIGH
: COUNTER_SIGNAL_LEVEL_LOW
;
179 static int mchp_tc_count_action_get(struct counter_device
*counter
,
180 struct counter_count
*count
,
181 struct counter_synapse
*synapse
,
184 struct mchp_tc_data
*const priv
= counter
->priv
;
187 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CMR
), &cmr
);
189 switch (cmr
& ATMEL_TC_ETRGEDG
) {
191 *action
= MCHP_TC_SYNAPSE_ACTION_NONE
;
193 case ATMEL_TC_ETRGEDG_RISING
:
194 *action
= MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
;
196 case ATMEL_TC_ETRGEDG_FALLING
:
197 *action
= MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
;
199 case ATMEL_TC_ETRGEDG_BOTH
:
200 *action
= MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
;
207 static int mchp_tc_count_action_set(struct counter_device
*counter
,
208 struct counter_count
*count
,
209 struct counter_synapse
*synapse
,
212 struct mchp_tc_data
*const priv
= counter
->priv
;
213 u32 edge
= ATMEL_TC_ETRGEDG_NONE
;
215 /* QDEC mode is rising edge only */
220 case MCHP_TC_SYNAPSE_ACTION_NONE
:
221 edge
= ATMEL_TC_ETRGEDG_NONE
;
223 case MCHP_TC_SYNAPSE_ACTION_RISING_EDGE
:
224 edge
= ATMEL_TC_ETRGEDG_RISING
;
226 case MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE
:
227 edge
= ATMEL_TC_ETRGEDG_FALLING
;
229 case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
:
230 edge
= ATMEL_TC_ETRGEDG_BOTH
;
233 /* should never reach this path */
237 return regmap_write_bits(priv
->regmap
,
238 ATMEL_TC_REG(priv
->channel
[0], CMR
),
239 ATMEL_TC_ETRGEDG
, edge
);
242 static int mchp_tc_count_read(struct counter_device
*counter
,
243 struct counter_count
*count
,
246 struct mchp_tc_data
*const priv
= counter
->priv
;
249 regmap_read(priv
->regmap
, ATMEL_TC_REG(priv
->channel
[0], CV
), &cnt
);
255 static struct counter_count mchp_tc_counts
[] = {
258 .name
= "Timer Counter",
259 .functions_list
= mchp_tc_count_functions
,
260 .num_functions
= ARRAY_SIZE(mchp_tc_count_functions
),
261 .synapses
= mchp_tc_count_synapses
,
262 .num_synapses
= ARRAY_SIZE(mchp_tc_count_synapses
),
266 static const struct counter_ops mchp_tc_ops
= {
267 .signal_read
= mchp_tc_count_signal_read
,
268 .count_read
= mchp_tc_count_read
,
269 .function_get
= mchp_tc_count_function_get
,
270 .function_set
= mchp_tc_count_function_set
,
271 .action_get
= mchp_tc_count_action_get
,
272 .action_set
= mchp_tc_count_action_set
275 static const struct atmel_tcb_config tcb_rm9200_config
= {
279 static const struct atmel_tcb_config tcb_sam9x5_config
= {
283 static const struct atmel_tcb_config tcb_sama5d2_config
= {
289 static const struct atmel_tcb_config tcb_sama5d3_config
= {
294 static const struct of_device_id atmel_tc_of_match
[] = {
295 { .compatible
= "atmel,at91rm9200-tcb", .data
= &tcb_rm9200_config
, },
296 { .compatible
= "atmel,at91sam9x5-tcb", .data
= &tcb_sam9x5_config
, },
297 { .compatible
= "atmel,sama5d2-tcb", .data
= &tcb_sama5d2_config
, },
298 { .compatible
= "atmel,sama5d3-tcb", .data
= &tcb_sama5d3_config
, },
302 static void mchp_tc_clk_remove(void *ptr
)
304 clk_disable_unprepare((struct clk
*)ptr
);
307 static int mchp_tc_probe(struct platform_device
*pdev
)
309 struct device_node
*np
= pdev
->dev
.of_node
;
310 const struct atmel_tcb_config
*tcb_config
;
311 const struct of_device_id
*match
;
312 struct mchp_tc_data
*priv
;
314 struct regmap
*regmap
;
319 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
323 platform_set_drvdata(pdev
, priv
);
325 match
= of_match_node(atmel_tc_of_match
, np
->parent
);
326 tcb_config
= match
->data
;
328 dev_err(&pdev
->dev
, "No matching parent node found\n");
332 regmap
= syscon_node_to_regmap(np
->parent
);
334 return PTR_ERR(regmap
);
336 /* max. channels number is 2 when in QDEC mode */
337 priv
->num_channels
= of_property_count_u32_elems(np
, "reg");
338 if (priv
->num_channels
< 0) {
339 dev_err(&pdev
->dev
, "Invalid or missing channel\n");
343 /* Register channels and initialize clocks */
344 for (i
= 0; i
< priv
->num_channels
; i
++) {
345 ret
= of_property_read_u32_index(np
, "reg", i
, &channel
);
346 if (ret
< 0 || channel
> 2)
349 priv
->channel
[i
] = channel
;
351 snprintf(clk_name
, sizeof(clk_name
), "t%d_clk", channel
);
353 clk
[i
] = of_clk_get_by_name(np
->parent
, clk_name
);
354 if (IS_ERR(clk
[i
])) {
355 /* Fallback to t0_clk */
356 clk
[i
] = of_clk_get_by_name(np
->parent
, "t0_clk");
358 return PTR_ERR(clk
[i
]);
361 ret
= clk_prepare_enable(clk
[i
]);
365 ret
= devm_add_action_or_reset(&pdev
->dev
,
372 "Initialized capture mode on channel %d\n",
376 priv
->tc_cfg
= tcb_config
;
377 priv
->regmap
= regmap
;
378 priv
->counter
.name
= dev_name(&pdev
->dev
);
379 priv
->counter
.parent
= &pdev
->dev
;
380 priv
->counter
.ops
= &mchp_tc_ops
;
381 priv
->counter
.num_counts
= ARRAY_SIZE(mchp_tc_counts
);
382 priv
->counter
.counts
= mchp_tc_counts
;
383 priv
->counter
.num_signals
= ARRAY_SIZE(mchp_tc_count_signals
);
384 priv
->counter
.signals
= mchp_tc_count_signals
;
385 priv
->counter
.priv
= priv
;
387 return devm_counter_register(&pdev
->dev
, &priv
->counter
);
390 static const struct of_device_id mchp_tc_dt_ids
[] = {
391 { .compatible
= "microchip,tcb-capture", },
394 MODULE_DEVICE_TABLE(of
, mchp_tc_dt_ids
);
396 static struct platform_driver mchp_tc_driver
= {
397 .probe
= mchp_tc_probe
,
399 .name
= "microchip-tcb-capture",
400 .of_match_table
= mchp_tc_dt_ids
,
403 module_platform_driver(mchp_tc_driver
);
405 MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
406 MODULE_DESCRIPTION("Microchip TCB Capture driver");
407 MODULE_LICENSE("GPL v2");