77
88#include <linux/kernel.h>
99#include <linux/init.h>
10+ #include <linux/irq.h>
11+ #include <linux/irqdesc.h>
1012#include <linux/module.h>
1113#include <linux/spinlock.h>
1214#include <linux/err.h>
1315#include <linux/gpio/driver.h>
1416#include <linux/gpio/generic.h>
1517#include <linux/platform_device.h>
1618#include <linux/bitops.h>
19+ #include <linux/reset.h>
1720#include <asm/types.h>
1821
1922enum loongson_gpio_mode {
@@ -28,6 +31,14 @@ struct loongson_gpio_chip_data {
2831 unsigned int out_offset ;
2932 unsigned int in_offset ;
3033 unsigned int inten_offset ;
34+ unsigned int intpol_offset ;
35+ unsigned int intedge_offset ;
36+ unsigned int intclr_offset ;
37+ unsigned int intsts_offset ;
38+ unsigned int intdual_offset ;
39+ unsigned int intr_num ;
40+ irq_flow_handler_t irq_handler ;
41+ const struct irq_chip * girqchip ;
3142};
3243
3344struct loongson_gpio_chip {
@@ -137,7 +148,140 @@ static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
137148 return platform_get_irq (pdev , offset );
138149}
139150
140- static int loongson_gpio_init (struct device * dev , struct loongson_gpio_chip * lgpio ,
151+ static void loongson_gpio_irq_ack (struct irq_data * data )
152+ {
153+ struct gpio_chip * chip = irq_data_get_irq_chip_data (data );
154+ struct loongson_gpio_chip * lgpio = to_loongson_gpio_chip (chip );
155+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
156+
157+ writeb (0x1 , lgpio -> reg_base + lgpio -> chip_data -> intclr_offset + hwirq );
158+ }
159+
160+ static void loongson_gpio_irq_mask (struct irq_data * data )
161+ {
162+ struct gpio_chip * chip = irq_data_get_irq_chip_data (data );
163+ struct loongson_gpio_chip * lgpio = to_loongson_gpio_chip (chip );
164+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
165+
166+ writeb (0x0 , lgpio -> reg_base + lgpio -> chip_data -> inten_offset + hwirq );
167+ }
168+
169+ static void loongson_gpio_irq_unmask (struct irq_data * data )
170+ {
171+ struct gpio_chip * chip = irq_data_get_irq_chip_data (data );
172+ struct loongson_gpio_chip * lgpio = to_loongson_gpio_chip (chip );
173+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
174+
175+ writeb (0x1 , lgpio -> reg_base + lgpio -> chip_data -> inten_offset + hwirq );
176+ }
177+
178+ static int loongson_gpio_irq_set_type (struct irq_data * data , unsigned int type )
179+ {
180+ struct gpio_chip * chip = irq_data_get_irq_chip_data (data );
181+ struct loongson_gpio_chip * lgpio = to_loongson_gpio_chip (chip );
182+ irq_hw_number_t hwirq = irqd_to_hwirq (data );
183+ u8 pol = 0 , edge = 0 , dual = 0 ;
184+
185+ if ((type & IRQ_TYPE_SENSE_MASK ) == IRQ_TYPE_EDGE_BOTH ) {
186+ edge = 1 ;
187+ dual = 1 ;
188+ irq_set_handler_locked (data , handle_edge_irq );
189+ } else {
190+ switch (type ) {
191+ case IRQ_TYPE_LEVEL_HIGH :
192+ pol = 1 ;
193+ fallthrough ;
194+ case IRQ_TYPE_LEVEL_LOW :
195+ irq_set_handler_locked (data , handle_level_irq );
196+ break ;
197+
198+ case IRQ_TYPE_EDGE_RISING :
199+ pol = 1 ;
200+ fallthrough ;
201+ case IRQ_TYPE_EDGE_FALLING :
202+ edge = 1 ;
203+ irq_set_handler_locked (data , handle_edge_irq );
204+ break ;
205+
206+ default :
207+ return - EINVAL ;
208+ };
209+ }
210+
211+ writeb (pol , lgpio -> reg_base + lgpio -> chip_data -> intpol_offset + hwirq );
212+ writeb (edge , lgpio -> reg_base + lgpio -> chip_data -> intedge_offset + hwirq );
213+ writeb (dual , lgpio -> reg_base + lgpio -> chip_data -> intdual_offset + hwirq );
214+
215+ return 0 ;
216+ }
217+
218+ static void loongson_gpio_ls2k0300_irq_handler (struct irq_desc * desc )
219+ {
220+ struct loongson_gpio_chip * lgpio = irq_desc_get_handler_data (desc );
221+ struct irq_chip * girqchip = irq_desc_get_chip (desc );
222+ int i ;
223+
224+ chained_irq_enter (girqchip , desc );
225+
226+ for (i = 0 ; i < lgpio -> chip .gc .ngpio ; i ++ ) {
227+ /*
228+ * For the GPIO controller of LS2K0300, interrupts status bits
229+ * may be wrongly set even if the corresponding interrupt is
230+ * disabled. Thus interrupt enable bits are checked along with
231+ * status bits to detect interrupts reliably.
232+ */
233+ if (readb (lgpio -> reg_base + lgpio -> chip_data -> intsts_offset + i ) &&
234+ readb (lgpio -> reg_base + lgpio -> chip_data -> inten_offset + i ))
235+ generic_handle_domain_irq (lgpio -> chip .gc .irq .domain , i );
236+ }
237+
238+ chained_irq_exit (girqchip , desc );
239+ }
240+
241+ static const struct irq_chip loongson_gpio_ls2k0300_irqchip = {
242+ .irq_ack = loongson_gpio_irq_ack ,
243+ .irq_mask = loongson_gpio_irq_mask ,
244+ .irq_unmask = loongson_gpio_irq_unmask ,
245+ .irq_set_type = loongson_gpio_irq_set_type ,
246+ .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SKIP_SET_WAKE ,
247+ GPIOCHIP_IRQ_RESOURCE_HELPERS ,
248+ };
249+
250+ static int loongson_gpio_init_irqchip (struct platform_device * pdev ,
251+ struct loongson_gpio_chip * lgpio )
252+ {
253+ const struct loongson_gpio_chip_data * data = lgpio -> chip_data ;
254+ struct gpio_chip * chip = & lgpio -> chip .gc ;
255+ int i ;
256+
257+ chip -> irq .default_type = IRQ_TYPE_NONE ;
258+ chip -> irq .handler = handle_bad_irq ;
259+ chip -> irq .parent_handler = data -> irq_handler ;
260+ chip -> irq .parent_handler_data = lgpio ;
261+ gpio_irq_chip_set_chip (& chip -> irq , data -> girqchip );
262+
263+ chip -> irq .num_parents = data -> intr_num ;
264+ chip -> irq .parents = devm_kcalloc (& pdev -> dev , data -> intr_num ,
265+ sizeof (* chip -> irq .parents ), GFP_KERNEL );
266+ if (!chip -> parent )
267+ return - ENOMEM ;
268+
269+ for (i = 0 ; i < data -> intr_num ; i ++ ) {
270+ chip -> irq .parents [i ] = platform_get_irq (pdev , i );
271+ if (chip -> irq .parents [i ] < 0 )
272+ return dev_err_probe (& pdev -> dev , chip -> irq .parents [i ],
273+ "failed to get IRQ %d\n" , i );
274+ }
275+
276+ for (i = 0 ; i < data -> intr_num ; i ++ ) {
277+ writeb (0x0 , lgpio -> reg_base + data -> inten_offset + i );
278+ writeb (0x1 , lgpio -> reg_base + data -> intclr_offset + i );
279+ }
280+
281+ return 0 ;
282+ }
283+
284+ static int loongson_gpio_init (struct platform_device * pdev , struct loongson_gpio_chip * lgpio ,
141285 void __iomem * reg_base )
142286{
143287 struct gpio_generic_chip_config config ;
@@ -146,7 +290,7 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp
146290 lgpio -> reg_base = reg_base ;
147291 if (lgpio -> chip_data -> mode == BIT_CTRL_MODE ) {
148292 config = (typeof (config )){
149- .dev = dev ,
293+ .dev = & pdev -> dev ,
150294 .sz = 8 ,
151295 .dat = lgpio -> reg_base + lgpio -> chip_data -> in_offset ,
152296 .set = lgpio -> reg_base + lgpio -> chip_data -> out_offset ,
@@ -155,7 +299,7 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp
155299
156300 ret = gpio_generic_chip_init (& lgpio -> chip , & config );
157301 if (ret ) {
158- dev_err (dev , "unable to init generic GPIO\n" );
302+ dev_err (& pdev -> dev , "unable to init generic GPIO\n" );
159303 return ret ;
160304 }
161305 } else {
@@ -164,23 +308,29 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp
164308 lgpio -> chip .gc .get_direction = loongson_gpio_get_direction ;
165309 lgpio -> chip .gc .direction_output = loongson_gpio_direction_output ;
166310 lgpio -> chip .gc .set = loongson_gpio_set ;
167- lgpio -> chip .gc .parent = dev ;
311+ lgpio -> chip .gc .parent = & pdev -> dev ;
168312 spin_lock_init (& lgpio -> lock );
169313 }
170314
171315 lgpio -> chip .gc .label = lgpio -> chip_data -> label ;
172316 lgpio -> chip .gc .can_sleep = false;
173- if (lgpio -> chip_data -> inten_offset )
317+ if (lgpio -> chip_data -> girqchip ) {
318+ ret = loongson_gpio_init_irqchip (pdev , lgpio );
319+ if (ret )
320+ return dev_err_probe (& pdev -> dev , ret , "failed to initialize irqchip\n" );
321+ } else if (lgpio -> chip_data -> inten_offset ) {
174322 lgpio -> chip .gc .to_irq = loongson_gpio_to_irq ;
323+ }
175324
176- return devm_gpiochip_add_data (dev , & lgpio -> chip .gc , lgpio );
325+ return devm_gpiochip_add_data (& pdev -> dev , & lgpio -> chip .gc , lgpio );
177326}
178327
179328static int loongson_gpio_probe (struct platform_device * pdev )
180329{
181330 void __iomem * reg_base ;
182331 struct loongson_gpio_chip * lgpio ;
183332 struct device * dev = & pdev -> dev ;
333+ struct reset_control * rst ;
184334
185335 lgpio = devm_kzalloc (dev , sizeof (* lgpio ), GFP_KERNEL );
186336 if (!lgpio )
@@ -192,7 +342,11 @@ static int loongson_gpio_probe(struct platform_device *pdev)
192342 if (IS_ERR (reg_base ))
193343 return PTR_ERR (reg_base );
194344
195- return loongson_gpio_init (dev , lgpio , reg_base );
345+ rst = devm_reset_control_get_optional_exclusive_deasserted (& pdev -> dev , NULL );
346+ if (IS_ERR (rst ))
347+ return dev_err_probe (& pdev -> dev , PTR_ERR (rst ), "failed to get reset control\n" );
348+
349+ return loongson_gpio_init (pdev , lgpio , reg_base );
196350}
197351
198352static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
@@ -204,6 +358,23 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
204358 .inten_offset = 0x30 ,
205359};
206360
361+ static const struct loongson_gpio_chip_data loongson_gpio_ls2k0300_data = {
362+ .label = "ls2k0300_gpio" ,
363+ .mode = BYTE_CTRL_MODE ,
364+ .conf_offset = 0x800 ,
365+ .in_offset = 0xa00 ,
366+ .out_offset = 0x900 ,
367+ .inten_offset = 0xb00 ,
368+ .intpol_offset = 0xc00 ,
369+ .intedge_offset = 0xd00 ,
370+ .intclr_offset = 0xe00 ,
371+ .intsts_offset = 0xf00 ,
372+ .intdual_offset = 0xf80 ,
373+ .intr_num = 7 ,
374+ .irq_handler = loongson_gpio_ls2k0300_irq_handler ,
375+ .girqchip = & loongson_gpio_ls2k0300_irqchip ,
376+ };
377+
207378static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = {
208379 .label = "ls2k0500_gpio" ,
209380 .mode = BIT_CTRL_MODE ,
@@ -300,6 +471,10 @@ static const struct of_device_id loongson_gpio_of_match[] = {
300471 .compatible = "loongson,ls2k-gpio" ,
301472 .data = & loongson_gpio_ls2k_data ,
302473 },
474+ {
475+ .compatible = "loongson,ls2k0300-gpio" ,
476+ .data = & loongson_gpio_ls2k0300_data ,
477+ },
303478 {
304479 .compatible = "loongson,ls2k0500-gpio0" ,
305480 .data = & loongson_gpio_ls2k0500_data0 ,
0 commit comments