commit
805fa87f6d
@ -0,0 +1,78 @@ |
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Analog Devices Inc. |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#ifndef __CLOCK_H__ |
||||
#define __CLOCK_H__ |
||||
|
||||
#include <asm/blackfin.h> |
||||
#ifdef PLL_CTL |
||||
#include <asm/mach-common/bits/pll.h> |
||||
# define pll_is_bypassed() (bfin_read_PLL_CTL() & BYPASS) |
||||
#else |
||||
#include <asm/mach-common/bits/cgu.h> |
||||
# define pll_is_bypassed() (bfin_read_CGU_STAT() & PLLBP) |
||||
# define bfin_read_PLL_CTL() bfin_read_CGU_CTL() |
||||
# define bfin_read_PLL_DIV() bfin_read_CGU_DIV() |
||||
# define SSEL SYSSEL |
||||
# define SSEL_P SYSSEL_P |
||||
#endif |
||||
|
||||
__attribute__((always_inline)) |
||||
static inline uint32_t early_division(uint32_t dividend, uint32_t divisor) |
||||
{ |
||||
uint32_t quotient; |
||||
uint32_t i, j; |
||||
|
||||
for (quotient = 1, i = 1; dividend > divisor; ++i) { |
||||
j = divisor << i; |
||||
if (j > dividend || (j & 0x80000000)) { |
||||
--i; |
||||
quotient += (1 << i); |
||||
dividend -= (divisor << i); |
||||
i = 0; |
||||
} |
||||
} |
||||
|
||||
return quotient; |
||||
} |
||||
|
||||
__attribute__((always_inline)) |
||||
static inline uint32_t early_get_uart_clk(void) |
||||
{ |
||||
uint32_t msel, pll_ctl, vco; |
||||
uint32_t div, ssel, sclk, uclk; |
||||
|
||||
pll_ctl = bfin_read_PLL_CTL(); |
||||
msel = (pll_ctl & MSEL) >> MSEL_P; |
||||
if (msel == 0) |
||||
msel = (MSEL >> MSEL_P) + 1; |
||||
|
||||
vco = (CONFIG_CLKIN_HZ >> (pll_ctl & DF)) * msel; |
||||
sclk = vco; |
||||
if (!pll_is_bypassed()) { |
||||
div = bfin_read_PLL_DIV(); |
||||
ssel = (div & SSEL) >> SSEL_P; |
||||
#if CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_BYPASS |
||||
sclk = vco/ssel; |
||||
#else |
||||
sclk = early_division(vco, ssel); |
||||
#endif |
||||
} |
||||
uclk = sclk; |
||||
#ifdef CGU_DIV |
||||
ssel = (div & S0SEL) >> S0SEL_P; |
||||
uclk = early_division(sclk, ssel); |
||||
#endif |
||||
return uclk; |
||||
} |
||||
|
||||
#ifdef CGU_DIV |
||||
# define get_uart_clk get_sclk0 |
||||
#else |
||||
# define get_uart_clk get_sclk |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,18 @@ |
||||
/*
|
||||
* U-boot - main board file |
||||
* |
||||
* Copyright (c) 2008-2012 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#ifndef __SOFT_SWITCH_H__ |
||||
#define __SOFT_SWITCH_H__ |
||||
|
||||
#define IO_PORT_A 0 |
||||
#define IO_PORT_B 1 |
||||
#define IO_PORT_INPUT 0 |
||||
#define IO_PORT_OUTPUT 1 |
||||
|
||||
int config_switch_bit(int num, int port, int bit, int dir, uchar value); |
||||
#endif |
@ -0,0 +1,171 @@ |
||||
/*
|
||||
* U-boot - main board file |
||||
* |
||||
* Copyright (c) 2008-2011 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/blackfin.h> |
||||
#include <asm/io.h> |
||||
#include <i2c.h> |
||||
#include "soft_switch.h" |
||||
|
||||
struct switch_config { |
||||
uchar dir0; /* IODIRA */ |
||||
uchar dir1; /* IODIRB */ |
||||
uchar value0; /* OLATA */ |
||||
uchar value1; /* OLATB */ |
||||
}; |
||||
|
||||
static struct switch_config switch_config_array[NUM_SWITCH] = { |
||||
{ |
||||
/*
|
||||
U45 Port A U45 Port B |
||||
|
||||
7--------------- RMII_CLK_EN | 7--------------- ~TEMP_THERM_EN |
||||
| 6------------- ~CNT0ZM_EN | | 6------------- ~TEMP_IRQ_EN |
||||
| | 5----------- ~CNT0DG_EN | | | 5----------- ~UART0CTS_146_EN |
||||
| | | 4--------- ~CNT0UD_EN | | | | 4--------- ~UART0CTS_RST_EN |
||||
| | | | 3------- ~CAN0RX_EN | | | | | 3------- ~UART0CTS_RTS_LPBK |
||||
| | | | | 2----- ~CAN0_ERR_EN | | | | | | 2----- ~UART0CTS_EN |
||||
| | | | | | 1--- ~CAN_STB | | | | | | | 1--- ~UART0RX_EN |
||||
| | | | | | | 0- CAN_EN | | | | | | | | 0- ~UART0RTS_EN |
||||
| | | | | | | | | | | | | | | | | |
||||
O O O O O O O O | O O O O O O O O (I/O direction) |
||||
1 0 0 0 0 0 1 1 | 1 1 1 1 1 0 0 0 (value being set) |
||||
*/ |
||||
.dir0 = 0x0, /* all output */ |
||||
.dir1 = 0x0, /* all output */ |
||||
.value0 = RMII_CLK_EN | CAN_STB | CAN_EN, |
||||
.value1 = TEMP_THERM_EN | TEMP_IRQ_EN | UART0CTS_146_EN |
||||
| UART0CTS_RST_EN | UART0CTS_RTS_LPBK, |
||||
}, |
||||
{ |
||||
/*
|
||||
U46 Port A U46 Port B |
||||
|
||||
7--------------- ~LED4_GPIO_EN | 7--------------- EMPTY |
||||
| 6------------- ~LED3_GPIO_EN | | 6------------- ~SPI0D3_EN |
||||
| | 5----------- ~LED2_GPIO_EN | | | 5----------- ~SPI0D2_EN |
||||
| | | 4--------- ~LED1_GPIO_EN | | | | 4--------- ~SPIFLASH_CS_EN |
||||
| | | | 3------- SMC0_LP0_EN | | | | | 3------- ~SD_WP_EN |
||||
| | | | | 2----- EMPTY | | | | | | 2----- ~SD_CD_EN |
||||
| | | | | | 1--- SMC0_EPPI2 | | | | | | | 1--- ~PUSHBUTTON2_EN |
||||
_LP1_SWITCH |
||||
| | | | | | | 0- OVERRIDE_SMC0 | | | | | | | | 0- ~PUSHBUTTON1_EN |
||||
_LP0_BOOT |
||||
| | | | | | | | | | | | | | | | | |
||||
O O O O O O O O | O O O O O O O O (I/O direction) |
||||
0 0 0 0 0 X 0 1 | X 0 0 0 0 0 0 0 (value being set) |
||||
*/ |
||||
.dir0 = 0x0, /* all output */ |
||||
.dir1 = 0x0, /* all output */ |
||||
#ifdef CONFIG_BFIN_LINKPORT |
||||
.value0 = OVERRIDE_SMC0_LP0_BOOT, |
||||
#else |
||||
.value0 = SMC0_EPPI2_LP1_SWITCH, |
||||
#endif |
||||
.value1 = 0x0, |
||||
}, |
||||
{ |
||||
/*
|
||||
U47 Port A U47 Port B |
||||
|
||||
7--------------- ~PD2_SPI0MISO | 7--------------- EMPTY |
||||
_EI3_EN |
||||
| 6------------- ~PD1_SPI0D3 | | 6------------- EMPTY |
||||
_EPPI1D17 |
||||
_SPI0SEL2 |
||||
_EI3_EN |
||||
| | 5----------- ~PD0_SPI0D2 | | | 5----------- EMPTY |
||||
_EPPI1D16 |
||||
_SPI0SEL3 |
||||
_EI3_EN |
||||
| | | 4--------- ~WAKE_PUSH | | | | 4--------- EMPTY |
||||
BUTTON_EN |
||||
| | | | 3------- ~ETHERNET_EN | | | | | 3------- EMPTY |
||||
| | | | | 2----- PHYAD0 | | | | | | 2----- EMPTY |
||||
| | | | | | 1--- PHY_PWR | | | | | | | 1--- ~PD4_SPI0CK_EI3_EN |
||||
_DWN_INT |
||||
| | | | | | | 0- ~PHYINT_EN | | | | | | | | 0- ~PD3_SPI0MOSI_EI3_EN |
||||
| | | | | | | | | | | | | | | | | |
||||
O O O O O I I O | O O O O O O O O (I/O direction) |
||||
1 1 1 0 0 0 0 0 | X X X X X X 1 1 (value being set) |
||||
*/ |
||||
.dir0 = 0x6, /* bits 1 and 2 input, all others output */ |
||||
.dir1 = 0x0, /* all output */ |
||||
.value0 = PD1_SPI0D3_EN | PD0_SPI0D2_EN, |
||||
.value1 = 0, |
||||
}, |
||||
}; |
||||
|
||||
static int setup_soft_switch(int addr, struct switch_config *config) |
||||
{ |
||||
int ret = 0; |
||||
|
||||
ret = i2c_write(addr, OLATA, 1, &config->value0, 1); |
||||
if (ret) |
||||
return ret; |
||||
ret = i2c_write(addr, OLATB, 1, &config->value1, 1); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
ret = i2c_write(addr, IODIRA, 1, &config->dir0, 1); |
||||
if (ret) |
||||
return ret; |
||||
return i2c_write(addr, IODIRB, 1, &config->dir1, 1); |
||||
} |
||||
|
||||
int config_switch_bit(int addr, int port, int bit, int dir, uchar value) |
||||
{ |
||||
int ret, data_reg, dir_reg; |
||||
uchar tmp; |
||||
|
||||
if (port == IO_PORT_A) { |
||||
data_reg = OLATA; |
||||
dir_reg = IODIRA; |
||||
} else { |
||||
data_reg = OLATB; |
||||
dir_reg = IODIRB; |
||||
} |
||||
|
||||
if (dir == IO_PORT_INPUT) { |
||||
ret = i2c_read(addr, dir_reg, 1, &tmp, 1); |
||||
if (ret) |
||||
return ret; |
||||
tmp |= bit; |
||||
return i2c_write(addr, dir_reg, 1, &tmp, 1); |
||||
} else { |
||||
ret = i2c_read(addr, data_reg, 1, &tmp, 1); |
||||
if (ret) |
||||
return ret; |
||||
if (value) |
||||
tmp |= bit; |
||||
else |
||||
tmp &= ~bit; |
||||
ret = i2c_write(addr, data_reg, 1, &tmp, 1); |
||||
if (ret) |
||||
return ret; |
||||
ret = i2c_read(addr, dir_reg, 1, &tmp, 1); |
||||
if (ret) |
||||
return ret; |
||||
tmp &= ~bit; |
||||
return i2c_write(addr, dir_reg, 1, &tmp, 1); |
||||
} |
||||
} |
||||
|
||||
int setup_board_switches(void) |
||||
{ |
||||
int ret; |
||||
int i; |
||||
|
||||
for (i = 0; i < NUM_SWITCH; i++) { |
||||
ret = setup_soft_switch(SWITCH_ADDR + i, |
||||
&switch_config_array[i]); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,80 @@ |
||||
/*
|
||||
* U-boot - main board file |
||||
* |
||||
* Copyright (c) 2008-2011 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#ifndef __BOARD_SOFT_SWITCH_H__ |
||||
#define __BOARD_SOFT_SWITCH_H__ |
||||
|
||||
#include <asm/soft_switch.h> |
||||
|
||||
/* switch 0 port A */ |
||||
#define CAN_EN 0x1 |
||||
#define CAN_STB 0x2 |
||||
#define CAN0_ERR_EN 0x4 |
||||
#define CAN0RX_EN 0x8 |
||||
#define CNT0UD_EN 0x10 |
||||
#define CNT0DG_EN 0x20 |
||||
#define CNT0ZM_EN 0x40 |
||||
#define RMII_CLK_EN 0x80 |
||||
|
||||
/* switch 0 port B */ |
||||
#define UART0RTS_EN 0x1 |
||||
#define UART0RX_EN 0x2 |
||||
#define UART0CTS_EN 0x4 |
||||
#define UART0CTS_RTS_LPBK 0x8 |
||||
#define UART0CTS_RST_EN 0x10 |
||||
#define UART0CTS_146_EN 0x20 |
||||
#define TEMP_IRQ_EN 0x40 |
||||
#define TEMP_THERM_EN 0x80 |
||||
|
||||
/* switch 1 port A */ |
||||
#define OVERRIDE_SMC0_LP0_BOOT 0x1 |
||||
#define SMC0_EPPI2_LP1_SWITCH 0x2 |
||||
#define SMC0_LP0_EN 0x8 |
||||
#define LED1_GPIO_EN 0x10 |
||||
#define LED2_GPIO_EN 0x20 |
||||
#define LED3_GPIO_EN 0x40 |
||||
#define LED4_GPIO_EN 0x80 |
||||
|
||||
/* switch 1 port B */ |
||||
#define PUSHBUTTON1_EN 0x1 |
||||
#define PUSHBUTTON2_EN 0x2 |
||||
#define SD_CD_EN 0x4 |
||||
#define SD_WP_EN 0x8 |
||||
#define SPIFLASH_CS_EN 0x10 |
||||
#define SPI0D2_EN 0x20 |
||||
#define SPI0D3_EN 0x40 |
||||
|
||||
/* switch 2 port A */ |
||||
#define PHYINT_EN 0x1 |
||||
#define PHY_PWR_DWN_INT 0x2 |
||||
#define PHYAD0 0x4 |
||||
#define ETHERNET_EN 0x8 |
||||
#define WAKE_PUSHBUTTON_EN 0x10 |
||||
#define PD0_SPI0D2_EN 0x20 |
||||
#define PD1_SPI0D3_EN 0x40 |
||||
#define PD2_SPI0MISO_EN 0x80 |
||||
|
||||
/* switch 2 port B */ |
||||
#define PD3_SPI0MOSI_EN 0x1 |
||||
#define PD4_SPI0CK_EN 0x2 |
||||
|
||||
#ifdef CONFIG_BFIN_BOARD_VERSION_1_0 |
||||
#define SWITCH_ADDR 0x21 |
||||
#else |
||||
#define SWITCH_ADDR 0x20 |
||||
#endif |
||||
|
||||
#define NUM_SWITCH 3 |
||||
#define IODIRA 0x0 |
||||
#define IODIRB 0x1 |
||||
#define OLATA 0x14 |
||||
#define OLATB 0x15 |
||||
|
||||
int setup_board_switches(void); |
||||
|
||||
#endif /* __BOARD_SOFT_SWITCH_H__ */ |
@ -0,0 +1,41 @@ |
||||
/*
|
||||
* cmd_softswitch.c - set the softswitch for bf60x |
||||
* |
||||
* Copyright (c) 2012 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <command.h> |
||||
#include <asm/blackfin.h> |
||||
#include <asm/soft_switch.h> |
||||
|
||||
int do_softswitch(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
||||
{ |
||||
int switchaddr, value, pin, port; |
||||
|
||||
if (argc != 5) |
||||
return CMD_RET_USAGE; |
||||
|
||||
if (strcmp(argv[2], "GPA") == 0) |
||||
port = IO_PORT_A; |
||||
else if (strcmp(argv[2], "GPB") == 0) |
||||
port = IO_PORT_B; |
||||
else |
||||
return CMD_RET_USAGE; |
||||
|
||||
switchaddr = simple_strtoul(argv[1], NULL, 16); |
||||
pin = simple_strtoul(argv[3], NULL, 16); |
||||
value = simple_strtoul(argv[4], NULL, 16); |
||||
|
||||
config_switch_bit(switchaddr, port, (1 << pin), IO_PORT_OUTPUT, value); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
softswitch_output, 5, 1, do_softswitch, |
||||
"switchaddr GPA/GPB pin_offset value", |
||||
"" |
||||
); |
@ -0,0 +1,440 @@ |
||||
/*
|
||||
* ADI GPIO2 Abstraction Layer |
||||
* Support BF54x, BF60x and future processors. |
||||
* |
||||
* Copyright 2008-2013 Analog Devices Inc. |
||||
* |
||||
* Licensed under the GPL-2 or later |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/errno.h> |
||||
#include <asm/gpio.h> |
||||
#include <asm/portmux.h> |
||||
|
||||
static struct gpio_port_t * const gpio_array[] = { |
||||
(struct gpio_port_t *)PORTA_FER, |
||||
(struct gpio_port_t *)PORTB_FER, |
||||
(struct gpio_port_t *)PORTC_FER, |
||||
(struct gpio_port_t *)PORTD_FER, |
||||
(struct gpio_port_t *)PORTE_FER, |
||||
(struct gpio_port_t *)PORTF_FER, |
||||
(struct gpio_port_t *)PORTG_FER, |
||||
#if defined(CONFIG_BF54x) |
||||
(struct gpio_port_t *)PORTH_FER, |
||||
(struct gpio_port_t *)PORTI_FER, |
||||
(struct gpio_port_t *)PORTJ_FER, |
||||
#endif |
||||
}; |
||||
|
||||
#define RESOURCE_LABEL_SIZE 16 |
||||
|
||||
static struct str_ident { |
||||
char name[RESOURCE_LABEL_SIZE]; |
||||
} str_ident[MAX_RESOURCES]; |
||||
|
||||
static void gpio_error(unsigned gpio) |
||||
{ |
||||
printf("adi_gpio2: GPIO %d wasn't requested!\n", gpio); |
||||
} |
||||
|
||||
static void set_label(unsigned short ident, const char *label) |
||||
{ |
||||
if (label) { |
||||
strncpy(str_ident[ident].name, label, |
||||
RESOURCE_LABEL_SIZE); |
||||
str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; |
||||
} |
||||
} |
||||
|
||||
static char *get_label(unsigned short ident) |
||||
{ |
||||
return *str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"; |
||||
} |
||||
|
||||
static int cmp_label(unsigned short ident, const char *label) |
||||
{ |
||||
if (label == NULL) |
||||
printf("adi_gpio2: please provide none-null label\n"); |
||||
|
||||
if (label) |
||||
return strcmp(str_ident[ident].name, label); |
||||
else |
||||
return -EINVAL; |
||||
} |
||||
|
||||
#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)] |
||||
#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i)) |
||||
#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i)) |
||||
#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i)) |
||||
#define DECLARE_RESERVED_MAP(m, c) unsigned short reserved_##m##_map[c] |
||||
|
||||
static DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM); |
||||
static DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES)); |
||||
|
||||
inline int check_gpio(unsigned gpio) |
||||
{ |
||||
#if defined(CONFIG_BF54x) |
||||
if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 || |
||||
gpio == GPIO_PH14 || gpio == GPIO_PH15 || |
||||
gpio == GPIO_PJ14 || gpio == GPIO_PJ15) |
||||
return -EINVAL; |
||||
#endif |
||||
if (gpio >= MAX_GPIOS) |
||||
return -EINVAL; |
||||
return 0; |
||||
} |
||||
|
||||
static void port_setup(unsigned gpio, unsigned short usage) |
||||
{ |
||||
#if defined(CONFIG_BF54x) |
||||
if (usage == GPIO_USAGE) |
||||
gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); |
||||
else |
||||
gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); |
||||
#else |
||||
if (usage == GPIO_USAGE) |
||||
gpio_array[gpio_bank(gpio)]->port_fer_clear = gpio_bit(gpio); |
||||
else |
||||
gpio_array[gpio_bank(gpio)]->port_fer_set = gpio_bit(gpio); |
||||
#endif |
||||
SSYNC(); |
||||
} |
||||
|
||||
inline void portmux_setup(unsigned short per) |
||||
{ |
||||
u32 pmux; |
||||
u16 ident = P_IDENT(per); |
||||
u16 function = P_FUNCT2MUX(per); |
||||
|
||||
pmux = gpio_array[gpio_bank(ident)]->port_mux; |
||||
|
||||
pmux &= ~(0x3 << (2 * gpio_sub_n(ident))); |
||||
pmux |= (function & 0x3) << (2 * gpio_sub_n(ident)); |
||||
|
||||
gpio_array[gpio_bank(ident)]->port_mux = pmux; |
||||
} |
||||
|
||||
inline u16 get_portmux(unsigned short per) |
||||
{ |
||||
u32 pmux; |
||||
u16 ident = P_IDENT(per); |
||||
|
||||
pmux = gpio_array[gpio_bank(ident)]->port_mux; |
||||
|
||||
return pmux >> (2 * gpio_sub_n(ident)) & 0x3; |
||||
} |
||||
|
||||
unsigned short get_gpio_dir(unsigned gpio) |
||||
{ |
||||
return 0x01 & |
||||
(gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio)); |
||||
} |
||||
|
||||
/***********************************************************
|
||||
* |
||||
* FUNCTIONS: Peripheral Resource Allocation |
||||
* and PortMux Setup |
||||
* |
||||
* INPUTS/OUTPUTS: |
||||
* per Peripheral Identifier |
||||
* label String |
||||
* |
||||
* DESCRIPTION: Peripheral Resource Allocation and Setup API |
||||
**************************************************************/ |
||||
|
||||
int peripheral_request(unsigned short per, const char *label) |
||||
{ |
||||
unsigned short ident = P_IDENT(per); |
||||
|
||||
/*
|
||||
* Don't cares are pins with only one dedicated function |
||||
*/ |
||||
|
||||
if (per & P_DONTCARE) |
||||
return 0; |
||||
|
||||
if (!(per & P_DEFINED)) |
||||
return -ENODEV; |
||||
|
||||
BUG_ON(ident >= MAX_RESOURCES); |
||||
|
||||
/* If a pin can be muxed as either GPIO or peripheral, make
|
||||
* sure it is not already a GPIO pin when we request it. |
||||
*/ |
||||
if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) { |
||||
printf("%s: Peripheral %d is already reserved as GPIO by %s!\n", |
||||
__func__, ident, get_label(ident)); |
||||
return -EBUSY; |
||||
} |
||||
|
||||
if (unlikely(is_reserved(peri, ident, 1))) { |
||||
/*
|
||||
* Pin functions like AMC address strobes my |
||||
* be requested and used by several drivers |
||||
*/ |
||||
|
||||
if (!((per & P_MAYSHARE) && |
||||
get_portmux(per) == P_FUNCT2MUX(per))) { |
||||
/*
|
||||
* Allow that the identical pin function can |
||||
* be requested from the same driver twice |
||||
*/ |
||||
|
||||
if (cmp_label(ident, label) == 0) |
||||
goto anyway; |
||||
|
||||
printf("%s: Peripheral %d function %d is already " |
||||
"reserved by %s!\n", __func__, ident, |
||||
P_FUNCT2MUX(per), get_label(ident)); |
||||
return -EBUSY; |
||||
} |
||||
} |
||||
|
||||
anyway: |
||||
reserve(peri, ident); |
||||
|
||||
portmux_setup(per); |
||||
port_setup(ident, PERIPHERAL_USAGE); |
||||
|
||||
set_label(ident, label); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int peripheral_request_list(const unsigned short per[], const char *label) |
||||
{ |
||||
u16 cnt; |
||||
int ret; |
||||
|
||||
for (cnt = 0; per[cnt] != 0; cnt++) { |
||||
ret = peripheral_request(per[cnt], label); |
||||
|
||||
if (ret < 0) { |
||||
for (; cnt > 0; cnt--) |
||||
peripheral_free(per[cnt - 1]); |
||||
|
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void peripheral_free(unsigned short per) |
||||
{ |
||||
unsigned short ident = P_IDENT(per); |
||||
|
||||
if (per & P_DONTCARE) |
||||
return; |
||||
|
||||
if (!(per & P_DEFINED)) |
||||
return; |
||||
|
||||
if (unlikely(!is_reserved(peri, ident, 0))) |
||||
return; |
||||
|
||||
if (!(per & P_MAYSHARE)) |
||||
port_setup(ident, GPIO_USAGE); |
||||
|
||||
unreserve(peri, ident); |
||||
|
||||
set_label(ident, "free"); |
||||
} |
||||
|
||||
void peripheral_free_list(const unsigned short per[]) |
||||
{ |
||||
u16 cnt; |
||||
for (cnt = 0; per[cnt] != 0; cnt++) |
||||
peripheral_free(per[cnt]); |
||||
} |
||||
|
||||
/***********************************************************
|
||||
* |
||||
* FUNCTIONS: GPIO Driver |
||||
* |
||||
* INPUTS/OUTPUTS: |
||||
* gpio PIO Number between 0 and MAX_GPIOS |
||||
* label String |
||||
* |
||||
* DESCRIPTION: GPIO Driver API |
||||
**************************************************************/ |
||||
|
||||
int gpio_request(unsigned gpio, const char *label) |
||||
{ |
||||
if (check_gpio(gpio) < 0) |
||||
return -EINVAL; |
||||
|
||||
/*
|
||||
* Allow that the identical GPIO can |
||||
* be requested from the same driver twice |
||||
* Do nothing and return - |
||||
*/ |
||||
|
||||
if (cmp_label(gpio, label) == 0) |
||||
return 0; |
||||
|
||||
if (unlikely(is_reserved(gpio, gpio, 1))) { |
||||
printf("adi_gpio2: GPIO %d is already reserved by %s!\n", |
||||
gpio, get_label(gpio)); |
||||
return -EBUSY; |
||||
} |
||||
if (unlikely(is_reserved(peri, gpio, 1))) { |
||||
printf("adi_gpio2: GPIO %d is already reserved as Peripheral " |
||||
"by %s!\n", gpio, get_label(gpio)); |
||||
return -EBUSY; |
||||
} |
||||
|
||||
reserve(gpio, gpio); |
||||
set_label(gpio, label); |
||||
|
||||
port_setup(gpio, GPIO_USAGE); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int gpio_free(unsigned gpio) |
||||
{ |
||||
if (check_gpio(gpio) < 0) |
||||
return -1; |
||||
|
||||
if (unlikely(!is_reserved(gpio, gpio, 0))) { |
||||
gpio_error(gpio); |
||||
return -1; |
||||
} |
||||
|
||||
unreserve(gpio, gpio); |
||||
|
||||
set_label(gpio, "free"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#ifdef ADI_SPECIAL_GPIO_BANKS |
||||
static DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES)); |
||||
|
||||
int special_gpio_request(unsigned gpio, const char *label) |
||||
{ |
||||
/*
|
||||
* Allow that the identical GPIO can |
||||
* be requested from the same driver twice |
||||
* Do nothing and return - |
||||
*/ |
||||
|
||||
if (cmp_label(gpio, label) == 0) |
||||
return 0; |
||||
|
||||
if (unlikely(is_reserved(special_gpio, gpio, 1))) { |
||||
printf("adi_gpio2: GPIO %d is already reserved by %s!\n", |
||||
gpio, get_label(gpio)); |
||||
return -EBUSY; |
||||
} |
||||
if (unlikely(is_reserved(peri, gpio, 1))) { |
||||
printf("adi_gpio2: GPIO %d is already reserved as Peripheral " |
||||
"by %s!\n", gpio, get_label(gpio)); |
||||
|
||||
return -EBUSY; |
||||
} |
||||
|
||||
reserve(special_gpio, gpio); |
||||
reserve(peri, gpio); |
||||
|
||||
set_label(gpio, label); |
||||
port_setup(gpio, GPIO_USAGE); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void special_gpio_free(unsigned gpio) |
||||
{ |
||||
if (unlikely(!is_reserved(special_gpio, gpio, 0))) { |
||||
gpio_error(gpio); |
||||
return; |
||||
} |
||||
|
||||
reserve(special_gpio, gpio); |
||||
reserve(peri, gpio); |
||||
set_label(gpio, "free"); |
||||
} |
||||
#endif |
||||
|
||||
static inline void __gpio_direction_input(unsigned gpio) |
||||
{ |
||||
gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio); |
||||
#if defined(CONFIG_BF54x) |
||||
gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio); |
||||
#else |
||||
gpio_array[gpio_bank(gpio)]->inen_set = gpio_bit(gpio); |
||||
#endif |
||||
} |
||||
|
||||
int gpio_direction_input(unsigned gpio) |
||||
{ |
||||
unsigned long flags; |
||||
|
||||
if (!is_reserved(gpio, gpio, 0)) { |
||||
gpio_error(gpio); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
local_irq_save(flags); |
||||
__gpio_direction_input(gpio); |
||||
local_irq_restore(flags); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int gpio_set_value(unsigned gpio, int arg) |
||||
{ |
||||
if (arg) |
||||
gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); |
||||
else |
||||
gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int gpio_direction_output(unsigned gpio, int value) |
||||
{ |
||||
unsigned long flags; |
||||
|
||||
if (!is_reserved(gpio, gpio, 0)) { |
||||
gpio_error(gpio); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
local_irq_save(flags); |
||||
|
||||
#if defined(CONFIG_BF54x) |
||||
gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); |
||||
#else |
||||
gpio_array[gpio_bank(gpio)]->inen_clear = gpio_bit(gpio); |
||||
#endif |
||||
gpio_set_value(gpio, value); |
||||
gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio); |
||||
|
||||
local_irq_restore(flags); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int gpio_get_value(unsigned gpio) |
||||
{ |
||||
return 1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio)); |
||||
} |
||||
|
||||
void gpio_labels(void) |
||||
{ |
||||
int c, gpio; |
||||
|
||||
for (c = 0; c < MAX_RESOURCES; c++) { |
||||
gpio = is_reserved(gpio, c, 1); |
||||
if (!check_gpio(c) && gpio) |
||||
printf("GPIO_%d:\t%s\tGPIO %s\n", c, get_label(c), |
||||
get_gpio_dir(c) ? "OUTPUT" : "INPUT"); |
||||
else if (is_reserved(peri, c, 1)) |
||||
printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c)); |
||||
else |
||||
continue; |
||||
} |
||||
} |
Loading…
Reference in new issue