diff options
author | Davide Garberi <dade.garberi@gmail.com> | 2019-08-21 13:42:02 +0200 |
---|---|---|
committer | Michael Bestas <mkbestas@lineageos.org> | 2020-05-01 18:21:38 +0300 |
commit | 868513a4a7b79621eb897a6cf3d1569e58c213f6 (patch) | |
tree | ec4a9ca6c6d862063e45183bd7e9dcd9d73aab55 /drivers/misc | |
parent | 0a2e5d578b6f4b57374b096091ef4d0db8c85660 (diff) |
misc: Import ant_check
Change-Id: I3517b7834d14971e5fb8f37e88c8afe0e97f2433
Signed-off-by: Isaac Chen <tingyi364@gmail.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 8 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/ant_check.c | 300 |
3 files changed, 309 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 52f75b1faec0..efd1595cfc76 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -579,6 +579,14 @@ config MEMORY_STATE_TIME help Memory time statistics exported to /sys/kernel/memory_state_time +config ANT_CHECK + tristate "ant check gpio" + help + Say 'y' here to include support for the QTI QPNP MISC + peripheral. The MISC peripheral holds the USB ID interrupt + and the driver provides an API to check if this interrupt + is available on the current PMIC chip. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b0718228d2d9..7a259a230578 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -66,3 +66,4 @@ obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o obj-y += qcom/ obj-$(CONFIG_QPNP_MISC) += qpnp-misc.o obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o +obj-$(CONFIG_ANT_CHECK) += ant_check.o diff --git a/drivers/misc/ant_check.c b/drivers/misc/ant_check.c new file mode 100644 index 000000000000..05e05af635c2 --- /dev/null +++ b/drivers/misc/ant_check.c @@ -0,0 +1,300 @@ +#include <linux/init.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/wakelock.h> +#include <linux/delay.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/regulator/consumer.h> +#include <linux/fb.h> + +#define CONFIG_ANT_SYS + +struct ant_check_info +{ + struct mutex io_lock; + u32 irq_gpio; + u32 irq_gpio_flags; + int irq; + int ant_check_state; + struct input_dev *ipdev; +#ifdef CONFIG_ANT_SYS + struct class *ant_sys_class; +#endif +}; + +struct ant_check_info *global_ant_info; + +static irqreturn_t ant_interrupt(int irq, void *data) +{ + struct ant_check_info *ant_info = data; + int ant_gpio; + + ant_gpio = gpio_get_value_cansleep(ant_info->irq_gpio); + pr_err("Macle irq interrupt gpio = %d\n", ant_gpio); + if(ant_gpio == ant_info->ant_check_state){ + return IRQ_HANDLED; + }else{ + ant_info->ant_check_state = ant_gpio; + pr_err("Macle report key s "); + } + if (ant_gpio) { + input_report_key(ant_info->ipdev, KEY_ANT_CONNECT, 1); + input_report_key(ant_info->ipdev, KEY_ANT_CONNECT, 0); + input_sync(ant_info->ipdev); + }else{ + input_report_key(ant_info->ipdev, KEY_ANT_UNCONNECT, 1); + input_report_key(ant_info->ipdev, KEY_ANT_UNCONNECT, 0); + input_sync(ant_info->ipdev); + } + + + return IRQ_HANDLED; +} + +static int ant_parse_dt(struct device *dev, struct ant_check_info *pdata) +{ + struct device_node *np = dev->of_node; + + pdata->irq_gpio = of_get_named_gpio_flags(np, "ant_check_gpio", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + return pdata->irq_gpio; + + pr_info("Macle irq_gpio=%d\n", pdata->irq_gpio); + return 0; +} + + +#ifdef CONFIG_ANT_SYS +static ssize_t ant_state_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int state; + if (global_ant_info->ant_check_state) { + state = 3; + }else{ + state = 2; + } + pr_err("Macle ant_state_show state = %d, custome_state=%d\n", global_ant_info->ant_check_state, state); + return sprintf(buf, "%d\n", state); +} +#ifdef CONFIG_MACH_XIAOMI_WAYNE +static ssize_t ant_state_store(struct class *class, + struct class_attribute *attr, + const char *buf,size_t size) +{ + int rc =0; + int state = 0; + rc = kstrtoint(buf, 10, &state); + if (rc) { + pr_err("Macle kstrtoint failed.rc = %d\n", rc); + return rc; + } + if (state == 0) { + disable_irq(global_ant_info->irq); + printk("property disable ant_irq"); + }else{ + enable_irq(global_ant_info->irq); + printk("property enable ant_irq"); + } + return size; +} +#endif + +#ifdef CONFIG_MACH_XIAOMI_WAYNE +static struct class_attribute ant_state = + __ATTR(ant_state, S_IRUGO, ant_state_show, ant_state_store); +#else +static struct class_attribute ant_state = + __ATTR(ant_state, S_IRUGO, ant_state_show, NULL); +#endif + +static int ant_register_class_dev(struct ant_check_info *ant_info){ + int err; + if (!ant_info->ant_sys_class) { + ant_info->ant_sys_class = class_create(THIS_MODULE, "ant_class"); + if (IS_ERR(ant_info->ant_sys_class)){ + ant_info->ant_sys_class = NULL; + printk(KERN_ERR "could not allocate ant_class\n"); + return -1; + } + } + + err = class_create_file(ant_info->ant_sys_class, &ant_state); + if(err < 0){ + class_destroy(ant_info->ant_sys_class); + return -1; + } + return 0; +} +#endif + +static int ant_probe(struct platform_device *pdev) +{ + int rc = 0; + int err; + struct ant_check_info *ant_info; + pr_err("Macle ant_probe\n"); + + if (pdev->dev.of_node) { + ant_info = kzalloc(sizeof(struct ant_check_info), GFP_KERNEL); + if (!ant_info) { + pr_err("Macle %s: failed to alloc memory for module data\n",__func__); + return -ENOMEM; + } + err = ant_parse_dt(&pdev->dev, ant_info); + if (err) { + dev_err(&pdev->dev, "Macle ant_probe DT parsing failed\n"); + goto free_struct; + } + } else{ + return -ENOMEM; + } + mutex_init(&ant_info->io_lock); + + platform_set_drvdata(pdev, ant_info); + +/*input system config*/ + ant_info->ipdev = input_allocate_device(); + if (!ant_info->ipdev) { + pr_err("ant_probe: input_allocate_device fail\n"); + goto input_error; + } + ant_info->ipdev->name = "ant_check-input"; + input_set_capability(ant_info->ipdev, EV_KEY, KEY_ANT_CONNECT); + input_set_capability(ant_info->ipdev, EV_KEY, KEY_ANT_UNCONNECT); + set_bit(INPUT_PROP_NO_DUMMY_RELEASE, ant_info->ipdev->propbit); + rc = input_register_device(ant_info->ipdev); + if (rc) { + pr_err("ant_probe: input_register_device fail rc=%d\n", rc); + goto input_error; + } + + + + +/*interrupt config*/ + if (gpio_is_valid(ant_info->irq_gpio)) { + rc = gpio_request(ant_info->irq_gpio, "ant_check"); + if (rc < 0) { + pr_err("ant_probe: gpio_request fail rc=%d\n", rc); + goto free_input_device; + } + + rc = gpio_direction_input(ant_info->irq_gpio); + if (rc < 0) { + pr_err("ant_probe: gpio_direction_input fail rc=%d\n", rc); + goto err_irq; + } + ant_info->ant_check_state = gpio_get_value(ant_info->irq_gpio); + pr_err("ant_probe: gpios = %d, gpion=%d\n", ant_info->ant_check_state, ant_info->ant_check_state); + + ant_info->irq = gpio_to_irq(ant_info->irq_gpio); + pr_err("Macle irq = %d\n", ant_info->irq); +#ifdef CONFIG_MACH_XIAOMI_WAYNE + rc = request_irq(ant_info->irq, +#else + rc = devm_request_threaded_irq(&pdev->dev, ant_info->irq, NULL, +#endif + ant_interrupt, + IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_ONESHOT, "ant-switch-irq", ant_info); + if (rc < 0) { + pr_err("ant_probe: request_irq fail rc=%d\n", rc); + goto err_irq; + } +#ifdef CONFIG_MACH_XIAOMI_WAYNE + printk("D2S CN disable ant irq"); + disable_irq(ant_info->irq); +#else + device_init_wakeup(&pdev->dev, true); + irq_set_irq_wake(ant_info->irq,1); +#endif + }else{ + pr_err("Macle irq gpio not provided\n"); + goto free_input_device; + } + pr_err("ant_probe end\n"); +#ifdef CONFIG_ANT_SYS + ant_register_class_dev(ant_info); +#endif + global_ant_info = ant_info; + return 0; +err_irq: +#ifdef CONFIG_MACH_XIAOMI_WAYNE + disable_irq(ant_info->irq); +#else + disable_irq_wake(ant_info->irq); + device_init_wakeup(&pdev->dev, 0); +#endif + gpio_free(ant_info->irq_gpio); + +free_input_device: + input_unregister_device(ant_info->ipdev); + +input_error: + platform_set_drvdata(pdev, NULL); +free_struct: + kfree(ant_info); + + return rc; +} + +static int ant_remove(struct platform_device *pdev) +{ + struct ant_check_info *ant = platform_get_drvdata(pdev); +#ifdef CONFIG_ANT_SYS + class_destroy(ant->ant_sys_class); +#endif + pr_err("ant_remove\n"); +#ifdef CONFIG_MACH_XIAOMI_WAYNE + disable_irq(ant->irq); +#else + disable_irq_wake(ant->irq); + device_init_wakeup(&pdev->dev, 0); +#endif + free_irq(ant->irq, ant->ipdev); + gpio_free(ant->irq_gpio); + input_unregister_device(ant->ipdev); + return 0; +} + + + +static struct of_device_id sn_match_table[] = { + { .compatible = "ant_check", }, + { }, +}; + +static struct platform_driver ant_driver = { + .probe = ant_probe, + .remove = ant_remove, + .driver = { + .name = "ant_check", + .owner = THIS_MODULE, + .of_match_table = sn_match_table, + }, +}; + +static int __init ant_init(void) +{ + return platform_driver_register(&ant_driver); +} + +static void __exit ant_exit(void) +{ + platform_driver_unregister(&ant_driver); +} + +module_init(ant_init); +module_exit(ant_exit); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("lisuyang"); |