diff options
Diffstat (limited to 'drivers/media/rc/gpio-ir-tx.c')
| -rw-r--r-- | drivers/media/rc/gpio-ir-tx.c | 99 |
1 files changed, 64 insertions, 35 deletions
diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index cd476cab9782..e185ead40464 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2017 Sean Young <sean@mess.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -27,8 +19,6 @@ struct gpio_ir { struct gpio_desc *gpio; unsigned int carrier; unsigned int duty_cycle; - /* we need a spinlock to hold the cpu while transmitting */ - spinlock_t lock; }; static const struct of_device_id gpio_ir_tx_of_match[] = { @@ -50,7 +40,7 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) { struct gpio_ir *gpio_ir = dev->priv; - if (!carrier) + if (carrier > 500000) return -EINVAL; gpio_ir->carrier = carrier; @@ -58,11 +48,51 @@ static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) return 0; } -static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, - unsigned int count) +static void delay_until(ktime_t until) +{ + /* + * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on + * m68k ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; + + while (true) { + delta = ktime_us_delta(until, ktime_get()); + if (delta <= 0) + return; + + /* udelay more than 1ms may not work */ + if (delta >= 1000) { + mdelay(delta / 1000); + continue; + } + + udelay(delta); + break; + } +} + +static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, + uint count) +{ + ktime_t edge; + int i; + + edge = ktime_get(); + + for (i = 0; i < count; i++) { + gpiod_set_value(gpio_ir->gpio, !(i % 2)); + + edge = ktime_add_us(edge, txbuf[i]); + delay_until(edge); + } + + gpiod_set_value(gpio_ir->gpio, 0); +} + +static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, + uint count) { - struct gpio_ir *gpio_ir = dev->priv; - unsigned long flags; ktime_t edge; /* * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on @@ -78,22 +108,13 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) * (NSEC_PER_SEC / 100), gpio_ir->carrier); - spin_lock_irqsave(&gpio_ir->lock, flags); - edge = ktime_get(); for (i = 0; i < count; i++) { if (i % 2) { // space edge = ktime_add_us(edge, txbuf[i]); - delta = ktime_us_delta(edge, ktime_get()); - if (delta > 10) { - spin_unlock_irqrestore(&gpio_ir->lock, flags); - usleep_range(delta, delta + 10); - spin_lock_irqsave(&gpio_ir->lock, flags); - } else if (delta > 0) { - udelay(delta); - } + delay_until(edge); } else { // pulse ktime_t last = ktime_add_us(edge, txbuf[i]); @@ -116,8 +137,20 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, edge = last; } } +} - spin_unlock_irqrestore(&gpio_ir->lock, flags); +static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) +{ + struct gpio_ir *gpio_ir = dev->priv; + unsigned long flags; + + local_irq_save(flags); + if (gpio_ir->carrier) + gpio_ir_tx_modulated(gpio_ir, txbuf, count); + else + gpio_ir_tx_unmodulated(gpio_ir, txbuf, count); + local_irq_restore(flags); return count; } @@ -137,12 +170,9 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) return -ENOMEM; gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(gpio_ir->gpio)) { - if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get gpio (%ld)\n", - PTR_ERR(gpio_ir->gpio)); - return PTR_ERR(gpio_ir->gpio); - } + if (IS_ERR(gpio_ir->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(gpio_ir->gpio), + "Failed to get gpio\n"); rcdev->priv = gpio_ir; rcdev->driver_name = DRIVER_NAME; @@ -153,7 +183,6 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) gpio_ir->carrier = 38000; gpio_ir->duty_cycle = 50; - spin_lock_init(&gpio_ir->lock); rc = devm_rc_register_device(&pdev->dev, rcdev); if (rc < 0) @@ -166,7 +195,7 @@ static struct platform_driver gpio_ir_tx_driver = { .probe = gpio_ir_tx_probe, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(gpio_ir_tx_of_match), + .of_match_table = gpio_ir_tx_of_match, }, }; module_platform_driver(gpio_ir_tx_driver); |
