1
0
Fork 0
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:
Michael Sevakis 2008-05-21 08:42:11 +00:00
parent 5f796087b0
commit a9c20f5789
19 changed files with 443 additions and 235 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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,
};

View file

@ -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;

View file

@ -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 */

View file

@ -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 */

View 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
};

View file

@ -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);
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);
/* Enable mc13783 GPIO event */
gpio_enable_event(MC13783_EVENT_ID);
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)
{

View 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 */

View file

@ -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)

View file

@ -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 */

View file

@ -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)

View file

@ -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 */