2010-02-22 09:38:27 +03: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>
# include <linux/mmc/sdio_func.h>
# include <linux/mmc/sdio_ids.h>
# include <linux/mmc/card.h>
2011-02-28 01:13:58 +03:00
# include <linux/mmc/host.h>
2010-05-13 13:43:24 +04:00
# include <linux/gpio.h>
2010-09-16 03:31:35 +04:00
# include <linux/wl12xx.h>
2010-10-08 17:16:16 +04:00
# include <linux/pm_runtime.h>
2010-02-22 09:38:27 +03:00
2010-11-08 14:20:10 +03:00
# include "wl12xx.h"
2010-02-22 09:38:27 +03:00
# include "wl12xx_80211.h"
2010-11-08 14:20:10 +03:00
# include "io.h"
2010-02-22 09:38:27 +03: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-05-14 01:26:18 +04:00
static const struct sdio_device_id wl1271_devices [ ] __devinitconst = {
2010-02-22 09:38:27 +03:00
{ SDIO_DEVICE ( SDIO_VENDOR_ID_TI , SDIO_DEVICE_ID_TI_WL1271 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( sdio , wl1271_devices ) ;
2011-03-31 12:06:58 +04:00
static void wl1271_sdio_set_block_size ( struct wl1271 * wl , unsigned int blksz )
2011-03-14 15:05:13 +03:00
{
sdio_claim_host ( wl - > if_priv ) ;
2011-03-31 12:06:58 +04:00
sdio_set_block_size ( wl - > if_priv , blksz ) ;
2011-03-14 15:05:13 +03:00
sdio_release_host ( wl - > if_priv ) ;
}
2010-02-22 09:38:27 +03:00
static inline struct sdio_func * wl_to_func ( struct wl1271 * wl )
{
return wl - > if_priv ;
}
static struct device * wl1271_sdio_wl_to_dev ( struct wl1271 * wl )
{
return & ( wl_to_func ( wl ) - > dev ) ;
}
2011-03-01 16:14:41 +03:00
static irqreturn_t wl1271_hardirq ( int irq , void * cookie )
2010-02-22 09:38:27 +03:00
{
struct wl1271 * wl = cookie ;
unsigned long flags ;
wl1271_debug ( DEBUG_IRQ , " IRQ " ) ;
/* complete the ELP completion */
spin_lock_irqsave ( & wl - > wl_lock , flags ) ;
2011-03-01 16:14:41 +03:00
set_bit ( WL1271_FLAG_IRQ_RUNNING , & wl - > flags ) ;
2010-02-22 09:38:27 +03:00
if ( wl - > elp_compl ) {
complete ( wl - > elp_compl ) ;
wl - > elp_compl = NULL ;
}
2011-05-13 12:57:11 +04:00
if ( test_bit ( WL1271_FLAG_SUSPENDED , & wl - > flags ) ) {
/* don't enqueue a work right now. mark it as pending */
set_bit ( WL1271_FLAG_PENDING_WORK , & wl - > flags ) ;
wl1271_debug ( DEBUG_IRQ , " should not enqueue work " ) ;
disable_irq_nosync ( wl - > irq ) ;
pm_wakeup_event ( wl1271_sdio_wl_to_dev ( wl ) , 0 ) ;
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
return IRQ_HANDLED ;
}
2010-02-22 09:38:27 +03:00
spin_unlock_irqrestore ( & wl - > wl_lock , flags ) ;
2011-03-01 16:14:41 +03:00
return IRQ_WAKE_THREAD ;
2010-02-22 09:38:27 +03:00
}
static void wl1271_sdio_disable_interrupts ( struct wl1271 * wl )
{
disable_irq ( wl - > irq ) ;
}
static void wl1271_sdio_enable_interrupts ( struct wl1271 * wl )
{
enable_irq ( wl - > irq ) ;
}
static void wl1271_sdio_raw_read ( struct wl1271 * wl , int addr , void * buf ,
2010-03-18 13:26:41 +03:00
size_t len , bool fixed )
2010-02-22 09:38:27 +03:00
{
int ret ;
struct sdio_func * func = wl_to_func ( wl ) ;
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG_ADDR ) ) {
( ( u8 * ) buf ) [ 0 ] = sdio_f0_readb ( func , addr , & ret ) ;
2010-03-18 13:26:41 +03:00
wl1271_debug ( DEBUG_SDIO , " sdio read 52 addr 0x%x, byte 0x%02x " ,
2010-02-22 09:38:27 +03:00
addr , ( ( u8 * ) buf ) [ 0 ] ) ;
} else {
if ( fixed )
ret = sdio_readsb ( func , buf , addr , len ) ;
else
ret = sdio_memcpy_fromio ( func , buf , addr , len ) ;
2010-03-26 13:53:16 +03:00
wl1271_debug ( DEBUG_SDIO , " sdio read 53 addr 0x%x, %zu bytes " ,
2010-02-22 09:38:27 +03:00
addr , len ) ;
2010-03-18 13:26:41 +03:00
wl1271_dump_ascii ( DEBUG_SDIO , " data: " , buf , len ) ;
2010-02-22 09:38:27 +03:00
}
if ( ret )
wl1271_error ( " sdio read failed (%d) " , ret ) ;
}
static void wl1271_sdio_raw_write ( struct wl1271 * wl , int addr , void * buf ,
2010-03-18 13:26:41 +03:00
size_t len , bool fixed )
2010-02-22 09:38:27 +03:00
{
int ret ;
struct sdio_func * func = wl_to_func ( wl ) ;
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG_ADDR ) ) {
sdio_f0_writeb ( func , ( ( u8 * ) buf ) [ 0 ] , addr , & ret ) ;
2010-03-18 13:26:41 +03:00
wl1271_debug ( DEBUG_SDIO , " sdio write 52 addr 0x%x, byte 0x%02x " ,
2010-02-22 09:38:27 +03:00
addr , ( ( u8 * ) buf ) [ 0 ] ) ;
} else {
2010-03-26 13:53:16 +03:00
wl1271_debug ( DEBUG_SDIO , " sdio write 53 addr 0x%x, %zu bytes " ,
2010-02-22 09:38:27 +03:00
addr , len ) ;
2010-03-18 13:26:41 +03:00
wl1271_dump_ascii ( DEBUG_SDIO , " data: " , buf , len ) ;
2010-02-22 09:38:27 +03:00
if ( fixed )
ret = sdio_writesb ( func , addr , buf , len ) ;
else
ret = sdio_memcpy_toio ( func , addr , buf , len ) ;
}
2010-09-07 05:24:21 +04:00
2010-02-22 09:38:27 +03:00
if ( ret )
wl1271_error ( " sdio write failed (%d) " , ret ) ;
2010-09-07 05:24:21 +04:00
}
2010-09-16 03:22:04 +04:00
static int wl1271_sdio_power_on ( struct wl1271 * wl )
2010-09-07 05:24:21 +04:00
{
struct sdio_func * func = wl_to_func ( wl ) ;
2010-10-08 17:16:16 +04:00
int ret ;
2011-05-29 17:36:03 +04: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 ) ;
if ( ret )
goto out ;
2011-06-26 19:00:11 +04: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 17:36:03 +04:00
}
2010-02-22 09:38:27 +03:00
2010-09-07 05:24:21 +04:00
sdio_claim_host ( func ) ;
sdio_enable_func ( func ) ;
2010-09-16 03:22:04 +04:00
2010-10-08 17:16:16 +04:00
out :
return ret ;
2010-09-07 05:24:21 +04:00
}
2010-09-16 03:22:04 +04:00
static int wl1271_sdio_power_off ( struct wl1271 * wl )
2010-09-07 05:24:21 +04:00
{
struct sdio_func * func = wl_to_func ( wl ) ;
2011-02-28 01:13:58 +03:00
int ret ;
2010-09-07 05:24:21 +04:00
sdio_disable_func ( func ) ;
sdio_release_host ( func ) ;
2010-09-16 03:22:04 +04:00
2011-06-26 19:00:11 +04:00
/* Power off the card manually, even if runtime PM is enabled. */
2011-02-28 01:13:58 +03:00
ret = mmc_power_save_host ( func - > card - > host ) ;
if ( ret < 0 )
return ret ;
2011-05-29 17:36:03 +04: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 09:38:27 +03:00
}
2010-09-16 03:22:04 +04:00
static int wl1271_sdio_set_power ( struct wl1271 * wl , bool enable )
2010-03-18 13:26:27 +03:00
{
2010-09-07 05:24:21 +04:00
if ( enable )
2010-09-16 03:22:04 +04:00
return wl1271_sdio_power_on ( wl ) ;
2010-09-07 05:24:21 +04:00
else
2010-09-16 03:22:04 +04:00
return wl1271_sdio_power_off ( wl ) ;
2010-03-18 13:26:27 +03:00
}
2010-02-22 09:38:27 +03:00
static struct wl1271_if_operations sdio_ops = {
. read = wl1271_sdio_raw_read ,
. write = wl1271_sdio_raw_write ,
2010-03-18 13:26:27 +03:00
. power = wl1271_sdio_set_power ,
2010-02-22 09:38:27 +03:00
. dev = wl1271_sdio_wl_to_dev ,
. enable_irq = wl1271_sdio_enable_interrupts ,
2011-03-14 15:05:13 +03:00
. disable_irq = wl1271_sdio_disable_interrupts ,
. set_block_size = wl1271_sdio_set_block_size ,
2010-02-22 09:38:27 +03:00
} ;
static int __devinit wl1271_probe ( struct sdio_func * func ,
const struct sdio_device_id * id )
{
struct ieee80211_hw * hw ;
2010-09-16 03:31:35 +04:00
const struct wl12xx_platform_data * wlan_data ;
2010-02-22 09:38:27 +03:00
struct wl1271 * wl ;
2011-03-31 12:07:01 +04:00
unsigned long irqflags ;
2011-05-13 12:57:12 +04:00
mmc_pm_flag_t mmcflags ;
2010-02-22 09:38:27 +03:00
int ret ;
/* We are only able to handle the wlan function */
if ( func - > num ! = 0x02 )
return - ENODEV ;
hw = wl1271_alloc_hw ( ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
wl = hw - > priv ;
wl - > if_priv = func ;
wl - > if_ops = & sdio_ops ;
/* Grab access to FN0 for ELP reg. */
func - > card - > quirks | = MMC_QUIRK_LENIENT_FN0 ;
2011-03-18 15:49:57 +03:00
/* Use block mode for transferring over one block size of data */
func - > card - > quirks | = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE ;
2010-09-16 03:31:35 +04:00
wlan_data = wl12xx_get_platform_data ( ) ;
if ( IS_ERR ( wlan_data ) ) {
ret = PTR_ERR ( wlan_data ) ;
wl1271_error ( " missing wlan platform data: %d " , ret ) ;
2010-02-22 09:38:27 +03:00
goto out_free ;
}
2010-09-16 03:31:35 +04:00
wl - > irq = wlan_data - > irq ;
2010-09-16 03:31:51 +04:00
wl - > ref_clock = wlan_data - > board_ref_clock ;
2011-03-06 17:32:11 +03:00
wl - > tcxo_clock = wlan_data - > board_tcxo_clock ;
2011-03-31 12:07:01 +04:00
wl - > platform_quirks = wlan_data - > platform_quirks ;
if ( wl - > platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ )
irqflags = IRQF_TRIGGER_RISING ;
else
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT ;
2010-09-16 03:31:35 +04:00
2011-03-01 16:14:41 +03:00
ret = request_threaded_irq ( wl - > irq , wl1271_hardirq , wl1271_irq ,
2011-03-31 12:07:01 +04:00
irqflags ,
2011-03-01 16:14:41 +03:00
DRIVER_NAME , wl ) ;
2010-02-22 09:38:27 +03:00
if ( ret < 0 ) {
wl1271_error ( " request_irq() failed: %d " , ret ) ;
goto out_free ;
}
2011-06-06 13:21:55 +04:00
ret = enable_irq_wake ( wl - > irq ) ;
if ( ! ret ) {
wl - > irq_wake_enabled = true ;
device_init_wakeup ( wl1271_sdio_wl_to_dev ( wl ) , 1 ) ;
2011-05-13 12:57:08 +04:00
2011-06-06 13:21:55 +04:00
/* if sdio can keep power while host is suspended, enable wow */
mmcflags = sdio_get_host_pm_caps ( func ) ;
wl1271_debug ( DEBUG_SDIO , " sdio PM caps = 0x%x " , mmcflags ) ;
2011-05-13 12:57:12 +04:00
2011-06-06 13:21:55 +04:00
if ( mmcflags & MMC_PM_KEEP_POWER )
hw - > wiphy - > wowlan . flags = WIPHY_WOWLAN_ANY ;
}
disable_irq ( wl - > irq ) ;
2011-05-13 12:57:12 +04:00
2010-02-22 09:38:27 +03:00
ret = wl1271_init_ieee80211 ( wl ) ;
if ( ret )
goto out_irq ;
ret = wl1271_register_hw ( wl ) ;
if ( ret )
goto out_irq ;
2010-02-22 09:38:29 +03:00
sdio_set_drvdata ( func , wl ) ;
2010-10-08 17:16:16 +04:00
/* Tell PM core that we don't need the card to be powered now */
pm_runtime_put_noidle ( & func - > dev ) ;
2010-02-22 09:38:27 +03:00
return 0 ;
out_irq :
free_irq ( wl - > irq , wl ) ;
out_free :
2010-03-18 13:26:46 +03:00
wl1271_free_hw ( wl ) ;
2010-02-22 09:38:27 +03:00
return ret ;
}
static void __devexit wl1271_remove ( struct sdio_func * func )
{
struct wl1271 * wl = sdio_get_drvdata ( func ) ;
2010-10-08 17:16:16 +04:00
/* Undo decrement done above in wl1271_probe */
pm_runtime_get_noresume ( & func - > dev ) ;
2010-03-18 13:26:46 +03:00
wl1271_unregister_hw ( wl ) ;
2011-06-06 13:21:55 +04:00
if ( wl - > irq_wake_enabled ) {
device_init_wakeup ( wl1271_sdio_wl_to_dev ( wl ) , 0 ) ;
disable_irq_wake ( wl - > irq ) ;
}
2010-08-13 06:46:48 +04:00
free_irq ( wl - > irq , wl ) ;
2010-03-18 13:26:42 +03:00
wl1271_free_hw ( wl ) ;
2010-02-22 09:38:27 +03:00
}
2011-05-19 00:51:26 +04:00
# ifdef CONFIG_PM
2010-10-08 17:16:27 +04: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 12:57:10 +04: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 ;
wl1271_debug ( DEBUG_MAC80211 , " wl1271 suspend. wow_enabled: %d " ,
wl - > wow_enabled ) ;
/* 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 ) ) {
wl1271_error ( " can't keep power while host "
" is suspended " ) ;
ret = - EINVAL ;
goto out ;
}
/* keep power while host suspended */
ret = sdio_set_host_pm_flags ( func , MMC_PM_KEEP_POWER ) ;
if ( ret ) {
wl1271_error ( " error while trying to keep power " ) ;
goto out ;
}
2011-05-13 12:57:11 +04:00
/* release host */
sdio_release_host ( func ) ;
2011-05-13 12:57:10 +04:00
}
out :
return ret ;
2010-10-08 17:16:27 +04:00
}
static int wl1271_resume ( struct device * dev )
{
2011-05-13 12:57:11 +04:00
struct sdio_func * func = dev_to_sdio_func ( dev ) ;
struct wl1271 * wl = sdio_get_drvdata ( func ) ;
wl1271_debug ( DEBUG_MAC80211 , " wl1271 resume " ) ;
if ( wl - > wow_enabled ) {
/* claim back host */
sdio_claim_host ( func ) ;
}
2010-10-08 17:16:27 +04:00
return 0 ;
}
static const struct dev_pm_ops wl1271_sdio_pm_ops = {
. suspend = wl1271_suspend ,
. resume = wl1271_resume ,
} ;
2011-05-19 00:51:26 +04:00
# endif
2010-10-08 17:16:27 +04:00
2010-02-22 09:38:27 +03:00
static struct sdio_driver wl1271_sdio_driver = {
2010-04-01 12:38:17 +04:00
. name = " wl1271_sdio " ,
2010-02-22 09:38:27 +03:00
. id_table = wl1271_devices ,
. probe = wl1271_probe ,
. remove = __devexit_p ( wl1271_remove ) ,
2011-05-19 00:51:26 +04:00
# ifdef CONFIG_PM
2010-10-08 17:16:27 +04:00
. drv = {
. pm = & wl1271_sdio_pm_ops ,
} ,
2011-05-19 00:51:26 +04:00
# endif
2010-02-22 09:38:27 +03:00
} ;
static int __init wl1271_init ( void )
{
2011-05-14 01:26:20 +04:00
return sdio_register_driver ( & wl1271_sdio_driver ) ;
2010-02-22 09:38:27 +03: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 22:31:39 +04:00
MODULE_AUTHOR ( " Luciano Coelho <coelho@ti.com> " ) ;
2010-02-22 09:38:27 +03:00
MODULE_AUTHOR ( " Juuso Oikarinen <juuso.oikarinen@nokia.com> " ) ;
MODULE_FIRMWARE ( WL1271_FW_NAME ) ;
2011-03-06 17:32:07 +03:00
MODULE_FIRMWARE ( WL128X_FW_NAME ) ;
2011-03-06 17:32:18 +03:00
MODULE_FIRMWARE ( WL127X_AP_FW_NAME ) ;
MODULE_FIRMWARE ( WL128X_AP_FW_NAME ) ;