2009-10-12 19:15:09 +04:00
/*
* wm8350 - irq . c - - IRQ support for Wolfson WM8350
*
* Copyright 2007 , 2008 , 2009 Wolfson Microelectronics PLC .
*
* Author : Liam Girdwood , Mark Brown
*
* 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/bug.h>
# include <linux/device.h>
# include <linux/interrupt.h>
2010-01-05 16:59:09 +03:00
# include <linux/irq.h>
2009-10-12 19:15:09 +04:00
# include <linux/mfd/wm8350/core.h>
# include <linux/mfd/wm8350/audio.h>
# include <linux/mfd/wm8350/comparator.h>
# include <linux/mfd/wm8350/gpio.h>
# include <linux/mfd/wm8350/pmic.h>
# include <linux/mfd/wm8350/rtc.h>
# include <linux/mfd/wm8350/supply.h>
# include <linux/mfd/wm8350/wdt.h>
2009-10-12 19:15:10 +04:00
# define WM8350_INT_OFFSET_1 0
# define WM8350_INT_OFFSET_2 1
# define WM8350_POWER_UP_INT_OFFSET 2
# define WM8350_UNDER_VOLTAGE_INT_OFFSET 3
# define WM8350_OVER_CURRENT_INT_OFFSET 4
# define WM8350_GPIO_INT_OFFSET 5
# define WM8350_COMPARATOR_INT_OFFSET 6
struct wm8350_irq_data {
int primary ;
int reg ;
int mask ;
int primary_only ;
} ;
static struct wm8350_irq_data wm8350_irqs [ ] = {
[ WM8350_IRQ_OC_LS ] = {
. primary = WM8350_OC_INT ,
. reg = WM8350_OVER_CURRENT_INT_OFFSET ,
. mask = WM8350_OC_LS_EINT ,
. primary_only = 1 ,
} ,
[ WM8350_IRQ_UV_DC1 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC1_EINT ,
} ,
[ WM8350_IRQ_UV_DC2 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC2_EINT ,
} ,
[ WM8350_IRQ_UV_DC3 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC3_EINT ,
} ,
[ WM8350_IRQ_UV_DC4 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC4_EINT ,
} ,
[ WM8350_IRQ_UV_DC5 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC5_EINT ,
} ,
[ WM8350_IRQ_UV_DC6 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_DC6_EINT ,
} ,
[ WM8350_IRQ_UV_LDO1 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_LDO1_EINT ,
} ,
[ WM8350_IRQ_UV_LDO2 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_LDO2_EINT ,
} ,
[ WM8350_IRQ_UV_LDO3 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_LDO3_EINT ,
} ,
[ WM8350_IRQ_UV_LDO4 ] = {
. primary = WM8350_UV_INT ,
. reg = WM8350_UNDER_VOLTAGE_INT_OFFSET ,
. mask = WM8350_UV_LDO4_EINT ,
} ,
[ WM8350_IRQ_CHG_BAT_HOT ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_BAT_HOT_EINT ,
} ,
[ WM8350_IRQ_CHG_BAT_COLD ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_BAT_COLD_EINT ,
} ,
[ WM8350_IRQ_CHG_BAT_FAIL ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_BAT_FAIL_EINT ,
} ,
[ WM8350_IRQ_CHG_TO ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_TO_EINT ,
} ,
[ WM8350_IRQ_CHG_END ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_END_EINT ,
} ,
[ WM8350_IRQ_CHG_START ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_START_EINT ,
} ,
[ WM8350_IRQ_CHG_FAST_RDY ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_FAST_RDY_EINT ,
} ,
[ WM8350_IRQ_CHG_VBATT_LT_3P9 ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_VBATT_LT_3P9_EINT ,
} ,
[ WM8350_IRQ_CHG_VBATT_LT_3P1 ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_VBATT_LT_3P1_EINT ,
} ,
[ WM8350_IRQ_CHG_VBATT_LT_2P85 ] = {
. primary = WM8350_CHG_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_CHG_VBATT_LT_2P85_EINT ,
} ,
[ WM8350_IRQ_RTC_ALM ] = {
. primary = WM8350_RTC_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_RTC_ALM_EINT ,
} ,
[ WM8350_IRQ_RTC_SEC ] = {
. primary = WM8350_RTC_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_RTC_SEC_EINT ,
} ,
[ WM8350_IRQ_RTC_PER ] = {
. primary = WM8350_RTC_INT ,
. reg = WM8350_INT_OFFSET_1 ,
. mask = WM8350_RTC_PER_EINT ,
} ,
[ WM8350_IRQ_CS1 ] = {
. primary = WM8350_CS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_CS1_EINT ,
} ,
[ WM8350_IRQ_CS2 ] = {
. primary = WM8350_CS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_CS2_EINT ,
} ,
[ WM8350_IRQ_SYS_HYST_COMP_FAIL ] = {
. primary = WM8350_SYS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_SYS_HYST_COMP_FAIL_EINT ,
} ,
[ WM8350_IRQ_SYS_CHIP_GT115 ] = {
. primary = WM8350_SYS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_SYS_CHIP_GT115_EINT ,
} ,
[ WM8350_IRQ_SYS_CHIP_GT140 ] = {
. primary = WM8350_SYS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_SYS_CHIP_GT140_EINT ,
} ,
[ WM8350_IRQ_SYS_WDOG_TO ] = {
. primary = WM8350_SYS_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_SYS_WDOG_TO_EINT ,
} ,
[ WM8350_IRQ_AUXADC_DATARDY ] = {
. primary = WM8350_AUXADC_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_AUXADC_DATARDY_EINT ,
} ,
[ WM8350_IRQ_AUXADC_DCOMP4 ] = {
. primary = WM8350_AUXADC_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_AUXADC_DCOMP4_EINT ,
} ,
[ WM8350_IRQ_AUXADC_DCOMP3 ] = {
. primary = WM8350_AUXADC_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_AUXADC_DCOMP3_EINT ,
} ,
[ WM8350_IRQ_AUXADC_DCOMP2 ] = {
. primary = WM8350_AUXADC_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_AUXADC_DCOMP2_EINT ,
} ,
[ WM8350_IRQ_AUXADC_DCOMP1 ] = {
. primary = WM8350_AUXADC_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_AUXADC_DCOMP1_EINT ,
} ,
[ WM8350_IRQ_USB_LIMIT ] = {
. primary = WM8350_USB_INT ,
. reg = WM8350_INT_OFFSET_2 ,
. mask = WM8350_USB_LIMIT_EINT ,
. primary_only = 1 ,
} ,
[ WM8350_IRQ_WKUP_OFF_STATE ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_OFF_STATE_EINT ,
} ,
[ WM8350_IRQ_WKUP_HIB_STATE ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_HIB_STATE_EINT ,
} ,
[ WM8350_IRQ_WKUP_CONV_FAULT ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_CONV_FAULT_EINT ,
} ,
[ WM8350_IRQ_WKUP_WDOG_RST ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_WDOG_RST_EINT ,
} ,
[ WM8350_IRQ_WKUP_GP_PWR_ON ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_GP_PWR_ON_EINT ,
} ,
[ WM8350_IRQ_WKUP_ONKEY ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_ONKEY_EINT ,
} ,
[ WM8350_IRQ_WKUP_GP_WAKEUP ] = {
. primary = WM8350_WKUP_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_WKUP_GP_WAKEUP_EINT ,
} ,
[ WM8350_IRQ_CODEC_JCK_DET_L ] = {
. primary = WM8350_CODEC_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_CODEC_JCK_DET_L_EINT ,
} ,
[ WM8350_IRQ_CODEC_JCK_DET_R ] = {
. primary = WM8350_CODEC_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_CODEC_JCK_DET_R_EINT ,
} ,
[ WM8350_IRQ_CODEC_MICSCD ] = {
. primary = WM8350_CODEC_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_CODEC_MICSCD_EINT ,
} ,
[ WM8350_IRQ_CODEC_MICD ] = {
. primary = WM8350_CODEC_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_CODEC_MICD_EINT ,
} ,
[ WM8350_IRQ_EXT_USB_FB ] = {
. primary = WM8350_EXT_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_EXT_USB_FB_EINT ,
} ,
[ WM8350_IRQ_EXT_WALL_FB ] = {
. primary = WM8350_EXT_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_EXT_WALL_FB_EINT ,
} ,
[ WM8350_IRQ_EXT_BAT_FB ] = {
. primary = WM8350_EXT_INT ,
. reg = WM8350_COMPARATOR_INT_OFFSET ,
. mask = WM8350_EXT_BAT_FB_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 0 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP0_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 1 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP1_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 2 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP2_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 3 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP3_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 4 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP4_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 5 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP5_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 6 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP6_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 7 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP7_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 8 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP8_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 9 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP9_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 10 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP10_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 11 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP11_EINT ,
} ,
[ WM8350_IRQ_GPIO ( 12 ) ] = {
. primary = WM8350_GP_INT ,
. reg = WM8350_GPIO_INT_OFFSET ,
. mask = WM8350_GP12_EINT ,
} ,
} ;
2010-01-05 16:59:09 +03:00
static inline struct wm8350_irq_data * irq_to_wm8350_irq ( struct wm8350 * wm8350 ,
int irq )
2009-10-12 19:15:09 +04:00
{
2010-01-05 16:59:09 +03:00
return & wm8350_irqs [ irq - wm8350 - > irq_base ] ;
2009-10-12 19:15:09 +04:00
}
/*
* This is a threaded IRQ handler so can access I2C / SPI . Since all
* interrupts are clear on read the IRQ line will be reasserted and
* the physical IRQ will be handled again if another interrupt is
* asserted while we run - in the normal course of events this is a
2010-01-05 16:59:09 +03:00
* rare occurrence so we save I2C / SPI reads . We ' re also assuming that
* it ' s rare to get lots of interrupts firing simultaneously so try to
* minimise I / O .
2009-10-12 19:15:09 +04:00
*/
2009-10-12 19:15:10 +04:00
static irqreturn_t wm8350_irq ( int irq , void * irq_data )
2009-10-12 19:15:09 +04:00
{
2009-10-12 19:15:10 +04:00
struct wm8350 * wm8350 = irq_data ;
u16 level_one ;
u16 sub_reg [ WM8350_NUM_IRQ_REGS ] ;
int read_done [ WM8350_NUM_IRQ_REGS ] ;
struct wm8350_irq_data * data ;
int i ;
2009-10-12 19:15:09 +04:00
level_one = wm8350_reg_read ( wm8350 , WM8350_SYSTEM_INTERRUPTS )
& ~ wm8350_reg_read ( wm8350 , WM8350_SYSTEM_INTERRUPTS_MASK ) ;
2009-10-12 19:15:10 +04:00
if ( ! level_one )
return IRQ_NONE ;
2009-10-12 19:15:09 +04:00
2009-10-12 19:15:10 +04:00
memset ( & read_done , 0 , sizeof ( read_done ) ) ;
2009-10-12 19:15:09 +04:00
2009-10-12 19:15:10 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8350_irqs ) ; i + + ) {
data = & wm8350_irqs [ i ] ;
2009-10-12 19:15:09 +04:00
2009-10-12 19:15:10 +04:00
if ( ! ( level_one & data - > primary ) )
continue ;
2009-10-12 19:15:09 +04:00
2009-10-12 19:15:10 +04:00
if ( ! read_done [ data - > reg ] ) {
sub_reg [ data - > reg ] =
wm8350_reg_read ( wm8350 , WM8350_INT_STATUS_1 +
data - > reg ) ;
2010-01-05 16:59:09 +03:00
sub_reg [ data - > reg ] & = ~ wm8350 - > irq_masks [ data - > reg ] ;
2009-10-12 19:15:10 +04:00
read_done [ data - > reg ] = 1 ;
2009-10-12 19:15:09 +04:00
}
2009-10-12 19:15:10 +04:00
if ( sub_reg [ data - > reg ] & data - > mask )
2010-01-05 16:59:09 +03:00
handle_nested_irq ( wm8350 - > irq_base + i ) ;
2009-10-12 19:15:09 +04:00
}
return IRQ_HANDLED ;
}
2010-11-24 21:01:43 +03:00
static void wm8350_irq_lock ( struct irq_data * data )
2009-10-12 19:15:09 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm8350 * wm8350 = irq_data_get_irq_chip_data ( data ) ;
2009-11-04 19:10:52 +03:00
2010-01-05 16:59:09 +03:00
mutex_lock ( & wm8350 - > irq_lock ) ;
2009-10-12 19:15:09 +04:00
}
2010-11-24 21:01:43 +03:00
static void wm8350_irq_sync_unlock ( struct irq_data * data )
2009-10-12 19:15:09 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm8350 * wm8350 = irq_data_get_irq_chip_data ( data ) ;
2010-01-05 16:59:09 +03:00
int i ;
2009-10-12 19:15:09 +04:00
2010-01-05 16:59:09 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8350 - > irq_masks ) ; i + + ) {
/* If there's been a change in the mask write it back
* to the hardware . */
2012-06-03 16:37:23 +04:00
WARN_ON ( regmap_update_bits ( wm8350 - > regmap ,
WM8350_INT_STATUS_1_MASK + i ,
0xffff , wm8350 - > irq_masks [ i ] ) ) ;
2010-01-05 16:59:09 +03:00
}
2009-11-04 19:10:52 +03:00
2010-01-05 16:59:09 +03:00
mutex_unlock ( & wm8350 - > irq_lock ) ;
2009-10-12 19:15:09 +04:00
}
2010-11-24 21:01:43 +03:00
static void wm8350_irq_enable ( struct irq_data * data )
2009-10-12 19:15:09 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm8350 * wm8350 = irq_data_get_irq_chip_data ( data ) ;
2010-11-24 21:01:43 +03:00
struct wm8350_irq_data * irq_data = irq_to_wm8350_irq ( wm8350 ,
data - > irq ) ;
2010-01-05 16:59:09 +03:00
wm8350 - > irq_masks [ irq_data - > reg ] & = ~ irq_data - > mask ;
2009-10-12 19:15:09 +04:00
}
2010-11-24 21:01:43 +03:00
static void wm8350_irq_disable ( struct irq_data * data )
2009-10-12 19:15:09 +04:00
{
2010-12-11 16:21:21 +03:00
struct wm8350 * wm8350 = irq_data_get_irq_chip_data ( data ) ;
2010-11-24 21:01:43 +03:00
struct wm8350_irq_data * irq_data = irq_to_wm8350_irq ( wm8350 ,
data - > irq ) ;
2010-01-05 16:59:09 +03:00
wm8350 - > irq_masks [ irq_data - > reg ] | = irq_data - > mask ;
2009-10-12 19:15:09 +04:00
}
2010-01-05 16:59:09 +03:00
static struct irq_chip wm8350_irq_chip = {
2010-11-24 21:01:43 +03:00
. name = " wm8350 " ,
. irq_bus_lock = wm8350_irq_lock ,
. irq_bus_sync_unlock = wm8350_irq_sync_unlock ,
. irq_disable = wm8350_irq_disable ,
. irq_enable = wm8350_irq_enable ,
2010-01-05 16:59:09 +03:00
} ;
2009-10-12 19:15:09 +04:00
int wm8350_irq_init ( struct wm8350 * wm8350 , int irq ,
struct wm8350_platform_data * pdata )
{
2010-01-05 16:59:09 +03:00
int ret , cur_irq , i ;
2009-10-12 19:15:09 +04:00
int flags = IRQF_ONESHOT ;
2011-06-02 22:18:54 +04:00
int irq_base = - 1 ;
2009-10-12 19:15:09 +04:00
if ( ! irq ) {
2010-01-05 16:59:09 +03:00
dev_warn ( wm8350 - > dev , " No interrupt support, no core IRQ \n " ) ;
return 0 ;
}
/* Mask top level interrupts */
2009-10-12 19:15:09 +04:00
wm8350_reg_write ( wm8350 , WM8350_SYSTEM_INTERRUPTS_MASK , 0xFFFF ) ;
2010-01-05 16:59:09 +03:00
/* Mask all individual interrupts by default and cache the
* masks . We read the masks back since there are unwritable
* bits in the mask registers . */
for ( i = 0 ; i < ARRAY_SIZE ( wm8350 - > irq_masks ) ; i + + ) {
wm8350_reg_write ( wm8350 , WM8350_INT_STATUS_1_MASK + i ,
0xFFFF ) ;
wm8350 - > irq_masks [ i ] =
wm8350_reg_read ( wm8350 ,
WM8350_INT_STATUS_1_MASK + i ) ;
}
mutex_init ( & wm8350 - > irq_lock ) ;
2009-10-12 19:15:09 +04:00
wm8350 - > chip_irq = irq ;
2011-06-02 22:18:54 +04:00
if ( pdata & & pdata - > irq_base > 0 )
irq_base = pdata - > irq_base ;
2014-07-21 15:57:25 +04:00
wm8350 - > irq_base =
irq_alloc_descs ( irq_base , 0 , ARRAY_SIZE ( wm8350_irqs ) , 0 ) ;
2011-06-02 22:18:54 +04:00
if ( wm8350 - > irq_base < 0 ) {
dev_warn ( wm8350 - > dev , " Allocating irqs failed with %d \n " ,
wm8350 - > irq_base ) ;
return 0 ;
}
if ( pdata & & pdata - > irq_high ) {
2009-10-12 19:15:09 +04:00
flags | = IRQF_TRIGGER_HIGH ;
wm8350_set_bits ( wm8350 , WM8350_SYSTEM_CONTROL_1 ,
WM8350_IRQ_POL ) ;
} else {
flags | = IRQF_TRIGGER_LOW ;
wm8350_clear_bits ( wm8350 , WM8350_SYSTEM_CONTROL_1 ,
WM8350_IRQ_POL ) ;
}
2010-01-05 16:59:09 +03:00
/* Register with genirq */
for ( cur_irq = wm8350 - > irq_base ;
cur_irq < ARRAY_SIZE ( wm8350_irqs ) + wm8350 - > irq_base ;
cur_irq + + ) {
2011-03-25 14:12:32 +03:00
irq_set_chip_data ( cur_irq , wm8350 ) ;
irq_set_chip_and_handler ( cur_irq , & wm8350_irq_chip ,
2010-01-05 16:59:09 +03:00
handle_edge_irq ) ;
2011-03-25 14:12:32 +03:00
irq_set_nested_thread ( cur_irq , 1 ) ;
2010-01-05 16:59:09 +03:00
2015-07-27 23:55:20 +03:00
irq_clear_status_flags ( cur_irq , IRQ_NOREQUEST | IRQ_NOPROBE ) ;
2010-01-05 16:59:09 +03:00
}
2009-10-12 19:15:09 +04:00
ret = request_threaded_irq ( irq , NULL , wm8350_irq , flags ,
" wm8350 " , wm8350 ) ;
if ( ret ! = 0 )
dev_err ( wm8350 - > dev , " Failed to request IRQ: %d \n " , ret ) ;
2010-01-05 16:59:09 +03:00
/* Allow interrupts to fire */
wm8350_reg_write ( wm8350 , WM8350_SYSTEM_INTERRUPTS_MASK , 0 ) ;
2009-10-12 19:15:09 +04:00
return ret ;
}
int wm8350_irq_exit ( struct wm8350 * wm8350 )
{
free_irq ( wm8350 - > chip_irq , wm8350 ) ;
return 0 ;
}