aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch
blob: ec541dca5e7089c05a865a91d411503d7f20ae62 (plain)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
From xxxx Mon Sep 17 00:00:00 2001
From: Josef Ahmad <josef.ahmad@linux.intel.com>
Date: Tue, 11 Feb 2014 16:28:26 +0000
Subject: [PATCH 15/21] Quark GPIO 1/2

---
 drivers/gpio/Kconfig       |    7 ++-
 drivers/gpio/gpiolib.c     |  130 ++++++++++++++++++++++++++++++++++++++++++++
 include/asm-generic/gpio.h |    4 ++
 include/linux/gpio.h       |   10 ++++
 4 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de75..afab416 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -243,13 +243,14 @@ config GPIO_VR41XX
 	  Say yes here to support the NEC VR4100 series General-purpose I/O Uint
 
 config GPIO_SCH
-	tristate "Intel SCH/TunnelCreek/Centerton GPIO"
+	tristate "Intel SCH/TunnelCreek/Centerton/Quark GPIO"
 	depends on PCI && X86
 	select MFD_CORE
 	select LPC_SCH
 	help
 	  Say yes here to support GPIO interface on Intel Poulsbo SCH,
-	  Intel Tunnel Creek processor or Intel Centerton processor.
+	  Intel Tunnel Creek processor, Intel Centerton processor or Intel
+	  Quark.
 	  The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
 	  powered by the core power rail and are turned off during sleep
 	  modes (S3 and higher). The remaining four GPIOs are powered by
@@ -261,6 +262,8 @@ config GPIO_SCH
 	  The Intel Centerton processor has a total of 30 GPIO pins.
 	  Twenty-one are powered by the core power rail and 9 from the
 	  suspend power supply.
+	  The Intel Quark has 2 GPIOs powered by the core power well and 6
+	  form the suspend power well.
 
 config GPIO_ICH
 	tristate "Intel ICH GPIO"
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5359ca7..5e897ff 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -60,11 +60,17 @@ struct gpio_desc {
 #define FLAG_ACTIVE_LOW	7	/* sysfs value has active low */
 #define FLAG_OPEN_DRAIN	8	/* Gpio is open drain type */
 #define FLAG_OPEN_SOURCE 9	/* Gpio is open source type */
+#define FLAG_PULLUP	10	/* Gpio drive is resistive pullup */
+#define FLAG_PULLDOWN	11	/* Gpio drive is resistive pulldown */
+#define FLAG_STRONG	12	/* Gpio drive is strong (fast output) */
+#define FLAG_HIZ	13	/* Gpio drive is Hi-Z (input) */
 
 #define ID_SHIFT	16	/* add new flags before this one */
 
 #define GPIO_FLAGS_MASK		((1 << ID_SHIFT) - 1)
 #define GPIO_TRIGGER_MASK	(BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
+#define GPIO_DRIVE_MASK		(BIT(FLAG_PULLUP) | BIT(FLAG_PULLDOWN)	\
+				| BIT(FLAG_STRONG) | BIT(FLAG_HIZ))
 
 #ifdef CONFIG_DEBUG_FS
 	const char		*label;
@@ -243,6 +249,10 @@ static DEFINE_MUTEX(sysfs_lock);
  *      * is read/write as zero/nonzero
  *      * also affects existing and subsequent "falling" and "rising"
  *        /edge configuration
+ *   /drive
+ *      * sets signal drive mode
+ *      * is read/write as "pullup", "pulldown", "strong" or "hiz"
+ *
  */
 
 static ssize_t gpio_direction_show(struct device *dev,
@@ -573,9 +583,85 @@ static ssize_t gpio_active_low_store(struct device *dev,
 static const DEVICE_ATTR(active_low, 0644,
 		gpio_active_low_show, gpio_active_low_store);
 
+static ssize_t gpio_drive_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	const struct gpio_desc	*desc = dev_get_drvdata(dev);
+	ssize_t			status;
+
+	mutex_lock(&sysfs_lock);
+
+	if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+		status = -EIO;
+	} else {
+		if (test_bit(FLAG_PULLUP, &desc->flags))
+			status = sprintf(buf, "pullup\n");
+		else if (test_bit(FLAG_PULLDOWN, &desc->flags))
+			status = sprintf(buf, "pulldown\n");
+		else if (test_bit(FLAG_STRONG, &desc->flags))
+			status = sprintf(buf, "strong\n");
+		else if (test_bit(FLAG_HIZ, &desc->flags))
+			status = sprintf(buf, "hiz\n");
+		else
+			status = -EINVAL;
+	}
+
+	mutex_unlock(&sysfs_lock);
+	return status;
+}
+
+static ssize_t gpio_drive_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct gpio_desc	*desc = dev_get_drvdata(dev);
+	unsigned		gpio = desc - gpio_desc;
+	ssize_t			status;
+
+	mutex_lock(&sysfs_lock);
+
+	if (!test_bit(FLAG_EXPORT, &desc->flags))
+		status = -EIO;
+	else {
+		if (sysfs_streq(buf, "pullup")) {
+			status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLUP);
+			if (!status) {
+				desc->flags &= ~GPIO_DRIVE_MASK;
+				set_bit(FLAG_PULLUP, &desc->flags);
+			}
+		} else if (sysfs_streq(buf, "pulldown")) {
+			status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLDOWN);
+			if (!status) {
+				desc->flags &= ~GPIO_DRIVE_MASK;
+				set_bit(FLAG_PULLDOWN, &desc->flags);
+			}
+		} else if (sysfs_streq(buf, "strong")) {
+			status = gpio_set_drive(gpio, GPIOF_DRIVE_STRONG);
+			if (!status) {
+				desc->flags &= ~GPIO_DRIVE_MASK;
+				set_bit(FLAG_STRONG, &desc->flags);
+			}
+		} else if (sysfs_streq(buf, "hiz")) {
+			status = gpio_set_drive(gpio, GPIOF_DRIVE_HIZ);
+			if (!status) {
+				desc->flags &= ~GPIO_DRIVE_MASK;
+				set_bit(FLAG_HIZ, &desc->flags);
+			}
+		} else {
+			status = -EINVAL;
+		}
+	}
+
+	mutex_unlock(&sysfs_lock);
+	return status ? : size;
+}
+
+static const DEVICE_ATTR(drive, 0644,
+		gpio_drive_show, gpio_drive_store);
+
 static const struct attribute *gpio_attrs[] = {
 	&dev_attr_value.attr,
 	&dev_attr_active_low.attr,
+	&dev_attr_drive.attr,
 	NULL,
 };
 
@@ -1677,6 +1763,50 @@ fail:
 }
 EXPORT_SYMBOL_GPL(gpio_set_debounce);
 
+/**
+ * gpio_set_drive - sets drive @mode for a @gpio
+ * @gpio: the gpio to set the drive mode
+ * @mode: the drive mode
+ */
+int gpio_set_drive(unsigned gpio, unsigned mode)
+{
+	unsigned long		flags;
+	struct gpio_chip	*chip;
+	struct gpio_desc	*desc = &gpio_desc[gpio];
+	int			status = -EINVAL;
+
+	spin_lock_irqsave(&gpio_lock, flags);
+
+	if (!gpio_is_valid(gpio))
+		goto fail;
+	chip = desc->chip;
+	if (!chip || !chip->set || !chip->set_drive)
+		goto fail;
+	gpio -= chip->base;
+	if (gpio >= chip->ngpio)
+		goto fail;
+	status = gpio_ensure_requested(desc, gpio);
+	if (status < 0)
+		goto fail;
+
+	/* now we know the gpio is valid and chip won't vanish */
+
+	spin_unlock_irqrestore(&gpio_lock, flags);
+
+	might_sleep_if(chip->can_sleep);
+
+	return chip->set_drive(chip, gpio, mode);
+
+fail:
+	spin_unlock_irqrestore(&gpio_lock, flags);
+	if (status)
+		pr_debug("%s: gpio-%d status %d\n",
+			__func__, gpio, status);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(gpio_set_drive);
+
 /* I/O calls are only valid after configuration completed; the relevant
  * "is this a valid GPIO" error checks should already have been done.
  *
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 20ca766..8265ccc 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -65,6 +65,7 @@ struct device_node;
  * @direction_output: configures signal "offset" as output, or returns error
  * @set_debounce: optional hook for setting debounce time for specified gpio in
  *      interrupt triggered gpio chips
+ * @set_drive: optional hook for setting the drive signal for "offset"
  * @set: assigns output value for signal "offset"
  * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
  *	implementation may not sleep
@@ -113,6 +114,8 @@ struct gpio_chip {
 						unsigned offset, int value);
 	int			(*set_debounce)(struct gpio_chip *chip,
 						unsigned offset, unsigned debounce);
+	int			(*set_drive)(struct gpio_chip *chip,
+					     unsigned offset, unsigned mode);
 
 	void			(*set)(struct gpio_chip *chip,
 						unsigned offset, int value);
@@ -172,6 +175,7 @@ extern int gpio_direction_input(unsigned gpio);
 extern int gpio_direction_output(unsigned gpio, int value);
 
 extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
+extern int gpio_set_drive(unsigned gpio, unsigned mode);
 
 extern int gpio_get_value_cansleep(unsigned gpio);
 extern void gpio_set_value_cansleep(unsigned gpio, int value);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index bfe6656..cadd9d2 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -27,6 +27,11 @@
 #define GPIOF_EXPORT_DIR_FIXED	(GPIOF_EXPORT)
 #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
 
+#define GPIOF_DRIVE_PULLUP	(1 << 6)
+#define GPIOF_DRIVE_PULLDOWN	(1 << 7)
+#define GPIOF_DRIVE_STRONG	(1 << 8)
+#define GPIOF_DRIVE_HIZ		(1 << 9)
+
 /**
  * struct gpio - a structure describing a GPIO with configuration
  * @gpio:	the GPIO number
@@ -156,6 +161,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
 	return -ENOSYS;
 }
 
+static inline int gpio_set_drive(unsigned gpio, unsigned mode)
+{
+	return -ENOSYS;
+}
+
 static inline int gpio_get_value(unsigned gpio)
 {
 	/* GPIO can never have been requested or set as {in,out}put */
-- 
1.7.4.1