Linux Audio

Check our new training course

Loading...
v6.2
  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");
v3.1
 
  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");