Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpio/gpio-bt8xx.c
51380 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
4
bt8xx GPIO abuser
5
6
Copyright (C) 2008 Michael Buesch <[email protected]>
7
8
Please do _only_ contact the people listed _above_ with issues related to this driver.
9
All the other people listed below are not related to this driver. Their names
10
are only here, because this driver is derived from the bt848 driver.
11
12
13
Derived from the bt848 driver:
14
15
Copyright (C) 1996,97,98 Ralph Metzler
16
& Marcus Metzler
17
(c) 1999-2002 Gerd Knorr
18
19
some v4l2 code lines are taken from Justin's bttv2 driver which is
20
(c) 2000 Justin Schoeman
21
22
V4L1 removal from:
23
(c) 2005-2006 Nickolay V. Shmyrev
24
25
Fixes to be fully V4L2 compliant by
26
(c) 2006 Mauro Carvalho Chehab
27
28
Cropping and overscan support
29
Copyright (C) 2005, 2006 Michael H. Schimek
30
Sponsored by OPQ Systems AB
31
32
*/
33
34
#include <linux/cleanup.h>
35
#include <linux/module.h>
36
#include <linux/pci.h>
37
#include <linux/spinlock.h>
38
#include <linux/gpio/driver.h>
39
#include <linux/slab.h>
40
41
/* Steal the hardware definitions from the bttv driver. */
42
#include "../media/pci/bt8xx/bt848.h"
43
44
45
#define BT8XXGPIO_NR_GPIOS 24 /* We have 24 GPIO pins */
46
47
48
struct bt8xxgpio {
49
spinlock_t lock;
50
51
void __iomem *mmio;
52
struct pci_dev *pdev;
53
struct gpio_chip gpio;
54
55
u32 saved_outen;
56
u32 saved_data;
57
};
58
59
#define bgwrite(dat, adr) writel((dat), bg->mmio+(adr))
60
#define bgread(adr) readl(bg->mmio+(adr))
61
62
63
static int modparam_gpiobase = -1/* dynamic */;
64
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
65
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
66
67
68
static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
69
{
70
struct bt8xxgpio *bg = gpiochip_get_data(gpio);
71
u32 outen, data;
72
73
guard(spinlock_irqsave)(&bg->lock);
74
75
data = bgread(BT848_GPIO_DATA);
76
data &= ~(1 << nr);
77
bgwrite(data, BT848_GPIO_DATA);
78
79
outen = bgread(BT848_GPIO_OUT_EN);
80
outen &= ~(1 << nr);
81
bgwrite(outen, BT848_GPIO_OUT_EN);
82
83
return 0;
84
}
85
86
static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
87
{
88
struct bt8xxgpio *bg = gpiochip_get_data(gpio);
89
u32 val;
90
91
guard(spinlock_irqsave)(&bg->lock);
92
93
val = bgread(BT848_GPIO_DATA);
94
95
return !!(val & (1 << nr));
96
}
97
98
static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
99
unsigned nr, int val)
100
{
101
struct bt8xxgpio *bg = gpiochip_get_data(gpio);
102
u32 outen, data;
103
104
guard(spinlock_irqsave)(&bg->lock);
105
106
outen = bgread(BT848_GPIO_OUT_EN);
107
outen |= (1 << nr);
108
bgwrite(outen, BT848_GPIO_OUT_EN);
109
110
data = bgread(BT848_GPIO_DATA);
111
if (val)
112
data |= (1 << nr);
113
else
114
data &= ~(1 << nr);
115
bgwrite(data, BT848_GPIO_DATA);
116
117
return 0;
118
}
119
120
static int bt8xxgpio_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
121
{
122
struct bt8xxgpio *bg = gpiochip_get_data(gpio);
123
u32 data;
124
125
guard(spinlock_irqsave)(&bg->lock);
126
127
data = bgread(BT848_GPIO_DATA);
128
if (val)
129
data |= (1 << nr);
130
else
131
data &= ~(1 << nr);
132
bgwrite(data, BT848_GPIO_DATA);
133
134
return 0;
135
}
136
137
static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
138
{
139
struct gpio_chip *c = &bg->gpio;
140
141
c->label = dev_name(&bg->pdev->dev);
142
c->owner = THIS_MODULE;
143
c->direction_input = bt8xxgpio_gpio_direction_input;
144
c->get = bt8xxgpio_gpio_get;
145
c->direction_output = bt8xxgpio_gpio_direction_output;
146
c->set = bt8xxgpio_gpio_set;
147
c->dbg_show = NULL;
148
c->base = modparam_gpiobase;
149
c->ngpio = BT8XXGPIO_NR_GPIOS;
150
c->can_sleep = false;
151
}
152
153
static int bt8xxgpio_probe(struct pci_dev *dev,
154
const struct pci_device_id *pci_id)
155
{
156
struct bt8xxgpio *bg;
157
int err;
158
159
bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
160
if (!bg)
161
return -ENOMEM;
162
163
bg->pdev = dev;
164
spin_lock_init(&bg->lock);
165
166
err = pci_enable_device(dev);
167
if (err) {
168
dev_err(&dev->dev, "can't enable device.\n");
169
return err;
170
}
171
if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
172
pci_resource_len(dev, 0),
173
"bt8xxgpio")) {
174
dev_warn(&dev->dev, "can't request iomem (0x%llx).\n",
175
(unsigned long long)pci_resource_start(dev, 0));
176
err = -EBUSY;
177
goto err_disable;
178
}
179
pci_set_master(dev);
180
pci_set_drvdata(dev, bg);
181
182
bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
183
if (!bg->mmio) {
184
dev_err(&dev->dev, "ioremap() failed\n");
185
err = -EIO;
186
goto err_disable;
187
}
188
189
/* Disable interrupts */
190
bgwrite(0, BT848_INT_MASK);
191
192
/* gpio init */
193
bgwrite(0, BT848_GPIO_DMA_CTL);
194
bgwrite(0, BT848_GPIO_REG_INP);
195
bgwrite(0, BT848_GPIO_OUT_EN);
196
197
bt8xxgpio_gpio_setup(bg);
198
err = gpiochip_add_data(&bg->gpio, bg);
199
if (err) {
200
dev_err(&dev->dev, "failed to register GPIOs\n");
201
goto err_disable;
202
}
203
204
return 0;
205
206
err_disable:
207
pci_disable_device(dev);
208
209
return err;
210
}
211
212
static void bt8xxgpio_remove(struct pci_dev *pdev)
213
{
214
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
215
216
gpiochip_remove(&bg->gpio);
217
218
bgwrite(0, BT848_INT_MASK);
219
bgwrite(~0x0, BT848_INT_STAT);
220
bgwrite(0x0, BT848_GPIO_OUT_EN);
221
222
pci_disable_device(pdev);
223
}
224
225
226
static int bt8xxgpio_suspend(struct device *dev)
227
{
228
struct pci_dev *pdev = to_pci_dev(dev);
229
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
230
231
scoped_guard(spinlock_irqsave, &bg->lock) {
232
bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
233
bg->saved_data = bgread(BT848_GPIO_DATA);
234
235
bgwrite(0, BT848_INT_MASK);
236
bgwrite(~0x0, BT848_INT_STAT);
237
bgwrite(0x0, BT848_GPIO_OUT_EN);
238
}
239
240
return 0;
241
}
242
243
static int bt8xxgpio_resume(struct device *dev)
244
{
245
struct pci_dev *pdev = to_pci_dev(dev);
246
struct bt8xxgpio *bg = pci_get_drvdata(pdev);
247
248
guard(spinlock_irqsave)(&bg->lock);
249
250
bgwrite(0, BT848_INT_MASK);
251
bgwrite(0, BT848_GPIO_DMA_CTL);
252
bgwrite(0, BT848_GPIO_REG_INP);
253
bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
254
bgwrite(bg->saved_data & bg->saved_outen,
255
BT848_GPIO_DATA);
256
257
return 0;
258
}
259
260
static DEFINE_SIMPLE_DEV_PM_OPS(bt8xxgpio_pm_ops, bt8xxgpio_suspend, bt8xxgpio_resume);
261
262
static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
263
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
264
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
265
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
266
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
267
{ 0, },
268
};
269
MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
270
271
static struct pci_driver bt8xxgpio_pci_driver = {
272
.name = "bt8xxgpio",
273
.id_table = bt8xxgpio_pci_tbl,
274
.probe = bt8xxgpio_probe,
275
.remove = bt8xxgpio_remove,
276
.driver.pm = &bt8xxgpio_pm_ops,
277
};
278
279
module_pci_driver(bt8xxgpio_pci_driver);
280
281
MODULE_LICENSE("GPL");
282
MODULE_AUTHOR("Michael Buesch");
283
MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");
284
285