Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpio/bt8xxgpio.c
15109 views
1
/*
2
3
bt8xx GPIO abuser
4
5
Copyright (C) 2008 Michael Buesch <[email protected]>
6
7
Please do _only_ contact the people listed _above_ with issues related to this driver.
8
All the other people listed below are not related to this driver. Their names
9
are only here, because this driver is derived from the bt848 driver.
10
11
12
Derived from the bt848 driver:
13
14
Copyright (C) 1996,97,98 Ralph Metzler
15
& Marcus Metzler
16
(c) 1999-2002 Gerd Knorr
17
18
some v4l2 code lines are taken from Justin's bttv2 driver which is
19
(c) 2000 Justin Schoeman
20
21
V4L1 removal from:
22
(c) 2005-2006 Nickolay V. Shmyrev
23
24
Fixes to be fully V4L2 compliant by
25
(c) 2006 Mauro Carvalho Chehab
26
27
Cropping and overscan support
28
Copyright (C) 2005, 2006 Michael H. Schimek
29
Sponsored by OPQ Systems AB
30
31
This program is free software; you can redistribute it and/or modify
32
it under the terms of the GNU General Public License as published by
33
the Free Software Foundation; either version 2 of the License, or
34
(at your option) any later version.
35
36
This program is distributed in the hope that it will be useful,
37
but WITHOUT ANY WARRANTY; without even the implied warranty of
38
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39
GNU General Public License for more details.
40
41
You should have received a copy of the GNU General Public License
42
along with this program; if not, write to the Free Software
43
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44
*/
45
46
#include <linux/module.h>
47
#include <linux/pci.h>
48
#include <linux/spinlock.h>
49
#include <linux/gpio.h>
50
#include <linux/slab.h>
51
52
/* Steal the hardware definitions from the bttv driver. */
53
#include "../media/video/bt8xx/bt848.h"
54
55
56
#define BT8XXGPIO_NR_GPIOS 24 /* We have 24 GPIO pins */
57
58
59
struct bt8xxgpio {
60
spinlock_t lock;
61
62
void __iomem *mmio;
63
struct pci_dev *pdev;
64
struct gpio_chip gpio;
65
66
#ifdef CONFIG_PM
67
u32 saved_outen;
68
u32 saved_data;
69
#endif
70
};
71
72
#define bgwrite(dat, adr) writel((dat), bg->mmio+(adr))
73
#define bgread(adr) readl(bg->mmio+(adr))
74
75
76
static int modparam_gpiobase = -1/* dynamic */;
77
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
78
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
79
80
81
static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
82
{
83
struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
84
unsigned long flags;
85
u32 outen, data;
86
87
spin_lock_irqsave(&bg->lock, flags);
88
89
data = bgread(BT848_GPIO_DATA);
90
data &= ~(1 << nr);
91
bgwrite(data, BT848_GPIO_DATA);
92
93
outen = bgread(BT848_GPIO_OUT_EN);
94
outen &= ~(1 << nr);
95
bgwrite(outen, BT848_GPIO_OUT_EN);
96
97
spin_unlock_irqrestore(&bg->lock, flags);
98
99
return 0;
100
}
101
102
static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
103
{
104
struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
105
unsigned long flags;
106
u32 val;
107
108
spin_lock_irqsave(&bg->lock, flags);
109
val = bgread(BT848_GPIO_DATA);
110
spin_unlock_irqrestore(&bg->lock, flags);
111
112
return !!(val & (1 << nr));
113
}
114
115
static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
116
unsigned nr, int val)
117
{
118
struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
119
unsigned long flags;
120
u32 outen, data;
121
122
spin_lock_irqsave(&bg->lock, flags);
123
124
outen = bgread(BT848_GPIO_OUT_EN);
125
outen |= (1 << nr);
126
bgwrite(outen, BT848_GPIO_OUT_EN);
127
128
data = bgread(BT848_GPIO_DATA);
129
if (val)
130
data |= (1 << nr);
131
else
132
data &= ~(1 << nr);
133
bgwrite(data, BT848_GPIO_DATA);
134
135
spin_unlock_irqrestore(&bg->lock, flags);
136
137
return 0;
138
}
139
140
static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
141
unsigned nr, int val)
142
{
143
struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
144
unsigned long flags;
145
u32 data;
146
147
spin_lock_irqsave(&bg->lock, flags);
148
149
data = bgread(BT848_GPIO_DATA);
150
if (val)
151
data |= (1 << nr);
152
else
153
data &= ~(1 << nr);
154
bgwrite(data, BT848_GPIO_DATA);
155
156
spin_unlock_irqrestore(&bg->lock, flags);
157
}
158
159
static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
160
{
161
struct gpio_chip *c = &bg->gpio;
162
163
c->label = dev_name(&bg->pdev->dev);
164
c->owner = THIS_MODULE;
165
c->direction_input = bt8xxgpio_gpio_direction_input;
166
c->get = bt8xxgpio_gpio_get;
167
c->direction_output = bt8xxgpio_gpio_direction_output;
168
c->set = bt8xxgpio_gpio_set;
169
c->dbg_show = NULL;
170
c->base = modparam_gpiobase;
171
c->ngpio = BT8XXGPIO_NR_GPIOS;
172
c->can_sleep = 0;
173
}
174
175
static int bt8xxgpio_probe(struct pci_dev *dev,
176
const struct pci_device_id *pci_id)
177
{
178
struct bt8xxgpio *bg;
179
int err;
180
181
bg = kzalloc(sizeof(*bg), GFP_KERNEL);
182
if (!bg)
183
return -ENOMEM;
184
185
bg->pdev = dev;
186
spin_lock_init(&bg->lock);
187
188
err = pci_enable_device(dev);
189
if (err) {
190
printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
191
goto err_freebg;
192
}
193
if (!request_mem_region(pci_resource_start(dev, 0),
194
pci_resource_len(dev, 0),
195
"bt8xxgpio")) {
196
printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
197
(unsigned long long)pci_resource_start(dev, 0));
198
err = -EBUSY;
199
goto err_disable;
200
}
201
pci_set_master(dev);
202
pci_set_drvdata(dev, bg);
203
204
bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
205
if (!bg->mmio) {
206
printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
207
err = -EIO;
208
goto err_release_mem;
209
}
210
211
/* Disable interrupts */
212
bgwrite(0, BT848_INT_MASK);
213
214
/* gpio init */
215
bgwrite(0, BT848_GPIO_DMA_CTL);
216
bgwrite(0, BT848_GPIO_REG_INP);
217
bgwrite(0, BT848_GPIO_OUT_EN);
218
219
bt8xxgpio_gpio_setup(bg);
220
err = gpiochip_add(&bg->gpio);
221
if (err) {
222
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
223
goto err_release_mem;
224
}
225
226
printk(KERN_INFO "bt8xxgpio: Abusing BT8xx card for GPIOs %d to %d\n",
227
bg->gpio.base, bg->gpio.base + BT8XXGPIO_NR_GPIOS - 1);
228
229
return 0;
230
231
err_release_mem:
232
release_mem_region(pci_resource_start(dev, 0),
233
pci_resource_len(dev, 0));
234
pci_set_drvdata(dev, NULL);
235
err_disable:
236
pci_disable_device(dev);
237
err_freebg:
238
kfree(bg);
239
240
return err;
241
}
242
243
static void bt8xxgpio_remove(struct pci_dev *pdev)
244
{
245
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
246
247
gpiochip_remove(&bg->gpio);
248
249
bgwrite(0, BT848_INT_MASK);
250
bgwrite(~0x0, BT848_INT_STAT);
251
bgwrite(0x0, BT848_GPIO_OUT_EN);
252
253
iounmap(bg->mmio);
254
release_mem_region(pci_resource_start(pdev, 0),
255
pci_resource_len(pdev, 0));
256
pci_disable_device(pdev);
257
258
pci_set_drvdata(pdev, NULL);
259
kfree(bg);
260
}
261
262
#ifdef CONFIG_PM
263
static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
264
{
265
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
266
unsigned long flags;
267
268
spin_lock_irqsave(&bg->lock, flags);
269
270
bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
271
bg->saved_data = bgread(BT848_GPIO_DATA);
272
273
bgwrite(0, BT848_INT_MASK);
274
bgwrite(~0x0, BT848_INT_STAT);
275
bgwrite(0x0, BT848_GPIO_OUT_EN);
276
277
spin_unlock_irqrestore(&bg->lock, flags);
278
279
pci_save_state(pdev);
280
pci_disable_device(pdev);
281
pci_set_power_state(pdev, pci_choose_state(pdev, state));
282
283
return 0;
284
}
285
286
static int bt8xxgpio_resume(struct pci_dev *pdev)
287
{
288
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
289
unsigned long flags;
290
int err;
291
292
pci_set_power_state(pdev, 0);
293
err = pci_enable_device(pdev);
294
if (err)
295
return err;
296
pci_restore_state(pdev);
297
298
spin_lock_irqsave(&bg->lock, flags);
299
300
bgwrite(0, BT848_INT_MASK);
301
bgwrite(0, BT848_GPIO_DMA_CTL);
302
bgwrite(0, BT848_GPIO_REG_INP);
303
bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
304
bgwrite(bg->saved_data & bg->saved_outen,
305
BT848_GPIO_DATA);
306
307
spin_unlock_irqrestore(&bg->lock, flags);
308
309
return 0;
310
}
311
#else
312
#define bt8xxgpio_suspend NULL
313
#define bt8xxgpio_resume NULL
314
#endif /* CONFIG_PM */
315
316
static struct pci_device_id bt8xxgpio_pci_tbl[] = {
317
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
318
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
319
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
320
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
321
{ 0, },
322
};
323
MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
324
325
static struct pci_driver bt8xxgpio_pci_driver = {
326
.name = "bt8xxgpio",
327
.id_table = bt8xxgpio_pci_tbl,
328
.probe = bt8xxgpio_probe,
329
.remove = bt8xxgpio_remove,
330
.suspend = bt8xxgpio_suspend,
331
.resume = bt8xxgpio_resume,
332
};
333
334
static int __init bt8xxgpio_init(void)
335
{
336
return pci_register_driver(&bt8xxgpio_pci_driver);
337
}
338
module_init(bt8xxgpio_init)
339
340
static void __exit bt8xxgpio_exit(void)
341
{
342
pci_unregister_driver(&bt8xxgpio_pci_driver);
343
}
344
module_exit(bt8xxgpio_exit)
345
346
MODULE_LICENSE("GPL");
347
MODULE_AUTHOR("Michael Buesch");
348
MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");
349
350