mirror of
https://github.com/brain-hackers/linux-brain.git
synced 2024-06-09 15:26:21 +09:00
Merge pull request #14 from brain-hackers/keyboard
Add keyboard support for newer models
This commit is contained in:
commit
fa266bf78b
|
@ -4,6 +4,7 @@
|
|||
|
||||
/dts-v1/;
|
||||
#include "imx28.dtsi"
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
/ {
|
||||
model = "SHARP Brain PW-SH1";
|
||||
|
@ -236,7 +237,7 @@
|
|||
compatible = "sharp,brain-kbd-i2c";
|
||||
reg = <0x28>;
|
||||
interrupt-parent = <&gpio4>;
|
||||
interrupts = <2 4>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -286,4 +287,9 @@
|
|||
brightness-levels = <0 4 8 16 32 64 128 255>;
|
||||
default-brightness-level = <4>; //Set 4 for identification on probing
|
||||
};
|
||||
|
||||
keyboard_gpio: keyboard_gpio {
|
||||
status = "disabled";
|
||||
compatible = "sharp,brain-kbd-gpio";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
/dts-v1/;
|
||||
#include "imx28-brain.dtsi"
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "SHARP Brain PW-SH3";
|
||||
|
@ -26,3 +27,126 @@
|
|||
<&gpio0 27 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 16 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
&keyboard_gpio {
|
||||
status = "okay";
|
||||
matrix-in-gpios =
|
||||
<&gpio4 0 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 1 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 2 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 3 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 4 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 5 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 6 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 7 GPIO_ACTIVE_HIGH>;
|
||||
matrix-out-gpios =
|
||||
<&gpio2 16 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 17 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 18 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 19 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 20 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 21 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 8 GPIO_ACTIVE_HIGH>;
|
||||
symbol-key = <4 3>;
|
||||
keymap =
|
||||
/* Bank 0x01 */
|
||||
<0 0 KEY_PAGEUP>, /* Eiwa Waei */
|
||||
<0 1 KEY_ESC>, /* Search */
|
||||
<0 2 KEY_TAB>, /* Kokugo */
|
||||
<0 3 KEY_PAGEDOWN>, /* My Dictionary */
|
||||
<0 4 KEY_INSERT>, /* History / Bookmark */
|
||||
<0 5 KEY_DELETE>, /* Marker test */
|
||||
/* <0x01 6 Home>, */
|
||||
|
||||
/* Bank 0x02 */
|
||||
<1 0 KEY_Q>, /* Q */
|
||||
<1 1 KEY_W>, /* W */
|
||||
<1 2 KEY_E>, /* E */
|
||||
<1 3 KEY_T>, /* T */
|
||||
<1 4 KEY_Y>, /* Y */
|
||||
<1 5 KEY_U>, /* U */
|
||||
<1 6 KEY_I>, /* I */
|
||||
|
||||
/* Bank 0x04 */
|
||||
<2 0 KEY_A>, /* A */
|
||||
<2 1 KEY_S>, /* S */
|
||||
<2 2 KEY_D>, /* D */
|
||||
<2 3 KEY_G>, /* G */
|
||||
<2 4 KEY_H>, /* H */
|
||||
<2 5 KEY_O>, /* O */
|
||||
<2 6 KEY_P>, /* P */
|
||||
|
||||
/* Bank 0x08 */
|
||||
<3 0 KEY_Z>, /* Z */
|
||||
<3 1 KEY_X>, /* X */
|
||||
<3 2 KEY_C>, /* C */
|
||||
<3 3 KEY_B>, /* B */
|
||||
<3 4 KEY_J>, /* J */
|
||||
<3 5 KEY_K>, /* K */
|
||||
<3 6 KEY_L>, /* L */
|
||||
|
||||
/* Bank 0x10 */
|
||||
<4 0 KEY_LEFTSHIFT>, /* Shift */
|
||||
<4 1 KEY_R>, /* R */
|
||||
<4 2 KEY_F>, /* F */
|
||||
<4 3 0>, /* Symbols (specify 0 to mark this key used) */
|
||||
<4 4 KEY_N>, /* N */
|
||||
<4 5 KEY_M>, /* M */
|
||||
<4 6 KEY_MINUS>, /* Minus */
|
||||
|
||||
/* Bank 0x20 */
|
||||
<5 0 KEY_V>, /* V */
|
||||
<5 1 KEY_LEFTCTRL>, /* Page Up */
|
||||
<5 2 KEY_SPACE>, /* Space */
|
||||
<5 3 KEY_LEFT>, /* Left */
|
||||
<5 4 KEY_UP>, /* Up */
|
||||
<5 5 KEY_DOWN>, /* Down */
|
||||
<5 6 KEY_RIGHT>, /* Right */
|
||||
|
||||
/* Bank 0x40 */
|
||||
<6 0 KEY_LEFTALT>, /* Switch characters */
|
||||
/* <6 1 KEY_PAGEDOWN>, */ /* Page Down */
|
||||
/* <6 2 Memorization tool> */
|
||||
<6 3 KEY_ESC>, /* Go Back */
|
||||
<6 4 KEY_ENTER>, /* Enter */
|
||||
/* <6 5 ?> */
|
||||
<6 6 KEY_BACKSPACE>; /* Backspace */
|
||||
keymap-symbol =
|
||||
<0 0 KEY_PAGEUP>, /* Eiwa Waei */
|
||||
<0 1 KEY_ESC>, /* Search */
|
||||
<0 2 KEY_TAB>, /* Kokugo */
|
||||
<0 3 KEY_PAGEDOWN>, /* My Dictionary */
|
||||
<0 4 KEY_INSERT>, /* History / Bookmark */
|
||||
<0 5 KEY_DELETE>, /* Marker test */
|
||||
/* <0 6 Home>, */
|
||||
|
||||
<1 0 KEY_1>, /* Q */
|
||||
<1 1 KEY_2>, /* W */
|
||||
<1 2 KEY_3>, /* E */
|
||||
<1 3 KEY_5>, /* T */
|
||||
<1 4 KEY_6>, /* Y */
|
||||
<1 5 KEY_7>, /* U */
|
||||
<1 6 KEY_8>, /* I */
|
||||
|
||||
<2 2 KEY_GRAVE>, /* D */
|
||||
<2 3 KEY_BACKSLASH>, /* G */
|
||||
<2 4 KEY_SEMICOLON>, /* H */
|
||||
<2 5 KEY_9>, /* O */
|
||||
<2 6 KEY_0>, /* P */
|
||||
|
||||
<3 4 KEY_APOSTROPHE>, /* J */
|
||||
<3 5 KEY_LEFTBRACE>, /* K */
|
||||
<3 6 KEY_RIGHTBRACE>, /* L */
|
||||
|
||||
<4 0 KEY_LEFTSHIFT>, /* Shift */
|
||||
<4 1 KEY_4>, /* R */
|
||||
<4 2 KEY_EQUAL>, /* F */
|
||||
<4 4 KEY_COMMA>, /* N */
|
||||
<4 5 KEY_DOT>, /* M */
|
||||
<4 6 KEY_SLASH>, /* Minus */
|
||||
|
||||
<5 1 KEY_LEFTCTRL>, /* Page Up */
|
||||
|
||||
<6 0 KEY_LEFTALT>, /* Switch characters */
|
||||
<6 6 KEY_BACKSPACE>; /* Backspace */
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
/dts-v1/;
|
||||
#include "imx28-brain.dtsi"
|
||||
#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
model = "SHARP Brain PW-SH5";
|
||||
|
@ -26,3 +27,123 @@
|
|||
<&gpio0 27 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 16 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
&keyboard_gpio {
|
||||
status = "okay";
|
||||
matrix-in-gpios =
|
||||
<&gpio4 0 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 1 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 2 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 3 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 4 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 5 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 6 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 7 GPIO_ACTIVE_HIGH>;
|
||||
matrix-out-gpios =
|
||||
<&gpio2 16 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 17 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 18 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 19 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 20 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio2 21 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio4 8 GPIO_ACTIVE_HIGH>;
|
||||
symbol-key = <4 6>;
|
||||
keymap =
|
||||
/* Bank 0x01 */
|
||||
<0 6 KEY_PAGEUP>, /* Kokugo */
|
||||
<0 0 KEY_TAB>, /* Brain English */
|
||||
<0 5 KEY_PAGEDOWN>, /* Eiwa Waei */
|
||||
<0 4 KEY_INSERT>, /* My Discitonary */
|
||||
<0 3 KEY_DELETE>, /* History */
|
||||
|
||||
/* Bank 0x02 */
|
||||
<1 0 KEY_P>, /* P */
|
||||
<1 1 KEY_O>, /* O */
|
||||
<1 2 KEY_I>, /* I */
|
||||
<1 3 KEY_U>, /* U */
|
||||
<1 4 KEY_Y>, /* Y */
|
||||
<1 5 KEY_T>, /* T */
|
||||
<1 6 KEY_R>, /* R */
|
||||
|
||||
/* Bank 0x04 */
|
||||
<2 0 KEY_L>, /* L */
|
||||
<2 1 KEY_K>, /* K */
|
||||
<2 2 KEY_J>, /* J */
|
||||
<2 3 KEY_H>, /* H */
|
||||
<2 4 KEY_G>, /* G */
|
||||
<2 5 KEY_F>, /* F */
|
||||
<2 6 KEY_D>, /* D */
|
||||
|
||||
/* Bank 0x08 */
|
||||
<3 0 KEY_BACKSPACE>, /* Backspace */
|
||||
<3 1 KEY_MINUS>, /* Minus */
|
||||
<3 2 KEY_M>, /* M */
|
||||
<3 3 KEY_UP>, /* Up */
|
||||
<3 4 KEY_N>, /* N */
|
||||
<3 5 KEY_B>, /* B */
|
||||
<3 6 KEY_V>, /* V */
|
||||
|
||||
/* Bank 0x10 */
|
||||
<4 0 KEY_ENTER>, /* Enter */
|
||||
<4 1 KEY_RIGHT>, /* Right */
|
||||
<4 2 KEY_DOWN>, /* Down */
|
||||
<4 3 KEY_LEFT>, /* Left */
|
||||
<4 4 KEY_ESC>, /* Go Back */
|
||||
<4 5 KEY_SPACE>, /* Space */
|
||||
<4 6 0>, /* Symbols (specify 0 to mark this key used) */
|
||||
|
||||
/* Bank 0x20 */
|
||||
<5 0 KEY_ESC>, /* Home */
|
||||
<5 1 KEY_Q>, /* Q */
|
||||
<5 2 KEY_W>, /* W */
|
||||
<5 3 KEY_E>, /* E */
|
||||
<5 4 KEY_A>, /* A */
|
||||
<5 5 KEY_S>, /* S */
|
||||
<5 6 KEY_RIGHT>, /* Right */
|
||||
|
||||
/* Bank 0x40 */
|
||||
<6 0 KEY_LEFTSHIFT>, /* Shift */
|
||||
<6 1 KEY_Z>, /* Z */
|
||||
<6 2 KEY_X>, /* X */
|
||||
<6 3 KEY_C>, /* C */
|
||||
<6 4 KEY_LEFTCTRL>, /* PageUp */
|
||||
/* <6 5 ?> */
|
||||
<6 6 KEY_LEFTALT>; /* Onsei */
|
||||
keymap-symbol =
|
||||
<0 6 KEY_PAGEUP>, /* Kokugo */
|
||||
<0 0 KEY_TAB>, /* Brain English */
|
||||
<0 5 KEY_PAGEDOWN>, /* Eiwa Waei */
|
||||
<0 4 KEY_INSERT>, /* My Discitonary */
|
||||
<0 3 KEY_DELETE>, /* History */
|
||||
|
||||
<1 0 KEY_0>, /* P */
|
||||
<1 1 KEY_9>, /* O */
|
||||
<1 2 KEY_8>, /* I */
|
||||
<1 3 KEY_7>, /* U */
|
||||
<1 4 KEY_6>, /* Y */
|
||||
<1 5 KEY_5>, /* T */
|
||||
<1 6 KEY_4>, /* R */
|
||||
<5 3 KEY_3>, /* E */
|
||||
<5 2 KEY_2>, /* W */
|
||||
<5 1 KEY_1>, /* Q */
|
||||
|
||||
<2 6 KEY_GRAVE>, /* D */
|
||||
<2 4 KEY_BACKSLASH>, /* G */
|
||||
<2 3 KEY_SEMICOLON>, /* H */
|
||||
|
||||
|
||||
<2 2 KEY_APOSTROPHE>, /* J */
|
||||
<2 1 KEY_LEFTBRACE>, /* K */
|
||||
<2 0 KEY_RIGHTBRACE>, /* L */
|
||||
|
||||
<6 0 KEY_LEFTSHIFT>, /* Shift */
|
||||
<2 5 KEY_EQUAL>, /* F */
|
||||
<3 4 KEY_COMMA>, /* N */
|
||||
<3 2 KEY_DOT>, /* M */
|
||||
<3 1 KEY_SLASH>, /* Minus */
|
||||
|
||||
<6 4 KEY_LEFTCTRL>, /* Page Up */
|
||||
|
||||
<6 6 KEY_LEFTALT>, /* Onsei */
|
||||
<3 0 KEY_BACKSPACE>; /* Backspace */
|
||||
};
|
||||
|
|
|
@ -100,7 +100,9 @@ CONFIG_RTW88=y
|
|||
# CONFIG_WLAN_VENDOR_TI is not set
|
||||
# CONFIG_WLAN_VENDOR_ZYDAS is not set
|
||||
# CONFIG_WLAN_VENDOR_QUANTENNA is not set
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_KEYBOARD_BRAIN_GPIO=y
|
||||
CONFIG_KEYBOARD_BRAIN_I2C=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
|
|
|
@ -766,6 +766,16 @@ config KEYBOARD_BCM
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called bcm-keypad.
|
||||
|
||||
config KEYBOARD_BRAIN_GPIO
|
||||
tristate "SHARP Brain keyboard (GPIO)"
|
||||
depends on OF && GPIOLIB
|
||||
help
|
||||
Say Y here to enable the SHARP Brain keyboard driver
|
||||
which is accessible via GPIO.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called brain-kbd-gpio.
|
||||
|
||||
config KEYBOARD_BRAIN_I2C
|
||||
tristate "SHARP Brain keyboard (I2C)"
|
||||
depends on OF && I2C
|
||||
|
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o
|
|||
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
|
||||
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_BRAIN_GPIO) += brain-kbd-gpio.o
|
||||
obj-$(CONFIG_KEYBOARD_BRAIN_I2C) += brain-kbd-i2c.o
|
||||
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
|
||||
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
|
||||
|
|
339
drivers/input/keyboard/brain-kbd-gpio.c
Normal file
339
drivers/input/keyboard/brain-kbd-gpio.c
Normal file
|
@ -0,0 +1,339 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SHARP Brain keyboard (I2C) driver
|
||||
*
|
||||
* Copyright 2021 Takumi Sueda
|
||||
*
|
||||
* Author: Takumi Sueda <puhitaku@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define DEV_NAME "brain-kbd-gpio"
|
||||
|
||||
#define BK_CMD_KEYCODE 0x04
|
||||
|
||||
#define BK_IS_PRESSED(val) ((~val & 0x40) >> 6)
|
||||
|
||||
struct bk_gpio_data {
|
||||
struct input_polled_dev *polldev;
|
||||
struct gpio_desc* in[8];
|
||||
struct gpio_desc* out[7];
|
||||
unsigned int km[7][7];
|
||||
unsigned int km_symbol[7][7];
|
||||
int kmlen;
|
||||
int kmlen_symbol;
|
||||
unsigned int sym_key_bank;
|
||||
unsigned int sym_key_num;
|
||||
|
||||
bool symbol;
|
||||
ulong last_in[7];
|
||||
bool pressed[7][7];
|
||||
};
|
||||
|
||||
static void bk_gpio_read_keys(struct input_polled_dev *polldev, ulong* result)
|
||||
{
|
||||
struct bk_gpio_data *kbd = polldev->private;
|
||||
struct device *dev = &polldev->input->dev;
|
||||
int try, i, err;
|
||||
ulong in[10][7];
|
||||
|
||||
for (try = 0; try < ARRAY_SIZE(in); try++) {
|
||||
for (i = 0; i < ARRAY_SIZE(in[0]); i++) {
|
||||
gpiod_set_value(kbd->out[i], 1);
|
||||
udelay(100);
|
||||
in[try][i] = 0;
|
||||
err = gpiod_get_array_value(8, kbd->in, NULL, &in[try][i]);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to get array value: %d\n", err);
|
||||
}
|
||||
in[try][i] = ~(((in[try][i] ^ (in[try][i] >> 1)) & 0x1f) ^ (in[try][i] >> 1)) & 0x7f;
|
||||
gpiod_set_value(kbd->out[i], 0);
|
||||
}
|
||||
|
||||
if (try < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
memcmp(in[try-2], in[try-1], sizeof(in[0])) == 0 &&
|
||||
memcmp(in[try-1], in[try], sizeof(in[0])) == 0
|
||||
) {
|
||||
for (i = 0; i < ARRAY_SIZE(in[0]); i++) {
|
||||
result[i] = in[try][i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// not to exceed 10ms in total
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (try == ARRAY_SIZE(in)) {
|
||||
dev_dbg(dev, "failed to debounce: exceeded %d tries\n", ARRAY_SIZE(in));
|
||||
for (i = 0; i < ARRAY_SIZE(in[0]); i++) {
|
||||
result[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bk_gpio_poll(struct input_polled_dev *polldev)
|
||||
{
|
||||
struct bk_gpio_data *kbd = polldev->private;
|
||||
struct device *dev = &polldev->input->dev;
|
||||
int i, j, bank;
|
||||
ulong in[7], agg;
|
||||
|
||||
bk_gpio_read_keys(polldev, in);
|
||||
|
||||
if (memcmp(in, kbd->last_in, sizeof(in)) == 0) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
dev_dbg(
|
||||
dev,
|
||||
"%02lx %02lx %02lx %02lx %02lx %02lx %02lx",
|
||||
in[0], in[1], in[2], in[3], in[4], in[5], in[6]
|
||||
);
|
||||
|
||||
agg = 0;
|
||||
for (i = 0; i < 7; i++) {
|
||||
agg |= in[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
bank = 1 << i;
|
||||
if (agg & bank) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
// skip invalid keymap
|
||||
if (kbd->km[i][j] == UINT_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((in[j] & bank) == 0) {
|
||||
if (!kbd->pressed[i][j]) {
|
||||
if (i == kbd->sym_key_bank && j == kbd->sym_key_num) {
|
||||
dev_dbg(dev, "symbol\n");
|
||||
kbd->symbol = true;
|
||||
} else {
|
||||
dev_dbg(dev, "P: %04x\n", kbd->km[i][j]);
|
||||
input_report_key(
|
||||
polldev->input,
|
||||
kbd->symbol ? kbd->km_symbol[i][j] : kbd->km[i][j],
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
kbd->pressed[i][j] = true;
|
||||
} else {
|
||||
kbd->pressed[i][j] = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// flush deasserted bank
|
||||
for (j = 0; j < 7; j++) {
|
||||
if (!kbd->pressed[i][j]) {
|
||||
continue;
|
||||
}
|
||||
kbd->pressed[i][j] = false;
|
||||
|
||||
if (i == kbd->sym_key_bank && j == kbd->sym_key_num) {
|
||||
kbd->symbol = false;
|
||||
} else {
|
||||
dev_dbg(dev, "R: %04x\n", kbd->km[i][j]);
|
||||
input_report_key(polldev->input, kbd->km[i][j], 0);
|
||||
input_report_key(polldev->input, kbd->km_symbol[i][j], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(polldev->input);
|
||||
skip:
|
||||
memcpy(kbd->last_in, in, sizeof(in));
|
||||
}
|
||||
|
||||
static int bk_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bk_gpio_data *kbd;
|
||||
int i, j, count, err, cells, len, offset;
|
||||
struct gpio_desc *gpio;
|
||||
u32 keydef[3];
|
||||
|
||||
kbd = devm_kzalloc(dev, sizeof(*kbd), GFP_KERNEL);
|
||||
if (!kbd) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
count = gpiod_count(dev, "matrix-in");
|
||||
if (count != 8) {
|
||||
dev_err(dev, "expected length of matrix-in-gpios is 8, not %d\n", count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < gpiod_count(dev, "matrix-in"); i++) {
|
||||
gpio = devm_gpiod_get_index(dev, "matrix-in", i, GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "failed to get input gpio %d\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
kbd->in[i] = gpio;
|
||||
}
|
||||
|
||||
count = gpiod_count(dev, "matrix-out");
|
||||
if (count != 7) {
|
||||
dev_err(dev, "expected length of matrix-out-gpios is 7, not %d\n", count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < gpiod_count(dev, "matrix-out"); i++) {
|
||||
gpio = devm_gpiod_get_index(dev, "matrix-out", i, GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "failed to get output gpio %d\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
gpiod_set_value(gpio, 0);
|
||||
kbd->out[i] = gpio;
|
||||
}
|
||||
|
||||
// Init input device
|
||||
|
||||
kbd->polldev = devm_input_allocate_polled_device(dev);
|
||||
if (!kbd->polldev) {
|
||||
dev_err(dev, "failed to allocate inpute device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kbd->polldev->private = kbd;
|
||||
kbd->polldev->poll = bk_gpio_poll;
|
||||
kbd->polldev->poll_interval = 100;
|
||||
kbd->polldev->input->name = DEV_NAME;
|
||||
kbd->polldev->input->id.bustype = BUS_HOST;
|
||||
|
||||
__set_bit(EV_KEY, kbd->polldev->input->evbit); /* FIXME: is it really necessary? */
|
||||
__set_bit(EV_REP, kbd->polldev->input->evbit); /* autorepeat */
|
||||
|
||||
// Parse keymap
|
||||
|
||||
cells = 3;
|
||||
if (!of_get_property(dev->of_node, "keymap", &len)) {
|
||||
dev_err(dev, "DT node has no keymap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len /= sizeof(u32) * cells;
|
||||
kbd->kmlen = len;
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
// sentinel value to indicate unused mapping
|
||||
kbd->km[i][j] = UINT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
offset = i * cells;
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (of_property_read_u32_index(dev->of_node, "keymap",
|
||||
offset + j, keydef + j)) {
|
||||
dev_err(dev,
|
||||
"could not read DT property (brain keycode)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
kbd->km[keydef[0] & 0xff][keydef[1] & 0xff] = keydef[2];
|
||||
dev_dbg(dev, "normal: brain: %x %x, kernel: %x",
|
||||
keydef[0], keydef[1], keydef[2]);
|
||||
|
||||
input_set_capability(kbd->polldev->input, EV_KEY, keydef[2]);
|
||||
}
|
||||
|
||||
if (!of_get_property(dev->of_node, "keymap-symbol", &len)) {
|
||||
dev_err(dev, "DT node has no keymap (symbol)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
len /= sizeof(u32) * cells;
|
||||
kbd->kmlen_symbol = len;
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
// sentinel value to indicate unused mapping
|
||||
kbd->km_symbol[i][j] = UINT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
offset = i * cells;
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (of_property_read_u32_index(dev->of_node, "keymap-symbol",
|
||||
offset + j, keydef + j)) {
|
||||
dev_err(dev,
|
||||
"could not read DT property (brain keycode)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
kbd->km_symbol[keydef[0] & 0xff][keydef[1] & 0xff] = keydef[2];
|
||||
dev_dbg(dev, "symbol: brain: %02x %02x, kernel: %02x",
|
||||
keydef[0], keydef[1], keydef[2]);
|
||||
|
||||
input_set_capability(kbd->polldev->input, EV_KEY, keydef[2]);
|
||||
}
|
||||
|
||||
if (of_property_read_u32_index(dev->of_node, "symbol-key", 0, &kbd->sym_key_bank)) {
|
||||
dev_err(dev, "could not read symbol key bank\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(dev, "sym_key_bank = %d\n", kbd->sym_key_bank);
|
||||
|
||||
if (of_property_read_u32_index(dev->of_node, "symbol-key", 1, &kbd->sym_key_num)) {
|
||||
dev_err(dev, "could not read symbol key num\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(dev, "sym_key_num = %d\n", kbd->sym_key_num);
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
kbd->pressed[i][j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
err = input_register_polled_device(kbd->polldev);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to register input device: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bk_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "sharp,brain-kbd-gpio",
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver bk_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DEV_NAME,
|
||||
.of_match_table = of_match_ptr(bk_gpio_of_match),
|
||||
},
|
||||
.probe = bk_gpio_probe,
|
||||
};
|
||||
module_platform_driver(bk_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Takumi Sueda <puhitaku@gmail.com>");
|
||||
MODULE_DESCRIPTION("SHARP Brain keyboard driver");
|
||||
MODULE_LICENSE("GPL v2");
|
Loading…
Reference in New Issue
Block a user