tri_state_key: bring inline with lineage-15.1

Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
This commit is contained in:
codeworkx 2018-12-14 18:42:37 +01:00 committed by Timi
parent fdf7a2555a
commit 0a1f43c27f

View file

@ -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");