summaryrefslogtreecommitdiff
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-2220a4b695f2f5ac9fe212de4bcfa5365318136f.tar.gz
rockbox-2220a4b695f2f5ac9fe212de4bcfa5365318136f.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
1139target/arm/imx31/gigabeat-s/adc-gigabeat-s.c 1139target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
1140target/arm/imx31/gigabeat-s/backlight-gigabeat-s.c 1140target/arm/imx31/gigabeat-s/backlight-gigabeat-s.c
1141target/arm/imx31/gigabeat-s/button-gigabeat-s.c 1141target/arm/imx31/gigabeat-s/button-gigabeat-s.c
1142target/arm/imx31/gigabeat-s/gpio-gigabeat-s.c
1143target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c 1142target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c
1144target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c 1143target/arm/imx31/gigabeat-s/i2s-gigabeat-s.c
1145target/arm/imx31/gigabeat-s/mc13783-gigabeat-s.c
1146target/arm/imx31/gigabeat-s/power-gigabeat-s.c 1144target/arm/imx31/gigabeat-s/power-gigabeat-s.c
1147target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c 1145target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
1148target/arm/imx31/gigabeat-s/system-gigabeat-s.c 1146target/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 @@
86 86
87#define AB_REPEAT_ENABLE 87#define AB_REPEAT_ENABLE
88 88
89/* Define this if you have a SI4700 fm radio tuner */
90#define CONFIG_TUNER SI4700
91
92#define HAVE_RDS_CAP
93#define RDS_ISR_PROCESSING
94
95/* Define this if you have the WM8978 audio codec */ 89/* Define this if you have the WM8978 audio codec */
96#define HAVE_WM8978 90#define HAVE_WM8978
97 91
@@ -124,6 +118,10 @@
124#define HAVE_LCD_ENABLE 118#define HAVE_LCD_ENABLE
125 119
126#ifndef BOOTLOADER 120#ifndef BOOTLOADER
121/* Define this if you have a SI4700 fm radio tuner */
122#define CONFIG_TUNER SI4700
123#define HAVE_RDS_CAP
124#define RDS_ISR_PROCESSING
127 125
128/* define this if you can flip your LCD */ 126/* define this if you can flip your LCD */
129#define HAVE_LCD_FLIP 127#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
1256#define MC13783_TC3PERIOD_POS (21) 1256#define MC13783_TC3PERIOD_POS (21)
1257#define MC13783_TC3TRIODE (0x1 << 23) 1257#define MC13783_TC3TRIODE (0x1 << 23)
1258 1258
1259/* For event enum values which are target-defined */
1260#include "mc13783-target.h"
1261
1262void mc13783_init(void); 1259void mc13783_init(void);
1263void mc13783_close(void); 1260void mc13783_close(void);
1264uint32_t mc13783_set(unsigned address, uint32_t bits); 1261uint32_t mc13783_set(unsigned address, uint32_t bits);
@@ -1296,7 +1293,7 @@ enum mc13783_int_ids
1296 MC13783_INT_ID_CHGSHORT = 9, 1293 MC13783_INT_ID_CHGSHORT = 9,
1297 MC13783_INT_ID_CCCV = 10, 1294 MC13783_INT_ID_CCCV = 10,
1298 MC13783_INT_ID_CHGCURR = 11, 1295 MC13783_INT_ID_CHGCURR = 11,
1299 MC13783_INT_ID_BPONI = 12, 1296 MC13783_INT_ID_BPON = 12,
1300 MC13783_INT_ID_LOBATL = 13, 1297 MC13783_INT_ID_LOBATL = 13,
1301 MC13783_INT_ID_LOBATH = 14, 1298 MC13783_INT_ID_LOBATH = 14,
1302 MC13783_INT_ID_UDP = 15, 1299 MC13783_INT_ID_UDP = 15,
@@ -1306,41 +1303,70 @@ enum mc13783_int_ids
1306 MC13783_INT_ID_CKDET = 22, 1303 MC13783_INT_ID_CKDET = 22,
1307 MC13783_INT_ID_UDM = 23, 1304 MC13783_INT_ID_UDM = 23,
1308 /* *STATUS1/MASK1/SENSE1 */ 1305 /* *STATUS1/MASK1/SENSE1 */
1309 MC13783_INT_ID_1HZ = 0 + 0x20, 1306 MC13783_INT_ID_1HZ = 0 + 32,
1310 MC13783_INT_ID_TODA = 1 + 0x20, 1307 MC13783_INT_ID_TODA = 1 + 32,
1311 MC13783_INT_ID_ONOFD1 = 3 + 0x20, /* ON1B */ 1308 MC13783_INT_ID_ONOFD1 = 3 + 32, /* ON1B */
1312 MC13783_INT_ID_ONOFD2 = 4 + 0x20, /* ON2B */ 1309 MC13783_INT_ID_ONOFD2 = 4 + 32, /* ON2B */
1313 MC13783_INT_ID_ONOFD3 = 5 + 0x20, /* ON3B */ 1310 MC13783_INT_ID_ONOFD3 = 5 + 32, /* ON3B */
1314 MC13783_INT_ID_SYSRST = 6 + 0x20, 1311 MC13783_INT_ID_SYSRST = 6 + 32,
1315 MC13783_INT_ID_RTCRST = 7 + 0x20, 1312 MC13783_INT_ID_RTCRST = 7 + 32,
1316 MC13783_INT_ID_PCI = 8 + 0x20, 1313 MC13783_INT_ID_PCI = 8 + 32,
1317 MC13783_INT_ID_WARM = 9 + 0x20, 1314 MC13783_INT_ID_WARM = 9 + 32,
1318 MC13783_INT_ID_MEMHLD = 10 + 0x20, 1315 MC13783_INT_ID_MEMHLD = 10 + 32,
1319 MC13783_INT_ID_PWRRDY = 11 + 0x20, 1316 MC13783_INT_ID_PWRRDY = 11 + 32,
1320 MC13783_INT_ID_THWARNL = 12 + 0x20, 1317 MC13783_INT_ID_THWARNL = 12 + 32,
1321 MC13783_INT_ID_THWARNH = 13 + 0x20, 1318 MC13783_INT_ID_THWARNH = 13 + 32,
1322 MC13783_INT_ID_CLK = 14 + 0x20, 1319 MC13783_INT_ID_CLK = 14 + 32,
1323 MC13783_INT_ID_SEMAF = 15 + 0x20, 1320 MC13783_INT_ID_SEMAF = 15 + 32,
1324 MC13783_INT_ID_MC2B = 17 + 0x20, 1321 MC13783_INT_ID_MC2B = 17 + 32,
1325 MC13783_INT_ID_HSDET = 18 + 0x20, 1322 MC13783_INT_ID_HSDET = 18 + 32,
1326 MC13783_INT_ID_HSL = 19 + 0x20, 1323 MC13783_INT_ID_HSL = 19 + 32,
1327 MC13783_INT_ID_ALSPTH = 20 + 0x20, 1324 MC13783_INT_ID_ALSPTH = 20 + 32,
1328 MC13783_INT_ID_AHSSHORT = 21 + 0x20, 1325 MC13783_INT_ID_AHSSHORT = 21 + 32,
1329}; 1326};
1330 1327
1331#define MC13783_INT_ID_SET_DIV (0x20) 1328#ifdef DEFINE_MC13783_VECTOR_TABLE
1332#define MC13783_INT_ID_NUM_MASK (0x1f)
1333 1329
1334struct mc13783_event 1330struct mc13783_event
1335{ 1331{
1336 enum mc13783_int_ids int_id : 8; 1332 uint32_t id : 8; /* MC13783_INT_ID_x */
1337 uint32_t sense : 24; 1333 uint32_t sense : 24; /* MC13783_xS */
1338 void (*callback)(void); 1334 void (*callback)(void); /* MC13783_EVENT_CB_x */
1339}; 1335};
1340 1336
1341void mc13783_enable_event(enum mc13783_event_ids id, bool enable); 1337/* Declares vector table. Order-implied priority */
1338#define MC13783_EVENT_VECTOR_TBL_START() \
1339 static FORCE_INLINE uintptr_t __mc13783_event_vector_tbl(int __what) \
1340 { \
1341 static const struct mc13783_event __tbl[] = {
1342
1343#define MC13783_EVENT_VECTOR(__name, __sense) \
1344 { .id = MC13783_INT_ID_##__name, \
1345 .sense = (__sense), \
1346 .callback = ({ void MC13783_EVENT_CB_##__name(void); \
1347 MC13783_EVENT_CB_##__name; }) },
1348
1349#define MC13783_EVENT_VECTOR_TBL_END() \
1350 }; \
1351 switch (__what) \
1352 { \
1353 default: return (uintptr_t)__tbl; \
1354 case 1: return (uintptr_t)ARRAYLEN(__tbl); \
1355 } \
1356 }
1357
1358#define mc13783_event_vector_tbl \
1359 ((const struct mc13783_event *)__mc13783_event_vector_tbl(0))
1360
1361#define mc13783_event_vector_tbl_len \
1362 ((unsigned int)__mc13783_event_vector_tbl(1))
1363
1364#endif /* DEFINE_MC13783_VECTOR_TABLE */
1365
1366void mc13783_enable_event(enum mc13783_int_ids id, bool enable);
1342 1367
1343/* Read the sense bit if one exists - valid only within event handlers */ 1368/* Read the sense bit(s) if configured - valid only within the respective
1344uint32_t mc13783_event_sense(enum mc13783_event_ids id); 1369 event handler */
1370uint32_t mc13783_event_sense(void);
1345 1371
1346#endif /* _MC13783_H_ */ 1372#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)
111} 111}
112 112
113/* ADC conversion complete event - called from PMIC ISR */ 113/* ADC conversion complete event - called from PMIC ISR */
114void adc_done(void) 114void MC13783_EVENT_CB_ADCDONE(void)
115{ 115{
116 semaphore_release(&adc_done_signal); 116 semaphore_release(&adc_done_signal);
117} 117}
@@ -132,5 +132,5 @@ void adc_init(void)
132 132
133 /* Enable ADCDONE event */ 133 /* Enable ADCDONE event */
134 mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI); 134 mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI);
135 mc13783_enable_event(MC13783_ADCDONE_EVENT, true); 135 mc13783_enable_event(MC13783_INT_ID_ADCDONE, true);
136} 136}
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 @@
46#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */ 46#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
47#define ADC_READ_ERROR 0xFFFF 47#define ADC_READ_ERROR 0xFFFF
48 48
49void adc_done(void);
50/* Enable conversion of specified channel (if switchoff is possible) */ 49/* Enable conversion of specified channel (if switchoff is possible) */
51bool adc_enable_channel(int channel, bool enable); 50bool adc_enable_channel(int channel, bool enable);
52 51
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)
157} 157}
158 158
159/* Power button event - called from PMIC ISR */ 159/* Power button event - called from PMIC ISR */
160void button_power_event(void) 160void MC13783_EVENT_CB_ONOFD1(void)
161{ 161{
162 power_button_update(!mc13783_event_sense(MC13783_ONOFD1_EVENT)); 162 power_button_update(!mc13783_event_sense());
163} 163}
164 164
165void button_init_device(void) 165void button_init_device(void)
@@ -197,7 +197,7 @@ void button_init_device(void)
197 197
198 power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1) 198 power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1)
199 & MC13783_ONOFD1S)); 199 & MC13783_ONOFD1S));
200 mc13783_enable_event(MC13783_ONOFD1_EVENT, true); 200 mc13783_enable_event(MC13783_INT_ID_ONOFD1, true);
201 201
202#ifdef HAVE_HEADPHONE_DETECTION 202#ifdef HAVE_HEADPHONE_DETECTION
203 headphone_init(); 203 headphone_init();
@@ -213,7 +213,7 @@ void button_close_device(void)
213 /* Assumes HP detection is not available */ 213 /* Assumes HP detection is not available */
214 initialized = false; 214 initialized = false;
215 215
216 mc13783_enable_event(MC13783_ONOFD1_EVENT, false); 216 mc13783_enable_event(MC13783_INT_ID_ONOFD1, false);
217 ext_btn = BUTTON_NONE; 217 ext_btn = BUTTON_NONE;
218} 218}
219#endif /* BUTTON_DRIVER_CLOSE */ 219#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 @@
30#endif 30#endif
31 31
32void button_close_device(void); 32void button_close_device(void);
33void button_power_event(void);
34void headphone_detect_event(void);
35void headphone_init(void); 33void headphone_init(void);
36void button_headphone_set(int button); 34void button_headphone_set(int button);
37 35
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 @@
26#include "thread.h" 26#include "thread.h"
27#include "mc13783.h" 27#include "mc13783.h"
28#include "iomuxc-imx31.h" 28#include "iomuxc-imx31.h"
29#include "gpio-imx31.h" 29#include "gpio-target.h"
30#include "i2c-imx31.h" 30#include "i2c-imx31.h"
31#include "fmradio_i2c.h" 31#include "fmradio_i2c.h"
32#include "rds.h" 32#include "rds.h"
@@ -139,20 +139,25 @@ static struct si4700_i2c_transfer_desc
139 .xfer = { .node = &si4700_i2c_node } 139 .xfer = { .node = &si4700_i2c_node }
140}; 140};
141 141
142static bool int_restore;
143
142static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer) 144static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
143{ 145{
144 struct si4700_i2c_transfer_desc *xf = 146 struct si4700_i2c_transfer_desc *xf =
145 (struct si4700_i2c_transfer_desc *)xfer; 147 (struct si4700_i2c_transfer_desc *)xfer;
146 148
147 if (xfer->rxcount != 0) 149 if (xfer->rxcount == 0)
148 return; /* Read didn't finish */ 150 {
149 151 uint16_t rds_data[4];
150 uint16_t rds_data[4]; 152 si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
151 153
152 si4700_rds_read_raw_async_complete(xf->regbuf, rds_data); 154 if (rds_process(rds_data))
155 si4700_rds_set_event();
156 }
157 /* else read didn't finish */
153 158
154 if (rds_process(rds_data)) 159 if (int_restore)
155 si4700_rds_set_event(); 160 gpio_int_enable(SI4700_EVENT_ID);
156} 161}
157 162
158/* Callback from si4700_rds_read_raw to execute the read */ 163/* Callback from si4700_rds_read_raw to execute the read */
@@ -169,10 +174,13 @@ void si4700_read_raw_async(int count)
169} 174}
170 175
171/* RDS GPIO interrupt handler - start RDS data read */ 176/* RDS GPIO interrupt handler - start RDS data read */
172void si4700_stc_rds_event(void) 177void INT_SI4700_RDS(void)
173{ 178{
174 /* read and clear the interrupt */ 179 /* mask and clear the interrupt */
175 SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE); 180 gpio_int_disable(SI4700_EVENT_ID);
181 gpio_int_clear(SI4700_EVENT_ID);
182
183 /* read the RDS data */
176 si4700_rds_read_raw_async(); 184 si4700_rds_read_raw_async();
177} 185}
178 186
@@ -180,13 +188,10 @@ void si4700_stc_rds_event(void)
180 powering down */ 188 powering down */
181void si4700_rds_powerup(bool on) 189void si4700_rds_powerup(bool on)
182{ 190{
183 gpio_disable_event(SI4700_STC_RDS_EVENT_ID); 191 int_restore = on;
184 192 gpio_int_disable(SI4700_EVENT_ID);
185 if (on) 193 gpio_int_clear(SI4700_EVENT_ID);
186 { 194 gpio_enable_event(SI4700_EVENT_ID, on);
187 SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
188 gpio_enable_event(SI4700_STC_RDS_EVENT_ID);
189 }
190} 195}
191 196
192/* One-time RDS init at startup */ 197/* 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * Gigabeat S GPIO interrupt event descriptions
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "config.h"
24#include "system.h"
25#include "avic-imx31.h"
26#include "gpio-imx31.h"
27
28/* Gigabeat S definitions for static GPIO event registration */
29
30/* Describes single events for each GPIO1 pin */
31const struct gpio_event gpio1_events[] =
32{
33 /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked
34 * interrupts become active when clearing them or if a source being
35 * cleared becomes active at that time. Edge-detection will not get
36 * a rising edge in that case so use high-level sense. */
37 [MC13783_EVENT_ID-GPIO1_EVENT_FIRST] =
38 {
39 .mask = 1 << MC13783_GPIO_LINE,
40 .sense = GPIO_SENSE_HIGH_LEVEL,
41 .callback = mc13783_event,
42 },
43#ifndef BOOTLOADER
44 /* Generates a 5ms low pulse on the line - detect the falling edge */
45 [SI4700_STC_RDS_EVENT_ID] =
46 {
47 .mask = 1 << SI4700_GPIO_STC_RDS_LINE,
48 .sense = GPIO_SENSE_FALLING,
49 .callback = si4700_stc_rds_event,
50 },
51#endif
52};
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 @@
23#ifndef GPIO_TARGET_H 23#ifndef GPIO_TARGET_H
24#define GPIO_TARGET_H 24#define GPIO_TARGET_H
25 25
26/* MC13783 GPIO pin info for this target */ 26/* Gigabeat S definitions for static GPIO event registration */
27#define MC13783_GPIO_IMR GPIO1_IMR 27#include "gpio-imx31.h"
28#define MC13783_GPIO_NUM GPIO1_NUM 28
29#define MC13783_GPIO_ISR GPIO1_ISR 29#ifdef DEFINE_GPIO_VECTOR_TABLE
30#define MC13783_GPIO_LINE 31 30
31 31GPIO_VECTOR_TBL_START()
32/* SI4700 GPIO STC/RDS pin info for this target */ 32 /* mc13783 keeps the PRIINT high (no low pulse) if other unmasked
33#define SI4700_GPIO_STC_RDS_IMR GPIO1_IMR 33 * interrupts become active when clearing them or if a source being
34#define SI4700_GPIO_STC_RDS_NUM GPIO1_NUM 34 * cleared becomes active at that time. Edge-detection will not get
35#define SI4700_GPIO_STC_RDS_ISR GPIO1_ISR 35 * a rising edge in that case so use high-level sense. */
36#define SI4700_GPIO_STC_RDS_LINE 27 36 GPIO_EVENT_VECTOR(GPIO1_31, GPIO_SENSE_HIGH_LEVEL)
37#if CONFIG_TUNER
38 /* Generates a 5ms low pulse on the line - detect the falling edge */
39 GPIO_EVENT_VECTOR(GPIO1_27, GPIO_SENSE_FALLING)
40#endif /* CONFIG_TUNER */
41GPIO_VECTOR_TBL_END()
37 42
38#define GPIO1_INT_PRIO INT_PRIO_DEFAULT 43#define GPIO1_INT_PRIO INT_PRIO_DEFAULT
39 44
40/* Declare event indexes in priority order in a packed array */ 45#endif /* DEFINE_GPIO_VECTOR_TABLE */
41enum gpio_event_ids 46
42{ 47#define INT_MC13783 GPIO1_31_EVENT_CB
43 /* GPIO1 event IDs */ 48#define MC13783_EVENT_ID GPIO1_31_ID
44 MC13783_EVENT_ID = GPIO1_EVENT_FIRST, 49
45 SI4700_STC_RDS_EVENT_ID, 50#if CONFIG_TUNER
46 GPIO1_NUM_EVENTS = 2, 51#define INT_SI4700_RDS GPIO1_27_EVENT_CB
47 /* GPIO2 event IDs */ 52#define SI4700_EVENT_ID GPIO1_27_ID
48 /* none defined */ 53#endif /* CONFIG_TUNER */
49 /* GPIO3 event IDs */
50 /* none defined */
51};
52
53void mc13783_event(void);
54void si4700_stc_rds_event(void);
55 54
56#endif /* GPIO_TARGET_H */ 55#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 @@
25#include "kernel.h" 25#include "kernel.h"
26#include "thread.h" 26#include "thread.h"
27#include "mc13783.h" 27#include "mc13783.h"
28#include "mc13783-target.h"
29#include "adc.h" 28#include "adc.h"
30#include "button.h" 29#include "button.h"
31 30
@@ -146,7 +145,7 @@ static void NORETURN_ATTR headphone_thread(void)
146} 145}
147 146
148/* HP plugged/unplugged event - called from PMIC ISR */ 147/* HP plugged/unplugged event - called from PMIC ISR */
149void headphone_detect_event(void) 148void MC13783_EVENT_CB_ONOFD2(void)
150{ 149{
151 /* Trigger the thread immediately. */ 150 /* Trigger the thread immediately. */
152 semaphore_release(&headphone_wakeup); 151 semaphore_release(&headphone_wakeup);
@@ -170,5 +169,5 @@ void INIT_ATTR headphone_init(void)
170 IF_COP(, CPU)); 169 IF_COP(, CPU));
171 170
172 /* Enable PMIC event */ 171 /* Enable PMIC event */
173 mc13783_enable_event(MC13783_ONOFD2_EVENT, true); 172 mc13783_enable_event(MC13783_INT_ID_ONOFD2, true);
174} 173}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2008 by Michael Sevakis
11 *
12 * Gigabeat S MC13783 event descriptions
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "config.h"
24#include "system.h"
25#include "spi-imx31.h"
26#include "mc13783.h"
27#include "mc13783-target.h"
28#include "adc-target.h"
29#include "button-target.h"
30#include "power-gigabeat-s.h"
31#include "powermgmt-target.h"
32
33/* Gigabeat S mc13783 serial interface node. */
34
35struct spi_node mc13783_spi =
36{
37 /* Based upon original firmware settings */
38 CSPI2_NUM, /* CSPI module 2 */
39 CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
40 CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
41 CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */
42 CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
43 CSPI_CONREG_SSPOL | /* SS active high */
44 CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */
45 CSPI_CONREG_MODE, /* Master mode */
46 0, /* SPI clock - no wait states */
47};
48
49
50/* Gigabeat S definitions for static MC13783 event registration */
51
52const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS] =
53{
54 [MC13783_ADCDONE_EVENT] = /* ADC conversion complete */
55 {
56 .int_id = MC13783_INT_ID_ADCDONE,
57 .sense = 0,
58 .callback = adc_done,
59 },
60 [MC13783_ONOFD1_EVENT] = /* Power button */
61 {
62 .int_id = MC13783_INT_ID_ONOFD1,
63 .sense = MC13783_ONOFD1S,
64 .callback = button_power_event,
65 },
66 [MC13783_SE1_EVENT] = /* Main charger detection */
67 {
68 .int_id = MC13783_INT_ID_SE1,
69 .sense = MC13783_SE1S,
70 .callback = charger_main_detect_event,
71 },
72 [MC13783_USB_EVENT] = /* USB insertion/USB charger detection */
73 {
74 .int_id = MC13783_INT_ID_USB,
75 .sense = MC13783_USB4V4S,
76 .callback = usb_connect_event,
77 },
78#ifdef HAVE_HEADPHONE_DETECTION
79 [MC13783_ONOFD2_EVENT] = /* Headphone jack */
80 {
81 .int_id = MC13783_INT_ID_ONOFD2,
82 .sense = 0,
83 .callback = headphone_detect_event,
84 },
85#endif
86};
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 @@
23#ifndef MC13783_TARGET_H 23#ifndef MC13783_TARGET_H
24#define MC13783_TARGET_H 24#define MC13783_TARGET_H
25 25
26/* Declare event indexes in priority order in a packed array */ 26#include "mc13783.h"
27enum mc13783_event_ids 27
28#ifdef DEFINE_MC13783_VECTOR_TABLE
29
30/* Gigabeat S mc13783 serial interface node. */
31static struct spi_node mc13783_spi =
28{ 32{
29 MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */ 33 /* Based upon original firmware settings */
30 MC13783_ONOFD1_EVENT, /* Power button */ 34 CSPI2_NUM, /* CSPI module 2 */
31#ifdef HAVE_HEADPHONE_DETECTION 35 CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
32 MC13783_ONOFD2_EVENT, /* Headphone jack */ 36 CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
33#endif 37 CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */
34 MC13783_SE1_EVENT, /* Main charger detection */ 38 CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
35 MC13783_USB_EVENT, /* USB insertion */ 39 CSPI_CONREG_SSPOL | /* SS active high */
36 MC13783_NUM_EVENTS, 40 CSPI_CONREG_SSCTL | /* Negate SS between SPI bursts */
41 CSPI_CONREG_MODE, /* Master mode */
42 0, /* SPI clock - no wait states */
37}; 43};
38 44
45/* Gigabeat S definitions for static MC13783 event registration */
46MC13783_EVENT_VECTOR_TBL_START()
47 /* ADC conversion complete */
48 MC13783_EVENT_VECTOR(ADCDONE, 0)
49 /* Power button */
50 MC13783_EVENT_VECTOR(ONOFD1, MC13783_ONOFD1S)
51 /* Main charger detection */
52 MC13783_EVENT_VECTOR(SE1, MC13783_SE1S)
53 /* USB insertion/USB charger detection */
54 MC13783_EVENT_VECTOR(USB, MC13783_USB4V4S)
55#ifdef HAVE_HEADPHONE_DETECTION
56 /* Headphone jack */
57 MC13783_EVENT_VECTOR(ONOFD2, 0)
58#endif /* HAVE_HEADPHONE_DETECTION */
59MC13783_EVENT_VECTOR_TBL_END()
60
61#endif /* DEFINE_MC13783_VECTOR_TABLE */
62
39#endif /* MC13783_TARGET_H */ 63#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)
66} 66}
67 67
68/* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */ 68/* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */
69void charger_main_detect_event(void) 69void MC13783_EVENT_CB_SE1(void)
70{ 70{
71 update_main_charger(mc13783_event_sense(MC13783_SE1_EVENT)); 71 update_main_charger(mc13783_event_sense());
72} 72}
73 73
74/* Detect changes in USB bus power. Called from usb connect event ISR. */ 74/* Detect changes in USB bus power. Called from usb connect event ISR. */
@@ -159,5 +159,5 @@ void power_init(void)
159 & MC13783_SE1S); 159 & MC13783_SE1S);
160 160
161 /* Enable detect event */ 161 /* Enable detect event */
162 mc13783_enable_event(MC13783_SE1_EVENT, true); 162 mc13783_enable_event(MC13783_INT_ID_SE1, true);
163} 163}
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 @@
21#ifndef POWER_IMX31_H 21#ifndef POWER_IMX31_H
22#define POWER_IMX31_H 22#define POWER_IMX31_H
23 23
24void charger_main_detect_event(void);
25void charger_usb_detect_event(int status); 24void charger_usb_detect_event(int status);
26 25
27#endif /* POWER_IMX31_H */ 26#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)
70} 70}
71 71
72/* Detect presence of USB bus - called from PMIC ISR */ 72/* Detect presence of USB bus - called from PMIC ISR */
73void usb_connect_event(void) 73void MC13783_EVENT_CB_USB(void)
74{ 74{
75 /* Read the associated sense value */ 75 /* Read the associated sense value */
76 update_usb_status(mc13783_event_sense(MC13783_USB_EVENT)); 76 update_usb_status(mc13783_event_sense());
77} 77}
78 78
79int usb_detect(void) 79int usb_detect(void)
@@ -90,7 +90,7 @@ void usb_init_device(void)
90 update_usb_status(usb_plugged()); 90 update_usb_status(usb_plugged());
91 91
92 /* Enable PMIC event */ 92 /* Enable PMIC event */
93 mc13783_enable_event(MC13783_USB_EVENT, true); 93 mc13783_enable_event(MC13783_INT_ID_USB, true);
94} 94}
95 95
96void usb_enable(bool on) 96void 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 @@
23#include "config.h" 23#include "config.h"
24#include "system.h" 24#include "system.h"
25#include "avic-imx31.h" 25#include "avic-imx31.h"
26#include "gpio-imx31.h" 26#define DEFINE_GPIO_VECTOR_TABLE
27#include "gpio-target.h"
27 28
28/* UIE vector found in avic-imx31.c */ 29/* UIE vector found in avic-imx31.c */
29extern void UIE_VECTOR(void); 30extern void UIE_VECTOR(void);
@@ -31,101 +32,91 @@ extern void UIE_VECTOR(void);
31/* Event lists are allocated for the specific target */ 32/* Event lists are allocated for the specific target */
32#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 33#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
33static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void); 34static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
34extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS];
35#endif 35#endif
36 36
37#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) 37#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
38static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void); 38static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
39extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS];
40#endif 39#endif
41 40
42#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) 41#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
43static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void); 42static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
44extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS];
45#endif 43#endif
46 44
47#define DR (0x00 / sizeof (unsigned long)) /* 00h */ 45static struct gpio_module_desc
48#define GDIR (0x04 / sizeof (unsigned long)) /* 04h */
49#define PSR (0x08 / sizeof (unsigned long)) /* 08h */
50#define ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
51#define IMR (0x14 / sizeof (unsigned long)) /* 14h */
52#define ISR (0x18 / sizeof (unsigned long))
53
54static const struct gpio_module_desc
55{ 46{
56 volatile unsigned long * const base; /* Module base address */ 47 volatile unsigned long * const base; /* Module base address */
57 void (* const handler)(void); /* Interrupt function */ 48 void (* const handler)(void); /* Interrupt function */
58 const struct gpio_event * const events; /* Event handler list */ 49 const struct gpio_event *events; /* Event handler list */
50 unsigned long enabled; /* Enabled event mask */
59 const uint8_t ints; /* AVIC int number */ 51 const uint8_t ints; /* AVIC int number */
60 const uint8_t int_priority; /* AVIC int priority */ 52 const uint8_t int_priority; /* AVIC int priority */
61 const uint8_t count; /* Number of events */ 53 uint8_t count; /* Number of events */
62} gpio_descs[GPIO_NUM_GPIO] = 54} * const gpio_descs[] =
63{ 55{
64#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 56#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
65 { 57 [GPIO1_NUM] = &(struct gpio_module_desc) {
66 .base = (unsigned long *)GPIO1_BASE_ADDR, 58 .base = (unsigned long *)GPIO1_BASE_ADDR,
67 .ints = INT_GPIO1, 59 .ints = INT_GPIO1,
68 .handler = GPIO1_HANDLER, 60 .handler = GPIO1_HANDLER,
69 .events = gpio1_events,
70 .count = GPIO1_NUM_EVENTS,
71 .int_priority = GPIO1_INT_PRIO 61 .int_priority = GPIO1_INT_PRIO
72 }, 62 },
73#endif 63#endif
74#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) 64#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
75 { 65 [GPIO2_NUM] = &(struct gpio_module_desc) {
76 .base = (unsigned long *)GPIO2_BASE_ADDR, 66 .base = (unsigned long *)GPIO2_BASE_ADDR,
77 .ints = INT_GPIO2, 67 .ints = INT_GPIO2,
78 .handler = GPIO2_HANDLER, 68 .handler = GPIO2_HANDLER,
79 .events = gpio2_events,
80 .count = GPIO2_NUM_EVENTS,
81 .int_priority = GPIO2_INT_PRIO 69 .int_priority = GPIO2_INT_PRIO
82 }, 70 },
83#endif 71#endif
84#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) 72#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
85 { 73 [GPIO3_NUM] = &(struct gpio_module_desc) {
86 .base = (unsigned long *)GPIO3_BASE_ADDR, 74 .base = (unsigned long *)GPIO3_BASE_ADDR,
87 .ints = INT_GPIO3, 75 .ints = INT_GPIO3,
88 .handler = GPIO3_HANDLER, 76 .handler = GPIO3_HANDLER,
89 .events = gpio3_events,
90 .count = GPIO3_NUM_EVENTS,
91 .int_priority = GPIO3_INT_PRIO, 77 .int_priority = GPIO3_INT_PRIO,
92 }, 78 },
93#endif 79#endif
94}; 80};
95 81
82#define GPIO_MODULE_CNT ARRAYLEN(gpio_descs)
83
84static const struct gpio_event * event_from_id(
85 const struct gpio_module_desc *desc, enum gpio_id id)
86{
87 const struct gpio_event *events = desc->events;
88 for (unsigned int i = 0; i < desc->count; i++)
89 {
90 if (events[i].id == id)
91 return &events[i];
92 }
93
94 return NULL;
95}
96
96static void gpio_call_events(enum gpio_module_number gpio) 97static void gpio_call_events(enum gpio_module_number gpio)
97{ 98{
98 const struct gpio_module_desc * const desc = &gpio_descs[gpio]; 99 const struct gpio_module_desc * const desc = gpio_descs[gpio];
99 volatile unsigned long * const base = desc->base; 100 volatile unsigned long * const base = desc->base;
100 const struct gpio_event * event, *event_last;
101 101
102 event = desc->events; 102 /* Send only events that are not masked */
103 event_last = event + desc->count; 103 unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR];
104 104
105 /* Intersect pending and unmasked bits */ 105 if (pnd & ~desc->enabled)
106 unsigned long pnd = base[ISR] & base[IMR]; 106 UIE_VECTOR(); /* One or more aren't handled properly */
107 107
108 /* Call each event handler in order */ 108 const struct gpio_event *event = desc->events;
109 /* .count is surely expected to be > 0 */
110 do
111 {
112 unsigned long mask = event->mask;
113 109
110 while (pnd)
111 {
112 unsigned long mask = 1ul << (event->id % 32);
114 if (pnd & mask) 113 if (pnd & mask)
115 { 114 {
116 event->callback(); 115 event->callback();
117 pnd &= ~mask; 116 pnd &= ~mask;
118 } 117 }
119 118
120 if (pnd == 0) 119 event++;
121 break; /* Teminate early if nothing more to service */
122 }
123 while (++event < event_last);
124
125 if (pnd != 0)
126 {
127 /* One or more weren't handled */
128 UIE_VECTOR();
129 } 120 }
130} 121}
131 122
@@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
152 143
153void INIT_ATTR gpio_init(void) 144void INIT_ATTR gpio_init(void)
154{ 145{
155 /* Mask-out GPIO interrupts - enable what's wanted later */ 146 for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++)
156 int i; 147 {
157 for (i = 0; i < GPIO_NUM_GPIO; i++) 148 struct gpio_module_desc * const desc = gpio_descs[mod];
158 gpio_descs[i].base[IMR] = 0; 149 if (!desc)
150 continue;
151
152 /* Parse the event table per module. First contiguous run seen for a
153 * module is used. */
154 const struct gpio_event *event = gpio_event_vector_tbl;
155 for (unsigned int i = 0; i < gpio_event_vector_tbl_len; i++, event++)
156 {
157 if (event->id / 32 == mod)
158 {
159 desc->events = event;
160 while (++desc->count < 32 && (++event)->id / 32 == mod);
161 break;
162 }
163 }
164
165 /* Mask-out GPIO interrupts - enable what's wanted later */
166 desc->base[GPIO_IMR] = 0;
167 }
159} 168}
160 169
161bool gpio_enable_event(enum gpio_event_ids id) 170bool gpio_enable_event(enum gpio_id id, bool enable)
162{ 171{
163 const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; 172 unsigned int mod = id / 32;
164 const struct gpio_event * const event = &desc->events[id & 31];
165 volatile unsigned long * const base = desc->base;
166 volatile unsigned long *icr;
167 unsigned long mask, line;
168 unsigned long imr;
169 int shift;
170 173
171 int oldlevel = disable_irq_save(); 174 struct gpio_module_desc * const desc = gpio_descs[mod];
172 175
173 imr = base[IMR]; 176 if (mod >= GPIO_MODULE_CNT || desc == NULL)
177 return false;
174 178
175 if (imr == 0) 179 const struct gpio_event * const event = event_from_id(desc, id);
176 { 180 if (!event)
177 /* First enabled interrupt for this GPIO */ 181 return false;
178 avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
179 desc->handler);
180 }
181
182 /* Set the line sense */
183 line = find_first_set_bit(event->mask);
184 icr = &base[ICR + (line >> 4)];
185 shift = 2*(line & 15);
186 mask = GPIO_SENSE_CONFIG_MASK << shift;
187 182
188 *icr = (*icr & ~mask) | ((event->sense << shift) & mask); 183 volatile unsigned long * const base = desc->base;
184 unsigned long num = id % 32;
185 unsigned long mask = 1ul << num;
189 186
190 /* Unmask the line */ 187 unsigned long cpsr = disable_irq_save();
191 base[IMR] = imr | event->mask;
192 188
193 restore_irq(oldlevel); 189 unsigned long imr = base[GPIO_IMR];
194 190
195 return true; 191 if (enable)
196} 192 {
193 if (desc->enabled == 0)
194 {
195 /* First enabled interrupt for this GPIO */
196 avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
197 desc->handler);
198 }
197 199
198void gpio_disable_event(enum gpio_event_ids id) 200 /* Set the line sense */
199{ 201 if (event->sense == GPIO_SENSE_EDGE_SEL)
200 const struct gpio_module_desc * const desc = &gpio_descs[id >> 5]; 202 {
201 const struct gpio_event * const event = &desc->events[id & 31]; 203 /* Interrupt configuration register is ignored */
202 volatile unsigned long * const base = desc->base; 204 base[GPIO_EDGE_SEL] |= mask;
203 unsigned long imr; 205 }
206 else
207 {
208 volatile unsigned long *icrp = &base[GPIO_ICR + num / 16];
209 unsigned int shift = 2*(num % 16);
210 bitmod32(icrp, event->sense << shift, 0x3 << shift);
211 base[GPIO_EDGE_SEL] &= ~mask;
212 }
204 213
205 int oldlevel = disable_irq_save(); 214 /* Unmask the line */
215 desc->enabled |= mask;
216 imr |= mask;
217 }
218 else
219 {
220 imr &= ~mask;
221 desc->enabled &= ~mask;
206 222
207 /* Remove bit from mask */ 223 if (desc->enabled == 0)
208 imr = base[IMR] & ~event->mask; 224 avic_disable_int(desc->ints); /* No events remain enabled */
225 }
209 226
210 /* Mask the line */ 227 base[GPIO_IMR] = imr;
211 base[IMR] = imr;
212 228
213 if (imr == 0) 229 restore_irq(cpsr);
214 {
215 /* No events remain enabled */
216 avic_disable_int(desc->ints);
217 }
218 230
219 restore_irq(oldlevel); 231 return true;
220} 232}
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 @@
26#define USE_GPIO2_EVENTS (1 << 1) 26#define USE_GPIO2_EVENTS (1 << 1)
27#define USE_GPIO3_EVENTS (1 << 2) 27#define USE_GPIO3_EVENTS (1 << 2)
28 28
29/* Module indexes defined by which GPIO modules are used */ 29/* Module logical indexes */
30enum gpio_module_number 30enum gpio_module_number
31{ 31{
32 __GPIO_NUM_START = -1, 32 GPIO1_NUM, /* ID 0..31 */
33#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 33 GPIO2_NUM, /* ID 32..63 */
34 GPIO1_NUM, 34 GPIO3_NUM, /* ID 64..95 */
35#endif
36#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
37 GPIO2_NUM,
38#endif
39#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
40 GPIO3_NUM,
41#endif
42 GPIO_NUM_GPIO, 35 GPIO_NUM_GPIO,
43}; 36};
44 37
45/* Possible values for gpio interrupt line config */ 38enum gpio_id
46enum gpio_int_sense_enum
47{ 39{
48 GPIO_SENSE_LOW_LEVEL = 0, /* High-level sensitive */ 40 /* GPIO1 */
49 GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */ 41 GPIO1_0_ID = 0,
50 GPIO_SENSE_RISING, /* Rising-edge sensitive */ 42 GPIO1_1_ID,
51 GPIO_SENSE_FALLING, /* Falling-edge sensitive */ 43 GPIO1_2_ID,
44 GPIO1_3_ID,
45 GPIO1_4_ID,
46 GPIO1_5_ID,
47 GPIO1_6_ID,
48 GPIO1_7_ID,
49 GPIO1_8_ID,
50 GPIO1_9_ID,
51 GPIO1_10_ID,
52 GPIO1_11_ID,
53 GPIO1_12_ID,
54 GPIO1_13_ID,
55 GPIO1_14_ID,
56 GPIO1_15_ID,
57 GPIO1_16_ID,
58 GPIO1_17_ID,
59 GPIO1_18_ID,
60 GPIO1_19_ID,
61 GPIO1_20_ID,
62 GPIO1_21_ID,
63 GPIO1_22_ID,
64 GPIO1_23_ID,
65 GPIO1_24_ID,
66 GPIO1_25_ID,
67 GPIO1_26_ID,
68 GPIO1_27_ID,
69 GPIO1_28_ID,
70 GPIO1_29_ID,
71 GPIO1_30_ID,
72 GPIO1_31_ID,
73 /* GPIO2 */
74 GPIO2_0_ID = 32,
75 GPIO2_1_ID,
76 GPIO2_2_ID,
77 GPIO2_3_ID,
78 GPIO2_4_ID,
79 GPIO2_5_ID,
80 GPIO2_6_ID,
81 GPIO2_7_ID,
82 GPIO2_8_ID,
83 GPIO2_9_ID,
84 GPIO2_10_ID,
85 GPIO2_11_ID,
86 GPIO2_12_ID,
87 GPIO2_13_ID,
88 GPIO2_14_ID,
89 GPIO2_15_ID,
90 GPIO2_16_ID,
91 GPIO2_17_ID,
92 GPIO2_18_ID,
93 GPIO2_19_ID,
94 GPIO2_20_ID,
95 GPIO2_21_ID,
96 GPIO2_22_ID,
97 GPIO2_23_ID,
98 GPIO2_24_ID,
99 GPIO2_25_ID,
100 GPIO2_26_ID,
101 GPIO2_27_ID,
102 GPIO2_28_ID,
103 GPIO2_29_ID,
104 GPIO2_30_ID,
105 GPIO2_31_ID,
106 /* GPIO3 */
107 GPIO3_0_ID = 64,
108 GPIO3_1_ID,
109 GPIO3_2_ID,
110 GPIO3_3_ID,
111 GPIO3_4_ID,
112 GPIO3_5_ID,
113 GPIO3_6_ID,
114 GPIO3_7_ID,
115 GPIO3_8_ID,
116 GPIO3_9_ID,
117 GPIO3_10_ID,
118 GPIO3_11_ID,
119 GPIO3_12_ID,
120 GPIO3_13_ID,
121 GPIO3_14_ID,
122 GPIO3_15_ID,
123 GPIO3_16_ID,
124 GPIO3_17_ID,
125 GPIO3_18_ID,
126 GPIO3_19_ID,
127 GPIO3_20_ID,
128 GPIO3_21_ID,
129 GPIO3_22_ID,
130 GPIO3_23_ID,
131 GPIO3_24_ID,
132 GPIO3_25_ID,
133 GPIO3_26_ID,
134 GPIO3_27_ID,
135 GPIO3_28_ID,
136 GPIO3_29_ID,
137 GPIO3_30_ID,
138 GPIO3_31_ID,
52}; 139};
53 140
54#define GPIO_SENSE_CONFIG_MASK 0x3 141/* Possible values for gpio interrupt line config */
142enum gpio_int_sense
143{
144 GPIO_SENSE_LOW_LEVEL, /* High-level sensitive */
145 GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
146 GPIO_SENSE_RISING, /* Rising-edge sensitive */
147 GPIO_SENSE_FALLING, /* Falling-edge sensitive */
148 GPIO_SENSE_EDGE_SEL, /* Detect any edge */
149};
55 150
56/* Pending events will be called in array order which allows easy 151/* Handlers will be called in declared order for a given module
57 * pioritization */ 152 Handlers of same module should be grouped together; module order
153 doesn't matter */
154#ifdef DEFINE_GPIO_VECTOR_TABLE
58 155
59/* Describes a single event for a pin */ 156/* Describes a single event for a pin */
60struct gpio_event 157struct gpio_event
61{ 158{
62 unsigned long mask; /* mask: 1 << (0...31) */ 159 uint8_t id; /* GPIOx_y_ID */
63 enum gpio_int_sense_enum sense; /* Type of sense */ 160 uint8_t sense; /* GPIO_SENSE_x */
64 void (*callback)(void); /* Callback function */ 161 void (*callback)(void); /* GPIOx_y_EVENT_CB */
65}; 162};
66 163
67/* Module corresponding to the event ID is identified by range */ 164#define GPIO_VECTOR_TBL_START() \
68enum gpio_event_bases 165 static FORCE_INLINE uintptr_t __gpio_event_vector_tbl(int __what) \
69{ 166 { \
70#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS) 167 static const struct gpio_event __tbl[] = {
71 GPIO1_EVENT_FIRST = 32*GPIO1_NUM, 168
72#endif 169#define GPIO_EVENT_VECTOR(__name, __sense) \
73#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS) 170 { .id = (__name##_ID), \
74 GPIO2_EVENT_FIRST = 32*GPIO2_NUM, 171 .sense = (__sense), \
75#endif 172 .callback = ({ void __name##_EVENT_CB(void); \
76#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS) 173 __name##_EVENT_CB; }) },
77 GPIO3_EVENT_FIRST = 32*GPIO3_NUM, 174
78#endif 175#define GPIO_VECTOR_TBL_END() \
79}; 176 }; \
177 switch (__what) \
178 { \
179 default: return (uintptr_t)__tbl; \
180 case 1: return (uintptr_t)ARRAYLEN(__tbl); \
181 } \
182 }
80 183
81#include "gpio-target.h" 184#define gpio_event_vector_tbl \
185 ((const struct gpio_event *)__gpio_event_vector_tbl(0))
186
187#define gpio_event_vector_tbl_len \
188 ((unsigned int)__gpio_event_vector_tbl(1))
189
190#endif /* DEFINE_GPIO_VECTOR_TABLE */
191
192#define GPIO_BASE_ADDR \
193 (volatile unsigned long * const [GPIO_NUM_GPIO]) { \
194 (volatile unsigned long *)GPIO1_BASE_ADDR, \
195 (volatile unsigned long *)GPIO2_BASE_ADDR, \
196 (volatile unsigned long *)GPIO3_BASE_ADDR }
197
198#define GPIO_DR (0x00 / sizeof (unsigned long)) /* 00h */
199#define GPIO_GDIR (0x04 / sizeof (unsigned long)) /* 04h */
200#define GPIO_PSR (0x08 / sizeof (unsigned long)) /* 08h */
201#define GPIO_ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
202#define GPIO_IMR (0x14 / sizeof (unsigned long)) /* 14h */
203#define GPIO_ISR (0x18 / sizeof (unsigned long)) /* 18h */
204#define GPIO_EDGE_SEL (0x1C / sizeof (unsigned long)) /* 1Ch */
82 205
83void gpio_init(void); 206void gpio_init(void);
84bool gpio_enable_event(enum gpio_event_ids id); 207bool gpio_enable_event(enum gpio_id id, bool enable);
85void gpio_disable_event(enum gpio_event_ids id); 208
209static FORCE_INLINE void gpio_int_clear(enum gpio_id id)
210 { GPIO_BASE_ADDR[id / 32][GPIO_ISR] = 1ul << (id % 32); }
211
212static FORCE_INLINE void gpio_int_enable(enum gpio_id id)
213 { bitset32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }
214
215static FORCE_INLINE void gpio_int_disable(enum gpio_id id)
216 { bitclr32(&GPIO_BASE_ADDR[id / 32][GPIO_IMR], 1ul << (id % 32)); }
86 217
87#endif /* GPIO_IMX31_H */ 218#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 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "system.h" 21#include "system.h"
22#include "cpu.h" 22#include "cpu.h"
23#include "gpio-imx31.h" 23#define DEFINE_MC13783_VECTOR_TABLE
24#include "mc13783.h"
25#include "mc13783-target.h" 24#include "mc13783-target.h"
25#include "gpio-target.h"
26#include "debug.h" 26#include "debug.h"
27#include "kernel.h" 27#include "kernel.h"
28 28
@@ -32,21 +32,42 @@ struct mc13783_transfer_desc
32 struct spi_transfer_desc xfer; 32 struct spi_transfer_desc xfer;
33 union 33 union
34 { 34 {
35 /* Pick _either_ data or semaphore */
35 struct semaphore sema; 36 struct semaphore sema;
36 uint32_t data; 37 uint32_t data[4];
37 }; 38 };
38}; 39};
39 40
40extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS]; 41static uint32_t pmic_int_enb[2]; /* Enabled ints */
41extern struct spi_node mc13783_spi; 42static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */
43static struct mc13783_transfer_desc int_xfers[2]; /* ISR transfer descriptor */
44static const struct mc13783_event *current_event; /* Current event in callback */
45static bool int_restore; /* Prevent SPI callback from
46 unmasking GPIO interrupt
47 (lockout) */
42 48
43static uint32_t pmic_int_enb[2]; /* Enabled ints */ 49static const struct mc13783_event * event_from_id(enum mc13783_int_ids id)
44static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */ 50{
45static uint32_t int_pnd_buf[2]; /* Pending ints */ 51 for (unsigned int i = 0; i < mc13783_event_vector_tbl_len; i++)
46static uint32_t int_data_buf[4]; /* ISR data buffer */ 52 {
47static struct spi_transfer_desc int_xfers[2]; /* ISR transfer descriptor */ 53 if (mc13783_event_vector_tbl[i].id == id)
48static bool restore_event = true; /* Protect SPI callback from unmasking GPIO 54 return &mc13783_event_vector_tbl[i];
49 interrupt (lockout) */ 55 }
56
57 return NULL;
58}
59
60/* Called when a transfer is finished and data is ready/written */
61static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer)
62{
63 semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema);
64}
65
66static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer)
67{
68 return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK)
69 == OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
70}
50 71
51static inline bool mc13783_transfer(struct spi_transfer_desc *xfer, 72static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
52 uint32_t *txbuf, 73 uint32_t *txbuf,
@@ -64,90 +85,96 @@ static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
64 return spi_transfer(xfer); 85 return spi_transfer(xfer);
65} 86}
66 87
67/* Called when a transfer is finished and data is ready/written */ 88static inline void sync_transfer_init(struct mc13783_transfer_desc *xfer)
68static void mc13783_xfer_complete_cb(struct spi_transfer_desc *xfer)
69{ 89{
70 semaphore_release(&((struct mc13783_transfer_desc *)xfer)->sema); 90 semaphore_init(&xfer->sema, 1, 0);
71} 91}
72 92
73static inline bool wait_for_transfer_complete(struct mc13783_transfer_desc *xfer) 93static inline bool mc13783_sync_transfer(struct mc13783_transfer_desc *xfer,
94 uint32_t *txbuf,
95 uint32_t *rxbuf,
96 int count)
74{ 97{
75 return semaphore_wait(&xfer->sema, TIMEOUT_BLOCK) 98 sync_transfer_init(xfer);
76 == OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0; 99 return mc13783_transfer(&xfer->xfer, txbuf, rxbuf, count, mc13783_xfer_complete_cb);
77} 100}
78 101
79/* Efficient interrupt status and acking */ 102/* Efficient interrupt status and acking */
80static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer) 103static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer)
81{ 104{
105 struct mc13783_transfer_desc *desc1 = (struct mc13783_transfer_desc *)xfer;
106 uint32_t pnd0 = desc1->data[0], pnd1 = desc1->data[1];
107
82 /* Restore PMIC interrupt events */ 108 /* Restore PMIC interrupt events */
83 if (restore_event) 109 if (int_restore)
84 bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); 110 gpio_int_enable(MC13783_EVENT_ID);
85 111
86 /* Call handlers */ 112 /* Call handlers */
87 for ( 113 const struct mc13783_event *event = mc13783_event_vector_tbl;
88 const struct mc13783_event *event = mc13783_events; 114 while (pnd0 | pnd1)
89 int_pnd_buf[0] | int_pnd_buf[1];
90 event++
91 )
92 { 115 {
93 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; 116 uint32_t id = event->id;
94 uint32_t pnd = int_pnd_buf[set]; 117 uint32_t set = id / 32;
95 uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK); 118 uint32_t bit = 1 << (id % 32);
96 119
97 if (pnd & mask) 120 uint32_t pnd = set == 0 ? pnd0 : pnd1;
121 if (pnd & bit)
98 { 122 {
123 current_event = event;
99 event->callback(); 124 event->callback();
100 int_pnd_buf[set] = pnd & ~mask; 125 set == 0 ? (pnd0 &= ~bit) : (pnd1 &= ~bit);
101 } 126 }
102 }
103 127
104 (void)xfer; 128 event++;
129 }
105} 130}
106 131
107static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer) 132static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer)
108{ 133{
109 /* Only clear interrupts with handlers */ 134 /* Only clear interrupts with handlers */
110 int_pnd_buf[0] &= pmic_int_enb[0]; 135 struct mc13783_transfer_desc *desc0 = (struct mc13783_transfer_desc *)xfer;
111 int_pnd_buf[1] &= pmic_int_enb[1]; 136 struct mc13783_transfer_desc *desc1 = &int_xfers[1];
112 137
113 /* Only read sense if enabled interrupts have them enabled */ 138 uint32_t pnd0 = desc0->data[0] & pmic_int_enb[0];
114 if ((int_pnd_buf[0] & pmic_int_sense_enb[0]) || 139 uint32_t pnd1 = desc0->data[1] & pmic_int_enb[1];
115 (int_pnd_buf[1] & pmic_int_sense_enb[1])) 140
116 { 141 desc1->data[0] = pnd0;
117 int_data_buf[2] = MC13783_INTERRUPT_SENSE0 << 25; 142 desc1->data[1] = pnd1;
118 int_data_buf[3] = MC13783_INTERRUPT_SENSE1 << 25;
119 int_xfers[1].rxbuf = int_data_buf;
120 int_xfers[1].count = 4;
121 }
122 143
123 /* Setup the write packets with status(es) to clear */ 144 /* Setup the write packets with status(es) to clear */
124 int_data_buf[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) 145 desc0->data[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) | pnd0;
125 | int_pnd_buf[0]; 146 desc0->data[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) | pnd1;
126 int_data_buf[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) 147
127 | int_pnd_buf[1]; 148 /* Only read sense if any pending interrupts have them enabled */
128 (void)xfer; 149 if ((pnd0 & pmic_int_sense_enb[0]) || (pnd1 & pmic_int_sense_enb[1]))
150 {
151 desc0->data[2] = MC13783_INTERRUPT_SENSE0 << 25;
152 desc0->data[3] = MC13783_INTERRUPT_SENSE1 << 25;
153 desc1->xfer.rxbuf = desc0->data;
154 desc1->xfer.count = 4;
155 }
129} 156}
130 157
131/* GPIO interrupt handler for mc13783 */ 158/* GPIO interrupt handler for mc13783 */
132void mc13783_event(void) 159void INT_MC13783(void)
133{ 160{
134 /* Mask the interrupt (unmasked after final read services it). */ 161 /* Mask the interrupt (unmasked after final read services it). */
135 bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); 162 gpio_int_disable(MC13783_EVENT_ID);
136 MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); 163 gpio_int_clear(MC13783_EVENT_ID);
137 164
138 /* Setup the read packets */ 165 /* Setup the read packets */
139 int_pnd_buf[0] = MC13783_INTERRUPT_STATUS0 << 25; 166 int_xfers[0].data[0] = MC13783_INTERRUPT_STATUS0 << 25;
140 int_pnd_buf[1] = MC13783_INTERRUPT_STATUS1 << 25; 167 int_xfers[0].data[1] = MC13783_INTERRUPT_STATUS1 << 25;
141 168
142 unsigned long cpsr = disable_irq_save(); 169 unsigned long cpsr = disable_irq_save();
143 170
144 /* Do these without intervening transfers */ 171 /* Do these without intervening transfers */
145 if (mc13783_transfer(&int_xfers[0], int_pnd_buf, int_pnd_buf, 2, 172 if (mc13783_transfer(&int_xfers[0].xfer, int_xfers[0].data,
146 mc13783_int_svc_callback)) 173 int_xfers[0].data, 2, mc13783_int_svc_callback))
147 { 174 {
148 /* Start this provisionally and fill-in actual values during the 175 /* Start this provisionally and fill-in actual values during the
149 first transfer's callback - set whatever could be known */ 176 first transfer's callback - set whatever could be known */
150 mc13783_transfer(&int_xfers[1], int_data_buf, NULL, 2, 177 mc13783_transfer(&int_xfers[1].xfer, int_xfers[0].data, NULL, 2,
151 mc13783_int_svc_complete_callback); 178 mc13783_int_svc_complete_callback);
152 } 179 }
153 180
@@ -166,43 +193,45 @@ void INIT_ATTR mc13783_init(void)
166 mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff); 193 mc13783_write(MC13783_INTERRUPT_MASK0, 0xffffff);
167 mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff); 194 mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
168 195
169 MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); 196 gpio_int_clear(MC13783_EVENT_ID);
170 gpio_enable_event(MC13783_EVENT_ID); 197 gpio_enable_event(MC13783_EVENT_ID, true);
171} 198}
172 199
173void mc13783_close(void) 200void mc13783_close(void)
174{ 201{
175 restore_event = false; 202 int_restore = false;
176 gpio_disable_event(MC13783_EVENT_ID); 203 gpio_int_disable(MC13783_EVENT_ID);
204 gpio_enable_event(MC13783_EVENT_ID, false);
177 spi_enable_node(&mc13783_spi, false); 205 spi_enable_node(&mc13783_spi, false);
178} 206}
179 207
180void mc13783_enable_event(enum mc13783_event_ids id, bool enable) 208void mc13783_enable_event(enum mc13783_int_ids id, bool enable)
181{ 209{
182 static const unsigned char pmic_intm_regs[2] = 210 static const unsigned char pmic_intm_regs[2] =
183 { MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 }; 211 { MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 };
184 212
185 const struct mc13783_event * const event = &mc13783_events[id]; 213 const struct mc13783_event * const event = event_from_id(id);
186 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; 214 if (event == NULL)
187 uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK); 215 return;
216
217 unsigned int set = id / 32;
218 uint32_t mask = 1 << (id % 32);
219 uint32_t bit = enable ? mask : 0;
188 220
189 /* Mask GPIO while changing bits around */ 221 /* Mask GPIO while changing bits around */
190 restore_event = false; 222 int_restore = false;
191 bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE); 223 gpio_int_disable(MC13783_EVENT_ID);
192 mc13783_write_masked(pmic_intm_regs[set], 224 mc13783_write_masked(pmic_intm_regs[set], bit ^ mask, mask);
193 enable ? 0 : mask, mask); 225 bitmod32(&pmic_int_sense_enb[set], event->sense ? bit : 0, mask);
194 bitmod32(&pmic_int_enb[set], enable ? mask : 0, mask); 226 bitmod32(&pmic_int_enb[set], bit, mask);
195 bitmod32(&pmic_int_sense_enb[set], enable ? event->sense : 0, 227 int_restore = true;
196 event->sense); 228 gpio_int_enable(MC13783_EVENT_ID);
197 restore_event = true;
198 bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
199} 229}
200 230
201uint32_t mc13783_event_sense(enum mc13783_event_ids id) 231uint32_t mc13783_event_sense(void)
202{ 232{
203 const struct mc13783_event * const event = &mc13783_events[id]; 233 const struct mc13783_event *event = current_event;
204 unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV; 234 return int_xfers[0].data[2 + event->id / 32] & event->sense;
205 return int_data_buf[2 + set] & event->sense;
206} 235}
207 236
208uint32_t mc13783_set(unsigned address, uint32_t bits) 237uint32_t mc13783_set(unsigned address, uint32_t bits)
@@ -219,8 +248,7 @@ uint32_t mc13783_clear(unsigned address, uint32_t bits)
219static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer) 248static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer)
220{ 249{
221 struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer; 250 struct mc13783_transfer_desc *desc = (struct mc13783_transfer_desc *)xfer;
222 uint32_t *packets = desc->xfer.rxbuf; /* Will have been advanced by 1 */ 251 desc->data[1] |= desc->data[0] & desc->data[2]; /* & ~mask */
223 packets[0] |= packets[-1] & ~desc->data;
224} 252}
225 253
226uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t mask) 254uint32_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)
230 258
231 mask &= 0xffffff; 259 mask &= 0xffffff;
232 260
233 uint32_t packets[2] =
234 {
235 address << 25,
236 (1 << 31) | (address << 25) | (data & mask)
237 };
238
239 struct mc13783_transfer_desc xfers[2]; 261 struct mc13783_transfer_desc xfers[2];
240 xfers[0].data = mask; 262 xfers[0].data[0] = address << 25;
241 semaphore_init(&xfers[1].sema, 1, 0); 263 xfers[0].data[1] = (1 << 31) | (address << 25) | (data & mask);
264 xfers[0].data[2] = ~mask;
242 265
243 unsigned long cpsr = disable_irq_save(); 266 unsigned long cpsr = disable_irq_save();
244 267
245 /* Queue up two transfers in a row */ 268 /* Queue up two transfers in a row */
246 bool ok = mc13783_transfer(&xfers[0].xfer, &packets[0], &packets[0], 1, 269 bool ok = mc13783_transfer(&xfers[0].xfer,
270 &xfers[0].data[0], &xfers[0].data[0], 1,
247 mc13783_write_masked_cb) && 271 mc13783_write_masked_cb) &&
248 mc13783_transfer(&xfers[1].xfer, &packets[1], NULL, 1, 272 mc13783_sync_transfer(&xfers[1], &xfers[0].data[1], NULL, 1);
249 mc13783_xfer_complete_cb);
250 273
251 restore_irq(cpsr); 274 restore_irq(cpsr);
252 275
253 if (ok && wait_for_transfer_complete(&xfers[1])) 276 if (ok && wait_for_transfer_complete(&xfers[1]))
254 return packets[0]; 277 return xfers[0].data[0];
255 278
256 return MC13783_DATA_ERROR; 279 return MC13783_DATA_ERROR;
257} 280}
@@ -264,10 +287,7 @@ uint32_t mc13783_read(unsigned address)
264 uint32_t packet = address << 25; 287 uint32_t packet = address << 25;
265 288
266 struct mc13783_transfer_desc xfer; 289 struct mc13783_transfer_desc xfer;
267 semaphore_init(&xfer.sema, 1, 0); 290 if (mc13783_sync_transfer(&xfer, &packet, &packet, 1) &&
268
269 if (mc13783_transfer(&xfer.xfer, &packet, &packet, 1,
270 mc13783_xfer_complete_cb) &&
271 wait_for_transfer_complete(&xfer)) 291 wait_for_transfer_complete(&xfer))
272 { 292 {
273 return packet; 293 return packet;
@@ -284,10 +304,7 @@ int mc13783_write(unsigned address, uint32_t data)
284 uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff); 304 uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff);
285 305
286 struct mc13783_transfer_desc xfer; 306 struct mc13783_transfer_desc xfer;
287 semaphore_init(&xfer.sema, 1, 0); 307 if (mc13783_sync_transfer(&xfer, &packet, NULL, 1) &&
288
289 if (mc13783_transfer(&xfer.xfer, &packet, NULL, 1,
290 mc13783_xfer_complete_cb) &&
291 wait_for_transfer_complete(&xfer)) 308 wait_for_transfer_complete(&xfer))
292 { 309 {
293 return 1 - xfer.xfer.count; 310 return 1 - xfer.xfer.count;
@@ -300,7 +317,7 @@ int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer,
300 int count) 317 int count)
301{ 318{
302 struct mc13783_transfer_desc xfer; 319 struct mc13783_transfer_desc xfer;
303 semaphore_init(&xfer.sema, 1, 0); 320 sync_transfer_init(&xfer);
304 321
305 if (mc13783_read_async(&xfer.xfer, regs, buffer, count, 322 if (mc13783_read_async(&xfer.xfer, regs, buffer, count,
306 mc13783_xfer_complete_cb) && 323 mc13783_xfer_complete_cb) &&
@@ -316,7 +333,7 @@ int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer,
316 int count) 333 int count)
317{ 334{
318 struct mc13783_transfer_desc xfer; 335 struct mc13783_transfer_desc xfer;
319 semaphore_init(&xfer.sema, 1, 0); 336 sync_transfer_init(&xfer);
320 337
321 if (mc13783_write_async(&xfer.xfer, regs, buffer, count, 338 if (mc13783_write_async(&xfer.xfer, regs, buffer, count,
322 mc13783_xfer_complete_cb) && 339 mc13783_xfer_complete_cb) &&