[PATCH 2/5] Input: matrix_keypad - switch to gpiod API and generic device properties
Dmitry Torokhov
dmitry.torokhov at gmail.com
Sun Aug 4 18:47:05 PDT 2024
gpiod API and generic device properties work with software nodes and
static properties, which will allow removing platform data support
from the driver, simplifying and streamlining the code.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov at gmail.com>
---
drivers/input/keyboard/matrix_keypad.c | 341 ++++++++++++++-----------
1 file changed, 185 insertions(+), 156 deletions(-)
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 604e90d13ed0..5f7e6f27e9c5 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -17,17 +17,26 @@
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.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 {
- const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
unsigned int row_shift;
+ unsigned int col_scan_delay_us;
+ /* key debounce interval in milli-second */
+ unsigned int debounce_ms;
+ bool drive_inactive_cols;
+
+ struct gpio_desc *row_gpios[MATRIX_MAX_ROWS];
+ unsigned int num_row_gpios;
+
+ struct gpio_desc *col_gpios[MATRIX_MAX_ROWS];
+ unsigned int num_col_gpios;
+
unsigned int row_irqs[MATRIX_MAX_ROWS];
DECLARE_BITMAP(wakeup_enabled_irqs, MATRIX_MAX_ROWS);
@@ -44,50 +53,43 @@ struct matrix_keypad {
* columns. In that case it is configured here to be input, otherwise it is
* driven with the inactive value.
*/
-static void __activate_col(const struct matrix_keypad_platform_data *pdata,
- int col, bool on)
+static void __activate_col(struct matrix_keypad *keypad, int col, bool on)
{
- bool level_on = !pdata->active_low;
-
if (on) {
- gpio_direction_output(pdata->col_gpios[col], level_on);
+ gpiod_direction_output(keypad->col_gpios[col], 1);
} else {
- gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);
- if (!pdata->drive_inactive_cols)
- gpio_direction_input(pdata->col_gpios[col]);
+ gpiod_set_value_cansleep(keypad->col_gpios[col], 0);
+ if (!keypad->drive_inactive_cols)
+ gpiod_direction_input(keypad->col_gpios[col]);
}
}
-static void activate_col(const struct matrix_keypad_platform_data *pdata,
- int col, bool on)
+static void activate_col(struct matrix_keypad *keypad, int col, bool on)
{
- __activate_col(pdata, col, on);
+ __activate_col(keypad, col, on);
- if (on && pdata->col_scan_delay_us)
- udelay(pdata->col_scan_delay_us);
+ if (on && keypad->col_scan_delay_us)
+ udelay(keypad->col_scan_delay_us);
}
-static void activate_all_cols(const struct matrix_keypad_platform_data *pdata,
- bool on)
+static void activate_all_cols(struct matrix_keypad *keypad, bool on)
{
int col;
- for (col = 0; col < pdata->num_col_gpios; col++)
- __activate_col(pdata, col, on);
+ for (col = 0; col < keypad->num_col_gpios; col++)
+ __activate_col(keypad, col, on);
}
-static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
- int row)
+static bool row_asserted(struct matrix_keypad *keypad, int row)
{
- return gpio_get_value_cansleep(pdata->row_gpios[row]) ?
- !pdata->active_low : pdata->active_low;
+ return gpiod_get_value_cansleep(keypad->row_gpios[row]);
}
static void enable_row_irqs(struct matrix_keypad *keypad)
{
int i;
- for (i = 0; i < keypad->pdata->num_row_gpios; i++)
+ for (i = 0; i < keypad->num_row_gpios; i++)
enable_irq(keypad->row_irqs[i]);
}
@@ -95,7 +97,7 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
{
int i;
- for (i = 0; i < keypad->pdata->num_row_gpios; i++)
+ for (i = 0; i < keypad->num_row_gpios; i++)
disable_irq_nosync(keypad->row_irqs[i]);
}
@@ -108,39 +110,38 @@ static void matrix_keypad_scan(struct work_struct *work)
container_of(work, struct matrix_keypad, work.work);
struct input_dev *input_dev = keypad->input_dev;
const unsigned short *keycodes = input_dev->keycode;
- const struct matrix_keypad_platform_data *pdata = keypad->pdata;
uint32_t new_state[MATRIX_MAX_COLS];
int row, col, code;
/* de-activate all columns for scanning */
- activate_all_cols(pdata, false);
+ activate_all_cols(keypad, false);
memset(new_state, 0, sizeof(new_state));
- for (row = 0; row < pdata->num_row_gpios; row++)
- gpio_direction_input(pdata->row_gpios[row]);
+ for (row = 0; row < keypad->num_row_gpios; row++)
+ gpiod_direction_input(keypad->row_gpios[row]);
/* assert each column and read the row status out */
- for (col = 0; col < pdata->num_col_gpios; col++) {
+ for (col = 0; col < keypad->num_col_gpios; col++) {
- activate_col(pdata, col, true);
+ activate_col(keypad, col, true);
- for (row = 0; row < pdata->num_row_gpios; row++)
+ for (row = 0; row < keypad->num_row_gpios; row++)
new_state[col] |=
- row_asserted(pdata, row) ? (1 << row) : 0;
+ row_asserted(keypad, row) ? BIT(row) : 0;
- activate_col(pdata, col, false);
+ activate_col(keypad, col, false);
}
- for (col = 0; col < pdata->num_col_gpios; col++) {
+ for (col = 0; col < keypad->num_col_gpios; col++) {
uint32_t bits_changed;
bits_changed = keypad->last_key_state[col] ^ new_state[col];
if (bits_changed == 0)
continue;
- for (row = 0; row < pdata->num_row_gpios; row++) {
- if ((bits_changed & (1 << row)) == 0)
+ for (row = 0; row < keypad->num_row_gpios; row++) {
+ if (!(bits_changed & BIT(row)))
continue;
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
@@ -154,7 +155,7 @@ static void matrix_keypad_scan(struct work_struct *work)
memcpy(keypad->last_key_state, new_state, sizeof(new_state));
- activate_all_cols(pdata, true);
+ activate_all_cols(keypad, true);
/* Enable IRQs again */
spin_lock_irq(&keypad->lock);
@@ -181,7 +182,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->debounce_ms));
out:
spin_unlock_irqrestore(&keypad->lock, flags);
@@ -225,7 +226,7 @@ static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
int i;
for_each_clear_bit(i, keypad->wakeup_enabled_irqs,
- keypad->pdata->num_row_gpios)
+ keypad->num_row_gpios)
if (enable_irq_wake(keypad->row_irqs[i]) == 0)
__set_bit(i, keypad->wakeup_enabled_irqs);
}
@@ -235,7 +236,7 @@ static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
int i;
for_each_set_bit(i, keypad->wakeup_enabled_irqs,
- keypad->pdata->num_row_gpios) {
+ keypad->num_row_gpios) {
disable_irq_wake(keypad->row_irqs[i]);
__clear_bit(i, keypad->wakeup_enabled_irqs);
}
@@ -270,11 +271,14 @@ static int matrix_keypad_resume(struct device *dev)
static DEFINE_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)
+static int matrix_keypad_init_pdata_gpio(struct platform_device *pdev,
+ const struct matrix_keypad_platform_data *pdata,
+ struct matrix_keypad *keypad)
{
- const struct matrix_keypad_platform_data *pdata = keypad->pdata;
- int i, irq, err;
+ int i, err;
+
+ keypad->num_col_gpios = pdata->num_col_gpios;
+ keypad->num_row_gpios = pdata->num_row_gpios;
/* initialized strobe lines as outputs, activated */
for (i = 0; i < pdata->num_col_gpios; i++) {
@@ -287,7 +291,12 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
return err;
}
- gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
+ keypad->col_gpios[i] = gpio_to_desc(pdata->col_gpios[i]);
+
+ if (pdata->active_low ^ gpiod_is_active_low(keypad->col_gpios[i]))
+ gpiod_toggle_active_low(keypad->col_gpios[i]);
+
+ gpiod_direction_output(keypad->col_gpios[i], 1);
}
for (i = 0; i < pdata->num_row_gpios; i++) {
@@ -300,137 +309,125 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
return err;
}
- gpio_direction_input(pdata->row_gpios[i]);
- }
-
- for (i = 0; i < pdata->num_row_gpios; i++) {
- irq = gpio_to_irq(pdata->row_gpios[i]);
- if (irq < 0) {
- err = irq;
- dev_err(&pdev->dev,
- "Unable to convert GPIO line %i to irq: %d\n",
- pdata->row_gpios[i], err);
- return err;
- }
+ keypad->row_gpios[i] = gpio_to_desc(pdata->row_gpios[i]);
- err = devm_request_any_context_irq(&pdev->dev,
- irq,
- 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",
- pdata->row_gpios[i]);
- return err;
- }
+ if (pdata->active_low ^ gpiod_is_active_low(keypad->row_gpios[i]))
+ gpiod_toggle_active_low(keypad->row_gpios[i]);
- keypad->row_irqs[i] = irq;
+ gpiod_direction_input(keypad->row_gpios[i]);
}
- /* initialized as disabled - enabled by input->open */
- disable_row_irqs(keypad);
-
return 0;
}
-#ifdef CONFIG_OF
-static struct matrix_keypad_platform_data *
-matrix_keypad_parse_dt(struct device *dev)
+static int matrix_keypad_init_gpio(struct platform_device *pdev,
+ struct matrix_keypad *keypad)
{
- 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);
- }
+ bool active_low;
+ int nrow, ncol;
+ int err;
+ int i;
- pdata->num_row_gpios = nrow = gpiod_count(dev, "row");
- pdata->num_col_gpios = ncol = gpiod_count(dev, "col");
+ nrow = gpiod_count(&pdev->dev, "row");
+ ncol = gpiod_count(&pdev->dev, "col");
if (nrow < 0 || ncol < 0) {
- dev_err(dev, "number of keypad rows/columns not specified\n");
- return ERR_PTR(-EINVAL);
+ dev_err(&pdev->dev, "missing row or column GPIOs\n");
+ return -EINVAL;
}
- pdata->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
+ keypad->num_row_gpios = nrow;
+ keypad->num_col_gpios = ncol;
- pdata->wakeup = of_property_read_bool(np, "wakeup-source") ||
- of_property_read_bool(np, "linux,wakeup"); /* legacy */
+ active_low = device_property_read_bool(&pdev->dev, "gpio-activelow");
- pdata->active_low = of_property_read_bool(np, "gpio-activelow");
+ /* initialize strobe lines as outputs, activated */
+ for (i = 0; i < keypad->num_col_gpios; i++) {
+ keypad->col_gpios[i] = devm_gpiod_get_index(&pdev->dev, "col",
+ i, GPIOD_ASIS);
+ err = PTR_ERR_OR_ZERO(keypad->col_gpios[i]);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to request GPIO for COL%d: %d\n",
+ i, err);
+ return err;
+ }
- pdata->drive_inactive_cols =
- of_property_read_bool(np, "drive-inactive-cols");
+ gpiod_set_consumer_name(keypad->col_gpios[i], "matrix_kbd_col");
- 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);
+ if (active_low ^ gpiod_is_active_low(keypad->col_gpios[i]))
+ gpiod_toggle_active_low(keypad->col_gpios[i]);
- 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);
+ gpiod_direction_output(keypad->col_gpios[i], 1);
}
- 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 < keypad->num_row_gpios; i++) {
+ keypad->row_gpios[i] = devm_gpiod_get_index(&pdev->dev, "row",
+ i, GPIOD_IN);
+ err = PTR_ERR_OR_ZERO(keypad->row_gpios[i]);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to request GPIO for ROW%d: %d\n",
+ i, err);
+ return err;
+ }
- 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;
- }
+ gpiod_set_consumer_name(keypad->row_gpios[i], "matrix_kbd_row");
- pdata->row_gpios = gpios;
- pdata->col_gpios = &gpios[pdata->num_row_gpios];
+ if (active_low ^ gpiod_is_active_low(keypad->row_gpios[i]))
+ gpiod_toggle_active_low(keypad->row_gpios[i]);
+ }
- return pdata;
+ return 0;
}
-#else
-static inline struct matrix_keypad_platform_data *
-matrix_keypad_parse_dt(struct device *dev)
+
+static int matrix_keypad_setup_interrupts(struct platform_device *pdev,
+ struct matrix_keypad *keypad)
{
- dev_err(dev, "no platform data defined\n");
+ int err;
+ int irq;
+ int i;
+
+ for (i = 0; i < keypad->num_row_gpios; i++) {
+ irq = gpiod_to_irq(keypad->row_gpios[i]);
+ if (irq < 0) {
+ err = irq;
+ dev_err(&pdev->dev,
+ "Unable to convert GPIO line %i to irq: %d\n",
+ i, err);
+ return err;
+ }
+
+ err = devm_request_any_context_irq(&pdev->dev, irq,
+ matrix_keypad_interrupt,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "matrix-keypad", keypad);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Unable to acquire interrupt for row %i: %d\n",
+ i, err);
+ return err;
+ }
+
+ keypad->row_irqs[i] = irq;
+ }
- return ERR_PTR(-EINVAL);
+ /* initialized as disabled - enabled by input->open */
+ disable_row_irqs(keypad);
+
+ return 0;
}
-#endif
static int matrix_keypad_probe(struct platform_device *pdev)
{
- const struct matrix_keypad_platform_data *pdata;
+ const struct matrix_keypad_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
struct matrix_keypad *keypad;
struct input_dev *input_dev;
+ bool autorepeat;
+ bool wakeup;
int err;
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- pdata = matrix_keypad_parse_dt(&pdev->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 = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
@@ -440,40 +437,72 @@ static int matrix_keypad_probe(struct platform_device *pdev)
return -ENOMEM;
keypad->input_dev = input_dev;
- keypad->pdata = pdata;
- keypad->row_shift = get_count_order(pdata->num_col_gpios);
keypad->stopped = true;
INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
spin_lock_init(&keypad->lock);
+ keypad->drive_inactive_cols =
+ device_property_read_bool(&pdev->dev, "drive-inactive-cols");
+ device_property_read_u32(&pdev->dev, "debounce-delay-ms",
+ &keypad->debounce_ms);
+ device_property_read_u32(&pdev->dev, "col-scan-delay-us",
+ &keypad->col_scan_delay_us);
+
+ if (pdata) {
+ keypad->col_scan_delay_us = pdata->col_scan_delay_us;
+ keypad->debounce_ms = pdata->debounce_ms;
+ keypad->drive_inactive_cols = pdata->drive_inactive_cols;
+ }
+
+ if (pdata)
+ err = matrix_keypad_init_pdata_gpio(pdev, pdata, keypad);
+ else
+ err = matrix_keypad_init_gpio(pdev, keypad);
+ if (err)
+ return err;
+
+ keypad->row_shift = get_count_order(keypad->num_col_gpios);
+
+ err = matrix_keypad_setup_interrupts(pdev, keypad);
+ if (err)
+ return err;
+
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
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,
+ err = matrix_keypad_build_keymap(pdata ? pdata->keymap_data : NULL,
+ NULL,
+ keypad->num_row_gpios,
+ keypad->num_col_gpios,
NULL, input_dev);
if (err) {
dev_err(&pdev->dev, "failed to build keymap\n");
return -ENOMEM;
}
- if (!pdata->no_autorepeat)
+ autorepeat = !device_property_read_bool(&pdev->dev,
+ "linux,no-autorepeat");
+ if (autorepeat && pdata->no_autorepeat)
+ autorepeat = false;
+ if (autorepeat)
__set_bit(EV_REP, input_dev->evbit);
+
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
- err = matrix_keypad_init_gpio(pdev, keypad);
- if (err)
- return err;
-
err = input_register_device(keypad->input_dev);
if (err)
return err;
- device_init_wakeup(&pdev->dev, pdata->wakeup);
+ wakeup = device_property_read_bool(&pdev->dev, "wakeup-source") ||
+ /* legacy */
+ device_property_read_bool(&pdev->dev, "linux,wakeup");
+ if (!wakeup && pdata)
+ wakeup = pdata->wakeup;
+ device_init_wakeup(&pdev->dev, wakeup);
+
platform_set_drvdata(pdev, keypad);
return 0;
--
2.46.0.rc2.264.g509ed76dc8-goog
More information about the linux-arm-kernel
mailing list