1 This patch adds support for Sharp CE-RH2 on Spitz.
3 It is not clean enough to be upstreamed:
4 - It is a bit syslog-noisy.
5 - Does not support other Zaurus models.
6 - Maybe split to more parts:
9 * virtual keyboard on top of linear input device
11 Index: linux-2.6.26/arch/arm/mach-pxa/spitz.c
12 ===================================================================
13 --- linux-2.6.26.orig/arch/arm/mach-pxa/spitz.c 2008-07-13 21:51:29.000000000 +0000
14 +++ linux-2.6.26/arch/arm/mach-pxa/spitz.c 2008-07-15 10:11:15.000000000 +0000
20 + * Spitz Remote Control Device
22 +static struct platform_device sharpsl_rc_device = {
23 + .name = "sharpsl-remote-control",
37 Index: linux-2.6.26/drivers/input/keyboard/Kconfig
38 ===================================================================
39 --- linux-2.6.26.orig/drivers/input/keyboard/Kconfig 2008-07-13 21:51:29.000000000 +0000
40 +++ linux-2.6.26/drivers/input/keyboard/Kconfig 2008-07-15 10:11:15.000000000 +0000
43 Say Y only if you know, what you are doing!
46 + tristate "Sharp SL-Cxx00 Remote Control"
47 + depends on PXA_SHARPSL
50 + Say Y here to enable the remote on the Sharp Zaurus SL-Cxx00,
51 + SL-C1000, SL-C3000 and Sl-C3100 series of PDAs.
53 + To compile this driver as a module, choose M here: the
54 + module will be called sharpsl_rc.
57 tristate "Amiga keyboard"
59 Index: linux-2.6.26/drivers/input/keyboard/Makefile
60 ===================================================================
61 --- linux-2.6.26.orig/drivers/input/keyboard/Makefile 2008-07-13 21:51:29.000000000 +0000
62 +++ linux-2.6.26/drivers/input/keyboard/Makefile 2008-07-15 10:11:15.000000000 +0000
64 obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
65 obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
66 obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
67 +obj-$(CONFIG_SHARPSL_RC) += sharpsl_rc.o
68 obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
69 Index: linux-2.6.26/drivers/input/keyboard/sharpsl_rc.c
70 ===================================================================
71 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
72 +++ linux-2.6.26/drivers/input/keyboard/sharpsl_rc.c 2008-07-15 10:11:15.000000000 +0000
75 + * Keyboard driver for Sharp Clamshell Models (SL-Cxx00)
77 + * Copyright (c) 2004-2005 Richard Purdie
79 + * Based on corgikbd.c and Sharp's RC driver
81 + * This program is free software; you can redistribute it and/or modify
82 + * it under the terms of the GNU General Public License version 2 as
83 + * published by the Free Software Foundation.
88 +#include <linux/delay.h>
89 +#include <linux/platform_device.h>
90 +#include <linux/init.h>
91 +#include <linux/input.h>
92 +#include <linux/interrupt.h>
93 +#include <linux/jiffies.h>
94 +#include <linux/module.h>
95 +#include <linux/slab.h>
97 +#include <asm/mach-types.h>
98 +#include <asm/arch/spitz.h>
99 +#include <asm/arch/akita.h>
100 +#include <asm/arch/corgi.h>
102 +#include <asm/arch/hardware.h>
103 +#include <asm/arch/pxa-regs.h>
104 +#include <asm/arch/pxa2xx-gpio.h>
105 +#include <asm/hardware/scoop.h>
106 +#include <asm/arch/sharpsl.h>
107 +#include <asm/hardware/sharpsl_pm.h>
109 +#define DPRINTK(fmt, args...) dev_dbg(data->dev, fmt "\n", ##args)
111 +struct remote_control_key {
117 +static struct remote_control_key remote_keys_spitz[] = {
118 + /* CE-RH2 values */
119 + { 25, 35, KEY_STOPCD},
120 + { 55, 65, KEY_PLAYPAUSE},
121 + { 85, 95, KEY_NEXTSONG},
122 + { 115, 125, KEY_VOLUMEUP},
123 + { 145, 155, KEY_PREVIOUSSONG},
124 + { 180, 190, KEY_MUTE},
125 + { 215, 225, KEY_VOLUMEDOWN},
127 +static struct remote_control_key remote_keys_corgi[] = {
128 + /* CE-RH1 values */
129 + { 27, 35, KEY_STOPCD},
130 + { 7, 13, KEY_PLAYPAUSE},
131 + { 77, 93, KEY_NEXTSONG},
132 + { 115, 132, KEY_VOLUMEUP},
133 + { 46, 58, KEY_PREVIOUSSONG},
134 + { 170, 186, KEY_VOLUMEDOWN},
137 +#define RELEASE_HI 230
138 +#define MAX_EARPHONE 6
139 +#define RC_POLL_MS 10
140 +#define RC_FINISH_MS 500
141 +#define WAIT_STATE 3
142 +#define NOISE_THRESHOLD 100
145 + struct input_dev *input;
146 + struct device *dev;
149 + struct timer_list rctimer;
150 + struct timer_list rctimer_finish;
152 + unsigned int handling_press;
153 + unsigned int noise;
154 + unsigned int state;
155 + unsigned int last_key;
158 +static int get_remocon_raw(void)
161 + struct remote_control_key *remote_keys;
163 + if (machine_is_borzoi() || machine_is_spitz() || machine_is_akita())
164 + remote_keys = remote_keys_spitz;
166 + remote_keys = remote_keys_corgi;
168 + val = sharpsl_pm_pxa_read_max1111(MAX1111_REMCOM);
169 + for (i = 0; i < (machine_is_borzoi() || machine_is_spitz() || machine_is_akita() ?
170 + ARRAY_SIZE(remote_keys_spitz) : ARRAY_SIZE(remote_keys_corgi));
172 + if (val >= remote_keys[i].min
173 + && val <= remote_keys[i].max) {
174 + printk("get_remocon_raw: VAL=%i, KEY=%i\n", val, remote_keys[i].key);
175 + return remote_keys[i].key;
181 +static irqreturn_t sharpsl_rc_interrupt(int irq, void *dev_id)
183 + struct sharpsl_rc *data = dev_id;
184 + DPRINTK("sharpsl_rc_interrupt %d\n", irq);
185 + if (!data->handling_press) {
186 + DPRINTK("handling interrupt");
187 + data->handling_press = 1;
190 + data->last_key = 0;
192 + if (machine_is_borzoi() || machine_is_spitz())
193 + reset_scoop_gpio(platform_scoop_config->devs[1].dev, SPITZ_SCP2_AKIN_PULLUP);
194 + else if (machine_is_akita())
195 + akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_AKIN_PULLUP);
197 + reset_scoop_gpio(platform_scoop_config->devs[0].dev, CORGI_SCP_AKIN_PULLUP);
198 + mod_timer(&data->rctimer, jiffies + msecs_to_jiffies(RC_POLL_MS));
200 + return IRQ_HANDLED;
203 +static void sharpsl_rc_timer_callback(unsigned long dataPtr)
205 + struct sharpsl_rc *data = (struct sharpsl_rc *) dataPtr;
207 + int key = get_remocon_raw();
208 + DPRINTK("timer callback, key: %d", key);
210 + //wait for value to stabilize
211 + if (data->state < WAIT_STATE) {
212 + if (data->last_key != key) {
214 + if (data->noise > NOISE_THRESHOLD) {
215 + DPRINTK("too much noise, bailing");
222 + data->last_key = key;
224 + //stable value, send event
225 + } else if (data->state == WAIT_STATE) {
227 + //non-key returned, skip the rest of the states and bail now
228 + if (data->last_key == 0) {
229 + DPRINTK("non-key detected %d, noise: %d", data->last_key, data->noise);
231 + //send button press
233 + DPRINTK("key press detected %d, noise %d", data->last_key, data->noise);
234 + input_report_key(data->input, data->last_key, 1);
238 + //wait until key is released
239 + } else if (data->state < WAIT_STATE * 2) {
240 + if (key == data->last_key
241 + && data->noise < NOISE_THRESHOLD) {
242 + data->state = WAIT_STATE + 1;
247 + //key is released, send event
249 + //send button release
250 + DPRINTK("release key %d", data->last_key);
251 + input_report_key(data->input, data->last_key, 0);
255 + mod_timer(&data->rctimer, jiffies + msecs_to_jiffies(RC_POLL_MS));
257 + if (machine_is_borzoi() || machine_is_spitz())
258 + set_scoop_gpio(platform_scoop_config->devs[1].dev, SPITZ_SCP2_AKIN_PULLUP);
259 + else if (machine_is_akita())
260 + akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_AKIN_PULLUP);
262 + set_scoop_gpio(platform_scoop_config->devs[0].dev, CORGI_SCP_AKIN_PULLUP);
263 + data->handling_press = 0;
267 +static int __init sharpsl_rc_probe(struct platform_device *pdev)
269 + struct sharpsl_rc *sharpsl_rc;
270 + struct input_dev *input_dev;
272 + struct remote_control_key *remote_keys;
274 + dev_dbg(&pdev->dev, "sharpsl_rc_probe\n");
276 + sharpsl_rc = kzalloc(sizeof(struct sharpsl_rc), GFP_KERNEL);
277 + input_dev = input_allocate_device();
278 + if (!sharpsl_rc || !input_dev) {
280 + input_free_device(input_dev);
284 + platform_set_drvdata(pdev, sharpsl_rc);
286 + sharpsl_rc->dev = &pdev->dev;
287 + sharpsl_rc->input = input_dev;
288 + spin_lock_init(&sharpsl_rc->lock);
290 + /* Init Remote Control Timer */
291 + init_timer(&sharpsl_rc->rctimer);
292 + sharpsl_rc->rctimer.function = sharpsl_rc_timer_callback;
293 + sharpsl_rc->rctimer.data = (unsigned long) sharpsl_rc;
295 + input_dev->name = "Sharp Remote Control CE-RHX";
296 + input_dev->phys = "sharpsl_rc/input0";
297 + input_dev->id.bustype = BUS_HOST;
298 + input_dev->id.vendor = 0x0001;
299 + input_dev->id.product = 0x0001;
300 + input_dev->id.version = 0x0100;
301 + input_dev->dev.parent = &pdev->dev;
303 + input_dev->evbit[0] = BIT(EV_KEY);
305 + if (machine_is_borzoi() || machine_is_spitz() || machine_is_akita())
306 + remote_keys = remote_keys_spitz;
308 + remote_keys = remote_keys_corgi;
309 + for (i = 0; i < (machine_is_borzoi() || machine_is_spitz() || machine_is_akita() ?
310 + ARRAY_SIZE(remote_keys_spitz) : ARRAY_SIZE(remote_keys_corgi));
312 + set_bit(remote_keys[i].key, input_dev->keybit);
314 + ret = input_register_device(sharpsl_rc->input);
316 + dev_dbg(&pdev->dev, "Failed to register Sharp Remote input device\n");
318 + input_free_device(input_dev);
322 + if (machine_is_borzoi() || machine_is_spitz() || machine_is_akita()) {
323 + pxa_gpio_mode(SPITZ_GPIO_AK_INT | GPIO_IN);
324 + ret = request_irq(SPITZ_IRQ_GPIO_AK_INT,
325 + sharpsl_rc_interrupt,
326 + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
330 + pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN);
331 + ret = request_irq(CORGI_IRQ_GPIO_AK_INT,
332 + sharpsl_rc_interrupt,
333 + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
338 + dev_dbg(&pdev->dev, "Can't get IRQ: %d!\n", i);
340 + input_free_device(input_dev);
347 +static int sharpsl_rc_remove(struct platform_device *pdev)
349 + struct sharpsl_rc *sharpsl_rc = platform_get_drvdata(pdev);
351 + dev_dbg(&pdev->dev, "sharpsl_rc_remove\n");
353 + if (machine_is_borzoi() || machine_is_spitz() || machine_is_akita())
354 + free_irq(SPITZ_IRQ_GPIO_AK_INT, sharpsl_rc);
356 + free_irq(CORGI_IRQ_GPIO_AK_INT, sharpsl_rc);
357 + del_timer_sync(&sharpsl_rc->rctimer);
358 + input_unregister_device(sharpsl_rc->input);
364 +static struct platform_driver sharpsl_rc_driver = {
365 + .probe = sharpsl_rc_probe,
366 + .remove = sharpsl_rc_remove,
370 + .name = "sharpsl-remote-control",
374 +static int __devinit sharpsl_rc_init(void)
376 + printk("sharpsl_rc_init\n");
377 + return platform_driver_register(&sharpsl_rc_driver);
380 +static void __exit sharpsl_rc_exit(void)
382 + printk("sharpsl_rc_exit\n");
383 + platform_driver_unregister(&sharpsl_rc_driver);
386 +module_init(sharpsl_rc_init);
387 +module_exit(sharpsl_rc_exit);
389 +MODULE_AUTHOR("Justin Patrin <papercrane@reversefold.com>");
390 +MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
391 +MODULE_DESCRIPTION("SharpSL Remote Control Driver");
392 +MODULE_LICENSE("GPL");
393 Index: linux-2.6.26/drivers/input/keyboard/spitzkbd.c
394 ===================================================================
395 --- linux-2.6.26.orig/drivers/input/keyboard/spitzkbd.c 2008-07-13 21:51:29.000000000 +0000
396 +++ linux-2.6.26/drivers/input/keyboard/spitzkbd.c 2008-07-15 10:11:15.000000000 +0000
398 #include <linux/jiffies.h>
399 #include <linux/module.h>
400 #include <linux/slab.h>
401 +#include <linux/kmod.h>
403 #include <asm/arch/spitz.h>
404 #include <asm/arch/hardware.h>
405 @@ -280,13 +281,21 @@
406 static int sharpsl_hinge_state;
407 static int hinge_count;
409 +void spitzkbd_handle_sharpsl_rc(void *arg) {
410 + request_module("sharpsl_rc");
413 +DECLARE_WORK(spitzkbd_work, spitzkbd_handle_sharpsl_rc);
415 static void spitzkbd_hinge_timer(unsigned long data)
417 struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
420 + unsigned int headphone, remote;
422 state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB));
423 + state |= (GPLR(SPITZ_GPIO_HP_IN) & GPIO_bit(SPITZ_GPIO_HP_IN));
424 state |= (GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT));
425 if (state != sharpsl_hinge_state) {
429 input_report_switch(spitzkbd_data->input, SW_LID, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
430 input_report_switch(spitzkbd_data->input, SW_TABLET_MODE, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
431 - input_report_switch(spitzkbd_data->input, SW_HEADPHONE_INSERT, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0));
433 + headphone = ((GPLR(SPITZ_GPIO_HP_IN) & GPIO_bit(SPITZ_GPIO_HP_IN)) != 0);
434 + input_report_switch(spitzkbd_data->input, SW_HEADPHONE_INSERT, headphone);
436 + remote = headphone && ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) == 0);
437 + input_report_switch(spitzkbd_data->input, SW_REMOTE_INSERT, remote);
438 input_sync(spitzkbd_data->input);
441 + schedule_work(&spitzkbd_work);
444 spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
446 mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
448 set_bit(SW_LID, input_dev->swbit);
449 set_bit(SW_TABLET_MODE, input_dev->swbit);
450 set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
451 + set_bit(SW_REMOTE_INSERT, input_dev->swbit);
453 err = input_register_device(input_dev);
456 request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
457 IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
458 "Spitzkbd SWB", spitzkbd);
459 - request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
460 + request_irq(SPITZ_IRQ_GPIO_HP_IN, spitzkbd_hinge_isr,
461 IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
462 "Spitzkbd HP", spitzkbd);
463 + request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
464 + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
465 + "Spitzkbd HP Type", spitzkbd);
470 free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd);
471 free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd);
472 free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd);
473 + free_irq(SPITZ_IRQ_GPIO_HP_IN, spitzkbd);
474 free_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd);
476 del_timer_sync(&spitzkbd->htimer);
477 Index: linux-2.6.26/arch/arm/mach-pxa/sharpsl.h
478 ===================================================================
479 --- linux-2.6.26.orig/arch/arm/mach-pxa/sharpsl.h 2008-07-13 21:51:29.000000000 +0000
480 +++ linux-2.6.26/arch/arm/mach-pxa/sharpsl.h 2008-07-15 10:11:15.000000000 +0000
483 #define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x))
485 -/* MAX1111 Channel Definitions */
486 -#define MAX1111_BATT_VOLT 4u
487 -#define MAX1111_BATT_TEMP 2u
488 -#define MAX1111_ACIN_VOLT 6u
490 extern struct battery_thresh spitz_battery_levels_acin[];
491 extern struct battery_thresh spitz_battery_levels_noac[];
492 void sharpsl_pm_pxa_init(void);
493 void sharpsl_pm_pxa_remove(void);
494 -int sharpsl_pm_pxa_read_max1111(int channel);
498 Index: linux-2.6.26/arch/arm/mach-pxa/sharpsl_pm.c
499 ===================================================================
500 --- linux-2.6.26.orig/arch/arm/mach-pxa/sharpsl_pm.c 2008-07-13 21:51:29.000000000 +0000
501 +++ linux-2.6.26/arch/arm/mach-pxa/sharpsl_pm.c 2008-07-15 10:11:15.000000000 +0000
503 | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
506 +EXPORT_SYMBOL(sharpsl_pm_pxa_read_max1111);
508 void sharpsl_pm_pxa_init(void)
510 pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN);
511 Index: linux-2.6.26/include/asm-arm/hardware/sharpsl_pm.h
512 ===================================================================
513 --- linux-2.6.26.orig/include/asm-arm/hardware/sharpsl_pm.h 2008-07-13 21:51:29.000000000 +0000
514 +++ linux-2.6.26/include/asm-arm/hardware/sharpsl_pm.h 2008-07-15 10:11:15.000000000 +0000
516 irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id);
517 irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id);
519 +/* MAX1111 Channel Definitions */
520 +#define MAX1111_REMCOM 0u
521 +#define MAX1111_BATT_VOLT 4u
522 +#define MAX1111_BATT_TEMP 2u
523 +#define MAX1111_ACIN_VOLT 6u
525 +int sharpsl_pm_pxa_read_max1111(int channel);
526 Index: linux-2.6.26/include/linux/input.h
527 ===================================================================
528 --- linux-2.6.26.orig/include/linux/input.h 2008-07-13 21:51:29.000000000 +0000
529 +++ linux-2.6.26/include/linux/input.h 2008-07-15 10:13:04.000000000 +0000
531 #define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any"
532 set = radio enabled */
533 #define SW_RADIO SW_RFKILL_ALL /* deprecated */
534 +#define SW_REMOTE_INSERT 0x04 /* set = remote */
536 #define SW_CNT (SW_MAX+1)
538 Index: linux-2.6.26/arch/arm/mach-pxa/spitz_pm.c
539 ===================================================================
540 --- linux-2.6.26.orig/arch/arm/mach-pxa/spitz_pm.c 2008-07-13 21:51:29.000000000 +0000
541 +++ linux-2.6.26/arch/arm/mach-pxa/spitz_pm.c 2008-07-15 10:11:15.000000000 +0000
543 if (resume_on_alarm && (PEDR & PWER_RTC))
544 is_resume |= PWER_RTC;
546 + printk("wakeup: PEDR: %x, PKSR: %x, HP_IN: %x, AK_INT: %x\n", PEDR, PKSR, GPIO_bit(SPITZ_GPIO_HP_IN), GPIO_bit(SPITZ_GPIO_AK_INT));
548 + //remote/headphone interrupt, wakeup
549 + if (PEDR == 0 && (PKSR & 0xc0d01) != 0) {
550 + is_resume |= PWER_RTC;
553 dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);