File Index
Files and directories
Sign in
FILE

gpio-bt8xx.c

File preview with syntax highlighting.

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