Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3
4 bt8xx GPIO abuser
5
6 Copyright (C) 2008 Michael Buesch <m@bues.ch>
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
48struct 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
63static int modparam_gpiobase = -1/* dynamic */;
64module_param_named(gpiobase, modparam_gpiobase, int, 0444);
65MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
66
67
68static 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
86static 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
98static 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
120static 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
137static 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
153static 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
206err_disable:
207 pci_disable_device(dev);
208
209 return err;
210}
211
212static 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
226static 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
243static 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
260static DEFINE_SIMPLE_DEV_PM_OPS(bt8xxgpio_pm_ops, bt8xxgpio_suspend, bt8xxgpio_resume);
261
262static 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};
269MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
270
271static 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
279module_pci_driver(bt8xxgpio_pci_driver);
280
281MODULE_LICENSE("GPL");
282MODULE_AUTHOR("Michael Buesch");
283MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");