blob: 7920cf2567988d1be49696a1153dfae036e3ece4 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Michael Bueschff1d5c22008-07-25 01:46:10 -07002/*
3
4 bt8xx GPIO abuser
5
Michael Büscheb032b92011-07-04 20:50:05 +02006 Copyright (C) 2008 Michael Buesch <m@bues.ch>
Michael Bueschff1d5c22008-07-25 01:46:10 -07007
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
Michael Bueschff1d5c22008-07-25 01:46:10 -070032*/
33
34#include <linux/module.h>
35#include <linux/pci.h>
36#include <linux/spinlock.h>
Linus Walleije88a2ae2018-01-13 22:56:52 +010037#include <linux/gpio/driver.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090038#include <linux/slab.h>
Michael Bueschff1d5c22008-07-25 01:46:10 -070039
40/* Steal the hardware definitions from the bttv driver. */
Axel Lin52d32252012-08-21 17:37:13 +080041#include "../media/pci/bt8xx/bt848.h"
Michael Bueschff1d5c22008-07-25 01:46:10 -070042
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{
Linus Walleije51b5522015-12-04 15:44:16 +010071 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
Michael Bueschff1d5c22008-07-25 01:46:10 -070072 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{
Linus Walleije51b5522015-12-04 15:44:16 +010092 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
Michael Bueschff1d5c22008-07-25 01:46:10 -070093 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{
Linus Walleije51b5522015-12-04 15:44:16 +0100106 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700107 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{
Linus Walleije51b5522015-12-04 15:44:16 +0100131 struct bt8xxgpio *bg = gpiochip_get_data(gpio);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700132 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
Kay Sievers3e274bd2009-03-24 16:38:23 -0700151 c->label = dev_name(&bg->pdev->dev);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700152 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;
Linus Walleij9fb1f392013-12-04 14:42:46 +0100160 c->can_sleep = false;
Michael Bueschff1d5c22008-07-25 01:46:10 -0700161}
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
abdoulaye berthea435e182014-05-12 17:40:42 +0200169 bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700170 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) {
Enrico Weigelt, metux IT consult3bf1d262020-12-03 19:24:21 +0100178 dev_err(&dev->dev, "can't enable device.\n");
abdoulaye berthea435e182014-05-12 17:40:42 +0200179 return err;
Michael Bueschff1d5c22008-07-25 01:46:10 -0700180 }
abdoulaye berthea435e182014-05-12 17:40:42 +0200181 if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
Michael Bueschff1d5c22008-07-25 01:46:10 -0700182 pci_resource_len(dev, 0),
183 "bt8xxgpio")) {
Enrico Weigelt, metux IT consult3bf1d262020-12-03 19:24:21 +0100184 dev_warn(&dev->dev, "can't request iomem (0x%llx).\n",
Michael Bueschff1d5c22008-07-25 01:46:10 -0700185 (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
abdoulaye berthea435e182014-05-12 17:40:42 +0200192 bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700193 if (!bg->mmio) {
Enrico Weigelt, metux IT consult3bf1d262020-12-03 19:24:21 +0100194 dev_err(&dev->dev, "ioremap() failed\n");
Michael Bueschff1d5c22008-07-25 01:46:10 -0700195 err = -EIO;
abdoulaye berthea435e182014-05-12 17:40:42 +0200196 goto err_disable;
Michael Bueschff1d5c22008-07-25 01:46:10 -0700197 }
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);
Linus Walleije51b5522015-12-04 15:44:16 +0100208 err = gpiochip_add_data(&bg->gpio, bg);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700209 if (err) {
Enrico Weigelt, metux IT consult3bf1d262020-12-03 19:24:21 +0100210 dev_err(&dev->dev, "failed to register GPIOs\n");
abdoulaye berthea435e182014-05-12 17:40:42 +0200211 goto err_disable;
Michael Bueschff1d5c22008-07-25 01:46:10 -0700212 }
213
Michael Bueschff1d5c22008-07-25 01:46:10 -0700214 return 0;
215
Michael Bueschff1d5c22008-07-25 01:46:10 -0700216err_disable:
217 pci_disable_device(dev);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700218
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
Michael Bueschff1d5c22008-07-25 01:46:10 -0700232 pci_disable_device(pdev);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700233}
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
Yijing Wang038f0ba2013-06-27 20:58:55 +0800265 pci_set_power_state(pdev, PCI_D0);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700266 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
Jingoo Han14f4a882013-12-03 08:08:45 +0900289static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
Michael Bueschff1d5c22008-07-25 01:46:10 -0700290 { 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
Axel Lin93baa652012-04-06 20:13:30 +0800307module_pci_driver(bt8xxgpio_pci_driver);
Michael Bueschff1d5c22008-07-25 01:46:10 -0700308
309MODULE_LICENSE("GPL");
310MODULE_AUTHOR("Michael Buesch");
311MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");