tri_state_key: bring inline with lineage-15.1
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
This commit is contained in:
parent
fdf7a2555a
commit
0a1f43c27f
1 changed files with 222 additions and 223 deletions
|
@ -12,6 +12,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
@ -25,149 +26,108 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define DRV_NAME "tri-state-key"
|
||||
#define DRV_NAME "tri-state-key"
|
||||
|
||||
/*
|
||||
KEY1(GPIO1) KEY2(GPIO92)
|
||||
pin1 connect to pin4 0 1 | MUTE
|
||||
pin2 connect to pin5 1 1 | Do Not Disturb
|
||||
pin4 connect to pin3 1 0 | Normal
|
||||
* Original tri-state modes designed by OnePlus
|
||||
*/
|
||||
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
MODE_UNKNOWN,
|
||||
MODE_MUTE,
|
||||
MODE_DO_NOT_DISTURB,
|
||||
MODE_NORMAL,
|
||||
MODE_MAX_NUM
|
||||
} tri_mode_t;
|
||||
|
||||
struct switch_dev_data
|
||||
{
|
||||
int irq_key3;
|
||||
int irq_key2;
|
||||
int irq_key1;
|
||||
int key1_gpio;
|
||||
int key2_gpio;
|
||||
int key3_gpio;
|
||||
/*
|
||||
* Target key codes sending to OPPO's Keyhandler
|
||||
* see KeyHandler.java in device/oppo/common/keyhandler
|
||||
*/
|
||||
|
||||
struct regulator *vdd_io;
|
||||
#define KEY_MODE_TOTAL_SILENCE 600
|
||||
#define KEY_MODE_ALARMS_ONLY 601
|
||||
#define KEY_MODE_PRIORITY_ONLY 602
|
||||
#define KEY_MODE_NONE 603
|
||||
|
||||
static int current_mode = MODE_UNKNOWN;
|
||||
|
||||
/*
|
||||
* Default mapping between OP's sti-state switch and OPPO's key codes
|
||||
* see Constants.java in device/oppo/common/configpanel
|
||||
*/
|
||||
|
||||
static int keyCode_slider_top = KEY_MODE_ALARMS_ONLY;
|
||||
static int keyCode_slider_middle = KEY_MODE_PRIORITY_ONLY;
|
||||
static int keyCode_slider_bottom = KEY_MODE_NONE;
|
||||
|
||||
struct switch_dev_data {
|
||||
int irq_key1;
|
||||
int irq_key2;
|
||||
int irq_key3;
|
||||
|
||||
int key1_gpio; // Mute
|
||||
int key2_gpio; // Do Not Disturb
|
||||
int key3_gpio; // Normal
|
||||
|
||||
struct work_struct work;
|
||||
struct switch_dev sdev;
|
||||
|
||||
struct device *dev;
|
||||
struct input_dev *input;
|
||||
struct switch_dev sdev;
|
||||
|
||||
struct timer_list s_timer;
|
||||
struct pinctrl * key_pinctrl;
|
||||
struct pinctrl_state * set_state;
|
||||
|
||||
struct pinctrl *key_pinctrl;
|
||||
struct pinctrl_state *set_state;
|
||||
};
|
||||
|
||||
static struct switch_dev_data *switch_data;
|
||||
static DEFINE_MUTEX(sem);
|
||||
static int set_gpio_by_pinctrl(void)
|
||||
{
|
||||
return pinctrl_select_state(switch_data->key_pinctrl, switch_data->set_state);
|
||||
}
|
||||
|
||||
/*set 3 gpio default state high */
|
||||
static int key_pre[3] = {1, 1, 1};
|
||||
static int delay_time;
|
||||
static DEFINE_MUTEX(sem);
|
||||
|
||||
static void send_input(int keyCode)
|
||||
{
|
||||
input_report_key(switch_data->input, keyCode, 1);
|
||||
input_sync(switch_data->input);
|
||||
input_report_key(switch_data->input, keyCode, 0);
|
||||
input_sync(switch_data->input);
|
||||
}
|
||||
|
||||
static void switch_dev_work(struct work_struct *work)
|
||||
{
|
||||
int key[3];
|
||||
int i, j;
|
||||
bool have_wrong_key = false;
|
||||
int state_same = 0;
|
||||
|
||||
msleep(delay_time);
|
||||
key[0] = gpio_get_value(switch_data->key1_gpio);
|
||||
key[1] = gpio_get_value(switch_data->key2_gpio);
|
||||
key[2] = gpio_get_value(switch_data->key3_gpio);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
/*if 3 gpio status is the same as before ,ignore them*/
|
||||
if (key_pre[i] == key[i])
|
||||
state_same++;
|
||||
if (state_same == 3)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
/*
|
||||
* 1,if the gpio key is low ,and previous status is low ,
|
||||
* we suspect that the gpio is in wrong states
|
||||
*/
|
||||
if (key[i] + key_pre[i] == 0) {
|
||||
pr_err("[sk]key[%d] is in wrong state\n", i);
|
||||
have_wrong_key = true;
|
||||
delay_time = 300;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int key1, key2, key3;
|
||||
int mode = MODE_UNKNOWN;
|
||||
int keyCode;
|
||||
|
||||
mutex_lock(&sem);
|
||||
if (have_wrong_key == true) {
|
||||
if (key[0]+key[1]+key[2] == 2) {
|
||||
if (i == 0)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_MUTE);
|
||||
if (i == 1)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_DO_NOT_DISTURB);
|
||||
if (i == 2)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_NORMAL);
|
||||
}
|
||||
else {
|
||||
for (j = 0; j < 3; j++) {
|
||||
/* we got the gpio is wrong state,
|
||||
* then check which gpio
|
||||
*/
|
||||
if ((key[j] == 0) && (i != j)) {
|
||||
if (j == 0)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_MUTE);
|
||||
if (j == 1)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_DO_NOT_DISTURB);
|
||||
if (j == 2)
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!key[0])
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_MUTE);
|
||||
if (!key[1])
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_DO_NOT_DISTURB);
|
||||
if (!key[2])
|
||||
switch_set_state(
|
||||
&switch_data->sdev,
|
||||
MODE_NORMAL);
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
key_pre[i] = key[i];
|
||||
|
||||
key1 = gpio_get_value(switch_data->key1_gpio);
|
||||
key2 = gpio_get_value(switch_data->key2_gpio);
|
||||
key3 = gpio_get_value(switch_data->key3_gpio);
|
||||
|
||||
if (key1 == 0) {
|
||||
mode = MODE_MUTE;
|
||||
keyCode = keyCode_slider_top;
|
||||
} else if (key2 == 0) {
|
||||
mode = MODE_DO_NOT_DISTURB;
|
||||
keyCode = keyCode_slider_middle;
|
||||
} else if (key3 == 0) {
|
||||
mode = MODE_NORMAL;
|
||||
keyCode = keyCode_slider_bottom;
|
||||
}
|
||||
|
||||
if (current_mode != mode && mode != MODE_UNKNOWN) {
|
||||
current_mode = mode;
|
||||
switch_set_state(&switch_data->sdev, current_mode);
|
||||
send_input(keyCode);
|
||||
printk(DRV_NAME " changed to mode: %d\n", switch_data->sdev.state);
|
||||
}
|
||||
|
||||
mutex_unlock(&sem);
|
||||
}
|
||||
|
||||
static irqreturn_t switch_dev_interrupt(int irq, void *_dev)
|
||||
irqreturn_t switch_dev_interrupt(int irq, void *_dev)
|
||||
{
|
||||
schedule_work(&switch_data->work);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -187,20 +147,17 @@ static int switch_dev_get_devtree_pdata(struct device *dev)
|
|||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
switch_data->key3_gpio= of_get_named_gpio(node, "tristate,gpio_key3", 0);
|
||||
if ((!gpio_is_valid(switch_data->key3_gpio)))
|
||||
switch_data->key1_gpio = of_get_named_gpio(node, "tristate,gpio_key1", 0);
|
||||
if (!gpio_is_valid(switch_data->key1_gpio))
|
||||
return -EINVAL;
|
||||
pr_err("switch_data->key3_gpio=%d \n", switch_data->key3_gpio);
|
||||
|
||||
switch_data->key2_gpio= of_get_named_gpio(node, "tristate,gpio_key2", 0);
|
||||
if ((!gpio_is_valid(switch_data->key2_gpio)))
|
||||
switch_data->key2_gpio = of_get_named_gpio(node, "tristate,gpio_key2", 0);
|
||||
if (!gpio_is_valid(switch_data->key2_gpio))
|
||||
return -EINVAL;
|
||||
pr_err("switch_data->key2_gpio=%d \n", switch_data->key2_gpio);
|
||||
|
||||
switch_data->key1_gpio= of_get_named_gpio(node, "tristate,gpio_key1", 0);
|
||||
if ((!gpio_is_valid(switch_data->key1_gpio)))
|
||||
switch_data->key3_gpio = of_get_named_gpio(node, "tristate,gpio_key3", 0);
|
||||
if (!gpio_is_valid(switch_data->key3_gpio))
|
||||
return -EINVAL;
|
||||
pr_err("switch_data->key1_gpio=%d \n", switch_data->key1_gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -208,111 +165,138 @@ static int switch_dev_get_devtree_pdata(struct device *dev)
|
|||
static inline int
|
||||
switch_dev_get_devtree_pdata(struct device *dev)
|
||||
{
|
||||
pr_info("%s inline function", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define KEYCODE_FOPS(WHICH)\
|
||||
static int keyCode_##WHICH##_show(struct seq_file *seq, void *offset)\
|
||||
{\
|
||||
seq_printf(seq, "%d\n", keyCode_slider_##WHICH);\
|
||||
return 0;\
|
||||
}\
|
||||
static ssize_t keyCode_##WHICH##_write(struct file *file,\
|
||||
const char __user *page, size_t t, loff_t *lo)\
|
||||
{\
|
||||
int data;\
|
||||
char buf[10];\
|
||||
if (copy_from_user(buf, page, t)) {\
|
||||
dev_err(switch_data->dev, "read proc input error.\n");\
|
||||
return t;\
|
||||
}\
|
||||
if (sscanf(buf, "%d", &data) != 1)\
|
||||
return t;\
|
||||
if (data < 600 || data > 603)\
|
||||
return t;\
|
||||
keyCode_slider_##WHICH = data;\
|
||||
if (current_mode == 1)\
|
||||
send_input(keyCode_slider_##WHICH);\
|
||||
return t;\
|
||||
}\
|
||||
static int keyCode_##WHICH##_open(struct inode *inode, struct file *file)\
|
||||
{\
|
||||
return single_open(file, keyCode_##WHICH##_show, inode->i_private);\
|
||||
}\
|
||||
const struct file_operations proc_keyCode_##WHICH = {\
|
||||
.owner = THIS_MODULE,\
|
||||
.open = keyCode_##WHICH##_open,\
|
||||
.read = seq_read,\
|
||||
.write = keyCode_##WHICH##_write,\
|
||||
.llseek = seq_lseek,\
|
||||
.release = single_release,\
|
||||
};
|
||||
|
||||
KEYCODE_FOPS(top);
|
||||
KEYCODE_FOPS(middle);
|
||||
KEYCODE_FOPS(bottom);
|
||||
|
||||
#define REGISTER_IRQ_FOR(KEY)\
|
||||
switch_data->irq_##KEY = gpio_to_irq(switch_data->KEY##_gpio);\
|
||||
if (switch_data->irq_##KEY <= 0) {\
|
||||
dev_err(dev, "%s: irq number is not specified, irq #= %d, int pin=%d\n",\
|
||||
__func__, switch_data->irq_##KEY, switch_data->KEY##_gpio);\
|
||||
goto err_detect_irq_num_failed;\
|
||||
} else {\
|
||||
error = gpio_request(switch_data->KEY##_gpio, "tristate_" #KEY "-int");\
|
||||
if (error < 0) {\
|
||||
dev_err(dev, "%s: gpio_request, err=%d\n", __func__, error);\
|
||||
goto err_request_gpio;\
|
||||
}\
|
||||
error = gpio_direction_input(switch_data->KEY##_gpio);\
|
||||
if (error < 0) {\
|
||||
dev_err(dev, "%s: gpio_direction_input, err=%d\n", __func__, error);\
|
||||
goto err_set_gpio_input;\
|
||||
}\
|
||||
error = request_irq(switch_data->irq_##KEY, switch_dev_interrupt,\
|
||||
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "tristate_" #KEY, switch_data);\
|
||||
if (error) {\
|
||||
dev_err(dev, "%s: request_irq, err=%d\n", __func__, error);\
|
||||
switch_data->irq_##KEY = -EINVAL;\
|
||||
goto err_request_irq;\
|
||||
}\
|
||||
}
|
||||
|
||||
static int tristate_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev;
|
||||
int ret = 0;
|
||||
|
||||
dev= &pdev->dev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct proc_dir_entry *procdir;
|
||||
int error = 0;
|
||||
|
||||
switch_data = kzalloc(sizeof(struct switch_dev_data), GFP_KERNEL);
|
||||
if (!switch_data)
|
||||
return -ENOMEM;
|
||||
|
||||
switch_data->dev = dev;
|
||||
switch_data->sdev.name = DRV_NAME;
|
||||
|
||||
switch_data->input = input_allocate_device();
|
||||
|
||||
// init input device
|
||||
|
||||
switch_data->input->name = DRV_NAME;
|
||||
switch_data->input->dev.parent = &pdev->dev;
|
||||
|
||||
set_bit(EV_KEY, switch_data->input->evbit);
|
||||
|
||||
set_bit(KEY_MODE_TOTAL_SILENCE, switch_data->input->keybit);
|
||||
set_bit(KEY_MODE_ALARMS_ONLY, switch_data->input->keybit);
|
||||
set_bit(KEY_MODE_PRIORITY_ONLY, switch_data->input->keybit);
|
||||
set_bit(KEY_MODE_NONE, switch_data->input->keybit);
|
||||
|
||||
input_set_drvdata(switch_data->input, switch_data);
|
||||
|
||||
error = input_register_device(switch_data->input);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to register input device\n");
|
||||
goto err_input_device_register;
|
||||
}
|
||||
|
||||
// init pinctrl
|
||||
|
||||
switch_data->key_pinctrl = devm_pinctrl_get(switch_data->dev);
|
||||
if (IS_ERR_OR_NULL(switch_data->key_pinctrl)) {
|
||||
dev_err(switch_data->dev, "Failed to get pinctrl \n");
|
||||
dev_err(dev, "Failed to get pinctrl\n");
|
||||
goto err_switch_dev_register;
|
||||
}
|
||||
|
||||
switch_data->set_state = pinctrl_lookup_state(switch_data->key_pinctrl,
|
||||
"pmx_tri_state_key_active");
|
||||
if (IS_ERR_OR_NULL(switch_data->set_state)) {
|
||||
dev_err(switch_data->dev, "Failed to lookup_state \n");
|
||||
dev_err(dev, "Failed to lookup_state\n");
|
||||
goto err_switch_dev_register;
|
||||
}
|
||||
|
||||
set_gpio_by_pinctrl();
|
||||
pinctrl_select_state(switch_data->key_pinctrl, switch_data->set_state);
|
||||
|
||||
ret = switch_dev_get_devtree_pdata(dev);
|
||||
if (ret) {
|
||||
// parse gpios from dt
|
||||
|
||||
error = switch_dev_get_devtree_pdata(dev);
|
||||
if (error) {
|
||||
dev_err(dev, "parse device tree fail!!!\n");
|
||||
goto err_switch_dev_register;
|
||||
}
|
||||
|
||||
ret = switch_dev_register(&switch_data->sdev);
|
||||
if (ret < 0)
|
||||
goto err_switch_dev_register;
|
||||
// irqs and work, timer stuffs
|
||||
|
||||
//config irq gpio and request irq
|
||||
ret = gpio_request(switch_data->key1_gpio, "tristate_key1");
|
||||
if (ret < 0)
|
||||
goto err_request_gpio;
|
||||
|
||||
ret = gpio_direction_input(switch_data->key1_gpio);
|
||||
if (ret < 0)
|
||||
goto err_set_gpio_input;
|
||||
|
||||
switch_data->irq_key1 = gpio_to_irq(switch_data->key1_gpio);
|
||||
if (switch_data->irq_key1 < 0) {
|
||||
ret = switch_data->irq_key1;
|
||||
goto err_detect_irq_num_failed;
|
||||
}
|
||||
|
||||
ret = request_irq(switch_data->irq_key1, switch_dev_interrupt,
|
||||
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
|
||||
"tristate_key1", switch_data);
|
||||
if (ret < 0)
|
||||
goto err_request_irq;
|
||||
|
||||
ret = gpio_request(switch_data->key2_gpio,
|
||||
"tristate_key2");
|
||||
if (ret < 0)
|
||||
goto err_request_gpio;
|
||||
|
||||
ret = gpio_direction_input(switch_data->key2_gpio);
|
||||
if (ret < 0)
|
||||
goto err_set_gpio_input;
|
||||
|
||||
switch_data->irq_key2 = gpio_to_irq(switch_data->key2_gpio);
|
||||
if (switch_data->irq_key2 < 0) {
|
||||
ret = switch_data->irq_key2;
|
||||
goto err_detect_irq_num_failed;
|
||||
}
|
||||
|
||||
ret = request_irq(switch_data->irq_key2, switch_dev_interrupt,
|
||||
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
|
||||
"tristate_key2", switch_data);
|
||||
if (ret < 0)
|
||||
goto err_request_irq;
|
||||
|
||||
ret = gpio_request(switch_data->key3_gpio,
|
||||
"tristate_key3");
|
||||
if (ret < 0)
|
||||
goto err_request_gpio;
|
||||
|
||||
ret = gpio_direction_input(switch_data->key3_gpio);
|
||||
if (ret < 0)
|
||||
goto err_set_gpio_input;
|
||||
|
||||
switch_data->irq_key3 = gpio_to_irq(switch_data->key3_gpio);
|
||||
if (switch_data->irq_key3 < 0) {
|
||||
ret = switch_data->irq_key3;
|
||||
goto err_detect_irq_num_failed;
|
||||
}
|
||||
|
||||
ret = request_irq(switch_data->irq_key3, switch_dev_interrupt,
|
||||
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
|
||||
"tristate_key3", switch_data);
|
||||
if (ret < 0)
|
||||
goto err_request_irq;
|
||||
REGISTER_IRQ_FOR(key1);
|
||||
REGISTER_IRQ_FOR(key2);
|
||||
REGISTER_IRQ_FOR(key3);
|
||||
|
||||
INIT_WORK(&switch_data->work, switch_dev_work);
|
||||
|
||||
|
@ -326,6 +310,28 @@ static int tristate_dev_probe(struct platform_device *pdev)
|
|||
enable_irq_wake(switch_data->irq_key2);
|
||||
enable_irq_wake(switch_data->irq_key3);
|
||||
|
||||
// init switch device
|
||||
|
||||
switch_data->sdev.name = DRV_NAME;
|
||||
error = switch_dev_register(&switch_data->sdev);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Failed to register switch dev\n");
|
||||
goto err_request_gpio;
|
||||
}
|
||||
|
||||
// init proc fs
|
||||
|
||||
procdir = proc_mkdir("tri-state-key", NULL);
|
||||
|
||||
proc_create_data("keyCode_top", 0666, procdir,
|
||||
&proc_keyCode_top, NULL);
|
||||
|
||||
proc_create_data("keyCode_middle", 0666, procdir,
|
||||
&proc_keyCode_middle, NULL);
|
||||
|
||||
proc_create_data("keyCode_bottom", 0666, procdir,
|
||||
&proc_keyCode_bottom, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_gpio:
|
||||
|
@ -333,13 +339,16 @@ err_request_gpio:
|
|||
err_request_irq:
|
||||
err_detect_irq_num_failed:
|
||||
err_set_gpio_input:
|
||||
gpio_free(switch_data->key2_gpio);
|
||||
gpio_free(switch_data->key1_gpio);
|
||||
gpio_free(switch_data->key2_gpio);
|
||||
gpio_free(switch_data->key3_gpio);
|
||||
err_switch_dev_register:
|
||||
kfree(switch_data);
|
||||
|
||||
return ret;
|
||||
err_input_device_register:
|
||||
input_unregister_device(switch_data->input);
|
||||
input_free_device(switch_data->input);
|
||||
dev_err(dev, "%s error: %d\n", __func__, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int tristate_dev_remove(struct platform_device *pdev)
|
||||
|
@ -350,12 +359,11 @@ static int tristate_dev_remove(struct platform_device *pdev)
|
|||
gpio_free(switch_data->key3_gpio);
|
||||
switch_dev_unregister(&switch_data->sdev);
|
||||
kfree(switch_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id tristate_dev_of_match[] =
|
||||
{
|
||||
static struct of_device_id tristate_dev_of_match[] = {
|
||||
{ .compatible = "oneplus,tri-state-key", },
|
||||
{ },
|
||||
};
|
||||
|
@ -363,24 +371,15 @@ MODULE_DEVICE_TABLE(of, tristate_dev_of_match);
|
|||
#endif
|
||||
|
||||
static struct platform_driver tristate_dev_driver = {
|
||||
.probe = tristate_dev_probe,
|
||||
.remove = tristate_dev_remove,
|
||||
.driver = {
|
||||
.probe = tristate_dev_probe,
|
||||
.remove = tristate_dev_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = tristate_dev_of_match,
|
||||
.of_match_table = of_match_ptr(tristate_dev_of_match),
|
||||
},
|
||||
};
|
||||
static int __init oem_tristate_init(void)
|
||||
{
|
||||
return platform_driver_register(&tristate_dev_driver);
|
||||
}
|
||||
module_init(oem_tristate_init);
|
||||
module_platform_driver(tristate_dev_driver);
|
||||
|
||||
static void __exit oem_tristate_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tristate_dev_driver);
|
||||
}
|
||||
module_exit(oem_tristate_exit);
|
||||
MODULE_DESCRIPTION("oem tri_state_key driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("switch Profiles by this triple key driver");
|
||||
|
|
Loading…
Add table
Reference in a new issue