2010-02-22 08:38:27 +02:00
/*
* This file is part of wl1271
*
* Copyright ( C ) 2009 - 2010 Nokia Corporation
*
* Contact : Luciano Coelho < luciano . coelho @ nokia . com >
*
* 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 .
*
* This program is distributed in the hope that 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/irq.h>
# include <linux/module.h>
# include <linux/vmalloc.h>
2011-10-05 09:00:12 +03:00
# include <linux/platform_device.h>
2010-02-22 08:38:27 +02:00
# include <linux/mmc/sdio_func.h>
# include <linux/mmc/sdio_ids.h>
# include <linux/mmc/card.h>
2011-02-28 00:13:58 +02:00
# include <linux/mmc/host.h>
2010-05-13 12:43:24 +03:00
# include <linux/gpio.h>
2010-09-16 01:31:35 +02:00
# include <linux/wl12xx.h>
2010-10-08 16:16:16 +03:00
# include <linux/pm_runtime.h>
2010-02-22 08:38:27 +02:00
2010-11-08 11:20:10 +00:00
# include "wl12xx.h"
2010-02-22 08:38:27 +02:00
# include "wl12xx_80211.h"
2010-11-08 11:20:10 +00:00
# include "io.h"
2010-02-22 08:38:27 +02:00
# ifndef SDIO_VENDOR_ID_TI
# define SDIO_VENDOR_ID_TI 0x0097
# endif
# ifndef SDIO_DEVICE_ID_TI_WL1271
# define SDIO_DEVICE_ID_TI_WL1271 0x4076
# endif
2011-10-04 23:10:28 +03:00
struct wl12xx_sdio_glue {
struct device * dev ;
2011-10-05 09:00:12 +03:00
struct platform_device * core ;
2011-10-04 23:10:28 +03:00
} ;
2011-05-14 00:26:18 +03:00
static const struct sdio_device_id wl1271_devices [ ] __devinitconst = {
2010-02-22 08:38:27 +02:00
{ SDIO_DEVICE ( SDIO_VENDOR_ID_TI , SDIO_DEVICE_ID_TI_WL1271 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( sdio , wl1271_devices ) ;
2011-10-06 10:07:44 +03:00
static void wl1271_sdio_set_block_size ( struct device * child ,
unsigned int blksz )
2011-03-14 14:05:13 +02:00
{
2011-10-06 10:07:44 +03:00
struct wl12xx_sdio_glue * glue = dev_get_drvdata ( child - > parent ) ;
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2010-02-22 08:38:27 +02:00
2011-10-06 10:07:44 +03:00
sdio_claim_host ( func ) ;
sdio_set_block_size ( func , blksz ) ;
sdio_release_host ( func ) ;
2010-02-22 08:38:27 +02:00
}
2011-10-06 10:07:44 +03:00
static void wl12xx_sdio_raw_read ( struct device * child , int addr , void * buf ,
2010-03-18 12:26:41 +02:00
size_t len , bool fixed )
2010-02-22 08:38:27 +02:00
{
int ret ;
2011-10-06 10:07:44 +03:00
struct wl12xx_sdio_glue * glue = dev_get_drvdata ( child - > parent ) ;
2011-10-04 23:10:28 +03:00
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2010-02-22 08:38:27 +02:00
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG_ADDR ) ) {
( ( u8 * ) buf ) [ 0 ] = sdio_f0_readb ( func , addr , & ret ) ;
2011-10-07 14:14:25 +03:00
dev_dbg ( child - > parent , " sdio read 52 addr 0x%x, byte 0x%02x \n " ,
addr , ( ( u8 * ) buf ) [ 0 ] ) ;
2010-02-22 08:38:27 +02:00
} else {
if ( fixed )
ret = sdio_readsb ( func , buf , addr , len ) ;
else
ret = sdio_memcpy_fromio ( func , buf , addr , len ) ;
2011-10-07 14:14:25 +03:00
dev_dbg ( child - > parent , " sdio read 53 addr 0x%x, %zu bytes \n " ,
addr , len ) ;
2010-02-22 08:38:27 +02:00
}
if ( ret )
2011-10-07 14:14:25 +03:00
dev_err ( child - > parent , " sdio read failed (%d) \n " , ret ) ;
2010-02-22 08:38:27 +02:00
}
2011-10-06 10:07:44 +03:00
static void wl12xx_sdio_raw_write ( struct device * child , int addr , void * buf ,
2010-03-18 12:26:41 +02:00
size_t len , bool fixed )
2010-02-22 08:38:27 +02:00
{
int ret ;
2011-10-06 10:07:44 +03:00
struct wl12xx_sdio_glue * glue = dev_get_drvdata ( child - > parent ) ;
2011-10-04 23:10:28 +03:00
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2010-02-22 08:38:27 +02:00
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG_ADDR ) ) {
sdio_f0_writeb ( func , ( ( u8 * ) buf ) [ 0 ] , addr , & ret ) ;
2011-10-07 14:14:25 +03:00
dev_dbg ( child - > parent , " sdio write 52 addr 0x%x, byte 0x%02x \n " ,
addr , ( ( u8 * ) buf ) [ 0 ] ) ;
2010-02-22 08:38:27 +02:00
} else {
2011-10-07 14:14:25 +03:00
dev_dbg ( child - > parent , " sdio write 53 addr 0x%x, %zu bytes \n " ,
addr , len ) ;
2010-02-22 08:38:27 +02:00
if ( fixed )
ret = sdio_writesb ( func , addr , buf , len ) ;
else
ret = sdio_memcpy_toio ( func , addr , buf , len ) ;
}
2010-09-07 04:24:21 +03:00
2010-02-22 08:38:27 +02:00
if ( ret )
2011-10-07 14:14:25 +03:00
dev_err ( child - > parent , " sdio write failed (%d) \n " , ret ) ;
2010-09-07 04:24:21 +03:00
}
2011-10-06 10:07:44 +03:00
static int wl12xx_sdio_power_on ( struct wl12xx_sdio_glue * glue )
2010-09-07 04:24:21 +03:00
{
2010-10-08 16:16:16 +03:00
int ret ;
2011-10-04 23:10:28 +03:00
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2010-10-08 16:16:16 +03:00
2011-05-29 16:36:03 +03:00
/* If enabled, tell runtime PM not to power off the card */
if ( pm_runtime_enabled ( & func - > dev ) ) {
ret = pm_runtime_get_sync ( & func - > dev ) ;
2011-08-22 23:19:49 +03:00
if ( ret < 0 )
2011-05-29 16:36:03 +03:00
goto out ;
2011-06-26 18:00:11 +03:00
} else {
/* Runtime PM is disabled: power up the card manually */
ret = mmc_power_restore_host ( func - > card - > host ) ;
if ( ret < 0 )
goto out ;
2011-05-29 16:36:03 +03:00
}
2010-02-22 08:38:27 +02:00
2010-09-07 04:24:21 +03:00
sdio_claim_host ( func ) ;
sdio_enable_func ( func ) ;
2010-09-16 01:22:04 +02:00
2010-10-08 16:16:16 +03:00
out :
return ret ;
2010-09-07 04:24:21 +03:00
}
2011-10-06 10:07:44 +03:00
static int wl12xx_sdio_power_off ( struct wl12xx_sdio_glue * glue )
2010-09-07 04:24:21 +03:00
{
2011-02-28 00:13:58 +02:00
int ret ;
2011-10-04 23:10:28 +03:00
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2010-09-07 04:24:21 +03:00
sdio_disable_func ( func ) ;
sdio_release_host ( func ) ;
2010-09-16 01:22:04 +02:00
2011-06-26 18:00:11 +03:00
/* Power off the card manually, even if runtime PM is enabled. */
2011-02-28 00:13:58 +02:00
ret = mmc_power_save_host ( func - > card - > host ) ;
if ( ret < 0 )
return ret ;
2011-05-29 16:36:03 +03:00
/* If enabled, let runtime PM know the card is powered off */
if ( pm_runtime_enabled ( & func - > dev ) )
ret = pm_runtime_put_sync ( & func - > dev ) ;
return ret ;
2010-02-22 08:38:27 +02:00
}
2011-10-06 10:07:44 +03:00
static int wl12xx_sdio_set_power ( struct device * child , bool enable )
2010-03-18 12:26:27 +02:00
{
2011-10-06 10:07:44 +03:00
struct wl12xx_sdio_glue * glue = dev_get_drvdata ( child - > parent ) ;
2010-09-07 04:24:21 +03:00
if ( enable )
2011-10-06 10:07:44 +03:00
return wl12xx_sdio_power_on ( glue ) ;
2010-09-07 04:24:21 +03:00
else
2011-10-06 10:07:44 +03:00
return wl12xx_sdio_power_off ( glue ) ;
2010-03-18 12:26:27 +02:00
}
2010-02-22 08:38:27 +02:00
static struct wl1271_if_operations sdio_ops = {
2011-10-06 10:07:44 +03:00
. read = wl12xx_sdio_raw_read ,
. write = wl12xx_sdio_raw_write ,
. power = wl12xx_sdio_set_power ,
2011-03-14 14:05:13 +02:00
. set_block_size = wl1271_sdio_set_block_size ,
2010-02-22 08:38:27 +02:00
} ;
static int __devinit wl1271_probe ( struct sdio_func * func ,
const struct sdio_device_id * id )
{
2011-10-06 10:07:44 +03:00
struct wl12xx_platform_data * wlan_data ;
2011-10-04 23:10:28 +03:00
struct wl12xx_sdio_glue * glue ;
2011-10-05 09:00:12 +03:00
struct resource res [ 1 ] ;
2011-05-13 11:57:12 +03:00
mmc_pm_flag_t mmcflags ;
2011-10-04 23:10:28 +03:00
int ret = - ENOMEM ;
2010-02-22 08:38:27 +02:00
/* We are only able to handle the wlan function */
if ( func - > num ! = 0x02 )
return - ENODEV ;
2011-10-04 23:10:28 +03:00
glue = kzalloc ( sizeof ( * glue ) , GFP_KERNEL ) ;
if ( ! glue ) {
2011-10-07 14:14:25 +03:00
dev_err ( & func - > dev , " can't allocate glue \n " ) ;
2011-10-04 23:10:28 +03:00
goto out ;
}
glue - > dev = & func - > dev ;
2010-02-22 08:38:27 +02:00
/* Grab access to FN0 for ELP reg. */
func - > card - > quirks | = MMC_QUIRK_LENIENT_FN0 ;
2011-03-18 14:49:57 +02:00
/* Use block mode for transferring over one block size of data */
func - > card - > quirks | = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE ;
2010-09-16 01:31:35 +02:00
wlan_data = wl12xx_get_platform_data ( ) ;
if ( IS_ERR ( wlan_data ) ) {
ret = PTR_ERR ( wlan_data ) ;
2011-10-07 14:14:25 +03:00
dev_err ( glue - > dev , " missing wlan platform data: %d \n " , ret ) ;
2011-10-06 10:07:44 +03:00
goto out_free_glue ;
2010-02-22 08:38:27 +02:00
}
2011-10-06 10:07:44 +03:00
/* if sdio can keep power while host is suspended, enable wow */
mmcflags = sdio_get_host_pm_caps ( func ) ;
2011-10-07 14:14:25 +03:00
dev_dbg ( glue - > dev , " sdio PM caps = 0x%x \n " , mmcflags ) ;
2011-05-13 11:57:08 +03:00
2011-10-06 10:07:44 +03:00
if ( mmcflags & MMC_PM_KEEP_POWER )
wlan_data - > pwr_in_suspend = true ;
2011-05-13 11:57:12 +03:00
2011-10-06 10:07:44 +03:00
wlan_data - > ops = & sdio_ops ;
2010-02-22 08:38:27 +02:00
2011-10-04 23:10:28 +03:00
sdio_set_drvdata ( func , glue ) ;
2010-02-22 08:38:29 +02:00
2010-10-08 16:16:16 +03:00
/* Tell PM core that we don't need the card to be powered now */
pm_runtime_put_noidle ( & func - > dev ) ;
2011-10-07 15:54:15 +03:00
glue - > core = platform_device_alloc ( " wl12xx " , - 1 ) ;
2011-10-05 09:00:12 +03:00
if ( ! glue - > core ) {
2011-10-07 14:14:25 +03:00
dev_err ( glue - > dev , " can't allocate platform_device " ) ;
2011-10-05 09:00:12 +03:00
ret = - ENOMEM ;
2011-10-06 10:07:44 +03:00
goto out_free_glue ;
2011-10-05 09:00:12 +03:00
}
glue - > core - > dev . parent = & func - > dev ;
memset ( res , 0x00 , sizeof ( res ) ) ;
res [ 0 ] . start = wlan_data - > irq ;
res [ 0 ] . flags = IORESOURCE_IRQ ;
res [ 0 ] . name = " irq " ;
ret = platform_device_add_resources ( glue - > core , res , ARRAY_SIZE ( res ) ) ;
if ( ret ) {
2011-10-07 14:14:25 +03:00
dev_err ( glue - > dev , " can't add resources \n " ) ;
2011-10-05 09:00:12 +03:00
goto out_dev_put ;
}
ret = platform_device_add_data ( glue - > core , wlan_data ,
sizeof ( * wlan_data ) ) ;
if ( ret ) {
2011-10-07 14:14:25 +03:00
dev_err ( glue - > dev , " can't add platform data \n " ) ;
2011-10-05 09:00:12 +03:00
goto out_dev_put ;
}
ret = platform_device_add ( glue - > core ) ;
if ( ret ) {
2011-10-07 14:14:25 +03:00
dev_err ( glue - > dev , " can't add platform device \n " ) ;
2011-10-05 09:00:12 +03:00
goto out_dev_put ;
}
2010-02-22 08:38:27 +02:00
return 0 ;
2011-10-05 09:00:12 +03:00
out_dev_put :
platform_device_put ( glue - > core ) ;
2011-10-04 23:10:28 +03:00
out_free_glue :
kfree ( glue ) ;
2011-10-06 10:07:44 +03:00
2011-10-04 23:10:28 +03:00
out :
2010-02-22 08:38:27 +02:00
return ret ;
}
static void __devexit wl1271_remove ( struct sdio_func * func )
{
2011-10-04 23:10:28 +03:00
struct wl12xx_sdio_glue * glue = sdio_get_drvdata ( func ) ;
2010-02-22 08:38:27 +02:00
2010-10-08 16:16:16 +03:00
/* Undo decrement done above in wl1271_probe */
pm_runtime_get_noresume ( & func - > dev ) ;
2011-10-05 09:00:12 +03:00
platform_device_del ( glue - > core ) ;
platform_device_put ( glue - > core ) ;
2011-10-04 23:10:28 +03:00
kfree ( glue ) ;
2010-02-22 08:38:27 +02:00
}
2011-05-18 16:51:26 -04:00
# ifdef CONFIG_PM
2010-10-08 16:16:27 +03:00
static int wl1271_suspend ( struct device * dev )
{
/* Tell MMC/SDIO core it's OK to power down the card
* ( if it isn ' t already ) , but not to remove it completely */
2011-05-13 11:57:10 +03:00
struct sdio_func * func = dev_to_sdio_func ( dev ) ;
struct wl1271 * wl = sdio_get_drvdata ( func ) ;
mmc_pm_flag_t sdio_flags ;
int ret = 0 ;
2011-10-07 14:14:25 +03:00
dev_dbg ( dev , " wl1271 suspend. wow_enabled: %d \n " ,
wl - > wow_enabled ) ;
2011-05-13 11:57:10 +03:00
/* check whether sdio should keep power */
if ( wl - > wow_enabled ) {
sdio_flags = sdio_get_host_pm_caps ( func ) ;
if ( ! ( sdio_flags & MMC_PM_KEEP_POWER ) ) {
2011-10-07 14:14:25 +03:00
dev_err ( dev , " can't keep power while host "
" is suspended \n " ) ;
2011-05-13 11:57:10 +03:00
ret = - EINVAL ;
goto out ;
}
/* keep power while host suspended */
ret = sdio_set_host_pm_flags ( func , MMC_PM_KEEP_POWER ) ;
if ( ret ) {
2011-10-07 14:14:25 +03:00
dev_err ( dev , " error while trying to keep power \n " ) ;
2011-05-13 11:57:10 +03:00
goto out ;
}
2011-05-13 11:57:11 +03:00
/* release host */
sdio_release_host ( func ) ;
2011-05-13 11:57:10 +03:00
}
out :
return ret ;
2010-10-08 16:16:27 +03:00
}
static int wl1271_resume ( struct device * dev )
{
2011-05-13 11:57:11 +03:00
struct sdio_func * func = dev_to_sdio_func ( dev ) ;
struct wl1271 * wl = sdio_get_drvdata ( func ) ;
2011-10-07 14:14:25 +03:00
dev_dbg ( dev , " wl1271 resume \n " ) ;
2011-05-13 11:57:11 +03:00
if ( wl - > wow_enabled ) {
/* claim back host */
sdio_claim_host ( func ) ;
}
2010-10-08 16:16:27 +03:00
return 0 ;
}
static const struct dev_pm_ops wl1271_sdio_pm_ops = {
. suspend = wl1271_suspend ,
. resume = wl1271_resume ,
} ;
2011-05-18 16:51:26 -04:00
# endif
2010-10-08 16:16:27 +03:00
2010-02-22 08:38:27 +02:00
static struct sdio_driver wl1271_sdio_driver = {
2010-04-01 11:38:17 +03:00
. name = " wl1271_sdio " ,
2010-02-22 08:38:27 +02:00
. id_table = wl1271_devices ,
. probe = wl1271_probe ,
. remove = __devexit_p ( wl1271_remove ) ,
2011-05-18 16:51:26 -04:00
# ifdef CONFIG_PM
2010-10-08 16:16:27 +03:00
. drv = {
. pm = & wl1271_sdio_pm_ops ,
} ,
2011-05-18 16:51:26 -04:00
# endif
2010-02-22 08:38:27 +02:00
} ;
static int __init wl1271_init ( void )
{
2011-05-14 00:26:20 +03:00
return sdio_register_driver ( & wl1271_sdio_driver ) ;
2010-02-22 08:38:27 +02:00
}
static void __exit wl1271_exit ( void )
{
sdio_unregister_driver ( & wl1271_sdio_driver ) ;
}
module_init ( wl1271_init ) ;
module_exit ( wl1271_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2011-03-30 21:31:39 +03:00
MODULE_AUTHOR ( " Luciano Coelho <coelho@ti.com> " ) ;
2010-02-22 08:38:27 +02:00
MODULE_AUTHOR ( " Juuso Oikarinen <juuso.oikarinen@nokia.com> " ) ;
2011-08-17 10:45:48 +03:00
MODULE_FIRMWARE ( WL127X_FW_NAME ) ;
2011-03-06 16:32:07 +02:00
MODULE_FIRMWARE ( WL128X_FW_NAME ) ;