66//
77// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
88
9+ #include <linux/array_size.h>
910#include <linux/device.h>
1011#include <linux/export.h>
1112#include <linux/interrupt.h>
1213#include <linux/irq.h>
1314#include <linux/irqdomain.h>
15+ #include <linux/overflow.h>
1416#include <linux/pm_runtime.h>
1517#include <linux/regmap.h>
1618#include <linux/slab.h>
@@ -33,6 +35,7 @@ struct regmap_irq_chip_data {
3335 void * status_reg_buf ;
3436 unsigned int * main_status_buf ;
3537 unsigned int * status_buf ;
38+ unsigned int * prev_status_buf ;
3639 unsigned int * mask_buf ;
3740 unsigned int * mask_buf_def ;
3841 unsigned int * wake_buf ;
@@ -193,10 +196,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
193196 /* If we've changed our wakeup count propagate it to the parent */
194197 if (d -> wake_count < 0 )
195198 for (i = d -> wake_count ; i < 0 ; i ++ )
196- irq_set_irq_wake (d -> irq , 0 );
199+ disable_irq_wake (d -> irq );
197200 else if (d -> wake_count > 0 )
198201 for (i = 0 ; i < d -> wake_count ; i ++ )
199- irq_set_irq_wake (d -> irq , 1 );
202+ enable_irq_wake (d -> irq );
200203
201204 d -> wake_count = 0 ;
202205
@@ -332,27 +335,13 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
332335 return ret ;
333336}
334337
335- static irqreturn_t regmap_irq_thread ( int irq , void * d )
338+ static int read_irq_data ( struct regmap_irq_chip_data * data )
336339{
337- struct regmap_irq_chip_data * data = d ;
338340 const struct regmap_irq_chip * chip = data -> chip ;
339341 struct regmap * map = data -> map ;
340342 int ret , i ;
341- bool handled = false;
342343 u32 reg ;
343344
344- if (chip -> handle_pre_irq )
345- chip -> handle_pre_irq (chip -> irq_drv_data );
346-
347- if (chip -> runtime_pm ) {
348- ret = pm_runtime_get_sync (map -> dev );
349- if (ret < 0 ) {
350- dev_err (map -> dev , "IRQ thread failed to resume: %d\n" ,
351- ret );
352- goto exit ;
353- }
354- }
355-
356345 /*
357346 * Read only registers with active IRQs if the chip has 'main status
358347 * register'. Else read in the statuses, using a single bulk read if
@@ -379,10 +368,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
379368 reg = data -> get_irq_reg (data , chip -> main_status , i );
380369 ret = regmap_read (map , reg , & data -> main_status_buf [i ]);
381370 if (ret ) {
382- dev_err (map -> dev ,
383- "Failed to read IRQ status %d\n" ,
384- ret );
385- goto exit ;
371+ dev_err (map -> dev , "Failed to read IRQ status %d\n" , ret );
372+ return ret ;
386373 }
387374 }
388375
@@ -398,10 +385,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
398385 ret = read_sub_irq_data (data , b );
399386
400387 if (ret != 0 ) {
401- dev_err (map -> dev ,
402- "Failed to read IRQ status %d\n" ,
403- ret );
404- goto exit ;
388+ dev_err (map -> dev , "Failed to read IRQ status %d\n" , ret );
389+ return ret ;
405390 }
406391 }
407392
@@ -418,9 +403,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
418403 data -> status_reg_buf ,
419404 chip -> num_regs );
420405 if (ret != 0 ) {
421- dev_err (map -> dev , "Failed to read IRQ status: %d\n" ,
422- ret );
423- goto exit ;
406+ dev_err (map -> dev , "Failed to read IRQ status: %d\n" , ret );
407+ return ret ;
424408 }
425409
426410 for (i = 0 ; i < data -> chip -> num_regs ; i ++ ) {
@@ -436,7 +420,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
436420 break ;
437421 default :
438422 BUG ();
439- goto exit ;
423+ return - EIO ;
440424 }
441425 }
442426
@@ -447,10 +431,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
447431 ret = regmap_read (map , reg , & data -> status_buf [i ]);
448432
449433 if (ret != 0 ) {
450- dev_err (map -> dev ,
451- "Failed to read IRQ status: %d\n" ,
452- ret );
453- goto exit ;
434+ dev_err (map -> dev , "Failed to read IRQ status: %d\n" , ret );
435+ return ret ;
454436 }
455437 }
456438 }
@@ -459,6 +441,42 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
459441 for (i = 0 ; i < data -> chip -> num_regs ; i ++ )
460442 data -> status_buf [i ] = ~data -> status_buf [i ];
461443
444+ return 0 ;
445+ }
446+
447+ static irqreturn_t regmap_irq_thread (int irq , void * d )
448+ {
449+ struct regmap_irq_chip_data * data = d ;
450+ const struct regmap_irq_chip * chip = data -> chip ;
451+ struct regmap * map = data -> map ;
452+ int ret , i ;
453+ bool handled = false;
454+ u32 reg ;
455+
456+ if (chip -> handle_pre_irq )
457+ chip -> handle_pre_irq (chip -> irq_drv_data );
458+
459+ if (chip -> runtime_pm ) {
460+ ret = pm_runtime_get_sync (map -> dev );
461+ if (ret < 0 ) {
462+ dev_err (map -> dev , "IRQ thread failed to resume: %d\n" , ret );
463+ goto exit ;
464+ }
465+ }
466+
467+ ret = read_irq_data (data );
468+ if (ret < 0 )
469+ goto exit ;
470+
471+ if (chip -> status_is_level ) {
472+ for (i = 0 ; i < data -> chip -> num_regs ; i ++ ) {
473+ unsigned int val = data -> status_buf [i ];
474+
475+ data -> status_buf [i ] ^= data -> prev_status_buf [i ];
476+ data -> prev_status_buf [i ] = val ;
477+ }
478+ }
479+
462480 /*
463481 * Ignore masked IRQs and ack if we need to; we ack early so
464482 * there is no race between handling and acknowledging the
@@ -705,6 +723,13 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
705723 if (!d -> status_buf )
706724 goto err_alloc ;
707725
726+ if (chip -> status_is_level ) {
727+ d -> prev_status_buf = kcalloc (chip -> num_regs , sizeof (* d -> prev_status_buf ),
728+ GFP_KERNEL );
729+ if (!d -> prev_status_buf )
730+ goto err_alloc ;
731+ }
732+
708733 d -> mask_buf = kcalloc (chip -> num_regs , sizeof (* d -> mask_buf ),
709734 GFP_KERNEL );
710735 if (!d -> mask_buf )
@@ -881,6 +906,16 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
881906 }
882907 }
883908
909+ /* Store current levels */
910+ if (chip -> status_is_level ) {
911+ ret = read_irq_data (d );
912+ if (ret < 0 )
913+ goto err_alloc ;
914+
915+ memcpy (d -> prev_status_buf , d -> status_buf ,
916+ array_size (d -> chip -> num_regs , sizeof (d -> prev_status_buf [0 ])));
917+ }
918+
884919 ret = regmap_irq_create_domain (fwnode , irq_base , chip , d );
885920 if (ret )
886921 goto err_alloc ;
@@ -908,6 +943,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
908943 kfree (d -> mask_buf );
909944 kfree (d -> main_status_buf );
910945 kfree (d -> status_buf );
946+ kfree (d -> prev_status_buf );
911947 kfree (d -> status_reg_buf );
912948 if (d -> config_buf ) {
913949 for (i = 0 ; i < chip -> num_config_bases ; i ++ )
@@ -985,6 +1021,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
9851021 kfree (d -> main_status_buf );
9861022 kfree (d -> status_reg_buf );
9871023 kfree (d -> status_buf );
1024+ kfree (d -> prev_status_buf );
9881025 if (d -> config_buf ) {
9891026 for (i = 0 ; i < d -> chip -> num_config_bases ; i ++ )
9901027 kfree (d -> config_buf [i ]);
0 commit comments