forked from len0rd/rockbox
Gigabeat S:
1) Rework event handling and static registration mechanism. No target- specific code in mc13783 driver. GPIO event driver interfaces more cleanly. 2) Somewhat related - enable thread priority for bootloader which is desireable here (ffs is used for GPIO event enabling anyway and that goes along with priority). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17593 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
5f796087b0
commit
a9c20f5789
19 changed files with 443 additions and 235 deletions
|
@ -679,12 +679,13 @@ target/arm/imx31/gigabeat-s/backlight-imx31.c
|
|||
target/arm/imx31/gigabeat-s/button-imx31.c
|
||||
target/arm/imx31/gigabeat-s/clkctl-imx31.c
|
||||
target/arm/imx31/gigabeat-s/dma_start.c
|
||||
target/arm/imx31/gigabeat-s/gpio-imx31.c
|
||||
target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/gpio-imx31.c
|
||||
target/arm/imx31/gigabeat-s/kernel-imx31.c
|
||||
target/arm/imx31/gigabeat-s/i2c-imx31.c
|
||||
target/arm/imx31/gigabeat-s/i2s-imx31.c
|
||||
target/arm/imx31/gigabeat-s/lcd-imx31.c
|
||||
target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/mc13783-imx31.c
|
||||
target/arm/imx31/gigabeat-s/mmu-imx31.c
|
||||
target/arm/imx31/gigabeat-s/power-imx31.c
|
||||
|
|
|
@ -67,11 +67,6 @@ enum rtc_registers_indexes
|
|||
/* was it an alarm that triggered power on ? */
|
||||
static bool alarm_start = false;
|
||||
|
||||
void mc13783_alarm_start(void)
|
||||
{
|
||||
alarm_start = true;
|
||||
}
|
||||
|
||||
static const unsigned char rtc_registers[RTC_NUM_REGS] =
|
||||
{
|
||||
[RTC_REG_TIME] = MC13783_RTC_TIME,
|
||||
|
@ -122,7 +117,12 @@ static int is_leap_year(int y)
|
|||
/** Public APIs **/
|
||||
void rtc_init(void)
|
||||
{
|
||||
/* Nothing to do */
|
||||
/* only needs to be polled on startup */
|
||||
if (mc13783_read(MC13783_INTERRUPT_STATUS1) & MC13783_TODAI)
|
||||
{
|
||||
alarm_start = true;
|
||||
mc13783_write(MC13783_INTERRUPT_STATUS1, MC13783_TODAI);
|
||||
}
|
||||
}
|
||||
|
||||
int rtc_read_datetime(unsigned char* buf)
|
||||
|
@ -264,7 +264,9 @@ bool rtc_enable_alarm(bool enable)
|
|||
bool rtc_check_alarm_started(bool release_alarm)
|
||||
{
|
||||
bool rc = alarm_start;
|
||||
alarm_start &= ~release_alarm;
|
||||
|
||||
if (release_alarm)
|
||||
alarm_start = false;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
/* Define the bitmask of modules used */
|
||||
#define SPI_MODULE_MASK (USE_CSPI2_MODULE)
|
||||
#define I2C_MODULE_MASK (USE_I2C1_MODULE)
|
||||
#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 1
|
||||
|
|
|
@ -341,7 +341,14 @@
|
|||
#endif
|
||||
|
||||
#if (CONFIG_CODEC == SWCODEC)
|
||||
#ifndef BOOTLOADER
|
||||
#ifdef BOOTLOADER
|
||||
|
||||
#if CONFIG_CPU == IMX31L
|
||||
/* Priority in bootloader is wanted */
|
||||
#define HAVE_PRIORITY_SCHEDULING
|
||||
#endif
|
||||
|
||||
#else /* !BOOTLOADER */
|
||||
|
||||
#define HAVE_EXTENDED_MESSAGING_AND_NAME
|
||||
|
||||
|
|
|
@ -1270,6 +1270,9 @@ enum mc13783_regs_enum
|
|||
#define MC13783_TC3PERIODr(x) (((x) & MC13783_TC3PERIOD) >> 21)
|
||||
#define MC13783_TC3TRIODE (0x1 << 23)
|
||||
|
||||
/* For event enum values which are target-defined */
|
||||
#include "mc13783-target.h"
|
||||
|
||||
void mc13783_init(void);
|
||||
void mc13783_close(void);
|
||||
uint32_t mc13783_set(unsigned address, uint32_t bits);
|
||||
|
@ -1281,6 +1284,28 @@ int mc13783_write_regset(const unsigned char *regs, const uint32_t *data, int co
|
|||
uint32_t mc13783_read(unsigned address);
|
||||
int mc13783_read_multiple(unsigned start, uint32_t *buffer, int count);
|
||||
int mc13783_read_regset(const unsigned char *regs, uint32_t *buffer, int count);
|
||||
void mc13783_alarm_start(void);
|
||||
|
||||
/* Statically-registered event enable/disable */
|
||||
enum mc13783_event_sets
|
||||
{
|
||||
MC13783_EVENT_SET0 = 0,
|
||||
MC13783_EVENT_SET1 = 1,
|
||||
};
|
||||
|
||||
struct mc13783_event
|
||||
{
|
||||
enum mc13783_event_sets set : 8;
|
||||
uint32_t mask : 24;
|
||||
void (*callback)(void);
|
||||
};
|
||||
|
||||
struct mc13783_event_list
|
||||
{
|
||||
unsigned count;
|
||||
const struct mc13783_event *events;
|
||||
};
|
||||
|
||||
bool mc13783_enable_event(enum mc13783_event_ids event);
|
||||
void mc13783_disable_event(enum mc13783_event_ids event);
|
||||
|
||||
#endif /* _MC13783_H_ */
|
||||
|
|
|
@ -77,11 +77,11 @@ unsigned short adc_read(int channel)
|
|||
|
||||
mutex_unlock(&adc_mtx);
|
||||
|
||||
/* Channels 0-3/8-11 in ADD1, 0-4/12-15 in ADD2 */
|
||||
/* Channels 0-3/8-11 in ADD1, 4-7/12-15 in ADD2 */
|
||||
return (channel & 4) ? MC13783_ADD2r(data) : MC13783_ADD1r(data);
|
||||
}
|
||||
|
||||
/* Called when conversion is complete */
|
||||
/* Called by mc13783 interrupt thread when conversion is complete */
|
||||
void adc_done(void)
|
||||
{
|
||||
wakeup_signal(&adc_wake);
|
||||
|
@ -100,7 +100,8 @@ void adc_init(void)
|
|||
MC13783_RTHEN | MC13783_CHRGICON);
|
||||
/* Enable ADC, set multi-channel mode */
|
||||
mc13783_write(MC13783_ADC1, MC13783_ADEN);
|
||||
/* Enable the ADCDONE interrupt - notifications are dispatched by
|
||||
* event handler. */
|
||||
mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_ADCDONEM);
|
||||
|
||||
/* Enable ADCDONE event */
|
||||
mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI);
|
||||
mc13783_enable_event(MC13783_ADCDONE_EVENT);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "backlight-target.h"
|
||||
#include "avic-imx31.h"
|
||||
#include "clkctl-imx31.h"
|
||||
#include "mc13783.h"
|
||||
|
||||
/* Most code in here is taken from the Linux BSP provided by Freescale
|
||||
* Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */
|
||||
|
@ -119,6 +120,71 @@ static __attribute__((interrupt("IRQ"))) void KPP_HANDLER(void)
|
|||
int_btn = button;
|
||||
}
|
||||
|
||||
bool button_hold(void)
|
||||
{
|
||||
return _button_hold();
|
||||
}
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
/* Simple poll of GPIO status */
|
||||
hold_button = _button_hold();
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/* Backlight hold handling */
|
||||
if (hold_button != hold_button_old)
|
||||
{
|
||||
hold_button_old = hold_button;
|
||||
backlight_hold_changed(hold_button);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable the keypad interrupt to cause it to fire if a key is down.
|
||||
* KPP_HANDLER will clear and disable it after the scan. If no key
|
||||
* is depressed then this bit will already be set in waiting for the
|
||||
* first key down event. */
|
||||
KPP_KPSR |= KPP_KPSR_KDIE;
|
||||
|
||||
/* If hold, ignore any pressed button */
|
||||
return hold_button ? BUTTON_NONE : int_btn;
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void button_power_event(void)
|
||||
{
|
||||
bool pressed =
|
||||
(mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD1S) == 0;
|
||||
|
||||
/* Prevent KPP_HANDLER from changing things */
|
||||
int oldlevel = disable_irq_save();
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
int_btn |= BUTTON_POWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
int_btn &= ~BUTTON_POWER;
|
||||
}
|
||||
|
||||
restore_irq(oldlevel);
|
||||
}
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void headphone_detect_event(void)
|
||||
{
|
||||
/* FIXME: Not really the correct method */
|
||||
headphones_detect =
|
||||
(mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD2S) == 0;
|
||||
}
|
||||
|
||||
bool headphones_inserted(void)
|
||||
{
|
||||
return headphones_detect;
|
||||
}
|
||||
#endif /* HAVE_HEADPHONE_DETECTION */
|
||||
|
||||
void button_init_device(void)
|
||||
{
|
||||
#ifdef BOOTLOADER
|
||||
|
@ -154,6 +220,14 @@ void button_init_device(void)
|
|||
|
||||
/* KPP IRQ at priority 3 */
|
||||
avic_enable_int(KPP, IRQ, 3, KPP_HANDLER);
|
||||
|
||||
button_power_event();
|
||||
mc13783_enable_event(MC13783_ONOFD1_EVENT);
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
headphone_detect_event();
|
||||
mc13783_enable_event(MC13783_ONOFD2_EVENT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BUTTON_DRIVER_CLOSE
|
||||
|
@ -168,66 +242,3 @@ void button_close_device(void)
|
|||
restore_irq(oldlevel);
|
||||
}
|
||||
#endif /* BUTTON_DRIVER_CLOSE */
|
||||
|
||||
bool button_hold(void)
|
||||
{
|
||||
return _button_hold();
|
||||
}
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
/* Simple poll of GPIO status */
|
||||
hold_button = _button_hold();
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/* Backlight hold handling */
|
||||
if (hold_button != hold_button_old)
|
||||
{
|
||||
hold_button_old = hold_button;
|
||||
backlight_hold_changed(hold_button);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable the keypad interrupt to cause it to fire if a key is down.
|
||||
* KPP_HANDLER will clear and disable it after the scan. If no key
|
||||
* is depressed then this bit will already be set in waiting for the
|
||||
* first key down event. */
|
||||
KPP_KPSR |= KPP_KPSR_KDIE;
|
||||
|
||||
/* If hold, ignore any pressed button */
|
||||
return hold_button ? BUTTON_NONE : int_btn;
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void button_power_set_state(bool pressed)
|
||||
{
|
||||
/* Prevent KPP_HANDLER from changing things */
|
||||
int oldlevel = disable_irq_save();
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
int_btn |= BUTTON_POWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
int_btn &= ~BUTTON_POWER;
|
||||
}
|
||||
|
||||
restore_irq(oldlevel);
|
||||
}
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void set_headphones_inserted(bool inserted)
|
||||
{
|
||||
headphones_detect = inserted;
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
/* TODO: Just do a post to the button queue directly - implement the
|
||||
* appropriate variant in the driver. */
|
||||
bool headphones_inserted(void)
|
||||
{
|
||||
return headphones_detect;
|
||||
}
|
||||
#endif /* HAVE_HEADPHONE_DETECTION */
|
||||
|
|
|
@ -32,8 +32,8 @@ bool button_hold(void);
|
|||
void button_init_device(void);
|
||||
void button_close_device(void);
|
||||
int button_read_device(void);
|
||||
void button_power_set_state(bool pressed);
|
||||
void set_headphones_inserted(bool inserted);
|
||||
void button_power_event(void);
|
||||
void headphone_detect_event(void);
|
||||
bool headphones_inserted(void);
|
||||
|
||||
/* Toshiba Gigabeat S-specific button codes */
|
||||
|
|
|
@ -22,18 +22,23 @@
|
|||
#include "system.h"
|
||||
#include "gpio-imx31.h"
|
||||
|
||||
extern int mc13783_event(void);
|
||||
/* Gigabeat S definitions for static GPIO event registration */
|
||||
|
||||
static const struct gpio_event gpio1_events =
|
||||
/* Describes single events for each GPIO1 pin */
|
||||
static const struct gpio_event gpio1_events[] =
|
||||
{
|
||||
.line = MC13783_GPIO_LINE,
|
||||
.sense = GPIO_SENSE_RISING,
|
||||
.callback = mc13783_event,
|
||||
[MC13783_EVENT_ID-GPIO1_EVENT_FIRST] =
|
||||
{
|
||||
.mask = 1 << MC13783_GPIO_LINE,
|
||||
.sense = GPIO_SENSE_RISING,
|
||||
.callback = mc13783_event,
|
||||
}
|
||||
};
|
||||
|
||||
/* Describes the events attached to GPIO1 port */
|
||||
const struct gpio_event_list gpio1_event_list =
|
||||
{
|
||||
.priority = 7,
|
||||
.count = 1,
|
||||
.events = &gpio1_events,
|
||||
.ints_priority = 7,
|
||||
.count = ARRAYLEN(gpio1_events),
|
||||
.events = gpio1_events,
|
||||
};
|
||||
|
|
|
@ -73,29 +73,38 @@ static struct gpio_module_descriptor
|
|||
#endif
|
||||
};
|
||||
|
||||
static void gpio_call_events(enum gpio_module_number gpio)
|
||||
static void gpio_call_events(const struct gpio_module_descriptor * const desc)
|
||||
{
|
||||
const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
|
||||
const struct gpio_event_list * const list = desc->list;
|
||||
struct gpio_map * const base = desc->base;
|
||||
unsigned i;
|
||||
const struct gpio_event * event, *event_last;
|
||||
|
||||
/* Intersect pending and unmasked bits */
|
||||
uint32_t pending = base->isr & base->imr;
|
||||
uint32_t pnd = base->isr & base->imr;
|
||||
|
||||
event = list->events;
|
||||
event_last = event + list->count;
|
||||
|
||||
/* Call each event handler in order */
|
||||
for (i = 0; i < list->count; i++)
|
||||
/* .count is surely expected to be > 0 */
|
||||
do
|
||||
{
|
||||
const struct gpio_event * const event = &list->events[i];
|
||||
uint32_t bit = 1ul << event->line;
|
||||
uint32_t mask = event->mask;
|
||||
|
||||
if ((pending & bit) && event->callback())
|
||||
pending &= ~bit;
|
||||
if (pnd & mask)
|
||||
{
|
||||
event->callback();
|
||||
pnd &= ~mask;
|
||||
}
|
||||
|
||||
if (pnd == 0)
|
||||
break; /* Teminate early if nothing more to service */
|
||||
}
|
||||
while (++event < event_last);
|
||||
|
||||
if (pending != 0)
|
||||
if (pnd != 0)
|
||||
{
|
||||
/* Wasn't handled */
|
||||
/* One or more weren't handled */
|
||||
UIE_VECTOR();
|
||||
}
|
||||
}
|
||||
|
@ -103,21 +112,21 @@ static void gpio_call_events(enum gpio_module_number gpio)
|
|||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
||||
static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void)
|
||||
{
|
||||
gpio_call_events(GPIO1_NUM);
|
||||
gpio_call_events(&gpio_descs[GPIO1_NUM]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
||||
static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void)
|
||||
{
|
||||
gpio_call_events(GPIO2_NUM);
|
||||
gpio_call_events(&gpio_descs[GPIO2_NUM]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
||||
static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
|
||||
{
|
||||
gpio_call_events(GPIO3_NUM);
|
||||
gpio_call_events(&gpio_descs[GPIO3_NUM]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -140,19 +149,16 @@ void gpio_init(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool gpio_enable_event(enum gpio_module_number gpio, unsigned id)
|
||||
bool gpio_enable_event(enum gpio_event_ids id)
|
||||
{
|
||||
const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
|
||||
const struct gpio_event * const event = &desc->list->events[id];
|
||||
const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5];
|
||||
const struct gpio_event * const event = &desc->list->events[id & 31];
|
||||
struct gpio_map * const base = desc->base;
|
||||
volatile uint32_t *icr;
|
||||
uint32_t mask;
|
||||
uint32_t mask, line;
|
||||
uint32_t imr;
|
||||
int shift;
|
||||
|
||||
if (id >= desc->list->count)
|
||||
return false;
|
||||
|
||||
int oldlevel = disable_irq_save();
|
||||
|
||||
imr = base->imr;
|
||||
|
@ -160,39 +166,37 @@ bool gpio_enable_event(enum gpio_module_number gpio, unsigned id)
|
|||
if (imr == 0)
|
||||
{
|
||||
/* First enabled interrupt for this GPIO */
|
||||
avic_enable_int(desc->ints, IRQ, desc->list->priority,
|
||||
avic_enable_int(desc->ints, IRQ, desc->list->ints_priority,
|
||||
desc->handler);
|
||||
}
|
||||
|
||||
/* Set the line sense */
|
||||
icr = &base->icr[event->line >> 4];
|
||||
shift = (event->line & 15) << 1;
|
||||
line = find_first_set_bit(event->mask);
|
||||
icr = &base->icr[line >> 4];
|
||||
shift = (line & 15) << 1;
|
||||
mask = GPIO_SENSE_CONFIG_MASK << shift;
|
||||
|
||||
*icr = (*icr & ~mask) | ((event->sense << shift) & mask);
|
||||
|
||||
/* Unmask the line */
|
||||
base->imr = imr | (1ul << event->line);
|
||||
base->imr = imr | event->mask;
|
||||
|
||||
restore_irq(oldlevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gpio_disable_event(enum gpio_module_number gpio, unsigned id)
|
||||
void gpio_disable_event(enum gpio_event_ids id)
|
||||
{
|
||||
const struct gpio_module_descriptor * const desc = &gpio_descs[gpio];
|
||||
const struct gpio_event * const event = &desc->list->events[id];
|
||||
const struct gpio_module_descriptor * const desc = &gpio_descs[id >> 5];
|
||||
const struct gpio_event * const event = &desc->list->events[id & 31];
|
||||
struct gpio_map * const base = desc->base;
|
||||
uint32_t imr;
|
||||
|
||||
if (id >= desc->list->count)
|
||||
return;
|
||||
|
||||
int oldlevel = disable_irq_save();
|
||||
|
||||
/* Remove bit from mask */
|
||||
imr = base->imr & ~(1ul << event->line);
|
||||
imr = base->imr & ~event->mask;
|
||||
|
||||
/* Mask the line */
|
||||
base->imr = imr;
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
#ifndef GPIO_IMX31_H
|
||||
#define GPIO_IMX31_H
|
||||
|
||||
#include "gpio-target.h"
|
||||
|
||||
/* Static registration mechanism for imx31 GPIO interrupts */
|
||||
#define USE_GPIO1_EVENTS (1 << 0)
|
||||
#define USE_GPIO2_EVENTS (1 << 1)
|
||||
#define USE_GPIO3_EVENTS (1 << 2)
|
||||
|
||||
/* Module indexes defined by which GPIO modules are used */
|
||||
enum gpio_module_number
|
||||
{
|
||||
__GPIO_NUM_START = -1,
|
||||
|
@ -40,6 +40,22 @@ enum gpio_module_number
|
|||
GPIO_NUM_GPIO,
|
||||
};
|
||||
|
||||
/* Module corresponding to the event ID is identified by range */
|
||||
enum gpio_event_bases
|
||||
{
|
||||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
||||
GPIO1_EVENT_FIRST = 32*GPIO1_NUM,
|
||||
#endif
|
||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
||||
GPIO2_EVENT_FIRST = 32*GPIO2_NUM,
|
||||
#endif
|
||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
||||
GPIO3_EVENT_FIRST = 32*GPIO3_NUM,
|
||||
#endif
|
||||
};
|
||||
|
||||
#include "gpio-target.h"
|
||||
|
||||
/* Possible values for gpio interrupt line config */
|
||||
enum gpio_int_sense_enum
|
||||
{
|
||||
|
@ -54,35 +70,43 @@ enum gpio_int_sense_enum
|
|||
/* Register map for each module */
|
||||
struct gpio_map
|
||||
{
|
||||
volatile uint32_t dr; /* 00h */
|
||||
volatile uint32_t gdir; /* 04h */
|
||||
volatile uint32_t psr; /* 08h */
|
||||
volatile uint32_t icr[2]; /* 0Ch */
|
||||
volatile uint32_t imr; /* 14h */
|
||||
volatile uint32_t isr; /* 18h */
|
||||
volatile uint32_t dr; /* 00h */
|
||||
volatile uint32_t gdir; /* 04h */
|
||||
volatile uint32_t psr; /* 08h */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
volatile uint32_t icr1; /* 0Ch */
|
||||
volatile uint32_t icr2; /* 10h */
|
||||
};
|
||||
volatile uint32_t icr[2]; /* 0Ch */
|
||||
};
|
||||
volatile uint32_t imr; /* 14h */
|
||||
volatile uint32_t isr; /* 18h */
|
||||
};
|
||||
|
||||
/* Pending events will be called in array order */
|
||||
/* Pending events will be called in array order which allows easy
|
||||
* pioritization */
|
||||
|
||||
/* Describes a single event for a pin */
|
||||
struct gpio_event
|
||||
{
|
||||
int line; /* Line number (0-31) */
|
||||
uint32_t mask; /* mask: 1 << (0...31) */
|
||||
enum gpio_int_sense_enum sense; /* Type of sense */
|
||||
int (*callback)(void); /* Callback function (return nonzero
|
||||
* to indicate this event was handled) */
|
||||
void (*callback)(void); /* Callback function */
|
||||
};
|
||||
|
||||
/* Describes the events attached to a port */
|
||||
struct gpio_event_list
|
||||
{
|
||||
int priority; /* Interrupt priority for this GPIO */
|
||||
unsigned count; /* Count of events */
|
||||
int ints_priority; /* Interrupt priority for this GPIO */
|
||||
unsigned count; /* Count of events for the module */
|
||||
const struct gpio_event *events; /* List of events */
|
||||
};
|
||||
|
||||
void gpio_init(void);
|
||||
bool gpio_enable_event(enum gpio_module_number gpio, unsigned id);
|
||||
void gpio_disable_event(enum gpio_module_number gpio, unsigned id);
|
||||
bool gpio_enable_event(enum gpio_event_ids id);
|
||||
void gpio_disable_event(enum gpio_event_ids id);
|
||||
|
||||
#endif /* GPIO_IMX31_H */
|
||||
|
|
|
@ -21,11 +21,22 @@
|
|||
#ifndef GPIO_TARGET_H
|
||||
#define GPIO_TARGET_H
|
||||
|
||||
#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
|
||||
|
||||
/* MC13783 GPIO pin info for this target */
|
||||
#define MC13783_GPIO_NUM GPIO1_NUM
|
||||
#define MC13783_GPIO_ISR GPIO1_ISR
|
||||
#define MC13783_GPIO_LINE 31
|
||||
#define MC13783_EVENT_ID 0
|
||||
|
||||
/* Declare event indexes in priority order in a packed array */
|
||||
enum gpio_event_ids
|
||||
{
|
||||
/* GPIO1 event IDs */
|
||||
MC13783_EVENT_ID = GPIO1_EVENT_FIRST,
|
||||
/* GPIO2 event IDs */
|
||||
/* none defined */
|
||||
/* GPIO3 event IDs */
|
||||
/* none defined */
|
||||
};
|
||||
|
||||
void mc13783_event(void);
|
||||
|
||||
#endif /* GPIO_TARGET_H */
|
||||
|
|
72
firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
Normal file
72
firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 by Michael Sevakis
|
||||
*
|
||||
* Gigabeat S MC13783 event descriptions
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "mc13783.h"
|
||||
#include "mc13783-target.h"
|
||||
#include "adc-target.h"
|
||||
#include "button-target.h"
|
||||
#include "usb-target.h"
|
||||
#include "power-imx31.h"
|
||||
|
||||
/* Gigabeat S definitions for static MC13783 event registration */
|
||||
|
||||
static const struct mc13783_event mc13783_events[] =
|
||||
{
|
||||
[MC13783_ADCDONE_EVENT] = /* ADC conversion complete */
|
||||
{
|
||||
.set = MC13783_EVENT_SET0,
|
||||
.mask = MC13783_ADCDONEM,
|
||||
.callback = adc_done,
|
||||
},
|
||||
[MC13783_ONOFD1_EVENT] = /* Power button */
|
||||
{
|
||||
.set = MC13783_EVENT_SET1,
|
||||
.mask = MC13783_ONOFD1M,
|
||||
.callback = button_power_event,
|
||||
},
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
[MC13783_ONOFD2_EVENT] = /* Headphone jack */
|
||||
{
|
||||
.set = MC13783_EVENT_SET1,
|
||||
.mask = MC13783_ONOFD2M,
|
||||
.callback = headphone_detect_event,
|
||||
},
|
||||
#endif
|
||||
[MC13783_CHGDET_EVENT] = /* Charger detection */
|
||||
{
|
||||
.set = MC13783_EVENT_SET0,
|
||||
.mask = MC13783_CHGDETM,
|
||||
.callback = charger_detect_event,
|
||||
},
|
||||
[MC13783_USB4V4_EVENT] = /* USB insertion */
|
||||
{
|
||||
.set = MC13783_EVENT_SET0,
|
||||
.mask = MC13783_USB4V4M,
|
||||
.callback = usb_connect_event,
|
||||
},
|
||||
};
|
||||
|
||||
const struct mc13783_event_list mc13783_event_list =
|
||||
{
|
||||
.count = ARRAYLEN(mc13783_events),
|
||||
.events = mc13783_events
|
||||
};
|
|
@ -49,121 +49,86 @@ static struct spi_node mc13783_spi =
|
|||
0, /* SPI clock - no wait states */
|
||||
};
|
||||
|
||||
static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)];
|
||||
extern const struct mc13783_event_list mc13783_event_list;
|
||||
|
||||
static int mc13783_thread_stack[3*DEFAULT_STACK_SIZE/sizeof(int)];
|
||||
static const char *mc13783_thread_name = "pmic";
|
||||
static struct wakeup mc13783_wake;
|
||||
|
||||
/* Tracking for which interrupts are enabled */
|
||||
static uint32_t pmic_int_enabled[2] =
|
||||
{ 0x00000000, 0x00000000 };
|
||||
|
||||
static const unsigned char pmic_intm_regs[2] =
|
||||
{ MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 };
|
||||
|
||||
static const unsigned char pmic_ints_regs[2] =
|
||||
{ MC13783_INTERRUPT_STATUS0, MC13783_INTERRUPT_STATUS1 };
|
||||
|
||||
#ifdef PMIC_DRIVER_CLOSE
|
||||
static bool pmic_close = false;
|
||||
static struct thread_entry *mc13783_thread_p = NULL;
|
||||
#endif
|
||||
|
||||
/* The next two functions are rather target-specific but they'll just be left
|
||||
* here for the moment */
|
||||
static void mc13783_interrupt_thread(void)
|
||||
{
|
||||
const unsigned char status_regs[2] =
|
||||
{
|
||||
MC13783_INTERRUPT_STATUS0,
|
||||
MC13783_INTERRUPT_STATUS1,
|
||||
};
|
||||
uint32_t pending[2];
|
||||
uint32_t value;
|
||||
|
||||
mc13783_read_regset(status_regs, pending, 2);
|
||||
mc13783_write_regset(status_regs, pending, 2);
|
||||
/* Enable mc13783 GPIO event */
|
||||
gpio_enable_event(MC13783_EVENT_ID);
|
||||
|
||||
gpio_enable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID);
|
||||
|
||||
if (pending[1] & MC13783_TODAI) /* only needs to be polled on startup */
|
||||
mc13783_alarm_start();
|
||||
|
||||
/* Check initial states for events with a sense bit */
|
||||
value = mc13783_read(MC13783_INTERRUPT_SENSE0);
|
||||
usb_set_status(value & MC13783_USB4V4S);
|
||||
set_charger_inserted(value & MC13783_CHGDETS);
|
||||
|
||||
value = mc13783_read(MC13783_INTERRUPT_SENSE1);
|
||||
button_power_set_state((value & MC13783_ONOFD1S) == 0);
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
set_headphones_inserted((value & MC13783_ONOFD2S) == 0);
|
||||
#endif
|
||||
|
||||
pending[0] = pending[1] = 0xffffff;
|
||||
mc13783_write_regset(status_regs, pending, 2);
|
||||
|
||||
/* Enable desired PMIC interrupts - some are unmasked in the drivers that
|
||||
* handle a specific task */
|
||||
mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_CHGDETM);
|
||||
mc13783_clear(MC13783_INTERRUPT_MASK1, MC13783_ONOFD1M |
|
||||
MC13783_ONOFD2M);
|
||||
|
||||
while (1)
|
||||
{
|
||||
const struct mc13783_event *event, *event_last;
|
||||
|
||||
wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK);
|
||||
|
||||
#ifdef PMIC_DRIVER_CLOSE
|
||||
if (pmic_close)
|
||||
{
|
||||
gpio_disable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
mc13783_read_regset(status_regs, pending, 2);
|
||||
mc13783_write_regset(status_regs, pending, 2);
|
||||
mc13783_read_regset(pmic_ints_regs, pending, 2);
|
||||
|
||||
if (pending[0])
|
||||
/* Only clear interrupts being dispatched */
|
||||
pending[0] &= pmic_int_enabled[0];
|
||||
pending[1] &= pmic_int_enabled[1];
|
||||
|
||||
mc13783_write_regset(pmic_ints_regs, pending, 2);
|
||||
|
||||
event = mc13783_event_list.events;
|
||||
event_last = event + mc13783_event_list.count;
|
||||
|
||||
/* .count is surely expected to be > 0 */
|
||||
do
|
||||
{
|
||||
/* Handle ...PENDING0 */
|
||||
enum mc13783_event_sets set = event->set;
|
||||
uint32_t pnd = pending[set];
|
||||
uint32_t mask = event->mask;
|
||||
|
||||
/* Handle interrupts without a sense bit */
|
||||
if (pending[0] & MC13783_ADCDONEI)
|
||||
adc_done();
|
||||
|
||||
/* Handle interrupts that have a sense bit that needs to
|
||||
* be checked */
|
||||
if (pending[0] & (MC13783_CHGDETI | MC13783_USB4V4I))
|
||||
if (pnd & mask)
|
||||
{
|
||||
value = mc13783_read(MC13783_INTERRUPT_SENSE0);
|
||||
|
||||
if (pending[0] & MC13783_CHGDETI)
|
||||
set_charger_inserted(value & MC13783_CHGDETS);
|
||||
|
||||
if (pending[0] & MC13783_USB4V4I)
|
||||
usb_set_status(value & MC13783_USB4V4S);
|
||||
}
|
||||
}
|
||||
|
||||
if (pending[1])
|
||||
{
|
||||
/* Handle ...PENDING1 */
|
||||
|
||||
/* Handle interrupts without a sense bit */
|
||||
/* ... */
|
||||
|
||||
/* Handle interrupts that have a sense bit that needs to
|
||||
* be checked */
|
||||
if (pending[1] & (MC13783_ONOFD1I | MC13783_ONOFD2I))
|
||||
{
|
||||
value = mc13783_read(MC13783_INTERRUPT_SENSE1);
|
||||
|
||||
if (pending[1] & MC13783_ONOFD1I)
|
||||
button_power_set_state((value & MC13783_ONOFD1S) == 0);
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
if (pending[1] & MC13783_ONOFD2I)
|
||||
set_headphones_inserted((value & MC13783_ONOFD2S) == 0);
|
||||
#endif
|
||||
event->callback();
|
||||
pnd &= ~mask;
|
||||
pending[set] = pnd;
|
||||
}
|
||||
|
||||
if ((pending[0] | pending[1]) == 0)
|
||||
break; /* Teminate early if nothing more to service */
|
||||
}
|
||||
while (++event < event_last);
|
||||
}
|
||||
|
||||
#ifdef PMIC_DRIVER_CLOSE
|
||||
gpio_disable_event(MC13783_EVENT_ID);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* GPIO interrupt handler for mc13783 */
|
||||
int mc13783_event(void)
|
||||
void mc13783_event(void)
|
||||
{
|
||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||
wakeup_signal(&mc13783_wake);
|
||||
return 1; /* Yes, it's handled */
|
||||
}
|
||||
|
||||
void mc13783_init(void)
|
||||
|
@ -174,8 +139,8 @@ void mc13783_init(void)
|
|||
/* Enable the PMIC SPI module */
|
||||
spi_enable_module(&mc13783_spi);
|
||||
|
||||
/* Mask any PMIC interrupts for now - poll initial status in thread
|
||||
* and enable them there */
|
||||
/* Mask any PMIC interrupts for now - modules will enable them as
|
||||
* required */
|
||||
mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff);
|
||||
mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
|
||||
|
||||
|
@ -203,7 +168,39 @@ void mc13783_close(void)
|
|||
wakeup_signal(&mc13783_wake);
|
||||
thread_wait(thread);
|
||||
}
|
||||
#endif
|
||||
#endif /* PMIC_DRIVER_CLOSE */
|
||||
|
||||
bool mc13783_enable_event(enum mc13783_event_ids id)
|
||||
{
|
||||
const struct mc13783_event * const event =
|
||||
&mc13783_event_list.events[id];
|
||||
int set = event->set;
|
||||
uint32_t mask = event->mask;
|
||||
|
||||
spi_lock(&mc13783_spi);
|
||||
|
||||
pmic_int_enabled[set] |= mask;
|
||||
mc13783_clear(pmic_intm_regs[set], mask);
|
||||
|
||||
spi_unlock(&mc13783_spi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mc13783_disable_event(enum mc13783_event_ids id)
|
||||
{
|
||||
const struct mc13783_event * const event =
|
||||
&mc13783_event_list.events[id];
|
||||
int set = event->set;
|
||||
uint32_t mask = event->mask;
|
||||
|
||||
spi_lock(&mc13783_spi);
|
||||
|
||||
pmic_int_enabled[set] &= ~mask;
|
||||
mc13783_set(pmic_intm_regs[set], mask);
|
||||
|
||||
spi_unlock(&mc13783_spi);
|
||||
}
|
||||
|
||||
uint32_t mc13783_set(unsigned address, uint32_t bits)
|
||||
{
|
||||
|
|
36
firmware/target/arm/imx31/gigabeat-s/mc13783-target.h
Normal file
36
firmware/target/arm/imx31/gigabeat-s/mc13783-target.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2008 by Michael Sevakis
|
||||
*
|
||||
* Gigabeat S mc13783 event descriptions
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef MC13783_TARGET_H
|
||||
#define MC13783_TARGET_H
|
||||
|
||||
/* Declare event indexes in priority order in a packed array */
|
||||
enum mc13783_event_ids
|
||||
{
|
||||
MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */
|
||||
MC13783_ONOFD1_EVENT, /* Power button */
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
MC13783_ONOFD2_EVENT, /* Headphone jack */
|
||||
#endif
|
||||
MC13783_CHGDET_EVENT, /* Charger detection */
|
||||
MC13783_USB4V4_EVENT, /* USB insertion */
|
||||
};
|
||||
|
||||
#endif /* MC13783_TARGET_H */
|
|
@ -28,14 +28,11 @@
|
|||
|
||||
static bool charger_detect = false;
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void set_charger_inserted(bool inserted)
|
||||
void charger_detect_event(void)
|
||||
{
|
||||
charger_detect = inserted;
|
||||
charger_detect =
|
||||
mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_CHGDETS;
|
||||
}
|
||||
|
||||
bool charger_inserted(void)
|
||||
|
@ -81,6 +78,15 @@ void power_off(void)
|
|||
while (1);
|
||||
}
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
/* Poll initial state */
|
||||
charger_detect_event();
|
||||
|
||||
/* Enable detect event */
|
||||
mc13783_enable_event(MC13783_CHGDET_EVENT);
|
||||
}
|
||||
|
||||
#else /* SIMULATOR */
|
||||
|
||||
bool charger_inserted(void)
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
#ifndef POWER_IMX31_H
|
||||
#define POWER_IMX31_H
|
||||
|
||||
void set_charger_inserted(bool inserted);
|
||||
void charger_detect_event(void);
|
||||
|
||||
#endif /* POWER_IMX31_H */
|
||||
|
|
|
@ -48,9 +48,10 @@ static void enable_transceiver(bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
void usb_set_status(bool plugged)
|
||||
void usb_connect_event(void)
|
||||
{
|
||||
usb_status = plugged ? USB_INSERTED : USB_EXTRACTED;
|
||||
uint32_t status = mc13783_read(MC13783_INTERRUPT_SENSE0);
|
||||
usb_status = (status & MC13783_USB4V4S) ? USB_INSERTED : USB_EXTRACTED;
|
||||
}
|
||||
|
||||
int usb_detect(void)
|
||||
|
@ -73,7 +74,11 @@ void usb_init_device(void)
|
|||
/* Module will be turned off later after firmware init */
|
||||
usb_drv_startup();
|
||||
|
||||
mc13783_clear(MC13783_INTERRUPT_MASK0, MC13783_USB4V4M);
|
||||
/* Initially poll */
|
||||
usb_connect_event();
|
||||
|
||||
/* Enable PMIC event */
|
||||
mc13783_enable_event(MC13783_USB4V4_EVENT);
|
||||
}
|
||||
|
||||
void usb_enable(bool on)
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define USB_DRIVER_CLOSE
|
||||
#endif
|
||||
|
||||
void usb_set_status(bool plugged);
|
||||
void usb_connect_event(void);
|
||||
bool usb_init_device(void);
|
||||
int usb_detect(void);
|
||||
/* Read the immediate state of the cable from the PMIC */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue