92e6c0e5d5d8dcce390626cc1f8322792867849a
[openwrt/staging/linusw.git] /
1 From 1db50b3b0222f6f9d89f30bfa8fd64457bd01bef Mon Sep 17 00:00:00 2001
2 From: Sean Young <sean@mess.org>
3 Date: Tue, 19 Dec 2023 16:30:29 +0000
4 Subject: [PATCH 0942/1085] media: pwm-ir-tx: Trigger edges from hrtimer
5 interrupt context
6
7 commit 363d0e56285e80cda997d41d94c22313b673557d upstream.
8
9 This makes the generated IR much more precise. Before this change, the
10 driver is unreliable and many users opted to use gpio-ir-tx instead.
11
12 Signed-off-by: Sean Young <sean@mess.org>
13 Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
14 ---
15 drivers/media/rc/pwm-ir-tx.c | 83 +++++++++++++++++++++++++++++++++---
16 1 file changed, 78 insertions(+), 5 deletions(-)
17
18 --- a/drivers/media/rc/pwm-ir-tx.c
19 +++ b/drivers/media/rc/pwm-ir-tx.c
20 @@ -10,6 +10,8 @@
21 #include <linux/slab.h>
22 #include <linux/of.h>
23 #include <linux/platform_device.h>
24 +#include <linux/hrtimer.h>
25 +#include <linux/completion.h>
26 #include <media/rc-core.h>
27
28 #define DRIVER_NAME "pwm-ir-tx"
29 @@ -17,8 +19,14 @@
30
31 struct pwm_ir {
32 struct pwm_device *pwm;
33 - unsigned int carrier;
34 - unsigned int duty_cycle;
35 + struct hrtimer timer;
36 + struct completion tx_done;
37 + struct pwm_state *state;
38 + u32 carrier;
39 + u32 duty_cycle;
40 + const unsigned int *txbuf;
41 + unsigned int txbuf_len;
42 + unsigned int txbuf_index;
43 };
44
45 static const struct of_device_id pwm_ir_of_match[] = {
46 @@ -48,8 +56,8 @@ static int pwm_ir_set_carrier(struct rc_
47 return 0;
48 }
49
50 -static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
51 - unsigned int count)
52 +static int pwm_ir_tx_sleep(struct rc_dev *dev, unsigned int *txbuf,
53 + unsigned int count)
54 {
55 struct pwm_ir *pwm_ir = dev->priv;
56 struct pwm_device *pwm = pwm_ir->pwm;
57 @@ -81,6 +89,62 @@ static int pwm_ir_tx(struct rc_dev *dev,
58 return count;
59 }
60
61 +static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf,
62 + unsigned int count)
63 +{
64 + struct pwm_ir *pwm_ir = dev->priv;
65 + struct pwm_device *pwm = pwm_ir->pwm;
66 + struct pwm_state state;
67 +
68 + pwm_init_state(pwm, &state);
69 +
70 + state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier);
71 + pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100);
72 +
73 + pwm_ir->txbuf = txbuf;
74 + pwm_ir->txbuf_len = count;
75 + pwm_ir->txbuf_index = 0;
76 + pwm_ir->state = &state;
77 +
78 + hrtimer_start(&pwm_ir->timer, 0, HRTIMER_MODE_REL);
79 +
80 + wait_for_completion(&pwm_ir->tx_done);
81 +
82 + return count;
83 +}
84 +
85 +static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer)
86 +{
87 + struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer);
88 + ktime_t now;
89 +
90 + /*
91 + * If we happen to hit an odd latency spike, loop through the
92 + * pulses until we catch up.
93 + */
94 + do {
95 + u64 ns;
96 +
97 + pwm_ir->state->enabled = !(pwm_ir->txbuf_index % 2);
98 + pwm_apply_atomic(pwm_ir->pwm, pwm_ir->state);
99 +
100 + if (pwm_ir->txbuf_index >= pwm_ir->txbuf_len) {
101 + complete(&pwm_ir->tx_done);
102 +
103 + return HRTIMER_NORESTART;
104 + }
105 +
106 + ns = US_TO_NS(pwm_ir->txbuf[pwm_ir->txbuf_index]);
107 + hrtimer_add_expires_ns(timer, ns);
108 +
109 + pwm_ir->txbuf_index++;
110 +
111 + now = timer->base->get_time();
112 + } while (hrtimer_get_expires_tv64(timer) < now);
113 +
114 + return HRTIMER_RESTART;
115 +}
116 +
117 static int pwm_ir_probe(struct platform_device *pdev)
118 {
119 struct pwm_ir *pwm_ir;
120 @@ -102,10 +166,19 @@ static int pwm_ir_probe(struct platform_
121 if (!rcdev)
122 return -ENOMEM;
123
124 + if (pwm_might_sleep(pwm_ir->pwm)) {
125 + dev_info(&pdev->dev, "TX will not be accurate as PWM device might sleep\n");
126 + rcdev->tx_ir = pwm_ir_tx_sleep;
127 + } else {
128 + init_completion(&pwm_ir->tx_done);
129 + hrtimer_init(&pwm_ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
130 + pwm_ir->timer.function = pwm_ir_timer;
131 + rcdev->tx_ir = pwm_ir_tx_atomic;
132 + }
133 +
134 rcdev->priv = pwm_ir;
135 rcdev->driver_name = DRIVER_NAME;
136 rcdev->device_name = DEVICE_NAME;
137 - rcdev->tx_ir = pwm_ir_tx;
138 rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle;
139 rcdev->s_tx_carrier = pwm_ir_set_carrier;
140