aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudip Mukherjee <sudip.mukherjee@codethink.co.uk>2017-01-19 17:23:20 -0500
committerLinus Walleij <linus.walleij@linaro.org>2017-01-26 05:11:40 -0500
commit6596e59e63cd4c0c0b787ce8c1e8bdd1d957b16e (patch)
treeed8e3c85cdeab061f0360bbf51454ea1ee60cd7f
parent99c8ac957e6b7c670b78ad7b8667051de8624d37 (diff)
gpio: exar: add gpio for exar cards
Exar XR17V352/354/358 chips have 16 multi-purpose inputs/outputs which can be controlled using gpio interface. Add the gpio specific code. Signed-off-by: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-exar.c200
3 files changed, 208 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 701809b1a105..2d7739222cdb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -185,6 +185,13 @@ config GPIO_ETRAXFS
185 help 185 help
186 Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. 186 Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
187 187
188config GPIO_EXAR
189 tristate "Support for GPIO pins on XR17V352/354/358"
190 depends on SERIAL_8250_EXAR
191 help
192 Selecting this option will enable handling of GPIO pins present
193 on Exar XR17V352/354/358 chips.
194
188config GPIO_GE_FPGA 195config GPIO_GE_FPGA
189 bool "GE FPGA based GPIO" 196 bool "GE FPGA based GPIO"
190 depends on GE_FPGA 197 depends on GE_FPGA
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index de45957b9b62..ee8b0dcac623 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
46obj-$(CONFIG_GPIO_EM) += gpio-em.o 46obj-$(CONFIG_GPIO_EM) += gpio-em.o
47obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o 47obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
48obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o 48obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
49obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
49obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o 50obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
50obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o 51obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
51obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o 52obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
new file mode 100644
index 000000000000..05c8946d6446
--- /dev/null
+++ b/drivers/gpio/gpio-exar.c
@@ -0,0 +1,200 @@
1/*
2 * GPIO driver for Exar XR17V35X chip
3 *
4 * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/bitops.h>
11#include <linux/device.h>
12#include <linux/gpio/driver.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/pci.h>
17#include <linux/platform_device.h>
18
19#define EXAR_OFFSET_MPIOLVL_LO 0x90
20#define EXAR_OFFSET_MPIOSEL_LO 0x93
21#define EXAR_OFFSET_MPIOLVL_HI 0x96
22#define EXAR_OFFSET_MPIOSEL_HI 0x99
23
24#define DRIVER_NAME "gpio_exar"
25
26static DEFINE_IDA(ida_index);
27
28struct exar_gpio_chip {
29 struct gpio_chip gpio_chip;
30 struct mutex lock;
31 int index;
32 void __iomem *regs;
33 char name[20];
34};
35
36static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
37 unsigned int offset)
38{
39 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
40 int temp;
41
42 mutex_lock(&exar_gpio->lock);
43 temp = readb(exar_gpio->regs + reg);
44 temp &= ~BIT(offset);
45 if (val)
46 temp |= BIT(offset);
47 writeb(temp, exar_gpio->regs + reg);
48 mutex_unlock(&exar_gpio->lock);
49}
50
51static int exar_set_direction(struct gpio_chip *chip, int direction,
52 unsigned int offset)
53{
54 unsigned int bank = offset / 8;
55 unsigned int addr;
56
57 addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
58 exar_update(chip, addr, direction, offset % 8);
59 return 0;
60}
61
62static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
63 int value)
64{
65 return exar_set_direction(chip, 0, offset);
66}
67
68static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
69{
70 return exar_set_direction(chip, 1, offset);
71}
72
73static int exar_get(struct gpio_chip *chip, unsigned int reg)
74{
75 struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
76 int value;
77
78 mutex_lock(&exar_gpio->lock);
79 value = readb(exar_gpio->regs + reg);
80 mutex_unlock(&exar_gpio->lock);
81
82 return !!value;
83}
84
85static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
86{
87 unsigned int bank = offset / 8;
88 unsigned int addr;
89 int val;
90
91 addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
92 val = exar_get(chip, addr) >> (offset % 8);
93
94 return !!val;
95}
96
97static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
98{
99 unsigned int bank = offset / 8;
100 unsigned int addr;
101 int val;
102
103 addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
104 val = exar_get(chip, addr) >> (offset % 8);
105
106 return !!val;
107}
108
109static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
110 int value)
111{
112 unsigned int bank = offset / 8;
113 unsigned int addr;
114
115 addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
116 exar_update(chip, addr, value, offset % 8);
117}
118
119static int gpio_exar_probe(struct platform_device *pdev)
120{
121 struct pci_dev *pcidev = platform_get_drvdata(pdev);
122 struct exar_gpio_chip *exar_gpio;
123 void __iomem *p;
124 int index, ret;
125
126 if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
127 return -ENODEV;
128
129 /*
130 * Map the pci device to get the register addresses.
131 * We will need to read and write those registers to control
132 * the GPIO pins.
133 * Using managed functions will save us from unmaping on exit.
134 * As the device is enabled using managed functions by the
135 * UART driver we can also use managed functions here.
136 */
137 p = pcim_iomap(pcidev, 0, 0);
138 if (!p)
139 return -ENOMEM;
140
141 exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
142 if (!exar_gpio)
143 return -ENOMEM;
144
145 mutex_init(&exar_gpio->lock);
146
147 index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
148
149 sprintf(exar_gpio->name, "exar_gpio%d", index);
150 exar_gpio->gpio_chip.label = exar_gpio->name;
151 exar_gpio->gpio_chip.parent = &pcidev->dev;
152 exar_gpio->gpio_chip.direction_output = exar_direction_output;
153 exar_gpio->gpio_chip.direction_input = exar_direction_input;
154 exar_gpio->gpio_chip.get_direction = exar_get_direction;
155 exar_gpio->gpio_chip.get = exar_get_value;
156 exar_gpio->gpio_chip.set = exar_set_value;
157 exar_gpio->gpio_chip.base = -1;
158 exar_gpio->gpio_chip.ngpio = 16;
159 exar_gpio->regs = p;
160 exar_gpio->index = index;
161
162 ret = devm_gpiochip_add_data(&pcidev->dev,
163 &exar_gpio->gpio_chip, exar_gpio);
164 if (ret)
165 goto err_destroy;
166
167 platform_set_drvdata(pdev, exar_gpio);
168
169 return 0;
170
171err_destroy:
172 ida_simple_remove(&ida_index, index);
173 mutex_destroy(&exar_gpio->lock);
174 return ret;
175}
176
177static int gpio_exar_remove(struct platform_device *pdev)
178{
179 struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
180
181 ida_simple_remove(&ida_index, exar_gpio->index);
182 mutex_destroy(&exar_gpio->lock);
183
184 return 0;
185}
186
187static struct platform_driver gpio_exar_driver = {
188 .probe = gpio_exar_probe,
189 .remove = gpio_exar_remove,
190 .driver = {
191 .name = DRIVER_NAME,
192 },
193};
194
195module_platform_driver(gpio_exar_driver);
196
197MODULE_ALIAS("platform:" DRIVER_NAME);
198MODULE_DESCRIPTION("Exar GPIO driver");
199MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
200MODULE_LICENSE("GPL");