Merge tag 'mac80211-next-for-davem-2015-01-19' of git://git.kernel.org/pub/scm/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / gpio / gpio-sch.c
1 /*
2  * GPIO interface for Intel Poulsbo SCH
3  *
4  *  Copyright (c) 2010 CompuLab Ltd
5  *  Author: Denis Turischev <denis@compulab.co.il>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License 2 as published
9  *  by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; see the file COPYING.  If not, write to
18  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/io.h>
25 #include <linux/errno.h>
26 #include <linux/acpi.h>
27 #include <linux/platform_device.h>
28 #include <linux/pci_ids.h>
29
30 #include <linux/gpio.h>
31
32 #define GEN     0x00
33 #define GIO     0x04
34 #define GLV     0x08
35
36 struct sch_gpio {
37         struct gpio_chip chip;
38         spinlock_t lock;
39         unsigned short iobase;
40         unsigned short core_base;
41         unsigned short resume_base;
42 };
43
44 #define to_sch_gpio(c)  container_of(c, struct sch_gpio, chip)
45
46 static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
47                                 unsigned reg)
48 {
49         unsigned base = 0;
50
51         if (gpio >= sch->resume_base) {
52                 gpio -= sch->resume_base;
53                 base += 0x20;
54         }
55
56         return base + reg + gpio / 8;
57 }
58
59 static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
60 {
61         if (gpio >= sch->resume_base)
62                 gpio -= sch->resume_base;
63         return gpio % 8;
64 }
65
66 static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
67 {
68         unsigned short offset, bit;
69         u8 enable;
70
71         spin_lock(&sch->lock);
72
73         offset = sch_gpio_offset(sch, gpio, GEN);
74         bit = sch_gpio_bit(sch, gpio);
75
76         enable = inb(sch->iobase + offset);
77         if (!(enable & (1 << bit)))
78                 outb(enable | (1 << bit), sch->iobase + offset);
79
80         spin_unlock(&sch->lock);
81 }
82
83 static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned  gpio_num)
84 {
85         struct sch_gpio *sch = to_sch_gpio(gc);
86         u8 curr_dirs;
87         unsigned short offset, bit;
88
89         spin_lock(&sch->lock);
90
91         offset = sch_gpio_offset(sch, gpio_num, GIO);
92         bit = sch_gpio_bit(sch, gpio_num);
93
94         curr_dirs = inb(sch->iobase + offset);
95
96         if (!(curr_dirs & (1 << bit)))
97                 outb(curr_dirs | (1 << bit), sch->iobase + offset);
98
99         spin_unlock(&sch->lock);
100         return 0;
101 }
102
103 static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
104 {
105         struct sch_gpio *sch = to_sch_gpio(gc);
106         int res;
107         unsigned short offset, bit;
108
109         offset = sch_gpio_offset(sch, gpio_num, GLV);
110         bit = sch_gpio_bit(sch, gpio_num);
111
112         res = !!(inb(sch->iobase + offset) & (1 << bit));
113
114         return res;
115 }
116
117 static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
118 {
119         struct sch_gpio *sch = to_sch_gpio(gc);
120         u8 curr_vals;
121         unsigned short offset, bit;
122
123         spin_lock(&sch->lock);
124
125         offset = sch_gpio_offset(sch, gpio_num, GLV);
126         bit = sch_gpio_bit(sch, gpio_num);
127
128         curr_vals = inb(sch->iobase + offset);
129
130         if (val)
131                 outb(curr_vals | (1 << bit), sch->iobase + offset);
132         else
133                 outb((curr_vals & ~(1 << bit)), sch->iobase + offset);
134
135         spin_unlock(&sch->lock);
136 }
137
138 static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
139                                   int val)
140 {
141         struct sch_gpio *sch = to_sch_gpio(gc);
142         u8 curr_dirs;
143         unsigned short offset, bit;
144
145         spin_lock(&sch->lock);
146
147         offset = sch_gpio_offset(sch, gpio_num, GIO);
148         bit = sch_gpio_bit(sch, gpio_num);
149
150         curr_dirs = inb(sch->iobase + offset);
151         if (curr_dirs & (1 << bit))
152                 outb(curr_dirs & ~(1 << bit), sch->iobase + offset);
153
154         spin_unlock(&sch->lock);
155
156         /*
157          * according to the datasheet, writing to the level register has no
158          * effect when GPIO is programmed as input.
159          * Actually the the level register is read-only when configured as input.
160          * Thus presetting the output level before switching to output is _NOT_ possible.
161          * Hence we set the level after configuring the GPIO as output.
162          * But we cannot prevent a short low pulse if direction is set to high
163          * and an external pull-up is connected.
164          */
165         sch_gpio_set(gc, gpio_num, val);
166         return 0;
167 }
168
169 static struct gpio_chip sch_gpio_chip = {
170         .label                  = "sch_gpio",
171         .owner                  = THIS_MODULE,
172         .direction_input        = sch_gpio_direction_in,
173         .get                    = sch_gpio_get,
174         .direction_output       = sch_gpio_direction_out,
175         .set                    = sch_gpio_set,
176 };
177
178 static int sch_gpio_probe(struct platform_device *pdev)
179 {
180         struct sch_gpio *sch;
181         struct resource *res;
182
183         sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
184         if (!sch)
185                 return -ENOMEM;
186
187         res = platform_get_resource(pdev, IORESOURCE_IO, 0);
188         if (!res)
189                 return -EBUSY;
190
191         if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
192                                  pdev->name))
193                 return -EBUSY;
194
195         spin_lock_init(&sch->lock);
196         sch->iobase = res->start;
197         sch->chip = sch_gpio_chip;
198         sch->chip.label = dev_name(&pdev->dev);
199         sch->chip.dev = &pdev->dev;
200
201         switch (pdev->id) {
202         case PCI_DEVICE_ID_INTEL_SCH_LPC:
203                 sch->core_base = 0;
204                 sch->resume_base = 10;
205                 sch->chip.ngpio = 14;
206
207                 /*
208                  * GPIO[6:0] enabled by default
209                  * GPIO7 is configured by the CMC as SLPIOVR
210                  * Enable GPIO[9:8] core powered gpios explicitly
211                  */
212                 sch_gpio_enable(sch, 8);
213                 sch_gpio_enable(sch, 9);
214                 /*
215                  * SUS_GPIO[2:0] enabled by default
216                  * Enable SUS_GPIO3 resume powered gpio explicitly
217                  */
218                 sch_gpio_enable(sch, 13);
219                 break;
220
221         case PCI_DEVICE_ID_INTEL_ITC_LPC:
222                 sch->core_base = 0;
223                 sch->resume_base = 5;
224                 sch->chip.ngpio = 14;
225                 break;
226
227         case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
228                 sch->core_base = 0;
229                 sch->resume_base = 21;
230                 sch->chip.ngpio = 30;
231                 break;
232
233         default:
234                 return -ENODEV;
235         }
236
237         platform_set_drvdata(pdev, sch);
238
239         return gpiochip_add(&sch->chip);
240 }
241
242 static int sch_gpio_remove(struct platform_device *pdev)
243 {
244         struct sch_gpio *sch = platform_get_drvdata(pdev);
245
246         gpiochip_remove(&sch->chip);
247         return 0;
248 }
249
250 static struct platform_driver sch_gpio_driver = {
251         .driver = {
252                 .name = "sch_gpio",
253         },
254         .probe          = sch_gpio_probe,
255         .remove         = sch_gpio_remove,
256 };
257
258 module_platform_driver(sch_gpio_driver);
259
260 MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
261 MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
262 MODULE_LICENSE("GPL");
263 MODULE_ALIAS("platform:sch_gpio");