armbian_build/patch/kernel/archive/sm8250-6.5/0020-drivers-input-misc-add-xiaomi-keyboard-vendor-driver.patch
Ricardo Pardini bf6b4b3cce sm8250 edge 6.5: rewrite patches, no changes
- done with `./compile.sh BOARD=xiaomi-elish BRANCH=sm8250 rewrite-kernel-patches`
2023-10-26 21:17:01 +08:00

724 lines
20 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: amazingfate <liujianfeng1994@gmail.com>
Date: Mon, 16 Oct 2023 13:29:58 +0800
Subject: drivers/input/misc: add xiaomi keyboard vendor driver
---
drivers/input/misc/Kconfig | 1 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/xiaomi_keyboard/Kconfig | 8 +
drivers/input/misc/xiaomi_keyboard/Makefile | 1 +
drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.c | 608 ++++++++++
drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.h | 45 +
6 files changed, 664 insertions(+)
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 8a320e6218e3..9cff88458f38 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -939,4 +939,5 @@ config INPUT_STPMIC1_ONKEY
To compile this driver as a module, choose M here: the
module will be called stpmic1_onkey.
+source "drivers/input/misc/xiaomi_keyboard/Kconfig"
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 04296a4abe8e..83773d457387 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -90,3 +90,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_XIAOMI_KEYBOARD) += xiaomi_keyboard/
diff --git a/drivers/input/misc/xiaomi_keyboard/Kconfig b/drivers/input/misc/xiaomi_keyboard/Kconfig
new file mode 100644
index 000000000000..bfc4b1d891e5
--- /dev/null
+++ b/drivers/input/misc/xiaomi_keyboard/Kconfig
@@ -0,0 +1,8 @@
+config XIAOMI_KEYBOARD
+ bool "xiaomi keyboard control-driver"
+ depends on INPUT
+ default n
+ help
+ Say Y here, compile xiaomi keyboard control driver.
+
+ If unsure, say N.
diff --git a/drivers/input/misc/xiaomi_keyboard/Makefile b/drivers/input/misc/xiaomi_keyboard/Makefile
new file mode 100644
index 000000000000..0a00118c658e
--- /dev/null
+++ b/drivers/input/misc/xiaomi_keyboard/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_XIAOMI_KEYBOARD) += xiaomi_keyboard.o
\ No newline at end of file
diff --git a/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.c b/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.c
new file mode 100644
index 000000000000..a7a736f3c1e8
--- /dev/null
+++ b/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.c
@@ -0,0 +1,608 @@
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include "xiaomi_keyboard.h"
+#include <drm/drm_notifier.h>
+#include <linux/notifier.h>
+
+static struct xiaomi_keyboard_data *mdata;
+
+static void set_keyboard_status(bool on);
+
+static void xiaomi_keyboard_reset(void)
+{
+ if (!mdata || !mdata->pdata) {
+ MI_KB_ERR("reset failed!Invalid Memory\n");
+ return;
+ }
+ MI_KB_INFO("xiaomi keyboard IC Reset\n");
+ gpio_direction_output(mdata->pdata->rst_gpio, 0);
+ msleep(2);
+ gpio_direction_output(mdata->pdata->rst_gpio, 1);
+}
+
+static void xiaomi_keyboard_connected_notify(struct device *dev)
+{
+ sysfs_notify(&dev->kobj, NULL, "xiaomi_keyboard_conn_status");
+ MI_KB_INFO("connected status notify\n");
+}
+
+static ssize_t xiaomi_keyboard_conn_status_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret = 0, value = 1;
+ MI_KB_INFO("%s enter\n", __func__);
+ if (!mdata) {
+ MI_KB_ERR("Invalid driver info\n");
+ return ret;
+ }
+
+ mutex_lock(&mdata->rw_mutex);
+ value = mdata->keyboard_conn_status;
+ mutex_unlock(&mdata->rw_mutex);
+
+ return scnprintf(buf, PAGE_SIZE, "%d", value);
+}
+
+static ssize_t xiaomi_keyboard_conn_status_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ char *cmd;
+ cmd = kzalloc(count + 1, GFP_KERNEL);
+
+ if (!cmd) {
+ MI_KB_ERR("Allocate Meomory Failed\n");
+ goto out;
+ }
+ memcpy(cmd, buf, count);
+
+ if (!mdata)
+ goto out;
+
+ if (!strncmp(cmd, "reset", 5)) {
+ xiaomi_keyboard_reset();
+ } else if (!strncmp(cmd, "enable_keyboard", 15)) {
+ MI_KB_INFO("enable keyboard\n");
+ set_keyboard_status(1);
+ } else if (!strncmp(cmd, "disable_keyboard", 16)) {
+ MI_KB_INFO("disable keyboard\n");
+ set_keyboard_status(0);
+ }
+ else
+ MI_KB_ERR("Undefined CMD: %s\n", cmd);
+out:
+ if (cmd)
+ kfree(cmd);
+ return count;
+}
+
+DEVICE_ATTR(xiaomi_keyboard_conn_status, (S_IRUGO | S_IWUSR | S_IWGRP), xiaomi_keyboard_conn_status_show, xiaomi_keyboard_conn_status_store);
+
+static irqreturn_t xiaomi_keyboard_irq_func(int irq, void *data)
+{
+ int value = 0;
+ MI_KB_INFO("keyboard event: wakeup system\n");
+ pm_wakeup_event(&mdata->pdev->dev, 500);
+ value = gpio_get_value_cansleep(mdata->pdata->in_irq_gpio);
+
+ mutex_lock(&mdata->rw_mutex);
+ mdata->keyboard_conn_status = !mdata->keyboard_conn_status;
+ mutex_unlock(&mdata->rw_mutex);
+
+ xiaomi_keyboard_connected_notify(&mdata->pdev->dev);
+ MI_KB_INFO("keyboard connected status: %d", mdata->keyboard_conn_status);
+ return IRQ_HANDLED;
+}
+
+static int xiaomi_keyboard_gpio_config(struct xiaomi_keyboard_platdata *pdata)
+{
+ int ret = 0;
+ if (gpio_is_valid(pdata->rst_gpio)) {
+ ret = gpio_request_one(pdata->rst_gpio, GPIOF_OUT_INIT_LOW, "kb_rst");
+ if (ret) {
+ MI_KB_ERR("Failed to request xiaomi keyboard rst gpio\n");
+ goto err_request_rst_gpio;
+ }
+ }
+
+ if (gpio_is_valid(pdata->in_irq_gpio)) {
+ ret = gpio_request_one(pdata->in_irq_gpio, GPIOF_IN, "kb_in_irq");
+ if (ret) {
+ MI_KB_ERR("Failed to request xiaomi keyboard in-irq gpio\n");
+ goto err_request_in_irq_gpio;
+ }
+ }
+
+ return ret;
+err_request_in_irq_gpio:
+ gpio_free(pdata->rst_gpio);
+err_request_rst_gpio:
+ return ret;
+}
+
+static void xiaomi_keyboard_gpio_deconfig(struct xiaomi_keyboard_platdata *pdata)
+{
+ if (gpio_is_valid(pdata->rst_gpio))
+ gpio_free(pdata->rst_gpio);
+
+ if (gpio_is_valid(pdata->in_irq_gpio))
+ gpio_free(pdata->in_irq_gpio);
+}
+
+static int xiaomi_keyboard_setup_gpio(struct xiaomi_keyboard_platdata *pdata)
+{
+ int ret = 0;
+ if (!pdata) {
+ MI_KB_ERR("xiaomi keyboard platdata is NULL\n");
+ return -EINVAL;
+ }
+ if (gpio_is_valid(pdata->rst_gpio))
+ gpio_direction_output(pdata->rst_gpio, 1);
+
+ mdata->irq = gpio_to_irq(pdata->in_irq_gpio);
+ if (mdata->irq) {
+ ret = request_threaded_irq(mdata->irq, NULL, xiaomi_keyboard_irq_func,
+ IRQF_TRIGGER_RISING|IRQF_ONESHOT, "MiKB-IRQ", mdata);
+ if (ret != 0) {
+ MI_KB_ERR("request threaded irq failed\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int xiaomi_keyboard_resetup_gpio(struct xiaomi_keyboard_platdata *pdata)
+{
+ int ret = 0;
+
+ if (!mdata || !pdata) {
+ MI_KB_ERR("mdata or pdata not ready, return!");
+ return -EINVAL;
+ }
+
+ if (gpio_is_valid(pdata->rst_gpio))
+ gpio_direction_output(pdata->rst_gpio, 0);
+
+ free_irq(mdata->irq, mdata);
+
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static int xiaomi_keyboard_parse_dt(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct xiaomi_keyboard_platdata *pdata;
+ int ret = 0;
+
+ pdata = mdata->pdata;
+
+ pdata->rst_gpio = of_get_named_gpio(np, "xiaomi-keyboard,rst-gpio", 0);
+ MI_KB_INFO("xiaomi-kb,reset-gpio=%d\n", pdata->rst_gpio);
+
+ pdata->in_irq_gpio = of_get_named_gpio(np, "xiaomi-keyboard,in-irq-gpio", 0);
+ MI_KB_INFO("xiaomi-kb,in-irq-gpio=%d\n", pdata->in_irq_gpio);
+
+ pdata->vdd_gpio = of_get_named_gpio(np, "xiaomi-keyboard,vdd-gpio", 0);
+ MI_KB_INFO("xiaomi-kb,vdd-gpio=%d\n", pdata->vdd_gpio);
+
+ return ret;
+}
+#else
+static int xiaomi_keyboard_parse_dt(struct device *dev)
+{
+ MI_KB_ERR("Xiaomi Keyboard dev is not defined\n");
+ return -EINVAL;
+}
+#endif
+
+static int xiaomi_keyboard_pinctrl_init(struct device *dev)
+{
+ int ret = 0;
+
+ mdata->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR_OR_NULL(mdata->pinctrl)) {
+ MI_KB_ERR("Failed to get pinctrl, please check dts\n");
+ ret = PTR_ERR(mdata->pinctrl);
+ goto err_pinctrl_get;
+ }
+ mdata->pins_active = pinctrl_lookup_state(mdata->pinctrl, "pm_kb_active");
+ if (IS_ERR_OR_NULL(mdata->pins_active)) {
+ MI_KB_ERR("Pin state [active] not found\n");
+ ret = PTR_ERR(mdata->pins_active);
+ goto err_pinctrl_lookup;
+ }
+
+ mdata->pins_suspend = pinctrl_lookup_state(mdata->pinctrl, "pm_kb_suspend");
+ if (IS_ERR_OR_NULL(mdata->pins_suspend)) {
+ MI_KB_ERR("Pin state [suspend] not found\n");
+ ret = PTR_ERR(mdata->pins_suspend);
+ goto err_pinctrl_lookup;
+ }
+
+ return 0;
+err_pinctrl_lookup:
+ if (mdata->pinctrl) {
+ devm_pinctrl_put(mdata->pinctrl);
+ }
+err_pinctrl_get:
+ return ret;
+}
+
+static int xiaomi_keyboard_power_on(void)
+{
+ int ret = 0;
+ struct xiaomi_keyboard_platdata *pdata;
+ pdata = mdata->pdata;
+ MI_KB_INFO("Power On\n");
+ if (gpio_is_valid(pdata->vdd_gpio)) {
+ ret = gpio_request_one(pdata->vdd_gpio, GPIOF_OUT_INIT_HIGH, "kb_vdd_gpio");
+ if (ret) {
+ MI_KB_ERR("Failed to request xiaomi-keyboard-out-irq gpio\n");
+ goto err_request_vdd_gpio;
+ }
+ }
+
+ gpio_direction_output(pdata->vdd_gpio, 1);
+err_request_vdd_gpio:
+ return ret;
+}
+
+static void xiaomi_keyboard_power_off(void)
+{
+ struct xiaomi_keyboard_platdata *pdata;
+ pdata = mdata->pdata;
+ MI_KB_INFO("Power Off\n");
+ if (gpio_is_valid(pdata->vdd_gpio)) {
+ gpio_direction_output(pdata->vdd_gpio, 0);
+ gpio_free(pdata->vdd_gpio);
+ }
+ return;
+}
+
+static int xiaomi_keyboard_suspend(struct device *dev)
+{
+ int ret = 0;
+ MI_KB_INFO("enter\n");
+ if (mdata->pinctrl && mdata->pins_suspend) {
+ ret = (mdata->keyboard_is_enable && mdata->is_usb_exist)
+ ? 0 : pinctrl_select_state(mdata->pinctrl, mdata->pins_suspend);
+ if (ret < 0) {
+ MI_KB_ERR("Set suspend pin state error:%d\n", ret);
+ }
+ }
+ MI_KB_INFO("exit\n");
+ return ret;
+}
+
+static int xiaomi_keyboard_resume(struct device *dev)
+{
+ int ret = 0;
+ MI_KB_INFO("enter\n");
+ if (!mdata->keyboard_is_enable) {
+ MI_KB_INFO("keyboard_is_enable is false, stop resume.\n");
+ MI_KB_INFO("exit\n");
+ return -1;
+ }
+ if (mdata->pinctrl && mdata->pins_active) {
+ ret = pinctrl_select_state(mdata->pinctrl, mdata->pins_active);
+ if (ret < 0) {
+ MI_KB_ERR("Set active pin state error:%d\n", ret);
+ }
+ }
+ MI_KB_INFO("exit\n");
+ return ret;
+}
+
+static int xiaomi_keyboard_pm_suspend(struct device *dev)
+{
+ int ret = 0;
+ MI_KB_INFO("enter\n");
+ enable_irq_wake(mdata->irq);
+ mdata->dev_pm_suspend = true;
+ return ret;
+}
+
+static int xiaomi_keyboard_pm_resume(struct device *dev)
+{
+ int ret = 0;
+ MI_KB_INFO("enter\n");
+ disable_irq_wake(mdata->irq);
+ mdata->dev_pm_suspend = false;
+ return ret;
+}
+
+static const struct dev_pm_ops xiaomi_keyboard_pm_ops = {
+ .suspend = xiaomi_keyboard_pm_suspend,
+ .resume = xiaomi_keyboard_pm_resume,
+};
+
+static int keyboard_drm_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
+{
+ int blank = *(enum drm_notifier_data *)data;
+ struct xiaomi_keyboard_data *mdata =
+ container_of(self, struct xiaomi_keyboard_data, drm_notif);
+
+ if (mdata) {
+ flush_workqueue(mdata->event_wq);
+ if (event == MI_DRM_EARLY_EVENT_BLANK) {
+ if (blank == MI_DRM_BLANK_POWERDOWN) {
+ MI_KB_ERR("keyboard suspend");
+ mdata->is_in_suspend = true;
+ queue_work(mdata->event_wq, &mdata->suspend_work);
+ }
+ } else if (event == MI_DRM_EVENT_BLANK) {
+ if (blank == MI_DRM_BLANK_UNBLANK) {
+ MI_KB_ERR("keyboard resume");
+ mdata->is_in_suspend = false;
+ flush_workqueue(mdata->event_wq);
+ queue_work(mdata->event_wq, &mdata->resume_work);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void keyboard_resume_work(struct work_struct *work)
+{
+ struct xiaomi_keyboard_data *mdata = container_of(work, struct xiaomi_keyboard_data, resume_work);
+ xiaomi_keyboard_resume(&mdata->pdev->dev);
+}
+
+static void keyboard_suspend_work(struct work_struct *work)
+{
+ struct xiaomi_keyboard_data *mdata = container_of(work, struct xiaomi_keyboard_data, resume_work);
+ xiaomi_keyboard_suspend(&mdata->pdev->dev);
+}
+
+static int kb_power_supply_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct xiaomi_keyboard_data *mdata =
+ container_of(nb, struct xiaomi_keyboard_data, power_supply_notifier);
+
+ if (mdata != NULL)
+ queue_work(mdata->event_wq, &mdata->power_supply_work);
+
+ return 0;
+}
+
+static void kb_power_supply_work(struct work_struct *work)
+{
+ struct xiaomi_keyboard_data *mdata = container_of(work, struct xiaomi_keyboard_data, power_supply_work);
+ int is_usb_exist = 0;
+
+ mutex_lock(&mdata->power_supply_lock);
+ is_usb_exist = !!power_supply_is_system_supplied();
+ if (is_usb_exist != mdata->is_usb_exist) {
+ mdata->is_usb_exist = is_usb_exist;
+ MI_KB_INFO("power supply is: %d", mdata->is_usb_exist);
+ }
+ mutex_unlock(&mdata->power_supply_lock);
+}
+
+static void set_keyboard_status(bool on) {
+ int ret = 0;
+
+ if (!mdata || !(mdata->pdata)) {
+ MI_KB_ERR("mdata or pdata not ready, return!");
+ return;
+ }
+
+ if (on && !(mdata->keyboard_is_enable)) {
+ ret = xiaomi_keyboard_power_on();
+ if (ret) {
+ MI_KB_ERR("Init 3.3V power failed\n");
+ return;
+ }
+ msleep(1);
+ ret = xiaomi_keyboard_setup_gpio(mdata->pdata);
+ if (ret) {
+ MI_KB_ERR("setup gpio failed\n");
+ return;
+ }
+ msleep(2);
+
+ if (!mdata->is_in_suspend) {
+ ret = pinctrl_select_state(mdata->pinctrl, mdata->pins_active);
+ if (ret < 0) {
+ MI_KB_ERR("Set active pin state error:%d\n", ret);
+ }
+ }
+ mdata->keyboard_is_enable = true;
+
+ } else if (!on && mdata->keyboard_is_enable) {
+ if (!mdata->is_in_suspend) {
+ ret = pinctrl_select_state(mdata->pinctrl, mdata->pins_suspend);
+ if (ret < 0) {
+ MI_KB_ERR("Set suspend pin state error:%d\n", ret);
+ }
+ }
+
+ ret = xiaomi_keyboard_resetup_gpio(mdata->pdata);
+ if (ret < 0) {
+ MI_KB_ERR("resetup gpio failed\n");
+ return;
+ }
+ xiaomi_keyboard_power_off();
+ mdata->keyboard_is_enable = false;
+ } else {
+ MI_KB_INFO("keyboard status do not need change!");
+ }
+}
+
+/*******************************************************
+Description:
+ xiami pad keyboard driver probe function.
+
+return:
+ Executive outcomes. 0---succeed. negative---failed
+*******************************************************/
+static int xiaomi_keyboard_probe(struct platform_device *pdev)
+{
+ struct xiaomi_keyboard_platdata *pdata;
+ int ret = 0;
+ MI_KB_INFO("enter\n");
+ mdata = kzalloc(sizeof(struct xiaomi_keyboard_data), GFP_KERNEL);
+ if (!mdata) {
+ MI_KB_ERR("Alloc Memory for xiaomi_keyboard_data failed\n");
+ return -ENOMEM;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(struct xiaomi_keyboard_platdata), GFP_KERNEL);
+ if (!pdata) {
+ MI_KB_ERR("Alloc Memory for xiaomi_keyboard_platdata failed\n");
+ return -ENOMEM;
+ }
+
+ mdata->pdev = pdev;
+ mdata->pdata = pdata;
+ mutex_init(&mdata->rw_mutex);
+ mutex_init(&mdata->power_supply_lock);
+ mdata->is_usb_exist = 0;
+
+ ret = xiaomi_keyboard_parse_dt(&pdev->dev);
+ if (ret) {
+ MI_KB_ERR("parse device tree failed\n");
+ goto out;
+ }
+
+ ret = xiaomi_keyboard_pinctrl_init(&pdev->dev);
+ if (ret) {
+ MI_KB_ERR("Pinctrl init failed\n");
+ goto out;
+ }
+
+ pdata = mdata->pdata;
+ ret = xiaomi_keyboard_gpio_config(pdata);
+ if (ret) {
+ MI_KB_ERR("set gpio config failed\n");
+ goto out;
+ }
+
+ mdata->dev_pm_suspend = false;
+ mdata->keyboard_is_enable = false;
+ mdata->is_in_suspend = false;
+
+ ret = sysfs_create_file(&mdata->pdev->dev.kobj, &dev_attr_xiaomi_keyboard_conn_status.attr);
+ if (ret < 0) {
+ MI_KB_ERR("Create sysfs attribute xiaomi_keyboard_conn_status Failed\n");
+ goto err_pinctrl_select;
+ }
+
+ mdata->event_wq = alloc_workqueue("kb-event-queue",
+ WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
+ if (!mdata->event_wq) {
+ MI_KB_ERR("Can not create work thread for suspend/resume!!");
+ ret = -ENOMEM;
+ goto err_alloc_work_thread_failed;
+ }
+
+ set_keyboard_status(1);
+
+ INIT_WORK(&mdata->resume_work, keyboard_resume_work);
+ INIT_WORK(&mdata->suspend_work, keyboard_suspend_work);
+ INIT_WORK(&mdata->power_supply_work, kb_power_supply_work);
+
+ mdata->drm_notif.notifier_call = keyboard_drm_notifier_callback;
+ ret = mi_drm_register_client(&mdata->drm_notif);
+ if(ret) {
+ MI_KB_ERR("register drm_notifier failed. ret=%d\n", ret);
+ goto err_register_drm_notif_failed;
+ }
+
+ mdata->power_supply_notifier.notifier_call = kb_power_supply_event;
+ ret = power_supply_reg_notifier(&mdata->power_supply_notifier);
+ if (ret) {
+ MI_KB_ERR("register power_supply_notifier failed. ret=%d\n", ret);
+ goto err_register_power_supply_notif_failed;
+ }
+
+ MI_KB_INFO("Success\n");
+ return ret;
+
+err_register_power_supply_notif_failed:
+err_register_drm_notif_failed:
+ if (mdata->event_wq) {
+ destroy_workqueue(mdata->event_wq);
+ }
+err_alloc_work_thread_failed:
+ sysfs_remove_file(&mdata->pdev->dev.kobj, &dev_attr_xiaomi_keyboard_conn_status.attr);
+err_pinctrl_select:
+ if (mdata->pinctrl) {
+ devm_pinctrl_put(mdata->pinctrl);
+ }
+ xiaomi_keyboard_gpio_deconfig(pdata);
+out:
+ mutex_destroy(&mdata->rw_mutex);
+ mutex_destroy(&mdata->power_supply_lock);
+ if (mdata) {
+ kfree(mdata);
+ mdata = NULL;
+ }
+ MI_KB_ERR("Failed\n");
+ return ret;
+}
+
+static int xiaomi_keyboard_remove(struct platform_device *pdev)
+{
+ MI_KB_INFO("enter\n");
+ mi_drm_unregister_client(&mdata->drm_notif);
+ destroy_workqueue(mdata->event_wq);
+ xiaomi_keyboard_gpio_deconfig(mdata->pdata);
+ sysfs_remove_file(&mdata->pdev->dev.kobj, &dev_attr_xiaomi_keyboard_conn_status.attr);
+ xiaomi_keyboard_power_off();
+ devm_pinctrl_put(mdata->pinctrl);
+ xiaomi_keyboard_gpio_deconfig(mdata->pdata);
+ mutex_destroy(&mdata->rw_mutex);
+ mutex_destroy(&mdata->power_supply_lock);
+ if (mdata) {
+ kfree(mdata);
+ mdata = NULL;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id xiaomi_keyboard_dt_match[] = {
+ { .compatible = "xiaomi,keyboard" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xiaomi_keyboard_dt_match);
+#endif
+
+static const struct platform_device_id xiaomi_keyboard_driver_ids[] = {
+ {
+ .name = "xiaomi-keyboard",
+ .driver_data = 0,
+ },
+};
+MODULE_DEVICE_TABLE(platform, xiaomi_keyboard_driver_ids);
+
+
+static struct platform_driver xiaomi_keyboard_driver = {
+ .probe = xiaomi_keyboard_probe,
+ .remove = xiaomi_keyboard_remove,
+ .driver = {
+ .name = "xiaomi-keyboard",
+ .of_match_table = of_match_ptr(xiaomi_keyboard_dt_match),
+ .pm = &xiaomi_keyboard_pm_ops,
+ },
+ .id_table = xiaomi_keyboard_driver_ids,
+};
+
+module_platform_driver(xiaomi_keyboard_driver);
+
+MODULE_DESCRIPTION("Xiaomi Keyboard Control-driver");
+MODULE_AUTHOR("Tonghui Wang<wangtonghui@xiaomi.com>");
diff --git a/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.h b/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.h
new file mode 100644
index 000000000000..5c4220077bf8
--- /dev/null
+++ b/drivers/input/misc/xiaomi_keyboard/xiaomi_keyboard.h
@@ -0,0 +1,45 @@
+#ifndef __XIAOMI_KEYBOARD_H
+#define __XIAOMI_KEYBOARD_H
+
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#define XIAOMI_KB_TAG "xiaomi-keyboard"
+#define MI_KB_INFO(fmt, args...) pr_info("[%s] %s %d: " fmt, XIAOMI_KB_TAG, __func__, __LINE__, ##args)
+#define MI_KB_ERR(fmt, args...) pr_err("[%s] %s %d: " fmt, XIAOMI_KB_TAG, __func__, __LINE__, ##args)
+
+struct xiaomi_keyboard_platdata {
+ u32 rst_gpio;
+ u32 rst_flags;
+ u32 in_irq_gpio;
+ u32 in_irq_flags;
+ u32 vdd_gpio;
+};
+
+struct xiaomi_keyboard_data {
+ struct notifier_block drm_notif;
+ struct xiaomi_keyboard_platdata *pdata;
+ bool dev_pm_suspend;
+ int irq;
+ struct platform_device *pdev;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_active;
+ struct pinctrl_state *pins_suspend;
+ struct workqueue_struct *event_wq;
+ struct work_struct resume_work;
+ struct work_struct suspend_work;
+ int keyboard_conn_status;
+ struct mutex rw_mutex;
+
+ struct mutex power_supply_lock;
+ struct work_struct power_supply_work;
+ struct notifier_block power_supply_notifier;
+ int is_usb_exist;
+ bool keyboard_is_enable;
+ bool is_in_suspend;
+};
+#endif
--
Armbian