2009-07-27 17:45:53 +04:00
/*
* wm831x - irq . c - - Interrupt controller support for Wolfson WM831x PMICs
*
* Copyright 2009 Wolfson Microelectronics PLC .
*
* Author : Mark Brown < broonie @ opensource . wolfsonmicro . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/i2c.h>
2009-11-11 19:10:22 +03:00
# include <linux/irq.h>
2009-07-27 17:45:53 +04:00
# include <linux/mfd/core.h>
# include <linux/interrupt.h>
# include <linux/mfd/wm831x/core.h>
# include <linux/mfd/wm831x/pdata.h>
2010-05-07 21:39:25 +04:00
# include <linux/mfd/wm831x/gpio.h>
2009-07-27 17:45:53 +04:00
# include <linux/mfd/wm831x/irq.h>
# include <linux/delay.h>
struct wm831x_irq_data {
int primary ;
int reg ;
int mask ;
} ;
static struct wm831x_irq_data wm831x_irqs [ ] = {
[ WM831X_IRQ_TEMP_THW ] = {
. primary = WM831X_TEMP_INT ,
. reg = 1 ,
. mask = WM831X_TEMP_THW_EINT ,
} ,
[ WM831X_IRQ_GPIO_1 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP1_EINT ,
} ,
[ WM831X_IRQ_GPIO_2 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP2_EINT ,
} ,
[ WM831X_IRQ_GPIO_3 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP3_EINT ,
} ,
[ WM831X_IRQ_GPIO_4 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP4_EINT ,
} ,
[ WM831X_IRQ_GPIO_5 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP5_EINT ,
} ,
[ WM831X_IRQ_GPIO_6 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP6_EINT ,
} ,
[ WM831X_IRQ_GPIO_7 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP7_EINT ,
} ,
[ WM831X_IRQ_GPIO_8 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP8_EINT ,
} ,
[ WM831X_IRQ_GPIO_9 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP9_EINT ,
} ,
[ WM831X_IRQ_GPIO_10 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP10_EINT ,
} ,
[ WM831X_IRQ_GPIO_11 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP11_EINT ,
} ,
[ WM831X_IRQ_GPIO_12 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP12_EINT ,
} ,
[ WM831X_IRQ_GPIO_13 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP13_EINT ,
} ,
[ WM831X_IRQ_GPIO_14 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP14_EINT ,
} ,
[ WM831X_IRQ_GPIO_15 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP15_EINT ,
} ,
[ WM831X_IRQ_GPIO_16 ] = {
. primary = WM831X_GP_INT ,
. reg = 5 ,
. mask = WM831X_GP16_EINT ,
} ,
[ WM831X_IRQ_ON ] = {
. primary = WM831X_ON_PIN_INT ,
. reg = 1 ,
. mask = WM831X_ON_PIN_EINT ,
} ,
[ WM831X_IRQ_PPM_SYSLO ] = {
. primary = WM831X_PPM_INT ,
. reg = 1 ,
. mask = WM831X_PPM_SYSLO_EINT ,
} ,
[ WM831X_IRQ_PPM_PWR_SRC ] = {
. primary = WM831X_PPM_INT ,
. reg = 1 ,
. mask = WM831X_PPM_PWR_SRC_EINT ,
} ,
[ WM831X_IRQ_PPM_USB_CURR ] = {
. primary = WM831X_PPM_INT ,
. reg = 1 ,
. mask = WM831X_PPM_USB_CURR_EINT ,
} ,
[ WM831X_IRQ_WDOG_TO ] = {
. primary = WM831X_WDOG_INT ,
. reg = 1 ,
. mask = WM831X_WDOG_TO_EINT ,
} ,
[ WM831X_IRQ_RTC_PER ] = {
. primary = WM831X_RTC_INT ,
. reg = 1 ,
. mask = WM831X_RTC_PER_EINT ,
} ,
[ WM831X_IRQ_RTC_ALM ] = {
. primary = WM831X_RTC_INT ,
. reg = 1 ,
. mask = WM831X_RTC_ALM_EINT ,
} ,
[ WM831X_IRQ_CHG_BATT_HOT ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_BATT_HOT_EINT ,
} ,
[ WM831X_IRQ_CHG_BATT_COLD ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_BATT_COLD_EINT ,
} ,
[ WM831X_IRQ_CHG_BATT_FAIL ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_BATT_FAIL_EINT ,
} ,
[ WM831X_IRQ_CHG_OV ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_OV_EINT ,
} ,
[ WM831X_IRQ_CHG_END ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_END_EINT ,
} ,
[ WM831X_IRQ_CHG_TO ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_TO_EINT ,
} ,
[ WM831X_IRQ_CHG_MODE ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_MODE_EINT ,
} ,
[ WM831X_IRQ_CHG_START ] = {
. primary = WM831X_CHG_INT ,
. reg = 2 ,
. mask = WM831X_CHG_START_EINT ,
} ,
[ WM831X_IRQ_TCHDATA ] = {
. primary = WM831X_TCHDATA_INT ,
. reg = 1 ,
. mask = WM831X_TCHDATA_EINT ,
} ,
[ WM831X_IRQ_TCHPD ] = {
. primary = WM831X_TCHPD_INT ,
. reg = 1 ,
. mask = WM831X_TCHPD_EINT ,
} ,
[ WM831X_IRQ_AUXADC_DATA ] = {
. primary = WM831X_AUXADC_INT ,
. reg = 1 ,
. mask = WM831X_AUXADC_DATA_EINT ,
} ,
[ WM831X_IRQ_AUXADC_DCOMP1 ] = {
. primary = WM831X_AUXADC_INT ,
. reg = 1 ,
. mask = WM831X_AUXADC_DCOMP1_EINT ,
} ,
[ WM831X_IRQ_AUXADC_DCOMP2 ] = {
. primary = WM831X_AUXADC_INT ,
. reg = 1 ,
. mask = WM831X_AUXADC_DCOMP2_EINT ,
} ,
[ WM831X_IRQ_AUXADC_DCOMP3 ] = {
. primary = WM831X_AUXADC_INT ,
. reg = 1 ,
. mask = WM831X_AUXADC_DCOMP3_EINT ,
} ,
[ WM831X_IRQ_AUXADC_DCOMP4 ] = {
. primary = WM831X_AUXADC_INT ,
. reg = 1 ,
. mask = WM831X_AUXADC_DCOMP4_EINT ,
} ,
[ WM831X_IRQ_CS1 ] = {
. primary = WM831X_CS_INT ,
. reg = 2 ,
. mask = WM831X_CS1_EINT ,
} ,
[ WM831X_IRQ_CS2 ] = {
. primary = WM831X_CS_INT ,
. reg = 2 ,
. mask = WM831X_CS2_EINT ,
} ,
[ WM831X_IRQ_HC_DC1 ] = {
. primary = WM831X_HC_INT ,
. reg = 4 ,
. mask = WM831X_HC_DC1_EINT ,
} ,
[ WM831X_IRQ_HC_DC2 ] = {
. primary = WM831X_HC_INT ,
. reg = 4 ,
. mask = WM831X_HC_DC2_EINT ,
} ,
[ WM831X_IRQ_UV_LDO1 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO1_EINT ,
} ,
[ WM831X_IRQ_UV_LDO2 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO2_EINT ,
} ,
[ WM831X_IRQ_UV_LDO3 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO3_EINT ,
} ,
[ WM831X_IRQ_UV_LDO4 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO4_EINT ,
} ,
[ WM831X_IRQ_UV_LDO5 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO5_EINT ,
} ,
[ WM831X_IRQ_UV_LDO6 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO6_EINT ,
} ,
[ WM831X_IRQ_UV_LDO7 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO7_EINT ,
} ,
[ WM831X_IRQ_UV_LDO8 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO8_EINT ,
} ,
[ WM831X_IRQ_UV_LDO9 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO9_EINT ,
} ,
[ WM831X_IRQ_UV_LDO10 ] = {
. primary = WM831X_UV_INT ,
. reg = 3 ,
. mask = WM831X_UV_LDO10_EINT ,
} ,
[ WM831X_IRQ_UV_DC1 ] = {
. primary = WM831X_UV_INT ,
. reg = 4 ,
. mask = WM831X_UV_DC1_EINT ,
} ,
[ WM831X_IRQ_UV_DC2 ] = {
. primary = WM831X_UV_INT ,
. reg = 4 ,
. mask = WM831X_UV_DC2_EINT ,
} ,
[ WM831X_IRQ_UV_DC3 ] = {
. primary = WM831X_UV_INT ,
. reg = 4 ,
. mask = WM831X_UV_DC3_EINT ,
} ,
[ WM831X_IRQ_UV_DC4 ] = {
. primary = WM831X_UV_INT ,
. reg = 4 ,
. mask = WM831X_UV_DC4_EINT ,
} ,
} ;
static inline int irq_data_to_status_reg ( struct wm831x_irq_data * irq_data )
{
return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data - > reg ;
}
static inline int irq_data_to_mask_reg ( struct wm831x_irq_data * irq_data )
{
return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data - > reg ;
}
2009-11-11 19:10:22 +03:00
static inline struct wm831x_irq_data * irq_to_wm831x_irq ( struct wm831x * wm831x ,
int irq )
2009-07-27 17:45:53 +04:00
{
2009-11-11 19:10:22 +03:00
return & wm831x_irqs [ irq - wm831x - > irq_base ] ;
2009-07-27 17:45:53 +04:00
}
2010-11-24 21:01:42 +03:00
static void wm831x_irq_lock ( struct irq_data * data )
2009-07-27 17:45:53 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm831x * wm831x = irq_data_get_irq_chip_data ( data ) ;
2009-07-27 17:45:53 +04:00
mutex_lock ( & wm831x - > irq_lock ) ;
}
2010-11-24 21:01:42 +03:00
static void wm831x_irq_sync_unlock ( struct irq_data * data )
2009-07-27 17:45:53 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm831x * wm831x = irq_data_get_irq_chip_data ( data ) ;
2009-11-11 19:10:22 +03:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( wm831x - > irq_masks_cur ) ; i + + ) {
/* If there's been a change in the mask write it back
* to the hardware . */
if ( wm831x - > irq_masks_cur [ i ] ! = wm831x - > irq_masks_cache [ i ] ) {
2011-03-01 23:12:44 +03:00
dev_dbg ( wm831x - > dev , " IRQ mask sync: %x = %x \n " ,
WM831X_INTERRUPT_STATUS_1_MASK + i ,
wm831x - > irq_masks_cur [ i ] ) ;
2009-11-11 19:10:22 +03:00
wm831x - > irq_masks_cache [ i ] = wm831x - > irq_masks_cur [ i ] ;
wm831x_reg_write ( wm831x ,
WM831X_INTERRUPT_STATUS_1_MASK + i ,
wm831x - > irq_masks_cur [ i ] ) ;
}
2009-07-27 17:45:53 +04:00
}
mutex_unlock ( & wm831x - > irq_lock ) ;
}
2011-03-01 23:12:44 +03:00
static void wm831x_irq_enable ( struct irq_data * data )
2009-07-27 17:45:53 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm831x * wm831x = irq_data_get_irq_chip_data ( data ) ;
2010-11-24 21:01:42 +03:00
struct wm831x_irq_data * irq_data = irq_to_wm831x_irq ( wm831x ,
data - > irq ) ;
2009-07-27 17:45:53 +04:00
2009-11-11 19:10:22 +03:00
wm831x - > irq_masks_cur [ irq_data - > reg - 1 ] & = ~ irq_data - > mask ;
2009-07-27 17:45:53 +04:00
}
2011-03-01 23:12:44 +03:00
static void wm831x_irq_disable ( struct irq_data * data )
2009-07-27 17:45:53 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm831x * wm831x = irq_data_get_irq_chip_data ( data ) ;
2010-11-24 21:01:42 +03:00
struct wm831x_irq_data * irq_data = irq_to_wm831x_irq ( wm831x ,
data - > irq ) ;
2009-11-11 19:10:22 +03:00
wm831x - > irq_masks_cur [ irq_data - > reg - 1 ] | = irq_data - > mask ;
2009-07-27 17:45:53 +04:00
}
2010-11-24 21:01:42 +03:00
static int wm831x_irq_set_type ( struct irq_data * data , unsigned int type )
2010-05-07 21:39:25 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm831x * wm831x = irq_data_get_irq_chip_data ( data ) ;
2010-11-24 21:01:42 +03:00
int val , irq ;
2010-05-07 21:39:25 +04:00
2010-11-24 21:01:42 +03:00
irq = data - > irq - wm831x - > irq_base ;
2010-05-07 21:39:25 +04:00
2010-08-16 23:26:51 +04:00
if ( irq < WM831X_IRQ_GPIO_1 | | irq > WM831X_IRQ_GPIO_11 ) {
/* Ignore internal-only IRQs */
if ( irq > = 0 & & irq < WM831X_NUM_IRQS )
return 0 ;
else
return - EINVAL ;
}
2010-05-07 21:39:25 +04:00
switch ( type ) {
case IRQ_TYPE_EDGE_BOTH :
val = WM831X_GPN_INT_MODE ;
break ;
case IRQ_TYPE_EDGE_RISING :
val = WM831X_GPN_POL ;
break ;
case IRQ_TYPE_EDGE_FALLING :
val = 0 ;
break ;
default :
return - EINVAL ;
}
return wm831x_set_bits ( wm831x , WM831X_GPIO1_CONTROL + irq ,
WM831X_GPN_INT_MODE | WM831X_GPN_POL , val ) ;
}
2009-11-11 19:10:22 +03:00
static struct irq_chip wm831x_irq_chip = {
2010-11-24 21:01:42 +03:00
. name = " wm831x " ,
. irq_bus_lock = wm831x_irq_lock ,
. irq_bus_sync_unlock = wm831x_irq_sync_unlock ,
2011-03-01 23:12:44 +03:00
. irq_disable = wm831x_irq_disable ,
. irq_enable = wm831x_irq_enable ,
2010-11-24 21:01:42 +03:00
. irq_set_type = wm831x_irq_set_type ,
2009-11-11 19:10:22 +03:00
} ;
/* The processing of the primary interrupt occurs in a thread so that
* we can interact with the device over I2C or SPI . */
static irqreturn_t wm831x_irq_thread ( int irq , void * data )
2009-07-27 17:45:53 +04:00
{
2009-11-11 19:10:22 +03:00
struct wm831x * wm831x = data ;
2009-07-27 17:45:53 +04:00
unsigned int i ;
int primary ;
2009-11-11 19:10:22 +03:00
int status_regs [ WM831X_NUM_IRQ_REGS ] = { 0 } ;
int read [ WM831X_NUM_IRQ_REGS ] = { 0 } ;
2009-07-27 17:45:53 +04:00
int * status ;
primary = wm831x_reg_read ( wm831x , WM831X_SYSTEM_INTERRUPTS ) ;
if ( primary < 0 ) {
dev_err ( wm831x - > dev , " Failed to read system interrupt: %d \n " ,
primary ) ;
goto out ;
}
2011-02-01 14:46:13 +03:00
/* The touch interrupts are visible in the primary register as
* an optimisation ; open code this to avoid complicating the
* main handling loop and so we can also skip iterating the
* descriptors .
*/
if ( primary & WM831X_TCHPD_INT )
handle_nested_irq ( wm831x - > irq_base + WM831X_IRQ_TCHPD ) ;
if ( primary & WM831X_TCHDATA_INT )
handle_nested_irq ( wm831x - > irq_base + WM831X_IRQ_TCHDATA ) ;
if ( primary & ( WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT ) )
goto out ;
2009-07-27 17:45:53 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( wm831x_irqs ) ; i + + ) {
int offset = wm831x_irqs [ i ] . reg - 1 ;
if ( ! ( primary & wm831x_irqs [ i ] . primary ) )
continue ;
status = & status_regs [ offset ] ;
/* Hopefully there should only be one register to read
* each time otherwise we ought to do a block read . */
if ( ! read [ offset ] ) {
* status = wm831x_reg_read ( wm831x ,
irq_data_to_status_reg ( & wm831x_irqs [ i ] ) ) ;
if ( * status < 0 ) {
dev_err ( wm831x - > dev ,
" Failed to read IRQ status: %d \n " ,
* status ) ;
2009-11-11 19:10:22 +03:00
goto out ;
2009-07-27 17:45:53 +04:00
}
read [ offset ] = 1 ;
}
2009-11-11 19:10:22 +03:00
/* Report it if it isn't masked, or forget the status. */
if ( ( * status & ~ wm831x - > irq_masks_cur [ offset ] )
& wm831x_irqs [ i ] . mask )
handle_nested_irq ( wm831x - > irq_base + i ) ;
else
* status & = ~ wm831x_irqs [ i ] . mask ;
2009-07-27 17:45:53 +04:00
}
out :
2011-01-14 16:38:16 +03:00
/* Touchscreen interrupts are handled specially in the driver */
status_regs [ 0 ] & = ~ ( WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT ) ;
2009-11-11 19:10:22 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( status_regs ) ; i + + ) {
if ( status_regs [ i ] )
wm831x_reg_write ( wm831x , WM831X_INTERRUPT_STATUS_1 + i ,
status_regs [ i ] ) ;
}
2009-07-27 17:45:53 +04:00
return IRQ_HANDLED ;
}
int wm831x_irq_init ( struct wm831x * wm831x , int irq )
{
2009-11-11 19:10:22 +03:00
struct wm831x_pdata * pdata = wm831x - > dev - > platform_data ;
int i , cur_irq , ret ;
2009-07-27 17:45:53 +04:00
2009-10-19 14:07:05 +04:00
mutex_init ( & wm831x - > irq_lock ) ;
2010-04-05 19:14:17 +04:00
/* Mask the individual interrupt sources */
for ( i = 0 ; i < ARRAY_SIZE ( wm831x - > irq_masks_cur ) ; i + + ) {
wm831x - > irq_masks_cur [ i ] = 0xffff ;
wm831x - > irq_masks_cache [ i ] = 0xffff ;
wm831x_reg_write ( wm831x , WM831X_INTERRUPT_STATUS_1_MASK + i ,
0xffff ) ;
}
2009-07-27 17:45:53 +04:00
if ( ! irq ) {
dev_warn ( wm831x - > dev ,
" No interrupt specified - functionality limited \n " ) ;
return 0 ;
}
2009-11-11 19:10:22 +03:00
if ( ! pdata | | ! pdata - > irq_base ) {
dev_err ( wm831x - > dev ,
" No interrupt base specified, no interrupts \n " ) ;
return 0 ;
2009-07-27 17:45:53 +04:00
}
2011-01-21 16:26:46 +03:00
if ( pdata - > irq_cmos )
i = 0 ;
else
i = WM831X_IRQ_OD ;
wm831x_set_bits ( wm831x , WM831X_IRQ_CONFIG ,
WM831X_IRQ_OD , i ) ;
2011-01-05 20:56:01 +03:00
/* Try to flag /IRQ as a wake source; there are a number of
* unconditional wake sources in the PMIC so this isn ' t
* conditional but we don ' t actually care * too * much if it
* fails .
*/
ret = enable_irq_wake ( irq ) ;
if ( ret ! = 0 ) {
dev_warn ( wm831x - > dev , " Can't enable IRQ as wake source: %d \n " ,
ret ) ;
}
2009-07-27 17:45:53 +04:00
wm831x - > irq = irq ;
2009-11-11 19:10:22 +03:00
wm831x - > irq_base = pdata - > irq_base ;
2009-07-27 17:45:53 +04:00
2009-11-11 19:10:22 +03:00
/* Register them with genirq */
for ( cur_irq = wm831x - > irq_base ;
cur_irq < ARRAY_SIZE ( wm831x_irqs ) + wm831x - > irq_base ;
cur_irq + + ) {
2011-03-25 14:12:32 +03:00
irq_set_chip_data ( cur_irq , wm831x ) ;
irq_set_chip_and_handler ( cur_irq , & wm831x_irq_chip ,
2009-11-11 19:10:22 +03:00
handle_edge_irq ) ;
2011-03-25 14:12:32 +03:00
irq_set_nested_thread ( cur_irq , 1 ) ;
2009-11-11 19:10:22 +03:00
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so . */
# ifdef CONFIG_ARM
set_irq_flags ( cur_irq , IRQF_VALID ) ;
# else
2011-03-25 14:12:32 +03:00
irq_set_noprobe ( cur_irq ) ;
2009-11-11 19:10:22 +03:00
# endif
}
2009-07-27 17:45:53 +04:00
2009-11-11 19:10:22 +03:00
ret = request_threaded_irq ( irq , NULL , wm831x_irq_thread ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" wm831x " , wm831x ) ;
2009-07-27 17:45:53 +04:00
if ( ret ! = 0 ) {
dev_err ( wm831x - > dev , " Failed to request IRQ %d: %d \n " ,
irq , ret ) ;
return ret ;
}
2009-11-11 19:10:22 +03:00
/* Enable top level interrupts, we mask at secondary level */
wm831x_reg_write ( wm831x , WM831X_SYSTEM_INTERRUPTS_MASK , 0 ) ;
2009-07-27 17:45:53 +04:00
return 0 ;
}
void wm831x_irq_exit ( struct wm831x * wm831x )
{
if ( wm831x - > irq )
free_irq ( wm831x - > irq , wm831x ) ;
}