Commit 88390243 authored by Laxman Dewangan's avatar Laxman Dewangan Committed by Dmitry Torokhov
Browse files

Input: tegra-kbc - add support for rows/columns configuration from dt



The NVIDIA's Tegra KBC has maximum 24 pins to make matrix keypad.
Any pin can be configured as row or column. The maximum column pin
can be 8 and maximum row pin can be 16.

Remove the assumption that all first 16 pins will be used as row
and remaining as columns and Add the property for configuring pins
to either row or column from DT. Update the devicetree binding
document accordingly.

Signed-off-by: default avatarLaxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 00eb81e5
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
* Tegra keyboard controller
The key controller has maximum 24 pins to make matrix keypad. Any pin
can be configured as row or column. The maximum column pin can be 8
and maximum row pins can be 16 for Tegra20/Tegra30.

Required properties:
- compatible: "nvidia,tegra20-kbc"
- reg: Register base address of KBC.
- interrupts: Interrupt number for the KBC.
- nvidia,kbc-row-pins: The KBC pins which are configured as row. This is an
  array of pin numbers which is used as rows.
- nvidia,kbc-col-pins: The KBC pins which are configured as column. This is an
  array of pin numbers which is used as column.
- linux,keymap: The keymap for keys as described in the binding document
  devicetree/bindings/input/matrix-keymap.txt.

Optional properties, in addition to those specified by the shared
matrix-keyboard bindings:
@@ -19,5 +30,16 @@ Example:
keyboard: keyboard {
	compatible = "nvidia,tegra20-kbc";
	reg = <0x7000e200 0x100>;
	interrupts = <0 85 0x04>;
	nvidia,ghost-filter;
	nvidia,debounce-delay-ms = <640>;
	nvidia,kbc-row-pins = <0 1 2>;    /* pin 0, 1, 2 as rows */
	nvidia,kbc-col-pins = <11 12 13>; /* pin 11, 12, 13 as columns */
	linux,keymap = <0x00000074
			0x00010067
			0x00020066
			0x01010068
			0x02000069
			0x02010070
			0x02020071>;
};
+63 −19
Original line number Diff line number Diff line
@@ -614,13 +614,21 @@ static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
	struct device_node *np = pdev->dev.of_node;
	u32 prop;
	int i;
	u32 num_rows = 0;
	u32 num_cols = 0;
	u32 cols_cfg[KBC_MAX_GPIO];
	u32 rows_cfg[KBC_MAX_GPIO];
	int proplen;
	int ret;

	if (!np)
		return NULL;
	if (!np) {
		dev_err(&pdev->dev, "device tree data is missing\n");
		return ERR_PTR(-ENOENT);
	}

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return NULL;
		return ERR_PTR(-ENOMEM);

	if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
		pdata->debounce_cnt = prop;
@@ -634,18 +642,55 @@ static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
	if (of_find_property(np, "nvidia,wakeup-source", NULL))
		pdata->wakeup = true;

	/*
	 * All currently known keymaps with device tree support use the same
	 * pin_cfg, so set it up here.
	 */
	for (i = 0; i < KBC_MAX_ROW; i++) {
		pdata->pin_cfg[i].num = i;
		pdata->pin_cfg[i].type = PIN_CFG_ROW;
	if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
		dev_err(&pdev->dev, "property nvidia,kbc-row-pins not found\n");
		return ERR_PTR(-ENOENT);
	}
	num_rows = proplen / sizeof(u32);

	if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
		dev_err(&pdev->dev, "property nvidia,kbc-col-pins not found\n");
		return ERR_PTR(-ENOENT);
	}
	num_cols = proplen / sizeof(u32);

	if (!of_get_property(np, "linux,keymap", &proplen)) {
		dev_err(&pdev->dev, "property linux,keymap not found\n");
		return ERR_PTR(-ENOENT);
	}

	if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
		dev_err(&pdev->dev,
			"keypad rows/columns not porperly specified\n");
		return ERR_PTR(-EINVAL);
	}

	for (i = 0; i < KBC_MAX_COL; i++) {
		pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
		pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
	/* Set all pins as non-configured */
	for (i = 0; i < KBC_MAX_GPIO; i++)
		pdata->pin_cfg[i].type = PIN_CFG_IGNORE;

	ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
				rows_cfg, num_rows);
	if (ret < 0) {
		dev_err(&pdev->dev, "Rows configurations are not proper\n");
		return ERR_PTR(-EINVAL);
	}

	ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins",
				cols_cfg, num_cols);
	if (ret < 0) {
		dev_err(&pdev->dev, "Cols configurations are not proper\n");
		return ERR_PTR(-EINVAL);
	}

	for (i = 0; i < num_rows; i++) {
		pdata->pin_cfg[rows_cfg[i]].type = PIN_CFG_ROW;
		pdata->pin_cfg[rows_cfg[i]].num = i;
	}

	for (i = 0; i < num_cols; i++) {
		pdata->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
		pdata->pin_cfg[cols_cfg[i]].num = i;
	}

	return pdata;
@@ -654,7 +699,8 @@ static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
	struct platform_device *pdev)
{
	return NULL;
	dev_err(&pdev->dev, "platform data is missing\n");
	return ERR_PTR(-EINVAL);
}
#endif

@@ -700,10 +746,8 @@ static int tegra_kbc_probe(struct platform_device *pdev)
	if (!pdata)
		pdata = tegra_kbc_dt_parse_pdata(pdev);

	if (!pdata) {
		dev_err(&pdev->dev, "Platform data missing\n");
		return -EINVAL;
	}
	if (IS_ERR(pdata))
		return PTR_ERR(pdata);

	if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
		return -EINVAL;