Input: pmic8xxx-keypad - migrate to DT

The driver is only supported on DT enabled platforms. Convert the
driver to DT so that it can probe properly.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Stephen Boyd 2014-03-29 12:35:35 -07:00 committed by Dmitry Torokhov
parent a5dde0c72c
commit 86ea5e6b79
3 changed files with 175 additions and 116 deletions

View File

@ -0,0 +1,89 @@
Qualcomm PM8xxx PMIC Keypad
PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058-keypad"
"qcom,pm8921-keypad"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: address of keypad control register
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: the first interrupt specifies the key sense interrupt
and the second interrupt specifies the key stuck interrupt.
The format of the specifier is defined by the binding
document describing the node's interrupt parent.
- linux,keymap:
Usage: required
Value type: <prop-encoded-array>
Definition: the linux keymap. More information can be found in
input/matrix-keymap.txt.
- linux,keypad-no-autorepeat:
Usage: optional
Value type: <bool>
Definition: don't enable autorepeat feature.
- linux,keypad-wakeup:
Usage: optional
Value type: <bool>
Definition: use any event on keypad as wakeup event.
- keypad,num-rows:
Usage: required
Value type: <u32>
Definition: number of rows in the keymap. More information can be found
in input/matrix-keymap.txt.
- keypad,num-columns:
Usage: required
Value type: <u32>
Definition: number of columns in the keymap. More information can be
found in input/matrix-keymap.txt.
- debounce:
Usage: optional
Value type: <u32>
Definition: time in microseconds that key must be pressed or release
for key sense interrupt to trigger.
- scan-delay:
Usage: optional
Value type: <u32>
Definition: time in microseconds to pause between successive scans
of the matrix array.
- row-hold:
Usage: optional
Value type: <u32>
Definition: time in nanoseconds to pause between scans of each row in
the matrix array.
EXAMPLE
keypad@148 {
compatible = "qcom,pm8921-keypad";
reg = <0x148>;
interrupt-parent = <&pmicintc>;
interrupts = <74 1>, <75 1>;
linux,keymap = <
MATRIX_KEY(0, 0, KEY_VOLUMEUP)
MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
MATRIX_KEY(0, 3, KEY_CAMERA)
>;
keypad,num-rows = <1>;
keypad,num-columns = <5>;
debounce = <15>;
scan-delay = <32>;
row-hold = <91500>;
};

View File

@ -20,8 +20,8 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/input/pmic8xxx-keypad.h>
#include <linux/of.h>
#include <linux/input/matrix_keypad.h>
#define PM8XXX_MAX_ROWS 18
#define PM8XXX_MAX_COLS 8
@ -84,7 +84,8 @@
/**
* struct pmic8xxx_kp - internal keypad data structure
* @pdata - keypad platform data pointer
* @num_cols - number of columns of keypad
* @num_rows - number of row of keypad
* @input - input device pointer for keypad
* @regmap - regmap handle
* @key_sense_irq - key press/release irq number
@ -96,7 +97,8 @@
* @ctrl_reg - control register value
*/
struct pmic8xxx_kp {
const struct pm8xxx_keypad_platform_data *pdata;
unsigned int num_rows;
unsigned int num_cols;
struct input_dev *input;
struct regmap *regmap;
int key_sense_irq;
@ -115,9 +117,9 @@ static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
{
/* all keys pressed on that particular row? */
if (col == 0x00)
return 1 << kp->pdata->num_cols;
return 1 << kp->num_cols;
else
return col & ((1 << kp->pdata->num_cols) - 1);
return col & ((1 << kp->num_cols) - 1);
}
/*
@ -180,10 +182,10 @@ static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
int rc, read_rows;
unsigned int scan_val;
if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
if (kp->num_rows < PM8XXX_MIN_ROWS)
read_rows = PM8XXX_MIN_ROWS;
else
read_rows = kp->pdata->num_rows;
read_rows = kp->num_rows;
pmic8xxx_chk_sync_read(kp);
@ -227,13 +229,13 @@ static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
{
int row, col, code;
for (row = 0; row < kp->pdata->num_rows; row++) {
for (row = 0; row < kp->num_rows; row++) {
int bits_changed = new_state[row] ^ old_state[row];
if (!bits_changed)
continue;
for (col = 0; col < kp->pdata->num_cols; col++) {
for (col = 0; col < kp->num_cols; col++) {
if (!(bits_changed & (1 << col)))
continue;
@ -259,9 +261,9 @@ static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
u16 check, row_state;
check = 0;
for (row = 0; row < kp->pdata->num_rows; row++) {
for (row = 0; row < kp->num_rows; row++) {
row_state = (~new_state[row]) &
((1 << kp->pdata->num_cols) - 1);
((1 << kp->num_cols) - 1);
if (hweight16(row_state) > 1) {
if (found_first == -1)
@ -369,8 +371,13 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
return IRQ_HANDLED;
}
static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp,
struct platform_device *pdev)
{
const struct device_node *of_node = pdev->dev.of_node;
unsigned int scan_delay_ms;
unsigned int row_hold_ns;
unsigned int debounce_ms;
int bits, rc, cycles;
u8 scan_val = 0, ctrl_val = 0;
static const u8 row_bits[] = {
@ -378,18 +385,18 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
};
/* Find column bits */
if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
bits = 0;
else
bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
KEYP_CTRL_SCAN_COLS_SHIFT;
/* Find row bits */
if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
bits = 0;
else
bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
@ -399,15 +406,44 @@ static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
return rc;
}
bits = (kp->pdata->debounce_ms / 5) - 1;
if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms))
scan_delay_ms = MIN_SCAN_DELAY;
if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY ||
!is_power_of_2(scan_delay_ms)) {
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
return -EINVAL;
}
if (of_property_read_u32(of_node, "row-hold", &row_hold_ns))
row_hold_ns = MIN_ROW_HOLD_DELAY;
if (row_hold_ns > MAX_ROW_HOLD_DELAY ||
row_hold_ns < MIN_ROW_HOLD_DELAY ||
((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
return -EINVAL;
}
if (of_property_read_u32(of_node, "debounce", &debounce_ms))
debounce_ms = MIN_DEBOUNCE_TIME;
if (((debounce_ms % 5) != 0) ||
debounce_ms > MAX_DEBOUNCE_TIME ||
debounce_ms < MIN_DEBOUNCE_TIME) {
dev_err(&pdev->dev, "invalid debounce time supplied\n");
return -EINVAL;
}
bits = (debounce_ms / 5) - 1;
scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
bits = fls(kp->pdata->scan_delay_ms) - 1;
bits = fls(scan_delay_ms) - 1;
scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
/* Row hold time is a multiple of 32KHz cycles. */
cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
@ -471,50 +507,27 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
*/
static int pmic8xxx_kp_probe(struct platform_device *pdev)
{
const struct pm8xxx_keypad_platform_data *pdata =
dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap_data;
unsigned int rows, cols;
bool repeat;
bool wakeup;
struct pmic8xxx_kp *kp;
int rc;
unsigned int ctrl_val;
if (!pdata || !pdata->num_cols || !pdata->num_rows ||
pdata->num_cols > PM8XXX_MAX_COLS ||
pdata->num_rows > PM8XXX_MAX_ROWS ||
pdata->num_cols < PM8XXX_MIN_COLS) {
rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
if (rc)
return rc;
if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS ||
cols < PM8XXX_MIN_COLS) {
dev_err(&pdev->dev, "invalid platform data\n");
return -EINVAL;
}
if (!pdata->scan_delay_ms ||
pdata->scan_delay_ms > MAX_SCAN_DELAY ||
pdata->scan_delay_ms < MIN_SCAN_DELAY ||
!is_power_of_2(pdata->scan_delay_ms)) {
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
return -EINVAL;
}
if (!pdata->row_hold_ns ||
pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
return -EINVAL;
}
if (!pdata->debounce_ms ||
((pdata->debounce_ms % 5) != 0) ||
pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
dev_err(&pdev->dev, "invalid debounce time supplied\n");
return -EINVAL;
}
keymap_data = pdata->keymap_data;
if (!keymap_data) {
dev_err(&pdev->dev, "no keymap data supplied\n");
return -EINVAL;
}
repeat = !of_property_read_bool(pdev->dev.of_node,
"linux,input-no-autorepeat");
wakeup = of_property_read_bool(pdev->dev.of_node,
"linux,keypad-wakeup");
kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
if (!kp)
@ -526,7 +539,8 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kp);
kp->pdata = pdata;
kp->num_rows = rows;
kp->num_cols = cols;
kp->dev = &pdev->dev;
kp->input = devm_input_allocate_device(&pdev->dev);
@ -547,8 +561,8 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
return kp->key_stuck_irq;
}
kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
kp->input->name = "PMIC8XXX keypad";
kp->input->phys = "pmic8xxx_keypad/input0";
kp->input->id.bustype = BUS_I2C;
kp->input->id.version = 0x0001;
@ -558,7 +572,7 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
kp->input->open = pmic8xxx_kp_open;
kp->input->close = pmic8xxx_kp_close;
rc = matrix_keypad_build_keymap(keymap_data, NULL,
rc = matrix_keypad_build_keymap(NULL, NULL,
PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
kp->keycodes, kp->input);
if (rc) {
@ -566,7 +580,7 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
return rc;
}
if (pdata->rep)
if (repeat)
__set_bit(EV_REP, kp->input->evbit);
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
@ -576,7 +590,7 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
memset(kp->keystate, 0xff, sizeof(kp->keystate));
memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
rc = pmic8xxx_kpd_init(kp);
rc = pmic8xxx_kpd_init(kp, pdev);
if (rc < 0) {
dev_err(&pdev->dev, "unable to initialize keypad controller\n");
return rc;
@ -612,7 +626,7 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev)
return rc;
}
device_init_wakeup(&pdev->dev, pdata->wakeup);
device_init_wakeup(&pdev->dev, wakeup);
return 0;
}
@ -662,12 +676,20 @@ static int pmic8xxx_kp_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
static const struct of_device_id pm8xxx_match_table[] = {
{ .compatible = "qcom,pm8058-keypad" },
{ .compatible = "qcom,pm8921-keypad" },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_match_table);
static struct platform_driver pmic8xxx_kp_driver = {
.probe = pmic8xxx_kp_probe,
.driver = {
.name = PM8XXX_KEYPAD_DEV_NAME,
.name = "pm8xxx-keypad",
.owner = THIS_MODULE,
.pm = &pm8xxx_kp_pm_ops,
.of_match_table = pm8xxx_match_table,
},
};
module_platform_driver(pmic8xxx_kp_driver);

View File

@ -1,52 +0,0 @@
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __PMIC8XXX_KEYPAD_H__
#define __PMIC8XXX_KEYPAD_H__
#include <linux/input/matrix_keypad.h>
#define PM8XXX_KEYPAD_DEV_NAME "pm8xxx-keypad"
/**
* struct pm8xxx_keypad_platform_data - platform data for keypad
* @keymap_data - matrix keymap data
* @input_name - input device name
* @input_phys_device - input device name
* @num_cols - number of columns of keypad
* @num_rows - number of row of keypad
* @debounce_ms - debounce period in milliseconds
* @scan_delay_ms - scan delay in milliseconds
* @row_hold_ns - row hold period in nanoseconds
* @wakeup - configure keypad as wakeup
* @rep - enable or disable key repeat bit
*/
struct pm8xxx_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
const char *input_name;
const char *input_phys_device;
unsigned int num_cols;
unsigned int num_rows;
unsigned int rows_gpio_start;
unsigned int cols_gpio_start;
unsigned int debounce_ms;
unsigned int scan_delay_ms;
unsigned int row_hold_ns;
bool wakeup;
bool rep;
};
#endif /*__PMIC8XXX_KEYPAD_H__ */