2009-08-07 13:33:42 +03:00
/*
* wl12xx SDIO routines
*
* 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
*
* Copyright ( C ) 2005 Texas Instruments Incorporated
* Copyright ( C ) 2008 Google Inc
* Copyright ( C ) 2009 Bob Copeland ( me @ bobcopeland . com )
*/
2011-06-06 10:43:46 +00:00
# include <linux/interrupt.h>
2009-08-07 13:33:42 +03:00
# include <linux/module.h>
# include <linux/mod_devicetable.h>
# include <linux/mmc/sdio_func.h>
# include <linux/mmc/sdio_ids.h>
2010-04-15 18:23:23 +03:00
# include <linux/platform_device.h>
2010-09-16 13:16:02 +02:00
# include <linux/wl12xx.h>
2010-04-16 13:22:12 +03:00
# include <linux/irq.h>
2010-11-08 15:29:36 +02:00
# include <linux/pm_runtime.h>
2014-02-15 00:05:53 +01:00
# include <linux/gpio.h>
2009-08-07 13:33:42 +03:00
# include "wl1251.h"
# ifndef SDIO_VENDOR_ID_TI
# define SDIO_VENDOR_ID_TI 0x104c
# endif
# ifndef SDIO_DEVICE_ID_TI_WL1251
# define SDIO_DEVICE_ID_TI_WL1251 0x9066
# endif
2010-06-08 14:33:31 +03:00
struct wl1251_sdio {
struct sdio_func * func ;
u32 elp_val ;
} ;
2009-08-07 13:33:42 +03:00
static struct sdio_func * wl_to_func ( struct wl1251 * wl )
{
2010-06-08 14:33:31 +03:00
struct wl1251_sdio * wl_sdio = wl - > if_priv ;
return wl_sdio - > func ;
2009-08-07 13:33:42 +03:00
}
static void wl1251_sdio_interrupt ( struct sdio_func * func )
{
2009-08-07 13:33:49 +03:00
struct wl1251 * wl = sdio_get_drvdata ( func ) ;
wl1251_debug ( DEBUG_IRQ , " IRQ " ) ;
/* FIXME should be synchronous for sdio */
2009-08-07 13:35:04 +03:00
ieee80211_queue_work ( wl - > hw , & wl - > irq_work ) ;
2009-08-07 13:33:42 +03:00
}
static const struct sdio_device_id wl1251_devices [ ] = {
{ SDIO_DEVICE ( SDIO_VENDOR_ID_TI , SDIO_DEVICE_ID_TI_WL1251 ) } ,
{ }
} ;
MODULE_DEVICE_TABLE ( sdio , wl1251_devices ) ;
2010-03-12 12:28:41 +02:00
static void wl1251_sdio_read ( struct wl1251 * wl , int addr ,
void * buf , size_t len )
2009-08-07 13:33:42 +03:00
{
int ret ;
struct sdio_func * func = wl_to_func ( wl ) ;
sdio_claim_host ( func ) ;
ret = sdio_memcpy_fromio ( func , buf , addr , len ) ;
if ( ret )
wl1251_error ( " sdio read failed (%d) " , ret ) ;
sdio_release_host ( func ) ;
}
2010-03-12 12:28:41 +02:00
static void wl1251_sdio_write ( struct wl1251 * wl , int addr ,
void * buf , size_t len )
2009-08-07 13:33:42 +03:00
{
int ret ;
struct sdio_func * func = wl_to_func ( wl ) ;
sdio_claim_host ( func ) ;
ret = sdio_memcpy_toio ( func , addr , buf , len ) ;
if ( ret )
wl1251_error ( " sdio write failed (%d) " , ret ) ;
sdio_release_host ( func ) ;
}
2010-03-11 17:44:57 +02:00
static void wl1251_sdio_read_elp ( struct wl1251 * wl , int addr , u32 * val )
{
int ret = 0 ;
2010-06-08 14:33:31 +03:00
struct wl1251_sdio * wl_sdio = wl - > if_priv ;
struct sdio_func * func = wl_sdio - > func ;
/*
* The hardware only supports RAW ( read after write ) access for
* reading , regular sdio_readb won ' t work here ( it interprets
* the unused bits of CMD52 as write data even if we send read
* request ) .
*/
2010-03-11 17:44:57 +02:00
sdio_claim_host ( func ) ;
2010-06-08 14:33:31 +03:00
* val = sdio_writeb_readb ( func , wl_sdio - > elp_val , addr , & ret ) ;
2010-03-11 17:44:57 +02:00
sdio_release_host ( func ) ;
if ( ret )
wl1251_error ( " sdio_readb failed (%d) " , ret ) ;
}
static void wl1251_sdio_write_elp ( struct wl1251 * wl , int addr , u32 val )
{
int ret = 0 ;
2010-06-08 14:33:31 +03:00
struct wl1251_sdio * wl_sdio = wl - > if_priv ;
struct sdio_func * func = wl_sdio - > func ;
2010-03-11 17:44:57 +02:00
sdio_claim_host ( func ) ;
sdio_writeb ( func , val , addr , & ret ) ;
sdio_release_host ( func ) ;
if ( ret )
wl1251_error ( " sdio_writeb failed (%d) " , ret ) ;
2010-06-08 14:33:31 +03:00
else
wl_sdio - > elp_val = val ;
2010-03-11 17:44:57 +02:00
}
2010-03-12 12:28:41 +02:00
static void wl1251_sdio_reset ( struct wl1251 * wl )
2009-08-07 13:33:42 +03:00
{
}
2009-08-07 13:33:49 +03:00
static void wl1251_sdio_enable_irq ( struct wl1251 * wl )
{
struct sdio_func * func = wl_to_func ( wl ) ;
sdio_claim_host ( func ) ;
sdio_claim_irq ( func , wl1251_sdio_interrupt ) ;
sdio_release_host ( func ) ;
}
static void wl1251_sdio_disable_irq ( struct wl1251 * wl )
{
struct sdio_func * func = wl_to_func ( wl ) ;
sdio_claim_host ( func ) ;
sdio_release_irq ( func ) ;
sdio_release_host ( func ) ;
}
2010-04-16 13:22:12 +03:00
/* Interrupts when using dedicated WLAN_IRQ pin */
static irqreturn_t wl1251_line_irq ( int irq , void * cookie )
{
struct wl1251 * wl = cookie ;
ieee80211_queue_work ( wl - > hw , & wl - > irq_work ) ;
return IRQ_HANDLED ;
}
static void wl1251_enable_line_irq ( struct wl1251 * wl )
{
return enable_irq ( wl - > irq ) ;
}
static void wl1251_disable_line_irq ( struct wl1251 * wl )
{
return disable_irq ( wl - > irq ) ;
}
2010-11-04 00:13:47 +02:00
static int wl1251_sdio_set_power ( struct wl1251 * wl , bool enable )
2009-08-07 13:33:42 +03:00
{
2010-11-08 15:29:36 +02:00
struct sdio_func * func = wl_to_func ( wl ) ;
int ret ;
2010-11-04 00:13:47 +02:00
2010-11-08 15:29:36 +02:00
if ( enable ) {
/*
* Power is controlled by runtime PM , but we still call board
* callback in case it wants to do any additional setup ,
* for example enabling clock buffer for the module .
*/
2014-02-15 00:05:53 +01:00
if ( gpio_is_valid ( wl - > power_gpio ) )
gpio_set_value ( wl - > power_gpio , true ) ;
2010-11-08 15:29:36 +02:00
ret = pm_runtime_get_sync ( & func - > dev ) ;
2013-02-28 15:51:32 +08:00
if ( ret < 0 ) {
pm_runtime_put_sync ( & func - > dev ) ;
2010-11-08 15:29:36 +02:00
goto out ;
2013-02-28 15:51:32 +08:00
}
2010-11-08 15:29:36 +02:00
sdio_claim_host ( func ) ;
sdio_enable_func ( func ) ;
sdio_release_host ( func ) ;
} else {
sdio_claim_host ( func ) ;
sdio_disable_func ( func ) ;
sdio_release_host ( func ) ;
ret = pm_runtime_put_sync ( & func - > dev ) ;
if ( ret < 0 )
goto out ;
2014-02-15 00:05:53 +01:00
if ( gpio_is_valid ( wl - > power_gpio ) )
gpio_set_value ( wl - > power_gpio , false ) ;
2010-11-08 15:29:36 +02:00
}
out :
return ret ;
2009-08-07 13:33:42 +03:00
}
2010-04-16 13:22:12 +03:00
static struct wl1251_if_operations wl1251_sdio_ops = {
2009-08-07 13:33:42 +03:00
. read = wl1251_sdio_read ,
. write = wl1251_sdio_write ,
2010-03-11 17:44:57 +02:00
. write_elp = wl1251_sdio_write_elp ,
. read_elp = wl1251_sdio_read_elp ,
2009-08-07 13:33:42 +03:00
. reset = wl1251_sdio_reset ,
2010-11-04 00:13:47 +02:00
. power = wl1251_sdio_set_power ,
2009-08-07 13:33:42 +03:00
} ;
2010-03-12 12:28:41 +02:00
static int wl1251_sdio_probe ( struct sdio_func * func ,
const struct sdio_device_id * id )
2009-08-07 13:33:42 +03:00
{
int ret ;
struct wl1251 * wl ;
struct ieee80211_hw * hw ;
2010-06-08 14:33:31 +03:00
struct wl1251_sdio * wl_sdio ;
2014-02-15 00:05:52 +01:00
const struct wl1251_platform_data * wl1251_board_data ;
2009-08-07 13:33:42 +03:00
hw = wl1251_alloc_hw ( ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
wl = hw - > priv ;
2010-06-08 14:33:31 +03:00
wl_sdio = kzalloc ( sizeof ( * wl_sdio ) , GFP_KERNEL ) ;
if ( wl_sdio = = NULL ) {
ret = - ENOMEM ;
goto out_free_hw ;
}
2009-08-07 13:33:42 +03:00
sdio_claim_host ( func ) ;
ret = sdio_enable_func ( func ) ;
if ( ret )
goto release ;
sdio_set_block_size ( func , 512 ) ;
2010-04-16 13:22:12 +03:00
sdio_release_host ( func ) ;
2009-08-07 13:33:42 +03:00
SET_IEEE80211_DEV ( hw , & func - > dev ) ;
2010-06-08 14:33:31 +03:00
wl_sdio - > func = func ;
wl - > if_priv = wl_sdio ;
2009-08-07 13:33:42 +03:00
wl - > if_ops = & wl1251_sdio_ops ;
2014-02-15 00:05:52 +01:00
wl1251_board_data = wl1251_get_platform_data ( ) ;
if ( ! IS_ERR ( wl1251_board_data ) ) {
2014-02-15 00:05:53 +01:00
wl - > power_gpio = wl1251_board_data - > power_gpio ;
2014-02-15 00:05:52 +01:00
wl - > irq = wl1251_board_data - > irq ;
wl - > use_eeprom = wl1251_board_data - > use_eeprom ;
2010-04-15 18:23:23 +03:00
}
2014-02-15 00:05:53 +01:00
if ( gpio_is_valid ( wl - > power_gpio ) ) {
ret = devm_gpio_request ( & func - > dev , wl - > power_gpio ,
" wl1251 power " ) ;
if ( ret ) {
wl1251_error ( " Failed to request gpio: %d \n " , ret ) ;
goto disable ;
}
}
2010-04-16 13:22:12 +03:00
if ( wl - > irq ) {
2012-05-18 03:04:08 +03:00
irq_set_status_flags ( wl - > irq , IRQ_NOAUTOEN ) ;
2010-04-16 13:22:12 +03:00
ret = request_irq ( wl - > irq , wl1251_line_irq , 0 , " wl1251 " , wl ) ;
if ( ret < 0 ) {
wl1251_error ( " request_irq() failed: %d " , ret ) ;
goto disable ;
}
2011-03-28 17:49:12 +02:00
irq_set_irq_type ( wl - > irq , IRQ_TYPE_EDGE_RISING ) ;
2010-04-16 13:22:12 +03:00
wl1251_sdio_ops . enable_irq = wl1251_enable_line_irq ;
wl1251_sdio_ops . disable_irq = wl1251_disable_line_irq ;
wl1251_info ( " using dedicated interrupt line " ) ;
} else {
wl1251_sdio_ops . enable_irq = wl1251_sdio_enable_irq ;
wl1251_sdio_ops . disable_irq = wl1251_sdio_disable_irq ;
wl1251_info ( " using SDIO interrupt " ) ;
}
2009-08-07 13:33:42 +03:00
ret = wl1251_init_ieee80211 ( wl ) ;
if ( ret )
2010-04-16 13:22:12 +03:00
goto out_free_irq ;
2009-08-07 13:33:42 +03:00
sdio_set_drvdata ( func , wl ) ;
2010-11-08 15:29:36 +02:00
/* Tell PM core that we don't need the card to be powered now */
pm_runtime_put_noidle ( & func - > dev ) ;
2009-08-07 13:33:42 +03:00
return ret ;
2010-04-16 13:22:12 +03:00
out_free_irq :
if ( wl - > irq )
free_irq ( wl - > irq , wl ) ;
2009-08-07 13:33:42 +03:00
disable :
2009-08-07 13:33:49 +03:00
sdio_claim_host ( func ) ;
2009-08-07 13:33:42 +03:00
sdio_disable_func ( func ) ;
release :
sdio_release_host ( func ) ;
2010-06-08 14:33:31 +03:00
kfree ( wl_sdio ) ;
out_free_hw :
2010-06-05 02:25:47 +03:00
wl1251_free_hw ( wl ) ;
2009-08-07 13:33:42 +03:00
return ret ;
}
2012-12-03 09:56:42 -05:00
static void wl1251_sdio_remove ( struct sdio_func * func )
2009-08-07 13:33:42 +03:00
{
struct wl1251 * wl = sdio_get_drvdata ( func ) ;
2010-06-08 14:33:31 +03:00
struct wl1251_sdio * wl_sdio = wl - > if_priv ;
2009-08-07 13:33:42 +03:00
2010-11-08 15:29:36 +02:00
/* Undo decrement done above in wl1251_probe */
pm_runtime_get_noresume ( & func - > dev ) ;
2010-04-16 13:22:12 +03:00
if ( wl - > irq )
free_irq ( wl - > irq , wl ) ;
2009-08-07 13:33:42 +03:00
wl1251_free_hw ( wl ) ;
2012-04-26 23:07:43 +03:00
kfree ( wl_sdio ) ;
2009-08-07 13:33:42 +03:00
sdio_claim_host ( func ) ;
sdio_release_irq ( func ) ;
sdio_disable_func ( func ) ;
sdio_release_host ( func ) ;
}
2010-11-08 15:29:36 +02:00
static int wl1251_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 .
*/
return 0 ;
}
static int wl1251_resume ( struct device * dev )
{
return 0 ;
}
static const struct dev_pm_ops wl1251_sdio_pm_ops = {
. suspend = wl1251_suspend ,
. resume = wl1251_resume ,
} ;
2009-08-07 13:33:42 +03:00
static struct sdio_driver wl1251_sdio_driver = {
. name = " wl1251_sdio " ,
. id_table = wl1251_devices ,
. probe = wl1251_sdio_probe ,
2012-12-03 09:56:42 -05:00
. remove = wl1251_sdio_remove ,
2010-11-08 15:29:36 +02:00
. drv . pm = & wl1251_sdio_pm_ops ,
2009-08-07 13:33:42 +03:00
} ;
static int __init wl1251_sdio_init ( void )
{
int err ;
err = sdio_register_driver ( & wl1251_sdio_driver ) ;
if ( err )
wl1251_error ( " failed to register sdio driver: %d " , err ) ;
return err ;
}
static void __exit wl1251_sdio_exit ( void )
{
sdio_unregister_driver ( & wl1251_sdio_driver ) ;
wl1251_notice ( " unloaded " ) ;
}
module_init ( wl1251_sdio_init ) ;
module_exit ( wl1251_sdio_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2010-08-22 22:46:15 +03:00
MODULE_AUTHOR ( " Kalle Valo <kvalo@adurom.com> " ) ;