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

📄 gpio.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);	else		gpio = irq - IH_GPIO_BASE;	if (check_gpio(gpio) < 0)		return -EINVAL;	if (type & ~IRQ_TYPE_SENSE_MASK)		return -EINVAL;	/* OMAP1 allows only only edge triggering */	if (!cpu_is_omap24xx()			&& (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))		return -EINVAL;	bank = get_irq_chip_data(irq);	spin_lock(&bank->lock);	retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);	if (retval == 0) {		irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;		irq_desc[irq].status |= type;	}	spin_unlock(&bank->lock);	return retval;}static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask){	void __iomem *reg = bank->base;	switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1	case METHOD_MPUIO:		/* MPUIO irqstatus is reset by reading the status register,		 * so do nothing here */		return;#endif#ifdef CONFIG_ARCH_OMAP15XX	case METHOD_GPIO_1510:		reg += OMAP1510_GPIO_INT_STATUS;		break;#endif#ifdef CONFIG_ARCH_OMAP16XX	case METHOD_GPIO_1610:		reg += OMAP1610_GPIO_IRQSTATUS1;		break;#endif#ifdef CONFIG_ARCH_OMAP730	case METHOD_GPIO_730:		reg += OMAP730_GPIO_INT_STATUS;		break;#endif#ifdef CONFIG_ARCH_OMAP24XX	case METHOD_GPIO_24XX:		reg += OMAP24XX_GPIO_IRQSTATUS1;		break;#endif	default:		WARN_ON(1);		return;	}	__raw_writel(gpio_mask, reg);	/* Workaround for clearing DSP GPIO interrupts to allow retention */	if (cpu_is_omap2420())		__raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2);}static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio){	_clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio));}static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank){	void __iomem *reg = bank->base;	int inv = 0;	u32 l;	u32 mask;	switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1	case METHOD_MPUIO:		reg += OMAP_MPUIO_GPIO_MASKIT;		mask = 0xffff;		inv = 1;		break;#endif#ifdef CONFIG_ARCH_OMAP15XX	case METHOD_GPIO_1510:		reg += OMAP1510_GPIO_INT_MASK;		mask = 0xffff;		inv = 1;		break;#endif#ifdef CONFIG_ARCH_OMAP16XX	case METHOD_GPIO_1610:		reg += OMAP1610_GPIO_IRQENABLE1;		mask = 0xffff;		break;#endif#ifdef CONFIG_ARCH_OMAP730	case METHOD_GPIO_730:		reg += OMAP730_GPIO_INT_MASK;		mask = 0xffffffff;		inv = 1;		break;#endif#ifdef CONFIG_ARCH_OMAP24XX	case METHOD_GPIO_24XX:		reg += OMAP24XX_GPIO_IRQENABLE1;		mask = 0xffffffff;		break;#endif	default:		WARN_ON(1);		return 0;	}	l = __raw_readl(reg);	if (inv)		l = ~l;	l &= mask;	return l;}static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable){	void __iomem *reg = bank->base;	u32 l;	switch (bank->method) {#ifdef CONFIG_ARCH_OMAP1	case METHOD_MPUIO:		reg += OMAP_MPUIO_GPIO_MASKIT;		l = __raw_readl(reg);		if (enable)			l &= ~(gpio_mask);		else			l |= gpio_mask;		break;#endif#ifdef CONFIG_ARCH_OMAP15XX	case METHOD_GPIO_1510:		reg += OMAP1510_GPIO_INT_MASK;		l = __raw_readl(reg);		if (enable)			l &= ~(gpio_mask);		else			l |= gpio_mask;		break;#endif#ifdef CONFIG_ARCH_OMAP16XX	case METHOD_GPIO_1610:		if (enable)			reg += OMAP1610_GPIO_SET_IRQENABLE1;		else			reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;		l = gpio_mask;		break;#endif#ifdef CONFIG_ARCH_OMAP730	case METHOD_GPIO_730:		reg += OMAP730_GPIO_INT_MASK;		l = __raw_readl(reg);		if (enable)			l &= ~(gpio_mask);		else			l |= gpio_mask;		break;#endif#ifdef CONFIG_ARCH_OMAP24XX	case METHOD_GPIO_24XX:		if (enable)			reg += OMAP24XX_GPIO_SETIRQENABLE1;		else			reg += OMAP24XX_GPIO_CLEARIRQENABLE1;		l = gpio_mask;		break;#endif	default:		WARN_ON(1);		return;	}	__raw_writel(l, reg);}static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable){	_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);}/* * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register. * 1510 does not seem to have a wake-up register. If JTAG is connected * to the target, system will wake up always on GPIO events. While * system is running all registered GPIO interrupts need to have wake-up * enabled. When system is suspended, only selected GPIO interrupts need * to have wake-up enabled. */static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable){	switch (bank->method) {#ifdef CONFIG_ARCH_OMAP16XX	case METHOD_MPUIO:	case METHOD_GPIO_1610:		spin_lock(&bank->lock);		if (enable) {			bank->suspend_wakeup |= (1 << gpio);			enable_irq_wake(bank->irq);		} else {			disable_irq_wake(bank->irq);			bank->suspend_wakeup &= ~(1 << gpio);		}		spin_unlock(&bank->lock);		return 0;#endif#ifdef CONFIG_ARCH_OMAP24XX	case METHOD_GPIO_24XX:		if (bank->non_wakeup_gpios & (1 << gpio)) {			printk(KERN_ERR "Unable to modify wakeup on "					"non-wakeup GPIO%d\n",					(bank - gpio_bank) * 32 + gpio);			return -EINVAL;		}		spin_lock(&bank->lock);		if (enable) {			bank->suspend_wakeup |= (1 << gpio);			enable_irq_wake(bank->irq);		} else {			disable_irq_wake(bank->irq);			bank->suspend_wakeup &= ~(1 << gpio);		}		spin_unlock(&bank->lock);		return 0;#endif	default:		printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",		       bank->method);		return -EINVAL;	}}static void _reset_gpio(struct gpio_bank *bank, int gpio){	_set_gpio_direction(bank, get_gpio_index(gpio), 1);	_set_gpio_irqenable(bank, gpio, 0);	_clear_gpio_irqstatus(bank, gpio);	_set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);}/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */static int gpio_wake_enable(unsigned int irq, unsigned int enable){	unsigned int gpio = irq - IH_GPIO_BASE;	struct gpio_bank *bank;	int retval;	if (check_gpio(gpio) < 0)		return -ENODEV;	bank = get_irq_chip_data(irq);	retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);	return retval;}int omap_request_gpio(int gpio){	struct gpio_bank *bank;	if (check_gpio(gpio) < 0)		return -EINVAL;	bank = get_gpio_bank(gpio);	spin_lock(&bank->lock);	if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) {		printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio);		dump_stack();		spin_unlock(&bank->lock);		return -1;	}	bank->reserved_map |= (1 << get_gpio_index(gpio));	/* Set trigger to none. You need to enable the desired trigger with	 * request_irq() or set_irq_type().	 */	_set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);#ifdef CONFIG_ARCH_OMAP15XX	if (bank->method == METHOD_GPIO_1510) {		void __iomem *reg;		/* Claim the pin for MPU */		reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;		__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);	}#endif	spin_unlock(&bank->lock);	return 0;}void omap_free_gpio(int gpio){	struct gpio_bank *bank;	if (check_gpio(gpio) < 0)		return;	bank = get_gpio_bank(gpio);	spin_lock(&bank->lock);	if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) {		printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);		dump_stack();		spin_unlock(&bank->lock);		return;	}#ifdef CONFIG_ARCH_OMAP16XX	if (bank->method == METHOD_GPIO_1610) {		/* Disable wake-up during idle for dynamic tick */		void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;		__raw_writel(1 << get_gpio_index(gpio), reg);	}#endif#ifdef CONFIG_ARCH_OMAP24XX	if (bank->method == METHOD_GPIO_24XX) {		/* Disable wake-up during idle for dynamic tick */		void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;		__raw_writel(1 << get_gpio_index(gpio), reg);	}#endif	bank->reserved_map &= ~(1 << get_gpio_index(gpio));	_reset_gpio(bank, gpio);	spin_unlock(&bank->lock);}/* * We need to unmask the GPIO bank interrupt as soon as possible to * avoid missing GPIO interrupts for other lines in the bank. * Then we need to mask-read-clear-unmask the triggered GPIO lines * in the bank to avoid missing nested interrupts for a GPIO line. * If we wait to unmask individual GPIO lines in the bank after the * line's interrupt handler has been run, we may miss some nested * interrupts. */static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc){	void __iomem *isr_reg = NULL;	u32 isr;	unsigned int gpio_irq;	struct gpio_bank *bank;	u32 retrigger = 0;	int unmasked = 0;	desc->chip->ack(irq);	bank = get_irq_data(irq);#ifdef CONFIG_ARCH_OMAP1	if (bank->method == METHOD_MPUIO)		isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;#endif#ifdef CONFIG_ARCH_OMAP15XX	if (bank->method == METHOD_GPIO_1510)		isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;#endif#if defined(CONFIG_ARCH_OMAP16XX)	if (bank->method == METHOD_GPIO_1610)		isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;#endif#ifdef CONFIG_ARCH_OMAP730	if (bank->method == METHOD_GPIO_730)		isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;#endif#ifdef CONFIG_ARCH_OMAP24XX	if (bank->method == METHOD_GPIO_24XX)		isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1;#endif	while(1) {		u32 isr_saved, level_mask = 0;		u32 enabled;		enabled = _get_gpio_irqbank_mask(bank);		isr_saved = isr = __raw_readl(isr_reg) & enabled;		if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))			isr &= 0x0000ffff;		if (cpu_is_omap24xx()) {			level_mask =				__raw_readl(bank->base +					OMAP24XX_GPIO_LEVELDETECT0) |				__raw_readl(bank->base +					OMAP24XX_GPIO_LEVELDETECT1);			level_mask &= enabled;		}		/* clear edge sensitive interrupts before handler(s) are		called so that we don't miss any interrupt occurred while		executing them */		_enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0);		_clear_gpio_irqbank(bank, isr_saved & ~level_mask);		_enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1);		/* if there is only edge sensitive GPIO pin interrupts		configured, we could unmask GPIO bank interrupt immediately */		if (!level_mask && !unmasked) {			unmasked = 1;			desc->chip->unmask(irq);		}		isr |= retrigger;		retrigger = 0;		if (!isr)			break;		gpio_irq = bank->virtual_irq_start;		for (; isr != 0; isr >>= 1, gpio_irq++) {			struct irq_desc *d;			int irq_mask;			if (!(isr & 1))				continue;			d = irq_desc + gpio_irq;			/* Don't run the handler if it's already running			 * or was disabled lazely.			 */			if (unlikely((d->depth ||				      (d->status & IRQ_INPROGRESS)))) {				irq_mask = 1 <<					(gpio_irq - bank->virtual_irq_start);				/* The unmasking will be done by				 * enable_irq in case it is disabled or				 * after returning from the handler if				 * it's already running.				 */				_enable_gpio_irqbank(bank, irq_mask, 0);				if (!d->depth) {					/* Level triggered interrupts					 * won't ever be reentered					 */					BUG_ON(level_mask & irq_mask);					d->status |= IRQ_PENDING;				}				continue;			}			desc_handle_irq(gpio_irq, d);			if (unlikely((d->status & IRQ_PENDING) && !d->depth)) {				irq_mask = 1 <<					(gpio_irq - bank->virtual_irq_start);				d->status &= ~IRQ_PENDING;				_enable_gpio_irqbank(bank, irq_mask, 1);				retrigger |= irq_mask;			}		}		if (cpu_is_omap24xx()) {			/* clear level sensitive interrupts after handler(s) */			_enable_gpio_irqbank(bank, isr_saved & level_mask, 0);			_clear_gpio_irqbank(bank, isr_saved & level_mask);			_enable_gpio_irqbank(bank, isr_saved & level_mask, 1);		}	}	/* if bank has any level sensitive GPIO pin interrupt	configured, we must unmask the bank interrupt only after	handler(s) are executed in order to avoid spurious bank	interrupt */	if (!unmasked)		desc->chip->unmask(irq);}static void gpio_irq_shutdown(unsigned int irq){	unsigned int gpio = irq - IH_GPIO_BASE;	struct gpio_bank *bank = get_irq_chip_data(irq);	_reset_gpio(bank, gpio);}static void gpio_ack_irq(unsigned int irq){	unsigned int gpio = irq - IH_GPIO_BASE;	struct gpio_bank *bank = get_irq_chip_data(irq);	_clear_gpio_irqstatus(bank, gpio);}static void gpio_mask_irq(unsigned int irq){	unsigned int gpio = irq - IH_GPIO_BASE;	struct gpio_bank *bank = get_irq_chip_data(irq);	_set_gpio_irqenable(bank, gpio, 0);}static void gpio_unmask_irq(unsigned int irq){	unsigned int gpio = irq - IH_GPIO_BASE;	unsigned int gpio_idx = get_gpio_index(gpio);	struct gpio_bank *bank = get_irq_chip_data(irq);	_set_gpio_irqenable(bank, gpio_idx, 1);}static struct irq_chip gpio_irq_chip = {	.name		= "GPIO",	.shutdown	= gpio_irq_shutdown,	.ack		= gpio_ack_irq,	.mask		= gpio_mask_irq,	.unmask		= gpio_unmask_irq,	.set_type	= gpio_irq_type,	.set_wake	= gpio_wake_enable,};/*---------------------------------------------------------------------*/#ifdef CONFIG_ARCH_OMAP1/* MPUIO uses the always-on 32k clock */static void mpuio_ack_irq(unsigned int irq){	/* The ISR is reset automatically, so do nothing here. */}static void mpuio_mask_irq(unsigned int irq){	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);	struct gpio_bank *bank = get_irq_chip_data(irq);	_set_gpio_irqenable(bank, gpio, 0);}static void mpuio_unmask_irq(unsigned int irq){	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);	struct gpio_bank *bank = get_irq_chip_data(irq);	_set_gpio_irqenable(bank, gpio, 1);}static struct irq_chip mpuio_irq_chip = {	.name		= "MPUIO",	.ack		= mpuio_ack_irq,	.mask		= mpuio_mask_irq,	.unmask		= mpuio_unmask_irq,	.set_type	= gpio_irq_type,#ifdef CONFIG_ARCH_OMAP16XX	/* REVISIT: assuming only 16xx supports MPUIO wake events */	.set_wake	= gpio_wake_enable,#endif};#define bank_is_mpuio(bank)	((bank)->method == METHOD_MPUIO)#ifdef CONFIG_ARCH_OMAP16XX#include <linux/platform_device.h>static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg){	struct gpio_bank	*bank = platform_get_drvdata(pdev);	void __iomem		*mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;	spin_lock(&bank->lock);	bank->saved_wakeup = __raw_readl(mask_reg);	__raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);

⌨️ 快捷键说明

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