1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 18:52:25 +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"
// 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)
@ -89,75 +89,89 @@ enum battery_type:
BATTERY_CHARGED
class Keyboard:
enum { NUM_COLS = 17 }
enum { COL_MASK = 0x2000ffff }
enum { ROW_MASK = 0x000000ff }
unsigned keys[NUM_COLS]
bool scanning
unsigned keys[GPIO_KBD_NUM_COLS]
void parse (unsigned col, unsigned data):
for unsigned row = 0; row < GPIO_KBD_NUM_ROWS; ++row:
if (data ^ keys[col]) & (1 << row):
unsigned code = (col << 3) | row
if data & (1 << row):
code |= 0x10000
event (KEYBOARD_EVENT, code)
keys[col] = data
public:
bool is_scanning ():
return scanning
void scan ():
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 ():
// Set all columns to input and disable the pull-ups.
GPIO_GPDIR (3) &= ~COL_MASK
GPIO_GPPUR (3) &= ~COL_MASK
// Set all columns to output without pull-ups when set as input.
GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
// Set all rows to input and enable the pull-ups.
GPIO_GPDIR (0) &= ~ROW_MASK
GPIO_GPPUR (0) |= ROW_MASK
// Enable interrupts on falling edge.
GPIO_GPIDLR (0) = (GPIO_GPIDLR (0) & 0xffff) | (GPIO_IRQ_FALLEDG * 0xaaaa)
GPIO_GPIER (0) |= 0xff
scanning = false
for unsigned i = 0; i < NUM_COLS; ++i:
GPIO_GPPUR (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
GPIO_GPDIR (GPIO_KBD_ROW_PORT) &= ~GPIO_KBD_ROW_MASK
// Detect interrupts on falling edge.
for unsigned i = 0; i < GPIO_KBD_NUM_ROWS; ++i:
gpio_irq_fall (GPIO_KBD_ROW_PORT, i)
// Initialize matrix.
for unsigned i = 0; i < GPIO_KBD_NUM_COLS; ++i:
keys[i] = 0xff
// Perform initial scan to get real values into matrix and set up the rest.
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:
unsigned old_state
public:
void check_events ():
unsigned state = GPIO_GPDR (0)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
if state & (1 << GPIO_TP_LEFT):
gpio_irq_fall (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
unsigned state = GPIO_GPDR (GPIO_TP_LEFT_PORT)
if state & (1 << 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)
else:
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
else:
gpio_irq_rise (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
if (state ^ old_state) & (1 << GPIO_TP_LEFT):
event (TOUCHPAD_EVENT, 0x10000)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
if state & (1 << GPIO_TP_RIGHT):
gpio_irq_fall (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if state & (1 << 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)
else:
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
else:
gpio_irq_rise (GPIO_TP_RIGHT_PORT, GPIO_TP_RIGHT)
if (state ^ old_state) & (1 << GPIO_TP_RIGHT):
event (TOUCHPAD_EVENT, 0x10001)
old_state = state
Touchpad ():
@ -165,20 +179,13 @@ class Touchpad:
gpio_as_input (GPIO_TP_LEFT_PORT, GPIO_TP_LEFT)
gpio_as_input (GPIO_TP_RIGHT_PORT, 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
// 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 ()
// Now enable the interrupts.
GPIO_GPIER (0) |= (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)
class Lockleds:
// 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:
Lockleds ():
gpio_as_output (GPIO_NUM_PORT, GPIO_NUM)
@ -203,13 +210,11 @@ class Lockleds:
class Power:
// 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
bool was_present
public:
void poll ():
#if 0
// Switch off keyboard interrupts, because this may interfere with them.
GPIO_GPIER (0) &= ~0xff
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
@ -237,16 +242,16 @@ class Power:
GPIO_GPDIR (3) &= ~(PWR_IN | BATTERY)
//udelay (100)
GPIO_GPIER (3) |= 0xff
#endif
Power ():
GPIO_GPDR (2) |= PWR_OUT
GPIO_GPDIR (2) |= PWR_OUT
was_present = true
old_state = BATTERY
//old_state = BATTERY
poll ()
void poweroff ():
gpio_as_gpio (GPIO_PW_O_PORT, GPIO_PW_O)
gpio_as_output (GPIO_PW_O_PORT, GPIO_PW_O)
GPIO_GPDR (GPIO_PW_O) &= ~(1 << GPIO_PW_O)
// TODO: doesn't work.
i2c_open ()
i2c_write_page (I2C_DEV_MCU, I2C_MCU_SHUTDOWN, "\1", 1)
i2c_close ()
while true:
// Do nothing; wait until the device stops running.
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.
class Pwm:
// Pin definitions, all in port 2.
enum { PWM_ENABLE = 1 << 30 }
public:
Pwm ():
GPIO_GPDIR (2) |= PWM_ENABLE
GPIO_GPDIR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
PWM_PER (0) = 300
void set_backlight (bool state):
if state:
PWM_DUT (0) = 300
PWM_CTR (0) = 0xbf
GPIO_GPDR (2) |= PWM_ENABLE
void set_backlight (unsigned level):
if level > 300:
level = 300
PWM_DUT (0) = level
if level:
PWM_CTR (0) = 0x80
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) |= 1 << GPIO_PWM_ENABLE
else:
PWM_DUT (0) = 0
PWM_CTR (0) = 0x3f
GPIO_GPDR (2) &= ~PWM_ENABLE
PWM_CTR (0) = 0x00
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
int main ():
schedule ()
map_gpio ()
map_pwm0 ()
map_wdt ()
map_i2c ()
Keyboard kbd
Touchpad tp
@ -287,6 +290,8 @@ int main ():
Power power
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)
Capability cap_kbd = receiver_create_capability (__my_receiver, CAP_KEYBOARD)
@ -302,25 +307,27 @@ int main ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
while true:
schedule ()
Message msg
wait (&msg)
switch msg.protected_data:
case ~0:
// Alarm.
if kbd.is_scanning ():
kbd.scan ()
//power.poll ()
kdebug ("alarm\n")
// Periodically scan several devices.
kbd.scan ()
power.poll ()
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
break
case IRQ_GPIO0:
kdebug ("gpio interrupt")
unsigned irq = GPIO_GPFR (0)
// Ack all. This works because they are all edge triggered.
GPIO_GPFR (0) = irq
if irq & 0xff:
kbd.scan ()
if irq & ((1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT)):
tp.check_events ()
kdebug ("gpio interrupt\n")
//unsigned irq = GPIO_GPFR (0)
// Ack all.
GPIO_GPFR (0) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
// Always scan keyboard and touchpad on any interrupt.
kbd.scan ()
tp.check_events ()
// Reregister the interrupt.
register_interrupt (IRQ_GPIO0)
break
case CAP_KEYBOARD:

View File

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

17
iris.h
View File

@ -30,7 +30,7 @@ extern "C" {
#endif
// Number of clock interrupts per second.
#define HZ 10
#define HZ 20
#define PAGE_BITS (12)
#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);
}
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)
{
Message msg;
@ -760,7 +774,6 @@ static unsigned memory_limit (Capability memory, unsigned limit)
static void drop (Capability cap)
{
return;
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_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)
@ -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 1
#define GPIO_PW_O_PORT 2
#define GPIO_PW_O 2
#define GPIO_MCU_PORT 2
#define GPIO_MCU 1
#define GPIO_LED_EN_PORT 2
#define GPIO_LED_EN 28
#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_RIGHT_PORT 0
#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)
@ -3012,6 +3028,48 @@ static __inline__ void gpio_as_cim ():
#define i2c_read() ( I2C_DR )
#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
***************************************************************************/