|
@@ -41,6 +41,9 @@
|
|
|
#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */
|
|
|
#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */
|
|
|
|
|
|
+#define KPDK_DKP (0x1 << 31)
|
|
|
+#define KPDK_DK(n) ((n) & 0xff)
|
|
|
+
|
|
|
#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
|
|
|
#define KPAS_RP(n) (((n) >> 4) & 0xf)
|
|
|
#define KPAS_CP(n) ((n) & 0xf)
|
|
@@ -60,6 +63,13 @@ struct pxa27x_keypad {
|
|
|
|
|
|
/* state row bits of each column scan */
|
|
|
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
|
|
|
+ uint32_t direct_key_state;
|
|
|
+
|
|
|
+ unsigned int direct_key_mask;
|
|
|
+
|
|
|
+ int rotary_rel_code[2];
|
|
|
+ int rotary_up_key[2];
|
|
|
+ int rotary_down_key[2];
|
|
|
};
|
|
|
|
|
|
static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
|
|
@@ -78,6 +88,25 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
|
|
|
keypad->matrix_keycodes[(row << 3) + col] = code;
|
|
|
set_bit(code, input_dev->keybit);
|
|
|
}
|
|
|
+
|
|
|
+ keypad->rotary_up_key[0] = pdata->rotary0_up_key;
|
|
|
+ keypad->rotary_up_key[1] = pdata->rotary1_up_key;
|
|
|
+ keypad->rotary_down_key[0] = pdata->rotary0_down_key;
|
|
|
+ keypad->rotary_down_key[1] = pdata->rotary1_down_key;
|
|
|
+ keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
|
|
|
+ keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
|
|
|
+
|
|
|
+ if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
|
|
|
+ set_bit(pdata->rotary0_up_key, input_dev->keybit);
|
|
|
+ set_bit(pdata->rotary0_down_key, input_dev->keybit);
|
|
|
+ } else
|
|
|
+ set_bit(pdata->rotary0_rel_code, input_dev->relbit);
|
|
|
+
|
|
|
+ if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
|
|
|
+ set_bit(pdata->rotary1_up_key, input_dev->keybit);
|
|
|
+ set_bit(pdata->rotary1_down_key, input_dev->keybit);
|
|
|
+ } else
|
|
|
+ set_bit(pdata->rotary1_rel_code, input_dev->relbit);
|
|
|
}
|
|
|
|
|
|
static inline unsigned int lookup_matrix_keycode(
|
|
@@ -151,35 +180,92 @@ scan:
|
|
|
|
|
|
#define DEFAULT_KPREC (0x007f007f)
|
|
|
|
|
|
+static inline int rotary_delta(uint32_t kprec)
|
|
|
+{
|
|
|
+ if (kprec & KPREC_OF0)
|
|
|
+ return (kprec & 0xff) + 0x7f;
|
|
|
+ else if (kprec & KPREC_UF0)
|
|
|
+ return (kprec & 0xff) - 0x7f - 0xff;
|
|
|
+ else
|
|
|
+ return (kprec & 0xff) - 0x7f;
|
|
|
+}
|
|
|
+
|
|
|
+static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
|
|
|
+{
|
|
|
+ struct input_dev *dev = keypad->input_dev;
|
|
|
+
|
|
|
+ if (delta == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
|
|
|
+ int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
|
|
|
+ keypad->rotary_down_key[r];
|
|
|
+
|
|
|
+ /* simulate a press-n-release */
|
|
|
+ input_report_key(dev, keycode, 1);
|
|
|
+ input_sync(dev);
|
|
|
+ input_report_key(dev, keycode, 0);
|
|
|
+ input_sync(dev);
|
|
|
+ } else {
|
|
|
+ input_report_rel(dev, keypad->rotary_rel_code[r], delta);
|
|
|
+ input_sync(dev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
|
|
|
+{
|
|
|
+ struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
|
|
+ uint32_t kprec;
|
|
|
+
|
|
|
+ /* read and reset to default count value */
|
|
|
+ kprec = KPREC;
|
|
|
+ KPREC = DEFAULT_KPREC;
|
|
|
+
|
|
|
+ if (pdata->enable_rotary0)
|
|
|
+ report_rotary_event(keypad, 0, rotary_delta(kprec));
|
|
|
+
|
|
|
+ if (pdata->enable_rotary1)
|
|
|
+ report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
|
|
|
+}
|
|
|
+
|
|
|
+static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
|
|
+{
|
|
|
+ struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
|
|
+ unsigned int new_state;
|
|
|
+ uint32_t kpdk, bits_changed;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ kpdk = KPDK;
|
|
|
+
|
|
|
+ if (pdata->enable_rotary0 || pdata->enable_rotary1)
|
|
|
+ pxa27x_keypad_scan_rotary(keypad);
|
|
|
+
|
|
|
+ if (pdata->direct_key_map == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
|
|
|
+ bits_changed = keypad->direct_key_state ^ new_state;
|
|
|
+
|
|
|
+ if (bits_changed == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; i < pdata->direct_key_num; i++) {
|
|
|
+ if (bits_changed & (1 << i))
|
|
|
+ input_report_key(keypad->input_dev,
|
|
|
+ pdata->direct_key_map[i],
|
|
|
+ (new_state & (1 << i)));
|
|
|
+ }
|
|
|
+ input_sync(keypad->input_dev);
|
|
|
+ keypad->direct_key_state = new_state;
|
|
|
+}
|
|
|
+
|
|
|
static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
|
|
|
{
|
|
|
struct pxa27x_keypad *keypad = dev_id;
|
|
|
- struct input_dev *input_dev = keypad->input_dev;
|
|
|
unsigned long kpc = KPC;
|
|
|
- int rel;
|
|
|
-
|
|
|
- if (kpc & KPC_DI) {
|
|
|
- unsigned long kpdk = KPDK;
|
|
|
-
|
|
|
- if (!(kpdk & KPDK_DKP)) {
|
|
|
- /* better luck next time */
|
|
|
- } else if (kpc & KPC_REE0) {
|
|
|
- unsigned long kprec = KPREC;
|
|
|
- KPREC = 0x7f;
|
|
|
-
|
|
|
- if (kprec & KPREC_OF0)
|
|
|
- rel = (kprec & 0xff) + 0x7f;
|
|
|
- else if (kprec & KPREC_UF0)
|
|
|
- rel = (kprec & 0xff) - 0x7f - 0xff;
|
|
|
- else
|
|
|
- rel = (kprec & 0xff) - 0x7f;
|
|
|
-
|
|
|
- if (rel) {
|
|
|
- input_report_rel(input_dev, REL_WHEEL, rel);
|
|
|
- input_sync(input_dev);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
+ if (kpc & KPC_DI)
|
|
|
+ pxa27x_keypad_scan_direct(keypad);
|
|
|
|
|
|
if (kpc & KPC_MI)
|
|
|
pxa27x_keypad_scan_matrix(keypad);
|
|
@@ -190,6 +276,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
|
|
|
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
|
|
|
{
|
|
|
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
|
|
+ unsigned int mask = 0, direct_key_num = 0;
|
|
|
unsigned long kpc = 0;
|
|
|
|
|
|
/* enable matrix keys with automatic scan */
|
|
@@ -199,10 +286,29 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
|
|
|
KPC_MKCN(pdata->matrix_key_cols);
|
|
|
}
|
|
|
|
|
|
- /* FIXME: hardcoded to enable rotary 0 _only_ */
|
|
|
- kpc |= KPC_DKN(2) | KPC_REE0 | KPC_DI | KPC_DIE;
|
|
|
+ /* enable rotary key, debounce interval same as direct keys */
|
|
|
+ if (pdata->enable_rotary0) {
|
|
|
+ mask |= 0x03;
|
|
|
+ direct_key_num = 2;
|
|
|
+ kpc |= KPC_REE0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pdata->enable_rotary1) {
|
|
|
+ mask |= 0x0c;
|
|
|
+ direct_key_num = 4;
|
|
|
+ kpc |= KPC_REE1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pdata->direct_key_num > direct_key_num)
|
|
|
+ direct_key_num = pdata->direct_key_num;
|
|
|
+
|
|
|
+ keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
|
|
|
+
|
|
|
+ /* enable direct key */
|
|
|
+ if (direct_key_num)
|
|
|
+ kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num);
|
|
|
|
|
|
- KPC = kpc;
|
|
|
+ KPC = kpc | KPC_RE_ZERO_DEB;
|
|
|
KPREC = DEFAULT_KPREC;
|
|
|
}
|
|
|
|
|
@@ -301,7 +407,6 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
|
|
|
|
|
|
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
|
|
|
BIT_MASK(EV_REL);
|
|
|
- input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
|
|
|
|
|
|
pxa27x_keypad_build_keycode(keypad);
|
|
|
|