|
6 | 6 | */
|
7 | 7 | #include <linux/clk.h>
|
8 | 8 | #include <linux/counter.h>
|
| 9 | +#include <linux/interrupt.h> |
9 | 10 | #include <linux/mfd/syscon.h>
|
10 | 11 | #include <linux/module.h>
|
11 | 12 | #include <linux/mutex.h>
|
12 | 13 | #include <linux/of.h>
|
| 14 | +#include <linux/of_irq.h> |
13 | 15 | #include <linux/platform_device.h>
|
14 | 16 | #include <linux/regmap.h>
|
| 17 | +#include <uapi/linux/counter/microchip-tcb-capture.h> |
15 | 18 | #include <soc/at91/atmel_tcb.h>
|
16 | 19 |
|
17 | 20 | #define ATMEL_TC_CMR_MASK (ATMEL_TC_LDRA_RISING | ATMEL_TC_LDRB_FALLING | \
|
18 | 21 | ATMEL_TC_ETRGEDG_RISING | ATMEL_TC_LDBDIS | \
|
19 | 22 | ATMEL_TC_LDBSTOP)
|
20 | 23 |
|
| 24 | +#define ATMEL_TC_DEF_IRQS (ATMEL_TC_ETRGS | ATMEL_TC_COVFS | \ |
| 25 | + ATMEL_TC_LDRAS | ATMEL_TC_LDRBS | ATMEL_TC_CPCS) |
| 26 | + |
21 | 27 | #define ATMEL_TC_QDEN BIT(8)
|
22 | 28 | #define ATMEL_TC_POSEN BIT(9)
|
23 | 29 |
|
@@ -294,6 +300,65 @@ static const struct of_device_id atmel_tc_of_match[] = {
|
294 | 300 | { /* sentinel */ }
|
295 | 301 | };
|
296 | 302 |
|
| 303 | +static irqreturn_t mchp_tc_isr(int irq, void *dev_id) |
| 304 | +{ |
| 305 | + struct counter_device *const counter = dev_id; |
| 306 | + struct mchp_tc_data *const priv = counter_priv(counter); |
| 307 | + u32 sr, mask; |
| 308 | + |
| 309 | + regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], SR), &sr); |
| 310 | + regmap_read(priv->regmap, ATMEL_TC_REG(priv->channel[0], IMR), &mask); |
| 311 | + |
| 312 | + sr &= mask; |
| 313 | + if (!(sr & ATMEL_TC_ALL_IRQ)) |
| 314 | + return IRQ_NONE; |
| 315 | + |
| 316 | + if (sr & ATMEL_TC_ETRGS) |
| 317 | + counter_push_event(counter, COUNTER_EVENT_CHANGE_OF_STATE, |
| 318 | + COUNTER_MCHP_EVCHN_CV); |
| 319 | + if (sr & ATMEL_TC_LDRAS) |
| 320 | + counter_push_event(counter, COUNTER_EVENT_CAPTURE, |
| 321 | + COUNTER_MCHP_EVCHN_RA); |
| 322 | + if (sr & ATMEL_TC_LDRBS) |
| 323 | + counter_push_event(counter, COUNTER_EVENT_CAPTURE, |
| 324 | + COUNTER_MCHP_EVCHN_RB); |
| 325 | + if (sr & ATMEL_TC_CPCS) |
| 326 | + counter_push_event(counter, COUNTER_EVENT_THRESHOLD, |
| 327 | + COUNTER_MCHP_EVCHN_RC); |
| 328 | + if (sr & ATMEL_TC_COVFS) |
| 329 | + counter_push_event(counter, COUNTER_EVENT_OVERFLOW, |
| 330 | + COUNTER_MCHP_EVCHN_CV); |
| 331 | + |
| 332 | + return IRQ_HANDLED; |
| 333 | +} |
| 334 | + |
| 335 | +static void mchp_tc_irq_remove(void *ptr) |
| 336 | +{ |
| 337 | + struct mchp_tc_data *priv = ptr; |
| 338 | + |
| 339 | + regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], IDR), ATMEL_TC_DEF_IRQS); |
| 340 | +} |
| 341 | + |
| 342 | +static int mchp_tc_irq_enable(struct counter_device *const counter, int irq) |
| 343 | +{ |
| 344 | + struct mchp_tc_data *const priv = counter_priv(counter); |
| 345 | + int ret = devm_request_irq(counter->parent, irq, mchp_tc_isr, 0, |
| 346 | + dev_name(counter->parent), counter); |
| 347 | + |
| 348 | + if (ret < 0) |
| 349 | + return ret; |
| 350 | + |
| 351 | + ret = regmap_write(priv->regmap, ATMEL_TC_REG(priv->channel[0], IER), ATMEL_TC_DEF_IRQS); |
| 352 | + if (ret < 0) |
| 353 | + return ret; |
| 354 | + |
| 355 | + ret = devm_add_action_or_reset(counter->parent, mchp_tc_irq_remove, priv); |
| 356 | + if (ret < 0) |
| 357 | + return ret; |
| 358 | + |
| 359 | + return 0; |
| 360 | +} |
| 361 | + |
297 | 362 | static void mchp_tc_clk_remove(void *ptr)
|
298 | 363 | {
|
299 | 364 | clk_disable_unprepare((struct clk *)ptr);
|
@@ -378,6 +443,15 @@ static int mchp_tc_probe(struct platform_device *pdev)
|
378 | 443 | counter->num_signals = ARRAY_SIZE(mchp_tc_count_signals);
|
379 | 444 | counter->signals = mchp_tc_count_signals;
|
380 | 445 |
|
| 446 | + i = of_irq_get(np->parent, 0); |
| 447 | + if (i == -EPROBE_DEFER) |
| 448 | + return -EPROBE_DEFER; |
| 449 | + if (i > 0) { |
| 450 | + ret = mchp_tc_irq_enable(counter, i); |
| 451 | + if (ret < 0) |
| 452 | + return dev_err_probe(&pdev->dev, ret, "Failed to set up IRQ"); |
| 453 | + } |
| 454 | + |
381 | 455 | ret = devm_counter_add(&pdev->dev, counter);
|
382 | 456 | if (ret < 0)
|
383 | 457 | return dev_err_probe(&pdev->dev, ret, "Failed to add counter\n");
|
|
0 commit comments