Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2019 SiFive
  4 */
  5
  6#include <linux/bitops.h>
  7#include <linux/device.h>
  8#include <linux/errno.h>
  9#include <linux/of_irq.h>
 10#include <linux/gpio/driver.h>
 11#include <linux/init.h>
 12#include <linux/platform_device.h>
 13#include <linux/slab.h>
 14#include <linux/spinlock.h>
 15#include <linux/regmap.h>
 16
 17#define SIFIVE_GPIO_INPUT_VAL	0x00
 18#define SIFIVE_GPIO_INPUT_EN	0x04
 19#define SIFIVE_GPIO_OUTPUT_EN	0x08
 20#define SIFIVE_GPIO_OUTPUT_VAL	0x0C
 21#define SIFIVE_GPIO_RISE_IE	0x18
 22#define SIFIVE_GPIO_RISE_IP	0x1C
 23#define SIFIVE_GPIO_FALL_IE	0x20
 24#define SIFIVE_GPIO_FALL_IP	0x24
 25#define SIFIVE_GPIO_HIGH_IE	0x28
 26#define SIFIVE_GPIO_HIGH_IP	0x2C
 27#define SIFIVE_GPIO_LOW_IE	0x30
 28#define SIFIVE_GPIO_LOW_IP	0x34
 29#define SIFIVE_GPIO_OUTPUT_XOR	0x40
 30
 31#define SIFIVE_GPIO_MAX		32
 32
 33struct sifive_gpio {
 34	void __iomem		*base;
 35	struct gpio_chip	gc;
 36	struct regmap		*regs;
 37	unsigned long		irq_state;
 38	unsigned int		trigger[SIFIVE_GPIO_MAX];
 39	unsigned int		irq_number[SIFIVE_GPIO_MAX];
 40};
 41
 42static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
 43{
 44	unsigned long flags;
 45	unsigned int trigger;
 46
 47	spin_lock_irqsave(&chip->gc.bgpio_lock, flags);
 48	trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0;
 49	regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset),
 50			   (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0);
 51	regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset),
 52			   (trigger & IRQ_TYPE_EDGE_FALLING) ? BIT(offset) : 0);
 53	regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset),
 54			   (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0);
 55	regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset),
 56			   (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0);
 57	spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags);
 58}
 59
 60static int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger)
 61{
 62	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 63	struct sifive_gpio *chip = gpiochip_get_data(gc);
 64	int offset = irqd_to_hwirq(d);
 65
 66	if (offset < 0 || offset >= gc->ngpio)
 67		return -EINVAL;
 68
 69	chip->trigger[offset] = trigger;
 70	sifive_gpio_set_ie(chip, offset);
 71	return 0;
 72}
 73
 74static void sifive_gpio_irq_enable(struct irq_data *d)
 75{
 76	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 77	struct sifive_gpio *chip = gpiochip_get_data(gc);
 78	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
 79	u32 bit = BIT(offset);
 80	unsigned long flags;
 81
 82	irq_chip_enable_parent(d);
 83
 84	/* Switch to input */
 85	gc->direction_input(gc, offset);
 86
 87	spin_lock_irqsave(&gc->bgpio_lock, flags);
 88	/* Clear any sticky pending interrupts */
 89	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
 90	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
 91	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
 92	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
 93	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 94
 95	/* Enable interrupts */
 96	assign_bit(offset, &chip->irq_state, 1);
 97	sifive_gpio_set_ie(chip, offset);
 98}
 99
100static void sifive_gpio_irq_disable(struct irq_data *d)
101{
102	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
103	struct sifive_gpio *chip = gpiochip_get_data(gc);
104	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
105
106	assign_bit(offset, &chip->irq_state, 0);
107	sifive_gpio_set_ie(chip, offset);
108	irq_chip_disable_parent(d);
109}
110
111static void sifive_gpio_irq_eoi(struct irq_data *d)
112{
113	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
114	struct sifive_gpio *chip = gpiochip_get_data(gc);
115	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
116	u32 bit = BIT(offset);
117	unsigned long flags;
118
119	spin_lock_irqsave(&gc->bgpio_lock, flags);
120	/* Clear all pending interrupts */
121	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
122	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
123	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
124	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
125	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
126
127	irq_chip_eoi_parent(d);
128}
129
130static int sifive_gpio_irq_set_affinity(struct irq_data *data,
131					const struct cpumask *dest,
132					bool force)
133{
134	if (data->parent_data)
135		return irq_chip_set_affinity_parent(data, dest, force);
136
137	return -EINVAL;
138}
139
140static struct irq_chip sifive_gpio_irqchip = {
141	.name		= "sifive-gpio",
142	.irq_set_type	= sifive_gpio_irq_set_type,
143	.irq_mask	= irq_chip_mask_parent,
144	.irq_unmask	= irq_chip_unmask_parent,
145	.irq_enable	= sifive_gpio_irq_enable,
146	.irq_disable	= sifive_gpio_irq_disable,
147	.irq_eoi	= sifive_gpio_irq_eoi,
148	.irq_set_affinity = sifive_gpio_irq_set_affinity,
149};
150
151static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
152					     unsigned int child,
153					     unsigned int child_type,
154					     unsigned int *parent,
155					     unsigned int *parent_type)
156{
157	struct sifive_gpio *chip = gpiochip_get_data(gc);
158	struct irq_data *d = irq_get_irq_data(chip->irq_number[child]);
159
160	*parent_type = IRQ_TYPE_NONE;
161	*parent = irqd_to_hwirq(d);
162
163	return 0;
164}
165
166static const struct regmap_config sifive_gpio_regmap_config = {
167	.reg_bits = 32,
168	.reg_stride = 4,
169	.val_bits = 32,
170	.fast_io = true,
171	.disable_locking = true,
172};
173
174static int sifive_gpio_probe(struct platform_device *pdev)
175{
176	struct device *dev = &pdev->dev;
177	struct device_node *node = pdev->dev.of_node;
178	struct device_node *irq_parent;
179	struct irq_domain *parent;
180	struct gpio_irq_chip *girq;
181	struct sifive_gpio *chip;
182	int ret, ngpio, i;
183
184	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
185	if (!chip)
186		return -ENOMEM;
187
188	chip->base = devm_platform_ioremap_resource(pdev, 0);
189	if (IS_ERR(chip->base)) {
190		dev_err(dev, "failed to allocate device memory\n");
191		return PTR_ERR(chip->base);
192	}
193
194	chip->regs = devm_regmap_init_mmio(dev, chip->base,
195					   &sifive_gpio_regmap_config);
196	if (IS_ERR(chip->regs))
197		return PTR_ERR(chip->regs);
198
199	ngpio = of_irq_count(node);
200	if (ngpio > SIFIVE_GPIO_MAX) {
201		dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
202			SIFIVE_GPIO_MAX);
203		return -ENXIO;
204	}
205
206	irq_parent = of_irq_find_parent(node);
207	if (!irq_parent) {
208		dev_err(dev, "no IRQ parent node\n");
209		return -ENODEV;
210	}
211	parent = irq_find_host(irq_parent);
212	if (!parent) {
213		dev_err(dev, "no IRQ parent domain\n");
214		return -ENODEV;
215	}
216
217	for (i = 0; i < ngpio; i++)
218		chip->irq_number[i] = platform_get_irq(pdev, i);
219
220	ret = bgpio_init(&chip->gc, dev, 4,
221			 chip->base + SIFIVE_GPIO_INPUT_VAL,
222			 chip->base + SIFIVE_GPIO_OUTPUT_VAL,
223			 NULL,
224			 chip->base + SIFIVE_GPIO_OUTPUT_EN,
225			 chip->base + SIFIVE_GPIO_INPUT_EN,
226			 0);
227	if (ret) {
228		dev_err(dev, "unable to init generic GPIO\n");
229		return ret;
230	}
231
232	/* Disable all GPIO interrupts before enabling parent interrupts */
233	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IE, 0);
234	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IE, 0);
235	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IE, 0);
236	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IE, 0);
237	chip->irq_state = 0;
238
239	chip->gc.base = -1;
240	chip->gc.ngpio = ngpio;
241	chip->gc.label = dev_name(dev);
242	chip->gc.parent = dev;
243	chip->gc.owner = THIS_MODULE;
244	girq = &chip->gc.irq;
245	girq->chip = &sifive_gpio_irqchip;
246	girq->fwnode = of_node_to_fwnode(node);
247	girq->parent_domain = parent;
248	girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq;
249	girq->handler = handle_bad_irq;
250	girq->default_type = IRQ_TYPE_NONE;
251
252	platform_set_drvdata(pdev, chip);
253	return gpiochip_add_data(&chip->gc, chip);
254}
255
256static const struct of_device_id sifive_gpio_match[] = {
257	{ .compatible = "sifive,gpio0" },
258	{ .compatible = "sifive,fu540-c000-gpio" },
259	{ },
260};
261
262static struct platform_driver sifive_gpio_driver = {
263	.probe		= sifive_gpio_probe,
264	.driver = {
265		.name	= "sifive_gpio",
266		.of_match_table = of_match_ptr(sifive_gpio_match),
267	},
268};
269builtin_platform_driver(sifive_gpio_driver)