mirror of
https://gitee.com/open-loongarch/linux-5.10.git
synced 2026-10-25 12:47:11 +08:00
1.add 2k300_gongkong board support 2.update dht11 driver 3.support EC200A-CN 4G model 4.goodix:reset: reset timing fixing 5.other bugs fix
389 lines
9.1 KiB
C
389 lines
9.1 KiB
C
// All GPIOS are pull-up
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/input.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/module.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/input/matrix_keypad.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/of_platform.h>
|
|
|
|
struct matrix_keypad_polled {
|
|
const struct matrix_keypad_platform_data *pdata;
|
|
struct input_dev *input;
|
|
unsigned int row_shift;
|
|
|
|
int out_value;
|
|
int row_values[MATRIX_MAX_ROWS];
|
|
int col_values[MATRIX_MAX_COLS];
|
|
int poll_interval;
|
|
};
|
|
|
|
enum matrix_keypad_edge {
|
|
MATRIX_KEY_GPIO_FALLING,
|
|
MATRIX_KEY_GPIO_RISING,
|
|
};
|
|
|
|
static void keypad_all_row_input(struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i;
|
|
|
|
for (i = 0; i < pdata->num_row_gpios; i++)
|
|
gpio_direction_input(pdata->row_gpios[i]);
|
|
}
|
|
|
|
static void keypad_all_row_output(struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i;
|
|
|
|
for (i = 0; i < pdata->num_row_gpios; i++)
|
|
gpio_direction_output(pdata->row_gpios[i], keypad->out_value);
|
|
}
|
|
|
|
static void keypad_all_col_input(struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i;
|
|
|
|
for (i = 0; i < pdata->num_col_gpios; i++)
|
|
gpio_direction_input(pdata->col_gpios[i]);
|
|
}
|
|
|
|
static void keypad_all_col_output(struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i;
|
|
|
|
for (i = 0; i < pdata->num_col_gpios; i++)
|
|
gpio_direction_output(pdata->col_gpios[i], keypad->out_value);
|
|
}
|
|
|
|
static int keypad_which_row_bounce(struct matrix_keypad_polled* keypad,
|
|
enum matrix_keypad_edge* edge)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int val, i;
|
|
|
|
for (i = 0; i < pdata->num_row_gpios; i++)
|
|
{
|
|
val = gpio_get_value_cansleep(pdata->row_gpios[i]);
|
|
if (val != keypad->row_values[i])
|
|
{
|
|
keypad->row_values[i] = val;
|
|
*edge = (val == 0) ?
|
|
MATRIX_KEY_GPIO_FALLING : MATRIX_KEY_GPIO_RISING;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int keypad_which_col_bounce(struct matrix_keypad_polled* keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int val, i;
|
|
|
|
for (i = 0; i < pdata->num_col_gpios; i++)
|
|
{
|
|
val = gpio_get_value_cansleep(pdata->col_gpios[i]);
|
|
if (val != keypad->col_values[i])
|
|
{
|
|
keypad->col_values[i] = val;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int keypad_assert_row(struct matrix_keypad_polled* keypad,
|
|
enum matrix_keypad_edge* edge)
|
|
{
|
|
keypad_all_col_output(keypad);
|
|
keypad_all_row_input(keypad);
|
|
|
|
return keypad_which_row_bounce(keypad, edge);
|
|
}
|
|
|
|
static int keypad_assert_col(struct matrix_keypad_polled* keypad)
|
|
{
|
|
keypad_all_row_output(keypad);
|
|
keypad_all_col_input(keypad);
|
|
|
|
return keypad_which_col_bounce(keypad);
|
|
}
|
|
|
|
static void matrix_keypad_polled(struct input_dev *input)
|
|
{
|
|
struct matrix_keypad_polled *keypad = input_get_drvdata(input);
|
|
const unsigned short *keycodes = input->keycode;
|
|
enum matrix_keypad_edge edge;
|
|
int row, col, code;
|
|
|
|
row = keypad_assert_row(keypad, &edge);
|
|
if (row >= 0)
|
|
{
|
|
col = keypad_assert_col(keypad);
|
|
|
|
//pr_info("(%d,%d) = %d\n",
|
|
// row, col, edge);
|
|
|
|
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
|
|
input_event(input, EV_MSC, MSC_SCAN, code);
|
|
input_report_key(input, keycodes[code], !edge);
|
|
}
|
|
|
|
input_sync(input);
|
|
}
|
|
|
|
static int matrix_keypad_polled_start(struct input_dev *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void matrix_keypad_polled_stop(struct input_dev *dev)
|
|
{
|
|
}
|
|
|
|
static int matrix_keypad_polled_init_gpio(struct platform_device *pdev,
|
|
struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i, err;
|
|
|
|
/* initialized strobe lines as outputs, activated */
|
|
for (i = 0; i < pdata->num_col_gpios; i++) {
|
|
err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col");
|
|
if (err) {
|
|
dev_err(&pdev->dev,
|
|
"failed to request GPIO%d for COL%d\n",
|
|
pdata->col_gpios[i], i);
|
|
goto err_free_cols;
|
|
}
|
|
|
|
gpio_direction_output(pdata->col_gpios[i], 0);
|
|
keypad->col_values[i] = ! keypad->out_value;
|
|
}
|
|
|
|
for (i = 0; i < pdata->num_row_gpios; i++) {
|
|
err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row");
|
|
if (err) {
|
|
dev_err(&pdev->dev,
|
|
"failed to request GPIO%d for ROW%d\n",
|
|
pdata->row_gpios[i], i);
|
|
goto err_free_rows;
|
|
}
|
|
|
|
gpio_direction_input(pdata->row_gpios[i]);
|
|
keypad->row_values[i] = ! keypad->out_value;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_free_rows:
|
|
while (--i >= 0)
|
|
gpio_free(pdata->row_gpios[i]);
|
|
i = pdata->num_col_gpios;
|
|
err_free_cols:
|
|
while (--i >= 0)
|
|
gpio_free(pdata->col_gpios[i]);
|
|
|
|
return err;
|
|
}
|
|
|
|
static void keypad_free_gpio(struct matrix_keypad_polled *keypad)
|
|
{
|
|
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
|
|
int i;
|
|
|
|
for (i = 0; i < pdata->num_row_gpios; i++)
|
|
gpio_free(pdata->row_gpios[i]);
|
|
|
|
for (i = 0; i < pdata->num_col_gpios; i++)
|
|
gpio_free(pdata->col_gpios[i]);
|
|
}
|
|
|
|
#ifdef CONFIG_OF
|
|
static struct matrix_keypad_platform_data *
|
|
matrix_keypad_polled_parse_dt(struct device *dev)
|
|
{
|
|
struct matrix_keypad_platform_data *pdata;
|
|
struct device_node *np = dev->of_node;
|
|
unsigned int *gpios;
|
|
int ret, i, nrow, ncol;
|
|
|
|
if (!np) {
|
|
dev_err(dev, "device lacks DT data\n");
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
|
if (!pdata) {
|
|
dev_err(dev, "could not allocate memory for platform data\n");
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
pdata->num_row_gpios = nrow = of_gpio_named_count(np, "row-gpios");
|
|
pdata->num_col_gpios = ncol = of_gpio_named_count(np, "col-gpios");
|
|
if (nrow <= 0 || ncol <= 0) {
|
|
dev_err(dev, "number of keypad rows/columns not specified\n");
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
if (of_get_property(np, "linux,no-autorepeat", NULL))
|
|
pdata->no_autorepeat = true;
|
|
|
|
gpios = devm_kcalloc(dev,
|
|
pdata->num_row_gpios + pdata->num_col_gpios,
|
|
sizeof(unsigned int),
|
|
GFP_KERNEL);
|
|
if (!gpios) {
|
|
dev_err(dev, "could not allocate memory for gpios\n");
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
for (i = 0; i < nrow; i++) {
|
|
ret = of_get_named_gpio(np, "row-gpios", i);
|
|
if (ret < 0)
|
|
return ERR_PTR(ret);
|
|
gpios[i] = ret;
|
|
}
|
|
|
|
for (i = 0; i < ncol; i++) {
|
|
ret = of_get_named_gpio(np, "col-gpios", i);
|
|
if (ret < 0)
|
|
return ERR_PTR(ret);
|
|
gpios[nrow + i] = ret;
|
|
}
|
|
|
|
pdata->row_gpios = gpios;
|
|
pdata->col_gpios = &gpios[pdata->num_row_gpios];
|
|
|
|
return pdata;
|
|
}
|
|
#else
|
|
static inline struct matrix_keypad_platform_data *
|
|
matrix_keypad_parse_dt(struct device *dev)
|
|
{
|
|
dev_err(dev, "no platform data defined\n");
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
#endif
|
|
|
|
static int matrix_keypad_polled_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
const struct matrix_keypad_platform_data *pdata;
|
|
struct matrix_keypad_polled *keypad;
|
|
struct input_dev *input;
|
|
int err;
|
|
|
|
pdata = dev_get_platdata(dev);
|
|
if (!pdata) {
|
|
pdata = matrix_keypad_polled_parse_dt(dev);
|
|
if (IS_ERR(pdata))
|
|
return PTR_ERR(pdata);
|
|
} else if (!pdata->keymap_data) {
|
|
dev_err(&pdev->dev, "no keymap data defined\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
keypad = kzalloc(sizeof(struct matrix_keypad_polled), GFP_KERNEL);
|
|
input = devm_input_allocate_device(dev);
|
|
if (!keypad || !input) {
|
|
err = -ENOMEM;
|
|
goto err_free_mem;
|
|
}
|
|
|
|
keypad->input = input;
|
|
keypad->pdata = pdata;
|
|
keypad->row_shift = get_count_order(pdata->num_col_gpios);
|
|
of_property_read_u32(dev->of_node, "poll-interval",
|
|
&keypad->poll_interval);
|
|
|
|
input->open = matrix_keypad_polled_start;
|
|
input->close = matrix_keypad_polled_stop;
|
|
|
|
err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
|
|
pdata->num_row_gpios,
|
|
pdata->num_col_gpios,
|
|
NULL, input);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "failed to build keymap\n");
|
|
goto err_free_mem;
|
|
}
|
|
|
|
__set_bit(EV_KEY, input->evbit);
|
|
if (!pdata->no_autorepeat)
|
|
__set_bit(EV_REP, input->evbit);
|
|
input_set_capability(input, EV_MSC, MSC_SCAN);
|
|
input_set_drvdata(input, keypad);
|
|
|
|
err = input_setup_polling(input, matrix_keypad_polled);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "unable to set up polling, err=%d\n", err);
|
|
return err;
|
|
}
|
|
|
|
input_set_poll_interval(input, keypad->poll_interval);
|
|
|
|
err = matrix_keypad_polled_init_gpio(pdev, keypad);
|
|
if (err)
|
|
goto err_free_mem;
|
|
|
|
err = input_register_device(input);
|
|
if (err)
|
|
goto err_free_gpio;
|
|
|
|
input_sync(input);
|
|
|
|
return 0;
|
|
|
|
err_free_gpio:
|
|
keypad_free_gpio(keypad);
|
|
err_free_mem:
|
|
input_free_device(input);
|
|
kfree(keypad);
|
|
return err;
|
|
}
|
|
|
|
static int matrix_keypad_polled_remove(struct platform_device *pdev)
|
|
{
|
|
struct matrix_keypad_polled *keypad = platform_get_drvdata(pdev);
|
|
|
|
keypad_free_gpio(keypad);
|
|
input_unregister_device(keypad->input);
|
|
kfree(keypad);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_OF
|
|
static const struct of_device_id matrix_keypad_polled_dt_match[] = {
|
|
{ .compatible = "gpio-matrix-keypad-polled" },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, matrix_keypad_polled_dt_match);
|
|
#endif
|
|
|
|
static struct platform_driver matrix_keypad_polled_driver = {
|
|
.probe = matrix_keypad_polled_probe,
|
|
.remove = matrix_keypad_polled_remove,
|
|
.driver = {
|
|
.name = "matrix-keypad-polled",
|
|
.of_match_table = of_match_ptr(matrix_keypad_polled_dt_match),
|
|
},
|
|
};
|
|
module_platform_driver(matrix_keypad_polled_driver);
|