aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>2011-01-12 20:00:22 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 11:03:14 -0500
commit49a367937fe4250144e24440e5a11ae4344202b1 (patch)
tree7ed12762e4d819c312960ce537f07159488fc0a4 /drivers/gpio
parent32518863b483d521edc813616a35601cad213d31 (diff)
gpio/ml_ioh_gpio: ML7213 GPIO driver
ML7213 is a companion chip for Intel Atom E6xx series. This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output Hub) which is for IVI(In-Vehicle Infotainment) use. This driver can access the IOH's GPIO device. Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> Cc: Samuel Ortiz <sameo@linux.intel.com> Cc: Rabin Vincent <rabin.vincent@stericsson.com> Cc: Marc Zyngier <maz@misterjones.org> Cc: Linus Walleij <linus.walleij@stericsson.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig9
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/ml_ioh_gpio.c352
3 files changed, 362 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 454e2bc373a8..664660e56335 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -333,6 +333,15 @@ config GPIO_PCH
333 which is an IOH(Input/Output Hub) for x86 embedded processor. 333 which is an IOH(Input/Output Hub) for x86 embedded processor.
334 This driver can access PCH GPIO device. 334 This driver can access PCH GPIO device.
335 335
336config GPIO_ML_IOH
337 tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
338 depends on PCI
339 help
340 ML7213 is companion chip for Intel Atom E6xx series.
341 This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
342 Hub) which is for IVI(In-Vehicle Infotainment) use.
343 This driver can access the IOH's GPIO device.
344
336config GPIO_TIMBERDALE 345config GPIO_TIMBERDALE
337 bool "Support for timberdale GPIO IP" 346 bool "Support for timberdale GPIO IP"
338 depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM 347 depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 39bfd7a37650..3351cf87b0ed 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -41,3 +41,4 @@ obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o
41obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o 41obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o
42obj-$(CONFIG_GPIO_SX150X) += sx150x.o 42obj-$(CONFIG_GPIO_SX150X) += sx150x.o
43obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o 43obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o
44obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o
diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c
new file mode 100644
index 000000000000..cead8e6ff345
--- /dev/null
+++ b/drivers/gpio/ml_ioh_gpio.c
@@ -0,0 +1,352 @@
1/*
2 * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 */
17#include <linux/kernel.h>
18#include <linux/pci.h>
19#include <linux/gpio.h>
20
21#define PCI_VENDOR_ID_ROHM 0x10DB
22
23struct ioh_reg_comn {
24 u32 ien;
25 u32 istatus;
26 u32 idisp;
27 u32 iclr;
28 u32 imask;
29 u32 imaskclr;
30 u32 po;
31 u32 pi;
32 u32 pm;
33 u32 im_0;
34 u32 im_1;
35 u32 reserved;
36};
37
38struct ioh_regs {
39 struct ioh_reg_comn regs[8];
40 u32 reserve1[16];
41 u32 ioh_sel_reg[4];
42 u32 reserve2[11];
43 u32 srst;
44};
45
46/**
47 * struct ioh_gpio_reg_data - The register store data.
48 * @po_reg: To store contents of PO register.
49 * @pm_reg: To store contents of PM register.
50 */
51struct ioh_gpio_reg_data {
52 u32 po_reg;
53 u32 pm_reg;
54};
55
56/**
57 * struct ioh_gpio - GPIO private data structure.
58 * @base: PCI base address of Memory mapped I/O register.
59 * @reg: Memory mapped IOH GPIO register list.
60 * @dev: Pointer to device structure.
61 * @gpio: Data for GPIO infrastructure.
62 * @ioh_gpio_reg: Memory mapped Register data is saved here
63 * when suspend.
64 * @ch: Indicate GPIO channel
65 */
66struct ioh_gpio {
67 void __iomem *base;
68 struct ioh_regs __iomem *reg;
69 struct device *dev;
70 struct gpio_chip gpio;
71 struct ioh_gpio_reg_data ioh_gpio_reg;
72 struct mutex lock;
73 int ch;
74};
75
76static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
77
78static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
79{
80 u32 reg_val;
81 struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
82
83 mutex_lock(&chip->lock);
84 reg_val = ioread32(&chip->reg->regs[chip->ch].po);
85 if (val)
86 reg_val |= (1 << nr);
87 else
88 reg_val &= ~(1 << nr);
89
90 iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
91 mutex_unlock(&chip->lock);
92}
93
94static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
95{
96 struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
97
98 return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr);
99}
100
101static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
102 int val)
103{
104 struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
105 u32 pm;
106 u32 reg_val;
107
108 mutex_lock(&chip->lock);
109 pm = ioread32(&chip->reg->regs[chip->ch].pm) &
110 ((1 << num_ports[chip->ch]) - 1);
111 pm |= (1 << nr);
112 iowrite32(pm, &chip->reg->regs[chip->ch].pm);
113
114 reg_val = ioread32(&chip->reg->regs[chip->ch].po);
115 if (val)
116 reg_val |= (1 << nr);
117 else
118 reg_val &= ~(1 << nr);
119
120 mutex_unlock(&chip->lock);
121
122 return 0;
123}
124
125static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
126{
127 struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
128 u32 pm;
129
130 mutex_lock(&chip->lock);
131 pm = ioread32(&chip->reg->regs[chip->ch].pm) &
132 ((1 << num_ports[chip->ch]) - 1);
133 pm &= ~(1 << nr);
134 iowrite32(pm, &chip->reg->regs[chip->ch].pm);
135 mutex_unlock(&chip->lock);
136
137 return 0;
138}
139
140/*
141 * Save register configuration and disable interrupts.
142 */
143static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
144{
145 chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po);
146 chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm);
147}
148
149/*
150 * This function restores the register configuration of the GPIO device.
151 */
152static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
153{
154 /* to store contents of PO register */
155 iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po);
156 /* to store contents of PM register */
157 iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
158}
159
160static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
161{
162 struct gpio_chip *gpio = &chip->gpio;
163
164 gpio->label = dev_name(chip->dev);
165 gpio->owner = THIS_MODULE;
166 gpio->direction_input = ioh_gpio_direction_input;
167 gpio->get = ioh_gpio_get;
168 gpio->direction_output = ioh_gpio_direction_output;
169 gpio->set = ioh_gpio_set;
170 gpio->dbg_show = NULL;
171 gpio->base = -1;
172 gpio->ngpio = num_port;
173 gpio->can_sleep = 0;
174}
175
176static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
177 const struct pci_device_id *id)
178{
179 int ret;
180 int i;
181 struct ioh_gpio *chip;
182 void __iomem *base;
183 void __iomem *chip_save;
184
185 ret = pci_enable_device(pdev);
186 if (ret) {
187 dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__);
188 goto err_pci_enable;
189 }
190
191 ret = pci_request_regions(pdev, KBUILD_MODNAME);
192 if (ret) {
193 dev_err(&pdev->dev, "pci_request_regions failed-%d", ret);
194 goto err_request_regions;
195 }
196
197 base = pci_iomap(pdev, 1, 0);
198 if (base == 0) {
199 dev_err(&pdev->dev, "%s : pci_iomap failed", __func__);
200 ret = -ENOMEM;
201 goto err_iomap;
202 }
203
204 chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL);
205 if (chip_save == NULL) {
206 dev_err(&pdev->dev, "%s : kzalloc failed", __func__);
207 ret = -ENOMEM;
208 goto err_kzalloc;
209 }
210
211 chip = chip_save;
212 for (i = 0; i < 8; i++, chip++) {
213 chip->dev = &pdev->dev;
214 chip->base = base;
215 chip->reg = chip->base;
216 chip->ch = i;
217 mutex_init(&chip->lock);
218 ioh_gpio_setup(chip, num_ports[i]);
219 ret = gpiochip_add(&chip->gpio);
220 if (ret) {
221 dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n");
222 goto err_gpiochip_add;
223 }
224 }
225
226 chip = chip_save;
227 pci_set_drvdata(pdev, chip);
228
229 return 0;
230
231err_gpiochip_add:
232 for (; i != 0; i--) {
233 chip--;
234 ret = gpiochip_remove(&chip->gpio);
235 if (ret)
236 dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
237 }
238 kfree(chip_save);
239
240err_kzalloc:
241 pci_iounmap(pdev, base);
242
243err_iomap:
244 pci_release_regions(pdev);
245
246err_request_regions:
247 pci_disable_device(pdev);
248
249err_pci_enable:
250
251 dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret);
252 return ret;
253}
254
255static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
256{
257 int err;
258 int i;
259 struct ioh_gpio *chip = pci_get_drvdata(pdev);
260 void __iomem *chip_save;
261
262 chip_save = chip;
263 for (i = 0; i < 8; i++, chip++) {
264 err = gpiochip_remove(&chip->gpio);
265 if (err)
266 dev_err(&pdev->dev, "Failed gpiochip_remove\n");
267 }
268
269 chip = chip_save;
270 pci_iounmap(pdev, chip->base);
271 pci_release_regions(pdev);
272 pci_disable_device(pdev);
273 kfree(chip);
274}
275
276#ifdef CONFIG_PM
277static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
278{
279 s32 ret;
280 struct ioh_gpio *chip = pci_get_drvdata(pdev);
281
282 ioh_gpio_save_reg_conf(chip);
283 ioh_gpio_restore_reg_conf(chip);
284
285 ret = pci_save_state(pdev);
286 if (ret) {
287 dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
288 return ret;
289 }
290 pci_disable_device(pdev);
291 pci_set_power_state(pdev, PCI_D0);
292 ret = pci_enable_wake(pdev, PCI_D0, 1);
293 if (ret)
294 dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
295
296 return 0;
297}
298
299static int ioh_gpio_resume(struct pci_dev *pdev)
300{
301 s32 ret;
302 struct ioh_gpio *chip = pci_get_drvdata(pdev);
303
304 ret = pci_enable_wake(pdev, PCI_D0, 0);
305
306 pci_set_power_state(pdev, PCI_D0);
307 ret = pci_enable_device(pdev);
308 if (ret) {
309 dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
310 return ret;
311 }
312 pci_restore_state(pdev);
313
314 iowrite32(0x01, &chip->reg->srst);
315 iowrite32(0x00, &chip->reg->srst);
316 ioh_gpio_restore_reg_conf(chip);
317
318 return 0;
319}
320#else
321#define ioh_gpio_suspend NULL
322#define ioh_gpio_resume NULL
323#endif
324
325static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = {
326 { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
327 { 0, }
328};
329
330static struct pci_driver ioh_gpio_driver = {
331 .name = "ml_ioh_gpio",
332 .id_table = ioh_gpio_pcidev_id,
333 .probe = ioh_gpio_probe,
334 .remove = __devexit_p(ioh_gpio_remove),
335 .suspend = ioh_gpio_suspend,
336 .resume = ioh_gpio_resume
337};
338
339static int __init ioh_gpio_pci_init(void)
340{
341 return pci_register_driver(&ioh_gpio_driver);
342}
343module_init(ioh_gpio_pci_init);
344
345static void __exit ioh_gpio_pci_exit(void)
346{
347 pci_unregister_driver(&ioh_gpio_driver);
348}
349module_exit(ioh_gpio_pci_exit);
350
351MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver");
352MODULE_LICENSE("GPL");