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
7 commit 363d0e56285e80cda997d41d94c22313b673557d upstream.
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.
12 Signed-off-by: Sean Young <sean@mess.org>
13 Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
15 drivers/media/rc/pwm-ir-tx.c | 83 +++++++++++++++++++++++++++++++++---
16 1 file changed, 78 insertions(+), 5 deletions(-)
18 --- a/drivers/media/rc/pwm-ir-tx.c
19 +++ b/drivers/media/rc/pwm-ir-tx.c
21 #include <linux/slab.h>
23 #include <linux/platform_device.h>
24 +#include <linux/hrtimer.h>
25 +#include <linux/completion.h>
26 #include <media/rc-core.h>
28 #define DRIVER_NAME "pwm-ir-tx"
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;
40 + const unsigned int *txbuf;
41 + unsigned int txbuf_len;
42 + unsigned int txbuf_index;
45 static const struct of_device_id pwm_ir_of_match[] = {
46 @@ -48,8 +56,8 @@ static int pwm_ir_set_carrier(struct rc_
50 -static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
52 +static int pwm_ir_tx_sleep(struct rc_dev *dev, unsigned int *txbuf,
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,
61 +static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf,
64 + struct pwm_ir *pwm_ir = dev->priv;
65 + struct pwm_device *pwm = pwm_ir->pwm;
66 + struct pwm_state state;
68 + pwm_init_state(pwm, &state);
70 + state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier);
71 + pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100);
73 + pwm_ir->txbuf = txbuf;
74 + pwm_ir->txbuf_len = count;
75 + pwm_ir->txbuf_index = 0;
76 + pwm_ir->state = &state;
78 + hrtimer_start(&pwm_ir->timer, 0, HRTIMER_MODE_REL);
80 + wait_for_completion(&pwm_ir->tx_done);
85 +static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer)
87 + struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer);
91 + * If we happen to hit an odd latency spike, loop through the
92 + * pulses until we catch up.
97 + pwm_ir->state->enabled = !(pwm_ir->txbuf_index % 2);
98 + pwm_apply_atomic(pwm_ir->pwm, pwm_ir->state);
100 + if (pwm_ir->txbuf_index >= pwm_ir->txbuf_len) {
101 + complete(&pwm_ir->tx_done);
103 + return HRTIMER_NORESTART;
106 + ns = US_TO_NS(pwm_ir->txbuf[pwm_ir->txbuf_index]);
107 + hrtimer_add_expires_ns(timer, ns);
109 + pwm_ir->txbuf_index++;
111 + now = timer->base->get_time();
112 + } while (hrtimer_get_expires_tv64(timer) < now);
114 + return HRTIMER_RESTART;
117 static int pwm_ir_probe(struct platform_device *pdev)
119 struct pwm_ir *pwm_ir;
120 @@ -102,10 +166,19 @@ static int pwm_ir_probe(struct platform_
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;
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;
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;