mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-09 21:22:39 -05:00
Improve imx31 interrupt code for PMIC and GPIO
Fix stuff that was bugging me about the way I did it at first. While messing around I found RDS code wasn't masking its GPIO ISR as it should, which might lead to two different interrupts messing with the static data. Change-Id: I54626809ea3039a842af0cc9e3e42853326c4193
This commit is contained in:
parent
d4303ac900
commit
2220a4b695
19 changed files with 552 additions and 485 deletions
|
|
@ -1139,10 +1139,8 @@ target/arm/imx31/uart-imx31.c
|
||||||
target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
|
target/arm/imx31/gigabeat-s/adc-gigabeat-s.c
|
||||||
target/arm/imx31/gigabeat-s/backlight-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/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/kernel-gigabeat-s.c
|
||||||
target/arm/imx31/gigabeat-s/i2s-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/power-gigabeat-s.c
|
||||||
target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
|
target/arm/imx31/gigabeat-s/powermgmt-gigabeat-s.c
|
||||||
target/arm/imx31/gigabeat-s/system-gigabeat-s.c
|
target/arm/imx31/gigabeat-s/system-gigabeat-s.c
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,6 @@
|
||||||
|
|
||||||
#define AB_REPEAT_ENABLE
|
#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 this if you have the WM8978 audio codec */
|
||||||
#define HAVE_WM8978
|
#define HAVE_WM8978
|
||||||
|
|
||||||
|
|
@ -124,6 +118,10 @@
|
||||||
#define HAVE_LCD_ENABLE
|
#define HAVE_LCD_ENABLE
|
||||||
|
|
||||||
#ifndef BOOTLOADER
|
#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 this if you can flip your LCD */
|
||||||
#define HAVE_LCD_FLIP
|
#define HAVE_LCD_FLIP
|
||||||
|
|
|
||||||
|
|
@ -1256,9 +1256,6 @@ enum mc13783_regs_enum
|
||||||
#define MC13783_TC3PERIOD_POS (21)
|
#define MC13783_TC3PERIOD_POS (21)
|
||||||
#define MC13783_TC3TRIODE (0x1 << 23)
|
#define MC13783_TC3TRIODE (0x1 << 23)
|
||||||
|
|
||||||
/* For event enum values which are target-defined */
|
|
||||||
#include "mc13783-target.h"
|
|
||||||
|
|
||||||
void mc13783_init(void);
|
void mc13783_init(void);
|
||||||
void mc13783_close(void);
|
void mc13783_close(void);
|
||||||
uint32_t mc13783_set(unsigned address, uint32_t bits);
|
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_CHGSHORT = 9,
|
||||||
MC13783_INT_ID_CCCV = 10,
|
MC13783_INT_ID_CCCV = 10,
|
||||||
MC13783_INT_ID_CHGCURR = 11,
|
MC13783_INT_ID_CHGCURR = 11,
|
||||||
MC13783_INT_ID_BPONI = 12,
|
MC13783_INT_ID_BPON = 12,
|
||||||
MC13783_INT_ID_LOBATL = 13,
|
MC13783_INT_ID_LOBATL = 13,
|
||||||
MC13783_INT_ID_LOBATH = 14,
|
MC13783_INT_ID_LOBATH = 14,
|
||||||
MC13783_INT_ID_UDP = 15,
|
MC13783_INT_ID_UDP = 15,
|
||||||
|
|
@ -1306,41 +1303,70 @@ enum mc13783_int_ids
|
||||||
MC13783_INT_ID_CKDET = 22,
|
MC13783_INT_ID_CKDET = 22,
|
||||||
MC13783_INT_ID_UDM = 23,
|
MC13783_INT_ID_UDM = 23,
|
||||||
/* *STATUS1/MASK1/SENSE1 */
|
/* *STATUS1/MASK1/SENSE1 */
|
||||||
MC13783_INT_ID_1HZ = 0 + 0x20,
|
MC13783_INT_ID_1HZ = 0 + 32,
|
||||||
MC13783_INT_ID_TODA = 1 + 0x20,
|
MC13783_INT_ID_TODA = 1 + 32,
|
||||||
MC13783_INT_ID_ONOFD1 = 3 + 0x20, /* ON1B */
|
MC13783_INT_ID_ONOFD1 = 3 + 32, /* ON1B */
|
||||||
MC13783_INT_ID_ONOFD2 = 4 + 0x20, /* ON2B */
|
MC13783_INT_ID_ONOFD2 = 4 + 32, /* ON2B */
|
||||||
MC13783_INT_ID_ONOFD3 = 5 + 0x20, /* ON3B */
|
MC13783_INT_ID_ONOFD3 = 5 + 32, /* ON3B */
|
||||||
MC13783_INT_ID_SYSRST = 6 + 0x20,
|
MC13783_INT_ID_SYSRST = 6 + 32,
|
||||||
MC13783_INT_ID_RTCRST = 7 + 0x20,
|
MC13783_INT_ID_RTCRST = 7 + 32,
|
||||||
MC13783_INT_ID_PCI = 8 + 0x20,
|
MC13783_INT_ID_PCI = 8 + 32,
|
||||||
MC13783_INT_ID_WARM = 9 + 0x20,
|
MC13783_INT_ID_WARM = 9 + 32,
|
||||||
MC13783_INT_ID_MEMHLD = 10 + 0x20,
|
MC13783_INT_ID_MEMHLD = 10 + 32,
|
||||||
MC13783_INT_ID_PWRRDY = 11 + 0x20,
|
MC13783_INT_ID_PWRRDY = 11 + 32,
|
||||||
MC13783_INT_ID_THWARNL = 12 + 0x20,
|
MC13783_INT_ID_THWARNL = 12 + 32,
|
||||||
MC13783_INT_ID_THWARNH = 13 + 0x20,
|
MC13783_INT_ID_THWARNH = 13 + 32,
|
||||||
MC13783_INT_ID_CLK = 14 + 0x20,
|
MC13783_INT_ID_CLK = 14 + 32,
|
||||||
MC13783_INT_ID_SEMAF = 15 + 0x20,
|
MC13783_INT_ID_SEMAF = 15 + 32,
|
||||||
MC13783_INT_ID_MC2B = 17 + 0x20,
|
MC13783_INT_ID_MC2B = 17 + 32,
|
||||||
MC13783_INT_ID_HSDET = 18 + 0x20,
|
MC13783_INT_ID_HSDET = 18 + 32,
|
||||||
MC13783_INT_ID_HSL = 19 + 0x20,
|
MC13783_INT_ID_HSL = 19 + 32,
|
||||||
MC13783_INT_ID_ALSPTH = 20 + 0x20,
|
MC13783_INT_ID_ALSPTH = 20 + 32,
|
||||||
MC13783_INT_ID_AHSSHORT = 21 + 0x20,
|
MC13783_INT_ID_AHSSHORT = 21 + 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MC13783_INT_ID_SET_DIV (0x20)
|
#ifdef DEFINE_MC13783_VECTOR_TABLE
|
||||||
#define MC13783_INT_ID_NUM_MASK (0x1f)
|
|
||||||
|
|
||||||
struct mc13783_event
|
struct mc13783_event
|
||||||
{
|
{
|
||||||
enum mc13783_int_ids int_id : 8;
|
uint32_t id : 8; /* MC13783_INT_ID_x */
|
||||||
uint32_t sense : 24;
|
uint32_t sense : 24; /* MC13783_xS */
|
||||||
void (*callback)(void);
|
void (*callback)(void); /* MC13783_EVENT_CB_x */
|
||||||
};
|
};
|
||||||
|
|
||||||
void mc13783_enable_event(enum mc13783_event_ids id, bool enable);
|
/* Declares vector table. Order-implied priority */
|
||||||
|
#define MC13783_EVENT_VECTOR_TBL_START() \
|
||||||
|
static FORCE_INLINE uintptr_t __mc13783_event_vector_tbl(int __what) \
|
||||||
|
{ \
|
||||||
|
static const struct mc13783_event __tbl[] = {
|
||||||
|
|
||||||
/* Read the sense bit if one exists - valid only within event handlers */
|
#define MC13783_EVENT_VECTOR(__name, __sense) \
|
||||||
uint32_t mc13783_event_sense(enum mc13783_event_ids id);
|
{ .id = MC13783_INT_ID_##__name, \
|
||||||
|
.sense = (__sense), \
|
||||||
|
.callback = ({ void MC13783_EVENT_CB_##__name(void); \
|
||||||
|
MC13783_EVENT_CB_##__name; }) },
|
||||||
|
|
||||||
|
#define MC13783_EVENT_VECTOR_TBL_END() \
|
||||||
|
}; \
|
||||||
|
switch (__what) \
|
||||||
|
{ \
|
||||||
|
default: return (uintptr_t)__tbl; \
|
||||||
|
case 1: return (uintptr_t)ARRAYLEN(__tbl); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define mc13783_event_vector_tbl \
|
||||||
|
((const struct mc13783_event *)__mc13783_event_vector_tbl(0))
|
||||||
|
|
||||||
|
#define mc13783_event_vector_tbl_len \
|
||||||
|
((unsigned int)__mc13783_event_vector_tbl(1))
|
||||||
|
|
||||||
|
#endif /* DEFINE_MC13783_VECTOR_TABLE */
|
||||||
|
|
||||||
|
void mc13783_enable_event(enum mc13783_int_ids id, bool enable);
|
||||||
|
|
||||||
|
/* Read the sense bit(s) if configured - valid only within the respective
|
||||||
|
event handler */
|
||||||
|
uint32_t mc13783_event_sense(void);
|
||||||
|
|
||||||
#endif /* _MC13783_H_ */
|
#endif /* _MC13783_H_ */
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ bool adc_enable_channel(int channel, bool enable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ADC conversion complete event - called from PMIC ISR */
|
/* ADC conversion complete event - called from PMIC ISR */
|
||||||
void adc_done(void)
|
void MC13783_EVENT_CB_ADCDONE(void)
|
||||||
{
|
{
|
||||||
semaphore_release(&adc_done_signal);
|
semaphore_release(&adc_done_signal);
|
||||||
}
|
}
|
||||||
|
|
@ -132,5 +132,5 @@ void adc_init(void)
|
||||||
|
|
||||||
/* Enable ADCDONE event */
|
/* Enable ADCDONE event */
|
||||||
mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI);
|
mc13783_write(MC13783_INTERRUPT_STATUS0, MC13783_ADCDONEI);
|
||||||
mc13783_enable_event(MC13783_ADCDONE_EVENT, true);
|
mc13783_enable_event(MC13783_INT_ID_ADCDONE, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@
|
||||||
#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
|
#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
|
||||||
#define ADC_READ_ERROR 0xFFFF
|
#define ADC_READ_ERROR 0xFFFF
|
||||||
|
|
||||||
void adc_done(void);
|
|
||||||
/* Enable conversion of specified channel (if switchoff is possible) */
|
/* Enable conversion of specified channel (if switchoff is possible) */
|
||||||
bool adc_enable_channel(int channel, bool enable);
|
bool adc_enable_channel(int channel, bool enable);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,9 +157,9 @@ static void power_button_update(bool pressed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Power button event - called from PMIC ISR */
|
/* 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)
|
void button_init_device(void)
|
||||||
|
|
@ -197,7 +197,7 @@ void button_init_device(void)
|
||||||
|
|
||||||
power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1)
|
power_button_update(!(mc13783_read(MC13783_INTERRUPT_SENSE1)
|
||||||
& MC13783_ONOFD1S));
|
& MC13783_ONOFD1S));
|
||||||
mc13783_enable_event(MC13783_ONOFD1_EVENT, true);
|
mc13783_enable_event(MC13783_INT_ID_ONOFD1, true);
|
||||||
|
|
||||||
#ifdef HAVE_HEADPHONE_DETECTION
|
#ifdef HAVE_HEADPHONE_DETECTION
|
||||||
headphone_init();
|
headphone_init();
|
||||||
|
|
@ -213,7 +213,7 @@ void button_close_device(void)
|
||||||
/* Assumes HP detection is not available */
|
/* Assumes HP detection is not available */
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
|
||||||
mc13783_enable_event(MC13783_ONOFD1_EVENT, false);
|
mc13783_enable_event(MC13783_INT_ID_ONOFD1, false);
|
||||||
ext_btn = BUTTON_NONE;
|
ext_btn = BUTTON_NONE;
|
||||||
}
|
}
|
||||||
#endif /* BUTTON_DRIVER_CLOSE */
|
#endif /* BUTTON_DRIVER_CLOSE */
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void button_close_device(void);
|
void button_close_device(void);
|
||||||
void button_power_event(void);
|
|
||||||
void headphone_detect_event(void);
|
|
||||||
void headphone_init(void);
|
void headphone_init(void);
|
||||||
void button_headphone_set(int button);
|
void button_headphone_set(int button);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "mc13783.h"
|
#include "mc13783.h"
|
||||||
#include "iomuxc-imx31.h"
|
#include "iomuxc-imx31.h"
|
||||||
#include "gpio-imx31.h"
|
#include "gpio-target.h"
|
||||||
#include "i2c-imx31.h"
|
#include "i2c-imx31.h"
|
||||||
#include "fmradio_i2c.h"
|
#include "fmradio_i2c.h"
|
||||||
#include "rds.h"
|
#include "rds.h"
|
||||||
|
|
@ -139,20 +139,25 @@ static struct si4700_i2c_transfer_desc
|
||||||
.xfer = { .node = &si4700_i2c_node }
|
.xfer = { .node = &si4700_i2c_node }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool int_restore;
|
||||||
|
|
||||||
static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
|
static void si4700_rds_read_raw_callback(struct i2c_transfer_desc *xfer)
|
||||||
{
|
{
|
||||||
struct si4700_i2c_transfer_desc *xf =
|
struct si4700_i2c_transfer_desc *xf =
|
||||||
(struct si4700_i2c_transfer_desc *)xfer;
|
(struct si4700_i2c_transfer_desc *)xfer;
|
||||||
|
|
||||||
if (xfer->rxcount != 0)
|
if (xfer->rxcount == 0)
|
||||||
return; /* Read didn't finish */
|
{
|
||||||
|
uint16_t rds_data[4];
|
||||||
|
si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
|
||||||
|
|
||||||
uint16_t rds_data[4];
|
if (rds_process(rds_data))
|
||||||
|
si4700_rds_set_event();
|
||||||
|
}
|
||||||
|
/* else read didn't finish */
|
||||||
|
|
||||||
si4700_rds_read_raw_async_complete(xf->regbuf, rds_data);
|
if (int_restore)
|
||||||
|
gpio_int_enable(SI4700_EVENT_ID);
|
||||||
if (rds_process(rds_data))
|
|
||||||
si4700_rds_set_event();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback from si4700_rds_read_raw to execute the read */
|
/* 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 */
|
/* RDS GPIO interrupt handler - start RDS data read */
|
||||||
void si4700_stc_rds_event(void)
|
void INT_SI4700_RDS(void)
|
||||||
{
|
{
|
||||||
/* read and clear the interrupt */
|
/* mask and clear the interrupt */
|
||||||
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
|
gpio_int_disable(SI4700_EVENT_ID);
|
||||||
|
gpio_int_clear(SI4700_EVENT_ID);
|
||||||
|
|
||||||
|
/* read the RDS data */
|
||||||
si4700_rds_read_raw_async();
|
si4700_rds_read_raw_async();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,13 +188,10 @@ void si4700_stc_rds_event(void)
|
||||||
powering down */
|
powering down */
|
||||||
void si4700_rds_powerup(bool on)
|
void si4700_rds_powerup(bool on)
|
||||||
{
|
{
|
||||||
gpio_disable_event(SI4700_STC_RDS_EVENT_ID);
|
int_restore = on;
|
||||||
|
gpio_int_disable(SI4700_EVENT_ID);
|
||||||
if (on)
|
gpio_int_clear(SI4700_EVENT_ID);
|
||||||
{
|
gpio_enable_event(SI4700_EVENT_ID, on);
|
||||||
SI4700_GPIO_STC_RDS_ISR = (1ul << SI4700_GPIO_STC_RDS_LINE);
|
|
||||||
gpio_enable_event(SI4700_STC_RDS_EVENT_ID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One-time RDS init at startup */
|
/* One-time RDS init at startup */
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
|
@ -23,34 +23,33 @@
|
||||||
#ifndef GPIO_TARGET_H
|
#ifndef GPIO_TARGET_H
|
||||||
#define GPIO_TARGET_H
|
#define GPIO_TARGET_H
|
||||||
|
|
||||||
/* MC13783 GPIO pin info for this target */
|
/* Gigabeat S definitions for static GPIO event registration */
|
||||||
#define MC13783_GPIO_IMR GPIO1_IMR
|
#include "gpio-imx31.h"
|
||||||
#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 */
|
#ifdef DEFINE_GPIO_VECTOR_TABLE
|
||||||
#define SI4700_GPIO_STC_RDS_IMR GPIO1_IMR
|
|
||||||
#define SI4700_GPIO_STC_RDS_NUM GPIO1_NUM
|
GPIO_VECTOR_TBL_START()
|
||||||
#define SI4700_GPIO_STC_RDS_ISR GPIO1_ISR
|
/* mc13783 keeps the PRIINT high (no low pulse) if other unmasked
|
||||||
#define SI4700_GPIO_STC_RDS_LINE 27
|
* 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
|
#define GPIO1_INT_PRIO INT_PRIO_DEFAULT
|
||||||
|
|
||||||
/* Declare event indexes in priority order in a packed array */
|
#endif /* DEFINE_GPIO_VECTOR_TABLE */
|
||||||
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);
|
#define INT_MC13783 GPIO1_31_EVENT_CB
|
||||||
void si4700_stc_rds_event(void);
|
#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 */
|
#endif /* GPIO_TARGET_H */
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "mc13783.h"
|
#include "mc13783.h"
|
||||||
#include "mc13783-target.h"
|
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
|
|
||||||
|
|
@ -146,7 +145,7 @@ static void NORETURN_ATTR headphone_thread(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HP plugged/unplugged event - called from PMIC ISR */
|
/* HP plugged/unplugged event - called from PMIC ISR */
|
||||||
void headphone_detect_event(void)
|
void MC13783_EVENT_CB_ONOFD2(void)
|
||||||
{
|
{
|
||||||
/* Trigger the thread immediately. */
|
/* Trigger the thread immediately. */
|
||||||
semaphore_release(&headphone_wakeup);
|
semaphore_release(&headphone_wakeup);
|
||||||
|
|
@ -170,5 +169,5 @@ void INIT_ATTR headphone_init(void)
|
||||||
IF_COP(, CPU));
|
IF_COP(, CPU));
|
||||||
|
|
||||||
/* Enable PMIC event */
|
/* Enable PMIC event */
|
||||||
mc13783_enable_event(MC13783_ONOFD2_EVENT, true);
|
mc13783_enable_event(MC13783_INT_ID_ONOFD2, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
|
@ -23,17 +23,41 @@
|
||||||
#ifndef MC13783_TARGET_H
|
#ifndef MC13783_TARGET_H
|
||||||
#define MC13783_TARGET_H
|
#define MC13783_TARGET_H
|
||||||
|
|
||||||
/* Declare event indexes in priority order in a packed array */
|
#include "mc13783.h"
|
||||||
enum mc13783_event_ids
|
|
||||||
|
#ifdef DEFINE_MC13783_VECTOR_TABLE
|
||||||
|
|
||||||
|
/* Gigabeat S mc13783 serial interface node. */
|
||||||
|
static struct spi_node mc13783_spi =
|
||||||
{
|
{
|
||||||
MC13783_ADCDONE_EVENT = 0, /* ADC conversion complete */
|
/* Based upon original firmware settings */
|
||||||
MC13783_ONOFD1_EVENT, /* Power button */
|
CSPI2_NUM, /* CSPI module 2 */
|
||||||
#ifdef HAVE_HEADPHONE_DETECTION
|
CSPI_CONREG_CHIP_SELECT_SS0 | /* Chip select 0 */
|
||||||
MC13783_ONOFD2_EVENT, /* Headphone jack */
|
CSPI_CONREG_DRCTL_DONT_CARE | /* Don't care about CSPI_RDY */
|
||||||
#endif
|
CSPI_CONREG_DATA_RATE_DIV_32 | /* Clock = IPG_CLK/32 = 2,062,500Hz. */
|
||||||
MC13783_SE1_EVENT, /* Main charger detection */
|
CSPI_BITCOUNT(32-1) | /* All 32 bits are to be transferred */
|
||||||
MC13783_USB_EVENT, /* USB insertion */
|
CSPI_CONREG_SSPOL | /* SS active high */
|
||||||
MC13783_NUM_EVENTS,
|
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 */
|
#endif /* MC13783_TARGET_H */
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@ static void update_main_charger(bool present)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect changes in presence of the AC adaptor. Called from PMIC ISR. */
|
/* 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. */
|
/* Detect changes in USB bus power. Called from usb connect event ISR. */
|
||||||
|
|
@ -159,5 +159,5 @@ void power_init(void)
|
||||||
& MC13783_SE1S);
|
& MC13783_SE1S);
|
||||||
|
|
||||||
/* Enable detect event */
|
/* Enable detect event */
|
||||||
mc13783_enable_event(MC13783_SE1_EVENT, true);
|
mc13783_enable_event(MC13783_INT_ID_SE1, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
#ifndef POWER_IMX31_H
|
#ifndef POWER_IMX31_H
|
||||||
#define POWER_IMX31_H
|
#define POWER_IMX31_H
|
||||||
|
|
||||||
void charger_main_detect_event(void);
|
|
||||||
void charger_usb_detect_event(int status);
|
void charger_usb_detect_event(int status);
|
||||||
|
|
||||||
#endif /* POWER_IMX31_H */
|
#endif /* POWER_IMX31_H */
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,10 @@ static void update_usb_status(bool sense)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect presence of USB bus - called from PMIC ISR */
|
/* 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 */
|
/* Read the associated sense value */
|
||||||
update_usb_status(mc13783_event_sense(MC13783_USB_EVENT));
|
update_usb_status(mc13783_event_sense());
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_detect(void)
|
int usb_detect(void)
|
||||||
|
|
@ -90,7 +90,7 @@ void usb_init_device(void)
|
||||||
update_usb_status(usb_plugged());
|
update_usb_status(usb_plugged());
|
||||||
|
|
||||||
/* Enable PMIC event */
|
/* Enable PMIC event */
|
||||||
mc13783_enable_event(MC13783_USB_EVENT, true);
|
mc13783_enable_event(MC13783_INT_ID_USB, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_enable(bool on)
|
void usb_enable(bool on)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "avic-imx31.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 */
|
/* UIE vector found in avic-imx31.c */
|
||||||
extern void UIE_VECTOR(void);
|
extern void UIE_VECTOR(void);
|
||||||
|
|
@ -31,101 +32,91 @@ extern void UIE_VECTOR(void);
|
||||||
/* Event lists are allocated for the specific target */
|
/* Event lists are allocated for the specific target */
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
||||||
static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
|
static __attribute__((interrupt("IRQ"))) void GPIO1_HANDLER(void);
|
||||||
extern const struct gpio_event gpio1_events[GPIO1_NUM_EVENTS];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
||||||
static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
|
static __attribute__((interrupt("IRQ"))) void GPIO2_HANDLER(void);
|
||||||
extern const struct gpio_event gpio2_events[GPIO2_NUM_EVENTS];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
||||||
static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
|
static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void);
|
||||||
extern const struct gpio_event gpio3_events[GPIO3_NUM_EVENTS];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DR (0x00 / sizeof (unsigned long)) /* 00h */
|
static struct gpio_module_desc
|
||||||
#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
|
|
||||||
{
|
{
|
||||||
volatile unsigned long * const base; /* Module base address */
|
volatile unsigned long * const base; /* Module base address */
|
||||||
void (* const handler)(void); /* Interrupt function */
|
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 ints; /* AVIC int number */
|
||||||
const uint8_t int_priority; /* AVIC int priority */
|
const uint8_t int_priority; /* AVIC int priority */
|
||||||
const uint8_t count; /* Number of events */
|
uint8_t count; /* Number of events */
|
||||||
} gpio_descs[GPIO_NUM_GPIO] =
|
} * const gpio_descs[] =
|
||||||
{
|
{
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
||||||
{
|
[GPIO1_NUM] = &(struct gpio_module_desc) {
|
||||||
.base = (unsigned long *)GPIO1_BASE_ADDR,
|
.base = (unsigned long *)GPIO1_BASE_ADDR,
|
||||||
.ints = INT_GPIO1,
|
.ints = INT_GPIO1,
|
||||||
.handler = GPIO1_HANDLER,
|
.handler = GPIO1_HANDLER,
|
||||||
.events = gpio1_events,
|
|
||||||
.count = GPIO1_NUM_EVENTS,
|
|
||||||
.int_priority = GPIO1_INT_PRIO
|
.int_priority = GPIO1_INT_PRIO
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
||||||
{
|
[GPIO2_NUM] = &(struct gpio_module_desc) {
|
||||||
.base = (unsigned long *)GPIO2_BASE_ADDR,
|
.base = (unsigned long *)GPIO2_BASE_ADDR,
|
||||||
.ints = INT_GPIO2,
|
.ints = INT_GPIO2,
|
||||||
.handler = GPIO2_HANDLER,
|
.handler = GPIO2_HANDLER,
|
||||||
.events = gpio2_events,
|
|
||||||
.count = GPIO2_NUM_EVENTS,
|
|
||||||
.int_priority = GPIO2_INT_PRIO
|
.int_priority = GPIO2_INT_PRIO
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
||||||
{
|
[GPIO3_NUM] = &(struct gpio_module_desc) {
|
||||||
.base = (unsigned long *)GPIO3_BASE_ADDR,
|
.base = (unsigned long *)GPIO3_BASE_ADDR,
|
||||||
.ints = INT_GPIO3,
|
.ints = INT_GPIO3,
|
||||||
.handler = GPIO3_HANDLER,
|
.handler = GPIO3_HANDLER,
|
||||||
.events = gpio3_events,
|
|
||||||
.count = GPIO3_NUM_EVENTS,
|
|
||||||
.int_priority = GPIO3_INT_PRIO,
|
.int_priority = GPIO3_INT_PRIO,
|
||||||
},
|
},
|
||||||
#endif
|
#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)
|
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;
|
volatile unsigned long * const base = desc->base;
|
||||||
const struct gpio_event * event, *event_last;
|
|
||||||
|
|
||||||
event = desc->events;
|
/* Send only events that are not masked */
|
||||||
event_last = event + desc->count;
|
unsigned long pnd = base[GPIO_ISR] & base[GPIO_IMR];
|
||||||
|
|
||||||
/* Intersect pending and unmasked bits */
|
if (pnd & ~desc->enabled)
|
||||||
unsigned long pnd = base[ISR] & base[IMR];
|
UIE_VECTOR(); /* One or more aren't handled properly */
|
||||||
|
|
||||||
/* Call each event handler in order */
|
const struct gpio_event *event = desc->events;
|
||||||
/* .count is surely expected to be > 0 */
|
|
||||||
do
|
while (pnd)
|
||||||
{
|
{
|
||||||
unsigned long mask = event->mask;
|
unsigned long mask = 1ul << (event->id % 32);
|
||||||
|
|
||||||
if (pnd & mask)
|
if (pnd & mask)
|
||||||
{
|
{
|
||||||
event->callback();
|
event->callback();
|
||||||
pnd &= ~mask;
|
pnd &= ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pnd == 0)
|
event++;
|
||||||
break; /* Teminate early if nothing more to service */
|
|
||||||
}
|
|
||||||
while (++event < event_last);
|
|
||||||
|
|
||||||
if (pnd != 0)
|
|
||||||
{
|
|
||||||
/* One or more weren't handled */
|
|
||||||
UIE_VECTOR();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,69 +143,90 @@ static __attribute__((interrupt("IRQ"))) void GPIO3_HANDLER(void)
|
||||||
|
|
||||||
void INIT_ATTR gpio_init(void)
|
void INIT_ATTR gpio_init(void)
|
||||||
{
|
{
|
||||||
/* Mask-out GPIO interrupts - enable what's wanted later */
|
for (unsigned int mod = 0; mod < GPIO_MODULE_CNT; mod++)
|
||||||
int i;
|
{
|
||||||
for (i = 0; i < GPIO_NUM_GPIO; i++)
|
struct gpio_module_desc * const desc = gpio_descs[mod];
|
||||||
gpio_descs[i].base[IMR] = 0;
|
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];
|
unsigned int mod = id / 32;
|
||||||
const struct gpio_event * const event = &desc->events[id & 31];
|
|
||||||
|
struct gpio_module_desc * const desc = gpio_descs[mod];
|
||||||
|
|
||||||
|
if (mod >= GPIO_MODULE_CNT || desc == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const struct gpio_event * const event = event_from_id(desc, id);
|
||||||
|
if (!event)
|
||||||
|
return false;
|
||||||
|
|
||||||
volatile unsigned long * const base = desc->base;
|
volatile unsigned long * const base = desc->base;
|
||||||
volatile unsigned long *icr;
|
unsigned long num = id % 32;
|
||||||
unsigned long mask, line;
|
unsigned long mask = 1ul << num;
|
||||||
unsigned long imr;
|
|
||||||
int shift;
|
|
||||||
|
|
||||||
int oldlevel = disable_irq_save();
|
unsigned long cpsr = disable_irq_save();
|
||||||
|
|
||||||
imr = base[IMR];
|
unsigned long imr = base[GPIO_IMR];
|
||||||
|
|
||||||
if (imr == 0)
|
if (enable)
|
||||||
{
|
{
|
||||||
/* First enabled interrupt for this GPIO */
|
if (desc->enabled == 0)
|
||||||
avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
|
{
|
||||||
desc->handler);
|
/* First enabled interrupt for this GPIO */
|
||||||
|
avic_enable_int(desc->ints, INT_TYPE_IRQ, desc->int_priority,
|
||||||
|
desc->handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the line sense */
|
||||||
|
if (event->sense == GPIO_SENSE_EDGE_SEL)
|
||||||
|
{
|
||||||
|
/* Interrupt configuration register is ignored */
|
||||||
|
base[GPIO_EDGE_SEL] |= mask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
volatile unsigned long *icrp = &base[GPIO_ICR + num / 16];
|
||||||
|
unsigned int shift = 2*(num % 16);
|
||||||
|
bitmod32(icrp, event->sense << shift, 0x3 << shift);
|
||||||
|
base[GPIO_EDGE_SEL] &= ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmask the line */
|
||||||
|
desc->enabled |= mask;
|
||||||
|
imr |= mask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imr &= ~mask;
|
||||||
|
desc->enabled &= ~mask;
|
||||||
|
|
||||||
|
if (desc->enabled == 0)
|
||||||
|
avic_disable_int(desc->ints); /* No events remain enabled */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the line sense */
|
base[GPIO_IMR] = imr;
|
||||||
line = find_first_set_bit(event->mask);
|
|
||||||
icr = &base[ICR + (line >> 4)];
|
|
||||||
shift = 2*(line & 15);
|
|
||||||
mask = GPIO_SENSE_CONFIG_MASK << shift;
|
|
||||||
|
|
||||||
*icr = (*icr & ~mask) | ((event->sense << shift) & mask);
|
restore_irq(cpsr);
|
||||||
|
|
||||||
/* Unmask the line */
|
|
||||||
base[IMR] = imr | event->mask;
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_disable_event(enum gpio_event_ids id)
|
|
||||||
{
|
|
||||||
const struct gpio_module_desc * const desc = &gpio_descs[id >> 5];
|
|
||||||
const struct gpio_event * const event = &desc->events[id & 31];
|
|
||||||
volatile unsigned long * const base = desc->base;
|
|
||||||
unsigned long imr;
|
|
||||||
|
|
||||||
int oldlevel = disable_irq_save();
|
|
||||||
|
|
||||||
/* Remove bit from mask */
|
|
||||||
imr = base[IMR] & ~event->mask;
|
|
||||||
|
|
||||||
/* Mask the line */
|
|
||||||
base[IMR] = imr;
|
|
||||||
|
|
||||||
if (imr == 0)
|
|
||||||
{
|
|
||||||
/* No events remain enabled */
|
|
||||||
avic_disable_int(desc->ints);
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_irq(oldlevel);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -26,62 +26,193 @@
|
||||||
#define USE_GPIO2_EVENTS (1 << 1)
|
#define USE_GPIO2_EVENTS (1 << 1)
|
||||||
#define USE_GPIO3_EVENTS (1 << 2)
|
#define USE_GPIO3_EVENTS (1 << 2)
|
||||||
|
|
||||||
/* Module indexes defined by which GPIO modules are used */
|
/* Module logical indexes */
|
||||||
enum gpio_module_number
|
enum gpio_module_number
|
||||||
{
|
{
|
||||||
__GPIO_NUM_START = -1,
|
GPIO1_NUM, /* ID 0..31 */
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
GPIO2_NUM, /* ID 32..63 */
|
||||||
GPIO1_NUM,
|
GPIO3_NUM, /* ID 64..95 */
|
||||||
#endif
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
|
||||||
GPIO2_NUM,
|
|
||||||
#endif
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
|
||||||
GPIO3_NUM,
|
|
||||||
#endif
|
|
||||||
GPIO_NUM_GPIO,
|
GPIO_NUM_GPIO,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Possible values for gpio interrupt line config */
|
enum gpio_id
|
||||||
enum gpio_int_sense_enum
|
|
||||||
{
|
{
|
||||||
GPIO_SENSE_LOW_LEVEL = 0, /* High-level sensitive */
|
/* GPIO1 */
|
||||||
GPIO_SENSE_HIGH_LEVEL, /* Low-level sensitive */
|
GPIO1_0_ID = 0,
|
||||||
GPIO_SENSE_RISING, /* Rising-edge sensitive */
|
GPIO1_1_ID,
|
||||||
GPIO_SENSE_FALLING, /* Falling-edge sensitive */
|
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
|
/* Handlers will be called in declared order for a given module
|
||||||
* pioritization */
|
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 */
|
/* Describes a single event for a pin */
|
||||||
struct gpio_event
|
struct gpio_event
|
||||||
{
|
{
|
||||||
unsigned long mask; /* mask: 1 << (0...31) */
|
uint8_t id; /* GPIOx_y_ID */
|
||||||
enum gpio_int_sense_enum sense; /* Type of sense */
|
uint8_t sense; /* GPIO_SENSE_x */
|
||||||
void (*callback)(void); /* Callback function */
|
void (*callback)(void); /* GPIOx_y_EVENT_CB */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Module corresponding to the event ID is identified by range */
|
#define GPIO_VECTOR_TBL_START() \
|
||||||
enum gpio_event_bases
|
static FORCE_INLINE uintptr_t __gpio_event_vector_tbl(int __what) \
|
||||||
{
|
{ \
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO1_EVENTS)
|
static const struct gpio_event __tbl[] = {
|
||||||
GPIO1_EVENT_FIRST = 32*GPIO1_NUM,
|
|
||||||
#endif
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO2_EVENTS)
|
|
||||||
GPIO2_EVENT_FIRST = 32*GPIO2_NUM,
|
|
||||||
#endif
|
|
||||||
#if (GPIO_EVENT_MASK & USE_GPIO3_EVENTS)
|
|
||||||
GPIO3_EVENT_FIRST = 32*GPIO3_NUM,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "gpio-target.h"
|
#define GPIO_EVENT_VECTOR(__name, __sense) \
|
||||||
|
{ .id = (__name##_ID), \
|
||||||
|
.sense = (__sense), \
|
||||||
|
.callback = ({ void __name##_EVENT_CB(void); \
|
||||||
|
__name##_EVENT_CB; }) },
|
||||||
|
|
||||||
|
#define GPIO_VECTOR_TBL_END() \
|
||||||
|
}; \
|
||||||
|
switch (__what) \
|
||||||
|
{ \
|
||||||
|
default: return (uintptr_t)__tbl; \
|
||||||
|
case 1: return (uintptr_t)ARRAYLEN(__tbl); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define gpio_event_vector_tbl \
|
||||||
|
((const struct gpio_event *)__gpio_event_vector_tbl(0))
|
||||||
|
|
||||||
|
#define gpio_event_vector_tbl_len \
|
||||||
|
((unsigned int)__gpio_event_vector_tbl(1))
|
||||||
|
|
||||||
|
#endif /* DEFINE_GPIO_VECTOR_TABLE */
|
||||||
|
|
||||||
|
#define GPIO_BASE_ADDR \
|
||||||
|
(volatile unsigned long * const [GPIO_NUM_GPIO]) { \
|
||||||
|
(volatile unsigned long *)GPIO1_BASE_ADDR, \
|
||||||
|
(volatile unsigned long *)GPIO2_BASE_ADDR, \
|
||||||
|
(volatile unsigned long *)GPIO3_BASE_ADDR }
|
||||||
|
|
||||||
|
#define GPIO_DR (0x00 / sizeof (unsigned long)) /* 00h */
|
||||||
|
#define GPIO_GDIR (0x04 / sizeof (unsigned long)) /* 04h */
|
||||||
|
#define GPIO_PSR (0x08 / sizeof (unsigned long)) /* 08h */
|
||||||
|
#define GPIO_ICR (0x0C / sizeof (unsigned long)) /* 0Ch ICR1,2 */
|
||||||
|
#define GPIO_IMR (0x14 / sizeof (unsigned long)) /* 14h */
|
||||||
|
#define GPIO_ISR (0x18 / sizeof (unsigned long)) /* 18h */
|
||||||
|
#define GPIO_EDGE_SEL (0x1C / sizeof (unsigned long)) /* 1Ch */
|
||||||
|
|
||||||
void gpio_init(void);
|
void gpio_init(void);
|
||||||
bool gpio_enable_event(enum gpio_event_ids id);
|
bool gpio_enable_event(enum gpio_id id, bool enable);
|
||||||
void gpio_disable_event(enum gpio_event_ids id);
|
|
||||||
|
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 */
|
#endif /* GPIO_IMX31_H */
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "gpio-imx31.h"
|
#define DEFINE_MC13783_VECTOR_TABLE
|
||||||
#include "mc13783.h"
|
|
||||||
#include "mc13783-target.h"
|
#include "mc13783-target.h"
|
||||||
|
#include "gpio-target.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
|
|
@ -32,21 +32,42 @@ struct mc13783_transfer_desc
|
||||||
struct spi_transfer_desc xfer;
|
struct spi_transfer_desc xfer;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
/* Pick _either_ data or semaphore */
|
||||||
struct semaphore sema;
|
struct semaphore sema;
|
||||||
uint32_t data;
|
uint32_t data[4];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct mc13783_event mc13783_events[MC13783_NUM_EVENTS];
|
static uint32_t pmic_int_enb[2]; /* Enabled ints */
|
||||||
extern struct spi_node mc13783_spi;
|
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 const struct mc13783_event * event_from_id(enum mc13783_int_ids id)
|
||||||
static uint32_t pmic_int_sense_enb[2]; /* Enabled sense reading */
|
{
|
||||||
static uint32_t int_pnd_buf[2]; /* Pending ints */
|
for (unsigned int i = 0; i < mc13783_event_vector_tbl_len; i++)
|
||||||
static uint32_t int_data_buf[4]; /* ISR data buffer */
|
{
|
||||||
static struct spi_transfer_desc int_xfers[2]; /* ISR transfer descriptor */
|
if (mc13783_event_vector_tbl[i].id == id)
|
||||||
static bool restore_event = true; /* Protect SPI callback from unmasking GPIO
|
return &mc13783_event_vector_tbl[i];
|
||||||
interrupt (lockout) */
|
}
|
||||||
|
|
||||||
|
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,
|
static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
|
||||||
uint32_t *txbuf,
|
uint32_t *txbuf,
|
||||||
|
|
@ -64,90 +85,96 @@ static inline bool mc13783_transfer(struct spi_transfer_desc *xfer,
|
||||||
return spi_transfer(xfer);
|
return spi_transfer(xfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when a transfer is finished and data is ready/written */
|
static inline void sync_transfer_init(struct mc13783_transfer_desc *xfer)
|
||||||
static void mc13783_xfer_complete_cb(struct spi_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)
|
sync_transfer_init(xfer);
|
||||||
== OBJ_WAIT_SUCCEEDED && xfer->xfer.count == 0;
|
return mc13783_transfer(&xfer->xfer, txbuf, rxbuf, count, mc13783_xfer_complete_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Efficient interrupt status and acking */
|
/* Efficient interrupt status and acking */
|
||||||
static void mc13783_int_svc_complete_callback(struct spi_transfer_desc *xfer)
|
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 */
|
/* Restore PMIC interrupt events */
|
||||||
if (restore_event)
|
if (int_restore)
|
||||||
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
gpio_int_enable(MC13783_EVENT_ID);
|
||||||
|
|
||||||
/* Call handlers */
|
/* Call handlers */
|
||||||
for (
|
const struct mc13783_event *event = mc13783_event_vector_tbl;
|
||||||
const struct mc13783_event *event = mc13783_events;
|
while (pnd0 | pnd1)
|
||||||
int_pnd_buf[0] | int_pnd_buf[1];
|
|
||||||
event++
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
uint32_t id = event->id;
|
||||||
uint32_t pnd = int_pnd_buf[set];
|
uint32_t set = id / 32;
|
||||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
uint32_t bit = 1 << (id % 32);
|
||||||
|
|
||||||
if (pnd & mask)
|
uint32_t pnd = set == 0 ? pnd0 : pnd1;
|
||||||
|
if (pnd & bit)
|
||||||
{
|
{
|
||||||
|
current_event = event;
|
||||||
event->callback();
|
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)
|
static void mc13783_int_svc_callback(struct spi_transfer_desc *xfer)
|
||||||
{
|
{
|
||||||
/* Only clear interrupts with handlers */
|
/* Only clear interrupts with handlers */
|
||||||
int_pnd_buf[0] &= pmic_int_enb[0];
|
struct mc13783_transfer_desc *desc0 = (struct mc13783_transfer_desc *)xfer;
|
||||||
int_pnd_buf[1] &= pmic_int_enb[1];
|
struct mc13783_transfer_desc *desc1 = &int_xfers[1];
|
||||||
|
|
||||||
/* Only read sense if enabled interrupts have them enabled */
|
uint32_t pnd0 = desc0->data[0] & pmic_int_enb[0];
|
||||||
if ((int_pnd_buf[0] & pmic_int_sense_enb[0]) ||
|
uint32_t pnd1 = desc0->data[1] & pmic_int_enb[1];
|
||||||
(int_pnd_buf[1] & pmic_int_sense_enb[1]))
|
|
||||||
{
|
desc1->data[0] = pnd0;
|
||||||
int_data_buf[2] = MC13783_INTERRUPT_SENSE0 << 25;
|
desc1->data[1] = pnd1;
|
||||||
int_data_buf[3] = MC13783_INTERRUPT_SENSE1 << 25;
|
|
||||||
int_xfers[1].rxbuf = int_data_buf;
|
|
||||||
int_xfers[1].count = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup the write packets with status(es) to clear */
|
/* Setup the write packets with status(es) to clear */
|
||||||
int_data_buf[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25)
|
desc0->data[0] = (1 << 31) | (MC13783_INTERRUPT_STATUS0 << 25) | pnd0;
|
||||||
| int_pnd_buf[0];
|
desc0->data[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25) | pnd1;
|
||||||
int_data_buf[1] = (1 << 31) | (MC13783_INTERRUPT_STATUS1 << 25)
|
|
||||||
| int_pnd_buf[1];
|
/* Only read sense if any pending interrupts have them enabled */
|
||||||
(void)xfer;
|
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 */
|
/* GPIO interrupt handler for mc13783 */
|
||||||
void mc13783_event(void)
|
void INT_MC13783(void)
|
||||||
{
|
{
|
||||||
/* Mask the interrupt (unmasked after final read services it). */
|
/* Mask the interrupt (unmasked after final read services it). */
|
||||||
bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
gpio_int_disable(MC13783_EVENT_ID);
|
||||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
gpio_int_clear(MC13783_EVENT_ID);
|
||||||
|
|
||||||
/* Setup the read packets */
|
/* Setup the read packets */
|
||||||
int_pnd_buf[0] = MC13783_INTERRUPT_STATUS0 << 25;
|
int_xfers[0].data[0] = MC13783_INTERRUPT_STATUS0 << 25;
|
||||||
int_pnd_buf[1] = MC13783_INTERRUPT_STATUS1 << 25;
|
int_xfers[0].data[1] = MC13783_INTERRUPT_STATUS1 << 25;
|
||||||
|
|
||||||
unsigned long cpsr = disable_irq_save();
|
unsigned long cpsr = disable_irq_save();
|
||||||
|
|
||||||
/* Do these without intervening transfers */
|
/* Do these without intervening transfers */
|
||||||
if (mc13783_transfer(&int_xfers[0], int_pnd_buf, int_pnd_buf, 2,
|
if (mc13783_transfer(&int_xfers[0].xfer, int_xfers[0].data,
|
||||||
mc13783_int_svc_callback))
|
int_xfers[0].data, 2, mc13783_int_svc_callback))
|
||||||
{
|
{
|
||||||
/* Start this provisionally and fill-in actual values during the
|
/* Start this provisionally and fill-in actual values during the
|
||||||
first transfer's callback - set whatever could be known */
|
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);
|
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_MASK0, 0xffffff);
|
||||||
mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
|
mc13783_write(MC13783_INTERRUPT_MASK1, 0xffffff);
|
||||||
|
|
||||||
MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE);
|
gpio_int_clear(MC13783_EVENT_ID);
|
||||||
gpio_enable_event(MC13783_EVENT_ID);
|
gpio_enable_event(MC13783_EVENT_ID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mc13783_close(void)
|
void mc13783_close(void)
|
||||||
{
|
{
|
||||||
restore_event = false;
|
int_restore = false;
|
||||||
gpio_disable_event(MC13783_EVENT_ID);
|
gpio_int_disable(MC13783_EVENT_ID);
|
||||||
|
gpio_enable_event(MC13783_EVENT_ID, false);
|
||||||
spi_enable_node(&mc13783_spi, 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] =
|
static const unsigned char pmic_intm_regs[2] =
|
||||||
{ MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 };
|
{ MC13783_INTERRUPT_MASK0, MC13783_INTERRUPT_MASK1 };
|
||||||
|
|
||||||
const struct mc13783_event * const event = &mc13783_events[id];
|
const struct mc13783_event * const event = event_from_id(id);
|
||||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
if (event == NULL)
|
||||||
uint32_t mask = 1 << (event->int_id & MC13783_INT_ID_NUM_MASK);
|
return;
|
||||||
|
|
||||||
|
unsigned int set = id / 32;
|
||||||
|
uint32_t mask = 1 << (id % 32);
|
||||||
|
uint32_t bit = enable ? mask : 0;
|
||||||
|
|
||||||
/* Mask GPIO while changing bits around */
|
/* Mask GPIO while changing bits around */
|
||||||
restore_event = false;
|
int_restore = false;
|
||||||
bitclr32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
gpio_int_disable(MC13783_EVENT_ID);
|
||||||
mc13783_write_masked(pmic_intm_regs[set],
|
mc13783_write_masked(pmic_intm_regs[set], bit ^ mask, mask);
|
||||||
enable ? 0 : mask, mask);
|
bitmod32(&pmic_int_sense_enb[set], event->sense ? bit : 0, mask);
|
||||||
bitmod32(&pmic_int_enb[set], enable ? mask : 0, mask);
|
bitmod32(&pmic_int_enb[set], bit, mask);
|
||||||
bitmod32(&pmic_int_sense_enb[set], enable ? event->sense : 0,
|
int_restore = true;
|
||||||
event->sense);
|
gpio_int_enable(MC13783_EVENT_ID);
|
||||||
restore_event = true;
|
|
||||||
bitset32(&MC13783_GPIO_IMR, 1ul << MC13783_GPIO_LINE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
const struct mc13783_event *event = current_event;
|
||||||
unsigned int set = event->int_id / MC13783_INT_ID_SET_DIV;
|
return int_xfers[0].data[2 + event->id / 32] & event->sense;
|
||||||
return int_data_buf[2 + set] & event->sense;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mc13783_set(unsigned address, uint32_t bits)
|
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)
|
static void mc13783_write_masked_cb(struct spi_transfer_desc *xfer)
|
||||||
{
|
{
|
||||||
struct mc13783_transfer_desc *desc = (struct mc13783_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 */
|
desc->data[1] |= desc->data[0] & desc->data[2]; /* & ~mask */
|
||||||
packets[0] |= packets[-1] & ~desc->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t mc13783_write_masked(unsigned address, uint32_t data, uint32_t 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;
|
mask &= 0xffffff;
|
||||||
|
|
||||||
uint32_t packets[2] =
|
|
||||||
{
|
|
||||||
address << 25,
|
|
||||||
(1 << 31) | (address << 25) | (data & mask)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mc13783_transfer_desc xfers[2];
|
struct mc13783_transfer_desc xfers[2];
|
||||||
xfers[0].data = mask;
|
xfers[0].data[0] = address << 25;
|
||||||
semaphore_init(&xfers[1].sema, 1, 0);
|
xfers[0].data[1] = (1 << 31) | (address << 25) | (data & mask);
|
||||||
|
xfers[0].data[2] = ~mask;
|
||||||
|
|
||||||
unsigned long cpsr = disable_irq_save();
|
unsigned long cpsr = disable_irq_save();
|
||||||
|
|
||||||
/* Queue up two transfers in a row */
|
/* 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_write_masked_cb) &&
|
||||||
mc13783_transfer(&xfers[1].xfer, &packets[1], NULL, 1,
|
mc13783_sync_transfer(&xfers[1], &xfers[0].data[1], NULL, 1);
|
||||||
mc13783_xfer_complete_cb);
|
|
||||||
|
|
||||||
restore_irq(cpsr);
|
restore_irq(cpsr);
|
||||||
|
|
||||||
if (ok && wait_for_transfer_complete(&xfers[1]))
|
if (ok && wait_for_transfer_complete(&xfers[1]))
|
||||||
return packets[0];
|
return xfers[0].data[0];
|
||||||
|
|
||||||
return MC13783_DATA_ERROR;
|
return MC13783_DATA_ERROR;
|
||||||
}
|
}
|
||||||
|
|
@ -264,10 +287,7 @@ uint32_t mc13783_read(unsigned address)
|
||||||
uint32_t packet = address << 25;
|
uint32_t packet = address << 25;
|
||||||
|
|
||||||
struct mc13783_transfer_desc xfer;
|
struct mc13783_transfer_desc xfer;
|
||||||
semaphore_init(&xfer.sema, 1, 0);
|
if (mc13783_sync_transfer(&xfer, &packet, &packet, 1) &&
|
||||||
|
|
||||||
if (mc13783_transfer(&xfer.xfer, &packet, &packet, 1,
|
|
||||||
mc13783_xfer_complete_cb) &&
|
|
||||||
wait_for_transfer_complete(&xfer))
|
wait_for_transfer_complete(&xfer))
|
||||||
{
|
{
|
||||||
return packet;
|
return packet;
|
||||||
|
|
@ -284,10 +304,7 @@ int mc13783_write(unsigned address, uint32_t data)
|
||||||
uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff);
|
uint32_t packet = (1 << 31) | (address << 25) | (data & 0xffffff);
|
||||||
|
|
||||||
struct mc13783_transfer_desc xfer;
|
struct mc13783_transfer_desc xfer;
|
||||||
semaphore_init(&xfer.sema, 1, 0);
|
if (mc13783_sync_transfer(&xfer, &packet, NULL, 1) &&
|
||||||
|
|
||||||
if (mc13783_transfer(&xfer.xfer, &packet, NULL, 1,
|
|
||||||
mc13783_xfer_complete_cb) &&
|
|
||||||
wait_for_transfer_complete(&xfer))
|
wait_for_transfer_complete(&xfer))
|
||||||
{
|
{
|
||||||
return 1 - xfer.xfer.count;
|
return 1 - xfer.xfer.count;
|
||||||
|
|
@ -300,7 +317,7 @@ int mc13783_read_regs(const unsigned char *regs, uint32_t *buffer,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
struct mc13783_transfer_desc xfer;
|
struct mc13783_transfer_desc xfer;
|
||||||
semaphore_init(&xfer.sema, 1, 0);
|
sync_transfer_init(&xfer);
|
||||||
|
|
||||||
if (mc13783_read_async(&xfer.xfer, regs, buffer, count,
|
if (mc13783_read_async(&xfer.xfer, regs, buffer, count,
|
||||||
mc13783_xfer_complete_cb) &&
|
mc13783_xfer_complete_cb) &&
|
||||||
|
|
@ -316,7 +333,7 @@ int mc13783_write_regs(const unsigned char *regs, uint32_t *buffer,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
struct mc13783_transfer_desc xfer;
|
struct mc13783_transfer_desc xfer;
|
||||||
semaphore_init(&xfer.sema, 1, 0);
|
sync_transfer_init(&xfer);
|
||||||
|
|
||||||
if (mc13783_write_async(&xfer.xfer, regs, buffer, count,
|
if (mc13783_write_async(&xfer.xfer, regs, buffer, count,
|
||||||
mc13783_xfer_complete_cb) &&
|
mc13783_xfer_complete_cb) &&
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue