forked from PacktPublishing/Linux-Device-Drivers-Development
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gpio-descriptor-module.c
104 lines (90 loc) · 2.95 KB
/
gpio-descriptor-module.c
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
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h> /* For platform devices */
#include <linux/gpio/consumer.h> /* For GPIO Descriptor interface */
#include <linux/interrupt.h> /* For IRQ */
#include <linux/of.h> /* For DT*/
/*
* Let us consider the bellow mapping
*
* foo_device {
* compatible = "packt,gpio-descriptor-sample";
* led-gpios = <&gpio2 15 GPIO_ACTIVE_HIGH>, // red
* <&gpio2 16 GPIO_ACTIVE_HIGH>, // green
*
* btn1-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
* btn2-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
* };
*/
static struct gpio_desc *red, *green, *btn1, *btn2;
static int irq;
static irqreturn_t btn1_pushed_irq_handler(int irq, void *dev_id)
{
int state;
/* read the button value and change the led state */
state = gpiod_get_value(btn2);
gpiod_set_value(red, state);
gpiod_set_value(green, state);
pr_info("btn1 interrupt: Interrupt! btn2 state is %d)\n", state);
return IRQ_HANDLED;
}
static const struct of_device_id gpiod_dt_ids[] = {
{ .compatible = "packt,gpio-descriptor-sample", },
{ /* sentinel */ }
};
static int my_pdrv_probe (struct platform_device *pdev)
{
int retval;
struct device *dev = &pdev->dev;
/*
* We use gpiod_get/gpiod_get_index() along with the flags
* in order to configure the GPIO direction and an initial
* value in a single function call.
*
* One could have used:
* red = gpiod_get_index(dev, "led", 0);
* gpiod_direction_output(red, 0);
*/
red = gpiod_get_index(dev, "led", 0, GPIOD_OUT_LOW);
green = gpiod_get_index(dev, "led", 1, GPIOD_OUT_LOW);
/*
* Configure Button GPIOs as input
*
* After this, one can call gpiod_set_debounce()
* only if the controller has the feature
* For example, to debounce a button with a delay of 200ms
* gpiod_set_debounce(btn1, 200);
*/
btn1 = gpiod_get(dev, "btn1", GPIOD_IN);
btn2 = gpiod_get(dev, "btn2", GPIOD_IN);
irq = gpiod_to_irq(btn1);
retval = request_threaded_irq(irq, NULL,
btn1_pushed_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"gpio-descriptor-sample", NULL);
pr_info("Hello! device probed!\n");
return 0;
}
static int my_pdrv_remove(struct platform_device *pdev)
{
free_irq(irq, NULL);
gpiod_put(red);
gpiod_put(green);
gpiod_put(btn1);
gpiod_put(btn2);
pr_info("good bye reader!\n");
return 0;
}
static struct platform_driver mypdrv = {
.probe = my_pdrv_probe,
.remove = my_pdrv_remove,
.driver = {
.name = "gpio_descriptor_sample",
.of_match_table = of_match_ptr(gpiod_dt_ids),
.owner = THIS_MODULE,
},
};
module_platform_driver(mypdrv);
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_LICENSE("GPL");