Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8-rc4 199 lines 4.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2017 Sean Young <sean@mess.org> 4 */ 5 6#include <linux/kernel.h> 7#include <linux/module.h> 8#include <linux/gpio/consumer.h> 9#include <linux/delay.h> 10#include <linux/slab.h> 11#include <linux/of.h> 12#include <linux/platform_device.h> 13#include <media/rc-core.h> 14 15#define DRIVER_NAME "gpio-ir-tx" 16#define DEVICE_NAME "GPIO IR Bit Banging Transmitter" 17 18struct gpio_ir { 19 struct gpio_desc *gpio; 20 unsigned int carrier; 21 unsigned int duty_cycle; 22 /* we need a spinlock to hold the cpu while transmitting */ 23 spinlock_t lock; 24}; 25 26static const struct of_device_id gpio_ir_tx_of_match[] = { 27 { .compatible = "gpio-ir-tx", }, 28 { }, 29}; 30MODULE_DEVICE_TABLE(of, gpio_ir_tx_of_match); 31 32static int gpio_ir_tx_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) 33{ 34 struct gpio_ir *gpio_ir = dev->priv; 35 36 gpio_ir->duty_cycle = duty_cycle; 37 38 return 0; 39} 40 41static int gpio_ir_tx_set_carrier(struct rc_dev *dev, u32 carrier) 42{ 43 struct gpio_ir *gpio_ir = dev->priv; 44 45 if (carrier > 500000) 46 return -EINVAL; 47 48 gpio_ir->carrier = carrier; 49 50 return 0; 51} 52 53static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, 54 uint count) 55{ 56 unsigned long flags; 57 ktime_t edge; 58 s32 delta; 59 int i; 60 61 spin_lock_irqsave(&gpio_ir->lock, flags); 62 63 edge = ktime_get(); 64 65 for (i = 0; i < count; i++) { 66 gpiod_set_value(gpio_ir->gpio, !(i % 2)); 67 68 edge = ktime_add_us(edge, txbuf[i]); 69 delta = ktime_us_delta(edge, ktime_get()); 70 if (delta > 0) 71 udelay(delta); 72 } 73 74 gpiod_set_value(gpio_ir->gpio, 0); 75 76 spin_unlock_irqrestore(&gpio_ir->lock, flags); 77} 78 79static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, 80 uint count) 81{ 82 unsigned long flags; 83 ktime_t edge; 84 /* 85 * delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on 86 * m68k ndelay(s64) does not compile; so use s32 rather than s64. 87 */ 88 s32 delta; 89 int i; 90 unsigned int pulse, space; 91 92 /* Ensure the dividend fits into 32 bit */ 93 pulse = DIV_ROUND_CLOSEST(gpio_ir->duty_cycle * (NSEC_PER_SEC / 100), 94 gpio_ir->carrier); 95 space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) * 96 (NSEC_PER_SEC / 100), gpio_ir->carrier); 97 98 spin_lock_irqsave(&gpio_ir->lock, flags); 99 100 edge = ktime_get(); 101 102 for (i = 0; i < count; i++) { 103 if (i % 2) { 104 // space 105 edge = ktime_add_us(edge, txbuf[i]); 106 delta = ktime_us_delta(edge, ktime_get()); 107 if (delta > 0) 108 udelay(delta); 109 } else { 110 // pulse 111 ktime_t last = ktime_add_us(edge, txbuf[i]); 112 113 while (ktime_before(ktime_get(), last)) { 114 gpiod_set_value(gpio_ir->gpio, 1); 115 edge = ktime_add_ns(edge, pulse); 116 delta = ktime_to_ns(ktime_sub(edge, 117 ktime_get())); 118 if (delta > 0) 119 ndelay(delta); 120 gpiod_set_value(gpio_ir->gpio, 0); 121 edge = ktime_add_ns(edge, space); 122 delta = ktime_to_ns(ktime_sub(edge, 123 ktime_get())); 124 if (delta > 0) 125 ndelay(delta); 126 } 127 128 edge = last; 129 } 130 } 131 132 spin_unlock_irqrestore(&gpio_ir->lock, flags); 133} 134 135static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf, 136 unsigned int count) 137{ 138 struct gpio_ir *gpio_ir = dev->priv; 139 140 if (gpio_ir->carrier) 141 gpio_ir_tx_modulated(gpio_ir, txbuf, count); 142 else 143 gpio_ir_tx_unmodulated(gpio_ir, txbuf, count); 144 145 return count; 146} 147 148static int gpio_ir_tx_probe(struct platform_device *pdev) 149{ 150 struct gpio_ir *gpio_ir; 151 struct rc_dev *rcdev; 152 int rc; 153 154 gpio_ir = devm_kmalloc(&pdev->dev, sizeof(*gpio_ir), GFP_KERNEL); 155 if (!gpio_ir) 156 return -ENOMEM; 157 158 rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); 159 if (!rcdev) 160 return -ENOMEM; 161 162 gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); 163 if (IS_ERR(gpio_ir->gpio)) { 164 if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER) 165 dev_err(&pdev->dev, "Failed to get gpio (%ld)\n", 166 PTR_ERR(gpio_ir->gpio)); 167 return PTR_ERR(gpio_ir->gpio); 168 } 169 170 rcdev->priv = gpio_ir; 171 rcdev->driver_name = DRIVER_NAME; 172 rcdev->device_name = DEVICE_NAME; 173 rcdev->tx_ir = gpio_ir_tx; 174 rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; 175 rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; 176 177 gpio_ir->carrier = 38000; 178 gpio_ir->duty_cycle = 50; 179 spin_lock_init(&gpio_ir->lock); 180 181 rc = devm_rc_register_device(&pdev->dev, rcdev); 182 if (rc < 0) 183 dev_err(&pdev->dev, "failed to register rc device\n"); 184 185 return rc; 186} 187 188static struct platform_driver gpio_ir_tx_driver = { 189 .probe = gpio_ir_tx_probe, 190 .driver = { 191 .name = DRIVER_NAME, 192 .of_match_table = of_match_ptr(gpio_ir_tx_of_match), 193 }, 194}; 195module_platform_driver(gpio_ir_tx_driver); 196 197MODULE_DESCRIPTION("GPIO IR Bit Banging Transmitter"); 198MODULE_AUTHOR("Sean Young <sean@mess.org>"); 199MODULE_LICENSE("GPL");