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