1 From 61f87edd9a522d70d979f679d11849d1dc20cedb Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.org>
3 Date: Thu, 23 Mar 2017 16:34:46 +0000
4 Subject: [PATCH 108/454] bcm2835-aux: Add aux interrupt controller
6 The AUX block has a shared interrupt line with a register indicating
7 which devices have active IRQs. Expose this as a nested interrupt
8 controller to avoid sharing problems.
10 See: https://github.com/raspberrypi/linux/issues/1484
11 https://github.com/raspberrypi/linux/issues/1573
13 Signed-off-by: Phil Elwell <phil@raspberrypi.org>
15 drivers/clk/bcm/clk-bcm2835-aux.c | 120 ++++++++++++++++++++++++++++++
16 1 file changed, 120 insertions(+)
18 --- a/drivers/clk/bcm/clk-bcm2835-aux.c
19 +++ b/drivers/clk/bcm/clk-bcm2835-aux.c
21 #include <linux/clk/bcm2835.h>
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 +#include <linux/interrupt.h>
25 +#include <linux/irqdomain.h>
26 +#include <linux/of_irq.h>
27 #include <dt-bindings/clock/bcm2835-aux.h>
29 #define BCM2835_AUXIRQ 0x00
30 #define BCM2835_AUXENB 0x04
32 +#define BCM2835_AUXIRQ_NUM_IRQS 3
34 +#define BCM2835_AUXIRQ_UART_IRQ 0
35 +#define BCM2835_AUXIRQ_SPI1_IRQ 1
36 +#define BCM2835_AUXIRQ_SPI2_IRQ 2
38 +#define BCM2835_AUXIRQ_UART_MASK 0x01
39 +#define BCM2835_AUXIRQ_SPI1_MASK 0x02
40 +#define BCM2835_AUXIRQ_SPI2_MASK 0x04
42 +#define BCM2835_AUXIRQ_ALL_MASK \
43 + (BCM2835_AUXIRQ_UART_MASK | \
44 + BCM2835_AUXIRQ_SPI1_MASK | \
45 + BCM2835_AUXIRQ_SPI2_MASK)
47 +struct auxirq_state {
48 + void __iomem *status;
50 + struct irq_domain *domain;
51 + struct regmap *local_regmap;
54 +static struct auxirq_state auxirq __read_mostly;
56 +static irqreturn_t bcm2835_auxirq_handler(int irq, void *dev_id)
58 + u32 stat = readl_relaxed(auxirq.status);
59 + u32 masked = stat & auxirq.enables;
61 + if (masked & BCM2835_AUXIRQ_UART_MASK)
62 + generic_handle_irq(irq_linear_revmap(auxirq.domain,
63 + BCM2835_AUXIRQ_UART_IRQ));
65 + if (masked & BCM2835_AUXIRQ_SPI1_MASK)
66 + generic_handle_irq(irq_linear_revmap(auxirq.domain,
67 + BCM2835_AUXIRQ_SPI1_IRQ));
69 + if (masked & BCM2835_AUXIRQ_SPI2_MASK)
70 + generic_handle_irq(irq_linear_revmap(auxirq.domain,
71 + BCM2835_AUXIRQ_SPI2_IRQ));
73 + return (masked & BCM2835_AUXIRQ_ALL_MASK) ? IRQ_HANDLED : IRQ_NONE;
76 +static int bcm2835_auxirq_xlate(struct irq_domain *d,
77 + struct device_node *ctrlr,
78 + const u32 *intspec, unsigned int intsize,
79 + unsigned long *out_hwirq,
80 + unsigned int *out_type)
82 + if (WARN_ON(intsize != 1))
85 + if (WARN_ON(intspec[0] >= BCM2835_AUXIRQ_NUM_IRQS))
88 + *out_hwirq = intspec[0];
89 + *out_type = IRQ_TYPE_NONE;
93 +static void bcm2835_auxirq_mask(struct irq_data *data)
95 + irq_hw_number_t hwirq = irqd_to_hwirq(data);
97 + auxirq.enables &= ~(1 << hwirq);
100 +static void bcm2835_auxirq_unmask(struct irq_data *data)
102 + irq_hw_number_t hwirq = irqd_to_hwirq(data);
104 + auxirq.enables |= (1 << hwirq);
107 +static struct irq_chip bcm2835_auxirq_chip = {
108 + .name = "bcm2835-auxirq",
109 + .irq_mask = bcm2835_auxirq_mask,
110 + .irq_unmask = bcm2835_auxirq_unmask,
113 +static const struct irq_domain_ops bcm2835_auxirq_ops = {
114 + .xlate = bcm2835_auxirq_xlate//irq_domain_xlate_onecell
117 static int bcm2835_aux_clk_probe(struct platform_device *pdev)
119 struct device *dev = &pdev->dev;
120 + struct device_node *node = dev->of_node;
121 struct clk_hw_onecell_data *onecell;
123 struct clk *parent_clk;
125 struct resource *res;
126 void __iomem *reg, *gate;
128 @@ -41,6 +131,36 @@ static int bcm2835_aux_clk_probe(struct
132 + parent_irq = irq_of_parse_and_map(node, 0);
137 + /* Manage the AUX irq as well */
138 + auxirq.status = reg + BCM2835_AUXIRQ;
139 + auxirq.domain = irq_domain_add_linear(node,
140 + BCM2835_AUXIRQ_NUM_IRQS,
141 + &bcm2835_auxirq_ops,
143 + if (!auxirq.domain)
146 + for (i = 0; i < BCM2835_AUXIRQ_NUM_IRQS; i++) {
147 + unsigned int irq = irq_create_mapping(auxirq.domain, i);
152 + irq_set_chip_and_handler(irq, &bcm2835_auxirq_chip,
156 + ret = devm_request_irq(dev, parent_irq, bcm2835_auxirq_handler,
157 + 0, "bcm2835-auxirq", NULL);
162 onecell = devm_kmalloc(dev, sizeof(*onecell) + sizeof(*onecell->hws) *
163 BCM2835_AUX_CLOCK_COUNT, GFP_KERNEL);