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 | |
47 | struct 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 | |
64 | static int modparam_gpiobase = -1/* dynamic */; |
65 | module_param_named(gpiobase, modparam_gpiobase, int, 0444); |
66 | MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default." ); |
67 | |
68 | |
69 | static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) |
70 | { |
71 | struct bt8xxgpio *bg = gpiochip_get_data(gc: 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(lock: &bg->lock, flags); |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr) |
91 | { |
92 | struct bt8xxgpio *bg = gpiochip_get_data(gc: 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(lock: &bg->lock, flags); |
99 | |
100 | return !!(val & (1 << nr)); |
101 | } |
102 | |
103 | static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio, |
104 | unsigned nr, int val) |
105 | { |
106 | struct bt8xxgpio *bg = gpiochip_get_data(gc: 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(lock: &bg->lock, flags); |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | static void bt8xxgpio_gpio_set(struct gpio_chip *gpio, |
129 | unsigned nr, int val) |
130 | { |
131 | struct bt8xxgpio *bg = gpiochip_get_data(gc: 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(lock: &bg->lock, flags); |
145 | } |
146 | |
147 | static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg) |
148 | { |
149 | struct gpio_chip *c = &bg->gpio; |
150 | |
151 | c->label = dev_name(dev: &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 | |
163 | static 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->dev, size: 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(pdev: dev, data: bg); |
191 | |
192 | bg->mmio = devm_ioremap(dev: &dev->dev, pci_resource_start(dev, 0), size: 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 | |
216 | err_disable: |
217 | pci_disable_device(dev); |
218 | |
219 | return err; |
220 | } |
221 | |
222 | static void bt8xxgpio_remove(struct pci_dev *pdev) |
223 | { |
224 | struct bt8xxgpio *bg = pci_get_drvdata(pdev); |
225 | |
226 | gpiochip_remove(gc: &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(dev: pdev); |
233 | } |
234 | |
235 | #ifdef CONFIG_PM |
236 | static 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(lock: &bg->lock, flags); |
251 | |
252 | pci_save_state(dev: pdev); |
253 | pci_disable_device(dev: pdev); |
254 | pci_set_power_state(dev: pdev, state: pci_choose_state(dev: pdev, state)); |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static 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(dev: pdev, PCI_D0); |
266 | err = pci_enable_device(dev: pdev); |
267 | if (err) |
268 | return err; |
269 | pci_restore_state(dev: 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(lock: &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 | |
289 | static 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 | }; |
296 | MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl); |
297 | |
298 | static 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 | |
307 | module_pci_driver(bt8xxgpio_pci_driver); |
308 | |
309 | MODULE_LICENSE("GPL" ); |
310 | MODULE_AUTHOR("Michael Buesch" ); |
311 | MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card" ); |
312 | |