Root/
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 | |
59 | struct 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 | |
76 | static int modparam_gpiobase = -1/* dynamic */; |
77 | module_param_named(gpiobase, modparam_gpiobase, int, 0444); |
78 | MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default."); |
79 | |
80 | |
81 | static 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 | |
102 | static 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 | |
115 | static 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 | |
140 | static 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 | |
159 | static 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 | |
175 | static 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 | return 0; |
227 | |
228 | err_release_mem: |
229 | release_mem_region(pci_resource_start(dev, 0), |
230 | pci_resource_len(dev, 0)); |
231 | pci_set_drvdata(dev, NULL); |
232 | err_disable: |
233 | pci_disable_device(dev); |
234 | err_freebg: |
235 | kfree(bg); |
236 | |
237 | return err; |
238 | } |
239 | |
240 | static void bt8xxgpio_remove(struct pci_dev *pdev) |
241 | { |
242 | struct bt8xxgpio *bg = pci_get_drvdata(pdev); |
243 | |
244 | gpiochip_remove(&bg->gpio); |
245 | |
246 | bgwrite(0, BT848_INT_MASK); |
247 | bgwrite(~0x0, BT848_INT_STAT); |
248 | bgwrite(0x0, BT848_GPIO_OUT_EN); |
249 | |
250 | iounmap(bg->mmio); |
251 | release_mem_region(pci_resource_start(pdev, 0), |
252 | pci_resource_len(pdev, 0)); |
253 | pci_disable_device(pdev); |
254 | |
255 | pci_set_drvdata(pdev, NULL); |
256 | kfree(bg); |
257 | } |
258 | |
259 | #ifdef CONFIG_PM |
260 | static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state) |
261 | { |
262 | struct bt8xxgpio *bg = pci_get_drvdata(pdev); |
263 | unsigned long flags; |
264 | |
265 | spin_lock_irqsave(&bg->lock, flags); |
266 | |
267 | bg->saved_outen = bgread(BT848_GPIO_OUT_EN); |
268 | bg->saved_data = bgread(BT848_GPIO_DATA); |
269 | |
270 | bgwrite(0, BT848_INT_MASK); |
271 | bgwrite(~0x0, BT848_INT_STAT); |
272 | bgwrite(0x0, BT848_GPIO_OUT_EN); |
273 | |
274 | spin_unlock_irqrestore(&bg->lock, flags); |
275 | |
276 | pci_save_state(pdev); |
277 | pci_disable_device(pdev); |
278 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); |
279 | |
280 | return 0; |
281 | } |
282 | |
283 | static int bt8xxgpio_resume(struct pci_dev *pdev) |
284 | { |
285 | struct bt8xxgpio *bg = pci_get_drvdata(pdev); |
286 | unsigned long flags; |
287 | int err; |
288 | |
289 | pci_set_power_state(pdev, 0); |
290 | err = pci_enable_device(pdev); |
291 | if (err) |
292 | return err; |
293 | pci_restore_state(pdev); |
294 | |
295 | spin_lock_irqsave(&bg->lock, flags); |
296 | |
297 | bgwrite(0, BT848_INT_MASK); |
298 | bgwrite(0, BT848_GPIO_DMA_CTL); |
299 | bgwrite(0, BT848_GPIO_REG_INP); |
300 | bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN); |
301 | bgwrite(bg->saved_data & bg->saved_outen, |
302 | BT848_GPIO_DATA); |
303 | |
304 | spin_unlock_irqrestore(&bg->lock, flags); |
305 | |
306 | return 0; |
307 | } |
308 | #else |
309 | #define bt8xxgpio_suspend NULL |
310 | #define bt8xxgpio_resume NULL |
311 | #endif /* CONFIG_PM */ |
312 | |
313 | static struct pci_device_id bt8xxgpio_pci_tbl[] = { |
314 | { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, |
315 | { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, |
316 | { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, |
317 | { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) }, |
318 | { 0, }, |
319 | }; |
320 | MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl); |
321 | |
322 | static struct pci_driver bt8xxgpio_pci_driver = { |
323 | .name = "bt8xxgpio", |
324 | .id_table = bt8xxgpio_pci_tbl, |
325 | .probe = bt8xxgpio_probe, |
326 | .remove = bt8xxgpio_remove, |
327 | .suspend = bt8xxgpio_suspend, |
328 | .resume = bt8xxgpio_resume, |
329 | }; |
330 | |
331 | module_pci_driver(bt8xxgpio_pci_driver); |
332 | |
333 | MODULE_LICENSE("GPL"); |
334 | MODULE_AUTHOR("Michael Buesch"); |
335 | MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card"); |
336 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9