Loading...
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/module.h>
35#include <linux/pci.h>
36#include <linux/spinlock.h>
37#include <linux/gpio/driver.h>
38#include <linux/slab.h>
39
40/* Steal the hardware definitions from the bttv driver. */
41#include "../media/pci/bt8xx/bt848.h"
42
43
44#define BT8XXGPIO_NR_GPIOS 24 /* We have 24 GPIO pins */
45
46
47struct bt8xxgpio {
48 spinlock_t lock;
49
50 void __iomem *mmio;
51 struct pci_dev *pdev;
52 struct gpio_chip gpio;
53
54#ifdef CONFIG_PM
55 u32 saved_outen;
56 u32 saved_data;
57#endif
58};
59
60#define bgwrite(dat, adr) writel((dat), bg->mmio+(adr))
61#define bgread(adr) readl(bg->mmio+(adr))
62
63
64static int modparam_gpiobase = -1/* dynamic */;
65module_param_named(gpiobase, modparam_gpiobase, int, 0444);
66MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
67
68
69static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
70{
71 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
72 unsigned long flags;
73 u32 outen, data;
74
75 spin_lock_irqsave(&bg->lock, flags);
76
77 data = bgread(BT848_GPIO_DATA);
78 data &= ~(1 << nr);
79 bgwrite(data, BT848_GPIO_DATA);
80
81 outen = bgread(BT848_GPIO_OUT_EN);
82 outen &= ~(1 << nr);
83 bgwrite(outen, BT848_GPIO_OUT_EN);
84
85 spin_unlock_irqrestore(&bg->lock, flags);
86
87 return 0;
88}
89
90static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
91{
92 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
93 unsigned long flags;
94 u32 val;
95
96 spin_lock_irqsave(&bg->lock, flags);
97 val = bgread(BT848_GPIO_DATA);
98 spin_unlock_irqrestore(&bg->lock, flags);
99
100 return !!(val & (1 << nr));
101}
102
103static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
104 unsigned nr, int val)
105{
106 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
107 unsigned long flags;
108 u32 outen, data;
109
110 spin_lock_irqsave(&bg->lock, flags);
111
112 outen = bgread(BT848_GPIO_OUT_EN);
113 outen |= (1 << nr);
114 bgwrite(outen, BT848_GPIO_OUT_EN);
115
116 data = bgread(BT848_GPIO_DATA);
117 if (val)
118 data |= (1 << nr);
119 else
120 data &= ~(1 << nr);
121 bgwrite(data, BT848_GPIO_DATA);
122
123 spin_unlock_irqrestore(&bg->lock, flags);
124
125 return 0;
126}
127
128static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
129 unsigned nr, int val)
130{
131 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
132 unsigned long flags;
133 u32 data;
134
135 spin_lock_irqsave(&bg->lock, flags);
136
137 data = bgread(BT848_GPIO_DATA);
138 if (val)
139 data |= (1 << nr);
140 else
141 data &= ~(1 << nr);
142 bgwrite(data, BT848_GPIO_DATA);
143
144 spin_unlock_irqrestore(&bg->lock, flags);
145}
146
147static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
148{
149 struct gpio_chip *c = &bg->gpio;
150
151 c->label = dev_name(&bg->pdev->dev);
152 c->owner = THIS_MODULE;
153 c->direction_input = bt8xxgpio_gpio_direction_input;
154 c->get = bt8xxgpio_gpio_get;
155 c->direction_output = bt8xxgpio_gpio_direction_output;
156 c->set = bt8xxgpio_gpio_set;
157 c->dbg_show = NULL;
158 c->base = modparam_gpiobase;
159 c->ngpio = BT8XXGPIO_NR_GPIOS;
160 c->can_sleep = false;
161}
162
163static int bt8xxgpio_probe(struct pci_dev *dev,
164 const struct pci_device_id *pci_id)
165{
166 struct bt8xxgpio *bg;
167 int err;
168
169 bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
170 if (!bg)
171 return -ENOMEM;
172
173 bg->pdev = dev;
174 spin_lock_init(&bg->lock);
175
176 err = pci_enable_device(dev);
177 if (err) {
178 dev_err(&dev->dev, "can't enable device.\n");
179 return err;
180 }
181 if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
182 pci_resource_len(dev, 0),
183 "bt8xxgpio")) {
184 dev_warn(&dev->dev, "can't request iomem (0x%llx).\n",
185 (unsigned long long)pci_resource_start(dev, 0));
186 err = -EBUSY;
187 goto err_disable;
188 }
189 pci_set_master(dev);
190 pci_set_drvdata(dev, bg);
191
192 bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
193 if (!bg->mmio) {
194 dev_err(&dev->dev, "ioremap() failed\n");
195 err = -EIO;
196 goto err_disable;
197 }
198
199 /* Disable interrupts */
200 bgwrite(0, BT848_INT_MASK);
201
202 /* gpio init */
203 bgwrite(0, BT848_GPIO_DMA_CTL);
204 bgwrite(0, BT848_GPIO_REG_INP);
205 bgwrite(0, BT848_GPIO_OUT_EN);
206
207 bt8xxgpio_gpio_setup(bg);
208 err = gpiochip_add_data(&bg->gpio, bg);
209 if (err) {
210 dev_err(&dev->dev, "failed to register GPIOs\n");
211 goto err_disable;
212 }
213
214 return 0;
215
216err_disable:
217 pci_disable_device(dev);
218
219 return err;
220}
221
222static void bt8xxgpio_remove(struct pci_dev *pdev)
223{
224 struct bt8xxgpio *bg = pci_get_drvdata(pdev);
225
226 gpiochip_remove(&bg->gpio);
227
228 bgwrite(0, BT848_INT_MASK);
229 bgwrite(~0x0, BT848_INT_STAT);
230 bgwrite(0x0, BT848_GPIO_OUT_EN);
231
232 pci_disable_device(pdev);
233}
234
235#ifdef CONFIG_PM
236static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
237{
238 struct bt8xxgpio *bg = pci_get_drvdata(pdev);
239 unsigned long flags;
240
241 spin_lock_irqsave(&bg->lock, flags);
242
243 bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
244 bg->saved_data = bgread(BT848_GPIO_DATA);
245
246 bgwrite(0, BT848_INT_MASK);
247 bgwrite(~0x0, BT848_INT_STAT);
248 bgwrite(0x0, BT848_GPIO_OUT_EN);
249
250 spin_unlock_irqrestore(&bg->lock, flags);
251
252 pci_save_state(pdev);
253 pci_disable_device(pdev);
254 pci_set_power_state(pdev, pci_choose_state(pdev, state));
255
256 return 0;
257}
258
259static int bt8xxgpio_resume(struct pci_dev *pdev)
260{
261 struct bt8xxgpio *bg = pci_get_drvdata(pdev);
262 unsigned long flags;
263 int err;
264
265 pci_set_power_state(pdev, PCI_D0);
266 err = pci_enable_device(pdev);
267 if (err)
268 return err;
269 pci_restore_state(pdev);
270
271 spin_lock_irqsave(&bg->lock, flags);
272
273 bgwrite(0, BT848_INT_MASK);
274 bgwrite(0, BT848_GPIO_DMA_CTL);
275 bgwrite(0, BT848_GPIO_REG_INP);
276 bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
277 bgwrite(bg->saved_data & bg->saved_outen,
278 BT848_GPIO_DATA);
279
280 spin_unlock_irqrestore(&bg->lock, flags);
281
282 return 0;
283}
284#else
285#define bt8xxgpio_suspend NULL
286#define bt8xxgpio_resume NULL
287#endif /* CONFIG_PM */
288
289static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
290 { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
291 { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
292 { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
293 { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
294 { 0, },
295};
296MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
297
298static struct pci_driver bt8xxgpio_pci_driver = {
299 .name = "bt8xxgpio",
300 .id_table = bt8xxgpio_pci_tbl,
301 .probe = bt8xxgpio_probe,
302 .remove = bt8xxgpio_remove,
303 .suspend = bt8xxgpio_suspend,
304 .resume = bt8xxgpio_resume,
305};
306
307module_pci_driver(bt8xxgpio_pci_driver);
308
309MODULE_LICENSE("GPL");
310MODULE_AUTHOR("Michael Buesch");
311MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");
1/*
2
3 bt8xx GPIO abuser
4
5 Copyright (C) 2008 Michael Buesch <m@bues.ch>
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
59struct 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
76static int modparam_gpiobase = -1/* dynamic */;
77module_param_named(gpiobase, modparam_gpiobase, int, 0444);
78MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
79
80
81static 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
102static 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
115static 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
140static 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
159static 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
175static 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
231err_release_mem:
232 release_mem_region(pci_resource_start(dev, 0),
233 pci_resource_len(dev, 0));
234 pci_set_drvdata(dev, NULL);
235err_disable:
236 pci_disable_device(dev);
237err_freebg:
238 kfree(bg);
239
240 return err;
241}
242
243static 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
263static 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
286static 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
316static 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};
323MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
324
325static 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
334static int __init bt8xxgpio_init(void)
335{
336 return pci_register_driver(&bt8xxgpio_pci_driver);
337}
338module_init(bt8xxgpio_init)
339
340static void __exit bt8xxgpio_exit(void)
341{
342 pci_unregister_driver(&bt8xxgpio_pci_driver);
343}
344module_exit(bt8xxgpio_exit)
345
346MODULE_LICENSE("GPL");
347MODULE_AUTHOR("Michael Buesch");
348MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");