Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1#include <linux/kernel.h>
  2#include <linux/init.h>
  3#include <linux/gpio/driver.h>
  4#include <linux/of_gpio.h>
  5#include <linux/io.h>
  6#include <linux/interrupt.h>
  7#include <linux/platform_device.h>
  8
  9#define ETRAX_FS_rw_pa_dout	0
 10#define ETRAX_FS_r_pa_din	4
 11#define ETRAX_FS_rw_pa_oe	8
 12#define ETRAX_FS_rw_intr_cfg	12
 13#define ETRAX_FS_rw_intr_mask	16
 14#define ETRAX_FS_rw_ack_intr	20
 15#define ETRAX_FS_r_intr		24
 16#define ETRAX_FS_r_masked_intr	28
 17#define ETRAX_FS_rw_pb_dout	32
 18#define ETRAX_FS_r_pb_din	36
 19#define ETRAX_FS_rw_pb_oe	40
 20#define ETRAX_FS_rw_pc_dout	48
 21#define ETRAX_FS_r_pc_din	52
 22#define ETRAX_FS_rw_pc_oe	56
 23#define ETRAX_FS_rw_pd_dout	64
 24#define ETRAX_FS_r_pd_din	68
 25#define ETRAX_FS_rw_pd_oe	72
 26#define ETRAX_FS_rw_pe_dout	80
 27#define ETRAX_FS_r_pe_din	84
 28#define ETRAX_FS_rw_pe_oe	88
 29
 30#define ARTPEC3_r_pa_din	0
 31#define ARTPEC3_rw_pa_dout	4
 32#define ARTPEC3_rw_pa_oe	8
 33#define ARTPEC3_r_pb_din	44
 34#define ARTPEC3_rw_pb_dout	48
 35#define ARTPEC3_rw_pb_oe	52
 36#define ARTPEC3_r_pc_din	88
 37#define ARTPEC3_rw_pc_dout	92
 38#define ARTPEC3_rw_pc_oe	96
 39#define ARTPEC3_r_pd_din	116
 40#define ARTPEC3_rw_intr_cfg	120
 41#define ARTPEC3_rw_intr_pins	124
 42#define ARTPEC3_rw_intr_mask	128
 43#define ARTPEC3_rw_ack_intr	132
 44#define ARTPEC3_r_masked_intr	140
 45
 46#define GIO_CFG_OFF		0
 47#define GIO_CFG_HI		1
 48#define GIO_CFG_LO		2
 49#define GIO_CFG_SET		3
 50#define GIO_CFG_POSEDGE		5
 51#define GIO_CFG_NEGEDGE		6
 52#define GIO_CFG_ANYEDGE		7
 53
 54struct etraxfs_gpio_info;
 55
 56struct etraxfs_gpio_block {
 57	spinlock_t lock;
 58	u32 mask;
 59	u32 cfg;
 60	u32 pins;
 61	unsigned int group[8];
 62
 63	void __iomem *regs;
 64	const struct etraxfs_gpio_info *info;
 65};
 66
 67struct etraxfs_gpio_chip {
 68	struct gpio_chip gc;
 69	struct etraxfs_gpio_block *block;
 70};
 71
 72struct etraxfs_gpio_port {
 73	const char *label;
 74	unsigned int oe;
 75	unsigned int dout;
 76	unsigned int din;
 77	unsigned int ngpio;
 78};
 79
 80struct etraxfs_gpio_info {
 81	unsigned int num_ports;
 82	const struct etraxfs_gpio_port *ports;
 83
 84	unsigned int rw_ack_intr;
 85	unsigned int rw_intr_mask;
 86	unsigned int rw_intr_cfg;
 87	unsigned int rw_intr_pins;
 88	unsigned int r_masked_intr;
 89};
 90
 91static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
 92	{
 93		.label	= "A",
 94		.ngpio	= 8,
 95		.oe	= ETRAX_FS_rw_pa_oe,
 96		.dout	= ETRAX_FS_rw_pa_dout,
 97		.din	= ETRAX_FS_r_pa_din,
 98	},
 99	{
100		.label	= "B",
101		.ngpio	= 18,
102		.oe	= ETRAX_FS_rw_pb_oe,
103		.dout	= ETRAX_FS_rw_pb_dout,
104		.din	= ETRAX_FS_r_pb_din,
105	},
106	{
107		.label	= "C",
108		.ngpio	= 18,
109		.oe	= ETRAX_FS_rw_pc_oe,
110		.dout	= ETRAX_FS_rw_pc_dout,
111		.din	= ETRAX_FS_r_pc_din,
112	},
113	{
114		.label	= "D",
115		.ngpio	= 18,
116		.oe	= ETRAX_FS_rw_pd_oe,
117		.dout	= ETRAX_FS_rw_pd_dout,
118		.din	= ETRAX_FS_r_pd_din,
119	},
120	{
121		.label	= "E",
122		.ngpio	= 18,
123		.oe	= ETRAX_FS_rw_pe_oe,
124		.dout	= ETRAX_FS_rw_pe_dout,
125		.din	= ETRAX_FS_r_pe_din,
126	},
127};
128
129static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
130	.num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
131	.ports = etraxfs_gpio_etraxfs_ports,
132	.rw_ack_intr	= ETRAX_FS_rw_ack_intr,
133	.rw_intr_mask	= ETRAX_FS_rw_intr_mask,
134	.rw_intr_cfg	= ETRAX_FS_rw_intr_cfg,
135	.r_masked_intr	= ETRAX_FS_r_masked_intr,
136};
137
138static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = {
139	{
140		.label	= "A",
141		.ngpio	= 32,
142		.oe	= ARTPEC3_rw_pa_oe,
143		.dout	= ARTPEC3_rw_pa_dout,
144		.din	= ARTPEC3_r_pa_din,
145	},
146	{
147		.label	= "B",
148		.ngpio	= 32,
149		.oe	= ARTPEC3_rw_pb_oe,
150		.dout	= ARTPEC3_rw_pb_dout,
151		.din	= ARTPEC3_r_pb_din,
152	},
153	{
154		.label	= "C",
155		.ngpio	= 16,
156		.oe	= ARTPEC3_rw_pc_oe,
157		.dout	= ARTPEC3_rw_pc_dout,
158		.din	= ARTPEC3_r_pc_din,
159	},
160	{
161		.label	= "D",
162		.ngpio	= 32,
163		.din	= ARTPEC3_r_pd_din,
164	},
165};
166
167static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
168	.num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports),
169	.ports = etraxfs_gpio_artpec3_ports,
170	.rw_ack_intr	= ARTPEC3_rw_ack_intr,
171	.rw_intr_mask	= ARTPEC3_rw_intr_mask,
172	.rw_intr_cfg	= ARTPEC3_rw_intr_cfg,
173	.r_masked_intr	= ARTPEC3_r_masked_intr,
174	.rw_intr_pins	= ARTPEC3_rw_intr_pins,
175};
176
177static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
178{
179	return gc->label[0] - 'A';
180}
181
182static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
183			       const struct of_phandle_args *gpiospec,
184			       u32 *flags)
185{
186	/*
187	 * Port numbers are A to E, and the properties are integers, so we
188	 * specify them as 0xA - 0xE.
189	 */
190	if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2])
191		return -EINVAL;
192
193	return of_gpio_simple_xlate(gc, gpiospec, flags);
194}
195
196static const struct of_device_id etraxfs_gpio_of_table[] = {
197	{
198		.compatible = "axis,etraxfs-gio",
199		.data = &etraxfs_gpio_etraxfs,
200	},
201	{
202		.compatible = "axis,artpec3-gio",
203		.data = &etraxfs_gpio_artpec3,
204	},
205	{},
206};
207
208static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio)
209{
210	return gpio % 8;
211}
212
213static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
214					      unsigned int gpio)
215{
216	return 4 * etraxfs_gpio_chip_to_port(&chip->gc) + gpio / 8;
217}
218
219static void etraxfs_gpio_irq_ack(struct irq_data *d)
220{
221	struct etraxfs_gpio_chip *chip =
222		gpiochip_get_data(irq_data_get_irq_chip_data(d));
223	struct etraxfs_gpio_block *block = chip->block;
224	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
225
226	writel(BIT(grpirq), block->regs + block->info->rw_ack_intr);
227}
228
229static void etraxfs_gpio_irq_mask(struct irq_data *d)
230{
231	struct etraxfs_gpio_chip *chip =
232		gpiochip_get_data(irq_data_get_irq_chip_data(d));
233	struct etraxfs_gpio_block *block = chip->block;
234	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
235
236	spin_lock(&block->lock);
237	block->mask &= ~BIT(grpirq);
238	writel(block->mask, block->regs + block->info->rw_intr_mask);
239	spin_unlock(&block->lock);
240}
241
242static void etraxfs_gpio_irq_unmask(struct irq_data *d)
243{
244	struct etraxfs_gpio_chip *chip =
245		gpiochip_get_data(irq_data_get_irq_chip_data(d));
246	struct etraxfs_gpio_block *block = chip->block;
247	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
248
249	spin_lock(&block->lock);
250	block->mask |= BIT(grpirq);
251	writel(block->mask, block->regs + block->info->rw_intr_mask);
252	spin_unlock(&block->lock);
253}
254
255static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
256{
257	struct etraxfs_gpio_chip *chip =
258		gpiochip_get_data(irq_data_get_irq_chip_data(d));
259	struct etraxfs_gpio_block *block = chip->block;
260	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
261	u32 cfg;
262
263	switch (type) {
264	case IRQ_TYPE_EDGE_RISING:
265		cfg = GIO_CFG_POSEDGE;
266		break;
267	case IRQ_TYPE_EDGE_FALLING:
268		cfg = GIO_CFG_NEGEDGE;
269		break;
270	case IRQ_TYPE_EDGE_BOTH:
271		cfg = GIO_CFG_ANYEDGE;
272		break;
273	case IRQ_TYPE_LEVEL_LOW:
274		cfg = GIO_CFG_LO;
275		break;
276	case IRQ_TYPE_LEVEL_HIGH:
277		cfg = GIO_CFG_HI;
278		break;
279	default:
280		return -EINVAL;
281	}
282
283	spin_lock(&block->lock);
284	block->cfg &= ~(0x7 << (grpirq * 3));
285	block->cfg |= (cfg << (grpirq * 3));
286	writel(block->cfg, block->regs + block->info->rw_intr_cfg);
287	spin_unlock(&block->lock);
288
289	return 0;
290}
291
292static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
293{
294	struct etraxfs_gpio_chip *chip =
295		gpiochip_get_data(irq_data_get_irq_chip_data(d));
296	struct etraxfs_gpio_block *block = chip->block;
297	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
298	int ret = -EBUSY;
299
300	spin_lock(&block->lock);
301	if (block->group[grpirq])
302		goto out;
303
304	ret = gpiochip_lock_as_irq(&chip->gc, d->hwirq);
305	if (ret)
306		goto out;
307
308	block->group[grpirq] = d->irq;
309	if (block->info->rw_intr_pins) {
310		unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq);
311
312		block->pins &= ~(0xf << (grpirq * 4));
313		block->pins |= (pin << (grpirq * 4));
314
315		writel(block->pins, block->regs + block->info->rw_intr_pins);
316	}
317
318out:
319	spin_unlock(&block->lock);
320	return ret;
321}
322
323static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
324{
325	struct etraxfs_gpio_chip *chip =
326		gpiochip_get_data(irq_data_get_irq_chip_data(d));
327	struct etraxfs_gpio_block *block = chip->block;
328	unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
329
330	spin_lock(&block->lock);
331	block->group[grpirq] = 0;
332	gpiochip_unlock_as_irq(&chip->gc, d->hwirq);
333	spin_unlock(&block->lock);
334}
335
336static struct irq_chip etraxfs_gpio_irq_chip = {
337	.name		= "gpio-etraxfs",
338	.irq_ack	= etraxfs_gpio_irq_ack,
339	.irq_mask	= etraxfs_gpio_irq_mask,
340	.irq_unmask	= etraxfs_gpio_irq_unmask,
341	.irq_set_type	= etraxfs_gpio_irq_set_type,
342	.irq_request_resources = etraxfs_gpio_irq_request_resources,
343	.irq_release_resources = etraxfs_gpio_irq_release_resources,
344};
345
346static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id)
347{
348	struct etraxfs_gpio_block *block = dev_id;
349	unsigned long intr = readl(block->regs + block->info->r_masked_intr);
350	int bit;
351
352	for_each_set_bit(bit, &intr, 8)
353		generic_handle_irq(block->group[bit]);
354
355	return IRQ_RETVAL(intr & 0xff);
356}
357
358static int etraxfs_gpio_probe(struct platform_device *pdev)
359{
360	struct device *dev = &pdev->dev;
361	const struct etraxfs_gpio_info *info;
362	const struct of_device_id *match;
363	struct etraxfs_gpio_block *block;
364	struct etraxfs_gpio_chip *chips;
365	struct resource *res, *irq;
366	bool allportsirq = false;
367	void __iomem *regs;
368	int ret;
369	int i;
370
371	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
372	regs = devm_ioremap_resource(dev, res);
373	if (IS_ERR(regs))
374		return PTR_ERR(regs);
375
376	match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
377	if (!match)
378		return -EINVAL;
379
380	info = match->data;
381
382	chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
383	if (!chips)
384		return -ENOMEM;
385
386	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
387	if (!irq)
388		return -EINVAL;
389
390	block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL);
391	if (!block)
392		return -ENOMEM;
393
394	spin_lock_init(&block->lock);
395
396	block->regs = regs;
397	block->info = info;
398
399	writel(0, block->regs + info->rw_intr_mask);
400	writel(0, block->regs + info->rw_intr_cfg);
401	if (info->rw_intr_pins) {
402		allportsirq = true;
403		writel(0, block->regs + info->rw_intr_pins);
404	}
405
406	ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt,
407			       IRQF_SHARED, dev_name(dev), block);
408	if (ret) {
409		dev_err(dev, "Unable to request irq %d\n", ret);
410		return ret;
411	}
412
413	for (i = 0; i < info->num_ports; i++) {
414		struct etraxfs_gpio_chip *chip = &chips[i];
415		struct gpio_chip *gc = &chip->gc;
416		const struct etraxfs_gpio_port *port = &info->ports[i];
417		unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET;
418		void __iomem *dat = regs + port->din;
419		void __iomem *set = regs + port->dout;
420		void __iomem *dirout = regs + port->oe;
421
422		chip->block = block;
423
424		if (dirout == set) {
425			dirout = set = NULL;
426			flags = BGPIOF_NO_OUTPUT;
427		}
428
429		ret = bgpio_init(gc, dev, 4,
430				 dat, set, NULL, dirout, NULL,
431				 flags);
432		if (ret) {
433			dev_err(dev, "Unable to init port %s\n",
434				port->label);
435			continue;
436		}
437
438		gc->ngpio = port->ngpio;
439		gc->label = port->label;
440
441		gc->of_node = dev->of_node;
442		gc->of_gpio_n_cells = 3;
443		gc->of_xlate = etraxfs_gpio_of_xlate;
444
445		ret = gpiochip_add_data(gc, chip);
446		if (ret) {
447			dev_err(dev, "Unable to register port %s\n",
448				gc->label);
449			continue;
450		}
451
452		if (i > 0 && !allportsirq)
453			continue;
454
455		ret = gpiochip_irqchip_add(gc, &etraxfs_gpio_irq_chip, 0,
456					   handle_level_irq, IRQ_TYPE_NONE);
457		if (ret) {
458			dev_err(dev, "Unable to add irqchip to port %s\n",
459				gc->label);
460		}
461	}
462
463	return 0;
464}
465
466static struct platform_driver etraxfs_gpio_driver = {
467	.driver = {
468		.name		= "etraxfs-gpio",
469		.of_match_table = of_match_ptr(etraxfs_gpio_of_table),
470	},
471	.probe	= etraxfs_gpio_probe,
472};
473
474static int __init etraxfs_gpio_init(void)
475{
476	return platform_driver_register(&etraxfs_gpio_driver);
477}
478
479device_initcall(etraxfs_gpio_init);