2012-11-23 21:17:34 +01:00
/*
* Secure Digital Host Controller Interface ACPI driver .
*
* Copyright ( c ) 2012 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
*/
# include <linux/init.h>
# include <linux/export.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/ioport.h>
# include <linux/io.h>
# include <linux/dma-mapping.h>
# include <linux/compiler.h>
# include <linux/stddef.h>
# include <linux/bitops.h>
# include <linux/types.h>
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/acpi.h>
# include <linux/pm.h>
# include <linux/pm_runtime.h>
2013-06-13 11:50:27 +03:00
# include <linux/delay.h>
2012-11-23 21:17:34 +01:00
# include <linux/mmc/host.h>
# include <linux/mmc/pm.h>
2014-03-10 15:02:42 +02:00
# include <linux/mmc/slot-gpio.h>
2012-11-23 21:17:34 +01:00
# include "sdhci.h"
enum {
2014-03-10 15:02:42 +02:00
SDHCI_ACPI_SD_CD = BIT ( 0 ) ,
SDHCI_ACPI_RUNTIME_PM = BIT ( 1 ) ,
SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL = BIT ( 2 ) ,
2012-11-23 21:17:34 +01:00
} ;
struct sdhci_acpi_chip {
const struct sdhci_ops * ops ;
unsigned int quirks ;
unsigned int quirks2 ;
unsigned long caps ;
unsigned int caps2 ;
mmc_pm_flag_t pm_caps ;
} ;
struct sdhci_acpi_slot {
const struct sdhci_acpi_chip * chip ;
unsigned int quirks ;
unsigned int quirks2 ;
unsigned long caps ;
unsigned int caps2 ;
mmc_pm_flag_t pm_caps ;
unsigned int flags ;
2014-10-06 15:23:06 +03:00
int ( * probe_slot ) ( struct platform_device * , const char * , const char * ) ;
2014-09-01 11:35:40 +08:00
int ( * remove_slot ) ( struct platform_device * ) ;
2012-11-23 21:17:34 +01:00
} ;
struct sdhci_acpi_host {
struct sdhci_host * host ;
const struct sdhci_acpi_slot * slot ;
struct platform_device * pdev ;
bool use_runtime_pm ;
2014-11-04 12:42:47 +02:00
bool dma_setup ;
2012-11-23 21:17:34 +01:00
} ;
static inline bool sdhci_acpi_flag ( struct sdhci_acpi_host * c , unsigned int flag )
{
return c - > slot & & ( c - > slot - > flags & flag ) ;
}
static int sdhci_acpi_enable_dma ( struct sdhci_host * host )
{
2014-11-04 12:42:47 +02:00
struct sdhci_acpi_host * c = sdhci_priv ( host ) ;
struct device * dev = & c - > pdev - > dev ;
int err = - 1 ;
if ( c - > dma_setup )
return 0 ;
if ( host - > flags & SDHCI_USE_64_BIT_DMA ) {
if ( host - > quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA ) {
host - > flags & = ~ SDHCI_USE_64_BIT_DMA ;
} else {
err = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 64 ) ) ;
if ( err )
dev_warn ( dev , " Failed to set 64-bit DMA mask \n " ) ;
}
}
if ( err )
err = dma_set_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
c - > dma_setup = ! err ;
return err ;
2012-11-23 21:17:34 +01:00
}
2013-06-13 11:50:27 +03:00
static void sdhci_acpi_int_hw_reset ( struct sdhci_host * host )
{
u8 reg ;
reg = sdhci_readb ( host , SDHCI_POWER_CONTROL ) ;
reg | = 0x10 ;
sdhci_writeb ( host , reg , SDHCI_POWER_CONTROL ) ;
/* For eMMC, minimum is 1us but give it 9us for good measure */
udelay ( 9 ) ;
reg & = ~ 0x10 ;
sdhci_writeb ( host , reg , SDHCI_POWER_CONTROL ) ;
/* For eMMC, minimum is 200us but give it 300us for good measure */
usleep_range ( 300 , 1000 ) ;
}
2012-11-23 21:17:34 +01:00
static const struct sdhci_ops sdhci_acpi_ops_dflt = {
2014-04-25 12:58:55 +01:00
. set_clock = sdhci_set_clock ,
2012-11-23 21:17:34 +01:00
. enable_dma = sdhci_acpi_enable_dma ,
2014-04-25 12:57:07 +01:00
. set_bus_width = sdhci_set_bus_width ,
2014-04-25 12:57:12 +01:00
. reset = sdhci_reset ,
2014-04-25 12:59:26 +01:00
. set_uhs_signaling = sdhci_set_uhs_signaling ,
2012-11-23 21:17:34 +01:00
} ;
2013-06-13 11:50:27 +03:00
static const struct sdhci_ops sdhci_acpi_ops_int = {
2014-04-25 12:58:55 +01:00
. set_clock = sdhci_set_clock ,
2013-06-13 11:50:27 +03:00
. enable_dma = sdhci_acpi_enable_dma ,
2014-04-25 12:57:07 +01:00
. set_bus_width = sdhci_set_bus_width ,
2014-04-25 12:57:12 +01:00
. reset = sdhci_reset ,
2014-04-25 12:59:26 +01:00
. set_uhs_signaling = sdhci_set_uhs_signaling ,
2013-06-13 11:50:27 +03:00
. hw_reset = sdhci_acpi_int_hw_reset ,
} ;
static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
. ops = & sdhci_acpi_ops_int ,
} ;
2016-02-09 16:12:38 +02:00
static int bxt_get_cd ( struct mmc_host * mmc )
{
int gpio_cd = mmc_gpio_get_cd ( mmc ) ;
struct sdhci_host * host = mmc_priv ( mmc ) ;
unsigned long flags ;
int ret = 0 ;
if ( ! gpio_cd )
return 0 ;
pm_runtime_get_sync ( mmc - > parent ) ;
spin_lock_irqsave ( & host - > lock , flags ) ;
if ( host - > flags & SDHCI_DEVICE_DEAD )
goto out ;
ret = ! ! ( sdhci_readl ( host , SDHCI_PRESENT_STATE ) & SDHCI_CARD_PRESENT ) ;
out :
spin_unlock_irqrestore ( & host - > lock , flags ) ;
pm_runtime_mark_last_busy ( mmc - > parent ) ;
pm_runtime_put_autosuspend ( mmc - > parent ) ;
return ret ;
}
2014-10-06 15:23:06 +03:00
static int sdhci_acpi_emmc_probe_slot ( struct platform_device * pdev ,
const char * hid , const char * uid )
2014-09-01 11:35:40 +08:00
{
struct sdhci_acpi_host * c = platform_get_drvdata ( pdev ) ;
struct sdhci_host * host ;
if ( ! c | | ! c - > host )
return 0 ;
host = c - > host ;
2015-01-12 19:37:25 +02:00
/* Platform specific code during emmc probe slot goes here */
2014-09-01 11:35:40 +08:00
2014-10-06 15:23:07 +03:00
if ( hid & & uid & & ! strcmp ( hid , " 80860F14 " ) & & ! strcmp ( uid , " 1 " ) & &
sdhci_readl ( host , SDHCI_CAPABILITIES ) = = 0x446cc8b2 & &
sdhci_readl ( host , SDHCI_CAPABILITIES_1 ) = = 0x00000807 )
host - > timeout_clk = 1000 ; /* 1000 kHz i.e. 1 MHz */
2014-09-01 11:35:40 +08:00
return 0 ;
}
2014-10-06 15:23:06 +03:00
static int sdhci_acpi_sdio_probe_slot ( struct platform_device * pdev ,
const char * hid , const char * uid )
2014-09-01 11:35:40 +08:00
{
struct sdhci_acpi_host * c = platform_get_drvdata ( pdev ) ;
struct sdhci_host * host ;
if ( ! c | | ! c - > host )
return 0 ;
host = c - > host ;
2015-01-12 19:37:25 +02:00
/* Platform specific code during sdio probe slot goes here */
2014-09-01 11:35:40 +08:00
return 0 ;
}
2014-10-06 15:23:06 +03:00
static int sdhci_acpi_sd_probe_slot ( struct platform_device * pdev ,
const char * hid , const char * uid )
2014-09-01 11:35:40 +08:00
{
struct sdhci_acpi_host * c = platform_get_drvdata ( pdev ) ;
struct sdhci_host * host ;
if ( ! c | | ! c - > host | | ! c - > slot )
return 0 ;
host = c - > host ;
2015-01-12 19:37:25 +02:00
/* Platform specific code during sd probe slot goes here */
2014-09-01 11:35:40 +08:00
2016-02-09 16:12:38 +02:00
if ( hid & & ! strcmp ( hid , " 80865ACA " ) )
host - > mmc_host_ops . get_cd = bxt_get_cd ;
2014-09-01 11:35:40 +08:00
return 0 ;
}
2013-04-26 11:27:22 +03:00
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
2013-06-13 11:50:27 +03:00
. chip = & sdhci_acpi_chip_int ,
2014-07-08 19:11:01 +08:00
. caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
2014-12-01 15:51:19 +02:00
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY ,
2013-04-26 11:27:22 +03:00
. caps2 = MMC_CAP2_HC_ERASE_SZ ,
. flags = SDHCI_ACPI_RUNTIME_PM ,
2014-12-01 15:51:17 +02:00
. quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC ,
2015-10-21 11:15:46 +03:00
. quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 ,
2014-09-01 11:35:40 +08:00
. probe_slot = sdhci_acpi_emmc_probe_slot ,
2013-04-26 11:27:22 +03:00
} ;
2012-12-10 21:18:48 +01:00
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
2014-12-01 15:51:17 +02:00
. quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC ,
2012-12-10 21:18:48 +01:00
. quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON ,
2014-12-01 15:51:19 +02:00
. caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY ,
2012-12-10 21:18:48 +01:00
. flags = SDHCI_ACPI_RUNTIME_PM ,
. pm_caps = MMC_PM_KEEP_POWER ,
2014-09-01 11:35:40 +08:00
. probe_slot = sdhci_acpi_sdio_probe_slot ,
2012-12-10 21:18:48 +01:00
} ;
2013-04-26 11:27:22 +03:00
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
2014-03-10 15:02:42 +02:00
. flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
SDHCI_ACPI_RUNTIME_PM ,
2014-12-01 15:51:17 +02:00
. quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC ,
2014-09-24 10:27:28 +03:00
. quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC ,
2014-12-01 15:51:19 +02:00
. caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY ,
2014-09-01 11:35:40 +08:00
. probe_slot = sdhci_acpi_sd_probe_slot ,
2013-04-26 11:27:22 +03:00
} ;
struct sdhci_acpi_uid_slot {
const char * hid ;
const char * uid ;
const struct sdhci_acpi_slot * slot ;
} ;
static const struct sdhci_acpi_uid_slot sdhci_acpi_uids [ ] = {
2015-10-21 11:15:46 +03:00
{ " 80865ACA " , NULL , & sdhci_acpi_slot_int_sd } ,
{ " 80865ACC " , NULL , & sdhci_acpi_slot_int_emmc } ,
{ " 80865AD0 " , NULL , & sdhci_acpi_slot_int_sdio } ,
2013-04-26 11:27:22 +03:00
{ " 80860F14 " , " 1 " , & sdhci_acpi_slot_int_emmc } ,
{ " 80860F14 " , " 3 " , & sdhci_acpi_slot_int_sd } ,
2014-03-10 15:02:43 +02:00
{ " 80860F16 " , NULL , & sdhci_acpi_slot_int_sd } ,
2013-04-26 11:27:22 +03:00
{ " INT33BB " , " 2 " , & sdhci_acpi_slot_int_sdio } ,
2014-09-24 10:27:29 +03:00
{ " INT33BB " , " 3 " , & sdhci_acpi_slot_int_sd } ,
2013-04-26 11:27:22 +03:00
{ " INT33C6 " , NULL , & sdhci_acpi_slot_int_sdio } ,
2013-11-12 12:01:33 +02:00
{ " INT3436 " , NULL , & sdhci_acpi_slot_int_sdio } ,
2015-01-05 14:47:57 +02:00
{ " INT344D " , NULL , & sdhci_acpi_slot_int_sdio } ,
2015-09-05 08:49:52 +02:00
{ " PNP0FFF " , " 3 " , & sdhci_acpi_slot_int_sd } ,
2013-04-26 11:27:22 +03:00
{ " PNP0D40 " } ,
{ } ,
} ;
2012-11-23 21:17:34 +01:00
static const struct acpi_device_id sdhci_acpi_ids [ ] = {
2015-10-21 11:15:46 +03:00
{ " 80865ACA " } ,
{ " 80865ACC " } ,
{ " 80865AD0 " } ,
2013-04-26 11:27:22 +03:00
{ " 80860F14 " } ,
2014-03-10 15:02:43 +02:00
{ " 80860F16 " } ,
2013-04-26 11:27:22 +03:00
{ " INT33BB " } ,
{ " INT33C6 " } ,
2013-11-12 12:01:33 +02:00
{ " INT3436 " } ,
2015-01-05 14:47:57 +02:00
{ " INT344D " } ,
2013-04-26 11:27:22 +03:00
{ " PNP0D40 " } ,
2012-11-23 21:17:34 +01:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , sdhci_acpi_ids ) ;
2014-10-06 15:23:05 +03:00
static const struct sdhci_acpi_slot * sdhci_acpi_get_slot ( const char * hid ,
const char * uid )
2012-11-23 21:17:34 +01:00
{
2013-04-26 11:27:22 +03:00
const struct sdhci_acpi_uid_slot * u ;
for ( u = sdhci_acpi_uids ; u - > hid ; u + + ) {
if ( strcmp ( u - > hid , hid ) )
continue ;
if ( ! u - > uid )
return u - > slot ;
if ( uid & & ! strcmp ( u - > uid , uid ) )
return u - > slot ;
}
2012-11-23 21:17:34 +01:00
return NULL ;
}
2012-12-21 15:05:47 -08:00
static int sdhci_acpi_probe ( struct platform_device * pdev )
2012-11-23 21:17:34 +01:00
{
struct device * dev = & pdev - > dev ;
acpi_handle handle = ACPI_HANDLE ( dev ) ;
struct acpi_device * device ;
struct sdhci_acpi_host * c ;
struct sdhci_host * host ;
struct resource * iomem ;
resource_size_t len ;
const char * hid ;
2014-10-06 15:23:05 +03:00
const char * uid ;
2014-01-08 12:40:55 +02:00
int err ;
2012-11-23 21:17:34 +01:00
if ( acpi_bus_get_device ( handle , & device ) )
return - ENODEV ;
if ( acpi_bus_get_status ( device ) | | ! device - > status . present )
return - ENODEV ;
hid = acpi_device_hid ( device ) ;
2014-10-06 15:23:05 +03:00
uid = device - > pnp . unique_id ;
2012-11-23 21:17:34 +01:00
iomem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! iomem )
return - ENOMEM ;
len = resource_size ( iomem ) ;
if ( len < 0x100 )
dev_err ( dev , " Invalid iomem size! \n " ) ;
if ( ! devm_request_mem_region ( dev , iomem - > start , len , dev_name ( dev ) ) )
return - ENOMEM ;
host = sdhci_alloc_host ( dev , sizeof ( struct sdhci_acpi_host ) ) ;
if ( IS_ERR ( host ) )
return PTR_ERR ( host ) ;
c = sdhci_priv ( host ) ;
c - > host = host ;
2014-10-06 15:23:05 +03:00
c - > slot = sdhci_acpi_get_slot ( hid , uid ) ;
2012-11-23 21:17:34 +01:00
c - > pdev = pdev ;
c - > use_runtime_pm = sdhci_acpi_flag ( c , SDHCI_ACPI_RUNTIME_PM ) ;
platform_set_drvdata ( pdev , c ) ;
host - > hw_name = " ACPI " ;
host - > ops = & sdhci_acpi_ops_dflt ;
host - > irq = platform_get_irq ( pdev , 0 ) ;
host - > ioaddr = devm_ioremap_nocache ( dev , iomem - > start ,
resource_size ( iomem ) ) ;
if ( host - > ioaddr = = NULL ) {
err = - ENOMEM ;
goto err_free ;
}
if ( c - > slot ) {
2014-09-01 11:35:40 +08:00
if ( c - > slot - > probe_slot ) {
2014-10-06 15:23:06 +03:00
err = c - > slot - > probe_slot ( pdev , hid , uid ) ;
2014-09-01 11:35:40 +08:00
if ( err )
goto err_free ;
}
2012-11-23 21:17:34 +01:00
if ( c - > slot - > chip ) {
host - > ops = c - > slot - > chip - > ops ;
host - > quirks | = c - > slot - > chip - > quirks ;
host - > quirks2 | = c - > slot - > chip - > quirks2 ;
host - > mmc - > caps | = c - > slot - > chip - > caps ;
host - > mmc - > caps2 | = c - > slot - > chip - > caps2 ;
host - > mmc - > pm_caps | = c - > slot - > chip - > pm_caps ;
}
host - > quirks | = c - > slot - > quirks ;
host - > quirks2 | = c - > slot - > quirks2 ;
host - > mmc - > caps | = c - > slot - > caps ;
host - > mmc - > caps2 | = c - > slot - > caps2 ;
host - > mmc - > pm_caps | = c - > slot - > pm_caps ;
}
2013-04-04 16:41:06 +03:00
host - > mmc - > caps2 | = MMC_CAP2_NO_PRESCAN_POWERUP ;
2013-05-06 12:17:33 +03:00
if ( sdhci_acpi_flag ( c , SDHCI_ACPI_SD_CD ) ) {
2014-03-10 15:02:42 +02:00
bool v = sdhci_acpi_flag ( c , SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL ) ;
2014-10-02 09:08:46 +02:00
if ( mmc_gpiod_request_cd ( host - > mmc , NULL , 0 , v , 0 , NULL ) ) {
2014-03-10 15:02:42 +02:00
dev_warn ( dev , " failed to setup card detect gpio \n " ) ;
2013-05-06 12:17:33 +03:00
c - > use_runtime_pm = false ;
2014-03-10 15:02:42 +02:00
}
2013-05-06 12:17:33 +03:00
}
2014-03-10 15:02:42 +02:00
err = sdhci_add_host ( host ) ;
if ( err )
goto err_free ;
2012-11-23 21:17:34 +01:00
if ( c - > use_runtime_pm ) {
2013-04-26 11:27:21 +03:00
pm_runtime_set_active ( dev ) ;
2012-11-23 21:17:34 +01:00
pm_suspend_ignore_children ( dev , 1 ) ;
pm_runtime_set_autosuspend_delay ( dev , 50 ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_enable ( dev ) ;
}
2016-01-22 12:35:26 +08:00
device_enable_async_suspend ( dev ) ;
2012-11-23 21:17:34 +01:00
return 0 ;
err_free :
sdhci_free_host ( c - > host ) ;
return err ;
}
2012-12-21 15:05:47 -08:00
static int sdhci_acpi_remove ( struct platform_device * pdev )
2012-11-23 21:17:34 +01:00
{
struct sdhci_acpi_host * c = platform_get_drvdata ( pdev ) ;
struct device * dev = & pdev - > dev ;
int dead ;
if ( c - > use_runtime_pm ) {
pm_runtime_get_sync ( dev ) ;
pm_runtime_disable ( dev ) ;
pm_runtime_put_noidle ( dev ) ;
}
2014-09-01 11:35:40 +08:00
if ( c - > slot & & c - > slot - > remove_slot )
c - > slot - > remove_slot ( pdev ) ;
2012-11-23 21:17:34 +01:00
dead = ( sdhci_readl ( c - > host , SDHCI_INT_STATUS ) = = ~ 0 ) ;
sdhci_remove_host ( c - > host , dead ) ;
sdhci_free_host ( c - > host ) ;
return 0 ;
}
# ifdef CONFIG_PM_SLEEP
static int sdhci_acpi_suspend ( struct device * dev )
{
struct sdhci_acpi_host * c = dev_get_drvdata ( dev ) ;
return sdhci_suspend_host ( c - > host ) ;
}
static int sdhci_acpi_resume ( struct device * dev )
{
struct sdhci_acpi_host * c = dev_get_drvdata ( dev ) ;
return sdhci_resume_host ( c - > host ) ;
}
# else
# define sdhci_acpi_suspend NULL
# define sdhci_acpi_resume NULL
# endif
2014-12-05 03:05:33 +01:00
# ifdef CONFIG_PM
2012-11-23 21:17:34 +01:00
static int sdhci_acpi_runtime_suspend ( struct device * dev )
{
struct sdhci_acpi_host * c = dev_get_drvdata ( dev ) ;
return sdhci_runtime_suspend_host ( c - > host ) ;
}
static int sdhci_acpi_runtime_resume ( struct device * dev )
{
struct sdhci_acpi_host * c = dev_get_drvdata ( dev ) ;
return sdhci_runtime_resume_host ( c - > host ) ;
}
# endif
static const struct dev_pm_ops sdhci_acpi_pm_ops = {
. suspend = sdhci_acpi_suspend ,
. resume = sdhci_acpi_resume ,
2014-08-12 17:14:29 +01:00
SET_RUNTIME_PM_OPS ( sdhci_acpi_runtime_suspend ,
2015-01-02 14:47:00 +01:00
sdhci_acpi_runtime_resume , NULL )
2012-11-23 21:17:34 +01:00
} ;
static struct platform_driver sdhci_acpi_driver = {
. driver = {
. name = " sdhci-acpi " ,
. acpi_match_table = sdhci_acpi_ids ,
. pm = & sdhci_acpi_pm_ops ,
} ,
. probe = sdhci_acpi_probe ,
2012-12-21 15:05:47 -08:00
. remove = sdhci_acpi_remove ,
2012-11-23 21:17:34 +01:00
} ;
module_platform_driver ( sdhci_acpi_driver ) ;
MODULE_DESCRIPTION ( " Secure Digital Host Controller Interface ACPI driver " ) ;
MODULE_AUTHOR ( " Adrian Hunter " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;