Index: linux-2.6.17/arch/arm/mach-pxa/spitz.c =================================================================== --- linux-2.6.17.orig/arch/arm/mach-pxa/spitz.c +++ linux-2.6.17/arch/arm/mach-pxa/spitz.c @@ -244,6 +244,13 @@ static struct platform_device spitzkbd_d .id = -1, }; +/* + * Spitz Remote Control Device + */ +static struct platform_device sharpsl_rc_device = { + .name = "sharpsl-remote-control", + .id = -1, +}; /* * Spitz LEDs @@ -476,6 +483,7 @@ static struct platform_device *devices[] &spitzscoop_device, &spitzssp_device, &spitzkbd_device, + &sharpsl_rc_device, &spitzts_device, &spitzbl_device, &spitzled_device, Index: linux-2.6.17/drivers/input/keyboard/Kconfig =================================================================== --- linux-2.6.17.orig/drivers/input/keyboard/Kconfig +++ linux-2.6.17/drivers/input/keyboard/Kconfig @@ -143,6 +143,17 @@ config KEYBOARD_SPITZ To compile this driver as a module, choose M here: the module will be called spitzkbd. +config SHARPSL_RC + tristate "Sharp SL-Cxx00 Remote Control" + depends on PXA_SHARPSL + default y + help + Say Y here to enable the remote on the Sharp Zaurus SL-Cxx00, + SL-C1000, SL-C3000 and Sl-C3100 series of PDAs. + + To compile this driver as a module, choose M here: the + module will be called sharpsl_rc. + config KEYBOARD_AMIGA tristate "Amiga keyboard" depends on AMIGA Index: linux-2.6.17/drivers/input/keyboard/Makefile =================================================================== --- linux-2.6.17.orig/drivers/input/keyboard/Makefile +++ linux-2.6.17/drivers/input/keyboard/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomo obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o +obj-$(CONFIG_SHARPSL_RC) += sharpsl_rc.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o Index: linux-2.6.17/drivers/input/keyboard/sharpsl_rc.c =================================================================== --- /dev/null +++ linux-2.6.17/drivers/input/keyboard/sharpsl_rc.c @@ -0,0 +1,348 @@ +/* + * Keyboard driver for Sharp Clamshell Models (SL-Cxx00) + * + * Copyright (c) 2004-2005 Richard Purdie + * + * Based on corgikbd.c and Sharp's RC driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define REMOTE_CONTROL_REL 1 +#define REMOTE_CONTROL_PHONE 9 + +struct remote_control_key { + unsigned char min; + unsigned char max; + unsigned char key; +}; + +struct remote_control_key spitz_remote_keys[] = { + { 25, 35, KEY_STOPCD}, + { 55, 65, KEY_PLAYPAUSE}, + { 85, 95, KEY_NEXTSONG}, + { 115, 125, KEY_VOLUMEUP}, + { 145, 155, KEY_PREVIOUSSONG}, + { 180, 190, KEY_MUTE}, + { 215, 225, KEY_VOLUMEDOWN}, +}; + +#define RELEASE_HI 230 +#define MAX_EARPHONE 6 + +struct sharpsl_rc { + struct input_dev *input; + + spinlock_t lock; + struct timer_list rctimer; + + unsigned int suspended; + unsigned int suspend_jiffies; +}; + +#define MAX1111_REMCOM 0u //FIXME + +#define SLKEY_RCREL 128 //95 for non-spitz +#define HPJACK_STATE_NONE (0) +#define HPJACK_STATE_REMOCON (2) +#define HPJACK_STATE_HEADPHONE (1) +#define RC_POLL_TIMER (HZ/100) + +static int remocon_dev_stat = HPJACK_STATE_NONE; +static int remocon_scan_state = 8; +static int read_first = REMOTE_CONTROL_REL; +static int last_key = SLKEY_RCREL; +static int button_type = SLKEY_RCREL; +static int remocon_noise_count = 0; + +static int get_remocon_raw(void) +{ + int i, val, key = 0; + + val = sharpsl_pm_pxa_read_max1111(MAX1111_REMCOM); + if (val >= RELEASE_HI) { + /* Key release */ + key = REMOTE_CONTROL_REL; + } else if (val <= MAX_EARPHONE) { + /* remote control unplugged */ + key = REMOTE_CONTROL_PHONE; + } else { + for (i = 0; i < ARRAY_SIZE(spitz_remote_keys); ++i) { + if (val >= spitz_remote_keys[i].min + && val <= spitz_remote_keys[i].max) { + key = spitz_remote_keys[i].key; + } + } + } + return key; +} + +static irqreturn_t sharpsl_rc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sharpsl_rc *sharpsl_rc_data = dev_id; + + dev_dbg(NULL, "sharpsl_rc_interrupt %d scan state: %d\n", irq, remocon_scan_state); + + if(( remocon_scan_state >= 4 ) && ( remocon_scan_state <= 6 )){ + // eject remocon ? + if(( get_remocon_raw() == REMOTE_CONTROL_PHONE ) + &&( remocon_dev_stat == HPJACK_STATE_REMOCON )){ + remocon_dev_stat = HPJACK_STATE_NONE; + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_AKIN_PULLUP); //should this be here? + } + return 0; //used to return nothing + } + disable_irq(irq); // bad idea - remove me - just ignore subsequent interrupts... + + //was reset_set_scoop_gpio + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_AKIN_PULLUP); + + read_first = get_remocon_raw(); + remocon_scan_state = 0; + remocon_noise_count = 0; + last_key = read_first; + + mod_timer(&sharpsl_rc_data->rctimer, jiffies + RC_POLL_TIMER); // should use msecs_to_jiffies(xxx) + + return IRQ_HANDLED; +} + + + + +static void sharpsl_rc_timer_callback(unsigned long data) +{ + struct sharpsl_rc *sharpsl_rc_data = (struct sharpsl_rc *) data; + int type; + int is_irqen = 0, interval = 0; + + if( remocon_scan_state < 6 ){ + type = get_remocon_raw(); + } else { + type = 0; + } + dev_dbg(NULL, "time callback, state: %d, type: %d\n", remocon_scan_state, type); + + switch( remocon_scan_state ){ + case 0: + case 1: + case 2: + interval = RC_POLL_TIMER; + if( last_key == type ){ + remocon_scan_state ++; + } else { + last_key = type; + remocon_scan_state = 0; + remocon_noise_count++; + } + break; + case 3: + dev_dbg(NULL, "state 3 type: %d last_key: %d\n", type, last_key); + if( last_key != type ){ + type = last_key; + remocon_noise_count++; + } + dev_dbg(NULL, "noise count:%d\n", remocon_noise_count ); + interval = RC_POLL_TIMER; + dev_dbg(NULL, "KEY(42): %d\n", 42); + input_report_key(sharpsl_rc_data->input, 42, 1); + + dev_dbg(NULL, "state 3 type: %d\n", type); + + switch(type) { + case REMOTE_CONTROL_REL: + dev_dbg(NULL, "release\n"); + remocon_scan_state = 7; + // it looks like a head-phone (AD value 3 typ.) at ejecting remocon + if(( read_first == REMOTE_CONTROL_PHONE )||( remocon_noise_count > 3 )){ + remocon_dev_stat = HPJACK_STATE_NONE; + } + break; + case REMOTE_CONTROL_PHONE: + remocon_dev_stat = HPJACK_STATE_HEADPHONE; + dev_dbg(NULL, "phone\n"); + remocon_scan_state = 7; + break; + case 0: + // it looks like a head-phone (AD value 3 typ.) at ejecting remocon + if(( read_first == REMOTE_CONTROL_PHONE )||( remocon_noise_count > 3 )){ + remocon_dev_stat = HPJACK_STATE_NONE; + } + dev_dbg(NULL, "out of range\n"); + remocon_scan_state = 7; + break; + default: + remocon_dev_stat = HPJACK_STATE_REMOCON; + dev_dbg(NULL, "button: %d\n", type;); + dev_dbg(NULL, "KEY: %d\n", type); + input_report_key(sharpsl_rc_data->input, type, 1); + button_type = type; + break; + } + + if( remocon_scan_state == 3 ){ + remocon_scan_state ++; + + // to catch eject remocon... + enable_irq(SPITZ_IRQ_GPIO_AK_INT); // bad idea - remove me + } + break; + case 4: + case 5: // release wait + interval = RC_POLL_TIMER; + if( type != last_key ){ + remocon_scan_state ++; + }else{ + remocon_scan_state = 4; + } + break; + case 6: // release + dev_dbg(NULL, "release 1\n"); + dev_dbg(NULL, "KEY: %d\n", button_type); + input_report_key(sharpsl_rc_data->input, button_type, 0); + // go below + case 7: + + remocon_scan_state = 8; + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_AKIN_PULLUP); + is_irqen = 1; + break; + default: + is_irqen = 1; + return; + } + + dev_dbg(NULL, "timer interval: %d, RC_POLL_TIMER: %d\n", interval, RC_POLL_TIMER); + + if( is_irqen ){ + enable_irq(SPITZ_IRQ_GPIO_AK_INT); // bad idea - remove me + } else { + if( interval != 0 ){ + mod_timer(&sharpsl_rc_data->rctimer, jiffies + interval); // should use msecs_to_jiffies(xxx) + } + } +} + + + +static int __init sharpsl_rc_probe(struct platform_device *pdev) +{ + struct sharpsl_rc *sharpsl_rc; + struct input_dev *input_dev; + int i, ret; + + dev_dbg(NULL, "sharpsl_rc_probe\n"); + + sharpsl_rc = kzalloc(sizeof(struct sharpsl_rc), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!sharpsl_rc || !input_dev) { + kfree(sharpsl_rc); + input_free_device(input_dev); + return -ENOMEM; + } + + platform_set_drvdata(pdev, sharpsl_rc); + + sharpsl_rc->input = input_dev; + spin_lock_init(&sharpsl_rc->lock); + + /* Init Remote Control Timer */ + init_timer(&sharpsl_rc->rctimer); + sharpsl_rc->rctimer.function = sharpsl_rc_timer_callback; + sharpsl_rc->rctimer.data = (unsigned long) sharpsl_rc; + + input_dev->name = "Spitz Remote Control"; + input_dev->phys = "sharpsl_rc/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &pdev->dev; + input_dev->private = sharpsl_rc; + + input_dev->evbit[0] = BIT(EV_KEY);// | BIT(EV_REP); + + for (i = 0; i <= ARRAY_SIZE(spitz_remote_keys); i++) + set_bit(spitz_remote_keys[i].key, input_dev->keybit); + + input_register_device(sharpsl_rc->input); + + pxa_gpio_mode(SPITZ_GPIO_AK_INT | GPIO_IN); + ret = request_irq(SPITZ_IRQ_GPIO_AK_INT, + sharpsl_rc_interrupt, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING | SA_SHIRQ, + "sharpsl_rc", + sharpsl_rc); // Should be rise or fall or both? + if (ret < 0) { + dev_dbg(NULL, "sharpsl_rc: Can't get IRQ: %d!\n", i); + return ret; + } + + return 0; +} + +static int sharpsl_rc_remove(struct platform_device *pdev) +{ + struct sharpsl_rc *sharpsl_rc = platform_get_drvdata(pdev); + + dev_dbg(NULL, "sharpsl_rc_remove\n"); + + free_irq(SPITZ_IRQ_GPIO_AK_INT, sharpsl_rc); + + del_timer_sync(&sharpsl_rc->rctimer); + + input_unregister_device(sharpsl_rc->input); + + kfree(sharpsl_rc); + + return 0; +} + +static struct platform_driver sharpsl_rc_driver = { + .probe = sharpsl_rc_probe, + .remove = sharpsl_rc_remove, + .suspend = NULL, + .resume = NULL, + .driver = { + .name = "sharpsl-remote-control", + }, +}; + +static int __devinit sharpsl_rc_init(void) +{ + dev_dbg(NULL, "sharpsl_rc_init\n"); + return platform_driver_register(&sharpsl_rc_driver); +} + +static void __exit sharpsl_rc_exit(void) +{ + dev_dbg(NULL, "sharpsl_rc_exit\n"); + platform_driver_unregister(&sharpsl_rc_driver); +} + +module_init(sharpsl_rc_init); +module_exit(sharpsl_rc_exit); + +MODULE_AUTHOR("Justin Patrin "); +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("SharpSL Remote Control Driver"); +MODULE_LICENSE("GPL"); Index: linux-2.6.17/drivers/input/keyboard/spitzkbd.c =================================================================== --- linux-2.6.17.orig/drivers/input/keyboard/spitzkbd.c +++ linux-2.6.17/drivers/input/keyboard/spitzkbd.c @@ -437,7 +437,7 @@ static int __init spitzkbd_probe(struct SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, "Spitzkbd SWB", spitzkbd); request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr, - SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING | SA_SHIRQ, "Spitzkbd HP", spitzkbd); printk(KERN_INFO "input: Spitz Keyboard Registered\n"); Index: linux-2.6.17/arch/arm/mach-pxa/sharpsl.h =================================================================== --- linux-2.6.17.orig/arch/arm/mach-pxa/sharpsl.h +++ linux-2.6.17/arch/arm/mach-pxa/sharpsl.h @@ -59,6 +59,6 @@ extern struct battery_thresh spitz_batte extern struct battery_thresh spitz_battery_levels_noac[]; void sharpsl_pm_pxa_init(void); void sharpsl_pm_pxa_remove(void); -int sharpsl_pm_pxa_read_max1111(int channel); + Index: linux-2.6.17/arch/arm/mach-pxa/sharpsl_pm.c =================================================================== --- linux-2.6.17.orig/arch/arm/mach-pxa/sharpsl_pm.c +++ linux-2.6.17/arch/arm/mach-pxa/sharpsl_pm.c @@ -27,7 +27,7 @@ #include #include #include -#include "sharpsl.h" +#include struct battery_thresh spitz_battery_levels_acin[] = { { 213, 100}, @@ -115,14 +115,6 @@ struct battery_thresh spitz_battery_lev { 0, 0}, }; -/* MAX1111 Commands */ -#define MAXCTRL_PD0 1u << 0 -#define MAXCTRL_PD1 1u << 1 -#define MAXCTRL_SGL 1u << 2 -#define MAXCTRL_UNI 1u << 3 -#define MAXCTRL_SEL_SH 4 -#define MAXCTRL_STR 1u << 7 - /* * Read MAX1111 ADC */ @@ -135,6 +127,8 @@ int sharpsl_pm_pxa_read_max1111(int chan | MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR); } +EXPORT_SYMBOL(sharpsl_pm_pxa_read_max1111); + void sharpsl_pm_pxa_init(void) { pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN); Index: linux-2.6.17/include/asm-arm/hardware/sharpsl_pm.h =================================================================== --- linux-2.6.17.orig/include/asm-arm/hardware/sharpsl_pm.h +++ linux-2.6.17/include/asm-arm/hardware/sharpsl_pm.h @@ -103,3 +103,12 @@ irqreturn_t sharpsl_ac_isr(int irq, void irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp); irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp); +/* MAX1111 Commands */ +#define MAXCTRL_PD0 1u << 0 +#define MAXCTRL_PD1 1u << 1 +#define MAXCTRL_SGL 1u << 2 +#define MAXCTRL_UNI 1u << 3 +#define MAXCTRL_SEL_SH 4 +#define MAXCTRL_STR 1u << 7 + +int sharpsl_pm_pxa_read_max1111(int channel);