forked from len0rd/rockbox
Button and click wheel driver for iPod 4g and Nano.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8256 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
a601fb8d19
commit
8bf079ffc1
3 changed files with 185 additions and 4 deletions
|
|
@ -63,6 +63,143 @@ static int button_read(void);
|
||||||
static bool remote_button_hold_only(void);
|
static bool remote_button_hold_only(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_KEYPAD == IPOD_4G_PAD || CONFIG_KEYPAD == IPOD_NANO_PAD
|
||||||
|
/* Variable to use for setting button status in interrupt handler */
|
||||||
|
int int_btn = BUTTON_NONE;
|
||||||
|
|
||||||
|
static void opto_i2c_init(void)
|
||||||
|
{
|
||||||
|
int i, curr_value;
|
||||||
|
|
||||||
|
/* wait for value to settle */
|
||||||
|
i = 1000;
|
||||||
|
curr_value = (inl(0x7000c104) << 16) >> 24;
|
||||||
|
while (i > 0)
|
||||||
|
{
|
||||||
|
int new_value = (inl(0x7000c104) << 16) >> 24;
|
||||||
|
|
||||||
|
if (new_value != curr_value) {
|
||||||
|
i = 10000;
|
||||||
|
curr_value = new_value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GPIOB_OUTPUT_VAL |= 0x10;
|
||||||
|
DEV_EN |= 0x10000;
|
||||||
|
DEV_RS |= 0x10000;
|
||||||
|
udelay(5);
|
||||||
|
DEV_RS &= ~0x10000; /* finish reset */
|
||||||
|
|
||||||
|
outl(0xffffffff, 0x7000c120);
|
||||||
|
outl(0xffffffff, 0x7000c124);
|
||||||
|
outl(0xc00a1f00, 0x7000c100);
|
||||||
|
outl(0x1000000, 0x7000c104);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipod_4g_button_read(void)
|
||||||
|
{
|
||||||
|
unsigned reg, status;
|
||||||
|
static int clickwheel_down = 0;
|
||||||
|
static int old_wheel_value = -1;
|
||||||
|
int wheel_keycode = BUTTON_NONE;
|
||||||
|
int wheel_delta, wheel_delta_abs;
|
||||||
|
int new_wheel_value;
|
||||||
|
int btn = BUTTON_NONE;
|
||||||
|
|
||||||
|
udelay(250);
|
||||||
|
reg = 0x7000c104;
|
||||||
|
if ((inl(0x7000c104) & 0x4000000) != 0) {
|
||||||
|
reg = reg + 0x3C; /* 0x7000c140 */
|
||||||
|
|
||||||
|
status = inl(0x7000c140);
|
||||||
|
outl(0x0, 0x7000c140); /* clear interrupt status? */
|
||||||
|
|
||||||
|
if ((status & 0x800000ff) == 0x8000001a) {
|
||||||
|
/* NB: highest wheel = 0x5F, clockwise increases */
|
||||||
|
new_wheel_value = ((status << 9) >> 25) & 0xff;
|
||||||
|
|
||||||
|
if (status & 0x100)
|
||||||
|
btn |= BUTTON_SELECT;
|
||||||
|
if (status & 0x200)
|
||||||
|
btn |= BUTTON_RIGHT;
|
||||||
|
if (status & 0x400)
|
||||||
|
btn |= BUTTON_LEFT;
|
||||||
|
if (status & 0x800)
|
||||||
|
btn |= BUTTON_PLAY;
|
||||||
|
if (status & 0x1000)
|
||||||
|
btn |= BUTTON_MENU;
|
||||||
|
if (status & 0x40000000) {
|
||||||
|
/* scroll wheel down */
|
||||||
|
clickwheel_down = 1;
|
||||||
|
backlight_on();
|
||||||
|
if (old_wheel_value != -1) {
|
||||||
|
wheel_delta = new_wheel_value - old_wheel_value;
|
||||||
|
wheel_delta_abs = wheel_delta < 0 ? -wheel_delta : wheel_delta;
|
||||||
|
|
||||||
|
wheel_delta = new_wheel_value - old_wheel_value;
|
||||||
|
|
||||||
|
/* TODO: these thresholds should most definitely be
|
||||||
|
settings, and we're probably going to want a more
|
||||||
|
advanced scheme than this anyway. */
|
||||||
|
if (wheel_delta > 4) {
|
||||||
|
wheel_keycode = BUTTON_SCROLL_FWD;
|
||||||
|
old_wheel_value = new_wheel_value;
|
||||||
|
} else if (wheel_delta < -4) {
|
||||||
|
wheel_keycode = BUTTON_SCROLL_BACK;
|
||||||
|
old_wheel_value = new_wheel_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wheel_keycode != BUTTON_NONE)
|
||||||
|
queue_post(&button_queue, wheel_keycode, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
old_wheel_value = new_wheel_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (clickwheel_down) {
|
||||||
|
/* scroll wheel up */
|
||||||
|
old_wheel_value = -1;
|
||||||
|
clickwheel_down = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Don't know why this should be needed, let me know if you do.
|
||||||
|
else if ((status & 0x800000FF) == 0x8000003A) {
|
||||||
|
wheel_value = status & 0x800000FF;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
else if (status == 0xffffffff) {
|
||||||
|
opto_i2c_init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((inl(reg) & 0x8000000) != 0) {
|
||||||
|
outl(0xffffffff, 0x7000c120);
|
||||||
|
outl(0xffffffff, 0x7000c124);
|
||||||
|
}
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ipod_4g_button_int(void)
|
||||||
|
{
|
||||||
|
PP5020_CPU_HI_INT_CLR = PP5020_I2C_MASK;
|
||||||
|
udelay(250);
|
||||||
|
outl(0x0, 0x7000c140);
|
||||||
|
int_btn = ipod_4g_button_read();
|
||||||
|
outl(inl(0x7000c104) | 0xC000000, 0x7000c104);
|
||||||
|
outl(0x400a1f00, 0x7000c100);
|
||||||
|
|
||||||
|
GPIOB_OUTPUT_VAL |= 0x10;
|
||||||
|
PP5020_CPU_INT_EN = 0x40000000;
|
||||||
|
PP5020_CPU_HI_INT_EN = PP5020_I2C_MASK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void button_tick(void)
|
static void button_tick(void)
|
||||||
{
|
{
|
||||||
static int tick = 0;
|
static int tick = 0;
|
||||||
|
|
@ -234,6 +371,18 @@ void button_init(void)
|
||||||
/* nothing to initialize here */
|
/* nothing to initialize here */
|
||||||
#elif CONFIG_KEYPAD == GMINI100_PAD
|
#elif CONFIG_KEYPAD == GMINI100_PAD
|
||||||
/* nothing to initialize here */
|
/* nothing to initialize here */
|
||||||
|
#elif CONFIG_KEYPAD == IPOD_4G_PAD || CONFIG_KEYPAD == IPOD_NANO_PAD
|
||||||
|
opto_i2c_init();
|
||||||
|
/* hold button - enable as input */
|
||||||
|
GPIOA_ENABLE |= 0x20;
|
||||||
|
GPIOA_OUTPUT_EN &= ~0x20;
|
||||||
|
/* hold button - set interrupt levels */
|
||||||
|
GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x20);
|
||||||
|
GPIOA_INT_CLR = GPIOA_INT_STAT & 0x20;
|
||||||
|
/* enable interrupts */
|
||||||
|
GPIOA_INT_EN = 0x20;
|
||||||
|
PP5020_CPU_INT_EN = 0x40000000;
|
||||||
|
PP5020_CPU_HI_INT_EN = PP5020_I2C_MASK;
|
||||||
#endif /* CONFIG_KEYPAD */
|
#endif /* CONFIG_KEYPAD */
|
||||||
|
|
||||||
queue_init(&button_queue);
|
queue_init(&button_queue);
|
||||||
|
|
@ -673,8 +822,9 @@ static int button_read(void)
|
||||||
btn |= BUTTON_ON;
|
btn |= BUTTON_ON;
|
||||||
|
|
||||||
#elif CONFIG_KEYPAD == IPOD_4G_PAD || CONFIG_KEYPAD == IPOD_NANO_PAD
|
#elif CONFIG_KEYPAD == IPOD_4G_PAD || CONFIG_KEYPAD == IPOD_NANO_PAD
|
||||||
/* TODO: Implement for iPod */
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
/* The int_btn variable is set in the button interrupt handler */
|
||||||
|
btn = int_btn;
|
||||||
#endif /* CONFIG_KEYPAD */
|
#endif /* CONFIG_KEYPAD */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,36 @@
|
||||||
#define GPIOC_ENABLE (*(volatile unsigned long *)(0x6000d008))
|
#define GPIOC_ENABLE (*(volatile unsigned long *)(0x6000d008))
|
||||||
#define GPIOD_ENABLE (*(volatile unsigned long *)(0x6000d00c))
|
#define GPIOD_ENABLE (*(volatile unsigned long *)(0x6000d00c))
|
||||||
#define GPIOA_OUTPUT_EN (*(volatile unsigned long *)(0x6000d010))
|
#define GPIOA_OUTPUT_EN (*(volatile unsigned long *)(0x6000d010))
|
||||||
|
#define GPIOB_OUTPUT_EN (*(volatile unsigned long *)(0x6000d014))
|
||||||
|
#define GPIOC_OUTPUT_EN (*(volatile unsigned long *)(0x6000d018))
|
||||||
|
#define GPIOD_OUTPUT_EN (*(volatile unsigned long *)(0x6000d01c))
|
||||||
#define GPIOA_OUTPUT_VAL (*(volatile unsigned long *)(0x6000d020))
|
#define GPIOA_OUTPUT_VAL (*(volatile unsigned long *)(0x6000d020))
|
||||||
|
#define GPIOB_OUTPUT_VAL (*(volatile unsigned long *)(0x6000d024))
|
||||||
|
#define GPIOC_OUTPUT_VAL (*(volatile unsigned long *)(0x6000d028))
|
||||||
|
#define GPIOD_OUTPUT_VAL (*(volatile unsigned long *)(0x6000d02c))
|
||||||
#define GPIOA_INPUT_VAL (*(volatile unsigned long *)(0x6000d030))
|
#define GPIOA_INPUT_VAL (*(volatile unsigned long *)(0x6000d030))
|
||||||
|
#define GPIOB_INPUT_VAL (*(volatile unsigned long *)(0x6000d034))
|
||||||
|
#define GPIOC_INPUT_VAL (*(volatile unsigned long *)(0x6000d038))
|
||||||
|
#define GPIOD_INPUT_VAL (*(volatile unsigned long *)(0x6000d03c))
|
||||||
#define GPIOA_INT_STAT (*(volatile unsigned long *)(0x6000d040))
|
#define GPIOA_INT_STAT (*(volatile unsigned long *)(0x6000d040))
|
||||||
|
#define GPIOB_INT_STAT (*(volatile unsigned long *)(0x6000d044))
|
||||||
|
#define GPIOC_INT_STAT (*(volatile unsigned long *)(0x6000d048))
|
||||||
|
#define GPIOD_INT_STAT (*(volatile unsigned long *)(0x6000d04c))
|
||||||
#define GPIOA_INT_EN (*(volatile unsigned long *)(0x6000d050))
|
#define GPIOA_INT_EN (*(volatile unsigned long *)(0x6000d050))
|
||||||
|
#define GPIOB_INT_EN (*(volatile unsigned long *)(0x6000d054))
|
||||||
|
#define GPIOC_INT_EN (*(volatile unsigned long *)(0x6000d058))
|
||||||
|
#define GPIOD_INT_EN (*(volatile unsigned long *)(0x6000d05c))
|
||||||
#define GPIOA_INT_LEV (*(volatile unsigned long *)(0x6000d060))
|
#define GPIOA_INT_LEV (*(volatile unsigned long *)(0x6000d060))
|
||||||
|
#define GPIOB_INT_LEV (*(volatile unsigned long *)(0x6000d064))
|
||||||
|
#define GPIOC_INT_LEV (*(volatile unsigned long *)(0x6000d068))
|
||||||
|
#define GPIOD_INT_LEV (*(volatile unsigned long *)(0x6000d06c))
|
||||||
#define GPIOA_INT_CLR (*(volatile unsigned long *)(0x6000d070))
|
#define GPIOA_INT_CLR (*(volatile unsigned long *)(0x6000d070))
|
||||||
|
#define GPIOB_INT_CLR (*(volatile unsigned long *)(0x6000d074))
|
||||||
|
#define GPIOC_INT_CLR (*(volatile unsigned long *)(0x6000d078))
|
||||||
|
#define GPIOD_INT_CLR (*(volatile unsigned long *)(0x6000d07c))
|
||||||
|
|
||||||
|
#define DEV_RS (*(volatile unsigned long *)(0x60006004))
|
||||||
|
#define DEV_EN (*(volatile unsigned long *)(0x6000600c))
|
||||||
|
|
||||||
#define PP5020_TIMER1 (*(volatile unsigned long *)(0x60005000))
|
#define PP5020_TIMER1 (*(volatile unsigned long *)(0x60005000))
|
||||||
#define PP5020_TIMER1_ACK (*(volatile unsigned long *)(0x60005004))
|
#define PP5020_TIMER1_ACK (*(volatile unsigned long *)(0x60005004))
|
||||||
|
|
@ -39,9 +63,13 @@
|
||||||
#define PP5020_TIMER2_ACK (*(volatile unsigned long *)(0x6000500c))
|
#define PP5020_TIMER2_ACK (*(volatile unsigned long *)(0x6000500c))
|
||||||
#define PP5020_TIMER_STATUS (*(volatile unsigned long *)(0x60005010))
|
#define PP5020_TIMER_STATUS (*(volatile unsigned long *)(0x60005010))
|
||||||
|
|
||||||
#define PP5020_CPU_INT_STAT (*(volatile unsigned long*)(0x64004000))
|
#define PP5020_CPU_INT_STAT (*(volatile unsigned long*)(0x64004000))
|
||||||
#define PP5020_CPU_INT_EN (*(volatile unsigned long*)(0x60004024))
|
#define PP5020_CPU_HI_INT_STAT (*(volatile unsigned long*)(0x64004100))
|
||||||
|
#define PP5020_CPU_INT_EN (*(volatile unsigned long*)(0x60004024))
|
||||||
|
#define PP5020_CPU_HI_INT_EN (*(volatile unsigned long*)(0x60004124))
|
||||||
|
#define PP5020_CPU_INT_CLR (*(volatile unsigned long*)(0x60004028))
|
||||||
|
#define PP5020_CPU_HI_INT_CLR (*(volatile unsigned long*)(0x60004128))
|
||||||
|
|
||||||
#define PP5020_TIMER1_IRQ 0
|
#define PP5020_TIMER1_IRQ 0
|
||||||
#define PP5020_TIMER2_IRQ 1
|
#define PP5020_TIMER2_IRQ 1
|
||||||
#define PP5020_I2S_IRQ 10
|
#define PP5020_I2S_IRQ 10
|
||||||
|
|
|
||||||
|
|
@ -1107,11 +1107,14 @@ int system_memory_guard(int newmode)
|
||||||
#elif CONFIG_CPU==PP5020
|
#elif CONFIG_CPU==PP5020
|
||||||
|
|
||||||
extern void TIMER1(void);
|
extern void TIMER1(void);
|
||||||
|
extern void ipod_4g_button_int(void);
|
||||||
|
|
||||||
void irq(void)
|
void irq(void)
|
||||||
{
|
{
|
||||||
if (PP5020_CPU_INT_STAT & PP5020_TIMER1_MASK)
|
if (PP5020_CPU_INT_STAT & PP5020_TIMER1_MASK)
|
||||||
TIMER1();
|
TIMER1();
|
||||||
|
else if (PP5020_CPU_HI_INT_STAT & PP5020_I2C_MASK)
|
||||||
|
ipod_4g_button_int();
|
||||||
}
|
}
|
||||||
|
|
||||||
void system_init(void)
|
void system_init(void)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue