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