bfin_gpio.c

来自「linux 内核源代码」· C语言 代码 · 共 1,197 行 · 第 1/2 页

C
1,197
字号
/* * File:         arch/blackfin/kernel/bfin_gpio.c * Based on: * Author:       Michael Hennerich (hennerich@blackfin.uclinux.org) * * Created: * Description:  GPIO Abstraction Layer * * Modified: *               Copyright 2007 Analog Devices Inc. * * Bugs:         Enter bugs at http://blackfin.uclinux.org/ * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see the file COPYING, or write * to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *//**  Number     BF537/6/4    BF561    BF533/2/1	   BF549/8/4/2**  GPIO_0       PF0         PF0        PF0	   PA0...PJ13*  GPIO_1       PF1         PF1        PF1*  GPIO_2       PF2         PF2        PF2*  GPIO_3       PF3         PF3        PF3*  GPIO_4       PF4         PF4        PF4*  GPIO_5       PF5         PF5        PF5*  GPIO_6       PF6         PF6        PF6*  GPIO_7       PF7         PF7        PF7*  GPIO_8       PF8         PF8        PF8*  GPIO_9       PF9         PF9        PF9*  GPIO_10      PF10        PF10       PF10*  GPIO_11      PF11        PF11       PF11*  GPIO_12      PF12        PF12       PF12*  GPIO_13      PF13        PF13       PF13*  GPIO_14      PF14        PF14       PF14*  GPIO_15      PF15        PF15       PF15*  GPIO_16      PG0         PF16*  GPIO_17      PG1         PF17*  GPIO_18      PG2         PF18*  GPIO_19      PG3         PF19*  GPIO_20      PG4         PF20*  GPIO_21      PG5         PF21*  GPIO_22      PG6         PF22*  GPIO_23      PG7         PF23*  GPIO_24      PG8         PF24*  GPIO_25      PG9         PF25*  GPIO_26      PG10        PF26*  GPIO_27      PG11        PF27*  GPIO_28      PG12        PF28*  GPIO_29      PG13        PF29*  GPIO_30      PG14        PF30*  GPIO_31      PG15        PF31*  GPIO_32      PH0         PF32*  GPIO_33      PH1         PF33*  GPIO_34      PH2         PF34*  GPIO_35      PH3         PF35*  GPIO_36      PH4         PF36*  GPIO_37      PH5         PF37*  GPIO_38      PH6         PF38*  GPIO_39      PH7         PF39*  GPIO_40      PH8         PF40*  GPIO_41      PH9         PF41*  GPIO_42      PH10        PF42*  GPIO_43      PH11        PF43*  GPIO_44      PH12        PF44*  GPIO_45      PH13        PF45*  GPIO_46      PH14        PF46*  GPIO_47      PH15        PF47*/#include <linux/delay.h>#include <linux/module.h>#include <linux/err.h>#include <asm/blackfin.h>#include <asm/gpio.h>#include <asm/portmux.h>#include <linux/irq.h>#if ANOMALY_05000311 || ANOMALY_05000323enum {	AWA_data = SYSCR,	AWA_data_clear = SYSCR,	AWA_data_set = SYSCR,	AWA_toggle = SYSCR,	AWA_maska = UART_SCR,	AWA_maska_clear = UART_SCR,	AWA_maska_set = UART_SCR,	AWA_maska_toggle = UART_SCR,	AWA_maskb = UART_GCTL,	AWA_maskb_clear = UART_GCTL,	AWA_maskb_set = UART_GCTL,	AWA_maskb_toggle = UART_GCTL,	AWA_dir = SPORT1_STAT,	AWA_polar = SPORT1_STAT,	AWA_edge = SPORT1_STAT,	AWA_both = SPORT1_STAT,#if ANOMALY_05000311	AWA_inen = TIMER_ENABLE,#elif ANOMALY_05000323	AWA_inen = DMA1_1_CONFIG,#endif};	/* Anomaly Workaround */#define AWA_DUMMY_READ(name) bfin_read16(AWA_ ## name)#else#define AWA_DUMMY_READ(...)  do { } while (0)#endif#ifdef BF533_FAMILYstatic struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(struct gpio_port_t *) FIO_FLAG_D,};#endif#if defined(BF527_FAMILY) || defined(BF537_FAMILY)static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(struct gpio_port_t *) PORTFIO,	(struct gpio_port_t *) PORTGIO,	(struct gpio_port_t *) PORTHIO,};static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(unsigned short *) PORTF_FER,	(unsigned short *) PORTG_FER,	(unsigned short *) PORTH_FER,};#endif#ifdef BF527_FAMILYstatic unsigned short *port_mux[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(unsigned short *) PORTF_MUX,	(unsigned short *) PORTG_MUX,	(unsigned short *) PORTH_MUX,};static constu8 pmux_offset[][16] =	{{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 8, 8, 10, 10 }, /* PORTF */	 { 0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 8, 10, 10, 10, 12, 12 }, /* PORTG */	 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }, /* PORTH */	};#endif#ifdef BF561_FAMILYstatic struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(struct gpio_port_t *) FIO0_FLAG_D,	(struct gpio_port_t *) FIO1_FLAG_D,	(struct gpio_port_t *) FIO2_FLAG_D,};#endif#ifdef BF548_FAMILYstatic struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = {	(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,	(struct gpio_port_t *)PORTH_FER,	(struct gpio_port_t *)PORTI_FER,	(struct gpio_port_t *)PORTJ_FER,};#endifstatic unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)];#define MAX_RESOURCES 		256#define RESOURCE_LABEL_SIZE 	16struct str_ident {	char name[RESOURCE_LABEL_SIZE];} *str_ident;#ifdef CONFIG_PMstatic unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];#ifdef BF533_FAMILYstatic unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};#endif#ifdef BF537_FAMILYstatic unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};#endif#ifdef BF527_FAMILYstatic unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PORTF_INTB, IRQ_PORTG_INTB, IRQ_PORTH_INTB};#endif#ifdef BF561_FAMILYstatic unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};#endif#endif /* CONFIG_PM */#if defined(BF548_FAMILY)inline int check_gpio(unsigned short gpio){	if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15	    || gpio == GPIO_PH14 || gpio == GPIO_PH15	    || gpio == GPIO_PJ14 || gpio == GPIO_PJ15	    || gpio > MAX_BLACKFIN_GPIOS)		return -EINVAL;	return 0;}#elseinline int check_gpio(unsigned short gpio){	if (gpio >= MAX_BLACKFIN_GPIOS)		return -EINVAL;	return 0;}#endifstatic void set_label(unsigned short ident, const char *label){	if (label && str_ident) {		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){	if (!str_ident)		return "UNKNOWN";	return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN");}static int cmp_label(unsigned short ident, const char *label){	if (label && str_ident)		return strncmp(str_ident[ident].name,				 label, strlen(label));	else		return -EINVAL;}#if defined(BF527_FAMILY) || defined(BF537_FAMILY)static void port_setup(unsigned short gpio, unsigned short usage){	if (!check_gpio(gpio)) {		if (usage == GPIO_USAGE)			*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);		else			*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);		SSYNC();	}}#elif defined(BF548_FAMILY)static void port_setup(unsigned short gpio, unsigned short usage){	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);	SSYNC();}#else# define port_setup(...)  do { } while (0)#endif#ifdef BF537_FAMILYstatic struct {	unsigned short res;	unsigned short offset;} port_mux_lut[] = {	{.res = P_PPI0_D13, .offset = 11},	{.res = P_PPI0_D14, .offset = 11},	{.res = P_PPI0_D15, .offset = 11},	{.res = P_SPORT1_TFS, .offset = 11},	{.res = P_SPORT1_TSCLK, .offset = 11},	{.res = P_SPORT1_DTPRI, .offset = 11},	{.res = P_PPI0_D10, .offset = 10},	{.res = P_PPI0_D11, .offset = 10},	{.res = P_PPI0_D12, .offset = 10},	{.res = P_SPORT1_RSCLK, .offset = 10},	{.res = P_SPORT1_RFS, .offset = 10},	{.res = P_SPORT1_DRPRI, .offset = 10},	{.res = P_PPI0_D8, .offset = 9},	{.res = P_PPI0_D9, .offset = 9},	{.res = P_SPORT1_DRSEC, .offset = 9},	{.res = P_SPORT1_DTSEC, .offset = 9},	{.res = P_TMR2, .offset = 8},	{.res = P_PPI0_FS3, .offset = 8},	{.res = P_TMR3, .offset = 7},	{.res = P_SPI0_SSEL4, .offset = 7},	{.res = P_TMR4, .offset = 6},	{.res = P_SPI0_SSEL5, .offset = 6},	{.res = P_TMR5, .offset = 5},	{.res = P_SPI0_SSEL6, .offset = 5},	{.res = P_UART1_RX, .offset = 4},	{.res = P_UART1_TX, .offset = 4},	{.res = P_TMR6, .offset = 4},	{.res = P_TMR7, .offset = 4},	{.res = P_UART0_RX, .offset = 3},	{.res = P_UART0_TX, .offset = 3},	{.res = P_DMAR0, .offset = 3},	{.res = P_DMAR1, .offset = 3},	{.res = P_SPORT0_DTSEC, .offset = 1},	{.res = P_SPORT0_DRSEC, .offset = 1},	{.res = P_CAN0_RX, .offset = 1},	{.res = P_CAN0_TX, .offset = 1},	{.res = P_SPI0_SSEL7, .offset = 1},	{.res = P_SPORT0_TFS, .offset = 0},	{.res = P_SPORT0_DTPRI, .offset = 0},	{.res = P_SPI0_SSEL2, .offset = 0},	{.res = P_SPI0_SSEL3, .offset = 0},};static void portmux_setup(unsigned short per, unsigned short function){	u16 y, offset, muxreg;	for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) {		if (port_mux_lut[y].res == per) {			/* SET PORTMUX REG */			offset = port_mux_lut[y].offset;			muxreg = bfin_read_PORT_MUX();			if (offset != 1) {				muxreg &= ~(1 << offset);			} else {				muxreg &= ~(3 << 1);			}			muxreg |= (function << offset);			bfin_write_PORT_MUX(muxreg);		}	}}#elif defined(BF548_FAMILY)inline void portmux_setup(unsigned short portno, unsigned short function){	u32 pmux;	pmux = gpio_array[gpio_bank(portno)]->port_mux;	pmux &= ~(0x3 << (2 * gpio_sub_n(portno)));	pmux |= (function & 0x3) << (2 * gpio_sub_n(portno));	gpio_array[gpio_bank(portno)]->port_mux = pmux;}inline u16 get_portmux(unsigned short portno){	u32 pmux;	pmux = gpio_array[gpio_bank(portno)]->port_mux;	return (pmux >> (2 * gpio_sub_n(portno)) & 0x3);}#elif defined(BF527_FAMILY)inline void portmux_setup(unsigned short portno, unsigned short function){	u16 pmux, ident = P_IDENT(portno);	u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];	pmux = *port_mux[gpio_bank(ident)];	pmux &= ~(3 << offset);	pmux |= (function & 3) << offset;	*port_mux[gpio_bank(ident)] = pmux;	SSYNC();}#else# define portmux_setup(...)  do { } while (0)#endif#ifndef BF548_FAMILYstatic void default_gpio(unsigned short gpio){	unsigned short bank, bitmask;	unsigned long flags;	bank = gpio_bank(gpio);	bitmask = gpio_bit(gpio);	local_irq_save(flags);	gpio_bankb[bank]->maska_clear = bitmask;	gpio_bankb[bank]->maskb_clear = bitmask;	SSYNC();	gpio_bankb[bank]->inen &= ~bitmask;	gpio_bankb[bank]->dir &= ~bitmask;	gpio_bankb[bank]->polar &= ~bitmask;	gpio_bankb[bank]->both &= ~bitmask;	gpio_bankb[bank]->edge &= ~bitmask;	AWA_DUMMY_READ(edge);	local_irq_restore(flags);}#else# define default_gpio(...)  do { } while (0)#endifstatic int __init bfin_gpio_init(void){	str_ident = kcalloc(MAX_RESOURCES,				 sizeof(struct str_ident), GFP_KERNEL);	if (str_ident == NULL)		return -ENOMEM;	memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident));	printk(KERN_INFO "Blackfin GPIO Controller\n");	return 0;}arch_initcall(bfin_gpio_init);#ifndef BF548_FAMILY/************************************************************* FUNCTIONS: Blackfin General Purpose Ports Access Functions** INPUTS/OUTPUTS:* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS*** DESCRIPTION: These functions abstract direct register access*              to Blackfin processor General Purpose*              Ports Regsiters** CAUTION: These functions do not belong to the GPIO Driver API************************************************************** MODIFICATION HISTORY :**************************************************************//* Set a specific bit */#define SET_GPIO(name) \void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \{ \	unsigned long flags; \	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \	local_irq_save(flags); \	if (arg) \		gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \	else \		gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \	AWA_DUMMY_READ(name); \	local_irq_restore(flags); \} \EXPORT_SYMBOL(set_gpio_ ## name);SET_GPIO(dir)SET_GPIO(inen)SET_GPIO(polar)SET_GPIO(edge)SET_GPIO(both)#if ANOMALY_05000311 || ANOMALY_05000323#define SET_GPIO_SC(name) \void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \{ \	unsigned long flags; \	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \	local_irq_save(flags); \	if (arg) \		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \	else \		gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \	AWA_DUMMY_READ(name); \	local_irq_restore(flags); \} \EXPORT_SYMBOL(set_gpio_ ## name);#else#define SET_GPIO_SC(name) \void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \{ \	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \	if (arg) \		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \	else \		gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \} \EXPORT_SYMBOL(set_gpio_ ## name);#endifSET_GPIO_SC(maska)SET_GPIO_SC(maskb)SET_GPIO_SC(data)#if ANOMALY_05000311 || ANOMALY_05000323void set_gpio_toggle(unsigned short gpio){	unsigned long flags;	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));	local_irq_save(flags);	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);	AWA_DUMMY_READ(toggle);	local_irq_restore(flags);}#elsevoid set_gpio_toggle(unsigned short gpio){	BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);}#endifEXPORT_SYMBOL(set_gpio_toggle);/*Set current PORT date (16-bit word)*/#if ANOMALY_05000311 || ANOMALY_05000323#define SET_GPIO_P(name) \void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \{ \	unsigned long flags; \	local_irq_save(flags); \	gpio_bankb[gpio_bank(gpio)]->name = arg; \	AWA_DUMMY_READ(name); \	local_irq_restore(flags); \} \EXPORT_SYMBOL(set_gpiop_ ## name);#else#define SET_GPIO_P(name) \void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \{ \	gpio_bankb[gpio_bank(gpio)]->name = arg; \} \EXPORT_SYMBOL(set_gpiop_ ## name);#endifSET_GPIO_P(data)SET_GPIO_P(dir)SET_GPIO_P(inen)SET_GPIO_P(polar)SET_GPIO_P(edge)SET_GPIO_P(both)SET_GPIO_P(maska)SET_GPIO_P(maskb)/* Get a specific bit */#if ANOMALY_05000311 || ANOMALY_05000323#define GET_GPIO(name) \unsigned short get_gpio_ ## name(unsigned short gpio) \{ \	unsigned long flags; \	unsigned short ret; \	local_irq_save(flags); \	ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \	AWA_DUMMY_READ(name); \	local_irq_restore(flags); \	return ret; \} \EXPORT_SYMBOL(get_gpio_ ## name);#else#define GET_GPIO(name) \unsigned short get_gpio_ ## name(unsigned short gpio) \{ \	return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \} \EXPORT_SYMBOL(get_gpio_ ## name);#endifGET_GPIO(data)GET_GPIO(dir)GET_GPIO(inen)GET_GPIO(polar)GET_GPIO(edge)GET_GPIO(both)GET_GPIO(maska)GET_GPIO(maskb)/*Get current PORT date (16-bit word)*/#if ANOMALY_05000311 || ANOMALY_05000323#define GET_GPIO_P(name) \unsigned short get_gpiop_ ## name(unsigned short gpio) \{ \

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?