1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
#include <linux/fs.h> #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/poll.h>
struct gpio_node { int gpio; int irq; int irq_mode; };
struct gpio_controller { struct gpio_node *data; int count; };
struct fasync_struct *fasync_queue;
static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { int ret, i; struct gpio_controller *gpio_controller = dev_id; for (i = 0; i < gpio_controller->count; i++) { if (gpio_controller->data[i].irq == irq) { ret = gpio_get_value(gpio_controller->data[i].gpio); break; } } printk("gpio-interrupt: handle, irq=%d value=%d\n", irq, ret); kill_fasync(&fasync_queue, SIGIO, POLL_IN); return IRQ_HANDLED; }
static int gpio_interrupt_probe(struct platform_device *pdev) { int ret ,i; enum of_gpio_flags flag; struct gpio_controller *gpio_controller; struct device_node *device_node = pdev->dev.of_node;
dev_info(&pdev->dev, "start probe gpio-interrupt %s\n", dev_name(&pdev->dev)); gpio_controller = devm_kzalloc(&pdev->dev, sizeof(struct gpio_controller *), GFP_KERNEL); if (!gpio_controller) { dev_err(&pdev->dev, "devm_kzalloc failed!\n"); return -ENOMEM; }
gpio_controller->count = of_gpio_named_count(device_node, "irq-gpios"); if (gpio_controller->count <= 0) { dev_err(&pdev->dev, "gpio-interrupt: irq-gpios count %d is invalid\n", gpio_controller->count); return -ENODEV; } gpio_controller->data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_node) * gpio_controller->count, GFP_KERNEL);
for (i = 0; i < gpio_controller->count; i++) { gpio_controller->data[i].gpio = of_get_named_gpio_flags(device_node, "irq-gpios", i, &flag); if (!gpio_is_valid(gpio_controller->data[i].gpio)) { dev_err(&pdev->dev, "gpio-interrupt: gpio[%d] %d is invalid\n", i, gpio_controller->data[i].gpio); ret = -ENODEV; goto err; }
gpio_controller->data[i].irq = gpio_to_irq(gpio_controller->data[i].gpio); if (!gpio_controller->data[i].irq) { dev_err(&pdev->dev, "gpio-interrupt: gpio[%d] %d irq is invalid\n", i, gpio_controller->data[i].gpio); ret = -ENODEV; goto err; }
gpio_controller->data[i].irq_mode = flag;
if (gpio_request(gpio_controller->data[i].gpio, "gpio-interrupt")) { dev_err(&pdev->dev, "gpio-interrupt: gpio[%d] %d gpio request failed!\n", i, gpio_controller->data[i].gpio); ret = -ENODEV; goto err; }
ret = request_irq(gpio_controller->data[i].irq, gpio_irq_handler, flag, "gpio-interrupt", gpio_controller); if (ret != 0) { dev_err(&pdev->dev, "gpio-interrupt: gpiod[%d] %d irq request failed!\n", i, gpio_controller->data[i].gpio); ret = IRQ_NONE; goto err; }
ret = gpio_export(gpio_controller->data[i].gpio, 0); if (ret != 0) { dev_err(&pdev->dev, "gpio-interrupt: gpiod[%d] %d export failed!\n", i, gpio_controller->data[i].gpio); ret = IRQ_NONE; goto err; } }
dev_info(&pdev->dev, "finish probe gpio-interrupt %s, register %d gpios\n", dev_name(&pdev->dev), gpio_controller->count); return 0; err: for (i = 0; i < gpio_controller->count; i++) { free_irq(gpio_controller->data[i].irq, gpio_controller); gpio_free(gpio_controller->data[i].gpio); } return ret; }
static int gpio_interrupt_fasync(int fd, struct file *file, int on) { return fasync_helper(fd, file, on, &fasync_queue); }
static struct file_operations gpio_interrupt_file_operations = { .owner = THIS_MODULE, .fasync = gpio_interrupt_fasync, };
static struct miscdevice gpio_interrupt_miscdevice = { .minor = MISC_DYNAMIC_MINOR, .fops = &gpio_interrupt_file_operations, .name = "gpio-interrupt", };
static struct of_device_id match_table[] = { { .compatible = "zbqh,gpio-interrupt", }, {}, };
static struct platform_driver gpio_interrupt_driver = { .driver = { .owner = THIS_MODULE, .name = "gpio-interrupt", .of_match_table = match_table, }, .probe = gpio_interrupt_probe, };
static int gpio_interrupt_init(void) { misc_register(&gpio_interrupt_miscdevice); return platform_driver_register(&gpio_interrupt_driver); } module_init(gpio_interrupt_init);
static void gpio_interrupt_exit(void) { misc_deregister(&gpio_interrupt_miscdevice); platform_driver_unregister(&gpio_interrupt_driver); } module_exit(gpio_interrupt_exit);
MODULE_DESCRIPTION("GPIO interrupt driver"); MODULE_AUTHOR("kuretru <[email protected]"); MODULE_ALIAS("platform:gpio-interrupt"); MODULE_LICENSE("GPL v3");
|