⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gpio.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
字号:
/*  * linux/arch/arm/mach-omap2/gpio.c *  * Support functions for OMAP2 GPIO * * Copyright (C) 2003 Nokia Corporation * Written by Juha Yrjölä <juha.yrjola@nokia.com> * * Copyright (C) 2004 Texas Instruments, Inc.  *  * This package is free software; you can redistribute it and/or modify  * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.  *  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.  */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <asm/hardware.h>#include <asm/irq.h>#include <asm/arch/irqs.h>#include <asm/arch/gpio.h>#include <asm/mach/irq.h>#include <asm/io.h>#define GPIO_COUNT	128static const unsigned int gpio_irqs_2420[4] = {	INT_GPIO1_MPU_IRQ, INT_GPIO2_MPU_IRQ, INT_GPIO3_MPU_IRQ,	INT_GPIO4_MPU_IRQ};static const u32 gpio_base_2420[4] = {	OMAP2420_GPIO1_BASE, OMAP2420_GPIO2_BASE, OMAP2420_GPIO3_BASE,	OMAP2420_GPIO4_BASE};static const char *gpio_irq_names_2420[4] = {	"OMAP2 GPIO bank 1 IRQ demux",	"OMAP2 GPIO bank 2 IRQ demux",	"OMAP2 GPIO bank 3 IRQ demux",	"OMAP2 GPIO bank 4 IRQ demux"};static int gpio_bank_count;static int gpio_count;static const unsigned int *gpio_irqs;static const char **gpio_irq_names;static spinlock_t reserved_map_lock = SPIN_LOCK_UNLOCKED;static u32 gpio_reserved_map[4] = { 0, 0, 0, 0 };void omap_set_gpio_direction(int gpio, int is_input){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 l;	reg += OMAP2420_GPIO_DIRECTION;	l = __raw_readl(reg);	if (is_input)		l |= OMAP_GPIO_BIT(gpio);	else		l &= ~OMAP_GPIO_BIT(gpio);	__raw_writel(l, reg);}void omap_set_gpio_dataout(int gpio, int enable){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 l;	if (enable)		reg += OMAP2420_GPIO_SET_DATAOUT;	else		reg += OMAP2420_GPIO_CLEAR_DATAOUT;	l = OMAP_GPIO_BIT(gpio);	__raw_writel(l, reg);}int omap_get_gpio_datain(int gpio){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	reg += OMAP2420_GPIO_DATAIN;	return ((__raw_readl(reg) & OMAP_GPIO_BIT(gpio)) != 0);}void omap_set_gpio_debounce(int gpio, int enable){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 l = OMAP_GPIO_BIT(gpio);	u32 val;	reg += OMAP2420_GPIO_DEBOUNCE_EN;	val = __raw_readl(reg);	if (enable)		val |= l;	else		val &= ~l;	__raw_writel(val, reg);}void omap_set_gpio_debounce_time(int gpio, int enc_time){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	enc_time &= 0xff;	reg += OMAP2420_GPIO_DEBOUNCE_VAL;	__raw_writel(enc_time, reg);}void omap_set_gpio_edge_ctrl(int gpio, int polarity){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 v, p = OMAP_GPIO_BIT(gpio);	v = __raw_readl(reg + OMAP2420_GPIO_FALLING_EDGE) | p;	if (!(polarity & OMAP_GPIO_FALLING_EDGE))		v &= ~p;	__raw_writel(v, reg + OMAP2420_GPIO_FALLING_EDGE);	v = __raw_readl(reg + OMAP2420_GPIO_RISING_EDGE) | p;	if (!(polarity & OMAP_GPIO_RISING_EDGE))		v &= ~p;	__raw_writel(v, reg + OMAP2420_GPIO_RISING_EDGE);	v = __raw_readl(reg + OMAP2420_GPIO_HIGH_LEVEL) | p;	if (!(polarity & OMAP_GPIO_LEVEL_HIGH))		v &= ~p;	__raw_writel(v, reg + OMAP2420_GPIO_HIGH_LEVEL);	v = __raw_readl(reg + OMAP2420_GPIO_LOW_LEVEL) | p;	if (!(polarity & OMAP_GPIO_LEVEL_LOW))		v &= ~p;	__raw_writel(v, reg + OMAP2420_GPIO_LOW_LEVEL);}int omap_get_gpio_edge_ctrl(int gpio){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 v = OMAP_GPIO_NO_EDGE, p = OMAP_GPIO_BIT(gpio);	if (p & __raw_readl(reg + OMAP2420_GPIO_FALLING_EDGE)) ;	v |= OMAP_GPIO_FALLING_EDGE;	if (p & __raw_readl(reg + OMAP2420_GPIO_RISING_EDGE)) ;	v |= OMAP_GPIO_RISING_EDGE;	if (p & __raw_readl(reg + OMAP2420_GPIO_HIGH_LEVEL)) ;	v |= OMAP_GPIO_LEVEL_HIGH;	if (p & __raw_readl(reg + OMAP2420_GPIO_LOW_LEVEL)) ;	v |= OMAP_GPIO_LEVEL_LOW;	return v;}static inline void omap_clear_gpio_irqstatus(int gpio){	u32 reg = OMAP_GPIO_BASE_REG(gpio);;	reg += OMAP2420_GPIO_IRQSTATUS1;	__raw_writel(OMAP_GPIO_BIT(gpio), reg);}static inline void omap_set_gpio_irqenable(int gpio, int enable){	u32 reg = OMAP_GPIO_BASE_REG(gpio);	u32 l;	if (enable) {		reg += OMAP2420_GPIO_SET_IRQENABLE1;		omap_clear_gpio_irqstatus(gpio);	} else		reg += OMAP2420_GPIO_CLEAR_IRQENABLE1;	l = OMAP_GPIO_BIT(gpio);	__raw_writel(l, reg);}static inline u32 *get_map(int gpio){	return gpio_reserved_map + (gpio >> 5);}static inline void reserve_gpio(int gpio){	u32 *map;	map = get_map(gpio);	spin_lock(&reserved_map_lock);	if (unlikely(*map & (1 << OMAP_GPIO_INDEX(gpio)))) {		printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n",		       gpio);		BUG();	}	*map |= (1 << OMAP_GPIO_INDEX(gpio));	spin_unlock(&reserved_map_lock);}static inline void free_gpio(int gpio){	u32 *map;	map = get_map(gpio);	spin_lock(&reserved_map_lock);	if (unlikely(!(*map & (1 << OMAP_GPIO_INDEX(gpio))))) {		printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);		BUG();	}	*map &= ~(1 << OMAP_GPIO_INDEX(gpio));	spin_unlock(&reserved_map_lock);}static int check_gpio(int gpio){	if (gpio < 0 || (gpio >= GPIO_COUNT)) {		printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio);		BUG();		return -1;	}	return 0;}int omap_request_gpio(int gpio){	if (check_gpio(gpio) < 0)		return -EINVAL;	reserve_gpio(gpio);	return 0;}void omap_free_gpio(int gpio){	if (check_gpio(gpio) < 0)		return;	free_gpio(gpio);}/* gpio_irq_handler() :: GPIO IRQ demux.  This chained handler *  is entered from asm_do_IRQ. It needs to: *    -1- handle parent pic (2420 L1, #29) via desc functions. *    -2- identify mux'ed gpio sub function then disaptch to its helper. *    -3- the helper (do_level_IRQ) will use the L2GPIO chip desc's to  *        handle the GPIO pic (maskL2/ackL2/ {then dispatch to L3} umaskL2) *    -4- umask parent L1 pic.          */static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,			     struct pt_regs *regs){	u32 isr_reg;	unsigned int bank = (unsigned int)desc->data;	// find which bank gpio on	desc->chip->ack(irq);	// ack mask parent pic	isr_reg = gpio_base_2420[bank] + OMAP2420_GPIO_IRQSTATUS1;	for (;;) {		// Loop as long as active sources exist.		u32 isr = __raw_readl(isr_reg);		unsigned int gpio_irq;		if (!isr)	// no isr's left, leave			break;		gpio_irq = IH_GPIO_BASE + 32 * bank;	/* get base irq for bank */		for (; isr != 0; isr >>= 1, gpio_irq++) {	/* run though all bits checking */			if (isr & 1) {				struct irqdesc *d = irq_desc + gpio_irq;				d->handle(gpio_irq, d, regs);			}		}	}	desc->chip->unmask(irq);	// unmask parent                                   }static void gpio_mask_ack_irq(unsigned int irq){	unsigned int gpio = (irq - IH_GPIO_BASE) & 0x1f, val = 0;	unsigned int bank = (irq - IH_GPIO_BASE) >> 5;	__raw_writel(1 << gpio,		     gpio_base_2420[bank] + OMAP2420_GPIO_CLEAR_IRQENABLE1);	__asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4"::"r"(val));	/* memory barrier for ordering */	__raw_writel(1 << gpio,		     gpio_base_2420[bank] + OMAP2420_GPIO_IRQSTATUS1);	__asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4"::"r"(val));	/* memory barrier for ordering */}static void gpio_mask_irq(unsigned int irq){	unsigned int val = 0;	omap_set_gpio_irqenable(irq - IH_GPIO_BASE, 0);	__asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4"::"r"(val));	/* memory barrier for ordering */}void gpio_unmask_irq(unsigned int irq){	unsigned int gpio = irq - IH_GPIO_BASE;	if (omap_get_gpio_edge_ctrl(gpio) == OMAP_GPIO_NO_EDGE) {		printk(KERN_ERR		       "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",		       gpio);		omap_set_gpio_edge_ctrl(gpio, OMAP_GPIO_RISING_EDGE);	}	omap_set_gpio_irqenable(gpio, 1);}static struct irqchip gpio_irq_chip = {	.ack = gpio_mask_ack_irq,	.mask = gpio_mask_irq,	.unmask = gpio_unmask_irq,};static int initialized = 0;int __init omap_gpio_init(void){	int i, j, rev;	if (initialized)		return 0;	initialized = 1;	gpio_irqs = gpio_irqs_2420;	// set l1 irq number list.	gpio_count = GPIO_COUNT;	// get number of multiplexed isr's	gpio_irq_names = gpio_irq_names_2420;	// get names for request_irq	gpio_bank_count = 4;	rev = __raw_readl(gpio_base_2420[0] + OMAP2420_GPIO_REVISION);	printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",	       (rev >> 4) & 0x0f, rev & 0x0f);	for (i = IH_GPIO_BASE; i < IH_GPIO_BASE + gpio_count; i++) {		set_irq_chip(i, &gpio_irq_chip);		set_irq_handler(i, do_level_IRQ);		set_irq_flags(i, IRQF_VALID);	}	for (i = 0; i < gpio_bank_count; i++) {		/* TODO: possibly read any values set by bootloader */		/* get values to put back after reset */		/* reset the gpio block */		rev =		    0x2 | __raw_readl(gpio_base_2420[i] +				      OMAP2420_GPIO_SYSCONFIG);		__raw_writel(rev, gpio_base_2420[i] + OMAP2420_GPIO_SYSCONFIG);		for (j = 0; j < 500; j++) {			rev =			    __raw_readl(gpio_base_2420[i] +					OMAP2420_GPIO_SYSCONFIG);			if (!(rev & 0x2))				break;		}		if (j == 500) {			printk(KERN_WARNING			       "OMAP GPIO hardware reset problem\n");			__raw_writel(0x0,				     gpio_base_2420[i] +				     OMAP2420_GPIO_SYSCONFIG);		}		/* Disable interrupts and clear the ISR */		__raw_writel(0x00000000,			     gpio_base_2420[i] +			     OMAP2420_GPIO_CLEAR_IRQENABLE1);		__raw_writel(0xFFFFFFFF,			     gpio_base_2420[i] + OMAP2420_GPIO_IRQSTATUS1);		set_irq_chained_handler(gpio_irqs[i], gpio_irq_handler);		set_irq_data(gpio_irqs[i], (void *)i);	}	/* enable funciton clocks */	/* find me from pcrm */	return 0;}EXPORT_SYMBOL(omap_request_gpio);EXPORT_SYMBOL(omap_free_gpio);EXPORT_SYMBOL(omap_set_gpio_direction);EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);EXPORT_SYMBOL(omap_set_gpio_dataout);EXPORT_SYMBOL(omap_get_gpio_datain);EXPORT_SYMBOL(omap_get_gpio_edge_ctrl);EXPORT_SYMBOL(omap_set_gpio_debounce);EXPORT_SYMBOL(omap_set_gpio_debounce_time);EXPORT_SYMBOL(gpio_unmask_irq);__initcall(omap_gpio_init);

⌨️ 快捷键说明

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