2019-05-29 16:57:50 -07:00
// SPDX-License-Identifier: GPL-2.0-only
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 >
*/
# 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>
2012-05-10 12:13:07 +03:00
# include <linux/mmc/sdio.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-10-08 16:16:16 +03:00
# include <linux/pm_runtime.h>
2012-05-10 12:13:57 +03:00
# include <linux/printk.h>
2015-03-18 18:38:28 +02:00
# include <linux/of.h>
# include <linux/of_irq.h>
2010-02-22 08:38:27 +02:00
2011-11-21 19:25:24 +02:00
# include "wlcore.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
2012-05-10 12:13:57 +03:00
static bool dump = false ;
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
} ;
2012-12-03 09:56:42 -05:00
static const struct sdio_device_id wl1271_devices [ ] = {
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
}
2012-06-20 00:03:46 +03:00
static int __must_check wl12xx_sdio_raw_read ( struct device * child , int addr ,
void * buf , 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
2012-01-26 14:12:31 +02:00
sdio_claim_host ( func ) ;
2011-11-29 13:38:37 +02:00
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG ) ) {
2010-02-22 08:38:27 +02:00
( ( 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
}
2012-01-26 14:12:31 +02:00
sdio_release_host ( func ) ;
2012-06-17 20:30:05 +03:00
if ( WARN_ON ( ret ) )
2011-10-07 14:14:25 +03:00
dev_err ( child - > parent , " sdio read failed (%d) \n " , ret ) ;
2012-06-17 20:30:05 +03:00
2017-01-26 17:35:13 +02:00
if ( unlikely ( dump ) ) {
printk ( KERN_DEBUG " wlcore_sdio: READ from 0x%04x \n " , addr ) ;
print_hex_dump ( KERN_DEBUG , " wlcore_sdio: READ " ,
DUMP_PREFIX_OFFSET , 16 , 1 ,
buf , len , false ) ;
}
2012-06-17 20:30:05 +03:00
return ret ;
2010-02-22 08:38:27 +02:00
}
2012-06-20 00:03:46 +03:00
static int __must_check wl12xx_sdio_raw_write ( struct device * child , int addr ,
void * buf , 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
2012-01-26 14:12:31 +02:00
sdio_claim_host ( func ) ;
2012-05-10 12:13:57 +03:00
if ( unlikely ( dump ) ) {
printk ( KERN_DEBUG " wlcore_sdio: WRITE to 0x%04x \n " , addr ) ;
print_hex_dump ( KERN_DEBUG , " wlcore_sdio: WRITE " ,
DUMP_PREFIX_OFFSET , 16 , 1 ,
buf , len , false ) ;
}
2011-11-29 13:38:37 +02:00
if ( unlikely ( addr = = HW_ACCESS_ELP_CTRL_REG ) ) {
2010-02-22 08:38:27 +02:00
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
2012-01-26 14:12:31 +02:00
sdio_release_host ( func ) ;
2012-06-17 20:30:05 +03:00
if ( WARN_ON ( ret ) )
2011-10-07 14:14:25 +03:00
dev_err ( child - > parent , " sdio write failed (%d) \n " , ret ) ;
2012-06-17 20:30:05 +03:00
return 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 ) ;
2012-05-20 10:38:16 +03:00
struct mmc_card * card = func - > card ;
ret = pm_runtime_get_sync ( & card - > dev ) ;
2018-04-26 08:47:11 +03:00
if ( ret < 0 ) {
pm_runtime_put_noidle ( & card - > dev ) ;
dev_err ( glue - > dev , " %s: failed to get_sync(%d) \n " ,
__func__ , ret ) ;
2018-05-17 11:29:50 -07:00
return ret ;
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 ) ;
wlcore: sdio: Fixup power on/off sequence
During "wlan-up", we are programming the FW into the WiFi-chip. However,
re-programming the FW doesn't work, unless a power cycle of the WiFi-chip
is made in-between the programmings.
To conform to this requirement and to fix the regression in a simple way,
let's start by allowing that the SDIO card (WiFi-chip) may stay powered on
(runtime resumed) when wl12xx_sdio_power_off() returns. The intent with the
current code is to treat this scenario as an error, but unfortunate this
doesn't work as expected, so let's fix this.
The other part is to guarantee that a power cycle of the SDIO card has been
completed when wl12xx_sdio_power_on() returns, as to allow the FW
programming to succeed. However, relying solely on runtime PM to deal with
this isn't sufficient. For example, userspace may prevent runtime suspend
via sysfs for the device that represents the SDIO card, leading to that the
mmc core also keeps it powered on. For this reason, let's instead do a
brute force power cycle in wl12xx_sdio_power_on().
Fixes: 728a9dc61f13 ("wlcore: sdio: Fix flakey SDIO runtime PM handling")
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Tested-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-01-16 12:37:23 +01:00
/*
* To guarantee that the SDIO card is power cycled , as required to make
* the FW programming to succeed , let ' s do a brute force HW reset .
*/
mmc_hw_reset ( card - > host ) ;
2010-09-07 04:24:21 +03:00
sdio_enable_func ( func ) ;
2012-01-26 14:12:31 +02:00
sdio_release_host ( func ) ;
2010-09-16 01:22:04 +02:00
2018-05-17 11:29:50 -07:00
return 0 ;
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-10-04 23:10:28 +03:00
struct sdio_func * func = dev_to_sdio_func ( glue - > dev ) ;
2012-05-20 10:38:16 +03:00
struct mmc_card * card = func - > card ;
2010-09-07 04:24:21 +03:00
2012-01-26 14:12:31 +02:00
sdio_claim_host ( func ) ;
2010-09-07 04:24:21 +03:00
sdio_disable_func ( func ) ;
sdio_release_host ( func ) ;
2010-09-16 01:22:04 +02:00
2012-05-20 10:38:16 +03:00
/* Let runtime PM know the card is powered off */
wlcore: sdio: Fixup power on/off sequence
During "wlan-up", we are programming the FW into the WiFi-chip. However,
re-programming the FW doesn't work, unless a power cycle of the WiFi-chip
is made in-between the programmings.
To conform to this requirement and to fix the regression in a simple way,
let's start by allowing that the SDIO card (WiFi-chip) may stay powered on
(runtime resumed) when wl12xx_sdio_power_off() returns. The intent with the
current code is to treat this scenario as an error, but unfortunate this
doesn't work as expected, so let's fix this.
The other part is to guarantee that a power cycle of the SDIO card has been
completed when wl12xx_sdio_power_on() returns, as to allow the FW
programming to succeed. However, relying solely on runtime PM to deal with
this isn't sufficient. For example, userspace may prevent runtime suspend
via sysfs for the device that represents the SDIO card, leading to that the
mmc core also keeps it powered on. For this reason, let's instead do a
brute force power cycle in wl12xx_sdio_power_on().
Fixes: 728a9dc61f13 ("wlcore: sdio: Fix flakey SDIO runtime PM handling")
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Tested-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2019-01-16 12:37:23 +01:00
pm_runtime_put ( & card - > dev ) ;
2018-05-17 11:29:50 -07:00
return 0 ;
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
} ;
2015-03-18 18:38:28 +02:00
# ifdef CONFIG_OF
2016-09-17 09:06:30 -07:00
static const struct wilink_family_data wl127x_data = {
. name = " wl127x " ,
. nvs_name = " ti-connectivity/wl127x-nvs.bin " ,
} ;
static const struct wilink_family_data wl128x_data = {
. name = " wl128x " ,
. nvs_name = " ti-connectivity/wl128x-nvs.bin " ,
} ;
static const struct wilink_family_data wl18xx_data = {
. name = " wl18xx " ,
. cfg_name = " ti-connectivity/wl18xx-conf.bin " ,
2017-08-20 12:28:18 +00:00
. nvs_name = " ti-connectivity/wl1271-nvs.bin " ,
2016-09-17 09:06:30 -07:00
} ;
2015-03-18 18:38:28 +02:00
static const struct of_device_id wlcore_sdio_of_match_table [ ] = {
2016-09-17 09:06:30 -07:00
{ . compatible = " ti,wl1271 " , . data = & wl127x_data } ,
{ . compatible = " ti,wl1273 " , . data = & wl127x_data } ,
{ . compatible = " ti,wl1281 " , . data = & wl128x_data } ,
{ . compatible = " ti,wl1283 " , . data = & wl128x_data } ,
2017-06-08 22:50:00 +02:00
{ . compatible = " ti,wl1285 " , . data = & wl128x_data } ,
2016-09-17 09:06:30 -07:00
{ . compatible = " ti,wl1801 " , . data = & wl18xx_data } ,
{ . compatible = " ti,wl1805 " , . data = & wl18xx_data } ,
{ . compatible = " ti,wl1807 " , . data = & wl18xx_data } ,
{ . compatible = " ti,wl1831 " , . data = & wl18xx_data } ,
{ . compatible = " ti,wl1835 " , . data = & wl18xx_data } ,
{ . compatible = " ti,wl1837 " , . data = & wl18xx_data } ,
2015-03-18 18:38:28 +02:00
{ }
} ;
2018-10-01 14:41:10 -07:00
static int wlcore_probe_of ( struct device * dev , int * irq , int * wakeirq ,
2015-03-18 18:38:30 +02:00
struct wlcore_platdev_data * pdev_data )
2015-03-18 18:38:28 +02:00
{
struct device_node * np = dev - > of_node ;
2016-09-17 09:06:30 -07:00
const struct of_device_id * of_id ;
2015-03-18 18:38:28 +02:00
2016-09-17 09:06:30 -07:00
of_id = of_match_node ( wlcore_sdio_of_match_table , np ) ;
if ( ! of_id )
return - ENODEV ;
pdev_data - > family = of_id - > data ;
2015-03-18 18:38:28 +02:00
2015-03-18 18:38:30 +02:00
* irq = irq_of_parse_and_map ( np , 0 ) ;
if ( ! * irq ) {
2015-03-18 18:38:28 +02:00
dev_err ( dev , " No irq in platform data \n " ) ;
2015-03-18 18:38:30 +02:00
return - EINVAL ;
2015-03-18 18:38:28 +02:00
}
2018-10-01 14:41:10 -07:00
* wakeirq = irq_of_parse_and_map ( np , 1 ) ;
2015-03-18 18:38:28 +02:00
/* optional clock frequency params */
of_property_read_u32 ( np , " ref-clock-frequency " ,
2015-03-18 18:38:30 +02:00
& pdev_data - > ref_clock_freq ) ;
2015-03-18 18:38:28 +02:00
of_property_read_u32 ( np , " tcxo-clock-frequency " ,
2015-03-18 18:38:30 +02:00
& pdev_data - > tcxo_clock_freq ) ;
2015-03-18 18:38:28 +02:00
2015-03-18 18:38:30 +02:00
return 0 ;
2015-03-18 18:38:28 +02:00
}
# else
2018-10-01 14:41:10 -07:00
static int wlcore_probe_of ( struct device * dev , int * irq , int * wakeirq ,
2015-03-18 18:38:30 +02:00
struct wlcore_platdev_data * pdev_data )
2015-03-18 18:38:28 +02:00
{
2015-03-18 18:38:30 +02:00
return - ENODATA ;
2015-03-18 18:38:28 +02:00
}
# endif
2012-12-03 09:56:42 -05:00
static int wl1271_probe ( struct sdio_func * func ,
2010-02-22 08:38:27 +02:00
const struct sdio_device_id * id )
{
2016-09-17 09:06:30 -07:00
struct wlcore_platdev_data * pdev_data ;
2011-10-04 23:10:28 +03:00
struct wl12xx_sdio_glue * glue ;
2018-10-01 14:41:10 -07:00
struct resource res [ 2 ] ;
2011-05-13 11:57:12 +03:00
mmc_pm_flag_t mmcflags ;
2011-10-04 23:10:28 +03:00
int ret = - ENOMEM ;
wlcore: Fixup "Add support for optional wakeirq"
After commit 3c83dd577c7f ("wlcore: Add support for optional
wakeirq") landed upstream, I started seeing the following oops
on my HiKey board:
[ 1.870279] Unable to handle kernel read from unreadable memory at virtual address 0000000000000010
[ 1.870283] Mem abort info:
[ 1.870287] ESR = 0x96000005
[ 1.870292] Exception class = DABT (current EL), IL = 32 bits
[ 1.870296] SET = 0, FnV = 0
[ 1.870299] EA = 0, S1PTW = 0
[ 1.870302] Data abort info:
[ 1.870306] ISV = 0, ISS = 0x00000005
[ 1.870309] CM = 0, WnR = 0
[ 1.870312] [0000000000000010] user address but active_mm is swapper
[ 1.870318] Internal error: Oops: 96000005 [#1] PREEMPT SMP
[ 1.870327] CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 4.19.0-05129-gb3d1e8e #48
[ 1.870331] Hardware name: HiKey Development Board (DT)
[ 1.870350] Workqueue: events_freezable mmc_rescan
[ 1.870358] pstate: 60400005 (nZCv daif +PAN -UAO)
[ 1.870366] pc : wl1271_probe+0x210/0x350
[ 1.870371] lr : wl1271_probe+0x210/0x350
[ 1.870374] sp : ffffff80080739b0
[ 1.870377] x29: ffffff80080739b0 x28: 0000000000000000
[ 1.870384] x27: 0000000000000000 x26: 0000000000000000
[ 1.870391] x25: 0000000000000036 x24: ffffffc074ecb598
[ 1.870398] x23: ffffffc07ffdce78 x22: ffffffc0744ed808
[ 1.870404] x21: ffffffc074ecbb98 x20: ffffff8008ff9000
[ 1.870411] x19: ffffffc0744ed800 x18: ffffff8008ff9a48
[ 1.870418] x17: 0000000000000000 x16: 0000000000000000
[ 1.870425] x15: ffffffc074ecb503 x14: ffffffffffffffff
[ 1.870431] x13: ffffffc074ecb502 x12: 0000000000000030
[ 1.870438] x11: 0101010101010101 x10: 0000000000000040
[ 1.870444] x9 : ffffffc075400248 x8 : ffffffc075400270
[ 1.870451] x7 : 0000000000000000 x6 : 0000000000000000
[ 1.870457] x5 : 0000000000000000 x4 : 0000000000000000
[ 1.870463] x3 : 0000000000000000 x2 : 0000000000000000
[ 1.870469] x1 : 0000000000000028 x0 : 0000000000000000
[ 1.870477] Process kworker/0:0 (pid: 5, stack limit = 0x(____ptrval____))
[ 1.870480] Call trace:
[ 1.870485] wl1271_probe+0x210/0x350
[ 1.870491] sdio_bus_probe+0x100/0x128
[ 1.870500] really_probe+0x1a8/0x2b8
[ 1.870506] driver_probe_device+0x58/0x100
[ 1.870511] __device_attach_driver+0x94/0xd8
[ 1.870517] bus_for_each_drv+0x70/0xc8
[ 1.870522] __device_attach+0xe0/0x140
[ 1.870527] device_initial_probe+0x10/0x18
[ 1.870532] bus_probe_device+0x94/0xa0
[ 1.870537] device_add+0x374/0x5b8
[ 1.870542] sdio_add_func+0x60/0x88
[ 1.870546] mmc_attach_sdio+0x1b0/0x358
[ 1.870551] mmc_rescan+0x2cc/0x390
[ 1.870558] process_one_work+0x12c/0x320
[ 1.870563] worker_thread+0x48/0x458
[ 1.870569] kthread+0xf8/0x128
[ 1.870575] ret_from_fork+0x10/0x18
[ 1.870583] Code: 92400c21 b2760021 a90687a2 97e95bf9 (f9400803)
[ 1.870587] ---[ end trace 1e15f81d3c139ca9 ]---
It seems since we don't have a wakeirq value in the dts, the wakeirq
value in wl1271_probe() is zero, which then causes trouble in
irqd_get_trigger_type(irq_get_irq_data(wakeirq)).
This patch tries to address this by checking if wakeirq is zero,
and not trying to add it to the resources if that is the case.
Fixes: 3c83dd577c7f ("wlcore: Add support for optional wakeirq")
Cc: Tony Lindgren <tony@atomide.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: Eyal Reizer <eyalr@ti.com>
Cc: Anders Roxell <anders.roxell@linaro.org>
Cc: linux-wireless@vger.kernel.org
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Tested-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-10-25 10:57:21 -07:00
int irq , wakeirq , num_irqs ;
2012-05-10 12:13:07 +03:00
const char * chip_family ;
2010-02-22 08:38:27 +02:00
/* We are only able to handle the wlan function */
if ( func - > num ! = 0x02 )
return - ENODEV ;
2016-09-17 09:06:30 -07:00
pdev_data = devm_kzalloc ( & func - > dev , sizeof ( * pdev_data ) , GFP_KERNEL ) ;
if ( ! pdev_data )
return - ENOMEM ;
2013-01-25 11:57:48 +02:00
2016-09-17 09:06:30 -07:00
pdev_data - > if_ops = & sdio_ops ;
glue = devm_kzalloc ( & func - > dev , sizeof ( * glue ) , GFP_KERNEL ) ;
if ( ! glue )
return - ENOMEM ;
2011-10-04 23:10:28 +03:00
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 ;
2018-10-01 14:41:10 -07:00
ret = wlcore_probe_of ( & func - > dev , & irq , & wakeirq , pdev_data ) ;
2015-07-02 10:34:49 +02:00
if ( ret )
2016-09-17 09:06:30 -07:00
goto out ;
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 )
2016-09-17 09:06:30 -07:00
pdev_data - > pwr_in_suspend = true ;
2011-05-13 11:57:12 +03: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 ) ;
2012-05-10 12:13:07 +03:00
/*
* Due to a hardware bug , we can ' t differentiate wl18xx from
* wl12xx , because both report the same device ID . The only
* way to differentiate is by checking the SDIO revision ,
* which is 3.00 on the wl18xx chips .
*/
if ( func - > card - > cccr . sdio_vsn = = SDIO_SDIO_REV_3_00 )
chip_family = " wl18xx " ;
else
chip_family = " wl12xx " ;
2013-01-23 16:40:37 +02:00
glue - > core = platform_device_alloc ( chip_family , PLATFORM_DEVID_AUTO ) ;
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 ;
2016-09-17 09:06:30 -07:00
goto out ;
2011-10-05 09:00:12 +03:00
}
glue - > core - > dev . parent = & func - > dev ;
memset ( res , 0x00 , sizeof ( res ) ) ;
2015-03-18 18:38:30 +02:00
res [ 0 ] . start = irq ;
res [ 0 ] . flags = IORESOURCE_IRQ |
irqd_get_trigger_type ( irq_get_irq_data ( irq ) ) ;
2011-10-05 09:00:12 +03:00
res [ 0 ] . name = " irq " ;
2018-10-01 14:41:10 -07:00
wlcore: Fixup "Add support for optional wakeirq"
After commit 3c83dd577c7f ("wlcore: Add support for optional
wakeirq") landed upstream, I started seeing the following oops
on my HiKey board:
[ 1.870279] Unable to handle kernel read from unreadable memory at virtual address 0000000000000010
[ 1.870283] Mem abort info:
[ 1.870287] ESR = 0x96000005
[ 1.870292] Exception class = DABT (current EL), IL = 32 bits
[ 1.870296] SET = 0, FnV = 0
[ 1.870299] EA = 0, S1PTW = 0
[ 1.870302] Data abort info:
[ 1.870306] ISV = 0, ISS = 0x00000005
[ 1.870309] CM = 0, WnR = 0
[ 1.870312] [0000000000000010] user address but active_mm is swapper
[ 1.870318] Internal error: Oops: 96000005 [#1] PREEMPT SMP
[ 1.870327] CPU: 0 PID: 5 Comm: kworker/0:0 Not tainted 4.19.0-05129-gb3d1e8e #48
[ 1.870331] Hardware name: HiKey Development Board (DT)
[ 1.870350] Workqueue: events_freezable mmc_rescan
[ 1.870358] pstate: 60400005 (nZCv daif +PAN -UAO)
[ 1.870366] pc : wl1271_probe+0x210/0x350
[ 1.870371] lr : wl1271_probe+0x210/0x350
[ 1.870374] sp : ffffff80080739b0
[ 1.870377] x29: ffffff80080739b0 x28: 0000000000000000
[ 1.870384] x27: 0000000000000000 x26: 0000000000000000
[ 1.870391] x25: 0000000000000036 x24: ffffffc074ecb598
[ 1.870398] x23: ffffffc07ffdce78 x22: ffffffc0744ed808
[ 1.870404] x21: ffffffc074ecbb98 x20: ffffff8008ff9000
[ 1.870411] x19: ffffffc0744ed800 x18: ffffff8008ff9a48
[ 1.870418] x17: 0000000000000000 x16: 0000000000000000
[ 1.870425] x15: ffffffc074ecb503 x14: ffffffffffffffff
[ 1.870431] x13: ffffffc074ecb502 x12: 0000000000000030
[ 1.870438] x11: 0101010101010101 x10: 0000000000000040
[ 1.870444] x9 : ffffffc075400248 x8 : ffffffc075400270
[ 1.870451] x7 : 0000000000000000 x6 : 0000000000000000
[ 1.870457] x5 : 0000000000000000 x4 : 0000000000000000
[ 1.870463] x3 : 0000000000000000 x2 : 0000000000000000
[ 1.870469] x1 : 0000000000000028 x0 : 0000000000000000
[ 1.870477] Process kworker/0:0 (pid: 5, stack limit = 0x(____ptrval____))
[ 1.870480] Call trace:
[ 1.870485] wl1271_probe+0x210/0x350
[ 1.870491] sdio_bus_probe+0x100/0x128
[ 1.870500] really_probe+0x1a8/0x2b8
[ 1.870506] driver_probe_device+0x58/0x100
[ 1.870511] __device_attach_driver+0x94/0xd8
[ 1.870517] bus_for_each_drv+0x70/0xc8
[ 1.870522] __device_attach+0xe0/0x140
[ 1.870527] device_initial_probe+0x10/0x18
[ 1.870532] bus_probe_device+0x94/0xa0
[ 1.870537] device_add+0x374/0x5b8
[ 1.870542] sdio_add_func+0x60/0x88
[ 1.870546] mmc_attach_sdio+0x1b0/0x358
[ 1.870551] mmc_rescan+0x2cc/0x390
[ 1.870558] process_one_work+0x12c/0x320
[ 1.870563] worker_thread+0x48/0x458
[ 1.870569] kthread+0xf8/0x128
[ 1.870575] ret_from_fork+0x10/0x18
[ 1.870583] Code: 92400c21 b2760021 a90687a2 97e95bf9 (f9400803)
[ 1.870587] ---[ end trace 1e15f81d3c139ca9 ]---
It seems since we don't have a wakeirq value in the dts, the wakeirq
value in wl1271_probe() is zero, which then causes trouble in
irqd_get_trigger_type(irq_get_irq_data(wakeirq)).
This patch tries to address this by checking if wakeirq is zero,
and not trying to add it to the resources if that is the case.
Fixes: 3c83dd577c7f ("wlcore: Add support for optional wakeirq")
Cc: Tony Lindgren <tony@atomide.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: Eyal Reizer <eyalr@ti.com>
Cc: Anders Roxell <anders.roxell@linaro.org>
Cc: linux-wireless@vger.kernel.org
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Tested-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
2018-10-25 10:57:21 -07:00
if ( wakeirq > 0 ) {
res [ 1 ] . start = wakeirq ;
res [ 1 ] . flags = IORESOURCE_IRQ |
irqd_get_trigger_type ( irq_get_irq_data ( wakeirq ) ) ;
res [ 1 ] . name = " wakeirq " ;
num_irqs = 2 ;
} else {
num_irqs = 1 ;
}
ret = platform_device_add_resources ( glue - > core , res , num_irqs ) ;
2011-10-05 09:00:12 +03:00
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 ;
}
2016-09-17 09:06:30 -07:00
ret = platform_device_add_data ( glue - > core , pdev_data ,
sizeof ( * pdev_data ) ) ;
2011-10-05 09:00:12 +03:00
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 :
2010-02-22 08:38:27 +02:00
return ret ;
}
2012-12-03 09:56:42 -05:00
static void wl1271_remove ( struct sdio_func * func )
2010-02-22 08:38:27 +02:00
{
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 ) ;
2012-10-23 13:23:13 +08:00
platform_device_unregister ( glue - > core ) ;
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 ) ;
2011-11-08 15:56:55 +02:00
struct wl12xx_sdio_glue * glue = sdio_get_drvdata ( func ) ;
struct wl1271 * wl = platform_get_drvdata ( glue - > core ) ;
2011-05-13 11:57:10 +03:00
mmc_pm_flag_t sdio_flags ;
int ret = 0 ;
2018-05-28 11:36:42 +03:00
if ( ! wl ) {
dev_err ( dev , " no wilink module was probed \n " ) ;
goto out ;
}
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 ;
}
}
out :
return ret ;
2010-10-08 16:16:27 +03:00
}
static int wl1271_resume ( struct device * dev )
{
2011-10-07 14:14:25 +03:00
dev_dbg ( dev , " wl1271 resume \n " ) ;
2011-05-13 11:57:11 +03:00
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 ,
2012-12-03 09:56:42 -05:00
. remove = 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 ) ;
2018-03-23 15:54:37 -07:00
module_param ( dump , bool , 0600 ) ;
2012-05-10 12:13:57 +03:00
MODULE_PARM_DESC ( dump , " Enable sdio read/write dumps. " ) ;
2010-02-22 08:38:27 +02:00
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> " ) ;