x1000: GPIO refactor
The GPIO API was pretty clunky and pin settings were decentralized, making it hard to see what was happening and making GPIO stuff look like a mess, frankly. Instead of passing clunky (port, pin) pairs everywhere, GPIOs are now identified with a single int. The extra overhead should be minimal as GPIO configuration is generally not on a performance-critical path. Pin assignments are now mostly consolidated in gpio-target.h and put in various tables so gpio_init() can assign most pins at boot time. Most drivers no longer need to touch GPIOs and basic pin I/O stuff can happen without config since pins are put into the right state. IRQ pins still need to be configured manually before use. Change-Id: Ic5326284b0b2a2f613e9e76a41cb50e24af3aa47
This commit is contained in:
parent
695d1701cd
commit
e85bc74b30
|
@ -1659,7 +1659,9 @@ target/mips/ingenic_x1000/pwm-x1000.c
|
|||
target/mips/ingenic_x1000/sfc-x1000.c
|
||||
target/mips/ingenic_x1000/system-x1000.c
|
||||
target/mips/ingenic_x1000/timer-x1000.c
|
||||
#ifndef USB_NONE
|
||||
target/mips/ingenic_x1000/usb-x1000.c
|
||||
#endif
|
||||
#if (CONFIG_STORAGE & (STORAGE_SD|STORAGE_MMC|STORAGE_ATA))
|
||||
target/mips/ingenic_x1000/msc-x1000.c
|
||||
#endif
|
||||
|
|
|
@ -87,5 +87,5 @@ void audiohw_set_power_mode(int mode)
|
|||
|
||||
void ak4376_set_pdn_pin(int level)
|
||||
{
|
||||
gpio_config(GPIO_A, 1 << 16, GPIO_OUTPUT(level ? 1 : 0));
|
||||
gpio_set_level(GPIO_AK4376_POWER, level ? 1 : 0);
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
# include "font.h"
|
||||
#endif
|
||||
|
||||
#define FT_RST_PIN (1 << 15)
|
||||
#define FT_INT_PIN (1 << 12)
|
||||
#define ft_interrupt GPIOB12
|
||||
|
||||
/* Touch event types */
|
||||
|
@ -389,11 +387,13 @@ static void ft_init(void)
|
|||
i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K);
|
||||
|
||||
/* Reset chip */
|
||||
gpio_config(GPIO_B, FT_RST_PIN|FT_INT_PIN, GPIO_OUTPUT(0));
|
||||
gpio_set_level(GPIO_FT6x06_RESET, 0);
|
||||
mdelay(5);
|
||||
gpio_out_level(GPIO_B, FT_RST_PIN, 1);
|
||||
gpio_config(GPIO_B, FT_INT_PIN, GPIO_IRQ_EDGE(0));
|
||||
gpio_enable_irq(GPIO_B, FT_INT_PIN);
|
||||
gpio_set_level(GPIO_FT6x06_RESET, 1);
|
||||
|
||||
/* Configure the interrupt pin */
|
||||
gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0));
|
||||
gpio_enable_irq(GPIO_FT6x06_INTERRUPT);
|
||||
}
|
||||
|
||||
void touchpad_set_sensitivity(int level)
|
||||
|
@ -454,10 +454,6 @@ static void hp_detect_init(void)
|
|||
/* Rockbox interface */
|
||||
void button_init_device(void)
|
||||
{
|
||||
/* Configure physical button GPIOs */
|
||||
gpio_config(GPIO_A, (1 << 17) | (1 << 19), GPIO_INPUT);
|
||||
gpio_config(GPIO_B, (1 << 28) | (1 << 31), GPIO_INPUT);
|
||||
|
||||
/* Initialize touchpad */
|
||||
ft_init();
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* Name Port Pins Function */
|
||||
DEFINE_PINGROUP(LCD_DATA, GPIO_A, 0xffff << 0, GPIOF_DEVICE(1))
|
||||
DEFINE_PINGROUP(LCD_CONTROL, GPIO_B, 0x1a << 16, GPIOF_DEVICE(1))
|
||||
DEFINE_PINGROUP(MSC0, GPIO_A, 0x3f << 20, GPIOF_DEVICE(1))
|
||||
DEFINE_PINGROUP(SFC, GPIO_A, 0x3f << 26, GPIOF_DEVICE(1))
|
||||
DEFINE_PINGROUP(I2S, GPIO_B, 0x1f << 0, GPIOF_DEVICE(1))
|
||||
DEFINE_PINGROUP(DMIC, GPIO_B, 3 << 21, GPIOF_DEVICE(0))
|
||||
DEFINE_PINGROUP(I2C0, GPIO_B, 3 << 23, GPIOF_DEVICE(0))
|
||||
DEFINE_PINGROUP(I2C1, GPIO_C, 3 << 26, GPIOF_DEVICE(0))
|
||||
DEFINE_PINGROUP(I2C2, GPIO_D, 3 << 0, GPIOF_DEVICE(1))
|
||||
|
||||
/* Name Pin Function */
|
||||
DEFINE_GPIO(AK4376_POWER, GPIO_PA(16), GPIOF_OUTPUT(0))
|
||||
DEFINE_GPIO(BTN_PLAY, GPIO_PA(17), GPIOF_INPUT)
|
||||
DEFINE_GPIO(BTN_VOL_UP, GPIO_PA(19), GPIOF_INPUT)
|
||||
DEFINE_GPIO(MSC0_CD, GPIO_PB(6), GPIOF_INPUT)
|
||||
DEFINE_GPIO(USB_ID, GPIO_PB(7), GPIOF_INPUT)
|
||||
DEFINE_GPIO(AXP_IRQ, GPIO_PB(10), GPIOF_INPUT)
|
||||
DEFINE_GPIO(USB_DETECT, GPIO_PB(11), GPIOF_INPUT)
|
||||
DEFINE_GPIO(FT6x06_INTERRUPT, GPIO_PB(12), GPIOF_INPUT)
|
||||
DEFINE_GPIO(FT6x06_RESET, GPIO_PB(15), GPIOF_OUTPUT(0))
|
||||
DEFINE_GPIO(LCD_RD, GPIO_PB(16), GPIOF_OUTPUT(1))
|
||||
DEFINE_GPIO(LCD_CE, GPIO_PB(18), GPIOF_OUTPUT(1))
|
||||
DEFINE_GPIO(USB_DRVVBUS, GPIO_PB(25), GPIOF_OUTPUT(0))
|
||||
DEFINE_GPIO(BTN_VOL_DOWN, GPIO_PB(28), GPIOF_INPUT)
|
||||
DEFINE_GPIO(BTN_POWER, GPIO_PB(31), GPIOF_INPUT)
|
|
@ -25,9 +25,6 @@
|
|||
#include "gpio-x1000.h"
|
||||
#include "system.h"
|
||||
|
||||
#define CS_PIN (1 << 18)
|
||||
#define RD_PIN (1 << 16)
|
||||
|
||||
static const uint32_t fiio_lcd_cmd_enable[] = {
|
||||
/* Software reset */
|
||||
LCD_INSTR_CMD, 0x01,
|
||||
|
@ -169,17 +166,27 @@ const struct lcd_tgt_config lcd_tgt_config = {
|
|||
void lcd_tgt_enable(bool enable)
|
||||
{
|
||||
if(enable) {
|
||||
gpio_config(GPIO_A, 0xffff, GPIO_DEVICE(1));
|
||||
gpio_config(GPIO_B, 0x1f << 16, GPIO_DEVICE(1));
|
||||
gpio_config(GPIO_B, CS_PIN|RD_PIN, GPIO_OUTPUT(1));
|
||||
/* reset controller, probably */
|
||||
gpio_set_level(GPIO_LCD_CE, 1);
|
||||
gpio_set_level(GPIO_LCD_RD, 1);
|
||||
mdelay(5);
|
||||
gpio_out_level(GPIO_B, CS_PIN, 0);
|
||||
gpio_set_level(GPIO_LCD_CE, 0);
|
||||
|
||||
/* set the clock whatever it is... */
|
||||
lcd_set_clock(X1000_CLK_SCLK_A, 30000000);
|
||||
|
||||
/* program the initial configuration */
|
||||
lcd_exec_commands(&fiio_lcd_cmd_enable[0]);
|
||||
} else {
|
||||
/* go to sleep mode first */
|
||||
lcd_exec_commands(&fiio_lcd_cmd_sleep[0]);
|
||||
mdelay(115); /* ensure we wait a total of 120ms before power off */
|
||||
gpio_config(GPIO_B, CS_PIN|RD_PIN, 0);
|
||||
|
||||
/* ensure we wait a total of 120ms before power off */
|
||||
mdelay(115);
|
||||
|
||||
/* this is intended to power off the panel but I'm not sure it does */
|
||||
gpio_set_level(GPIO_LCD_CE, 0);
|
||||
gpio_set_level(GPIO_LCD_RD, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#endif
|
||||
#include "axp-pmu.h"
|
||||
#include "i2c-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
|
@ -53,9 +52,6 @@ const unsigned short percent_to_volt_charge[11] =
|
|||
3485, 3780, 3836, 3857, 3890, 3930, 3986, 4062, 4158, 4185, 4196
|
||||
};
|
||||
|
||||
#define AXP_IRQ_PORT GPIO_B
|
||||
#define AXP_IRQ_PIN (1 << 10)
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
/* Initialize driver */
|
||||
|
|
|
@ -116,7 +116,7 @@ int spl_get_boot_option(void)
|
|||
const int max_iter_count = 30;
|
||||
|
||||
/* Configure the button GPIOs as inputs */
|
||||
gpio_config(GPIO_A, pinmask, GPIO_INPUT);
|
||||
gpioz_configure(GPIO_A, pinmask, GPIOF_INPUT);
|
||||
|
||||
/* Poll the pins for a short duration to detect a keypress */
|
||||
do {
|
||||
|
|
|
@ -20,37 +20,91 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include "gpio-x1000.h"
|
||||
#include "kernel.h"
|
||||
|
||||
const struct gpio_setting gpio_settings[PIN_COUNT] = {
|
||||
#define DEFINE_GPIO(_name, _gpio, _func) \
|
||||
{.gpio = _gpio, .func = _func},
|
||||
#define DEFINE_PINGROUP(...)
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
};
|
||||
|
||||
const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = {
|
||||
#define DEFINE_GPIO(...)
|
||||
#define DEFINE_PINGROUP(_name, _port, _pins, _func) \
|
||||
{.port = _port, .pins = _pins, .func = _func},
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
};
|
||||
|
||||
const char* const gpio_names[PIN_COUNT] = {
|
||||
#define DEFINE_GPIO(_name, ...) #_name,
|
||||
#define DEFINE_PINGROUP(...)
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
};
|
||||
|
||||
const char* const pingroup_names[PINGROUP_COUNT] = {
|
||||
#define DEFINE_GPIO(...)
|
||||
#define DEFINE_PINGROUP(_name, ...) #_name,
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
};
|
||||
|
||||
void gpio_init(void)
|
||||
{
|
||||
/* Apply all initial GPIO settings */
|
||||
for(int i = 0; i < PINGROUP_COUNT; ++i) {
|
||||
const struct pingroup_setting* d = &pingroup_settings[i];
|
||||
if(d->pins != 0)
|
||||
gpioz_configure(d->port, d->pins, d->func);
|
||||
}
|
||||
|
||||
for(int i = 0; i < PIN_COUNT; ++i) {
|
||||
const struct gpio_setting* d = &gpio_settings[i];
|
||||
if(d->gpio != GPIO_NONE)
|
||||
gpioz_configure(GPION_PORT(d->gpio), GPION_MASK(d->gpio), d->func);
|
||||
}
|
||||
|
||||
/* Any GPIO pins left in an IRQ trigger state need to be switched off,
|
||||
* because the drivers won't be ready to handle the interrupts until they
|
||||
* get initialized later in the boot. */
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
uint32_t intbits = REG_GPIO_INT(i);
|
||||
if(intbits) {
|
||||
gpio_config(i, intbits, GPIO_INPUT);
|
||||
gpioz_configure(i, intbits, GPIOF_INPUT);
|
||||
jz_clr(GPIO_FLAG(i), intbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_config(int port, unsigned pinmask, int func)
|
||||
void gpioz_configure(int port, uint32_t pins, int func)
|
||||
{
|
||||
unsigned intr = REG_GPIO_INT(port);
|
||||
unsigned mask = REG_GPIO_MSK(port);
|
||||
unsigned pat1 = REG_GPIO_PAT1(port);
|
||||
unsigned pat0 = REG_GPIO_PAT0(port);
|
||||
uint32_t intr = REG_GPIO_INT(port);
|
||||
uint32_t mask = REG_GPIO_MSK(port);
|
||||
uint32_t pat1 = REG_GPIO_PAT1(port);
|
||||
uint32_t pat0 = REG_GPIO_PAT0(port);
|
||||
|
||||
if(func & 8) jz_set(GPIO_INT(GPIO_Z), (intr & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_INT(GPIO_Z), (~intr & pinmask) ^ pinmask);
|
||||
if(func & 4) jz_set(GPIO_MSK(GPIO_Z), (mask & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pinmask) ^ pinmask);
|
||||
if(func & 2) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pinmask) ^ pinmask);
|
||||
if(func & 1) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pinmask) ^ pinmask);
|
||||
else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pinmask) ^ pinmask);
|
||||
/* Note: GPIO Z has _only_ set and clear registers, which are used to
|
||||
* atomically manipulate the selected GPIO port when we write GID2LD.
|
||||
* So there's not really any direct setting or clearing going on here...
|
||||
*/
|
||||
if(func & GPIO_F_INT) jz_set(GPIO_INT(GPIO_Z), (intr & pins) ^ pins);
|
||||
else jz_clr(GPIO_INT(GPIO_Z), (~intr & pins) ^ pins);
|
||||
if(func & GPIO_F_MASK) jz_set(GPIO_MSK(GPIO_Z), (mask & pins) ^ pins);
|
||||
else jz_clr(GPIO_MSK(GPIO_Z), (~mask & pins) ^ pins);
|
||||
if(func & GPIO_F_PAT1) jz_set(GPIO_PAT1(GPIO_Z), (pat1 & pins) ^ pins);
|
||||
else jz_clr(GPIO_PAT1(GPIO_Z), (~pat1 & pins) ^ pins);
|
||||
if(func & GPIO_F_PAT0) jz_set(GPIO_PAT0(GPIO_Z), (pat0 & pins) ^ pins);
|
||||
else jz_clr(GPIO_PAT0(GPIO_Z), (~pat0 & pins) ^ pins);
|
||||
REG_GPIO_Z_GID2LD = port;
|
||||
gpio_set_pull(port, pinmask, func & 16);
|
||||
|
||||
if(func & GPIO_F_PULL)
|
||||
jz_set(GPIO_PULL(port), pins);
|
||||
else
|
||||
jz_clr(GPIO_PULL(port), pins);
|
||||
}
|
||||
|
|
|
@ -22,33 +22,6 @@
|
|||
#ifndef __GPIO_X1000_H__
|
||||
#define __GPIO_X1000_H__
|
||||
|
||||
/* GPIO API
|
||||
* --------
|
||||
*
|
||||
* To assign a new function to a GPIO, call gpio_config(). This uses the
|
||||
* hardware's GPIO Z facility to atomically set most GPIO registers at once,
|
||||
* so it can be used to make any state transition safely. Since GPIO Z is
|
||||
* a global hardware resource, it is unsafe to call gpio_config() from IRQ
|
||||
* context -- if the interrupted code was also running gpio_config(), then
|
||||
* the results would be unpredictable.
|
||||
*
|
||||
* Depending on the current GPIO state, certain state transitions are safe to
|
||||
* perform without locking, as they only change one register:
|
||||
*
|
||||
* - for pins in GPIO_OUTPUT state:
|
||||
* - use gpio_out_level() to change the output level
|
||||
*
|
||||
* - for pins in GPIO_IRQ_LEVEL or GPIO_IRQ_EDGE state:
|
||||
* - use gpio_irq_level() to change the trigger level
|
||||
* - use gpio_irq_mask() to mask/unmask the IRQ
|
||||
*
|
||||
* - for pins in GPIO_DEVICE or GPIO_INPUT state:
|
||||
* - no special transitions allowed
|
||||
*
|
||||
* - in all states:
|
||||
* - use gpio_set_pull() to change the pull-up/pull-down state
|
||||
*/
|
||||
|
||||
#include "x1000/gpio.h"
|
||||
|
||||
/* GPIO port numbers */
|
||||
|
@ -66,42 +39,137 @@
|
|||
#define GPIO_F_PAT0 1
|
||||
|
||||
/* GPIO function numbers */
|
||||
#define GPIO_DEVICE(i) ((i)&3)
|
||||
#define GPIO_OUTPUT(i) (0x4|((i)&1))
|
||||
#define GPIO_INPUT 0x16
|
||||
#define GPIO_IRQ_LEVEL(i) (0x1c|((i)&1))
|
||||
#define GPIO_IRQ_EDGE(i) (0x1e|((i)&1))
|
||||
#define GPIOF_DEVICE(i) ((i)&3)
|
||||
#define GPIOF_OUTPUT(i) (0x4|((i)&1))
|
||||
#define GPIOF_INPUT 0x16
|
||||
#define GPIOF_IRQ_LEVEL(i) (0x1c|((i)&1))
|
||||
#define GPIOF_IRQ_EDGE(i) (0x1e|((i)&1))
|
||||
|
||||
/* GPIO pin numbers */
|
||||
#define GPION_CREATE(port, pin) ((((port) & 3) << 5) | ((pin) & 0x1f))
|
||||
#define GPION_PORT(gpio) (((gpio) >> 5) & 3)
|
||||
#define GPION_PIN(gpio) ((gpio) & 0x1f)
|
||||
#define GPION_MASK(gpio) (1u << GPION_PIN(gpio))
|
||||
|
||||
/* Easy pin number macros */
|
||||
#define GPIO_PA(x) GPION_CREATE(GPIO_A, x)
|
||||
#define GPIO_PB(x) GPION_CREATE(GPIO_B, x)
|
||||
#define GPIO_PC(x) GPION_CREATE(GPIO_C, x)
|
||||
#define GPIO_PD(x) GPION_CREATE(GPIO_D, x)
|
||||
|
||||
/* Pingroup settings are used for system devices */
|
||||
struct pingroup_setting {
|
||||
int port;
|
||||
uint32_t pins;
|
||||
int func;
|
||||
};
|
||||
|
||||
/* GPIO settings are used for single pins under software control */
|
||||
struct gpio_setting {
|
||||
int gpio;
|
||||
int func;
|
||||
};
|
||||
|
||||
/* Target pins are defined as GPIO_XXX constants usable with the GPIO API */
|
||||
enum {
|
||||
#define DEFINE_GPIO(_name, _gpio, _func) GPIO_##_name = _gpio,
|
||||
#define DEFINE_PINGROUP(...)
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
GPIO_NONE = -1,
|
||||
};
|
||||
|
||||
/* These are pin IDs which index gpio_settings */
|
||||
enum {
|
||||
#define DEFINE_GPIO(_name, ...) PIN_##_name,
|
||||
#define DEFINE_PINGROUP(...)
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
PIN_COUNT,
|
||||
};
|
||||
|
||||
/* Pingroup IDs which index pingroup_settings */
|
||||
enum {
|
||||
#define DEFINE_GPIO(...)
|
||||
#define DEFINE_PINGROUP(_name, ...) PINGROUP_##_name,
|
||||
#include "gpio-target.h"
|
||||
#undef DEFINE_GPIO
|
||||
#undef DEFINE_PINGROUP
|
||||
PINGROUP_COUNT,
|
||||
};
|
||||
|
||||
/* arrays which define the target's GPIO settings */
|
||||
extern const struct gpio_setting gpio_settings[PIN_COUNT];
|
||||
extern const struct pingroup_setting pingroup_settings[PINGROUP_COUNT];
|
||||
|
||||
/* stringified names for use in debug menus */
|
||||
extern const char* const gpio_names[PIN_COUNT];
|
||||
extern const char* const pingroup_names[PINGROUP_COUNT];
|
||||
|
||||
/* called at early init to set up GPIOs */
|
||||
extern void gpio_init(void);
|
||||
extern void gpio_config(int port, unsigned pinmask, int func);
|
||||
|
||||
static inline void gpio_out_level(int port, unsigned pinmask, int level)
|
||||
/* Use GPIO Z to reconfigure several pins atomically */
|
||||
extern void gpioz_configure(int port, uint32_t pins, int func);
|
||||
|
||||
static inline void gpio_set_function(int gpio, int func)
|
||||
{
|
||||
if(level)
|
||||
jz_set(GPIO_PAT0(port), pinmask);
|
||||
else
|
||||
jz_clr(GPIO_PAT0(port), pinmask);
|
||||
gpioz_configure(GPION_PORT(gpio), GPION_MASK(gpio), func);
|
||||
}
|
||||
|
||||
#define gpio_irq_level gpio_out_level
|
||||
|
||||
static inline void gpio_irq_mask(int port, unsigned pinmask, int masked)
|
||||
static inline int gpio_get_level(int gpio)
|
||||
{
|
||||
if(masked)
|
||||
jz_set(GPIO_MSK(port), pinmask);
|
||||
else
|
||||
jz_clr(GPIO_MSK(port), pinmask);
|
||||
return REG_GPIO_PIN(GPION_PORT(gpio)) & GPION_MASK(gpio) ? 1 : 0;
|
||||
}
|
||||
|
||||
#define gpio_enable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 0)
|
||||
#define gpio_disable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 1)
|
||||
static inline void gpio_set_level(int gpio, int value)
|
||||
{
|
||||
if(value)
|
||||
jz_set(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
else
|
||||
jz_clr(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
}
|
||||
|
||||
static inline void gpio_set_pull(int port, unsigned pinmask, int state)
|
||||
static inline void gpio_set_pull(int gpio, int state)
|
||||
{
|
||||
if(state)
|
||||
jz_set(GPIO_PULL(port), pinmask);
|
||||
jz_set(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
else
|
||||
jz_clr(GPIO_PULL(port), pinmask);
|
||||
jz_clr(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
}
|
||||
|
||||
static inline void gpio_mask_irq(int gpio, int mask)
|
||||
{
|
||||
if(mask)
|
||||
jz_set(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
else
|
||||
jz_clr(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
|
||||
}
|
||||
|
||||
#define gpio_set_irq_level gpio_set_level
|
||||
#define gpio_enable_irq(gpio) gpio_mask_irq((gpio), 0)
|
||||
#define gpio_disable_irq(gpio) gpio_mask_irq((gpio), 1)
|
||||
|
||||
/* Helper function for edge-triggered IRQs when you want to get an
|
||||
* interrupt on both the rising and falling edges. The hardware can
|
||||
* only be set up to interrupt on one edge, so interrupt handlers
|
||||
* can call this function to flip the trigger to the other edge.
|
||||
*
|
||||
* Despite the name, this doesn't depend on the currently set edge,
|
||||
* it just reads the GPIO state and sets up an edge trigger to detect
|
||||
* a change to the other state -- if some transitions were missed the
|
||||
* IRQ trigger may remain unchanged.
|
||||
*
|
||||
* It can be safely used to initialize the IRQ level.
|
||||
*/
|
||||
static inline void gpio_flip_edge_irq(int gpio)
|
||||
{
|
||||
if(gpio_get_level(gpio))
|
||||
gpio_set_irq_level(gpio, 0);
|
||||
else
|
||||
gpio_set_irq_level(gpio, 1);
|
||||
}
|
||||
|
||||
#endif /* __GPIO_X1000_H__ */
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "kernel.h"
|
||||
#include "panic.h"
|
||||
#include "logf.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "clk-x1000.h"
|
||||
#include "irq-x1000.h"
|
||||
#include "x1000/i2c.h"
|
||||
|
@ -375,18 +374,6 @@ void i2c_init(void)
|
|||
/* Stuff only required during initialization is below, basically the same as
|
||||
* the old driver except for how the IRQs are initially set up. */
|
||||
|
||||
static const struct {
|
||||
int port;
|
||||
unsigned pins;
|
||||
int func;
|
||||
} i2c_x1000_gpio_data[] = {
|
||||
{GPIO_B, 3 << 23, GPIO_DEVICE(0)},
|
||||
{GPIO_C, 3 << 26, GPIO_DEVICE(0)},
|
||||
/* Note: I2C1 is also on the following pins (normally used by LCD) */
|
||||
/* {GPIO_A, 3 << 0, GPIO_DEVICE(2)}, */
|
||||
{GPIO_D, 3 << 0, GPIO_DEVICE(1)},
|
||||
};
|
||||
|
||||
static void i2c_x1000_gate(int chn, int gate)
|
||||
{
|
||||
switch(chn) {
|
||||
|
@ -468,11 +455,6 @@ void i2c_x1000_set_freq(int chn, int freq)
|
|||
jz_write(I2C_FHCNT(chn), t_HIGH);
|
||||
}
|
||||
|
||||
/* Claim pins */
|
||||
gpio_config(i2c_x1000_gpio_data[chn].port,
|
||||
i2c_x1000_gpio_data[chn].pins,
|
||||
i2c_x1000_gpio_data[chn].func);
|
||||
|
||||
/* Enable the controller */
|
||||
i2c_x1000_enable(chn);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,8 @@ static const msc_config msc_configs[] = {
|
|||
.msc_type = MSC_TYPE_SD,
|
||||
.bus_width = 4,
|
||||
.label = "microSD",
|
||||
.cd_gpio = {GPIO_B, 1 << 6, 0},
|
||||
.cd_gpio = GPIO_MSC0_CD,
|
||||
.cd_active_level = 0,
|
||||
},
|
||||
#else
|
||||
# error "Please add X1000 MSC config"
|
||||
|
@ -117,40 +118,14 @@ static void msc_init_one(msc_drv* d, int msc)
|
|||
msc_full_reset(d);
|
||||
system_enable_irq(msc == 0 ? IRQ_MSC0 : IRQ_MSC1);
|
||||
|
||||
/* Configure bus pins */
|
||||
int port, device;
|
||||
unsigned pins;
|
||||
if(msc == 0) {
|
||||
port = GPIO_A;
|
||||
device = 1;
|
||||
switch(d->config->bus_width) {
|
||||
case 8: pins = 0x3ff << 16; break;
|
||||
case 4: pins = 0x03f << 20; break;
|
||||
case 1: pins = 0x007 << 23; break;
|
||||
default: pins = 0; break;
|
||||
}
|
||||
} else {
|
||||
port = GPIO_C;
|
||||
device = 0;
|
||||
switch(d->config->bus_width) {
|
||||
case 4: pins = 0x3f; break;
|
||||
case 1: pins = 0x07; break;
|
||||
default: pins = 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
gpio_config(port, pins, GPIO_DEVICE(device));
|
||||
|
||||
/* Setup the card detect IRQ */
|
||||
if(d->config->cd_gpio.pin) {
|
||||
port = d->config->cd_gpio.port;
|
||||
pins = d->config->cd_gpio.pin;
|
||||
int level = (REG_GPIO_PIN(port) & pins) ? 1 : 0;
|
||||
if(level != d->config->cd_gpio.active_level)
|
||||
if(d->config->cd_gpio != GPIO_NONE) {
|
||||
if(gpio_get_level(d->config->cd_gpio) != d->config->cd_active_level)
|
||||
d->card_present = 0;
|
||||
|
||||
gpio_config(port, pins, GPIO_IRQ_EDGE(level ? 0 : 1));
|
||||
gpio_enable_irq(port, pins);
|
||||
gpio_set_function(d->config->cd_gpio, GPIOF_IRQ_EDGE(1));
|
||||
gpio_flip_edge_irq(d->config->cd_gpio);
|
||||
gpio_enable_irq(d->config->cd_gpio);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,12 +187,10 @@ void msc_full_reset(msc_drv* d)
|
|||
|
||||
bool msc_card_detect(msc_drv* d)
|
||||
{
|
||||
if(!d->config->cd_gpio.pin)
|
||||
if(d->config->cd_gpio == GPIO_NONE)
|
||||
return true;
|
||||
|
||||
int l = REG_GPIO_PIN(d->config->cd_gpio.port) & d->config->cd_gpio.pin;
|
||||
l = l ? 1 : 0;
|
||||
return l == d->config->cd_gpio.active_level;
|
||||
return gpio_get_level(d->config->cd_gpio) == d->config->cd_active_level;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
@ -661,7 +634,7 @@ static void msc_cd_interrupt(msc_drv* d)
|
|||
}
|
||||
|
||||
/* Invert the IRQ */
|
||||
REG_GPIO_PAT0(d->config->cd_gpio.port) ^= d->config->cd_gpio.pin;
|
||||
gpio_flip_edge_irq(d->config->cd_gpio);
|
||||
}
|
||||
|
||||
void MSC0(void)
|
||||
|
|
|
@ -83,18 +83,13 @@
|
|||
#define MSC_SPEED_FAST 25000000
|
||||
#define MSC_SPEED_HIGH 50000000
|
||||
|
||||
typedef struct msc_gpio_data {
|
||||
int port;
|
||||
int pin;
|
||||
int active_level;
|
||||
} msc_gpio_data;
|
||||
|
||||
typedef struct msc_config {
|
||||
int msc_nr;
|
||||
int msc_type;
|
||||
int bus_width;
|
||||
const char* label;
|
||||
struct msc_gpio_data cd_gpio;
|
||||
int cd_gpio;
|
||||
int cd_active_level;
|
||||
} msc_config;
|
||||
|
||||
typedef struct msc_req {
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "panic.h"
|
||||
#include "dma-x1000.h"
|
||||
#include "irq-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "x1000/aic.h"
|
||||
#include "x1000/cpm.h"
|
||||
|
||||
|
@ -55,7 +54,6 @@ void pcm_play_dma_init(void)
|
|||
* on Ingenic's datasheets but I'm not sure what they are. Probably safe to
|
||||
* assume they are not useful to Rockbox... */
|
||||
jz_writef(CPM_CLKGR, AIC(0));
|
||||
gpio_config(GPIO_B, 0x1f, GPIO_DEVICE(1));
|
||||
|
||||
/* Configure AIC with some sane defaults */
|
||||
jz_writef(AIC_CFG, RST(1));
|
||||
|
|
|
@ -26,12 +26,6 @@
|
|||
#include "kernel.h"
|
||||
#include "x1000/tcu.h"
|
||||
|
||||
struct pwm_gpio_data {
|
||||
int port;
|
||||
unsigned pin;
|
||||
int func;
|
||||
};
|
||||
|
||||
struct pwm_state {
|
||||
int period_ns;
|
||||
int duty_ns;
|
||||
|
@ -40,14 +34,6 @@ struct pwm_state {
|
|||
int prescaler;
|
||||
};
|
||||
|
||||
static const struct pwm_gpio_data pwm_gpios[] = {
|
||||
{GPIO_C, 1 << 25, GPIO_DEVICE(0)},
|
||||
{GPIO_C, 1 << 26, GPIO_DEVICE(1)},
|
||||
{GPIO_C, 1 << 27, GPIO_DEVICE(1)},
|
||||
{GPIO_B, 1 << 6, GPIO_DEVICE(2)},
|
||||
{GPIO_C, 1 << 24, GPIO_DEVICE(0)},
|
||||
};
|
||||
|
||||
static struct pwm_state pwm_state[] = {
|
||||
{-1, -1, -1, -1, -1},
|
||||
{-1, -1, -1, -1, -1},
|
||||
|
@ -56,6 +42,22 @@ static struct pwm_state pwm_state[] = {
|
|||
{-1, -1, -1, -1, -1},
|
||||
};
|
||||
|
||||
static const int pwm_gpio[] = {
|
||||
GPIO_PC(25),
|
||||
GPIO_PC(26),
|
||||
GPIO_PC(27),
|
||||
GPIO_PB(6),
|
||||
GPIO_PC(24),
|
||||
};
|
||||
|
||||
static const int pwm_gpio_func[] = {
|
||||
GPIOF_DEVICE(0),
|
||||
GPIOF_DEVICE(1),
|
||||
GPIOF_DEVICE(1),
|
||||
GPIOF_DEVICE(2),
|
||||
GPIOF_DEVICE(0),
|
||||
};
|
||||
|
||||
void pwm_init(int chn)
|
||||
{
|
||||
/* clear cached state */
|
||||
|
@ -67,8 +69,7 @@ void pwm_init(int chn)
|
|||
st->prescaler = -1;
|
||||
|
||||
/* clear GPIO and disable timer */
|
||||
const struct pwm_gpio_data* pg = &pwm_gpios[chn];
|
||||
gpio_config(pg->port, pg->pin, GPIO_OUTPUT(0));
|
||||
gpio_set_function(pwm_gpio[chn], GPIOF_OUTPUT(0));
|
||||
jz_clr(TCU_STOP, 1 << chn);
|
||||
jz_clr(TCU_ENABLE, 1 << chn);
|
||||
jz_set(TCU_STOP, 1 << chn);
|
||||
|
@ -161,15 +162,13 @@ void pwm_enable(int chn)
|
|||
jz_set(TCU_ENABLE, 1 << chn);
|
||||
|
||||
/* Configure GPIO function */
|
||||
const struct pwm_gpio_data* pg = &pwm_gpios[chn];
|
||||
gpio_config(pg->port, pg->pin, pg->func);
|
||||
gpio_set_function(pwm_gpio[chn], pwm_gpio_func[chn]);
|
||||
}
|
||||
|
||||
void pwm_disable(int chn)
|
||||
{
|
||||
/* Set GPIO to output 0 */
|
||||
const struct pwm_gpio_data* pg = &pwm_gpios[chn];
|
||||
gpio_config(pg->port, pg->pin, GPIO_OUTPUT(0));
|
||||
gpio_set_function(pwm_gpio[chn], GPIOF_OUTPUT(0));
|
||||
|
||||
/* Stop timer */
|
||||
jz_clr(TCU_ENABLE, 1 << chn);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "sdmmc.h"
|
||||
#include "sd.h"
|
||||
#include "msc-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include <string.h>
|
||||
|
||||
/* #define LOGF_ENABLE */
|
||||
|
@ -201,7 +202,7 @@ bool sd_removable(IF_MD_NONVOID(int drive))
|
|||
if(drive < 0)
|
||||
return false;
|
||||
|
||||
return sd_to_msc[IF_MD_DRV(drive)]->config->cd_gpio.pin != 0;
|
||||
return sd_to_msc[IF_MD_DRV(drive)]->config->cd_gpio != GPIO_NONE;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_STORAGE_MULTI
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "kernel.h"
|
||||
#include "panic.h"
|
||||
#include "sfc-x1000.h"
|
||||
#include "gpio-x1000.h"
|
||||
#include "irq-x1000.h"
|
||||
#include "x1000/sfc.h"
|
||||
#include "x1000/cpm.h"
|
||||
|
@ -75,7 +74,6 @@ void sfc_unlock(void)
|
|||
|
||||
void sfc_open(void)
|
||||
{
|
||||
gpio_config(GPIO_A, 0x3f << 26, GPIO_DEVICE(1));
|
||||
jz_writef(CPM_CLKGR, SFC(0));
|
||||
jz_writef(SFC_GLB, OP_MODE_V(SLAVE), PHASE_NUM(1),
|
||||
THRESHOLD(FIFO_THRESH), WP_EN(1));
|
||||
|
|
|
@ -29,20 +29,9 @@
|
|||
#include "x1000/cpm.h"
|
||||
|
||||
#ifdef FIIO_M3K
|
||||
# define USB_DETECT_PORT GPIO_B
|
||||
# define USB_DETECT_PIN (1 << 11)
|
||||
# define USB_DETECT_PIN_INT GPIOB11
|
||||
# define USB_ID_PORT GPIO_B
|
||||
# define USB_ID_PIN (1 << 7)
|
||||
#else
|
||||
# ifndef USB_NONE
|
||||
# error "please add USB GPIO pins"
|
||||
# endif
|
||||
# define USB_DETECT_PIN_INT GPIOB11 // TODO remove me
|
||||
#endif
|
||||
|
||||
#define USB_DRVVBUS_PORT GPIO_B
|
||||
#define USB_DRVVBUS_PIN (1 << 25)
|
||||
|
||||
/*
|
||||
* USB-Designware driver API
|
||||
*/
|
||||
|
@ -165,7 +154,8 @@ static volatile int usb_status = USB_EXTRACTED;
|
|||
|
||||
static int __usb_detect(void)
|
||||
{
|
||||
if(REG_GPIO_PIN(USB_DETECT_PORT) & USB_DETECT_PIN)
|
||||
/* XXX: Do we need an active level define for this? */
|
||||
if(gpio_get_level(GPIO_USB_DETECT))
|
||||
return USB_INSERTED;
|
||||
else
|
||||
return USB_EXTRACTED;
|
||||
|
@ -183,7 +173,7 @@ void usb_init_device(void)
|
|||
{
|
||||
/* Disable drvvbus pin -- it is only used when acting as a host,
|
||||
* which Rockbox does not support */
|
||||
gpio_config(USB_DRVVBUS_PORT, USB_DRVVBUS_PIN, GPIO_OUTPUT(0));
|
||||
gpio_set_function(GPIO_USB_DRVVBUS, GPIOF_OUTPUT(0));
|
||||
|
||||
/* Power up the core clocks to allow writing
|
||||
to some registers needed to power it down */
|
||||
|
@ -194,9 +184,9 @@ void usb_init_device(void)
|
|||
#ifdef USB_STATUS_BY_EVENT
|
||||
/* Setup USB detect pin IRQ */
|
||||
usb_status = __usb_detect();
|
||||
int level = (REG_GPIO_PIN(USB_DETECT_PORT) & USB_DETECT_PIN) ? 1 : 0;
|
||||
gpio_config(USB_DETECT_PORT, USB_DETECT_PIN, GPIO_IRQ_EDGE(level ? 0 : 1));
|
||||
gpio_enable_irq(USB_DETECT_PORT, USB_DETECT_PIN);
|
||||
gpio_set_function(GPIO_USB_DETECT, GPIOF_IRQ_EDGE(1));
|
||||
gpio_flip_edge_irq(GPIO_USB_DETECT);
|
||||
gpio_enable_irq(GPIO_USB_DETECT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -215,7 +205,7 @@ void USB_DETECT_PIN_INT(void)
|
|||
{
|
||||
/* Update status and flip the IRQ trigger edge */
|
||||
usb_status = __usb_detect();
|
||||
REG_GPIO_PAT0(USB_DETECT_PORT) ^= USB_DETECT_PIN;
|
||||
gpio_flip_edge_irq(GPIO_USB_DETECT);
|
||||
|
||||
/* Notify Rockbox of event */
|
||||
usb_status_event(usb_status);
|
||||
|
|
Loading…
Reference in New Issue