10
10
#include <linux/irqchip/chained_irq.h>
11
11
#include <linux/irqdomain.h>
12
12
#include <linux/kernel.h>
13
+ #include <linux/of_irq.h>
13
14
#include <linux/of_platform.h>
14
15
#include <linux/spinlock.h>
15
16
21
22
#define CHAN_MINTDIS (t ) (CTRL_STRIDE_OFF(t, 3) + 0x4)
22
23
#define CHAN_MASTRSTAT (t ) (CTRL_STRIDE_OFF(t, 3) + 0x8)
23
24
25
+ #define CHAN_MAX_OUTPUT_INT 0x8
26
+
24
27
struct irqsteer_data {
25
28
void __iomem * regs ;
26
29
struct clk * ipg_clk ;
27
- int irq ;
30
+ int irq [CHAN_MAX_OUTPUT_INT ];
31
+ int irq_count ;
28
32
raw_spinlock_t lock ;
29
33
int reg_num ;
30
34
int channel ;
@@ -87,23 +91,47 @@ static const struct irq_domain_ops imx_irqsteer_domain_ops = {
87
91
.xlate = irq_domain_xlate_onecell ,
88
92
};
89
93
94
+ static int imx_irqsteer_get_hwirq_base (struct irqsteer_data * data , u32 irq )
95
+ {
96
+ int i ;
97
+
98
+ for (i = 0 ; i < data -> irq_count ; i ++ ) {
99
+ if (data -> irq [i ] == irq )
100
+ return i * 64 ;
101
+ }
102
+
103
+ return - EINVAL ;
104
+ }
105
+
90
106
static void imx_irqsteer_irq_handler (struct irq_desc * desc )
91
107
{
92
108
struct irqsteer_data * data = irq_desc_get_handler_data (desc );
93
- int i ;
109
+ int hwirq ;
110
+ int irq , i ;
94
111
95
112
chained_irq_enter (irq_desc_get_chip (desc ), desc );
96
113
97
- for (i = 0 ; i < data -> reg_num * 32 ; i += 32 ) {
98
- int idx = imx_irqsteer_get_reg_index (data , i );
114
+ irq = irq_desc_get_irq (desc );
115
+ hwirq = imx_irqsteer_get_hwirq_base (data , irq );
116
+ if (hwirq < 0 ) {
117
+ pr_warn ("%s: unable to get hwirq base for irq %d\n" ,
118
+ __func__ , irq );
119
+ return ;
120
+ }
121
+
122
+ for (i = 0 ; i < 2 ; i ++ , hwirq += 32 ) {
123
+ int idx = imx_irqsteer_get_reg_index (data , hwirq );
99
124
unsigned long irqmap ;
100
125
int pos , virq ;
101
126
127
+ if (hwirq >= data -> reg_num * 32 )
128
+ break ;
129
+
102
130
irqmap = readl_relaxed (data -> regs +
103
131
CHANSTATUS (idx , data -> reg_num ));
104
132
105
133
for_each_set_bit (pos , & irqmap , 32 ) {
106
- virq = irq_find_mapping (data -> domain , pos + i );
134
+ virq = irq_find_mapping (data -> domain , pos + hwirq );
107
135
if (virq )
108
136
generic_handle_irq (virq );
109
137
}
@@ -117,7 +145,8 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
117
145
struct device_node * np = pdev -> dev .of_node ;
118
146
struct irqsteer_data * data ;
119
147
struct resource * res ;
120
- int ret ;
148
+ u32 irqs_num ;
149
+ int i , ret ;
121
150
122
151
data = devm_kzalloc (& pdev -> dev , sizeof (* data ), GFP_KERNEL );
123
152
if (!data )
@@ -130,12 +159,6 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
130
159
return PTR_ERR (data -> regs );
131
160
}
132
161
133
- data -> irq = platform_get_irq (pdev , 0 );
134
- if (data -> irq <= 0 ) {
135
- dev_err (& pdev -> dev , "failed to get irq\n" );
136
- return - ENODEV ;
137
- }
138
-
139
162
data -> ipg_clk = devm_clk_get (& pdev -> dev , "ipg" );
140
163
if (IS_ERR (data -> ipg_clk )) {
141
164
ret = PTR_ERR (data -> ipg_clk );
@@ -146,11 +169,15 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
146
169
147
170
raw_spin_lock_init (& data -> lock );
148
171
149
- of_property_read_u32 (np , "fsl,num-irqs" , & data -> reg_num );
172
+ of_property_read_u32 (np , "fsl,num-irqs" , & irqs_num );
150
173
of_property_read_u32 (np , "fsl,channel" , & data -> channel );
151
174
152
- /* one register bit map represents 32 input interrupts */
153
- data -> reg_num /= 32 ;
175
+ /*
176
+ * There is one output irq for each group of 64 inputs.
177
+ * One register bit map can represent 32 input interrupts.
178
+ */
179
+ data -> irq_count = DIV_ROUND_UP (irqs_num , 64 );
180
+ data -> reg_num = irqs_num / 32 ;
154
181
155
182
if (IS_ENABLED (CONFIG_PM_SLEEP )) {
156
183
data -> saved_reg = devm_kzalloc (& pdev -> dev ,
@@ -173,23 +200,44 @@ static int imx_irqsteer_probe(struct platform_device *pdev)
173
200
& imx_irqsteer_domain_ops , data );
174
201
if (!data -> domain ) {
175
202
dev_err (& pdev -> dev , "failed to create IRQ domain\n" );
176
- clk_disable_unprepare ( data -> ipg_clk ) ;
177
- return - ENOMEM ;
203
+ ret = - ENOMEM ;
204
+ goto out ;
178
205
}
179
206
180
- irq_set_chained_handler_and_data (data -> irq , imx_irqsteer_irq_handler ,
181
- data );
207
+ if (!data -> irq_count || data -> irq_count > CHAN_MAX_OUTPUT_INT ) {
208
+ ret = - EINVAL ;
209
+ goto out ;
210
+ }
211
+
212
+ for (i = 0 ; i < data -> irq_count ; i ++ ) {
213
+ data -> irq [i ] = irq_of_parse_and_map (np , i );
214
+ if (!data -> irq [i ]) {
215
+ ret = - EINVAL ;
216
+ goto out ;
217
+ }
218
+
219
+ irq_set_chained_handler_and_data (data -> irq [i ],
220
+ imx_irqsteer_irq_handler ,
221
+ data );
222
+ }
182
223
183
224
platform_set_drvdata (pdev , data );
184
225
185
226
return 0 ;
227
+ out :
228
+ clk_disable_unprepare (data -> ipg_clk );
229
+ return ret ;
186
230
}
187
231
188
232
static int imx_irqsteer_remove (struct platform_device * pdev )
189
233
{
190
234
struct irqsteer_data * irqsteer_data = platform_get_drvdata (pdev );
235
+ int i ;
236
+
237
+ for (i = 0 ; i < irqsteer_data -> irq_count ; i ++ )
238
+ irq_set_chained_handler_and_data (irqsteer_data -> irq [i ],
239
+ NULL , NULL );
191
240
192
- irq_set_chained_handler_and_data (irqsteer_data -> irq , NULL , NULL );
193
241
irq_domain_remove (irqsteer_data -> domain );
194
242
195
243
clk_disable_unprepare (irqsteer_data -> ipg_clk );
0 commit comments