1aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov/*
2c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely * Generic driver for memory-mapped GPIO controllers.
3aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *
4aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * Copyright 2008 MontaVista Software, Inc.
5aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
6aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *
7aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * This program is free software; you can redistribute  it and/or modify it
8aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * under  the terms of  the GNU General  Public License as published by the
9aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * Free Software Foundation;  either version 2 of the  License, or (at your
10aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * option) any later version.
11aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *
12aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
13aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * ...``                                                         ```````..
14aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * ..The simplest form of a GPIO controller that the driver supports is``
15aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  `.just a single "data" register, where GPIO state can be read and/or `
16aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *    `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.```````
17aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *        `````````
18aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov                                    ___
19aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov_/~~|___/~|   . ```~~~~~~       ___/___\___     ,~.`.`.`.`````.~~...,,,,...
20aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov__________|~$@~~~        %~    /o*o*o*o*o*o\   .. Implementing such a GPIO .
21aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovo        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
22aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov                                                 `....trivial..'~`.```.```
23aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *                                                    ```````
24aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  .```````~~~~`..`.``.``.
25aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * .  The driver supports  `...       ,..```.`~~~```````````````....````.``,,
26aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * .   big-endian notation, just`.  .. A bit more sophisticated controllers ,
27aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  . register the device with -be`. .with a pair of set/clear-bit registers ,
28aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *   `.. suffix.  ```~~`````....`.`   . affecting the data register and the .`
29aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *     ``.`.``...```                  ```.. output pins are also supported.`
30aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *                        ^^             `````.`````````.,``~``~``~~``````
31aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *                                                   .                  ^^
32aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *   ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`..
33aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov * .. The expectation is that in at least some cases .    ,-~~~-,
34aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  .this will be used with roll-your-own ASIC/FPGA .`     \   /
35aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  .logic in Verilog or VHDL. ~~~`````````..`````~~`       \ /
36aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *  ..````````......```````````                             \o_
37aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *                                                           |
38aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *                              ^^                          / \
39aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *
40aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *           ...`````~~`.....``.`..........``````.`.``.```........``.
41aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *            `  8, 16, 32 and 64 bits registers are supported, and``.
42aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *            . the number of GPIOs is determined by the width of   ~
43aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *             .. the registers. ,............```.`.`..`.`.~~~.`.`.`~
44aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov *               `.......````.```
45aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov */
46aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
47aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/init.h>
48280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles#include <linux/err.h>
49aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/bug.h>
50aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/kernel.h>
51aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/module.h>
52aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/spinlock.h>
53aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/compiler.h>
54aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/types.h>
55aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/errno.h>
56aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/log2.h>
57aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/ioport.h>
58aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/io.h>
59aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/gpio.h>
60aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/slab.h>
61aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/platform_device.h>
62aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/mod_devicetable.h>
63aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#include <linux/basic_mmio_gpio.h>
64aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
658467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic void bgpio_write8(void __iomem *reg, unsigned long data)
66aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
67fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	writeb(data, reg);
68aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
69aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
708467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic unsigned long bgpio_read8(void __iomem *reg)
71aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
72fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	return readb(reg);
738467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
748467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
758467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic void bgpio_write16(void __iomem *reg, unsigned long data)
768467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
77fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	writew(data, reg);
788467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
798467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
808467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic unsigned long bgpio_read16(void __iomem *reg)
818467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
82fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	return readw(reg);
838467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
848467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
858467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic void bgpio_write32(void __iomem *reg, unsigned long data)
868467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
87fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	writel(data, reg);
888467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
898467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
908467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic unsigned long bgpio_read32(void __iomem *reg)
918467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
92fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	return readl(reg);
938467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
948467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
95aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov#if BITS_PER_LONG >= 64
968467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic void bgpio_write64(void __iomem *reg, unsigned long data)
978467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
98fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	writeq(data, reg);
998467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
1008467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
1018467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic unsigned long bgpio_read64(void __iomem *reg)
1028467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
103fd9962352105f19711d55cc2caaf75b2e201598bJamie Iles	return readq(reg);
104aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
1058467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles#endif /* BITS_PER_LONG >= 64 */
106aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
107aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
108aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
1098467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	return 1 << pin;
1108467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
1118467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
1128467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Ilesstatic unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
1138467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles				       unsigned int pin)
1148467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
1158467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	return 1 << (bgc->bits - 1 - pin);
116aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
117aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
118aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
119aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
120aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	struct bgpio_chip *bgc = to_bgpio_chip(gc);
121aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
1228467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
123aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
124aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
125aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
126aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
127aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	struct bgpio_chip *bgc = to_bgpio_chip(gc);
1288467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	unsigned long mask = bgc->pin2mask(bgc, gpio);
129aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	unsigned long flags;
130aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
131aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	spin_lock_irqsave(&bgc->lock, flags);
132aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
133aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	if (val)
134aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov		bgc->data |= mask;
135aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	else
136aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov		bgc->data &= ~mask;
137aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
1388467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	bgc->write_reg(bgc->reg_dat, bgc->data);
139aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
140aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	spin_unlock_irqrestore(&bgc->lock, flags);
141aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
142aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
143e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Ilesstatic void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
144e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles				 int val)
145e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles{
146e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
147e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	unsigned long mask = bgc->pin2mask(bgc, gpio);
148e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
149e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	if (val)
150e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles		bgc->write_reg(bgc->reg_set, mask);
151e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	else
152e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles		bgc->write_reg(bgc->reg_clr, mask);
153e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles}
154e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
155dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Ilesstatic void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
156dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles{
157dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
158dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	unsigned long mask = bgc->pin2mask(bgc, gpio);
159dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	unsigned long flags;
160dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
161dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	spin_lock_irqsave(&bgc->lock, flags);
162dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
163dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	if (val)
164dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles		bgc->data |= mask;
165dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	else
166dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles		bgc->data &= ~mask;
167dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
168dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	bgc->write_reg(bgc->reg_set, bgc->data);
169dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
170dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	spin_unlock_irqrestore(&bgc->lock, flags);
171dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles}
172dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
17331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Ilesstatic int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
17431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles{
17531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	return 0;
17631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles}
17731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
17831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Ilesstatic int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
17931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles				int val)
18031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles{
18131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	gc->set(gc, gpio, val);
18231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
18331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	return 0;
18431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles}
18531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
186aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
187aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
18831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
18931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	unsigned long flags;
19031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
19131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_lock_irqsave(&bgc->lock, flags);
19231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
19331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
19431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->write_reg(bgc->reg_dir, bgc->dir);
19531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
19631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_unlock_irqrestore(&bgc->lock, flags);
19731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
198aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	return 0;
199aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
200aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
201aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
202aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
20331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
20431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	unsigned long flags;
20531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
20631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	gc->set(gc, gpio, val);
20731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
20831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_lock_irqsave(&bgc->lock, flags);
20931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
21031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->dir |= bgc->pin2mask(bgc, gpio);
21131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->write_reg(bgc->reg_dir, bgc->dir);
21231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
21331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_unlock_irqrestore(&bgc->lock, flags);
21431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
21531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	return 0;
21631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles}
21731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
21831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Ilesstatic int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
21931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles{
22031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
22131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	unsigned long flags;
22231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
22331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_lock_irqsave(&bgc->lock, flags);
22431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
22531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->dir |= bgc->pin2mask(bgc, gpio);
22631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->write_reg(bgc->reg_dir, bgc->dir);
22731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
22831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_unlock_irqrestore(&bgc->lock, flags);
22931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
23031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	return 0;
23131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles}
23231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
23331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Ilesstatic int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
23431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles{
23531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	struct bgpio_chip *bgc = to_bgpio_chip(gc);
23631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	unsigned long flags;
23731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
238e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	gc->set(gc, gpio, val);
239e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
24031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_lock_irqsave(&bgc->lock, flags);
24131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
24231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->dir &= ~bgc->pin2mask(bgc, gpio);
24331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	bgc->write_reg(bgc->reg_dir, bgc->dir);
24431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
24531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	spin_unlock_irqrestore(&bgc->lock, flags);
24631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
247aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	return 0;
248aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
249aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
250280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic int bgpio_setup_accessors(struct device *dev,
251280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles				 struct bgpio_chip *bgc,
252280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles				 bool be)
253aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
2548467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
2558467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	switch (bgc->bits) {
2568467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	case 8:
2578467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->read_reg	= bgpio_read8;
2588467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->write_reg	= bgpio_write8;
2598467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		break;
2608467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	case 16:
2618467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->read_reg	= bgpio_read16;
2628467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->write_reg	= bgpio_write16;
2638467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		break;
2648467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	case 32:
2658467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->read_reg	= bgpio_read32;
2668467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->write_reg	= bgpio_write32;
2678467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		break;
2688467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles#if BITS_PER_LONG >= 64
2698467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	case 64:
2708467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->read_reg	= bgpio_read64;
2718467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		bgc->write_reg	= bgpio_write64;
2728467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		break;
2738467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles#endif /* BITS_PER_LONG >= 64 */
2748467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	default:
275280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
2768467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		return -EINVAL;
2778467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	}
2788467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
279280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
2808467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
2818467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	return 0;
2828467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles}
2838467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles
284e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles/*
285e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles * Create the device and allocate the resources.  For setting GPIO's there are
286dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles * three supported configurations:
287e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles *
288dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles *	- single input/output register resource (named "dat").
289e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles *	- set/clear pair (named "set" and "clr").
290dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles *	- single output register resource and single input resource ("set" and
291dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles *	dat").
292e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles *
293e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles * For the single output register, this drives a 1 by setting a bit and a zero
294e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles * by clearing a bit.  For the set clr pair, this drives a 1 by setting a bit
295e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles * in the set register and clears it by setting a bit in the clear register.
296e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles * The configuration is detected by which resources are present.
29731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *
29831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles * For setting the GPIO direction, there are three supported configurations:
29931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *
30031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *	- simple bidirection GPIO that requires no configuration.
30131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *	- an output direction register (named "dirout") where a 1 bit
30231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *	indicates the GPIO is an output.
30331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *	- an input direction register (named "dirin") where a 1 bit indicates
30431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles *	the GPIO is an input.
305e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles */
306280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic int bgpio_setup_io(struct bgpio_chip *bgc,
307280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			  void __iomem *dat,
308280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			  void __iomem *set,
309280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			  void __iomem *clr)
3108467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles{
311aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
312280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->reg_dat = dat;
313aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	if (!bgc->reg_dat)
314280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return -EINVAL;
315e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
316280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (set && clr) {
317280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->reg_set = set;
318280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->reg_clr = clr;
319e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles		bgc->gc.set = bgpio_set_with_clear;
320280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	} else if (set && !clr) {
321280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->reg_set = set;
322dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles		bgc->gc.set = bgpio_set_set;
323e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	} else {
324e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles		bgc->gc.set = bgpio_set;
325aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	}
326aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
327dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles	bgc->gc.get = bgpio_get;
328dd86a0cc5e35161538c10e35eb85e2ad0adfe14dJamie Iles
329e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	return 0;
330e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles}
331e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
332280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic int bgpio_setup_direction(struct bgpio_chip *bgc,
333280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles				 void __iomem *dirout,
334280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles				 void __iomem *dirin)
33531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles{
336280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (dirout && dirin) {
33731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		return -EINVAL;
338280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	} else if (dirout) {
339280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->reg_dir = dirout;
34031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_output = bgpio_dir_out;
34131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_input = bgpio_dir_in;
342280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	} else if (dirin) {
343280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->reg_dir = dirin;
34431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_output = bgpio_dir_out_inv;
34531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_input = bgpio_dir_in_inv;
34631029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	} else {
34731029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_output = bgpio_simple_dir_out;
34831029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		bgc->gc.direction_input = bgpio_simple_dir_in;
34931029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	}
35031029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
35131029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	return 0;
35231029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles}
35331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
3544f5b04800a224aadb6cffcbbc3d3fa26e2367c7fRussell Kingint bgpio_remove(struct bgpio_chip *bgc)
355280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles{
356280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	int err = gpiochip_remove(&bgc->gc);
357280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
358280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	kfree(bgc);
359280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
360280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	return err;
361280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles}
362280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie IlesEXPORT_SYMBOL_GPL(bgpio_remove);
363280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
3644f5b04800a224aadb6cffcbbc3d3fa26e2367c7fRussell Kingint bgpio_init(struct bgpio_chip *bgc, struct device *dev,
3654f5b04800a224aadb6cffcbbc3d3fa26e2367c7fRussell King	       unsigned long sz, void __iomem *dat, void __iomem *set,
3664f5b04800a224aadb6cffcbbc3d3fa26e2367c7fRussell King	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
3674f5b04800a224aadb6cffcbbc3d3fa26e2367c7fRussell King	       bool big_endian)
368e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles{
369e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	int ret;
370e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
371280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!is_power_of_2(sz))
372280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return -EINVAL;
373e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles
374280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->bits = sz * 8;
375280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (bgc->bits > BITS_PER_LONG)
376280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return -EINVAL;
377280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
378280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	spin_lock_init(&bgc->lock);
379280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->gc.dev = dev;
380280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->gc.label = dev_name(dev);
381280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->gc.base = -1;
382280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc->gc.ngpio = bgc->bits;
383280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
384280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	ret = bgpio_setup_io(bgc, dat, set, clr);
385e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles	if (ret)
386e027d6f9d52d9ccabb307d0cb0265de3481b1e9eJamie Iles		return ret;
387aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
388280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	ret = bgpio_setup_accessors(dev, bgc, big_endian);
3898467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	if (ret)
3908467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles		return ret;
391aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
392280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	ret = bgpio_setup_direction(bgc, dirout, dirin);
39331029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles	if (ret)
39431029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles		return ret;
39531029116ebc1f2481bd2380437e9f7a18f18dca5Jamie Iles
3968467afec5f8137fd0c13121f8a38c99c54c913f6Jamie Iles	bgc->data = bgc->read_reg(bgc->reg_dat);
397924e7a9fc6da124588e27c611841d07047c157b4Jamie Iles
398280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	return ret;
399280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles}
400280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie IlesEXPORT_SYMBOL_GPL(bgpio_init);
401aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
402c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely#ifdef CONFIG_GPIO_GENERIC_PLATFORM
403aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
404280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic void __iomem *bgpio_map(struct platform_device *pdev,
405280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			       const char *name,
406280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			       resource_size_t sane_sz,
407280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			       int *err)
408280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles{
409280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct device *dev = &pdev->dev;
410280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct resource *r;
411280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	resource_size_t start;
412280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	resource_size_t sz;
413280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *ret;
414280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
415280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	*err = 0;
416280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
417280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
418280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!r)
419280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return NULL;
420280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
421280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	sz = resource_size(r);
422280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (sz != sane_sz) {
423280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		*err = -EINVAL;
424280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return NULL;
425280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	}
426280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
427280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	start = r->start;
428280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!devm_request_mem_region(dev, start, sz, r->name)) {
429280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		*err = -EBUSY;
430280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return NULL;
431280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	}
432280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
433280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	ret = devm_ioremap(dev, start, sz);
434280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!ret) {
435280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		*err = -ENOMEM;
436280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return NULL;
437280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	}
438aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
439aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	return ret;
440aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
441aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
442280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic int __devinit bgpio_pdev_probe(struct platform_device *pdev)
443280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles{
444280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct device *dev = &pdev->dev;
445280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct resource *r;
446280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *dat;
447280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *set;
448280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *clr;
449280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *dirout;
450280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	void __iomem *dirin;
451280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	unsigned long sz;
452280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bool be;
453280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	int err;
454280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct bgpio_chip *bgc;
455280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	struct bgpio_pdata *pdata = dev_get_platdata(dev);
456280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
457280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
458280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!r)
459280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return -EINVAL;
460280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
461280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	sz = resource_size(r);
462280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
463280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	dat = bgpio_map(pdev, "dat", sz, &err);
464280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!dat)
465280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err ? err : -EINVAL;
466280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
467280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	set = bgpio_map(pdev, "set", sz, &err);
468280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (err)
469280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err;
470280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
471280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	clr = bgpio_map(pdev, "clr", sz, &err);
472280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (err)
473280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err;
474280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
475280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	dirout = bgpio_map(pdev, "dirout", sz, &err);
476280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (err)
477280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err;
478280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
479280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	dirin = bgpio_map(pdev, "dirin", sz, &err);
480280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (err)
481280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err;
482280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
483280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
484280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
485280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
486280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (!bgc)
487280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return -ENOMEM;
488280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
489280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
490280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (err)
491280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		return err;
492280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
493280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	if (pdata) {
494280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		bgc->gc.base = pdata->base;
495280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles		if (pdata->ngpio > 0)
496280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles			bgc->gc.ngpio = pdata->ngpio;
497280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	}
498280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
499280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	platform_set_drvdata(pdev, bgc);
500280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
501280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	return gpiochip_add(&bgc->gc);
502280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles}
503280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
504280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Ilesstatic int __devexit bgpio_pdev_remove(struct platform_device *pdev)
505aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov{
5064ddb8ae217ad2aae888d00d97c5160f677dd38f4Jamie Iles	struct bgpio_chip *bgc = platform_get_drvdata(pdev);
507aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
508280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	return bgpio_remove(bgc);
509aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov}
510aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
511aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic const struct platform_device_id bgpio_id_table[] = {
512aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	{ "basic-mmio-gpio", },
513aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	{ "basic-mmio-gpio-be", },
514aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	{},
515aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov};
516aeec56e331c6d2750de02ef34b305338305ca690Anton VorontsovMODULE_DEVICE_TABLE(platform, bgpio_id_table);
517aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
518aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsovstatic struct platform_driver bgpio_driver = {
519aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	.driver = {
520aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov		.name = "basic-mmio-gpio",
521aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	},
522aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov	.id_table = bgpio_id_table,
523280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	.probe = bgpio_pdev_probe,
524280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles	.remove = __devexit_p(bgpio_pdev_remove),
525aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov};
526aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
5276f61415e9c4c0ab02c8eda7671bb652db4863cc0Mark Brownmodule_platform_driver(bgpio_driver);
528280df6b3c3ad777a91f1011cd98d50df891bfef8Jamie Iles
529c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely#endif /* CONFIG_GPIO_GENERIC_PLATFORM */
530aeec56e331c6d2750de02ef34b305338305ca690Anton Vorontsov
531aeec56e331c6d2750de02ef34b305338305ca690Anton VorontsovMODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
532aeec56e331c6d2750de02ef34b305338305ca690Anton VorontsovMODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
533aeec56e331c6d2750de02ef34b305338305ca690Anton VorontsovMODULE_LICENSE("GPL");
534