Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2017 Sean Young <sean@mess.org>
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/gpio/consumer.h>
0009 #include <linux/delay.h>
0010 #include <linux/slab.h>
0011 #include <linux/of.h>
0012 #include <linux/platform_device.h>
0013 #include <media/rc-core.h>
0014 
0015 #define DRIVER_NAME "gpio-ir-tx"
0016 #define DEVICE_NAME "GPIO IR Bit Banging Transmitter"
0017 
0018 struct gpio_ir {
0019     struct gpio_desc *gpio;
0020     unsigned int carrier;
0021     unsigned int duty_cycle;
0022 };
0023 
0024 static const struct of_device_id gpio_ir_tx_of_match[] = {
0025     { .compatible = "gpio-ir-tx", },
0026     { },
0027 };
0028 MODULE_DEVICE_TABLE(of, gpio_ir_tx_of_match);
0029 
0030 static int gpio_ir_tx_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
0031 {
0032     struct gpio_ir *gpio_ir = dev->priv;
0033 
0034     gpio_ir->duty_cycle = duty_cycle;
0035 
0036     return 0;
0037 }
0038 
0039 static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier)
0040 {
0041     struct gpio_ir *gpio_ir = dev->priv;
0042 
0043     if (carrier > 500000)
0044         return -EINVAL;
0045 
0046     gpio_ir->carrier = carrier;
0047 
0048     return 0;
0049 }
0050 
0051 static void delay_until(ktime_t until)
0052 {
0053     /*
0054      * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on
0055      * m68k ndelay(s64) does not compile; so use s32 rather than s64.
0056      */
0057     s32 delta;
0058 
0059     while (true) {
0060         delta = ktime_us_delta(until, ktime_get());
0061         if (delta <= 0)
0062             return;
0063 
0064         /* udelay more than 1ms may not work */
0065         if (delta >= 1000) {
0066             mdelay(delta / 1000);
0067             continue;
0068         }
0069 
0070         udelay(delta);
0071         break;
0072     }
0073 }
0074 
0075 static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
0076                    uint count)
0077 {
0078     ktime_t edge;
0079     int i;
0080 
0081     local_irq_disable();
0082 
0083     edge = ktime_get();
0084 
0085     for (i = 0; i < count; i++) {
0086         gpiod_set_value(gpio_ir->gpio, !(i % 2));
0087 
0088         edge = ktime_add_us(edge, txbuf[i]);
0089         delay_until(edge);
0090     }
0091 
0092     gpiod_set_value(gpio_ir->gpio, 0);
0093 }
0094 
0095 static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
0096                  uint count)
0097 {
0098     ktime_t edge;
0099     /*
0100      * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on
0101      * m68k ndelay(s64) does not compile; so use s32 rather than s64.
0102      */
0103     s32 delta;
0104     int i;
0105     unsigned int pulse, space;
0106 
0107     /* Ensure the dividend fits into 32 bit */
0108     pulse = DIV_ROUND_CLOSEST(gpio_ir->duty_cycle * (NSEC_PER_SEC / 100),
0109                   gpio_ir->carrier);
0110     space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) *
0111                   (NSEC_PER_SEC / 100), gpio_ir->carrier);
0112 
0113     local_irq_disable();
0114 
0115     edge = ktime_get();
0116 
0117     for (i = 0; i < count; i++) {
0118         if (i % 2) {
0119             // space
0120             edge = ktime_add_us(edge, txbuf[i]);
0121             delay_until(edge);
0122         } else {
0123             // pulse
0124             ktime_t last = ktime_add_us(edge, txbuf[i]);
0125 
0126             while (ktime_before(ktime_get(), last)) {
0127                 gpiod_set_value(gpio_ir->gpio, 1);
0128                 edge = ktime_add_ns(edge, pulse);
0129                 delta = ktime_to_ns(ktime_sub(edge,
0130                                   ktime_get()));
0131                 if (delta > 0)
0132                     ndelay(delta);
0133                 gpiod_set_value(gpio_ir->gpio, 0);
0134                 edge = ktime_add_ns(edge, space);
0135                 delta = ktime_to_ns(ktime_sub(edge,
0136                                   ktime_get()));
0137                 if (delta > 0)
0138                     ndelay(delta);
0139             }
0140 
0141             edge = last;
0142         }
0143     }
0144 }
0145 
0146 static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
0147               unsigned int count)
0148 {
0149     struct gpio_ir *gpio_ir = dev->priv;
0150     unsigned long flags;
0151 
0152     local_irq_save(flags);
0153     if (gpio_ir->carrier)
0154         gpio_ir_tx_modulated(gpio_ir, txbuf, count);
0155     else
0156         gpio_ir_tx_unmodulated(gpio_ir, txbuf, count);
0157     local_irq_restore(flags);
0158 
0159     return count;
0160 }
0161 
0162 static int gpio_ir_tx_probe(struct platform_device *pdev)
0163 {
0164     struct gpio_ir *gpio_ir;
0165     struct rc_dev *rcdev;
0166     int rc;
0167 
0168     gpio_ir = devm_kmalloc(&pdev->dev, sizeof(*gpio_ir), GFP_KERNEL);
0169     if (!gpio_ir)
0170         return -ENOMEM;
0171 
0172     rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX);
0173     if (!rcdev)
0174         return -ENOMEM;
0175 
0176     gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
0177     if (IS_ERR(gpio_ir->gpio)) {
0178         if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER)
0179             dev_err(&pdev->dev, "Failed to get gpio (%ld)\n",
0180                 PTR_ERR(gpio_ir->gpio));
0181         return PTR_ERR(gpio_ir->gpio);
0182     }
0183 
0184     rcdev->priv = gpio_ir;
0185     rcdev->driver_name = DRIVER_NAME;
0186     rcdev->device_name = DEVICE_NAME;
0187     rcdev->tx_ir = gpio_ir_tx;
0188     rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle;
0189     rcdev->s_tx_carrier = gpio_ir_tx_set_carrier;
0190 
0191     gpio_ir->carrier = 38000;
0192     gpio_ir->duty_cycle = 50;
0193 
0194     rc = devm_rc_register_device(&pdev->dev, rcdev);
0195     if (rc < 0)
0196         dev_err(&pdev->dev, "failed to register rc device\n");
0197 
0198     return rc;
0199 }
0200 
0201 static struct platform_driver gpio_ir_tx_driver = {
0202     .probe  = gpio_ir_tx_probe,
0203     .driver = {
0204         .name   = DRIVER_NAME,
0205         .of_match_table = of_match_ptr(gpio_ir_tx_of_match),
0206     },
0207 };
0208 module_platform_driver(gpio_ir_tx_driver);
0209 
0210 MODULE_DESCRIPTION("GPIO IR Bit Banging Transmitter");
0211 MODULE_AUTHOR("Sean Young <sean@mess.org>");
0212 MODULE_LICENSE("GPL");