Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpio/sch_gpio.c
15109 views
1
/*
2
* sch_gpio.c - GPIO interface for Intel Poulsbo SCH
3
*
4
* Copyright (c) 2010 CompuLab Ltd
5
* Author: Denis Turischev <[email protected]>
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
static DEFINE_SPINLOCK(gpio_lock);
33
34
#define CGEN (0x00)
35
#define CGIO (0x04)
36
#define CGLV (0x08)
37
38
#define RGEN (0x20)
39
#define RGIO (0x24)
40
#define RGLV (0x28)
41
42
static unsigned short gpio_ba;
43
44
static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
45
{
46
u8 curr_dirs;
47
unsigned short offset, bit;
48
49
spin_lock(&gpio_lock);
50
51
offset = CGIO + gpio_num / 8;
52
bit = gpio_num % 8;
53
54
curr_dirs = inb(gpio_ba + offset);
55
56
if (!(curr_dirs & (1 << bit)))
57
outb(curr_dirs | (1 << bit), gpio_ba + offset);
58
59
spin_unlock(&gpio_lock);
60
return 0;
61
}
62
63
static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
64
{
65
int res;
66
unsigned short offset, bit;
67
68
offset = CGLV + gpio_num / 8;
69
bit = gpio_num % 8;
70
71
res = !!(inb(gpio_ba + offset) & (1 << bit));
72
return res;
73
}
74
75
static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
76
{
77
u8 curr_vals;
78
unsigned short offset, bit;
79
80
spin_lock(&gpio_lock);
81
82
offset = CGLV + gpio_num / 8;
83
bit = gpio_num % 8;
84
85
curr_vals = inb(gpio_ba + offset);
86
87
if (val)
88
outb(curr_vals | (1 << bit), gpio_ba + offset);
89
else
90
outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
91
spin_unlock(&gpio_lock);
92
}
93
94
static int sch_gpio_core_direction_out(struct gpio_chip *gc,
95
unsigned gpio_num, int val)
96
{
97
u8 curr_dirs;
98
unsigned short offset, bit;
99
100
sch_gpio_core_set(gc, gpio_num, val);
101
102
spin_lock(&gpio_lock);
103
104
offset = CGIO + gpio_num / 8;
105
bit = gpio_num % 8;
106
107
curr_dirs = inb(gpio_ba + offset);
108
if (curr_dirs & (1 << bit))
109
outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
110
111
spin_unlock(&gpio_lock);
112
return 0;
113
}
114
115
static struct gpio_chip sch_gpio_core = {
116
.label = "sch_gpio_core",
117
.owner = THIS_MODULE,
118
.direction_input = sch_gpio_core_direction_in,
119
.get = sch_gpio_core_get,
120
.direction_output = sch_gpio_core_direction_out,
121
.set = sch_gpio_core_set,
122
};
123
124
static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
125
unsigned gpio_num)
126
{
127
u8 curr_dirs;
128
129
spin_lock(&gpio_lock);
130
131
curr_dirs = inb(gpio_ba + RGIO);
132
133
if (!(curr_dirs & (1 << gpio_num)))
134
outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO);
135
136
spin_unlock(&gpio_lock);
137
return 0;
138
}
139
140
static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
141
{
142
return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
143
}
144
145
static void sch_gpio_resume_set(struct gpio_chip *gc,
146
unsigned gpio_num, int val)
147
{
148
u8 curr_vals;
149
150
spin_lock(&gpio_lock);
151
152
curr_vals = inb(gpio_ba + RGLV);
153
154
if (val)
155
outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV);
156
else
157
outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV);
158
159
spin_unlock(&gpio_lock);
160
}
161
162
static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
163
unsigned gpio_num, int val)
164
{
165
u8 curr_dirs;
166
167
sch_gpio_resume_set(gc, gpio_num, val);
168
169
spin_lock(&gpio_lock);
170
171
curr_dirs = inb(gpio_ba + RGIO);
172
if (curr_dirs & (1 << gpio_num))
173
outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO);
174
175
spin_unlock(&gpio_lock);
176
return 0;
177
}
178
179
static struct gpio_chip sch_gpio_resume = {
180
.label = "sch_gpio_resume",
181
.owner = THIS_MODULE,
182
.direction_input = sch_gpio_resume_direction_in,
183
.get = sch_gpio_resume_get,
184
.direction_output = sch_gpio_resume_direction_out,
185
.set = sch_gpio_resume_set,
186
};
187
188
static int __devinit sch_gpio_probe(struct platform_device *pdev)
189
{
190
struct resource *res;
191
int err, id;
192
193
id = pdev->id;
194
if (!id)
195
return -ENODEV;
196
197
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
198
if (!res)
199
return -EBUSY;
200
201
if (!request_region(res->start, resource_size(res), pdev->name))
202
return -EBUSY;
203
204
gpio_ba = res->start;
205
206
switch (id) {
207
case PCI_DEVICE_ID_INTEL_SCH_LPC:
208
sch_gpio_core.base = 0;
209
sch_gpio_core.ngpio = 10;
210
211
sch_gpio_resume.base = 10;
212
sch_gpio_resume.ngpio = 4;
213
214
/*
215
* GPIO[6:0] enabled by default
216
* GPIO7 is configured by the CMC as SLPIOVR
217
* Enable GPIO[9:8] core powered gpios explicitly
218
*/
219
outb(0x3, gpio_ba + CGEN + 1);
220
/*
221
* SUS_GPIO[2:0] enabled by default
222
* Enable SUS_GPIO3 resume powered gpio explicitly
223
*/
224
outb(0x8, gpio_ba + RGEN);
225
break;
226
227
case PCI_DEVICE_ID_INTEL_ITC_LPC:
228
sch_gpio_core.base = 0;
229
sch_gpio_core.ngpio = 5;
230
231
sch_gpio_resume.base = 5;
232
sch_gpio_resume.ngpio = 9;
233
break;
234
235
default:
236
return -ENODEV;
237
}
238
239
sch_gpio_core.dev = &pdev->dev;
240
sch_gpio_resume.dev = &pdev->dev;
241
242
err = gpiochip_add(&sch_gpio_core);
243
if (err < 0)
244
goto err_sch_gpio_core;
245
246
err = gpiochip_add(&sch_gpio_resume);
247
if (err < 0)
248
goto err_sch_gpio_resume;
249
250
return 0;
251
252
err_sch_gpio_resume:
253
err = gpiochip_remove(&sch_gpio_core);
254
if (err)
255
dev_err(&pdev->dev, "%s failed, %d\n",
256
"gpiochip_remove()", err);
257
258
err_sch_gpio_core:
259
release_region(res->start, resource_size(res));
260
gpio_ba = 0;
261
262
return err;
263
}
264
265
static int __devexit sch_gpio_remove(struct platform_device *pdev)
266
{
267
struct resource *res;
268
if (gpio_ba) {
269
int err;
270
271
err = gpiochip_remove(&sch_gpio_core);
272
if (err)
273
dev_err(&pdev->dev, "%s failed, %d\n",
274
"gpiochip_remove()", err);
275
err = gpiochip_remove(&sch_gpio_resume);
276
if (err)
277
dev_err(&pdev->dev, "%s failed, %d\n",
278
"gpiochip_remove()", err);
279
280
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
281
282
release_region(res->start, resource_size(res));
283
gpio_ba = 0;
284
285
return err;
286
}
287
288
return 0;
289
}
290
291
static struct platform_driver sch_gpio_driver = {
292
.driver = {
293
.name = "sch_gpio",
294
.owner = THIS_MODULE,
295
},
296
.probe = sch_gpio_probe,
297
.remove = __devexit_p(sch_gpio_remove),
298
};
299
300
static int __init sch_gpio_init(void)
301
{
302
return platform_driver_register(&sch_gpio_driver);
303
}
304
305
static void __exit sch_gpio_exit(void)
306
{
307
platform_driver_unregister(&sch_gpio_driver);
308
}
309
310
module_init(sch_gpio_init);
311
module_exit(sch_gpio_exit);
312
313
MODULE_AUTHOR("Denis Turischev <[email protected]>");
314
MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
315
MODULE_LICENSE("GPL");
316
MODULE_ALIAS("platform:sch_gpio");
317
318