aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2012-04-24 06:02:49 -0400
committerGrant Likely <grant.likely@secretlab.ca>2012-05-11 15:14:54 -0400
commit25cf25073a4e1e0563c288908481f10f98acb19a (patch)
tree7a3e22eb3898b7329150620db3dcd3c2e35f5ca2
parentfd454997d6873ef7ba668200f4278e006139187e (diff)
gpio: add MSIC gpio driver
Add gpio support for Intel MSIC chips found in Intel Medfield platforms. MSIC supports totally 24 GPIOs with 16 low voltage and 8 high voltage pins. Driver uses MSIC mfd interface for MSIC access. (Updated comment to indicate why locking is actually safe) Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-msic.c339
3 files changed, 348 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8ee6d29c3714..5169a99e9f61 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -520,4 +520,12 @@ config GPIO_TPS65910
520 help 520 help
521 Select this option to enable GPIO driver for the TPS65910 521 Select this option to enable GPIO driver for the TPS65910
522 chip family. 522 chip family.
523
524config GPIO_MSIC
525 bool "Intel MSIC mixed signal gpio support"
526 depends on MFD_INTEL_MSIC
527 help
528 Enable support for GPIO on intel MSIC controllers found in
529 intel MID devices
530
523endif 531endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1c2f6c0a835e..7862f49b4d05 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
33obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o 33obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
34obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o 34obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
35obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o 35obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
36obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
36obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o 37obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
37obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o 38obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
38obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o 39obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
new file mode 100644
index 000000000000..71a838f44501
--- /dev/null
+++ b/drivers/gpio/gpio-msic.c
@@ -0,0 +1,339 @@
1/*
2 * Intel Medfield MSIC GPIO driver>
3 * Copyright (c) 2011, Intel Corporation.
4 *
5 * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
6 * Based on intel_pmic_gpio.c
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/slab.h>
26#include <linux/interrupt.h>
27#include <linux/init.h>
28#include <linux/gpio.h>
29#include <linux/platform_device.h>
30#include <linux/mfd/intel_msic.h>
31
32/* the offset for the mapping of global gpio pin to irq */
33#define MSIC_GPIO_IRQ_OFFSET 0x100
34
35#define MSIC_GPIO_DIR_IN 0
36#define MSIC_GPIO_DIR_OUT BIT(5)
37#define MSIC_GPIO_TRIG_FALL BIT(1)
38#define MSIC_GPIO_TRIG_RISE BIT(2)
39
40/* masks for msic gpio output GPIOxxxxCTLO registers */
41#define MSIC_GPIO_DIR_MASK BIT(5)
42#define MSIC_GPIO_DRV_MASK BIT(4)
43#define MSIC_GPIO_REN_MASK BIT(3)
44#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1))
45#define MSIC_GPIO_DOUT_MASK BIT(0)
46
47/* masks for msic gpio input GPIOxxxxCTLI registers */
48#define MSIC_GPIO_GLBYP_MASK BIT(5)
49#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3))
50#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1))
51#define MSIC_GPIO_DIN_MASK BIT(0)
52
53#define MSIC_NUM_GPIO 24
54
55struct msic_gpio {
56 struct platform_device *pdev;
57 struct mutex buslock;
58 struct gpio_chip chip;
59 int irq;
60 unsigned irq_base;
61 unsigned long trig_change_mask;
62 unsigned trig_type;
63};
64
65/*
66 * MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v).
67 * Both the high and low voltage gpios are divided in two banks.
68 * GPIOs are numbered with GPIO0LV0 as gpio_base in the following order:
69 * GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base
70 * GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8
71 * GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16
72 * GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20
73 */
74
75static int msic_gpio_to_ireg(unsigned offset)
76{
77 if (offset >= MSIC_NUM_GPIO)
78 return -EINVAL;
79
80 if (offset < 8)
81 return INTEL_MSIC_GPIO0LV0CTLI - offset;
82 if (offset < 16)
83 return INTEL_MSIC_GPIO1LV0CTLI - offset + 8;
84 if (offset < 20)
85 return INTEL_MSIC_GPIO0HV0CTLI - offset + 16;
86
87 return INTEL_MSIC_GPIO1HV0CTLI - offset + 20;
88}
89
90static int msic_gpio_to_oreg(unsigned offset)
91{
92 if (offset >= MSIC_NUM_GPIO)
93 return -EINVAL;
94
95 if (offset < 8)
96 return INTEL_MSIC_GPIO0LV0CTLO - offset;
97 if (offset < 16)
98 return INTEL_MSIC_GPIO1LV0CTLO - offset + 8;
99 if (offset < 20)
100 return INTEL_MSIC_GPIO0HV0CTLO - offset + 16;
101
102 return INTEL_MSIC_GPIO1HV0CTLO + offset + 20;
103}
104
105static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
106{
107 int reg;
108
109 reg = msic_gpio_to_oreg(offset);
110 if (reg < 0)
111 return reg;
112
113 return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK);
114}
115
116static int msic_gpio_direction_output(struct gpio_chip *chip,
117 unsigned offset, int value)
118{
119 int reg;
120 unsigned mask;
121
122 value = (!!value) | MSIC_GPIO_DIR_OUT;
123 mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK;
124
125 reg = msic_gpio_to_oreg(offset);
126 if (reg < 0)
127 return reg;
128
129 return intel_msic_reg_update(reg, value, mask);
130}
131
132static int msic_gpio_get(struct gpio_chip *chip, unsigned offset)
133{
134 u8 r;
135 int ret;
136 int reg;
137
138 reg = msic_gpio_to_ireg(offset);
139 if (reg < 0)
140 return reg;
141
142 ret = intel_msic_reg_read(reg, &r);
143 if (ret < 0)
144 return ret;
145
146 return r & MSIC_GPIO_DIN_MASK;
147}
148
149static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
150{
151 int reg;
152
153 reg = msic_gpio_to_oreg(offset);
154 if (reg < 0)
155 return;
156
157 intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK);
158}
159
160/*
161 * This is called from genirq with mg->buslock locked and
162 * irq_desc->lock held. We can not access the scu bus here, so we
163 * store the change and update in the bus_sync_unlock() function below
164 */
165static int msic_irq_type(struct irq_data *data, unsigned type)
166{
167 struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
168 u32 gpio = data->irq - mg->irq_base;
169
170 if (gpio >= mg->chip.ngpio)
171 return -EINVAL;
172
173 /* mark for which gpio the trigger changed, protected by buslock */
174 mg->trig_change_mask |= (1 << gpio);
175 mg->trig_type = type;
176
177 return 0;
178}
179
180static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
181{
182 struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip);
183 return mg->irq_base + offset;
184}
185
186static void msic_bus_lock(struct irq_data *data)
187{
188 struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
189 mutex_lock(&mg->buslock);
190}
191
192static void msic_bus_sync_unlock(struct irq_data *data)
193{
194 struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
195 int offset;
196 int reg;
197 u8 trig = 0;
198
199 /* We can only get one change at a time as the buslock covers the
200 entire transaction. The irq_desc->lock is dropped before we are
201 called but that is fine */
202 if (mg->trig_change_mask) {
203 offset = __ffs(mg->trig_change_mask);
204
205 reg = msic_gpio_to_ireg(offset);
206 if (reg < 0)
207 goto out;
208
209 if (mg->trig_type & IRQ_TYPE_EDGE_RISING)
210 trig |= MSIC_GPIO_TRIG_RISE;
211 if (mg->trig_type & IRQ_TYPE_EDGE_FALLING)
212 trig |= MSIC_GPIO_TRIG_FALL;
213
214 intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK);
215 mg->trig_change_mask = 0;
216 }
217out:
218 mutex_unlock(&mg->buslock);
219}
220
221/* Firmware does all the masking and unmasking for us, no masking here. */
222static void msic_irq_unmask(struct irq_data *data) { }
223
224static void msic_irq_mask(struct irq_data *data) { }
225
226static struct irq_chip msic_irqchip = {
227 .name = "MSIC-GPIO",
228 .irq_mask = msic_irq_mask,
229 .irq_unmask = msic_irq_unmask,
230 .irq_set_type = msic_irq_type,
231 .irq_bus_lock = msic_bus_lock,
232 .irq_bus_sync_unlock = msic_bus_sync_unlock,
233};
234
235static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
236{
237 struct irq_data *data = irq_desc_get_irq_data(desc);
238 struct msic_gpio *mg = irq_data_get_irq_handler_data(data);
239 struct irq_chip *chip = irq_data_get_irq_chip(data);
240 struct intel_msic *msic = pdev_to_intel_msic(mg->pdev);
241 int i;
242 int bitnr;
243 u8 pin;
244 unsigned long pending = 0;
245
246 for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) {
247 intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin);
248 pending = pin;
249
250 if (pending) {
251 for_each_set_bit(bitnr, &pending, BITS_PER_BYTE)
252 generic_handle_irq(mg->irq_base +
253 (i * BITS_PER_BYTE) + bitnr);
254 }
255 }
256 chip->irq_eoi(data);
257}
258
259static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
260{
261 struct device *dev = &pdev->dev;
262 struct intel_msic_gpio_pdata *pdata = dev->platform_data;
263 struct msic_gpio *mg;
264 int irq = platform_get_irq(pdev, 0);
265 int retval;
266 int i;
267
268 if (irq < 0) {
269 dev_err(dev, "no IRQ line\n");
270 return -EINVAL;
271 }
272
273 if (!pdata || !pdata->gpio_base) {
274 dev_err(dev, "incorrect or missing platform data\n");
275 return -EINVAL;
276 }
277
278 mg = kzalloc(sizeof(*mg), GFP_KERNEL);
279 if (!mg)
280 return -ENOMEM;
281
282 dev_set_drvdata(dev, mg);
283
284 mg->pdev = pdev;
285 mg->irq = irq;
286 mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET;
287 mg->chip.label = "msic_gpio";
288 mg->chip.direction_input = msic_gpio_direction_input;
289 mg->chip.direction_output = msic_gpio_direction_output;
290 mg->chip.get = msic_gpio_get;
291 mg->chip.set = msic_gpio_set;
292 mg->chip.to_irq = msic_gpio_to_irq;
293 mg->chip.base = pdata->gpio_base;
294 mg->chip.ngpio = MSIC_NUM_GPIO;
295 mg->chip.can_sleep = 1;
296 mg->chip.dev = dev;
297
298 mutex_init(&mg->buslock);
299
300 retval = gpiochip_add(&mg->chip);
301 if (retval) {
302 dev_err(dev, "Adding MSIC gpio chip failed\n");
303 goto err;
304 }
305
306 for (i = 0; i < mg->chip.ngpio; i++) {
307 irq_set_chip_data(i + mg->irq_base, mg);
308 irq_set_chip_and_handler_name(i + mg->irq_base,
309 &msic_irqchip,
310 handle_simple_irq,
311 "demux");
312 }
313 irq_set_chained_handler(mg->irq, msic_gpio_irq_handler);
314 irq_set_handler_data(mg->irq, mg);
315
316 return 0;
317err:
318 kfree(mg);
319 return retval;
320}
321
322static struct platform_driver platform_msic_gpio_driver = {
323 .driver = {
324 .name = "msic_gpio",
325 .owner = THIS_MODULE,
326 },
327 .probe = platform_msic_gpio_probe,
328};
329
330static int __init platform_msic_gpio_init(void)
331{
332 return platform_driver_register(&platform_msic_gpio_driver);
333}
334
335subsys_initcall(platform_msic_gpio_init);
336
337MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>");
338MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver");
339MODULE_LICENSE("GPL v2");