17
17
#include <linux/clk/bcm2835.h>
18
18
#include <linux/module.h>
19
19
#include <linux/platform_device.h>
20
+ #include <linux/interrupt.h>
21
+ #include <linux/irqdomain.h>
22
+ #include <linux/of_irq.h>
20
23
#include <dt-bindings/clock/bcm2835-aux.h>
21
24
22
25
#define BCM2835_AUXIRQ 0x00
23
26
#define BCM2835_AUXENB 0x04
24
27
28
+ #define BCM2835_AUXIRQ_NUM_IRQS 3
29
+
30
+ #define BCM2835_AUXIRQ_UART_IRQ 0
31
+ #define BCM2835_AUXIRQ_SPI1_IRQ 1
32
+ #define BCM2835_AUXIRQ_SPI2_IRQ 2
33
+
34
+ #define BCM2835_AUXIRQ_UART_MASK 0x01
35
+ #define BCM2835_AUXIRQ_SPI1_MASK 0x02
36
+ #define BCM2835_AUXIRQ_SPI2_MASK 0x04
37
+
38
+ #define BCM2835_AUXIRQ_ALL_MASK \
39
+ (BCM2835_AUXIRQ_UART_MASK | \
40
+ BCM2835_AUXIRQ_SPI1_MASK | \
41
+ BCM2835_AUXIRQ_SPI2_MASK)
42
+
43
+ struct auxirq_state {
44
+ void __iomem * status ;
45
+ u32 enables ;
46
+ struct irq_domain * domain ;
47
+ struct regmap * local_regmap ;
48
+ };
49
+
50
+ static struct auxirq_state auxirq __read_mostly ;
51
+
52
+ static irqreturn_t bcm2835_auxirq_handler (int irq , void * dev_id )
53
+ {
54
+ u32 stat = readl_relaxed (auxirq .status );
55
+ u32 masked = stat & auxirq .enables ;
56
+
57
+ if (masked & BCM2835_AUXIRQ_UART_MASK )
58
+ generic_handle_irq (irq_linear_revmap (auxirq .domain ,
59
+ BCM2835_AUXIRQ_UART_IRQ ));
60
+
61
+ if (masked & BCM2835_AUXIRQ_SPI1_MASK )
62
+ generic_handle_irq (irq_linear_revmap (auxirq .domain ,
63
+ BCM2835_AUXIRQ_SPI1_IRQ ));
64
+
65
+ if (masked & BCM2835_AUXIRQ_SPI2_MASK )
66
+ generic_handle_irq (irq_linear_revmap (auxirq .domain ,
67
+ BCM2835_AUXIRQ_SPI2_IRQ ));
68
+
69
+ return (masked & BCM2835_AUXIRQ_ALL_MASK ) ? IRQ_HANDLED : IRQ_NONE ;
70
+ }
71
+
72
+ static int bcm2835_auxirq_xlate (struct irq_domain * d ,
73
+ struct device_node * ctrlr ,
74
+ const u32 * intspec , unsigned int intsize ,
75
+ unsigned long * out_hwirq ,
76
+ unsigned int * out_type )
77
+ {
78
+ if (WARN_ON (intsize != 1 ))
79
+ return - EINVAL ;
80
+
81
+ if (WARN_ON (intspec [0 ] >= BCM2835_AUXIRQ_NUM_IRQS ))
82
+ return - EINVAL ;
83
+
84
+ * out_hwirq = intspec [0 ];
85
+ * out_type = IRQ_TYPE_NONE ;
86
+ return 0 ;
87
+ }
88
+
89
+ static void bcm2835_auxirq_mask (struct irq_data * data )
90
+ {
91
+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
92
+
93
+ auxirq .enables &= ~(1 << hwirq );
94
+ }
95
+
96
+ static void bcm2835_auxirq_unmask (struct irq_data * data )
97
+ {
98
+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
99
+
100
+ auxirq .enables |= (1 << hwirq );
101
+ }
102
+
103
+ static struct irq_chip bcm2835_auxirq_chip = {
104
+ .name = "bcm2835-auxirq" ,
105
+ .irq_mask = bcm2835_auxirq_mask ,
106
+ .irq_unmask = bcm2835_auxirq_unmask ,
107
+ };
108
+
109
+ static const struct irq_domain_ops bcm2835_auxirq_ops = {
110
+ .xlate = bcm2835_auxirq_xlate //irq_domain_xlate_onecell
111
+ };
112
+
25
113
static int bcm2835_aux_clk_probe (struct platform_device * pdev )
26
114
{
27
115
struct device * dev = & pdev -> dev ;
116
+ struct device_node * node = dev -> of_node ;
28
117
struct clk_hw_onecell_data * onecell ;
29
118
const char * parent ;
30
119
struct clk * parent_clk ;
120
+ int parent_irq ;
31
121
struct resource * res ;
32
122
void __iomem * reg , * gate ;
33
123
@@ -41,6 +131,36 @@ static int bcm2835_aux_clk_probe(struct platform_device *pdev)
41
131
if (IS_ERR (reg ))
42
132
return PTR_ERR (reg );
43
133
134
+ parent_irq = irq_of_parse_and_map (node , 0 );
135
+ if (parent_irq ) {
136
+ int ret ;
137
+ int i ;
138
+
139
+ /* Manage the AUX irq as well */
140
+ auxirq .status = reg + BCM2835_AUXIRQ ;
141
+ auxirq .domain = irq_domain_add_linear (node ,
142
+ BCM2835_AUXIRQ_NUM_IRQS ,
143
+ & bcm2835_auxirq_ops ,
144
+ NULL );
145
+ if (!auxirq .domain )
146
+ return - ENXIO ;
147
+
148
+ for (i = 0 ; i < BCM2835_AUXIRQ_NUM_IRQS ; i ++ ) {
149
+ unsigned int irq = irq_create_mapping (auxirq .domain , i );
150
+
151
+ if (irq == 0 )
152
+ return - ENXIO ;
153
+
154
+ irq_set_chip_and_handler (irq , & bcm2835_auxirq_chip ,
155
+ handle_level_irq );
156
+ }
157
+
158
+ ret = devm_request_irq (dev , parent_irq , bcm2835_auxirq_handler ,
159
+ 0 , "bcm2835-auxirq" , NULL );
160
+ if (ret )
161
+ return ret ;
162
+ }
163
+
44
164
onecell = devm_kmalloc (dev , sizeof (* onecell ) + sizeof (* onecell -> hws ) *
45
165
BCM2835_AUX_CLOCK_COUNT , GFP_KERNEL );
46
166
if (!onecell )
0 commit comments