mirror of https://github.com/OpenIPC/firmware.git
278 lines
6.7 KiB
Diff
278 lines
6.7 KiB
Diff
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 <linux/module.h>
|
||
+#include <linux/init.h>
|
||
+#include <linux/delay.h>
|
||
+#include <linux/platform_device.h>
|
||
+#include <linux/gpio.h>
|
||
+#include <linux/kernel.h>
|
||
+#include <linux/pm.h>
|
||
+#include <linux/arisc/arisc.h>
|
||
+#include <asm/irq.h>
|
||
+#include <linux/io.h>
|
||
+#include <linux/of.h>
|
||
+#include <linux/of_device.h>
|
||
+#include <linux/sunxi-gpio.h>
|
||
+#include <linux/of_gpio.h>
|
||
+
|
||
+#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);
|
||
+
|
||
+//<2F><><EFBFBD><EFBFBD><EFBFBD>ز<EFBFBD>
|
||
+void sendcarrier(int unum)
|
||
+{
|
||
+ int i;
|
||
+ unsigned long flags;
|
||
+
|
||
+ spin_lock_irqsave(&carrier, flags); //<2F><>ֹ<EFBFBD>ж<EFBFBD>
|
||
+
|
||
+ 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");
|