i.MX31 - Dethreading operations continue
Dispense with "pmic" thread and process PMIC events directly within ISR. Add sense bit reading as part of the handling. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31528 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1f0e653038
commit
5a8da163c8
9 changed files with 213 additions and 202 deletions
|
@ -164,7 +164,7 @@
|
|||
#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 2
|
||||
#define TARGET_EXTRA_THREADS 1
|
||||
|
||||
/* Type of mobile power - check this out */
|
||||
#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
|
||||
|
|
|
@ -1333,7 +1333,8 @@ enum mc13783_int_ids
|
|||
|
||||
struct mc13783_event
|
||||
{
|
||||
enum mc13783_int_ids int_id;
|
||||
enum mc13783_int_ids int_id : 8;
|
||||
uint32_t sense : 24;
|
||||
void (*callback)(void);
|
||||
};
|
||||
|
||||
|
@ -1343,7 +1344,9 @@ struct mc13783_event_list
|
|||
const struct mc13783_event *events;
|
||||
};
|
||||
|
||||
bool mc13783_enable_event(enum mc13783_event_ids event);
|
||||
void mc13783_disable_event(enum mc13783_event_ids event);
|
||||
void mc13783_enable_event(enum mc13783_event_ids id, bool enable);
|
||||
|
||||
/* Read the sense bit if one exists - valid only within event handlers */
|
||||
uint32_t mc13783_event_sense(enum mc13783_event_ids id);
|
||||
|
||||
#endif /* _MC13783_H_ */
|
||||
|
|
|
@ -110,7 +110,7 @@ bool adc_enable_channel(int channel, bool enable)
|
|||
!= MC13783_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Called by mc13783 interrupt thread when conversion is complete */
|
||||
/* ADC conversion complete event - called from PMIC ISR */
|
||||
void adc_done(void)
|
||||
{
|
||||
semaphore_release(&adc_done_signal);
|
||||
|
@ -132,5 +132,5 @@ void adc_init(void)
|
|||
|
||||
/* Enable ADCDONE event */
|
||||
mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI);
|
||||
mc13783_enable_event(MC13783_ADCDONE_EVENT);
|
||||
mc13783_enable_event(MC13783_ADCDONE_EVENT, true);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
static bool initialized = false;
|
||||
#endif
|
||||
|
||||
static int ext_btn = BUTTON_NONE; /* Buttons not on KPP */
|
||||
static unsigned long ext_btn = BUTTON_NONE; /* Buttons not on KPP */
|
||||
static bool hold_button = false;
|
||||
#ifndef BOOTLOADER
|
||||
static bool hold_button_old = false;
|
||||
|
@ -150,24 +150,16 @@ int button_read_device(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
/* Helper to update the power button status */
|
||||
static void power_button_update(bool pressed)
|
||||
{
|
||||
bitmod32(&ext_btn, pressed ? BUTTON_POWER : 0, BUTTON_POWER);
|
||||
}
|
||||
|
||||
/* Power button event - called from PMIC ISR */
|
||||
void button_power_event(void)
|
||||
{
|
||||
bool pressed =
|
||||
(mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD1S) == 0;
|
||||
|
||||
int oldlevel = disable_irq_save();
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
ext_btn |= BUTTON_POWER;
|
||||
}
|
||||
else
|
||||
{
|
||||
ext_btn &= ~BUTTON_POWER;
|
||||
}
|
||||
|
||||
restore_irq(oldlevel);
|
||||
power_button_update(!mc13783_event_sense(MC13783_ONOFD1_EVENT));
|
||||
}
|
||||
|
||||
void button_init_device(void)
|
||||
|
@ -203,8 +195,9 @@ void button_init_device(void)
|
|||
* 6. Set the KDIE control bit bit. */
|
||||
KPP_KPSR = KPP_KPSR_KRSS | KPP_KPSR_KDSC | KPP_KPSR_KPKD;
|
||||
|
||||
button_power_event();
|
||||
mc13783_enable_event(MC13783_ONOFD1_EVENT);
|
||||
power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1)
|
||||
& MC13783_ONOFD1S));
|
||||
mc13783_enable_event(MC13783_ONOFD1_EVENT, true);
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
headphone_init();
|
||||
|
@ -220,7 +213,7 @@ void button_close_device(void)
|
|||
/* Assumes HP detection is not available */
|
||||
initialized = false;
|
||||
|
||||
mc13783_disable_event(MC13783_ONOFD1_EVENT);
|
||||
mc13783_enable_event(MC13783_ONOFD1_EVENT, true);
|
||||
ext_btn = BUTTON_NONE;
|
||||
}
|
||||
#endif /* BUTTON_DRIVER_CLOSE */
|
||||
|
|
|
@ -171,7 +171,7 @@ static void headphone_thread(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
/* HP plugged/unplugged event - called from PMIC ISR */
|
||||
void headphone_detect_event(void)
|
||||
{
|
||||
/* Trigger the thread immediately. */
|
||||
|
@ -197,5 +197,5 @@ void INIT_ATTR headphone_init(void)
|
|||
|
||||
/* Initially poll and then enable PMIC event */
|
||||
headphone_detect_event();
|
||||
mc13783_enable_event(MC13783_ONOFD2_EVENT);
|
||||
mc13783_enable_event(MC13783_ONOFD2_EVENT, true);
|
||||
}
|
||||
|
|
|
@ -55,28 +55,33 @@ const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS] =
|
|||
{
|
||||
[MC13783_ADCDONE_EVENT] = /* ADC conversion complete */
|
||||
{
|
||||
.int_id = MC13783_INT_ID_ADCDONE,
|
||||
.int_id = MC13783_INT_ID_ADCDONE,
|
||||
.sense = 0,
|
||||
.callback = adc_done,
|
||||
},
|
||||
[MC13783_ONOFD1_EVENT] = /* Power button */
|
||||
{
|
||||
.int_id = MC13783_INT_ID_ONOFD1,
|
||||
.int_id = MC13783_INT_ID_ONOFD1,
|
||||
.sense = MC13783_ONOFD1S,
|
||||
.callback = button_power_event,
|
||||
},
|
||||
[MC13783_SE1_EVENT] = /* Main charger detection */
|
||||
{
|
||||
.int_id = MC13783_INT_ID_SE1,
|
||||
.int_id = MC13783_INT_ID_SE1,
|
||||
.sense = MC13783_SE1S,
|
||||
.callback = charger_main_detect_event,
|
||||
},
|
||||
[MC13783_USB_EVENT] = /* USB insertion/USB charger detection */
|
||||
{
|
||||
.int_id = MC13783_INT_ID_USB,
|
||||
.int_id = MC13783_INT_ID_USB,
|
||||
.sense = MC13783_USB4V4S,
|
||||
.callback = usb_connect_event,
|
||||
},
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
[MC13783_ONOFD2_EVENT] = /* Headphone jack */
|
||||
{
|
||||
.int_id = MC13783_INT_ID_ONOFD2,
|
||||
.int_id = MC13783_INT_ID_ONOFD2,
|
||||
.sense = 0,
|
||||
.callback = headphone_detect_event,
|
||||
},
|
||||
#endif
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "fmradio_i2c.h"
|
||||
#endif
|
||||
|
||||
static unsigned int power_status = POWER_INPUT_NONE;
|
||||
static unsigned long power_status = POWER_INPUT_NONE;
|
||||
|
||||
/* Detect which power sources are present. */
|
||||
unsigned int power_input_status(void)
|
||||
|
@ -58,24 +58,28 @@ void usb_charging_maxcurrent_change(int maxcurrent)
|
|||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/* Detect changes in presence of the AC adaptor. */
|
||||
void charger_main_detect_event(void)
|
||||
/* Helper to update the charger status */
|
||||
static void update_main_charger(bool present)
|
||||
{
|
||||
if (mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_SE1S)
|
||||
power_status |= POWER_INPUT_MAIN_CHARGER;
|
||||
else
|
||||
power_status &= ~POWER_INPUT_MAIN_CHARGER;
|
||||
bitmod32(&power_status, present ? POWER_INPUT_MAIN_CHARGER : 0,
|
||||
POWER_INPUT_MAIN_CHARGER);
|
||||
}
|
||||
|
||||
/* Detect changes in USB bus power. Called from usb connect event handler. */
|
||||
/* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */
|
||||
void charger_main_detect_event(void)
|
||||
{
|
||||
update_main_charger(mc13783_event_sense(MC13783_INT_ID_SE1)
|
||||
& MC13783_SE1S);
|
||||
}
|
||||
|
||||
/* Detect changes in USB bus power. Called from usb connect event ISR. */
|
||||
void charger_usb_detect_event(int status)
|
||||
{
|
||||
/* USB plugged does not imply charging is possible or even
|
||||
* powering the device to maintain the battery. */
|
||||
if (status == USB_INSERTED)
|
||||
power_status |= POWER_INPUT_USB_CHARGER;
|
||||
else
|
||||
power_status &= ~POWER_INPUT_USB_CHARGER;
|
||||
bitmod32(&power_status,
|
||||
status == USB_INSERTED ? POWER_INPUT_USB_CHARGER : 0,
|
||||
POWER_INPUT_USB_CHARGER);
|
||||
}
|
||||
|
||||
/* charging_state is implemented in powermgmt-imx31.c */
|
||||
|
@ -152,8 +156,9 @@ void power_init(void)
|
|||
#endif
|
||||
|
||||
/* Poll initial state */
|
||||
charger_main_detect_event();
|
||||
update_main_charger(mc13783_read(MC13783_INTERRUPT_SENSE0)
|
||||
& MC13783_SE1S);
|
||||
|
||||
/* Enable detect event */
|
||||
mc13783_enable_event(MC13783_SE1_EVENT);
|
||||
mc13783_enable_event(MC13783_SE1_EVENT, true);
|
||||
}
|
||||
|
|
|
@ -59,16 +59,23 @@ bool usb_plugged(void)
|
|||
return mc13783_read(MC13783_INTERRUPT_SENSE0) & MC13783_USB4V4S;
|
||||
}
|
||||
|
||||
void usb_connect_event(void)
|
||||
/* Helper to update the USB cable status */
|
||||
static void update_usb_status(bool sense)
|
||||
{
|
||||
/* Read the immediate state of the cable from the PMIC */
|
||||
int status = usb_plugged() ? USB_INSERTED : USB_EXTRACTED;
|
||||
int status = sense ? USB_INSERTED : USB_EXTRACTED;
|
||||
usb_status = status;
|
||||
/* Notify power that USB charging is potentially available */
|
||||
charger_usb_detect_event(status);
|
||||
usb_status_event(status);
|
||||
}
|
||||
|
||||
/* Detect presence of USB bus - called from PMIC ISR */
|
||||
void usb_connect_event(void)
|
||||
{
|
||||
/* Read the associated sense value */
|
||||
update_usb_status(mc13783_event_sense(MC13783_USB_EVENT));
|
||||
}
|
||||
|
||||
int usb_detect(void)
|
||||
{
|
||||
return usb_status;
|
||||
|
@ -80,10 +87,10 @@ void usb_init_device(void)
|
|||
usb_drv_startup();
|
||||
|
||||
/* Initially poll */
|
||||
usb_connect_event();
|
||||
update_usb_status(usb_plugged());
|
||||
|
||||
/* Enable PMIC event */
|
||||
mc13783_enable_event(MC13783_USB_EVENT);
|
||||
mc13783_enable_event(MC13783_USB_EVENT, true);
|
||||
}
|
||||
|
||||
void usb_enable(bool on)
|
||||
|
|
|
@ -26,26 +26,6 @@
|
|||
#include "debug.h"
|
||||
#include "kernel.h"
|
||||
|
||||
extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS];
|
||||
extern struct spi_node mc13783_spi;
|
||||
|
||||
/* PMIC event service data */
|
||||
static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)];
|
||||
static const char * const mc13783_thread_name = "pmic";
|
||||
static struct semaphore mc13783_svc_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 };
|
||||
|
||||
static volatile unsigned int mc13783_thread_id = 0;
|
||||
|
||||
/* Extend the basic SPI transfer descriptor with our own fields */
|
||||
struct mc13783_transfer_desc
|
||||
{
|
||||
|
@ -57,137 +37,15 @@ struct mc13783_transfer_desc
|
|||
};
|
||||
};
|
||||
|
||||
/* Called when a transfer is finished and data is ready/written */
|
||||
static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer)
|
||||
{
|
||||
semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema);
|
||||
}
|
||||
extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS];
|
||||
extern struct spi_node mc13783_spi;
|
||||
|
||||
static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer)
|
||||
{
|
||||
return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK)
|
||||
== OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
|
||||
}
|
||||
|
||||
static void mc13783_interrupt_thread(void)
|
||||
{
|
||||
uint32_t pending[2];
|
||||
|
||||
/* Enable mc13783 GPIO event */
|
||||
gpio_enable_event(MC13783_EVENT_ID);
|
||||
|
||||
while (1)
|
||||
{
|
||||
const struct mc13783_event *event, *event_last;
|
||||
|
||||
semaphore_wait(&mc13783_svc_wake, TIMEOUT_BLOCK);
|
||||
|
||||
if (mc13783_thread_id == 0)
|
||||
break;
|
||||
|
||||
mc13783_read_regs(pmic_ints_regs, pending, 2);
|
||||
|
||||
/* Only clear interrupts being dispatched */
|
||||
pending[0] &= pmic_int_enabled[0];
|
||||
pending[1] &= pmic_int_enabled[1];
|
||||
|
||||
mc13783_write_regs(pmic_ints_regs, pending, 2);
|
||||
|
||||
/* Whatever is going to be serviced in this loop has been
|
||||
* acknowledged. Reenable interrupt and if anything was still
|
||||
* pending or became pending again, another signal will be
|
||||
* generated. */
|
||||
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
|
||||
event = mc13783_events;
|
||||
event_last = event + MC13783_NUM_EVENTS;
|
||||
|
||||
/* .count is surely expected to be > 0 */
|
||||
do
|
||||
{
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
uint32_t pnd = pending[set];
|
||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
||||
|
||||
if (pnd & mask)
|
||||
{
|
||||
event->callback();
|
||||
pending[set] = pnd & ~mask;
|
||||
}
|
||||
|
||||
if ((pending[0] | pending[1]) == 0)
|
||||
break; /* Terminate early if nothing more to service */
|
||||
}
|
||||
while (++event < event_last);
|
||||
}
|
||||
|
||||
gpio_disable_event(MC13783_EVENT_ID);
|
||||
}
|
||||
|
||||
/* GPIO interrupt handler for mc13783 */
|
||||
void mc13783_event(void)
|
||||
{
|
||||
/* Mask the interrupt (unmasked when PMIC thread services it). */
|
||||
bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||
semaphore_release(&mc13783_svc_wake);
|
||||
}
|
||||
|
||||
void INIT_ATTR mc13783_init(void)
|
||||
{
|
||||
/* Serial interface must have been initialized first! */
|
||||
semaphore_init(&mc13783_svc_wake, 1, 0);
|
||||
|
||||
/* Enable the PMIC SPI module */
|
||||
spi_enable_node(&mc13783_spi, true);
|
||||
|
||||
/* Mask any PMIC interrupts for now - modules will enable them as
|
||||
* required */
|
||||
mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff);
|
||||
mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
|
||||
|
||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||
|
||||
mc13783_thread_id =
|
||||
create_thread(mc13783_interrupt_thread,
|
||||
mc13783_thread_stack, sizeof(mc13783_thread_stack), 0,
|
||||
mc13783_thread_name IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU));
|
||||
}
|
||||
|
||||
void mc13783_close(void)
|
||||
{
|
||||
unsigned int thread_id = mc13783_thread_id;
|
||||
|
||||
if (thread_id == 0)
|
||||
return;
|
||||
|
||||
mc13783_thread_id = 0;
|
||||
semaphore_release(&mc13783_svc_wake);
|
||||
thread_wait(thread_id);
|
||||
spi_enable_node(&mc13783_spi, false);
|
||||
}
|
||||
|
||||
bool mc13783_enable_event(enum mc13783_event_ids id)
|
||||
{
|
||||
const struct mc13783_event * const event = &mc13783_events[id];
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
||||
|
||||
pmic_int_enabled[set] |= mask;
|
||||
mc13783_clear(pmic_intm_regs[set], mask);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mc13783_disable_event(enum mc13783_event_ids id)
|
||||
{
|
||||
const struct mc13783_event * const event = &mc13783_events[id];
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
||||
|
||||
pmic_int_enabled[set] &= ~mask;
|
||||
mc13783_set(pmic_intm_regs[set], mask);
|
||||
}
|
||||
static uint32_t pmic_int_enb[2]; /* Enabled ints */
|
||||
static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */
|
||||
static uint32_t int_pnd_buf[2]; /* Pending ints */
|
||||
static uint32_t int_data_buf[4]; /* ISR data buffer */
|
||||
static struct spi_transfer_desc int_xfers[2]; /* ISR transfer descriptor */
|
||||
static bool restore_event = true;
|
||||
|
||||
static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
|
||||
uint32_t *txbuf,
|
||||
|
@ -205,6 +63,146 @@ static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
|
|||
return spi_transfer(xfer);
|
||||
}
|
||||
|
||||
/* Called when a transfer is finished and data is ready/written */
|
||||
static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer)
|
||||
{
|
||||
semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema);
|
||||
}
|
||||
|
||||
static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer)
|
||||
{
|
||||
return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK)
|
||||
== OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
|
||||
}
|
||||
|
||||
/* Efficient interrupt status and acking */
|
||||
static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer)
|
||||
{
|
||||
/* Restore PMIC interrupt events */
|
||||
if (restore_event)
|
||||
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
|
||||
/* Call handlers */
|
||||
for (
|
||||
const struct mc13783_event *event = mc13783_events;
|
||||
int_pnd_buf[0] | int_pnd_buf[1];
|
||||
event++
|
||||
)
|
||||
{
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
uint32_t pnd = int_pnd_buf[set];
|
||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
||||
|
||||
if (pnd & mask)
|
||||
{
|
||||
event->callback();
|
||||
int_pnd_buf[set] = pnd & ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
(void)xfer;
|
||||
}
|
||||
|
||||
static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer)
|
||||
{
|
||||
/* Only clear interrupts with handlers */
|
||||
int_pnd_buf[0] &= pmic_int_enb[0];
|
||||
int_pnd_buf[1] &= pmic_int_enb[1];
|
||||
|
||||
/* Only read sense if enabled interrupts have them enabled */
|
||||
if ((int_pnd_buf[0] & pmic_int_sense_enb[0]) ||
|
||||
(int_pnd_buf[1] & pmic_int_sense_enb[1]))
|
||||
{
|
||||
int_data_buf[2] = MC13783_INTERRUPT_SENSE0 << 25;
|
||||
int_data_buf[3] = MC13783_INTERRUPT_SENSE1 << 25;
|
||||
int_xfers[1].rxbuf = int_data_buf;
|
||||
int_xfers[1].count = 4;
|
||||
}
|
||||
|
||||
/* Setup the write packets with status(es) to clear */
|
||||
int_data_buf[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25)
|
||||
| int_pnd_buf[0];
|
||||
int_data_buf[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25)
|
||||
| int_pnd_buf[1];
|
||||
(void)xfer;
|
||||
}
|
||||
|
||||
/* GPIO interrupt handler for mc13783 */
|
||||
void mc13783_event(void)
|
||||
{
|
||||
/* Mask the interrupt (unmasked after final read services it). */
|
||||
bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||
|
||||
/* Setup the read packets */
|
||||
int_pnd_buf[0] = MC13783_INTERRUPT_STATUS0 << 25;
|
||||
int_pnd_buf[1] = MC13783_INTERRUPT_STATUS1 << 25;
|
||||
|
||||
unsigned long cpsr = disable_irq_save();
|
||||
|
||||
/* Do these without intervening transfers */
|
||||
if (mc13783_transfer(&int_xfers[0], int_pnd_buf, int_pnd_buf, 2,
|
||||
mc13783_int_svc_callback))
|
||||
{
|
||||
/* Start this provisionally and fill-in actual values during the
|
||||
first transfer's callback - set whatever could be known */
|
||||
mc13783_transfer(&int_xfers[1], int_data_buf, NULL, 2,
|
||||
mc13783_int_svc_complete_callback);
|
||||
}
|
||||
|
||||
restore_irq(cpsr);
|
||||
}
|
||||
|
||||
void INIT_ATTR mc13783_init(void)
|
||||
{
|
||||
/* Serial interface must have been initialized first! */
|
||||
|
||||
/* Enable the PMIC SPI module */
|
||||
spi_enable_node(&mc13783_spi, true);
|
||||
|
||||
/* Mask any PMIC interrupts for now - modules will enable them as
|
||||
* required */
|
||||
mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff);
|
||||
mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
|
||||
|
||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
||||
gpio_enable_event(MC13783_EVENT_ID);
|
||||
}
|
||||
|
||||
void mc13783_close(void)
|
||||
{
|
||||
gpio_disable_event(MC13783_EVENT_ID);
|
||||
spi_enable_node(&mc13783_spi, false);
|
||||
}
|
||||
|
||||
void mc13783_enable_event(enum mc13783_event_ids id, bool enable)
|
||||
{
|
||||
static const unsigned char pmic_intm_regs[2] =
|
||||
{ MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 };
|
||||
|
||||
const struct mc13783_event * const event = &mc13783_events[id];
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
||||
|
||||
/* Mask GPIO while changing bits around */
|
||||
restore_event = false;
|
||||
bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
mc13783_write_masked(pmic_intm_regs[set],
|
||||
enable ? 0 : mask, mask);
|
||||
bitmod32(&pmic_int_enb[set], enable ? mask : 0, mask);
|
||||
bitmod32(&pmic_int_sense_enb[set], enable ? event->sense : 0,
|
||||
event->sense);
|
||||
restore_event = true;
|
||||
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
||||
}
|
||||
|
||||
uint32_t mc13783_event_sense(enum mc13783_event_ids id)
|
||||
{
|
||||
const struct mc13783_event * const event = &mc13783_events[id];
|
||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
||||
return int_data_buf[2 + set] & event->sense;
|
||||
}
|
||||
|
||||
uint32_t mc13783_set(unsigned address, uint32_t bits)
|
||||
{
|
||||
return mc13783_write_masked(address, bits, bits);
|
||||
|
|
Loading…
Reference in a new issue