2011-12-25 21:36:02 +01:00
/*
* Generic GPIO card - detect helper
*
* Copyright ( C ) 2011 , Guennadi Liakhovetski < g . liakhovetski @ gmx . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/err.h>
# include <linux/gpio.h>
2014-03-10 15:02:39 +02:00
# include <linux/gpio/consumer.h>
2011-12-25 21:36:02 +01:00
# include <linux/interrupt.h>
# include <linux/jiffies.h>
# include <linux/mmc/host.h>
2012-04-30 23:31:57 +02:00
# include <linux/mmc/slot-gpio.h>
2011-12-25 21:36:02 +01:00
# include <linux/module.h>
# include <linux/slab.h>
2014-12-18 15:44:34 +01:00
# include "slot-gpio.h"
2012-04-30 23:31:57 +02:00
struct mmc_gpio {
2014-03-10 15:02:39 +02:00
struct gpio_desc * ro_gpio ;
struct gpio_desc * cd_gpio ;
bool override_ro_active_level ;
bool override_cd_active_level ;
2015-01-13 08:23:18 +13:00
irqreturn_t ( * cd_gpio_isr ) ( int irq , void * dev_id ) ;
2012-05-01 16:59:38 +02:00
char * ro_label ;
2012-04-30 23:31:57 +02:00
char cd_label [ 0 ] ;
2011-12-25 21:36:02 +01:00
} ;
2012-04-30 23:31:57 +02:00
static irqreturn_t mmc_gpio_cd_irqt ( int irq , void * dev_id )
2011-12-25 21:36:02 +01:00
{
/* Schedule a card detection after a debounce timeout */
2012-12-04 16:51:36 +01:00
struct mmc_host * host = dev_id ;
2014-04-08 15:19:43 -07:00
host - > trigger_card_event = true ;
2012-12-04 16:51:36 +01:00
mmc_detect_change ( host , msecs_to_jiffies ( 200 ) ) ;
2011-12-25 21:36:02 +01:00
return IRQ_HANDLED ;
}
2014-12-18 15:44:34 +01:00
int mmc_gpio_alloc ( struct mmc_host * host )
2012-05-01 16:51:38 +02:00
{
size_t len = strlen ( dev_name ( host - > parent ) ) + 4 ;
2014-12-18 15:44:36 +01:00
struct mmc_gpio * ctx = devm_kzalloc ( host - > parent ,
sizeof ( * ctx ) + 2 * len , GFP_KERNEL ) ;
if ( ctx ) {
ctx - > ro_label = ctx - > cd_label + len ;
snprintf ( ctx - > cd_label , len , " %s cd " , dev_name ( host - > parent ) ) ;
snprintf ( ctx - > ro_label , len , " %s ro " , dev_name ( host - > parent ) ) ;
host - > slot . handler_priv = ctx ;
host - > slot . cd_irq = - EINVAL ;
2012-05-01 16:51:38 +02:00
}
return ctx ? 0 : - ENOMEM ;
}
2012-05-01 16:59:38 +02:00
int mmc_gpio_get_ro ( struct mmc_host * host )
{
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2014-03-10 15:02:39 +02:00
if ( ! ctx | | ! ctx - > ro_gpio )
2012-05-01 16:59:38 +02:00
return - ENOSYS ;
2014-03-10 15:02:39 +02:00
if ( ctx - > override_ro_active_level )
return ! gpiod_get_raw_value_cansleep ( ctx - > ro_gpio ) ^
! ! ( host - > caps2 & MMC_CAP2_RO_ACTIVE_HIGH ) ;
return gpiod_get_value_cansleep ( ctx - > ro_gpio ) ;
2012-05-01 16:59:38 +02:00
}
EXPORT_SYMBOL ( mmc_gpio_get_ro ) ;
2012-05-01 16:27:25 +02:00
int mmc_gpio_get_cd ( struct mmc_host * host )
{
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2014-03-10 15:02:39 +02:00
if ( ! ctx | | ! ctx - > cd_gpio )
2012-05-01 16:27:25 +02:00
return - ENOSYS ;
2014-03-10 15:02:39 +02:00
if ( ctx - > override_cd_active_level )
return ! gpiod_get_raw_value_cansleep ( ctx - > cd_gpio ) ^
! ! ( host - > caps2 & MMC_CAP2_CD_ACTIVE_HIGH ) ;
return gpiod_get_value_cansleep ( ctx - > cd_gpio ) ;
2012-05-01 16:27:25 +02:00
}
EXPORT_SYMBOL ( mmc_gpio_get_cd ) ;
2012-12-11 22:32:18 +08:00
/**
* mmc_gpio_request_ro - request a gpio for write - protection
* @ host : mmc host
* @ gpio : gpio number requested
*
* As devm_ * managed functions are used in mmc_gpio_request_ro ( ) , client
2014-12-18 15:44:32 +01:00
* drivers do not need to worry about freeing up memory .
2012-12-11 22:32:18 +08:00
*
* Returns zero on success , else an error .
*/
2012-05-01 16:59:38 +02:00
int mmc_gpio_request_ro ( struct mmc_host * host , unsigned int gpio )
{
2014-12-18 15:44:36 +01:00
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2012-05-01 16:59:38 +02:00
int ret ;
if ( ! gpio_is_valid ( gpio ) )
return - EINVAL ;
2014-12-18 15:44:33 +01:00
ret = devm_gpio_request_one ( host - > parent , gpio , GPIOF_DIR_IN ,
2012-12-11 22:32:18 +08:00
ctx - > ro_label ) ;
2012-09-09 22:56:48 -04:00
if ( ret < 0 )
return ret ;
2014-03-10 15:02:39 +02:00
ctx - > override_ro_active_level = true ;
ctx - > ro_gpio = gpio_to_desc ( gpio ) ;
2012-09-09 22:56:48 -04:00
return 0 ;
2012-05-01 16:59:38 +02:00
}
EXPORT_SYMBOL ( mmc_gpio_request_ro ) ;
2014-03-10 15:02:41 +02:00
void mmc_gpiod_request_cd_irq ( struct mmc_host * host )
2014-03-10 15:02:40 +02:00
{
struct mmc_gpio * ctx = host - > slot . handler_priv ;
int ret , irq ;
if ( host - > slot . cd_irq > = 0 | | ! ctx | | ! ctx - > cd_gpio )
return ;
irq = gpiod_to_irq ( ctx - > cd_gpio ) ;
/*
* Even if gpiod_to_irq ( ) returns a valid IRQ number , the platform might
* still prefer to poll , e . g . , because that IRQ number is already used
* by another unit and cannot be shared .
*/
if ( irq > = 0 & & host - > caps & MMC_CAP_NEEDS_POLL )
irq = - EINVAL ;
if ( irq > = 0 ) {
2015-01-13 08:23:18 +13:00
if ( ! ctx - > cd_gpio_isr )
ctx - > cd_gpio_isr = mmc_gpio_cd_irqt ;
2014-12-18 15:44:33 +01:00
ret = devm_request_threaded_irq ( host - > parent , irq ,
2015-01-13 08:23:18 +13:00
NULL , ctx - > cd_gpio_isr ,
2014-03-10 15:02:40 +02:00
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT ,
ctx - > cd_label , host ) ;
if ( ret < 0 )
irq = ret ;
}
host - > slot . cd_irq = irq ;
if ( irq < 0 )
host - > caps | = MMC_CAP_NEEDS_POLL ;
}
2014-03-10 15:02:41 +02:00
EXPORT_SYMBOL ( mmc_gpiod_request_cd_irq ) ;
2014-03-10 15:02:40 +02:00
2015-01-13 08:23:18 +13:00
/* Register an alternate interrupt service routine for
* the card - detect GPIO .
*/
void mmc_gpio_set_cd_isr ( struct mmc_host * host ,
irqreturn_t ( * isr ) ( int irq , void * dev_id ) )
{
struct mmc_gpio * ctx = host - > slot . handler_priv ;
WARN_ON ( ctx - > cd_gpio_isr ) ;
ctx - > cd_gpio_isr = isr ;
}
EXPORT_SYMBOL ( mmc_gpio_set_cd_isr ) ;
2012-12-11 22:32:18 +08:00
/**
* mmc_gpio_request_cd - request a gpio for card - detection
* @ host : mmc host
* @ gpio : gpio number requested
2013-08-08 12:38:31 +02:00
* @ debounce : debounce time in microseconds
2012-12-11 22:32:18 +08:00
*
* As devm_ * managed functions are used in mmc_gpio_request_cd ( ) , client
2014-12-18 15:44:32 +01:00
* drivers do not need to worry about freeing up memory .
2012-12-11 22:32:18 +08:00
*
2013-08-08 12:38:31 +02:00
* If GPIO debouncing is desired , set the debounce parameter to a non - zero
* value . The caller is responsible for ensuring that the GPIO driver associated
* with the GPIO supports debouncing , otherwise an error will be returned .
*
2012-12-11 22:32:18 +08:00
* Returns zero on success , else an error .
*/
2013-08-08 12:38:31 +02:00
int mmc_gpio_request_cd ( struct mmc_host * host , unsigned int gpio ,
unsigned int debounce )
2011-12-25 21:36:02 +01:00
{
2014-12-18 15:44:36 +01:00
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2011-12-25 21:36:02 +01:00
int ret ;
2014-12-18 15:44:33 +01:00
ret = devm_gpio_request_one ( host - > parent , gpio , GPIOF_DIR_IN ,
2012-12-11 22:32:18 +08:00
ctx - > cd_label ) ;
2011-12-25 21:36:02 +01:00
if ( ret < 0 )
2012-05-01 16:51:38 +02:00
/*
* don ' t bother freeing memory . It might still get used by other
* slot functions , in any case it will be freed , when the device
* is destroyed .
*/
return ret ;
2011-12-25 21:36:02 +01:00
2013-08-08 12:38:31 +02:00
if ( debounce ) {
ret = gpio_set_debounce ( gpio , debounce ) ;
if ( ret < 0 )
return ret ;
}
2014-03-10 15:02:39 +02:00
ctx - > override_cd_active_level = true ;
ctx - > cd_gpio = gpio_to_desc ( gpio ) ;
2011-12-25 21:36:02 +01:00
return 0 ;
}
2012-04-30 23:31:57 +02:00
EXPORT_SYMBOL ( mmc_gpio_request_cd ) ;
2011-12-25 21:36:02 +01:00
2014-03-10 15:02:41 +02:00
/**
* mmc_gpiod_request_cd - request a gpio descriptor for card - detection
* @ host : mmc host
* @ con_id : function within the GPIO consumer
* @ idx : index of the GPIO to obtain in the consumer
* @ override_active_level : ignore % GPIO_ACTIVE_LOW flag
* @ debounce : debounce time in microseconds
2014-10-02 09:08:46 +02:00
* @ gpio_invert : will return whether the GPIO line is inverted or not , set
* to NULL to ignore
2014-03-10 15:02:41 +02:00
*
* Use this function in place of mmc_gpio_request_cd ( ) to use the GPIO
2014-12-18 15:44:32 +01:00
* descriptor API . Note that it must be called prior to mmc_add_host ( )
2014-03-10 15:02:41 +02:00
* otherwise the caller must also call mmc_gpiod_request_cd_irq ( ) .
*
* Returns zero on success , else an error .
*/
int mmc_gpiod_request_cd ( struct mmc_host * host , const char * con_id ,
unsigned int idx , bool override_active_level ,
2014-10-02 09:08:46 +02:00
unsigned int debounce , bool * gpio_invert )
2014-03-10 15:02:41 +02:00
{
2014-12-18 15:44:36 +01:00
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2014-03-10 15:02:41 +02:00
struct gpio_desc * desc ;
int ret ;
if ( ! con_id )
con_id = ctx - > cd_label ;
2014-08-27 13:00:50 +02:00
desc = devm_gpiod_get_index ( host - > parent , con_id , idx , GPIOD_IN ) ;
2014-03-10 15:02:41 +02:00
if ( IS_ERR ( desc ) )
return PTR_ERR ( desc ) ;
if ( debounce ) {
ret = gpiod_set_debounce ( desc , debounce ) ;
if ( ret < 0 )
return ret ;
}
2014-10-02 09:08:46 +02:00
if ( gpio_invert )
* gpio_invert = ! gpiod_is_active_low ( desc ) ;
2014-03-10 15:02:41 +02:00
ctx - > override_cd_active_level = override_active_level ;
ctx - > cd_gpio = desc ;
return 0 ;
}
EXPORT_SYMBOL ( mmc_gpiod_request_cd ) ;
2014-08-27 13:00:51 +02:00
/**
* mmc_gpiod_request_ro - request a gpio descriptor for write protection
* @ host : mmc host
* @ con_id : function within the GPIO consumer
* @ idx : index of the GPIO to obtain in the consumer
* @ override_active_level : ignore % GPIO_ACTIVE_LOW flag
* @ debounce : debounce time in microseconds
2014-10-02 09:08:46 +02:00
* @ gpio_invert : will return whether the GPIO line is inverted or not ,
* set to NULL to ignore
2014-08-27 13:00:51 +02:00
*
* Use this function in place of mmc_gpio_request_ro ( ) to use the GPIO
2014-12-18 15:44:32 +01:00
* descriptor API .
2014-08-27 13:00:51 +02:00
*
* Returns zero on success , else an error .
*/
int mmc_gpiod_request_ro ( struct mmc_host * host , const char * con_id ,
unsigned int idx , bool override_active_level ,
2014-10-02 09:08:46 +02:00
unsigned int debounce , bool * gpio_invert )
2014-08-27 13:00:51 +02:00
{
2014-12-18 15:44:36 +01:00
struct mmc_gpio * ctx = host - > slot . handler_priv ;
2014-08-27 13:00:51 +02:00
struct gpio_desc * desc ;
int ret ;
if ( ! con_id )
con_id = ctx - > ro_label ;
desc = devm_gpiod_get_index ( host - > parent , con_id , idx , GPIOD_IN ) ;
if ( IS_ERR ( desc ) )
return PTR_ERR ( desc ) ;
if ( debounce ) {
ret = gpiod_set_debounce ( desc , debounce ) ;
if ( ret < 0 )
return ret ;
}
2014-10-02 09:08:46 +02:00
if ( gpio_invert )
* gpio_invert = ! gpiod_is_active_low ( desc ) ;
2014-08-27 13:00:51 +02:00
ctx - > override_ro_active_level = override_active_level ;
ctx - > ro_gpio = desc ;
return 0 ;
}
EXPORT_SYMBOL ( mmc_gpiod_request_ro ) ;