vr41xx_giu.c

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

C
679
字号
	unsigned long flags;	if (pin >= giu_nr_pins)		return -EINVAL;	if (pin < 16) {		offset = GIUPIODL;		mask = (uint16_t)1 << pin;	} else if (pin < 32) {		offset = GIUPIODH;		mask = (uint16_t)1 << (pin - 16);	} else if (pin < 48) {		offset = GIUPODATL;		mask = (uint16_t)1 << (pin - 32);	} else {		offset = GIUPODATH;		mask = (uint16_t)1 << (pin - 48);	}	spin_lock_irqsave(&giu_lock, flags);	reg = giu_read(offset);	if (data == GPIO_DATA_HIGH)		reg |= mask;	else		reg &= ~mask;	giu_write(offset, reg);	spin_unlock_irqrestore(&giu_lock, flags);	return 0;}EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir){	uint16_t offset, mask, reg;	unsigned long flags;	if (pin >= giu_nr_pins)		return -EINVAL;	if (pin < 16) {		offset = GIUIOSELL;		mask = (uint16_t)1 << pin;	} else if (pin < 32) {		offset = GIUIOSELH;		mask = (uint16_t)1 << (pin - 16);	} else {		if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {			offset = GIUPODATEN;			mask = (uint16_t)1 << (pin - 32);		} else {			switch (pin) {			case 48:				offset = GIUPODATH;				mask = PIOEN0;				break;			case 49:				offset = GIUPODATH;				mask = PIOEN1;				break;			default:				return -EINVAL;			}		}	}	spin_lock_irqsave(&giu_lock, flags);	reg = giu_read(offset);	if (dir == GPIO_OUTPUT)		reg |= mask;	else		reg &= ~mask;	giu_write(offset, reg);	spin_unlock_irqrestore(&giu_lock, flags);	return 0;}EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull){	uint16_t reg, mask;	unsigned long flags;	if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)		return -EPERM;	if (pin >= 15)		return -EINVAL;	mask = (uint16_t)1 << pin;	spin_lock_irqsave(&giu_lock, flags);	if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {		reg = giu_read(GIUTERMUPDN);		if (pull == GPIO_PULL_UP)			reg |= mask;		else			reg &= ~mask;		giu_write(GIUTERMUPDN, reg);		reg = giu_read(GIUUSEUPDN);		reg |= mask;		giu_write(GIUUSEUPDN, reg);	} else {		reg = giu_read(GIUUSEUPDN);		reg &= ~mask;		giu_write(GIUUSEUPDN, reg);	}	spin_unlock_irqrestore(&giu_lock, flags);	return 0;}EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,                         loff_t *ppos){	unsigned int pin;	char value = '0';	pin = iminor(file->f_path.dentry->d_inode);	if (pin >= giu_nr_pins)		return -EBADF;	if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)		value = '1';	if (len <= 0)		return -EFAULT;	if (put_user(value, buf))		return -EFAULT;	return 1;}static ssize_t gpio_write(struct file *file, const char __user *data,                          size_t len, loff_t *ppos){	unsigned int pin;	size_t i;	char c;	int retval = 0;	pin = iminor(file->f_path.dentry->d_inode);	if (pin >= giu_nr_pins)		return -EBADF;	for (i = 0; i < len; i++) {		if (get_user(c, data + i))			return -EFAULT;		switch (c) {		case '0':			retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);			break;		case '1':			retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);			break;		case 'D':			printk(KERN_INFO "GPIO%d: pull down\n", pin);			retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);			break;		case 'd':			printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);			retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);			break;		case 'I':			printk(KERN_INFO "GPIO%d: input\n", pin);			retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);			break;		case 'O':			printk(KERN_INFO "GPIO%d: output\n", pin);			retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);			break;		case 'o':			printk(KERN_INFO "GPIO%d: output disable\n", pin);			retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);			break;		case 'P':			printk(KERN_INFO "GPIO%d: pull up\n", pin);			retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);			break;		case 'p':			printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);			retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);			break;		default:			break;		}		if (retval < 0)			break;	}	return i;}static int gpio_open(struct inode *inode, struct file *file){	unsigned int pin;	pin = iminor(inode);	if (pin >= giu_nr_pins)		return -EBADF;	return nonseekable_open(inode, file);}static int gpio_release(struct inode *inode, struct file *file){	unsigned int pin;	pin = iminor(inode);	if (pin >= giu_nr_pins)		return -EBADF;	return 0;}static const struct file_operations gpio_fops = {	.owner		= THIS_MODULE,	.read		= gpio_read,	.write		= gpio_write,	.open		= gpio_open,	.release	= gpio_release,};static int __devinit giu_probe(struct platform_device *dev){	struct resource *res;	unsigned int trigger, i, pin;	struct irq_chip *chip;	int irq, retval;	switch (dev->id) {	case GPIO_50PINS_PULLUPDOWN:		giu_flags = GPIO_HAS_PULLUPDOWN_IO;		giu_nr_pins = 50;		break;	case GPIO_36PINS:		giu_nr_pins = 36;		break;	case GPIO_48PINS_EDGE_SELECT:		giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;		giu_nr_pins = 48;		break;	default:		printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);		return -ENODEV;	}	res = platform_get_resource(dev, IORESOURCE_MEM, 0);	if (!res)		return -EBUSY;	giu_base = ioremap(res->start, res->end - res->start + 1);	if (!giu_base)		return -ENOMEM;	retval = register_chrdev(major, "GIU", &gpio_fops);	if (retval < 0) {		iounmap(giu_base);		giu_base = NULL;		return retval;	}	if (major == 0) {		major = retval;		printk(KERN_INFO "GIU: major number %d\n", major);	}	spin_lock_init(&giu_lock);	giu_write(GIUINTENL, 0);	giu_write(GIUINTENH, 0);	trigger = giu_read(GIUINTTYPH) << 16;	trigger |= giu_read(GIUINTTYPL);	for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {		pin = GPIO_PIN_OF_IRQ(i);		if (pin < GIUINT_HIGH_OFFSET)			chip = &giuint_low_irq_chip;		else			chip = &giuint_high_irq_chip;		if (trigger & (1 << pin))			set_irq_chip_and_handler(i, chip, handle_edge_irq);		else			set_irq_chip_and_handler(i, chip, handle_level_irq);	}	irq = platform_get_irq(dev, 0);	if (irq < 0 || irq >= NR_IRQS)		return -EBUSY;	return cascade_irq(irq, giu_get_irq);}static int __devexit giu_remove(struct platform_device *dev){	if (giu_base) {		iounmap(giu_base);		giu_base = NULL;	}	return 0;}static struct platform_driver giu_device_driver = {	.probe		= giu_probe,	.remove		= __devexit_p(giu_remove),	.driver		= {		.name	= "GIU",		.owner	= THIS_MODULE,	},};static int __init vr41xx_giu_init(void){	return platform_driver_register(&giu_device_driver);}static void __exit vr41xx_giu_exit(void){	platform_driver_unregister(&giu_device_driver);}module_init(vr41xx_giu_init);module_exit(vr41xx_giu_exit);

⌨️ 快捷键说明

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