[PATCH v3 2/3] driver: input: matric-keypad: add reduced matrix support
From: Gireesh.Hiremath
Date: Fri Aug 19 2022 - 03:00:56 EST
From: Gireesh Hiremath <Gireesh.Hiremath@xxxxxxxxxxxx>
Add support to reduced matrix keypad driver.
Tested on Bosch Guardian Dtect board(TI-am335x).
Signed-off-by: Gireesh Hiremath <Gireesh.Hiremath@xxxxxxxxxxxx>
---
drivers/input/keyboard/matrix_keypad.c | 559 +++++++++++++++++++++----
include/linux/input/matrix_keypad.h | 68 +--
2 files changed, 520 insertions(+), 107 deletions(-)
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b99574edad9c..72c0663b6ed3 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -21,9 +21,30 @@
#include <linux/of.h>
#include <linux/of_platform.h>
+struct button_states {
+ uint8_t previous_state : 1;
+ uint8_t current_state : 1;
+};
+
+union button_event {
+ uint8_t clear_event;
+ struct {
+ uint8_t global_changed : 1;
+ uint8_t pressed : 1;
+ uint8_t released : 1;
+ } status;
+};
+
+struct button {
+ uint8_t key;
+ union button_event event;
+ struct button_states state;
+};
+
struct matrix_keypad {
const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
+ struct button *button_array;
unsigned int row_shift;
DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
@@ -31,11 +52,34 @@ struct matrix_keypad {
uint32_t last_key_state[MATRIX_MAX_COLS];
struct delayed_work work;
spinlock_t lock;
+ int8_t current_line_gpio;
bool scan_pending;
bool stopped;
bool gpio_all_disabled;
};
+struct keypad_info {
+ unsigned char mode;
+};
+
+static const struct keypad_info keypad_infos[] = {
+ {
+ .mode = GENERIC,
+ },
+ {
+ .mode = REDUCED,
+ },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id matrix_keypad_dt_match[] = {
+ { .compatible = "gpio-matrix-keypad", .data = &keypad_infos[0] },
+ { .compatible = "gpio-matrix-keypad-reduced",
+ .data = &keypad_infos[1] },
+ {}
+};
+MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
+#endif
/*
* NOTE: If drive_inactive_cols is false, then the GPIO has to be put into
* HiZ when de-activated to cause minmal side effect when scanning other
@@ -78,7 +122,8 @@ static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
int row)
{
return gpiod_get_value_cansleep(pdata->row_gpios[row]) ?
- !pdata->active_low : pdata->active_low;
+ !pdata->active_low :
+ pdata->active_low;
}
static void enable_row_irqs(struct matrix_keypad *keypad)
@@ -107,6 +152,247 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
}
}
+static void
+__activate_line_driving(const struct matrix_keypad_platform_data *pdata,
+ int line, bool on)
+{
+ bool level_on = pdata->active_low;
+
+ if (on)
+ gpiod_direction_output(pdata->desc_gpios[line], level_on);
+ else
+ gpiod_direction_input(pdata->desc_gpios[line]);
+}
+
+static void
+activate_line_driving(const struct matrix_keypad_platform_data *pdata, int line,
+ bool on)
+{
+ __activate_line_driving(pdata, line, on);
+
+ if (on && pdata->col_scan_delay_us)
+ udelay(pdata->col_scan_delay_us);
+}
+
+static void button_init(struct button *btn, bool btn_hw_state, int key)
+{
+ btn->state.previous_state = btn_hw_state;
+ btn->state.current_state = btn_hw_state;
+ btn->event.clear_event = 0;
+ btn->key = key;
+}
+
+static bool check_button_changes(struct button *btn)
+{
+ /* Check if Button is pressed */
+ if ((!btn->state.previous_state) && btn->state.current_state)
+ btn->event.status.pressed = true;
+
+ /* Check if Button is released */
+ else if (btn->state.previous_state && (!btn->state.current_state))
+ btn->event.status.released = true;
+
+ if (btn->event.clear_event != 0)
+ btn->event.status.global_changed = true;
+
+ btn->state.previous_state = btn->state.current_state;
+
+ return btn->event.status.global_changed;
+}
+
+static union button_event get_and_clear_events(struct button *btn)
+{
+ union button_event temp = btn->event;
+
+ btn->event.clear_event = 0;
+
+ return temp;
+}
+
+static union button_event get_and_clear_btn_events(struct matrix_keypad *keypad,
+ int btn_index)
+{
+ if (btn_index < keypad->pdata->num_of_buttons)
+ return get_and_clear_events(&keypad->button_array[btn_index]);
+ else
+ return get_and_clear_events(&keypad->button_array[0]);
+}
+
+static void button_hdl_init(struct matrix_keypad *keypad)
+{
+ const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ int row, col, index;
+ int i;
+
+ /* Init Button Objects, will be reinited once states are captured */
+ i = 0;
+ for (row = 1; row < pdata->num_line_gpios; row++)
+ for (col = 0; col < row; col++) {
+ index = (row * pdata->num_line_gpios) + col;
+ if (pdata->keycode[index] != pdata->keycode[0]) {
+ if (i < pdata->num_of_buttons) {
+ button_init(&keypad->button_array[i],
+ false,
+ pdata->keycode[index]);
+ i++;
+ }
+ }
+ }
+
+ pr_debug("[matrix-keypad]: %s Done\n", __func__);
+}
+
+static void on_button_event(struct matrix_keypad *keypad, int btn_index,
+ union button_event btn_event,
+ struct input_dev *input_dev)
+{
+ unsigned int key_code = 0;
+ int key_value = 0;
+
+ key_code = keypad->button_array[btn_index].key;
+
+ if (btn_event.status.pressed) {
+ key_value = 1;
+ pr_debug("[matrix-keypad]:%d Pressed\n", key_code);
+ }
+
+ if (btn_event.status.released) {
+ key_value = 0;
+ pr_debug("[matrix-keypad]:%d Released\n", key_code);
+ }
+
+ input_report_key(input_dev, key_code, key_value);
+ input_sync(input_dev);
+}
+
+static void process_button_events(struct matrix_keypad *keypad,
+ struct input_dev *input_dev)
+{
+ int btn_index;
+
+ for (btn_index = 0; btn_index < keypad->pdata->num_of_buttons;
+ btn_index++) {
+ const union button_event beEvent =
+ get_and_clear_btn_events(keypad, (int)btn_index);
+
+ if (beEvent.status.global_changed) {
+ on_button_event(keypad, (int)btn_index, beEvent,
+ input_dev);
+ }
+ }
+}
+
+static bool get_gpio_line_value(const struct matrix_keypad_platform_data *pdata,
+ int row)
+{
+ return gpiod_get_value(pdata->desc_gpios[row]) ? pdata->active_low :
+ !pdata->active_low;
+}
+
+static uint8_t get_btn_index(struct matrix_keypad *keypad, int btn_key)
+{
+ uint8_t i;
+
+ for (i = 0; i < keypad->pdata->num_of_buttons; i++) {
+ if (keypad->button_array[i].key == btn_key)
+ break;
+ }
+ return i;
+}
+
+static void set_btn_state_by_hw(struct button *btn, bool buttonstate)
+{
+ btn->state.current_state = buttonstate;
+}
+
+static void poll_prepare(struct matrix_keypad *keypad)
+{
+ const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+
+ keypad->current_line_gpio = 0;
+ activate_line_driving(pdata, (int)keypad->current_line_gpio, true);
+}
+
+static void poll_process(struct matrix_keypad *keypad,
+ struct input_dev *input_dev)
+{
+ const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ bool btn_changes_occured = false;
+ int btn_index;
+
+ for (btn_index = 0; btn_index < pdata->num_of_buttons; btn_index++) {
+ btn_changes_occured |=
+ check_button_changes(&keypad->button_array[btn_index]);
+ }
+
+ if (btn_changes_occured)
+ process_button_events(keypad, input_dev);
+
+ keypad->current_line_gpio = 0;
+}
+
+static void poll_update(struct matrix_keypad *keypad,
+ struct input_dev *input_dev)
+{
+ const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ uint8_t *btn_keylines;
+ uint8_t number_of_buttons_pressed = 0;
+ uint8_t btn_index;
+ uint8_t btn_key;
+ uint16_t index;
+ int i;
+
+ btn_keylines =
+ kcalloc(pdata->num_line_gpios, sizeof(uint8_t), GFP_KERNEL);
+ for (i = 0; i < pdata->num_line_gpios; i++) {
+ index = (keypad->current_line_gpio * pdata->num_line_gpios) + i;
+ btn_key = pdata->keycode[index];
+ btn_keylines[i] = false;
+
+ if ((btn_key != pdata->keycode[0]) &&
+ (get_gpio_line_value(pdata, (int)i) != false)) {
+ btn_keylines[i] = true;
+ number_of_buttons_pressed++;
+ }
+ }
+ if (number_of_buttons_pressed < 2) {
+ for (i = 0; i < pdata->num_line_gpios; i++) {
+ index = (keypad->current_line_gpio *
+ pdata->num_line_gpios) +
+ i;
+ btn_key = pdata->keycode[index];
+ if (btn_key != pdata->keycode[0]) {
+ btn_index = get_btn_index(keypad, btn_key);
+ set_btn_state_by_hw(
+ &keypad->button_array[btn_index],
+ btn_keylines[i]);
+ }
+ }
+ }
+
+ kfree(btn_keylines);
+ activate_line_driving(pdata, (int)keypad->current_line_gpio, false);
+ keypad->current_line_gpio++;
+ activate_line_driving(
+ pdata, (int)(keypad->current_line_gpio % pdata->num_line_gpios),
+ true);
+}
+
+static void matrix_keypad_poll(struct input_dev *input)
+{
+ struct matrix_keypad *keypad = input_get_drvdata(input);
+ struct input_dev *input_dev = keypad->input_dev;
+
+ if (keypad->stopped == false) {
+ if (keypad->current_line_gpio ==
+ keypad->pdata->num_line_gpios) {
+ poll_process(keypad, input_dev);
+ } else {
+ poll_update(keypad, input_dev);
+ }
+ }
+}
+
/*
* This gets the keys from keyboard and reports it to input subsystem
*/
@@ -127,7 +413,6 @@ static void matrix_keypad_scan(struct work_struct *work)
/* assert each column and read the row status out */
for (col = 0; col < pdata->num_col_gpios; col++) {
-
activate_col(pdata, col, true);
for (row = 0; row < pdata->num_row_gpios; row++)
@@ -150,8 +435,7 @@ static void matrix_keypad_scan(struct work_struct *work)
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
- input_report_key(input_dev,
- keycodes[code],
+ input_report_key(input_dev, keycodes[code],
new_state[col] & (1 << row));
}
}
@@ -186,7 +470,7 @@ static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
disable_row_irqs(keypad);
keypad->scan_pending = true;
schedule_delayed_work(&keypad->work,
- msecs_to_jiffies(keypad->pdata->debounce_ms));
+ msecs_to_jiffies(keypad->pdata->debounce_ms));
out:
spin_unlock_irqrestore(&keypad->lock, flags);
@@ -204,7 +488,8 @@ static int matrix_keypad_start(struct input_dev *dev)
* Schedule an immediate key scan to capture current key state;
* columns will be activated and IRQs be enabled after the scan.
*/
- schedule_delayed_work(&keypad->work, 0);
+ if (keypad->pdata->mode == GENERIC)
+ schedule_delayed_work(&keypad->work, 0);
return 0;
}
@@ -217,7 +502,9 @@ static void matrix_keypad_stop(struct input_dev *dev)
keypad->stopped = true;
spin_unlock_irq(&keypad->lock);
- flush_delayed_work(&keypad->work);
+ if (keypad->pdata->mode == GENERIC)
+ flush_delayed_work(&keypad->work);
+
/*
* matrix_keypad_scan() will leave IRQs enabled;
* we should disable them now.
@@ -236,7 +523,6 @@ static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
if (enable_irq_wake(pdata->clustered_irq) == 0)
keypad->gpio_all_disabled = true;
} else {
-
for (i = 0; i < pdata->num_row_gpios; i++) {
if (!test_bit(i, keypad->disabled_gpios)) {
gpio = pdata->row_gpios[i];
@@ -296,8 +582,8 @@ static int matrix_keypad_resume(struct device *dev)
}
#endif
-static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
- matrix_keypad_suspend, matrix_keypad_resume);
+static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, matrix_keypad_suspend,
+ matrix_keypad_resume);
static int matrix_keypad_init_gpio(struct platform_device *pdev,
struct matrix_keypad *keypad)
@@ -316,9 +602,9 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
if (pdata->clustered_irq > 0) {
err = request_any_context_irq(pdata->clustered_irq,
- matrix_keypad_interrupt,
- pdata->clustered_irq_flags,
- "matrix-keypad", keypad);
+ matrix_keypad_interrupt,
+ pdata->clustered_irq_flags,
+ "matrix-keypad", keypad);
if (err < 0) {
dev_err(&pdev->dev,
"Unable to acquire clustered interrupt\n");
@@ -327,11 +613,10 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
} else {
for (i = 0; i < pdata->num_row_gpios; i++) {
err = request_any_context_irq(
- gpiod_to_irq(pdata->row_gpios[i]),
- matrix_keypad_interrupt,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "matrix-keypad", keypad);
+ gpiod_to_irq(pdata->row_gpios[i]),
+ matrix_keypad_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "matrix-keypad", keypad);
if (err < 0) {
dev_err(&pdev->dev,
"Unable to acquire interrupt for GPIO line %i\n",
@@ -361,30 +646,42 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
-
- if (pdata->clustered_irq > 0) {
- free_irq(pdata->clustered_irq, keypad);
+ if (pdata->mode == REDUCED) {
+ for (i = 0; i < pdata->num_line_gpios; i++)
+ gpiod_put(pdata->desc_gpios[i]);
} else {
- for (i = 0; i < pdata->num_row_gpios; i++)
- free_irq(gpiod_to_irq(pdata->row_gpios[i]), keypad);
- }
+ if (pdata->clustered_irq > 0) {
+ free_irq(pdata->clustered_irq, keypad);
+ } else {
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ free_irq(gpiod_to_irq(pdata->row_gpios[i]),
+ keypad);
+ }
- for (i = 0; i < pdata->num_row_gpios; i++)
- gpiod_put(pdata->row_gpios[i]);
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ gpiod_put(pdata->row_gpios[i]);
- for (i = 0; i < pdata->num_col_gpios; i++)
- gpiod_put(pdata->col_gpios[i]);
+ for (i = 0; i < pdata->num_col_gpios; i++)
+ gpiod_put(pdata->col_gpios[i]);
+ }
}
#ifdef CONFIG_OF
static struct matrix_keypad_platform_data *
matrix_keypad_parse_dt(struct device *dev)
{
+ const struct of_device_id *of_id =
+ of_match_device(matrix_keypad_dt_match, dev);
struct matrix_keypad_platform_data *pdata;
struct device_node *np = dev->of_node;
+ const struct keypad_info *info = of_id->data;
struct gpio_desc **gpios;
struct gpio_desc *desc;
int ret, i, nrow, ncol;
+ int8_t *keycode;
+ uint32_t *ptr;
+ int num_gpio;
+ int keymap;
if (!np) {
dev_err(dev, "device lacks DT data\n");
@@ -397,11 +694,23 @@ matrix_keypad_parse_dt(struct device *dev)
return ERR_PTR(-ENOMEM);
}
- pdata->num_row_gpios = nrow = gpiod_count(dev, "row");
- pdata->num_col_gpios = ncol = gpiod_count(dev, "col");
- if (nrow <= 0 || ncol <= 0) {
- dev_err(dev, "number of keypad rows/columns not specified\n");
- return ERR_PTR(-EINVAL);
+ pdata->mode = info->mode;
+
+ if (pdata->mode == REDUCED) {
+ num_gpio = gpiod_count(dev, "line");
+ if (num_gpio <= 0) {
+ dev_err(dev, "number of gpio line not specified\n");
+ return ERR_PTR(-EINVAL);
+ }
+ } else {
+ pdata->num_row_gpios = nrow = gpiod_count(dev, "row");
+ pdata->num_col_gpios = ncol = gpiod_count(dev, "col");
+
+ 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))
@@ -415,34 +724,90 @@ matrix_keypad_parse_dt(struct device *dev)
of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
of_property_read_u32(np, "col-scan-delay-us",
- &pdata->col_scan_delay_us);
-
- gpios = devm_kcalloc(dev,
- pdata->num_row_gpios + pdata->num_col_gpios,
- sizeof(*gpios),
- GFP_KERNEL);
- if (!gpios) {
- dev_err(dev, "could not allocate memory for gpios\n");
- return ERR_PTR(-ENOMEM);
- }
+ &pdata->col_scan_delay_us);
+ if (pdata->mode == REDUCED) {
+ gpios = devm_kcalloc(dev, num_gpio, sizeof(*gpios), GFP_KERNEL);
+ if (!gpios)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < num_gpio; i++) {
+ desc = devm_gpiod_get_index(dev, "line", i, GPIOD_ASIS);
+ if (IS_ERR(desc))
+ return ERR_PTR(-EPROBE_DEFER);
+ gpios[i] = desc;
+ }
- for (i = 0; i < nrow; i++) {
- desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
- if (IS_ERR(desc))
- return ERR_PTR(ret);
- gpios[i] = desc;
- }
+ pdata->desc_gpios = gpios;
+ pdata->num_line_gpios = num_gpio;
+
+ if (!gpiod_is_active_low(pdata->desc_gpios[0]))
+ pdata->active_low = true;
+ } else {
+ gpios = devm_kcalloc(
+ dev, pdata->num_row_gpios + pdata->num_col_gpios,
+ sizeof(*gpios), GFP_KERNEL);
+ if (!gpios) {
+ dev_err(dev, "could not allocate memory for gpios\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < nrow; i++) {
+ desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
+ if (IS_ERR(desc))
+ return ERR_PTR(ret);
+ gpios[i] = desc;
+ }
+
+ for (i = 0; i < ncol; i++) {
+ desc = devm_gpiod_get_index(dev, "col", i, GPIOD_IN);
+ if (IS_ERR(desc))
+ return ERR_PTR(ret);
+ gpios[nrow + i] = desc;
+ }
- for (i = 0; i < ncol; i++) {
- desc = devm_gpiod_get_index(dev, "col", i, GPIOD_IN);
- if (IS_ERR(desc))
- return ERR_PTR(ret);
- gpios[nrow + i] = desc;
+ pdata->row_gpios = gpios;
+ pdata->col_gpios = &gpios[pdata->num_row_gpios];
}
- pdata->row_gpios = gpios;
- pdata->col_gpios = &gpios[pdata->num_row_gpios];
+ if (pdata->mode == REDUCED) {
+ if (of_property_read_u32(np, "poll-interval-ms",
+ &pdata->poll_interval_ms))
+ pdata->poll_interval_ms = 10;
+ of_property_read_u32(np, "number-of-buttons",
+ &pdata->num_of_buttons);
+ if (pdata->num_of_buttons <= 0) {
+ dev_err(dev, "number of button not specified\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ keymap = device_property_count_u32(dev, "linux,keymap");
+ if (keymap <= 0 ||
+ keymap > (pdata->num_line_gpios * pdata->num_line_gpios)) {
+ dev_err(dev, "linux,keymap property count is invalid");
+ return ERR_PTR(-ENXIO);
+ }
+
+ ptr = devm_kzalloc(dev, (keymap * sizeof(uint32_t)),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ if (device_property_read_u32_array(dev, "linux,keymap", ptr,
+ keymap)) {
+ dev_err(dev, "problem parsing keymap property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ keycode = devm_kzalloc(dev, (keymap * sizeof(int8_t)),
+ GFP_KERNEL);
+ if (!keycode)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->keycode = keycode;
+ for (i = 0; i < keymap; i++)
+ pdata->keycode[i] = KEYCODE(ptr[i]);
+ }
return pdata;
}
#else
@@ -483,22 +848,58 @@ static int matrix_keypad_probe(struct platform_device *pdev)
keypad->pdata = pdata;
keypad->row_shift = get_count_order(pdata->num_col_gpios);
keypad->stopped = true;
- INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
+
+ if (pdata->mode == REDUCED) {
+ keypad->button_array = devm_kzalloc(
+ &pdev->dev,
+ sizeof(struct button) * (pdata->num_of_buttons),
+ GFP_KERNEL);
+ if (!keypad->button_array) {
+ dev_err(&pdev->dev,
+ "could not allocate memory for button array\n");
+ goto err_free_mem;
+ ;
+ }
+
+ poll_prepare(keypad);
+
+ err = input_setup_polling(input_dev, matrix_keypad_poll);
+ if (err) {
+ dev_err(&pdev->dev,
+ "unable to set up polling, err=%d\n", err);
+ return err;
+ }
+
+ input_set_poll_interval(input_dev, pdata->poll_interval_ms);
+ } else {
+ INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
+ }
spin_lock_init(&keypad->lock);
- input_dev->name = pdev->name;
- input_dev->id.bustype = BUS_HOST;
- input_dev->dev.parent = &pdev->dev;
- input_dev->open = matrix_keypad_start;
- input_dev->close = matrix_keypad_stop;
-
- err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
- pdata->num_row_gpios,
- pdata->num_col_gpios,
- NULL, input_dev);
- if (err) {
- dev_err(&pdev->dev, "failed to build keymap\n");
- goto err_free_mem;
+ input_dev->name = pdev->name;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->open = matrix_keypad_start;
+ input_dev->close = matrix_keypad_stop;
+
+ if (pdata->mode == REDUCED) {
+ err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+ pdata->num_line_gpios,
+ pdata->num_line_gpios, NULL,
+ input_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to build keymap for reduced mode\n");
+ goto err_free_mem;
+ }
+ } else {
+ err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+ pdata->num_row_gpios,
+ pdata->num_col_gpios, NULL,
+ input_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to build keymap for generic mode\n");
+ goto err_free_mem;
+ }
}
if (!pdata->no_autorepeat)
@@ -506,9 +907,13 @@ static int matrix_keypad_probe(struct platform_device *pdev)
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
- err = matrix_keypad_init_gpio(pdev, keypad);
- if (err)
- goto err_free_mem;
+ if (pdata->mode == REDUCED) {
+ button_hdl_init(keypad);
+ } else {
+ err = matrix_keypad_init_gpio(pdev, keypad);
+ if (err)
+ goto err_free_mem;
+ }
err = input_register_device(keypad->input_dev);
if (err)
@@ -538,14 +943,6 @@ static int matrix_keypad_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id matrix_keypad_dt_match[] = {
- { .compatible = "gpio-matrix-keypad" },
- { }
-};
-MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
-#endif
-
static struct platform_driver matrix_keypad_driver = {
.probe = matrix_keypad_probe,
.remove = matrix_keypad_remove,
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index 8ad7d4626e62..d5ba9ec21752 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -6,18 +6,22 @@
#include <linux/input.h>
#include <linux/of.h>
-#define MATRIX_MAX_ROWS 32
-#define MATRIX_MAX_COLS 32
+#define MATRIX_MAX_ROWS 32
+#define MATRIX_MAX_COLS 32
-#define KEY(row, col, val) ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\
- (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\
- ((val) & 0xffff))
+#define KEY(row, col, val) \
+ ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) | \
+ (((col) & (MATRIX_MAX_COLS - 1)) << 16) | ((val)&0xffff))
-#define KEY_ROW(k) (((k) >> 24) & 0xff)
-#define KEY_COL(k) (((k) >> 16) & 0xff)
-#define KEY_VAL(k) ((k) & 0xffff)
+#define KEY_ROW(k) (((k) >> 24) & 0xff)
+#define KEY_COL(k) (((k) >> 16) & 0xff)
+#define KEY_VAL(k) ((k)&0xffff)
-#define MATRIX_SCAN_CODE(row, col, row_shift) (((row) << (row_shift)) + (col))
+#define MATRIX_SCAN_CODE(row, col, row_shift) (((row) << (row_shift)) + (col))
+#define KEYCODE(keymap) (keymap & 0xFFFF)
+
+#define GENERIC (1) /* keypad mode generic */
+#define REDUCED (2) /* keypad mode reduced */
/**
* struct matrix_keymap_data - keymap for matrix keyboards
@@ -30,7 +34,7 @@
*/
struct matrix_keymap_data {
const uint32_t *keymap;
- unsigned int keymap_size;
+ unsigned int keymap_size;
};
/**
@@ -38,6 +42,7 @@ struct matrix_keymap_data {
* @keymap_data: pointer to &matrix_keymap_data
* @row_gpios: pointer to array of gpio numbers representing rows
* @col_gpios: pointer to array of gpio numbers reporesenting colums
+ * @desc_gpios: actual number of gpio used devide in reduced mode
* @num_row_gpios: actual number of row gpios used by device
* @num_col_gpios: actual number of col gpios used by device
* @col_scan_delay_us: delay, measured in microseconds, that is
@@ -46,6 +51,12 @@ struct matrix_keymap_data {
* @clustered_irq: may be specified if interrupts of all row/column GPIOs
* are bundled to one single irq
* @clustered_irq_flags: flags that are needed for the clustered irq
+ * @num_line_gpios: actual number of gpio line in reduced mode
+ * @num_of_buttons: number of physical buttons on keypad
+ * in reduced mode
+ * @poll_interval_ms: interval to poll gpio in reduced mode
+ * @keycode: hold the keycode value
+ * @mode: flag to set mode
* @active_low: gpio polarity
* @wakeup: controls whether the device should be set up as wakeup
* source
@@ -61,32 +72,37 @@ struct matrix_keypad_platform_data {
struct gpio_desc **row_gpios;
struct gpio_desc **col_gpios;
+ struct gpio_desc **desc_gpios;
- unsigned int num_row_gpios;
- unsigned int num_col_gpios;
+ unsigned int num_row_gpios;
+ unsigned int num_col_gpios;
- unsigned int col_scan_delay_us;
+ unsigned int col_scan_delay_us;
/* key debounce interval in milli-second */
- unsigned int debounce_ms;
+ unsigned int debounce_ms;
+
+ unsigned int clustered_irq;
+ unsigned int clustered_irq_flags;
+ unsigned int num_line_gpios;
+ unsigned int num_of_buttons;
+ unsigned int poll_interval_ms;
- unsigned int clustered_irq;
- unsigned int clustered_irq_flags;
+ int8_t *keycode;
+ int8_t mode;
- bool active_low;
- bool wakeup;
- bool no_autorepeat;
- bool drive_inactive_cols;
+ bool active_low;
+ bool wakeup;
+ bool no_autorepeat;
+ bool drive_inactive_cols;
};
int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
- const char *keymap_name,
- unsigned int rows, unsigned int cols,
- unsigned short *keymap,
+ const char *keymap_name, unsigned int rows,
+ unsigned int cols, unsigned short *keymap,
struct input_dev *input_dev);
-int matrix_keypad_parse_properties(struct device *dev,
- unsigned int *rows, unsigned int *cols);
-
+int matrix_keypad_parse_properties(struct device *dev, unsigned int *rows,
+ unsigned int *cols);
#define matrix_keypad_parse_of_params matrix_keypad_parse_properties
#endif /* _MATRIX_KEYPAD_H */
--
2.20.1