Improve imx31 interrupt code for PMIC and GPIO

Fix stuff that was bugging me about the way I did it at first.

While messing around I found RDS code wasn't masking its GPIO
ISR as it should, which might lead to two different interrupts
messing with the static data.

Change-Id: I54626809ea3039a842af0cc9e3e42853326c4193
This commit is contained in:
Michael Sevakis 2017-01-28 14:43:35 -05:00
parent d4303ac900
commit 2220a4b695
19 changed files with 552 additions and 485 deletions

View file

@ -1139,10 +1139,8 @@ target/arm/imx31/uart-imx31.c
target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
target/arm/imx31/gigabeat-s/backlight-gigabeat-s.c
target/arm/imx31/gigabeat-s/button-gigabeat-s.c
target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c
target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c
target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
target/arm/imx31/gigabeat-s/power-gigabeat-s.c
target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
target/arm/imx31/gigabeat-s/system-gigabeat-s.c

View file

@ -86,12 +86,6 @@
#define AB_REPEAT_ENABLE
/* Define this if you have a SI4700 fm radio tuner */
#define CONFIG_TUNER SI4700
#define HAVE_RDS_CAP
#define RDS_ISR_PROCESSING
/* Define this if you have the WM8978 audio codec */
#define HAVE_WM8978
@ -124,6 +118,10 @@
#define HAVE_LCD_ENABLE
#ifndef BOOTLOADER
/* Define this if you have a SI4700 fm radio tuner */
#define CONFIG_TUNER SI4700
#define HAVE_RDS_CAP
#define RDS_ISR_PROCESSING
/* define this if you can flip your LCD */
#define HAVE_LCD_FLIP

View file

@ -1256,9 +1256,6 @@ enum mc13783_regs_enum
#define MC13783_TC3PERIOD_POS (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);
@ -1296,7 +1293,7 @@ enum mc13783_int_ids
MC13783_INT_ID_CHGSHORT = 9,
MC13783_INT_ID_CCCV = 10,
MC13783_INT_ID_CHGCURR = 11,
MC13783_INT_ID_BPONI = 12,
MC13783_INT_ID_BPON = 12,
MC13783_INT_ID_LOBATL = 13,
MC13783_INT_ID_LOBATH = 14,
MC13783_INT_ID_UDP = 15,
@ -1306,41 +1303,70 @@ enum mc13783_int_ids
MC13783_INT_ID_CKDET = 22,
MC13783_INT_ID_UDM = 23,
/* *STATUS1/MASK1/SENSE1 */
MC13783_INT_ID_1HZ = 0 + 0x20,
MC13783_INT_ID_TODA = 1 + 0x20,
MC13783_INT_ID_ONOFD1 = 3 + 0x20, /* ON1B */
MC13783_INT_ID_ONOFD2 = 4 + 0x20, /* ON2B */
MC13783_INT_ID_ONOFD3 = 5 + 0x20, /* ON3B */
MC13783_INT_ID_SYSRST = 6 + 0x20,
MC13783_INT_ID_RTCRST = 7 + 0x20,
MC13783_INT_ID_PCI = 8 + 0x20,
MC13783_INT_ID_WARM = 9 + 0x20,
MC13783_INT_ID_MEMHLD = 10 + 0x20,
MC13783_INT_ID_PWRRDY = 11 + 0x20,
MC13783_INT_ID_THWARNL = 12 + 0x20,
MC13783_INT_ID_THWARNH = 13 + 0x20,
MC13783_INT_ID_CLK = 14 + 0x20,
MC13783_INT_ID_SEMAF = 15 + 0x20,
MC13783_INT_ID_MC2B = 17 + 0x20,
MC13783_INT_ID_HSDET = 18 + 0x20,
MC13783_INT_ID_HSL = 19 + 0x20,
MC13783_INT_ID_ALSPTH = 20 + 0x20,
MC13783_INT_ID_AHSSHORT = 21 + 0x20,
MC13783_INT_ID_1HZ = 0 + 32,
MC13783_INT_ID_TODA = 1 + 32,
MC13783_INT_ID_ONOFD1 = 3 + 32, /* ON1B */
MC13783_INT_ID_ONOFD2 = 4 + 32, /* ON2B */
MC13783_INT_ID_ONOFD3 = 5 + 32, /* ON3B */
MC13783_INT_ID_SYSRST = 6 + 32,
MC13783_INT_ID_RTCRST = 7 + 32,
MC13783_INT_ID_PCI = 8 + 32,
MC13783_INT_ID_WARM = 9 + 32,
MC13783_INT_ID_MEMHLD = 10 + 32,
MC13783_INT_ID_PWRRDY = 11 + 32,
MC13783_INT_ID_THWARNL = 12 + 32,
MC13783_INT_ID_THWARNH = 13 + 32,
MC13783_INT_ID_CLK = 14 + 32,
MC13783_INT_ID_SEMAF = 15 + 32,
MC13783_INT_ID_MC2B = 17 + 32,
MC13783_INT_ID_HSDET = 18 + 32,
MC13783_INT_ID_HSL = 19 + 32,
MC13783_INT_ID_ALSPTH = 20 + 32,
MC13783_INT_ID_AHSSHORT = 21 + 32,
};
#define MC13783_INT_ID_SET_DIV (0x20)
#define MC13783_INT_ID_NUM_MASK (0x1f)
#ifdef DEFINE_MC13783_VECTOR_TABLE
struct mc13783_event
{
enum mc13783_int_ids int_id : 8;
uint32_t sense : 24;
void (*callback)(void);
uint32_t id : 8; /* MC13783_INT_ID_x */
uint32_t sense : 24; /* MC13783_xS */
void (*callback)(void); /* MC13783_EVENT_CB_x */
};
void mc13783_enable_event(enum mc13783_event_ids id, bool enable);
/* Declares vector table. Order-implied priority */
#define MC13783_EVENT_VECTOR_TBL_START() \
static FORCE_INLINE uintptr_t __mc13783_event_vector_tbl(int __what) \
{ \
static const struct mc13783_event __tbl[] = {
/* Read the sense bit if one exists - valid only within event handlers */
uint32_t mc13783_event_sense(enum mc13783_event_ids id);
#define MC13783_EVENT_VECTOR(__name, __sense) \
{ .id = MC13783_INT_ID_##__name, \
.sense = (__sense), \
.callback = ({ void MC13783_EVENT_CB_##__name(void); \
MC13783_EVENT_CB_##__name; }) },
#define MC13783_EVENT_VECTOR_TBL_END() \
}; \
switch (__what) \
{ \
default: return (uintptr_t)__tbl; \
case 1: return (uintptr_t)ARRAYLEN(__tbl); \
} \
}
#define mc13783_event_vector_tbl \
((const struct mc13783_event *)__mc13783_event_vector_tbl(0))
#define mc13783_event_vector_tbl_len \
((unsigned int)__mc13783_event_vector_tbl(1))
#endif /* DEFINE_MC13783_VECTOR_TABLE */
void mc13783_enable_event(enum mc13783_int_ids id, bool enable);
/* Read the sense bit(s) if configured - valid only within the respective
event handler */
uint32_t mc13783_event_sense(void);
#endif /* _MC13783_H_ */

View file

@ -111,7 +111,7 @@ bool adc_enable_channel(int channel, bool enable)
}
/* ADC conversion complete event - called from PMIC ISR */
void adc_done(void)
void MC13783_EVENT_CB_ADCDONE(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, true);
mc13783_enable_event(MC13783_INT_ID_ADCDONE, true);
}

View file

@ -46,7 +46,6 @@
#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
#define ADC_READ_ERROR 0xFFFF
void adc_done(void);
/* Enable conversion of specified channel (if switchoff is possible) */
bool adc_enable_channel(int channel, bool enable);

View file

@ -157,9 +157,9 @@ static void power_button_update(bool pressed)
}
/* Power button event - called from PMIC ISR */
void button_power_event(void)
void MC13783_EVENT_CB_ONOFD1(void)
{
power_button_update(!mc13783_event_sense(MC13783_ONOFD1_EVENT));
power_button_update(!mc13783_event_sense());
}
void button_init_device(void)
@ -197,7 +197,7 @@ void button_init_device(void)
power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1)
& MC13783_ONOFD1S));
mc13783_enable_event(MC13783_ONOFD1_EVENT, true);
mc13783_enable_event(MC13783_INT_ID_ONOFD1, true);
#ifdef HAVE_HEADPHONE_DETECTION
headphone_init();
@ -213,7 +213,7 @@ void button_close_device(void)
/* Assumes HP detection is not available */
initialized = false;
mc13783_enable_event(MC13783_ONOFD1_EVENT, false);
mc13783_enable_event(MC13783_INT_ID_ONOFD1, false);
ext_btn = BUTTON_NONE;
}
#endif /* BUTTON_DRIVER_CLOSE */

View file

@ -30,8 +30,6 @@
#endif
void button_close_device(void);
void button_power_event(void);
void headphone_detect_event(void);
void headphone_init(void);
void button_headphone_set(int button);

View file

@ -26,7 +26,7 @@
#include "thread.h"
#include "mc13783.h"
#include "iomuxc-imx31.h"
#include "gpio-imx31.h"
#include "gpio-target.h"
#include "i2c-imx31.h"
#include "fmradio_i2c.h"
#include "rds.h"
@ -139,20 +139,25 @@ static struct si4700_i2c_transfer_desc
.xfer = { .node = &si4700_i2c_node }
};
static bool int_restore;
static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
{
struct si4700_i2c_transfer_desc *xf =
(struct si4700_i2c_transfer_desc *)xfer;
if (xfer->rxcount != 0)
return; /* Read didn't finish */
if (xfer->rxcount == 0)
{
uint16_t rds_data[4];
si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
uint16_t rds_data[4];
if (rds_process(rds_data))
si4700_rds_set_event();
}
/* else read didn't finish */
si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
if (rds_process(rds_data))
si4700_rds_set_event();
if (int_restore)
gpio_int_enable(SI4700_EVENT_ID);
}
/* Callback from si4700_rds_read_raw to execute the read */
@ -169,10 +174,13 @@ void si4700_read_raw_async(int count)
}
/* RDS GPIO interrupt handler - start RDS data read */
void si4700_stc_rds_event(void)
void INT_SI4700_RDS(void)
{
/* read and clear the interrupt */
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
/* mask and clear the interrupt */
gpio_int_disable(SI4700_EVENT_ID);
gpio_int_clear(SI4700_EVENT_ID);
/* read the RDS data */
si4700_rds_read_raw_async();
}
@ -180,13 +188,10 @@ void si4700_stc_rds_event(void)
powering down */
void si4700_rds_powerup(bool on)
{
gpio_disable_event(SI4700_STC_RDS_EVENT_ID);
if (on)
{
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
gpio_enable_event(SI4700_STC_RDS_EVENT_ID);
}
int_restore = on;
gpio_int_disable(SI4700_EVENT_ID);
gpio_int_clear(SI4700_EVENT_ID);
gpio_enable_event(SI4700_EVENT_ID, on);
}
/* One-time RDS init at startup */

View file

@ -1,52 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (c) 2008 by Michael Sevakis
*
* Gigabeat S GPIO interrupt event descriptions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 "avic-imx31.h"
#include "gpio-imx31.h"
/* Gigabeat S definitions for static GPIO event registration */
/* Describes single events for each GPIO1 pin */
const struct gpio_event gpio1_events[] =
{
/* mc13783 keeps the PRIINT high (no low pulse) if other unmasked
* interrupts become active when clearing them or if a source being
* cleared becomes active at that time. Edge-detection will not get
* a rising edge in that case so use high-level sense. */
[MC13783_EVENT_ID-GPIO1_EVENT_FIRST] =
{
.mask = 1 << MC13783_GPIO_LINE,
.sense = GPIO_SENSE_HIGH_LEVEL,
.callback = mc13783_event,
},
#ifndef BOOTLOADER
/* Generates a 5ms low pulse on the line - detect the falling edge */
[SI4700_STC_RDS_EVENT_ID] =
{
.mask = 1 << SI4700_GPIO_STC_RDS_LINE,
.sense = GPIO_SENSE_FALLING,
.callback = si4700_stc_rds_event,
},
#endif
};

View file

@ -23,34 +23,33 @@
#ifndef GPIO_TARGET_H
#define GPIO_TARGET_H
/* MC13783 GPIO pin info for this target */
#define MC13783_GPIO_IMR GPIO1_IMR
#define MC13783_GPIO_NUM GPIO1_NUM
#define MC13783_GPIO_ISR GPIO1_ISR
#define MC13783_GPIO_LINE 31
/* Gigabeat S definitions for static GPIO event registration */
#include "gpio-imx31.h"
/* SI4700 GPIO STC/RDS pin info for this target */
#define SI4700_GPIO_STC_RDS_IMR GPIO1_IMR
#define SI4700_GPIO_STC_RDS_NUM GPIO1_NUM
#define SI4700_GPIO_STC_RDS_ISR GPIO1_ISR
#define SI4700_GPIO_STC_RDS_LINE 27
#ifdef DEFINE_GPIO_VECTOR_TABLE
GPIO_VECTOR_TBL_START()
/* mc13783 keeps the PRIINT high (no low pulse) if other unmasked
* interrupts become active when clearing them or if a source being
* cleared becomes active at that time. Edge-detection will not get
* a rising edge in that case so use high-level sense. */
GPIO_EVENT_VECTOR(GPIO1_31, GPIO_SENSE_HIGH_LEVEL)
#if CONFIG_TUNER
/* Generates a 5ms low pulse on the line - detect the falling edge */
GPIO_EVENT_VECTOR(GPIO1_27, GPIO_SENSE_FALLING)
#endif /* CONFIG_TUNER */
GPIO_VECTOR_TBL_END()
#define GPIO1_INT_PRIO INT_PRIO_DEFAULT
/* Declare event indexes in priority order in a packed array */
enum gpio_event_ids
{
/* GPIO1 event IDs */
MC13783_EVENT_ID = GPIO1_EVENT_FIRST,
SI4700_STC_RDS_EVENT_ID,
GPIO1_NUM_EVENTS = 2,
/* GPIO2 event IDs */
/* none defined */
/* GPIO3 event IDs */
/* none defined */
};
#endif /* DEFINE_GPIO_VECTOR_TABLE */
void mc13783_event(void);
void si4700_stc_rds_event(void);
#define INT_MC13783 GPIO1_31_EVENT_CB
#define MC13783_EVENT_ID GPIO1_31_ID
#if CONFIG_TUNER
#define INT_SI4700_RDS GPIO1_27_EVENT_CB
#define SI4700_EVENT_ID GPIO1_27_ID
#endif /* CONFIG_TUNER */
#endif /* GPIO_TARGET_H */

View file

@ -25,7 +25,6 @@
#include "kernel.h"
#include "thread.h"
#include "mc13783.h"
#include "mc13783-target.h"
#include "adc.h"
#include "button.h"
@ -146,7 +145,7 @@ static void NORETURN_ATTR headphone_thread(void)
}
/* HP plugged/unplugged event - called from PMIC ISR */
void headphone_detect_event(void)
void MC13783_EVENT_CB_ONOFD2(void)
{
/* Trigger the thread immediately. */
semaphore_release(&headphone_wakeup);
@ -170,5 +169,5 @@ void INIT_ATTR headphone_init(void)
IF_COP(, CPU));
/* Enable PMIC event */
mc13783_enable_event(MC13783_ONOFD2_EVENT, true);
mc13783_enable_event(MC13783_INT_ID_ONOFD2, true);
}

View file

@ -1,86 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (c) 2008 by Michael Sevakis
*
* Gigabeat S MC13783 event descriptions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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 "spi-imx31.h"
#include "mc13783.h"
#include "mc13783-target.h"
#include "adc-target.h"
#include "button-target.h"
#include "power-gigabeat-s.h"
#include "powermgmt-target.h"
/* Gigabeat S mc13783 serial interface node. */
struct spi_node mc13783_spi =
{
/* Based upon original firmware settings */
CSPI2_NUM, /* CSPI module 2 */
CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */
CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
CSPI_CONREG_SSPOL | /* SS active high */
CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */
CSPI_CONREG_MODE, /* Master mode */
0, /* SPI clock - no wait states */
};
/* Gigabeat S definitions for static MC13783 event registration */
const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS] =
{
[MC13783_ADCDONE_EVENT] = /* ADC conversion complete */
{
.int_id = MC13783_INT_ID_ADCDONE,
.sense = 0,
.callback = adc_done,
},
[MC13783_ONOFD1_EVENT] = /* Power button */
{
.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,
.sense = MC13783_SE1S,
.callback = charger_main_detect_event,
},
[MC13783_USB_EVENT] = /* USB insertion/USB charger detection */
{
.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,
.sense = 0,
.callback = headphone_detect_event,
},
#endif
};

View file

@ -23,17 +23,41 @@
#ifndef MC13783_TARGET_H
#define MC13783_TARGET_H
/* Declare event indexes in priority order in a packed array */
enum mc13783_event_ids
#include "mc13783.h"
#ifdef DEFINE_MC13783_VECTOR_TABLE
/* Gigabeat S mc13783 serial interface node. */
static struct spi_node mc13783_spi =
{
MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */
MC13783_ONOFD1_EVENT, /* Power button */
#ifdef HAVE_HEADPHONE_DETECTION
MC13783_ONOFD2_EVENT, /* Headphone jack */
#endif
MC13783_SE1_EVENT, /* Main charger detection */
MC13783_USB_EVENT, /* USB insertion */
MC13783_NUM_EVENTS,
/* Based upon original firmware settings */
CSPI2_NUM, /* CSPI module 2 */
CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */
CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
CSPI_CONREG_SSPOL | /* SS active high */
CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */
CSPI_CONREG_MODE, /* Master mode */
0, /* SPI clock - no wait states */
};
/* Gigabeat S definitions for static MC13783 event registration */
MC13783_EVENT_VECTOR_TBL_START()
/* ADC conversion complete */
MC13783_EVENT_VECTOR(ADCDONE, 0)
/* Power button */
MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S)
/* Main charger detection */
MC13783_EVENT_VECTOR(SE1, MC13783_SE1S)
/* USB insertion/USB charger detection */
MC13783_EVENT_VECTOR(USB, MC13783_USB4V4S)
#ifdef HAVE_HEADPHONE_DETECTION
/* Headphone jack */
MC13783_EVENT_VECTOR(ONOFD2, 0)
#endif /* HAVE_HEADPHONE_DETECTION */
MC13783_EVENT_VECTOR_TBL_END()
#endif /* DEFINE_MC13783_VECTOR_TABLE */
#endif /* MC13783_TARGET_H */

View file

@ -66,9 +66,9 @@ static void update_main_charger(bool present)
}
/* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */
void charger_main_detect_event(void)
void MC13783_EVENT_CB_SE1(void)
{
update_main_charger(mc13783_event_sense(MC13783_SE1_EVENT));
update_main_charger(mc13783_event_sense());
}
/* Detect changes in USB bus power. Called from usb connect event ISR. */
@ -159,5 +159,5 @@ void power_init(void)
& MC13783_SE1S);
/* Enable detect event */
mc13783_enable_event(MC13783_SE1_EVENT, true);
mc13783_enable_event(MC13783_INT_ID_SE1, true);
}

View file

@ -21,7 +21,6 @@
#ifndef POWER_IMX31_H
#define POWER_IMX31_H
void charger_main_detect_event(void);
void charger_usb_detect_event(int status);
#endif /* POWER_IMX31_H */

View file

@ -70,10 +70,10 @@ static void update_usb_status(bool sense)
}
/* Detect presence of USB bus - called from PMIC ISR */
void usb_connect_event(void)
void MC13783_EVENT_CB_USB(void)
{
/* Read the associated sense value */
update_usb_status(mc13783_event_sense(MC13783_USB_EVENT));
update_usb_status(mc13783_event_sense());
}
int usb_detect(void)
@ -90,7 +90,7 @@ void usb_init_device(void)
update_usb_status(usb_plugged());
/* Enable PMIC event */
mc13783_enable_event(MC13783_USB_EVENT, true);
mc13783_enable_event(MC13783_INT_ID_USB, true);
}
void usb_enable(bool on)

View file

@ -23,7 +23,8 @@
#include "config.h"
#include "system.h"
#include "avic-imx31.h"
#include "gpio-imx31.h"
#define DEFINE_GPIO_VECTOR_TABLE
#include "gpio-target.h"
/* UIE vector found in avic-imx31.c */
extern void UIE_VECTOR(void);
@ -31,101 +32,91 @@ extern void UIE_VECTOR(void);
/* Event lists are allocated for the specific target */
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS];
#endif
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS];
#endif
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS];
#endif
#define DR (0x00 / sizeof (unsigned long)) /* 00h */
#define GDIR (0x04 / sizeof (unsigned long)) /* 04h */
#define PSR (0x08 / sizeof (unsigned long)) /* 08h */
#define ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
#define IMR (0x14 / sizeof (unsigned long)) /* 14h */
#define ISR (0x18 / sizeof (unsigned long))
static const struct gpio_module_desc
static struct gpio_module_desc
{
volatile unsigned long * const base; /* Module base address */
void (* const handler)(void); /* Interrupt function */
const struct gpio_event * const events; /* Event handler list */
const struct gpio_event *events; /* Event handler list */
unsigned long enabled; /* Enabled event mask */
const uint8_t ints; /* AVIC int number */
const uint8_t int_priority; /* AVIC int priority */
const uint8_t count; /* Number of events */
} gpio_descs[GPIO_NUM_GPIO] =
uint8_t count; /* Number of events */
} * const gpio_descs[] =
{
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
{
[GPIO1_NUM] = &(struct gpio_module_desc) {
.base = (unsigned long *)GPIO1_BASE_ADDR,
.ints = INT_GPIO1,
.handler = GPIO1_HANDLER,
.events = gpio1_events,
.count = GPIO1_NUM_EVENTS,
.int_priority = GPIO1_INT_PRIO
},
#endif
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
{
[GPIO2_NUM] = &(struct gpio_module_desc) {
.base = (unsigned long *)GPIO2_BASE_ADDR,
.ints = INT_GPIO2,
.handler = GPIO2_HANDLER,
.events = gpio2_events,
.count = GPIO2_NUM_EVENTS,
.int_priority = GPIO2_INT_PRIO
},
#endif
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
{
[GPIO3_NUM] = &(struct gpio_module_desc) {
.base = (unsigned long *)GPIO3_BASE_ADDR,
.ints = INT_GPIO3,
.handler = GPIO3_HANDLER,
.events = gpio3_events,
.count = GPIO3_NUM_EVENTS,
.int_priority = GPIO3_INT_PRIO,
},
#endif
};
#define GPIO_MODULE_CNT ARRAYLEN(gpio_descs)
static const struct gpio_event * event_from_id(
const struct gpio_module_desc *desc, enum gpio_id id)
{
const struct gpio_event *events = desc->events;
for (unsigned int i = 0; i < desc->count; i++)
{
if (events[i].id == id)
return &events[i];
}
return NULL;
}
static void gpio_call_events(enum gpio_module_number gpio)
{
const struct gpio_module_desc * const desc = &gpio_descs[gpio];
const struct gpio_module_desc * const desc = gpio_descs[gpio];
volatile unsigned long * const base = desc->base;
const struct gpio_event * event, *event_last;
event = desc->events;
event_last = event + desc->count;
/* Send only events that are not masked */
unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR];
/* Intersect pending and unmasked bits */
unsigned long pnd = base[ISR] & base[IMR];
if (pnd & ~desc->enabled)
UIE_VECTOR(); /* One or more aren't handled properly */
/* Call each event handler in order */
/* .count is surely expected to be > 0 */
do
const struct gpio_event *event = desc->events;
while (pnd)
{
unsigned long mask = event->mask;
unsigned long mask = 1ul << (event->id % 32);
if (pnd & mask)
{
event->callback();
pnd &= ~mask;
}
if (pnd == 0)
break; /* Teminate early if nothing more to service */
}
while (++event < event_last);
if (pnd != 0)
{
/* One or more weren't handled */
UIE_VECTOR();
event++;
}
}
@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
void INIT_ATTR gpio_init(void)
{
/* Mask-out GPIO interrupts - enable what's wanted later */
int i;
for (i = 0; i < GPIO_NUM_GPIO; i++)
gpio_descs[i].base[IMR] = 0;
for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++)
{
struct gpio_module_desc * const desc = gpio_descs[mod];
if (!desc)
continue;
/* Parse the event table per module. First contiguous run seen for a
* module is used. */
const struct gpio_event *event = gpio_event_vector_tbl;
for (unsigned int i = 0; i < gpio_event_vector_tbl_len; i++, event++)
{
if (event->id / 32 == mod)
{
desc->events = event;
while (++desc->count < 32 && (++event)->id / 32 == mod);
break;
}
}
/* Mask-out GPIO interrupts - enable what's wanted later */
desc->base[GPIO_IMR] = 0;
}
}
bool gpio_enable_event(enum gpio_event_ids id)
bool gpio_enable_event(enum gpio_id id, bool enable)
{
const struct gpio_module_desc * const desc = &gpio_descs[id >> 5];
const struct gpio_event * const event = &desc->events[id & 31];
unsigned int mod = id / 32;
struct gpio_module_desc * const desc = gpio_descs[mod];
if (mod >= GPIO_MODULE_CNT || desc == NULL)
return false;
const struct gpio_event * const event = event_from_id(desc, id);
if (!event)
return false;
volatile unsigned long * const base = desc->base;
volatile unsigned long *icr;
unsigned long mask, line;
unsigned long imr;
int shift;
unsigned long num = id % 32;
unsigned long mask = 1ul << num;
int oldlevel = disable_irq_save();
unsigned long cpsr = disable_irq_save();
imr = base[IMR];
unsigned long imr = base[GPIO_IMR];
if (imr == 0)
if (enable)
{
/* First enabled interrupt for this GPIO */
avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
desc->handler);
if (desc->enabled == 0)
{
/* First enabled interrupt for this GPIO */
avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
desc->handler);
}
/* Set the line sense */
if (event->sense == GPIO_SENSE_EDGE_SEL)
{
/* Interrupt configuration register is ignored */
base[GPIO_EDGE_SEL] |= mask;
}
else
{
volatile unsigned long *icrp = &base[GPIO_ICR + num / 16];
unsigned int shift = 2*(num % 16);
bitmod32(icrp, event->sense << shift, 0x3 << shift);
base[GPIO_EDGE_SEL] &= ~mask;
}
/* Unmask the line */
desc->enabled |= mask;
imr |= mask;
}
else
{
imr &= ~mask;
desc->enabled &= ~mask;
if (desc->enabled == 0)
avic_disable_int(desc->ints); /* No events remain enabled */
}
/* Set the line sense */
line = find_first_set_bit(event->mask);
icr = &base[ICR + (line >> 4)];
shift = 2*(line & 15);
mask = GPIO_SENSE_CONFIG_MASK << shift;
base[GPIO_IMR] = imr;
*icr = (*icr & ~mask) | ((event->sense << shift) & mask);
/* Unmask the line */
base[IMR] = imr | event->mask;
restore_irq(oldlevel);
restore_irq(cpsr);
return true;
}
void gpio_disable_event(enum gpio_event_ids id)
{
const struct gpio_module_desc * const desc = &gpio_descs[id >> 5];
const struct gpio_event * const event = &desc->events[id & 31];
volatile unsigned long * const base = desc->base;
unsigned long imr;
int oldlevel = disable_irq_save();
/* Remove bit from mask */
imr = base[IMR] & ~event->mask;
/* Mask the line */
base[IMR] = imr;
if (imr == 0)
{
/* No events remain enabled */
avic_disable_int(desc->ints);
}
restore_irq(oldlevel);
}

View file

@ -26,62 +26,193 @@
#define USE_GPIO2_EVENTS (1 << 1)
#define USE_GPIO3_EVENTS (1 << 2)
/* Module indexes defined by which GPIO modules are used */
/* Module logical indexes */
enum gpio_module_number
{
__GPIO_NUM_START = -1,
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
GPIO1_NUM,
#endif
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
GPIO2_NUM,
#endif
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
GPIO3_NUM,
#endif
GPIO1_NUM, /* ID 0..31 */
GPIO2_NUM, /* ID 32..63 */
GPIO3_NUM, /* ID 64..95 */
GPIO_NUM_GPIO,
};
/* Possible values for gpio interrupt line config */
enum gpio_int_sense_enum
enum gpio_id
{
GPIO_SENSE_LOW_LEVEL = 0, /* High-level sensitive */
GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
GPIO_SENSE_RISING, /* Rising-edge sensitive */
GPIO_SENSE_FALLING, /* Falling-edge sensitive */
/* GPIO1 */
GPIO1_0_ID = 0,
GPIO1_1_ID,
GPIO1_2_ID,
GPIO1_3_ID,
GPIO1_4_ID,
GPIO1_5_ID,
GPIO1_6_ID,
GPIO1_7_ID,
GPIO1_8_ID,
GPIO1_9_ID,
GPIO1_10_ID,
GPIO1_11_ID,
GPIO1_12_ID,
GPIO1_13_ID,
GPIO1_14_ID,
GPIO1_15_ID,
GPIO1_16_ID,
GPIO1_17_ID,
GPIO1_18_ID,
GPIO1_19_ID,
GPIO1_20_ID,
GPIO1_21_ID,
GPIO1_22_ID,
GPIO1_23_ID,
GPIO1_24_ID,
GPIO1_25_ID,
GPIO1_26_ID,
GPIO1_27_ID,
GPIO1_28_ID,
GPIO1_29_ID,
GPIO1_30_ID,
GPIO1_31_ID,
/* GPIO2 */
GPIO2_0_ID = 32,
GPIO2_1_ID,
GPIO2_2_ID,
GPIO2_3_ID,
GPIO2_4_ID,
GPIO2_5_ID,
GPIO2_6_ID,
GPIO2_7_ID,
GPIO2_8_ID,
GPIO2_9_ID,
GPIO2_10_ID,
GPIO2_11_ID,
GPIO2_12_ID,
GPIO2_13_ID,
GPIO2_14_ID,
GPIO2_15_ID,
GPIO2_16_ID,
GPIO2_17_ID,
GPIO2_18_ID,
GPIO2_19_ID,
GPIO2_20_ID,
GPIO2_21_ID,
GPIO2_22_ID,
GPIO2_23_ID,
GPIO2_24_ID,
GPIO2_25_ID,
GPIO2_26_ID,
GPIO2_27_ID,
GPIO2_28_ID,
GPIO2_29_ID,
GPIO2_30_ID,
GPIO2_31_ID,
/* GPIO3 */
GPIO3_0_ID = 64,
GPIO3_1_ID,
GPIO3_2_ID,
GPIO3_3_ID,
GPIO3_4_ID,
GPIO3_5_ID,
GPIO3_6_ID,
GPIO3_7_ID,
GPIO3_8_ID,
GPIO3_9_ID,
GPIO3_10_ID,
GPIO3_11_ID,
GPIO3_12_ID,
GPIO3_13_ID,
GPIO3_14_ID,
GPIO3_15_ID,
GPIO3_16_ID,
GPIO3_17_ID,
GPIO3_18_ID,
GPIO3_19_ID,
GPIO3_20_ID,
GPIO3_21_ID,
GPIO3_22_ID,
GPIO3_23_ID,
GPIO3_24_ID,
GPIO3_25_ID,
GPIO3_26_ID,
GPIO3_27_ID,
GPIO3_28_ID,
GPIO3_29_ID,
GPIO3_30_ID,
GPIO3_31_ID,
};
#define GPIO_SENSE_CONFIG_MASK 0x3
/* Possible values for gpio interrupt line config */
enum gpio_int_sense
{
GPIO_SENSE_LOW_LEVEL, /* High-level sensitive */
GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
GPIO_SENSE_RISING, /* Rising-edge sensitive */
GPIO_SENSE_FALLING, /* Falling-edge sensitive */
GPIO_SENSE_EDGE_SEL, /* Detect any edge */
};
/* Pending events will be called in array order which allows easy
* pioritization */
/* Handlers will be called in declared order for a given module
Handlers of same module should be grouped together; module order
doesn't matter */
#ifdef DEFINE_GPIO_VECTOR_TABLE
/* Describes a single event for a pin */
struct gpio_event
{
unsigned long mask; /* mask: 1 << (0...31) */
enum gpio_int_sense_enum sense; /* Type of sense */
void (*callback)(void); /* Callback function */
uint8_t id; /* GPIOx_y_ID */
uint8_t sense; /* GPIO_SENSE_x */
void (*callback)(void); /* GPIOx_y_EVENT_CB */
};
/* 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
};
#define GPIO_VECTOR_TBL_START() \
static FORCE_INLINE uintptr_t __gpio_event_vector_tbl(int __what) \
{ \
static const struct gpio_event __tbl[] = {
#include "gpio-target.h"
#define GPIO_EVENT_VECTOR(__name, __sense) \
{ .id = (__name##_ID), \
.sense = (__sense), \
.callback = ({ void __name##_EVENT_CB(void); \
__name##_EVENT_CB; }) },
#define GPIO_VECTOR_TBL_END() \
}; \
switch (__what) \
{ \
default: return (uintptr_t)__tbl; \
case 1: return (uintptr_t)ARRAYLEN(__tbl); \
} \
}
#define gpio_event_vector_tbl \
((const struct gpio_event *)__gpio_event_vector_tbl(0))
#define gpio_event_vector_tbl_len \
((unsigned int)__gpio_event_vector_tbl(1))
#endif /* DEFINE_GPIO_VECTOR_TABLE */
#define GPIO_BASE_ADDR \
(volatile unsigned long * const [GPIO_NUM_GPIO]) { \
(volatile unsigned long *)GPIO1_BASE_ADDR, \
(volatile unsigned long *)GPIO2_BASE_ADDR, \
(volatile unsigned long *)GPIO3_BASE_ADDR }
#define GPIO_DR (0x00 / sizeof (unsigned long)) /* 00h */
#define GPIO_GDIR (0x04 / sizeof (unsigned long)) /* 04h */
#define GPIO_PSR (0x08 / sizeof (unsigned long)) /* 08h */
#define GPIO_ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
#define GPIO_IMR (0x14 / sizeof (unsigned long)) /* 14h */
#define GPIO_ISR (0x18 / sizeof (unsigned long)) /* 18h */
#define GPIO_EDGE_SEL (0x1C / sizeof (unsigned long)) /* 1Ch */
void gpio_init(void);
bool gpio_enable_event(enum gpio_event_ids id);
void gpio_disable_event(enum gpio_event_ids id);
bool gpio_enable_event(enum gpio_id id, bool enable);
static FORCE_INLINE void gpio_int_clear(enum gpio_id id)
{ GPIO_BASE_ADDR[id / 32][GPIO_ISR] = 1ul << (id % 32); }
static FORCE_INLINE void gpio_int_enable(enum gpio_id id)
{ bitset32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }
static FORCE_INLINE void gpio_int_disable(enum gpio_id id)
{ bitclr32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }
#endif /* GPIO_IMX31_H */

View file

@ -20,9 +20,9 @@
****************************************************************************/
#include "system.h"
#include "cpu.h"
#include "gpio-imx31.h"
#include "mc13783.h"
#define DEFINE_MC13783_VECTOR_TABLE
#include "mc13783-target.h"
#include "gpio-target.h"
#include "debug.h"
#include "kernel.h"
@ -32,21 +32,42 @@ struct mc13783_transfer_desc
struct spi_transfer_desc xfer;
union
{
/* Pick _either_ data or semaphore */
struct semaphore sema;
uint32_t data;
uint32_t data[4];
};
};
extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS];
extern struct spi_node mc13783_spi;
static uint32_t pmic_int_enb[2]; /* Enabled ints */
static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */
static struct mc13783_transfer_desc int_xfers[2]; /* ISR transfer descriptor */
static const struct mc13783_event *current_event; /* Current event in callback */
static bool int_restore; /* Prevent SPI callback from
unmasking GPIO interrupt
(lockout) */
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; /* Protect SPI callback from unmasking GPIO
interrupt (lockout) */
static const struct mc13783_event * event_from_id(enum mc13783_int_ids id)
{
for (unsigned int i = 0; i < mc13783_event_vector_tbl_len; i++)
{
if (mc13783_event_vector_tbl[i].id == id)
return &mc13783_event_vector_tbl[i];
}
return NULL;
}
/* 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;
}
static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
uint32_t *txbuf,
@ -64,90 +85,96 @@ 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)
static inline void sync_transfer_init(struct mc13783_transfer_desc *xfer)
{
semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema);
semaphore_init(&xfer->sema, 1, 0);
}
static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer)
static inline bool mc13783_sync_transfer(struct mc13783_transfer_desc *xfer,
uint32_t *txbuf,
uint32_t *rxbuf,
int count)
{
return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK)
== OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
sync_transfer_init(xfer);
return mc13783_transfer(&xfer->xfer, txbuf, rxbuf, count, mc13783_xfer_complete_cb);
}
/* Efficient interrupt status and acking */
static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer)
{
struct mc13783_transfer_desc *desc1 = (struct mc13783_transfer_desc *)xfer;
uint32_t pnd0 = desc1->data[0], pnd1 = desc1->data[1];
/* Restore PMIC interrupt events */
if (restore_event)
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
if (int_restore)
gpio_int_enable(MC13783_EVENT_ID);
/* Call handlers */
for (
const struct mc13783_event *event = mc13783_events;
int_pnd_buf[0] | int_pnd_buf[1];
event++
)
const struct mc13783_event *event = mc13783_event_vector_tbl;
while (pnd0 | pnd1)
{
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);
uint32_t id = event->id;
uint32_t set = id / 32;
uint32_t bit = 1 << (id % 32);
if (pnd & mask)
uint32_t pnd = set == 0 ? pnd0 : pnd1;
if (pnd & bit)
{
current_event = event;
event->callback();
int_pnd_buf[set] = pnd & ~mask;
set == 0 ? (pnd0 &= ~bit) : (pnd1 &= ~bit);
}
}
(void)xfer;
event++;
}
}
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];
struct mc13783_transfer_desc *desc0 = (struct mc13783_transfer_desc *)xfer;
struct mc13783_transfer_desc *desc1 = &int_xfers[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;
}
uint32_t pnd0 = desc0->data[0] & pmic_int_enb[0];
uint32_t pnd1 = desc0->data[1] & pmic_int_enb[1];
desc1->data[0] = pnd0;
desc1->data[1] = pnd1;
/* 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;
desc0->data[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) | pnd0;
desc0->data[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) | pnd1;
/* Only read sense if any pending interrupts have them enabled */
if ((pnd0 & pmic_int_sense_enb[0]) || (pnd1 & pmic_int_sense_enb[1]))
{
desc0->data[2] = MC13783_INTERRUPT_SENSE0 << 25;
desc0->data[3] = MC13783_INTERRUPT_SENSE1 << 25;
desc1->xfer.rxbuf = desc0->data;
desc1->xfer.count = 4;
}
}
/* GPIO interrupt handler for mc13783 */
void mc13783_event(void)
void INT_MC13783(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);
gpio_int_disable(MC13783_EVENT_ID);
gpio_int_clear(MC13783_EVENT_ID);
/* Setup the read packets */
int_pnd_buf[0] = MC13783_INTERRUPT_STATUS0 << 25;
int_pnd_buf[1] = MC13783_INTERRUPT_STATUS1 << 25;
int_xfers[0].data[0] = MC13783_INTERRUPT_STATUS0 << 25;
int_xfers[0].data[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))
if (mc13783_transfer(&int_xfers[0].xfer, int_xfers[0].data,
int_xfers[0].data, 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_transfer(&int_xfers[1].xfer, int_xfers[0].data, NULL, 2,
mc13783_int_svc_complete_callback);
}
@ -166,43 +193,45 @@ void INIT_ATTR mc13783_init(void)
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);
gpio_int_clear(MC13783_EVENT_ID);
gpio_enable_event(MC13783_EVENT_ID, true);
}
void mc13783_close(void)
{
restore_event = false;
gpio_disable_event(MC13783_EVENT_ID);
int_restore = false;
gpio_int_disable(MC13783_EVENT_ID);
gpio_enable_event(MC13783_EVENT_ID, false);
spi_enable_node(&mc13783_spi, false);
}
void mc13783_enable_event(enum mc13783_event_ids id, bool enable)
void mc13783_enable_event(enum mc13783_int_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);
const struct mc13783_event * const event = event_from_id(id);
if (event == NULL)
return;
unsigned int set = id / 32;
uint32_t mask = 1 << (id % 32);
uint32_t bit = enable ? mask : 0;
/* 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);
int_restore = false;
gpio_int_disable(MC13783_EVENT_ID);
mc13783_write_masked(pmic_intm_regs[set], bit ^ mask, mask);
bitmod32(&pmic_int_sense_enb[set], event->sense ? bit : 0, mask);
bitmod32(&pmic_int_enb[set], bit, mask);
int_restore = true;
gpio_int_enable(MC13783_EVENT_ID);
}
uint32_t mc13783_event_sense(enum mc13783_event_ids id)
uint32_t mc13783_event_sense(void)
{
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;
const struct mc13783_event *event = current_event;
return int_xfers[0].data[2 + event->id / 32] & event->sense;
}
uint32_t mc13783_set(unsigned address, uint32_t bits)
@ -219,8 +248,7 @@ uint32_t mc13783_clear(unsigned address, uint32_t bits)
static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer)
{
struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer;
uint32_t *packets = desc->xfer.rxbuf; /* Will have been advanced by 1 */
packets[0] |= packets[-1] & ~desc->data;
desc->data[1] |= desc->data[0] & desc->data[2]; /* & ~mask */
}
uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask)
@ -230,28 +258,23 @@ uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask)
mask &= 0xffffff;
uint32_t packets[2] =
{
address << 25,
(1 << 31) | (address << 25) | (data & mask)
};
struct mc13783_transfer_desc xfers[2];
xfers[0].data = mask;
semaphore_init(&xfers[1].sema, 1, 0);
xfers[0].data[0] = address << 25;
xfers[0].data[1] = (1 << 31) | (address << 25) | (data & mask);
xfers[0].data[2] = ~mask;
unsigned long cpsr = disable_irq_save();
/* Queue up two transfers in a row */
bool ok = mc13783_transfer(&xfers[0].xfer, &packets[0], &packets[0], 1,
bool ok = mc13783_transfer(&xfers[0].xfer,
&xfers[0].data[0], &xfers[0].data[0], 1,
mc13783_write_masked_cb) &&
mc13783_transfer(&xfers[1].xfer, &packets[1], NULL, 1,
mc13783_xfer_complete_cb);
mc13783_sync_transfer(&xfers[1], &xfers[0].data[1], NULL, 1);
restore_irq(cpsr);
if (ok && wait_for_transfer_complete(&xfers[1]))
return packets[0];
return xfers[0].data[0];
return MC13783_DATA_ERROR;
}
@ -264,10 +287,7 @@ uint32_t mc13783_read(unsigned address)
uint32_t packet = address << 25;
struct mc13783_transfer_desc xfer;
semaphore_init(&xfer.sema, 1, 0);
if (mc13783_transfer(&xfer.xfer, &packet, &packet, 1,
mc13783_xfer_complete_cb) &&
if (mc13783_sync_transfer(&xfer, &packet, &packet, 1) &&
wait_for_transfer_complete(&xfer))
{
return packet;
@ -284,10 +304,7 @@ int mc13783_write(unsigned address, uint32_t data)
uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff);
struct mc13783_transfer_desc xfer;
semaphore_init(&xfer.sema, 1, 0);
if (mc13783_transfer(&xfer.xfer, &packet, NULL, 1,
mc13783_xfer_complete_cb) &&
if (mc13783_sync_transfer(&xfer, &packet, NULL, 1) &&
wait_for_transfer_complete(&xfer))
{
return 1 - xfer.xfer.count;
@ -300,7 +317,7 @@ int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer,
int count)
{
struct mc13783_transfer_desc xfer;
semaphore_init(&xfer.sema, 1, 0);
sync_transfer_init(&xfer);
if (mc13783_read_async(&xfer.xfer, regs, buffer, count,
mc13783_xfer_complete_cb) &&
@ -316,7 +333,7 @@ int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer,
int count)
{
struct mc13783_transfer_desc xfer;
semaphore_init(&xfer.sema, 1, 0);
sync_transfer_init(&xfer);
if (mc13783_write_async(&xfer.xfer, regs, buffer, count,
mc13783_xfer_complete_cb) &&