1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2017 Sean Young <sean@mess.org>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
9 #include <linux/delay.h>
10 #include <linux/slab.h>
12 #include <linux/platform_device.h>
13 #include <linux/hrtimer.h>
14 #include <linux/completion.h>
15 #include <media/rc-core.h>
17 #define DRIVER_NAME "pwm-ir-tx"
18 #define DEVICE_NAME "PWM IR Transmitter"
21 struct pwm_device
*pwm
;
23 struct completion tx_done
;
24 struct pwm_state
*state
;
27 const unsigned int *txbuf
;
28 unsigned int txbuf_len
;
29 unsigned int txbuf_index
;
32 static const struct of_device_id pwm_ir_of_match
[] = {
33 { .compatible
= "pwm-ir-tx", },
34 { .compatible
= "nokia,n900-ir" },
37 MODULE_DEVICE_TABLE(of
, pwm_ir_of_match
);
39 static int pwm_ir_set_duty_cycle(struct rc_dev
*dev
, u32 duty_cycle
)
41 struct pwm_ir
*pwm_ir
= dev
->priv
;
43 pwm_ir
->duty_cycle
= duty_cycle
;
48 static int pwm_ir_set_carrier(struct rc_dev
*dev
, u32 carrier
)
50 struct pwm_ir
*pwm_ir
= dev
->priv
;
55 pwm_ir
->carrier
= carrier
;
60 static int pwm_ir_tx_sleep(struct rc_dev
*dev
, unsigned int *txbuf
,
63 struct pwm_ir
*pwm_ir
= dev
->priv
;
64 struct pwm_device
*pwm
= pwm_ir
->pwm
;
65 struct pwm_state state
;
70 pwm_init_state(pwm
, &state
);
72 state
.period
= DIV_ROUND_CLOSEST(NSEC_PER_SEC
, pwm_ir
->carrier
);
73 pwm_set_relative_duty_cycle(&state
, pwm_ir
->duty_cycle
, 100);
77 for (i
= 0; i
< count
; i
++) {
78 state
.enabled
= !(i
% 2);
79 pwm_apply_might_sleep(pwm
, &state
);
81 edge
= ktime_add_us(edge
, txbuf
[i
]);
82 delta
= ktime_us_delta(edge
, ktime_get());
84 usleep_range(delta
, delta
+ 10);
87 state
.enabled
= false;
88 pwm_apply_might_sleep(pwm
, &state
);
93 static int pwm_ir_tx_atomic(struct rc_dev
*dev
, unsigned int *txbuf
,
96 struct pwm_ir
*pwm_ir
= dev
->priv
;
97 struct pwm_device
*pwm
= pwm_ir
->pwm
;
98 struct pwm_state state
;
100 pwm_init_state(pwm
, &state
);
102 state
.period
= DIV_ROUND_CLOSEST(NSEC_PER_SEC
, pwm_ir
->carrier
);
103 pwm_set_relative_duty_cycle(&state
, pwm_ir
->duty_cycle
, 100);
105 pwm_ir
->txbuf
= txbuf
;
106 pwm_ir
->txbuf_len
= count
;
107 pwm_ir
->txbuf_index
= 0;
108 pwm_ir
->state
= &state
;
110 hrtimer_start(&pwm_ir
->timer
, 0, HRTIMER_MODE_REL
);
112 wait_for_completion(&pwm_ir
->tx_done
);
117 static enum hrtimer_restart
pwm_ir_timer(struct hrtimer
*timer
)
119 struct pwm_ir
*pwm_ir
= container_of(timer
, struct pwm_ir
, timer
);
123 * If we happen to hit an odd latency spike, loop through the
124 * pulses until we catch up.
129 pwm_ir
->state
->enabled
= !(pwm_ir
->txbuf_index
% 2);
130 pwm_apply_atomic(pwm_ir
->pwm
, pwm_ir
->state
);
132 if (pwm_ir
->txbuf_index
>= pwm_ir
->txbuf_len
) {
133 complete(&pwm_ir
->tx_done
);
135 return HRTIMER_NORESTART
;
138 ns
= US_TO_NS(pwm_ir
->txbuf
[pwm_ir
->txbuf_index
]);
139 hrtimer_add_expires_ns(timer
, ns
);
141 pwm_ir
->txbuf_index
++;
143 now
= timer
->base
->get_time();
144 } while (hrtimer_get_expires_tv64(timer
) < now
);
146 return HRTIMER_RESTART
;
149 static int pwm_ir_probe(struct platform_device
*pdev
)
151 struct pwm_ir
*pwm_ir
;
152 struct rc_dev
*rcdev
;
155 pwm_ir
= devm_kmalloc(&pdev
->dev
, sizeof(*pwm_ir
), GFP_KERNEL
);
159 pwm_ir
->pwm
= devm_pwm_get(&pdev
->dev
, NULL
);
160 if (IS_ERR(pwm_ir
->pwm
))
161 return PTR_ERR(pwm_ir
->pwm
);
163 pwm_ir
->carrier
= 38000;
164 pwm_ir
->duty_cycle
= 50;
166 rcdev
= devm_rc_allocate_device(&pdev
->dev
, RC_DRIVER_IR_RAW_TX
);
170 if (pwm_might_sleep(pwm_ir
->pwm
)) {
171 dev_info(&pdev
->dev
, "TX will not be accurate as PWM device might sleep\n");
172 rcdev
->tx_ir
= pwm_ir_tx_sleep
;
174 init_completion(&pwm_ir
->tx_done
);
175 hrtimer_init(&pwm_ir
->timer
, CLOCK_MONOTONIC
, HRTIMER_MODE_REL
);
176 pwm_ir
->timer
.function
= pwm_ir_timer
;
177 rcdev
->tx_ir
= pwm_ir_tx_atomic
;
180 rcdev
->priv
= pwm_ir
;
181 rcdev
->driver_name
= DRIVER_NAME
;
182 rcdev
->device_name
= DEVICE_NAME
;
183 rcdev
->s_tx_duty_cycle
= pwm_ir_set_duty_cycle
;
184 rcdev
->s_tx_carrier
= pwm_ir_set_carrier
;
186 rc
= devm_rc_register_device(&pdev
->dev
, rcdev
);
188 dev_err(&pdev
->dev
, "failed to register rc device\n");
193 static struct platform_driver pwm_ir_driver
= {
194 .probe
= pwm_ir_probe
,
197 .of_match_table
= pwm_ir_of_match
,
200 module_platform_driver(pwm_ir_driver
);
202 MODULE_DESCRIPTION("PWM IR Transmitter");
203 MODULE_AUTHOR("Sean Young <sean@mess.org>");
204 MODULE_LICENSE("GPL");