diff -drupN a/drivers/input/keyboard/sunxi-gpio-ir-tx.c b/drivers/input/keyboard/sunxi-gpio-ir-tx.c --- a/drivers/input/keyboard/sunxi-gpio-ir-tx.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/input/keyboard/sunxi-gpio-ir-tx.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,273 @@ +/* + * drivers/input/keyboard/sunxi-gpio-ir-tx.c + * + * Copyright (c) 2013-2018 Allwinnertech Co., Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sunxi-gpio-ir-tx.h" + +/*DEBUG_INIT | DEBUG_INT | DEBUG_DATA_INFO | DEBUG_ERR;*/ +static u32 debug_mask = 0x13; + +#define dprintk(level_mask, fmt, arg...) \ +do { \ + if (unlikely(debug_mask & level_mask)) \ + pr_warn("%s()%d - "fmt, __func__, __LINE__, ##arg); \ +} while (0) + +#define IR_TX_GPIO_NAME "ir_gpio_tx" +#define GPIO_IR_RX_DRIVER_NAME "sunxi-gpio-ir-tx" + +#define GPIO_IR_HEADER_CODE0 0x04 /* Custom code 0*/ +#define GPIO_IR_HEADER_CODE1 0xFB /* Custom code 1*/ +#define CARRIER_1MS (10000/264) +#define CARRIER_9MS (90000/264) +#define CARRIER_560US (5600/264) + + +struct gpio_ir_tx_info { + unsigned int tx_gpio; + struct kobject *kobj; +}; + +struct gpio_ir_tx_info *tx_info; + +static DEFINE_MUTEX(sysfs_lock); +static DEFINE_SPINLOCK(lock); +static DEFINE_SPINLOCK(carrier); + +//·¢ËÍÔØ²¨ +void sendcarrier(int unum) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&carrier, flags); //½ûÖ¹ÖÐ¶Ï + + for (i = 0; i < unum; i++) { + gpio_set_value(tx_info->tx_gpio, 1); + udelay(13); + gpio_set_value(tx_info->tx_gpio, 0); + udelay(13); + ndelay(400); + } + gpio_set_value(tx_info->tx_gpio, 0); + + spin_unlock_irqrestore(&carrier, flags); +} + +void sendIrBit(unsigned char bit) +{ + sendcarrier(CARRIER_560US); + udelay(bit == 0x00 ? 560 : 1690); +} + +void sendIrByte(unsigned char data) +{ + unsigned char uMask = 0x01; + + while (uMask) { + /*low bit first*/ + sendIrBit(data & uMask); + uMask <<= 1; + } +} + +void sendIrInt(unsigned int data) +{ + unsigned int uMask = 0x01; + + while (uMask) { + sendIrBit(data & uMask); + uMask <<= 1; + } +} + +static ssize_t gpio_ir_send_code(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int key, keyOpposite; + unsigned long flags; + + dprintk(DEBUG_DATA_INFO, "gpio send buf: %s", buf); + + if (sscanf(buf, "%d", &key) != 1) { + dprintk(DEBUG_ERR, "error input key code\n"); + return -EINVAL; + } + + keyOpposite = ~key; + dprintk(DEBUG_DATA_INFO, "key 0x%x, keyOpp 0x%x\n", key, keyOpposite); + + spin_lock_irqsave(&lock, flags); + /*leader code*/ + sendcarrier(CARRIER_9MS); + mdelay(4); + udelay(500); + + /*addr code*/ + sendIrByte(GPIO_IR_HEADER_CODE0); + sendIrByte(GPIO_IR_HEADER_CODE1); + + /*data code*/ + sendIrByte((unsigned char)key); + sendIrByte((unsigned char)keyOpposite); + sendcarrier(CARRIER_560US); + + spin_unlock_irqrestore(&lock, flags); + dprintk(DEBUG_DATA_INFO, "ir code send finished\n"); + + return size; +} + +static const DEVICE_ATTR(ir_code, 0644, NULL, gpio_ir_send_code); + +static ssize_t gpio_ir_send_repeat(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int i, num; + unsigned long flags; + + dprintk(DEBUG_DATA_INFO, "ir test buf is %s", buf); + + if (sscanf(buf, "%d", &num) != 1) + return -EINVAL; + + dprintk(DEBUG_DATA_INFO, "repeat num is %d, tx pin %d\n", + num, tx_info->tx_gpio); + + /*repeat code*/ + for (i = 0; i < num; i++) { + spin_lock_irqsave(&lock, flags); + /*repeat leader code*/ + sendcarrier(CARRIER_9MS); + mdelay(2); + udelay(250); + sendcarrier(CARRIER_560US); + spin_unlock_irqrestore(&lock, flags); + msleep(100); + } + + return size; +} + +static const DEVICE_ATTR(ir_repeat, 0644, NULL, gpio_ir_send_repeat); + +static const struct attribute *ir_tx_attrs[] = { + &dev_attr_ir_code.attr, + &dev_attr_ir_repeat.attr, + + NULL, +}; + +static const struct attribute_group tx_info_attrs_group = { + .attrs = (struct attribute **)ir_tx_attrs, +}; + +static int __init gpio_ir_tx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_config config; + int ret = 0; + + dprintk(DEBUG_INIT, "enter gpio ir rx probe\n"); + tx_info = devm_kzalloc(dev, sizeof(struct gpio_ir_tx_info), GFP_KERNEL); + if (!tx_info) { + dev_err(dev, "can't allocate gpio ir-tx memory\n"); + return -ENOMEM; + } + /*ir gpio tx pin*/ + tx_info->tx_gpio = of_get_named_gpio_flags(dev->of_node, + "gpio-tx", 0, + (enum of_gpio_flags *)&config); + + dprintk(DEBUG_INIT, "%s, line: %d, gpio ir tx: %d!\n", + __func__, __LINE__, tx_info->tx_gpio); + + ret = devm_gpio_request(dev, tx_info->tx_gpio, "ir_tx_gpio"); + if (ret < 0) { + dev_err(dev, "error: can't request ir tx gpio %d\n", + tx_info->tx_gpio); + goto err_free_mem; + } + + ret = gpio_direction_output(tx_info->tx_gpio, 0); + if (ret < 0) { + dev_err(dev, "error: can't set output direction\n"); + goto err_free_gpio; + } + + tx_info->kobj = kobject_create_and_add(IR_TX_GPIO_NAME, NULL); + if (!tx_info->kobj) + goto err_free_gpio; + + ret = sysfs_create_group(tx_info->kobj, &tx_info_attrs_group); + if (ret) + kobject_put(tx_info->kobj); + + dprintk(DEBUG_INIT, "%s, line: %d succeed\n", __func__, __LINE__); + + return ret; + +err_free_gpio: + gpio_free(tx_info->tx_gpio); + +err_free_mem: + devm_kfree(dev, tx_info); + return ret; +} + + +static int gpio_ir_tx_remove(struct platform_device *pdev) +{ + kobject_put(tx_info->kobj); + gpio_free(tx_info->tx_gpio); + return 0; +} + +static const struct of_device_id gpio_ir_tx_match[] = { + { .compatible = "allwinner,gpio-ir-tx", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_ir_tx_match); + +static struct platform_driver gpio_ir_tx_driver = { + .driver = { + .name = GPIO_IR_RX_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = gpio_ir_tx_match, + }, + .probe = gpio_ir_tx_probe, + .remove = gpio_ir_tx_remove, +}; + +module_platform_driver(gpio_ir_tx_driver); +module_param_named(debug_mask, debug_mask, int, 0644); +MODULE_DESCRIPTION("Remote GPIO IR TX driver"); +MODULE_AUTHOR("xudong"); +MODULE_LICENSE("GPL");