1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-16 17:00:38 +02:00

fixes and improvements

This commit is contained in:
Bas Wijnen 2009-07-25 22:00:32 +02:00
parent df38266bb8
commit 283b97955d
4 changed files with 194 additions and 110 deletions

View File

@ -21,7 +21,7 @@
#include "arch.hh" #include "arch.hh"
// Interval between polls for keyboard (when keys are pressed) and battery/power (always) events // Interval between polls for keyboard (when keys are pressed) and battery/power (always) events
#define ALARM_INTERVAL (HZ / 10) #define ALARM_INTERVAL (HZ / 1)
// GPIO pins for the devices (port.pin) // GPIO pins for the devices (port.pin)
@ -89,75 +89,89 @@ enum battery_type:
BATTERY_CHARGED BATTERY_CHARGED
class Keyboard: class Keyboard:
enum { NUM_COLS = 17 } unsigned keys[GPIO_KBD_NUM_COLS]
enum { COL_MASK = 0x2000ffff } void parse (unsigned col, unsigned data):
enum { ROW_MASK = 0x000000ff } for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned keys[NUM_COLS] unsigned code = (col << 3) | row
bool scanning if data & (1 << row):
code |= 0x10000
event (KEYBOARD_EVENT, code)
keys[col] = data
public: public:
bool is_scanning (): void scan ():
return scanning kdebug ("keyboard scan\n")
// Disable interrupts during scan.
GPIO_GPIER (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// All columns are input.
GPIO_GPDIR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
int const cols[GPIO_KBD_NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
unsigned dir = GPIO_GPDIR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
unsigned dat = GPIO_GPDR (GPIO_KBD_COL_PORT) & ~GPIO_KBD_COL_MASK
unsigned data
for unsigned col = 0; col < GPIO_KBD_NUM_COLS; ++col:
// clear pin
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// output
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | (1 << cols[col])
// Generate events of previous column. Do that now, so there is a short delay for the data to stabilize.
if col != 0:
parse (col - 1, data)
else:
// Add a short delay for stabilization.
parse (0, keys[0])
data = GPIO_GPDR (GPIO_KBD_ROW_PORT) & GPIO_KBD_ROW_MASK
// set pin
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat | (1 << cols[col])
// input
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir
parse (GPIO_KBD_NUM_COLS - 1, data)
// set all to 0.
GPIO_GPDR (GPIO_KBD_COL_PORT) = dat
// set all to output.
GPIO_GPDIR (GPIO_KBD_COL_PORT) = dir | GPIO_KBD_COL_MASK
// clear pending interrupts.
for unsigned i = 0; i < 8; ++i:
GPIO_GPFR (GPIO_KBD_ROW_PORT) |= 1 << i
// Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard (): Keyboard ():
// Set all columns to input and disable the pull-ups. // Set all columns to output without pull-ups when set as input.
GPIO_GPDIR (3) &= ~COL_MASK GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
GPIO_GPPUR (3) &= ~COL_MASK GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
// Set all rows to input and enable the pull-ups. // Set all rows to input and enable the pull-ups.
GPIO_GPDIR (0) &= ~ROW_MASK GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPPUR (0) |= ROW_MASK GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Enable interrupts on falling edge. // Detect interrupts on falling edge.
GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & 0xffff) | (GPIO_IRQ_FALLEDG * 0xaaaa) for unsigned i = 0; i < GPIO_KBD_NUM_ROWS; ++i:
GPIO_GPIER (0) |= 0xff gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
scanning = false // Initialize matrix.
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i:
for unsigned i = 0; i < NUM_COLS; ++i:
keys[i] = 0xff keys[i] = 0xff
// Perform initial scan to get real values into matrix and set up the rest.
scan () scan ()
void scan ():
// Set all columns to 0 when they become output.
GPIO_GPDR (3) &= ~COL_MASK
scanning = false
int const cols[NUM_COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 29 }
for unsigned col = 0; col < NUM_COLS; ++col:
GPIO_GPDIR (3) = (GPIO_GPDIR (3) & ~COL_MASK) | (1 << cols[col])
//udelay (100)
unsigned data = GPIO_GPDR (0) & ROW_MASK
// Generate events.
for unsigned row = 0; row < 8; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned code = (row << 8) | col
if data & (1 << row):
code |= 0x10000
event (KEYBOARD_EVENT, code)
keys[col] = data
if data != ROW_MASK:
scanning = true
scanning = true
if scanning:
GPIO_GPDIR (3) &= ~COL_MASK
else:
GPIO_GPDIR (3) |= COL_MASK
class Touchpad: class Touchpad:
unsigned old_state unsigned old_state
public: public:
void check_events (): void check_events ():
unsigned state = GPIO_GPDR (0) unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT): if state & (1 << GPIO_TP_LEFT):
if state & (1 << GPIO_TP_LEFT): gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT) if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0) event (TOUCHPAD_EVENT, 0)
else: else:
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT) gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0x10000) event (TOUCHPAD_EVENT, 0x10000)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT): if state & (1 << GPIO_TP_RIGHT):
if state & (1 << GPIO_TP_RIGHT): gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT) if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 1) event (TOUCHPAD_EVENT, 1)
else: else:
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT) gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 0x10001) event (TOUCHPAD_EVENT, 0x10001)
old_state = state old_state = state
Touchpad (): Touchpad ():
@ -165,20 +179,13 @@ class Touchpad:
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT) gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT) gpio_as_input (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) GPIO_GPPUR (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
// Set up interrupts.
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
old_state = 0 old_state = 0
// See if they are already pressed. If so, the interrupt detection is changed. // See if they are already pressed. Also set up interrupts.
check_events () check_events ()
// Now enable the interrupts. // Now enable the interrupts.
GPIO_GPIER (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
class Lockleds: class Lockleds:
// Note that num lock is in port 2. The others are in port 0. // Note that num lock is in port 2. The others are in port 0.
enum { NUM = 1 << 22 }
enum { CAPS = 1 << 27 }
enum { SCROLL = 1 << 9 }
public: public:
Lockleds (): Lockleds ():
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM) gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
@ -203,13 +210,11 @@ class Lockleds:
class Power: class Power:
// Power out is in port 2, the rest in port 3. // Power out is in port 2, the rest in port 3.
enum { PWR_OUT = 1 << 2 }
enum { PWR_IN = 1 << 1 }
enum { BATTERY = 1 << 29 }
unsigned old_state unsigned old_state
bool was_present bool was_present
public: public:
void poll (): void poll ():
#if 0
// Switch off keyboard interrupts, because this may interfere with them. // Switch off keyboard interrupts, because this may interfere with them.
GPIO_GPIER (0) &= ~0xff GPIO_GPIER (0) &= ~0xff
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY) GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
@ -237,16 +242,16 @@ class Power:
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY) GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
//udelay (100) //udelay (100)
GPIO_GPIER (3) |= 0xff GPIO_GPIER (3) |= 0xff
#endif
Power (): Power ():
GPIO_GPDR (2) |= PWR_OUT
GPIO_GPDIR (2) |= PWR_OUT
was_present = true was_present = true
old_state = BATTERY //old_state = BATTERY
poll () poll ()
void poweroff (): void poweroff ():
gpio_as_gpio (GPIO_PW_O_PORT, GPIO_PW_O) // TODO: doesn't work.
gpio_as_output (GPIO_PW_O_PORT, GPIO_PW_O) i2c_open ()
GPIO_GPDR (GPIO_PW_O) &= ~(1 << GPIO_PW_O) i2c_write_page (I2C_DEV_MCU, I2C_MCU_SHUTDOWN, "\1", 1)
i2c_close ()
while true: while true:
// Do nothing; wait until the device stops running. // Do nothing; wait until the device stops running.
void reboot (): void reboot ():
@ -257,29 +262,27 @@ class Power:
// Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc. // Not really a gpio device, but it's so small, and uses gpio, so I include it here to avoid ipc.
class Pwm: class Pwm:
// Pin definitions, all in port 2.
enum { PWM_ENABLE = 1 << 30 }
public: public:
Pwm (): Pwm ():
GPIO_GPDIR (2) |= PWM_ENABLE GPIO_GPDIR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
PWM_PER (0) = 300 PWM_PER (0) = 300
void set_backlight (bool state): void set_backlight (unsigned level):
if state: if level > 300:
PWM_DUT (0) = 300 level = 300
PWM_CTR (0) = 0xbf PWM_DUT (0) = level
GPIO_GPDR (2) |= PWM_ENABLE if level:
PWM_CTR (0) = 0x80
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
else: else:
PWM_DUT (0) = 0 PWM_CTR (0) = 0x00
PWM_CTR (0) = 0x3f GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
GPIO_GPDR (2) &= ~PWM_ENABLE
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything. // TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
int main (): int main ():
schedule ()
map_gpio () map_gpio ()
map_pwm0 () map_pwm0 ()
map_wdt () map_wdt ()
map_i2c ()
Keyboard kbd Keyboard kbd
Touchpad tp Touchpad tp
@ -287,6 +290,8 @@ int main ():
Power power Power power
Pwm pwm Pwm pwm
// Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
register_interrupt (IRQ_GPIO0) register_interrupt (IRQ_GPIO0)
Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD) Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD)
@ -302,25 +307,27 @@ int main ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL) receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
while true: while true:
schedule ()
Message msg Message msg
wait (&msg) wait (&msg)
switch msg.protected_data: switch msg.protected_data:
case ~0: case ~0:
// Alarm. // Alarm.
if kbd.is_scanning (): kdebug ("alarm\n")
kbd.scan () // Periodically scan several devices.
//power.poll () kbd.scan ()
power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL) receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break break
case IRQ_GPIO0: case IRQ_GPIO0:
kdebug ("gpio interrupt") kdebug ("gpio interrupt\n")
unsigned irq = GPIO_GPFR (0) //unsigned irq = GPIO_GPFR (0)
// Ack all. This works because they are all edge triggered. // Ack all.
GPIO_GPFR (0) = irq GPIO_GPFR (0) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
if irq & 0xff: // Always scan keyboard and touchpad on any interrupt.
kbd.scan () kbd.scan ()
if irq & ((1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)): tp.check_events ()
tp.check_events () // Reregister the interrupt.
register_interrupt (IRQ_GPIO0) register_interrupt (IRQ_GPIO0)
break break
case CAP_KEYBOARD: case CAP_KEYBOARD:

View File

@ -39,7 +39,7 @@ static void setup ():
wait (&msg) wait (&msg)
switch msg.data[0]: switch msg.data[0]:
case INIT_SET_GPIO_0: case INIT_SET_GPIO_0:
kdebug ("gpio 0") kdebug ("gpio 0\n")
kbd = msg.cap[0] kbd = msg.cap[0]
tp = msg.cap[1] tp = msg.cap[1]
poweroff = msg.cap[2] poweroff = msg.cap[2]
@ -47,14 +47,14 @@ static void setup ():
++state ++state
break break
case INIT_SET_GPIO_1: case INIT_SET_GPIO_1:
kdebug ("gpio 1") kdebug ("gpio 1\n")
battery = msg.cap[0] battery = msg.cap[0]
lockleds = msg.cap[1] lockleds = msg.cap[1]
pwm = msg.cap[2] pwm = msg.cap[2]
++state ++state
break break
case INIT_SET_LCD: case INIT_SET_LCD:
kdebug ("lcd") kdebug ("lcd\n")
lcd = msg.cap[0] lcd = msg.cap[0]
++state ++state
break break
@ -67,10 +67,11 @@ static void setup ():
invoke_01 (pwm, 1) invoke_01 (pwm, 1)
int main (): int main ():
// Set up lcd first
schedule () schedule ()
kdebug ("start init") kdebug ("start init\n")
setup () setup ()
kdebug ("run init") kdebug ("run init\n")
while true: while true:
Message msg Message msg
wait (&msg) wait (&msg)
@ -81,9 +82,14 @@ int main ():
kdebug_char ('\n') kdebug_char ('\n')
break break
case TP: case TP:
if msg.data[0] == 0: unsigned leds = 0
// Press left button. if msg.data[0] & 1:
invoke_00 (poweroff) leds |= 0x1
else:
leds |= 0x4
if !(msg.data[0] & 0x10000):
leds |= 0x2
invoke_01 (lockleds, leds)
break break
case POWERBUTTON: case POWERBUTTON:
kdebug ("powerbutton event\n") kdebug ("powerbutton event\n")

17
iris.h
View File

@ -30,7 +30,7 @@ extern "C" {
#endif #endif
// Number of clock interrupts per second. // Number of clock interrupts per second.
#define HZ 10 #define HZ 20
#define PAGE_BITS (12) #define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS) #define PAGE_SIZE (1 << PAGE_BITS)
@ -441,6 +441,20 @@ static void invoke_41 (Capability t, Capability c0, Capability c1, Capability c2
invoke (t, &msg); invoke (t, &msg);
} }
static void call_00 (Capability c)
{
Message msg;
msg.cap[0] = c;
msg.data[0] = 0;
msg.data[1] = 0;
msg.data[2] = 0;
msg.data[3] = 0;
msg.cap[1] = 0;
msg.cap[2] = 0;
msg.cap[3] = 0;
call (__my_call, &msg);
}
static Capability call_c01 (Capability c, unsigned d) static Capability call_c01 (Capability c, unsigned d)
{ {
Message msg; Message msg;
@ -760,7 +774,6 @@ static unsigned memory_limit (Capability memory, unsigned limit)
static void drop (Capability cap) static void drop (Capability cap)
{ {
return;
invoke_11 (__my_memory, cap, CAP_MEMORY_DROP); invoke_11 (__my_memory, cap, CAP_MEMORY_DROP);
} }

View File

@ -1399,8 +1399,15 @@ static void __map_io (unsigned physical, unsigned mapping):
#define I2C_SR_DRF (1 << 1) #define I2C_SR_DRF (1 << 1)
#define I2C_SR_ACKF (1 << 0) #define I2C_SR_ACKF (1 << 0)
#define I2C_WRITE 0
#define I2C_READ 1
/* I2C devices */
#define I2C_DEV_MCU 0x48
/* I2C device registers */
#define I2C_MCU_SHUTDOWN 0xd8
#define I2C_MCU_BAT_STATUS 0xdb
#define I2C_MCU_BAT_CHARGE 0xd9
/************************************************************************* /*************************************************************************
* UDC usb device controller (unused in trendtac) * UDC usb device controller (unused in trendtac)
@ -2821,8 +2828,8 @@ static __inline__ unsigned msc_calc_slow_clk_divisor (bool is_sd):
#define GPIO_PW_I_PORT 3 #define GPIO_PW_I_PORT 3
#define GPIO_PW_I 1 #define GPIO_PW_I 1
#define GPIO_PW_O_PORT 2 #define GPIO_MCU_PORT 2
#define GPIO_PW_O 2 #define GPIO_MCU 1
#define GPIO_LED_EN_PORT 2 #define GPIO_LED_EN_PORT 2
#define GPIO_LED_EN 28 #define GPIO_LED_EN 28
#define GPIO_DISP_OFF_N_PORT 2 #define GPIO_DISP_OFF_N_PORT 2
@ -2847,6 +2854,15 @@ static __inline__ unsigned msc_calc_slow_clk_divisor (bool is_sd):
#define GPIO_TP_LEFT 16 #define GPIO_TP_LEFT 16
#define GPIO_TP_RIGHT_PORT 0 #define GPIO_TP_RIGHT_PORT 0
#define GPIO_TP_RIGHT 13 #define GPIO_TP_RIGHT 13
#define GPIO_PWM_ENABLE_PORT 2
#define GPIO_PWM_ENABLE 30
#define GPIO_KBD_NUM_ROWS 8
#define GPIO_KBD_NUM_COLS 17
#define GPIO_KBD_COL_PORT 3
#define GPIO_KBD_COL_MASK 0x2000ffff
#define GPIO_KBD_ROW_PORT 0
#define GPIO_KBD_ROW_MASK 0x000000ff
#define GPIO_KBD_ROW_HALF 0x00005555
#define GPIO_HALF(x) (((x) & 0xf) << 1) #define GPIO_HALF(x) (((x) & 0xf) << 1)
@ -3012,6 +3028,48 @@ static __inline__ void gpio_as_cim ():
#define i2c_read() ( I2C_DR ) #define i2c_read() ( I2C_DR )
#define i2c_write(val) ( I2C_DR = (val) ) #define i2c_write(val) ( I2C_DR = (val) )
#ifndef __KERNEL
static __inline__ void i2c_open ():
i2c_set_clk (JZ_EXTAL, 10000)
i2c_enable ()
// Note that this kills messages from the queue.
static __inline__ void i2c_close ():
Message msg
receiver_set_alarm (__my_receiver, 3 * HZ / 10)
call_00 (0)
i2c_disable ()
static __inline__ bool i2c_send (unsigned data):
unsigned timeout = 10000
i2c_write (data)
i2c_set_drf ()
while i2c_check_drf () != 0:
while !i2c_transmit_ended ():
while !i2c_received_ack ():
if !--timeout:
return false
return true
static __inline__ unsigned i2c_write_page (unsigned dev, unsigned addr, char const *data, unsigned count):
unsigned timeout = 5
i2c_send_start ()
if !i2c_send ((dev << 1) | I2C_WRITE):
i2c_send_stop ()
return 0
if !i2c_send (addr):
i2c_send_stop ()
return 0
if count > 8:
count = 8
unsigned i
for i = 0; i < count; ++i:
if !i2c_send (*data++):
break
i2c_send_stop ()
return i
#endif
/*************************************************************************** /***************************************************************************
* UDC * UDC
***************************************************************************/ ***************************************************************************/