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
|
diff -Naru linux-4.9.orig/drivers/gpio/gpiolib.c linux-4.9/drivers/gpio/gpiolib.c
--- linux-4.9.orig/drivers/gpio/gpiolib.c 2018-12-11 10:11:06.000000000 -0600
+++ linux-4.9/drivers/gpio/gpiolib.c 2018-12-12 10:20:01.690638477 -0600
@@ -478,6 +478,8 @@
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_PULLUP)
+ set_bit(FLAG_PULLUP, &desc->flags);
/*
* Lines have to be requested explicitly for input
@@ -804,6 +806,8 @@
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_PULLUP)
+ set_bit(FLAG_PULLUP, &desc->flags);
ret = gpiod_direction_input(desc);
if (ret)
@@ -953,6 +957,8 @@
lineinfo.flags |= GPIOLINE_FLAG_OPEN_DRAIN;
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_OPEN_SOURCE;
+ if (test_bit(FLAG_PULLUP, &desc->flags))
+ lineinfo.flags |= GPIOLINE_FLAG_PULLUP;
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
@@ -2090,6 +2096,7 @@
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ clear_bit(FLAG_PULLUP, &desc->flags);
clear_bit(FLAG_IS_HOGGED, &desc->flags);
ret = true;
}
@@ -2256,6 +2263,17 @@
if (!ret)
goto set_output_value;
}
+ /* Emulate open source by not actively driving the line low */
+ if (!value)
+ return gpiod_direction_input(desc);
+ }
+ else if (test_bit(FLAG_PULLUP, &desc->flags)) {
+ if (gc->set_single_ended) {
+ ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
+ LINE_MODE_PULLUP);
+ if (!ret)
+ goto set_output_value;
+ }
/* Emulate open source by not actively driving the line low */
if (!value)
return gpiod_direction_input(desc);
diff -Naru linux-4.9.orig/drivers/gpio/gpiolib.h linux-4.9/drivers/gpio/gpiolib.h
--- linux-4.9.orig/drivers/gpio/gpiolib.h 2018-12-11 12:10:06.937000782 -0600
+++ linux-4.9/drivers/gpio/gpiolib.h 2018-12-11 12:11:30.324998313 -0600
@@ -189,6 +189,7 @@
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
+#define FLAG_PULLUP 12 /* GPIO is pulled up */
/* Connection label */
const char *label;
diff -Naru linux-4.9.orig/drivers/pinctrl/pinctrl-at91.c linux-4.9/drivers/pinctrl/pinctrl-at91.c
--- linux-4.9.orig/drivers/pinctrl/pinctrl-at91.c 2018-12-11 10:11:15.000000000 -0600
+++ linux-4.9/drivers/pinctrl/pinctrl-at91.c 2018-12-12 10:25:46.154628279 -0600
@@ -1671,6 +1671,33 @@
return -EINVAL;
}
+static int at91_gpio_set_single_ended(struct gpio_chip *chip, unsigned offset, enum single_ended_mode mode)
+{
+ struct at91_gpio_chip *at91_gpio = gpiochip_get_data(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ /* Other possibilities:
+ * PIO_IFSCDR, PIO_IFSCER (Input Filter Slow Clock disable/enable register)
+ * PIO_SCDR (Slow Clock Divider Debouncing register)
+ */
+ switch(mode) {
+ case LINE_MODE_PULLUP:
+ at91_mux_set_pullup(pio, mask, true);
+ return 0;
+ case LINE_MODE_OPEN_DRAIN:
+ /* Open Drain is Multi Drive */
+ at91_mux_set_multidrive(pio, mask, true);
+ return 0;
+ case LINE_MODE_PUSH_PULL:
+ /* Not pull up or open drain */
+ at91_mux_set_pullup(pio, mask, false);
+ at91_mux_set_multidrive(pio, mask, false);
+ return 0;
+ default: return -EINVAL;
+ }
+}
+
/* This structure is replicated for each GPIO block allocated at probe time */
static const struct gpio_chip at91_gpio_template = {
.request = gpiochip_generic_request,
@@ -1681,6 +1708,7 @@
.direction_output = at91_gpio_direction_output,
.set = at91_gpio_set,
.set_multiple = at91_gpio_set_multiple,
+ .set_single_ended = at91_gpio_set_single_ended,
.dbg_show = at91_gpio_dbg_show,
.can_sleep = false,
.ngpio = MAX_NB_GPIO_PER_BANK,
diff -Naru linux-4.9.orig/include/linux/gpio/driver.h linux-4.9/include/linux/gpio/driver.h
--- linux-4.9.orig/include/linux/gpio/driver.h 2018-12-11 10:11:20.000000000 -0600
+++ linux-4.9/include/linux/gpio/driver.h 2018-12-11 17:47:56.188400715 -0600
@@ -23,11 +23,13 @@
* @LINE_MODE_PUSH_PULL: normal mode for a GPIO line, drive actively high/low
* @LINE_MODE_OPEN_DRAIN: set line to be open drain
* @LINE_MODE_OPEN_SOURCE: set line to be open source
+ * @LINE_MODE_PULLUP: set line to be pullup
*/
enum single_ended_mode {
LINE_MODE_PUSH_PULL,
LINE_MODE_OPEN_DRAIN,
LINE_MODE_OPEN_SOURCE,
+ LINE_MODE_PULLUP,
};
/**
diff -Naru linux-4.9.orig/include/uapi/linux/gpio.h linux-4.9/include/uapi/linux/gpio.h
--- linux-4.9.orig/include/uapi/linux/gpio.h 2018-12-11 10:11:21.000000000 -0600
+++ linux-4.9/include/uapi/linux/gpio.h 2018-12-11 12:21:03.884981333 -0600
@@ -32,6 +32,7 @@
#define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2)
#define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3)
#define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4)
+#define GPIOLINE_FLAG_PULLUP (1UL << 5)
/**
* struct gpioline_info - Information about a certain GPIO line
@@ -61,6 +62,7 @@
#define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2)
#define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
#define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
+#define GPIOHANDLE_REQUEST_PULLUP (1UL << 5)
/**
* struct gpiohandle_request - Information about a GPIO handle request
|