2018-03-15 00:15:19 +03:00
// SPDX-License-Identifier: GPL-2.0
2007-02-11 18:41:31 +03:00
# include <linux/module.h>
# include <linux/interrupt.h>
2007-07-27 17:24:33 +04:00
# include <linux/device.h>
2008-04-29 11:59:25 +04:00
# include <linux/gfp.h>
2017-02-10 15:23:23 +03:00
# include <linux/irq.h>
2007-02-11 18:41:31 +03:00
2017-05-31 19:06:59 +03:00
# include "internals.h"
2007-02-11 18:41:31 +03:00
/*
* Device resource management aware IRQ request / free implementation .
*/
struct irq_devres {
unsigned int irq ;
void * dev_id ;
} ;
static void devm_irq_release ( struct device * dev , void * res )
{
struct irq_devres * this = res ;
free_irq ( this - > irq , this - > dev_id ) ;
}
static int devm_irq_match ( struct device * dev , void * res , void * data )
{
struct irq_devres * this = res , * match = data ;
return this - > irq = = match - > irq & & this - > dev_id = = match - > dev_id ;
}
/**
2009-03-23 20:28:16 +03:00
* devm_request_threaded_irq - allocate an interrupt line for a managed device
2007-02-11 18:41:31 +03:00
* @ dev : device to request interrupt for
* @ irq : Interrupt line to allocate
* @ handler : Function to be called when the IRQ occurs
2009-03-23 20:28:16 +03:00
* @ thread_fn : function to be called in a threaded interrupt context . NULL
* for devices which handle everything in @ handler
2007-02-11 18:41:31 +03:00
* @ irqflags : Interrupt type flags
2017-02-12 18:31:44 +03:00
* @ devname : An ascii name for the claiming device , dev_name ( dev ) if NULL
2007-02-11 18:41:31 +03:00
* @ dev_id : A cookie passed back to the handler function
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as
2014-07-01 23:47:35 +04:00
* request_threaded_irq ( ) . IRQs requested with this function will be
2007-02-11 18:41:31 +03:00
* automatically freed on driver detach .
*
* If an IRQ allocated with this function needs to be freed
2010-02-11 17:04:36 +03:00
* separately , devm_free_irq ( ) must be used .
2007-02-11 18:41:31 +03:00
*/
2009-03-23 20:28:16 +03:00
int devm_request_threaded_irq ( struct device * dev , unsigned int irq ,
irq_handler_t handler , irq_handler_t thread_fn ,
unsigned long irqflags , const char * devname ,
void * dev_id )
2007-02-11 18:41:31 +03:00
{
struct irq_devres * dr ;
int rc ;
dr = devres_alloc ( devm_irq_release , sizeof ( struct irq_devres ) ,
GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
2017-02-12 18:31:44 +03:00
if ( ! devname )
devname = dev_name ( dev ) ;
2009-03-23 20:28:16 +03:00
rc = request_threaded_irq ( irq , handler , thread_fn , irqflags , devname ,
dev_id ) ;
2007-02-11 18:41:31 +03:00
if ( rc ) {
2007-04-07 09:59:41 +04:00
devres_free ( dr ) ;
2007-02-11 18:41:31 +03:00
return rc ;
}
dr - > irq = irq ;
dr - > dev_id = dev_id ;
devres_add ( dev , dr ) ;
return 0 ;
}
2009-03-23 20:28:16 +03:00
EXPORT_SYMBOL ( devm_request_threaded_irq ) ;
2007-02-11 18:41:31 +03:00
2014-01-03 04:37:32 +04:00
/**
* devm_request_any_context_irq - allocate an interrupt line for a managed device
* @ dev : device to request interrupt for
* @ irq : Interrupt line to allocate
* @ handler : Function to be called when the IRQ occurs
* @ irqflags : Interrupt type flags
2017-02-12 18:31:44 +03:00
* @ devname : An ascii name for the claiming device , dev_name ( dev ) if NULL
2014-01-03 04:37:32 +04:00
* @ dev_id : A cookie passed back to the handler function
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as
* request_any_context_irq ( ) . IRQs requested with this function will be
* automatically freed on driver detach .
*
* If an IRQ allocated with this function needs to be freed
* separately , devm_free_irq ( ) must be used .
*/
int devm_request_any_context_irq ( struct device * dev , unsigned int irq ,
irq_handler_t handler , unsigned long irqflags ,
const char * devname , void * dev_id )
{
struct irq_devres * dr ;
int rc ;
dr = devres_alloc ( devm_irq_release , sizeof ( struct irq_devres ) ,
GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
2017-02-12 18:31:44 +03:00
if ( ! devname )
devname = dev_name ( dev ) ;
2014-01-03 04:37:32 +04:00
rc = request_any_context_irq ( irq , handler , irqflags , devname , dev_id ) ;
2015-05-11 12:02:58 +03:00
if ( rc < 0 ) {
2014-01-03 04:37:32 +04:00
devres_free ( dr ) ;
return rc ;
}
dr - > irq = irq ;
dr - > dev_id = dev_id ;
devres_add ( dev , dr ) ;
2015-05-11 12:02:58 +03:00
return rc ;
2014-01-03 04:37:32 +04:00
}
EXPORT_SYMBOL ( devm_request_any_context_irq ) ;
2007-02-11 18:41:31 +03:00
/**
* devm_free_irq - free an interrupt
* @ dev : device to free interrupt for
* @ irq : Interrupt line to free
* @ dev_id : Device identity to free
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as free_irq ( ) .
* This function instead of free_irq ( ) should be used to manually
2010-02-02 09:54:51 +03:00
* free IRQs allocated with devm_request_irq ( ) .
2007-02-11 18:41:31 +03:00
*/
void devm_free_irq ( struct device * dev , unsigned int irq , void * dev_id )
{
struct irq_devres match_data = { irq , dev_id } ;
WARN_ON ( devres_destroy ( dev , devm_irq_release , devm_irq_match ,
& match_data ) ) ;
2011-07-26 04:12:59 +04:00
free_irq ( irq , dev_id ) ;
2007-02-11 18:41:31 +03:00
}
EXPORT_SYMBOL ( devm_free_irq ) ;
2017-02-10 15:23:23 +03:00
struct irq_desc_devres {
unsigned int from ;
unsigned int cnt ;
} ;
static void devm_irq_desc_release ( struct device * dev , void * res )
{
struct irq_desc_devres * this = res ;
irq_free_descs ( this - > from , this - > cnt ) ;
}
/**
* __devm_irq_alloc_descs - Allocate and initialize a range of irq descriptors
* for a managed device
* @ dev : Device to allocate the descriptors for
* @ irq : Allocate for specific irq number if irq > = 0
* @ from : Start the search from this irq number
* @ cnt : Number of consecutive irqs to allocate
* @ node : Preferred node on which the irq descriptor should be allocated
* @ owner : Owning module ( can be NULL )
2018-12-04 18:51:20 +03:00
* @ affinity : Optional pointer to an irq_affinity_desc array of size @ cnt
2017-02-10 15:23:23 +03:00
* which hints where the irq descriptors should be allocated
* and which default affinities to use
*
* Returns the first irq number or error code .
*
* Note : Use the provided wrappers ( devm_irq_alloc_desc * ) for simplicity .
*/
int __devm_irq_alloc_descs ( struct device * dev , int irq , unsigned int from ,
unsigned int cnt , int node , struct module * owner ,
2018-12-04 18:51:20 +03:00
const struct irq_affinity_desc * affinity )
2017-02-10 15:23:23 +03:00
{
struct irq_desc_devres * dr ;
int base ;
dr = devres_alloc ( devm_irq_desc_release , sizeof ( * dr ) , GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
base = __irq_alloc_descs ( irq , from , cnt , node , owner , affinity ) ;
if ( base < 0 ) {
devres_free ( dr ) ;
return base ;
}
dr - > from = base ;
dr - > cnt = cnt ;
devres_add ( dev , dr ) ;
return base ;
}
EXPORT_SYMBOL_GPL ( __devm_irq_alloc_descs ) ;
2017-05-31 19:06:59 +03:00
# ifdef CONFIG_GENERIC_IRQ_CHIP
/**
* devm_irq_alloc_generic_chip - Allocate and initialize a generic chip
* for a managed device
* @ dev : Device to allocate the generic chip for
* @ name : Name of the irq chip
* @ num_ct : Number of irq_chip_type instances associated with this
* @ irq_base : Interrupt base nr for this chip
* @ reg_base : Register base address ( virtual )
* @ handler : Default flow handler associated with this chip
*
* Returns an initialized irq_chip_generic structure . The chip defaults
* to the primary ( index 0 ) irq_chip_type and @ handler
*/
struct irq_chip_generic *
devm_irq_alloc_generic_chip ( struct device * dev , const char * name , int num_ct ,
unsigned int irq_base , void __iomem * reg_base ,
irq_flow_handler_t handler )
{
struct irq_chip_generic * gc ;
2019-04-10 20:09:14 +03:00
gc = devm_kzalloc ( dev , struct_size ( gc , chip_types , num_ct ) , GFP_KERNEL ) ;
2017-05-31 19:06:59 +03:00
if ( gc )
irq_init_generic_chip ( gc , name , num_ct ,
irq_base , reg_base , handler ) ;
return gc ;
}
EXPORT_SYMBOL_GPL ( devm_irq_alloc_generic_chip ) ;
2017-05-31 19:07:00 +03:00
struct irq_generic_chip_devres {
struct irq_chip_generic * gc ;
u32 msk ;
unsigned int clr ;
unsigned int set ;
} ;
static void devm_irq_remove_generic_chip ( struct device * dev , void * res )
{
struct irq_generic_chip_devres * this = res ;
irq_remove_generic_chip ( this - > gc , this - > msk , this - > clr , this - > set ) ;
}
/**
* devm_irq_setup_generic_chip - Setup a range of interrupts with a generic
* chip for a managed device
*
* @ dev : Device to setup the generic chip for
* @ gc : Generic irq chip holding all data
* @ msk : Bitmask holding the irqs to initialize relative to gc - > irq_base
* @ flags : Flags for initialization
* @ clr : IRQ_ * bits to clear
* @ set : IRQ_ * bits to set
*
* Set up max . 32 interrupts starting from gc - > irq_base . Note , this
* initializes all interrupts to the primary irq_chip_type and its
* associated handler .
*/
int devm_irq_setup_generic_chip ( struct device * dev , struct irq_chip_generic * gc ,
u32 msk , enum irq_gc_flags flags ,
unsigned int clr , unsigned int set )
{
struct irq_generic_chip_devres * dr ;
dr = devres_alloc ( devm_irq_remove_generic_chip ,
sizeof ( * dr ) , GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
irq_setup_generic_chip ( gc , msk , flags , clr , set ) ;
dr - > gc = gc ;
dr - > msk = msk ;
dr - > clr = clr ;
dr - > set = set ;
devres_add ( dev , dr ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( devm_irq_setup_generic_chip ) ;
2017-05-31 19:06:59 +03:00
# endif /* CONFIG_GENERIC_IRQ_CHIP */