@ -270,8 +270,10 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
static irqreturn_t mcp23s08_irq ( int irq , void * data )
{
struct mcp23s08 * mcp = data ;
int intcap , intf , i ;
int intcap , intf , i , gpio , gpio_orig , intcap_mask ;
unsigned int child_irq ;
bool intf_set , intcap_changed , gpio_bit_changed ,
defval_changed , gpio_set ;
mutex_lock ( & mcp - > lock ) ;
if ( mcp_read ( mcp , MCP_INTF , & intf ) < 0 ) {
@ -287,14 +289,67 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
}
mcp - > cache [ MCP_INTCAP ] = intcap ;
/* This clears the interrupt(configurable on S18) */
if ( mcp_read ( mcp , MCP_GPIO , & gpio ) < 0 ) {
mutex_unlock ( & mcp - > lock ) ;
return IRQ_HANDLED ;
}
gpio_orig = mcp - > cache [ MCP_GPIO ] ;
mcp - > cache [ MCP_GPIO ] = gpio ;
mutex_unlock ( & mcp - > lock ) ;
if ( mcp - > cache [ MCP_INTF ] = = 0 ) {
/* There is no interrupt pending */
return IRQ_HANDLED ;
}
dev_dbg ( mcp - > chip . parent ,
" intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X \n " ,
intcap , intf , gpio_orig , gpio ) ;
for ( i = 0 ; i < mcp - > chip . ngpio ; i + + ) {
if ( ( BIT ( i ) & mcp - > cache [ MCP_INTF ] ) & &
( ( BIT ( i ) & intcap & mcp - > irq_rise ) | |
( mcp - > irq_fall & ~ intcap & BIT ( i ) ) | |
( BIT ( i ) & mcp - > cache [ MCP_INTCON ] ) ) ) {
/* We must check all of the inputs on the chip,
* otherwise we may not notice a change on > = 2 pins .
*
* On at least the mcp23s17 , INTCAP is only updated
* one byte at a time ( INTCAPA and INTCAPB are
* not written to at the same time - only on a per - bank
* basis ) .
*
* INTF only contains the single bit that caused the
* interrupt per - bank . On the mcp23s17 , there is
* INTFA and INTFB . If two pins are changed on the A
* side at the same time , INTF will only have one bit
* set . If one pin on the A side and one pin on the B
* side are changed at the same time , INTF will have
* two bits set . Thus , INTF can ' t be the only check
* to see if the input has changed .
*/
intf_set = BIT ( i ) & mcp - > cache [ MCP_INTF ] ;
if ( i < 8 & & intf_set )
intcap_mask = 0x00FF ;
else if ( i > = 8 & & intf_set )
intcap_mask = 0xFF00 ;
else
intcap_mask = 0x00 ;
intcap_changed = ( intcap_mask &
( BIT ( i ) & mcp - > cache [ MCP_INTCAP ] ) ) ! =
( intcap_mask & ( BIT ( i ) & gpio_orig ) ) ;
gpio_set = BIT ( i ) & mcp - > cache [ MCP_GPIO ] ;
gpio_bit_changed = ( BIT ( i ) & gpio_orig ) ! =
( BIT ( i ) & mcp - > cache [ MCP_GPIO ] ) ;
defval_changed = ( BIT ( i ) & mcp - > cache [ MCP_INTCON ] ) & &
( ( BIT ( i ) & mcp - > cache [ MCP_GPIO ] ) ! =
( BIT ( i ) & mcp - > cache [ MCP_DEFVAL ] ) ) ;
if ( ( ( gpio_bit_changed | | intcap_changed ) & &
( BIT ( i ) & mcp - > irq_rise ) & & gpio_set ) | |
( ( gpio_bit_changed | | intcap_changed ) & &
( BIT ( i ) & mcp - > irq_fall ) & & ! gpio_set ) | |
defval_changed ) {
child_irq = irq_find_mapping ( mcp - > chip . irqdomain , i ) ;
handle_nested_irq ( child_irq ) ;
}