Files
openloongarch-linux-5.10/drivers/input/keyboard/matrix_keypad_polled.c
T
maoxiaochuan 9585ff23df update to e4af36c7270
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
2024-12-18 20:29:54 +08:00

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