summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2017-01-28 14:43:35 -0500
committerMichael Sevakis <jethead71@rockbox.org>2017-01-29 19:07:55 -0500
commit2220a4b695f2f5ac9fe212de4bcfa5365318136f (patch)
treeef0b31d798b12cbc5cd61e3f020f1856c1759db4
parentd4303ac900bae6b0fd2320db33bdb4f10861a430 (diff)
downloadrockbox-2220a4b.tar.gz
rockbox-2220a4b.tar.bz2
rockbox-2220a4b.zip
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
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/export/config/gigabeats.h10
-rw-r--r--firmware/export/mc13783.h90
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c4
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/adc-target.h1
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c8
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/button-target.h2
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c41
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c52
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/gpio-target.h51
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c5
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c86
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/mc13783-target.h44
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c6
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h1
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c6
-rw-r--r--firmware/target/arm/imx31/gpio-imx31.c198
-rw-r--r--firmware/target/arm/imx31/gpio-imx31.h209
-rw-r--r--firmware/target/arm/imx31/mc13783-imx31.c219
19 files changed, 551 insertions, 484 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index d00e56f1a6..88e40fa74f 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -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
diff --git a/firmware/export/config/gigabeats.h b/firmware/export/config/gigabeats.h
index b20a6934a7..e1bbb18529 100644
--- a/firmware/export/config/gigabeats.h
+++ b/firmware/export/config/gigabeats.h
@@ -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
diff --git a/firmware/export/mc13783.h b/firmware/export/mc13783.h
index 6ad34346df..d427830786 100644
--- a/firmware/export/mc13783.h
+++ b/firmware/export/mc13783.h
@@ -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[] = {
+
+#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 if one exists - valid only within event handlers */
-uint32_t mc13783_event_sense(enum mc13783_event_ids id);
+/* Read the sense bit(s) if configured - valid only within the respective
+ event handler */
+uint32_t mc13783_event_sense(void);
#endif /* _MC13783_H_ */
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
index b46fc2f63f..2a89a82e46 100644
--- a/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
@@ -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);
}
diff --git a/firmware/target/arm/imx31/gigabeat-s/adc-target.h b/firmware/target/arm/imx31/gigabeat-s/adc-target.h
index 00027e05df..dbca920b26 100644
--- a/firmware/target/arm/imx31/gigabeat-s/adc-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/adc-target.h
@@ -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);
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c
index 3972e5722f..cdd6da041b 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/button-gigabeat-s.c
@@ -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 */
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h
index ce624ed6cc..fba02d5dd2 100644
--- a/firmware/target/arm/imx31/gigabeat-s/button-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h
@@ -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);
diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
index 108a6d0944..ee91b99c0f 100644
--- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
@@ -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 */
-
- uint16_t rds_data[4];
+ if (xfer->rxcount == 0)
+ {
+ uint16_t rds_data[4];
+ si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
- si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
+ if (rds_process(rds_data))
+ si4700_rds_set_event();
+ }
+ /* else read didn't finish */
- 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 */
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
deleted file mode 100644
index 51446934aa..0000000000
--- a/firmware/target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
+++ /dev/null
@@ -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
-};
diff --git a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h
index 4903d0f631..543b25f244 100644
--- a/firmware/target/arm/imx31/gigabeat-s/gpio-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/gpio-target.h
@@ -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
-
-/* 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
+/* Gigabeat S definitions for static GPIO event registration */
+#include "gpio-imx31.h"
+
+#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 */
-};
-
-void mc13783_event(void);
-void si4700_stc_rds_event(void);
+#endif /* DEFINE_GPIO_VECTOR_TABLE */
+
+#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 */
diff --git a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
index 6fdde32185..cf0a378fc7 100644
--- a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
@@ -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);
}
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
deleted file mode 100644
index 76001dddd6..0000000000
--- a/firmware/target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
+++ /dev/null
@@ -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
-};
diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h
index 48d634035a..179c65cad6 100644
--- a/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h
+++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-target.h
@@ -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 */
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
index 5d89802bc9..81f150acd7 100644
--- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c
@@ -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);
}
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h
index 9294de102c..2cd509267c 100644
--- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h
+++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.h
@@ -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 */
diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c
index 9129568b7a..71e8342595 100644
--- a/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/usb-gigabeat-s.c
@@ -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)
diff --git a/firmware/target/arm/imx31/gpio-imx31.c b/firmware/target/arm/imx31/gpio-imx31.c
index e368d1ae07..7a7363be88 100644
--- a/firmware/target/arm/imx31/gpio-imx31.c
+++ b/firmware/target/arm/imx31/gpio-imx31.c
@@ -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
- {
- unsigned long mask = event->mask;
+ const struct gpio_event *event = desc->events;
+ while (pnd)
+ {
+ 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];
- volatile unsigned long * const base = desc->base;
- volatile unsigned long *icr;
- unsigned long mask, line;
- unsigned long imr;
- int shift;
+ unsigned int mod = id / 32;
- int oldlevel = disable_irq_save();
+ struct gpio_module_desc * const desc = gpio_descs[mod];
- imr = base[IMR];
+ if (mod >= GPIO_MODULE_CNT || desc == NULL)
+ return false;
- if (imr == 0)
- {
- /* First enabled interrupt for this GPIO */
- avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
- desc->handler);
- }
-
- /* 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;
+ const struct gpio_event * const event = event_from_id(desc, id);
+ if (!event)
+ return false;
- *icr = (*icr & ~mask) | ((event->sense << shift) & mask);
+ volatile unsigned long * const base = desc->base;
+ unsigned long num = id % 32;
+ unsigned long mask = 1ul << num;
- /* Unmask the line */
- base[IMR] = imr | event->mask;
+ unsigned long cpsr = disable_irq_save();
- restore_irq(oldlevel);
+ unsigned long imr = base[GPIO_IMR];
- return true;
-}
+ if (enable)
+ {
+ if (desc->enabled == 0)
+ {
+ /* First enabled interrupt for this GPIO */
+ avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
+ desc->handler);
+ }
-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;
+ /* 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;
+ }
- int oldlevel = disable_irq_save();
+ /* Unmask the line */
+ desc->enabled |= mask;
+ imr |= mask;
+ }
+ else
+ {
+ imr &= ~mask;
+ desc->enabled &= ~mask;
- /* Remove bit from mask */
- imr = base[IMR] & ~event->mask;
+ if (desc->enabled == 0)
+ avic_disable_int(desc->ints); /* No events remain enabled */
+ }
- /* Mask the line */
- base[IMR] = imr;
+ base[GPIO_IMR] = imr;
- if (imr == 0)
- {
- /* No events remain enabled */
- avic_disable_int(desc->ints);
- }
+ restore_irq(cpsr);
- restore_irq(oldlevel);
+ return true;
}
diff --git a/firmware/target/arm/imx31/gpio-imx31.h b/firmware/target/arm/imx31/gpio-imx31.h
index a1358672e8..86ca964f94 100644
--- a/firmware/target/arm/imx31/gpio-imx31.h
+++ b/firmware/target/arm/imx31/gpio-imx31.h
@@ -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[] = {
+
+#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); \
+ } \
+ }
-#include "gpio-target.h"
+#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 */
diff --git a/firmware/target/arm/imx31/mc13783-imx31.c b/firmware/target/arm/imx31/mc13783-imx31.c
index 627048fa54..6bf0b878f4 100644
--- a/firmware/target/arm/imx31/mc13783-imx31.c
+++ b/firmware/target/arm/imx31/mc13783-imx31.c
@@ -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) &&