Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(606)

Unified Diff: chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c

Issue 3579004: ath6kl: Bringing in the upstream version (Closed) Base URL: http://git.chromium.org/git/kernel.git
Patch Set: Created 10 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c
diff --git a/chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c b/chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c
index fcce4fb21b24e0776563e2f6f198c164028e5ce8..c307a555936243b3c04d5498b6882e44b5a8a69c 100644
--- a/chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c
+++ b/chromeos/drivers/ath6kl/hif/sdio/linux_sdio/src/hif.c
@@ -1,15 +1,19 @@
//------------------------------------------------------------------------------
// <copyright file="hif.c" company="Atheros">
-// Copyright (c) 2004-2008 Atheros Corporation. All rights reserved.
+// Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
//
-// 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;
//
-// Software distributed under the License is distributed on an "AS
-// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-// implied. See the License for the specific language governing
-// rights and limitations under the License.
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
//
//------------------------------------------------------------------------------
@@ -24,6 +28,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
+#include <linux/mmc/sd.h>
#include <linux/kthread.h>
/* by default setup a bounce buffer for the data packets, if the underlying host controller driver
@@ -39,13 +44,13 @@
* buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack).
* virt_addr_valid check fails on stack memory.
*/
-#define BUFFER_NEEDS_BOUNCE(buffer) (((A_UINT32)(buffer) & 0x3) || !virt_addr_valid((buffer)))
+#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || !virt_addr_valid((buffer)))
#else
#define BUFFER_NEEDS_BOUNCE(buffer) (FALSE)
#endif
/* ATHENV */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(CONFIG_PM)
+#if defined(CONFIG_PM)
#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
static int hifDeviceSuspend(struct device *dev);
@@ -57,6 +62,7 @@ static HIF_DEVICE *addHifDevice(struct sdio_func *func);
static HIF_DEVICE *getHifDevice(struct sdio_func *func);
static void delHifDevice(HIF_DEVICE * device);
static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, unsigned char byte);
+static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte);
int reset_sdio_on_unload = 0;
module_param(reset_sdio_on_unload, int, 0644);
@@ -81,16 +87,12 @@ static struct sdio_driver ar6k_driver = {
.remove = hifDeviceRemoved,
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(CONFIG_PM)
+#if defined(CONFIG_PM)
/* New suspend/resume based on linux-2.6.32
* Need to patch linux-2.6.32 with mmc2.6.32_suspend.patch
* Need to patch with msmsdcc2.6.29_suspend.patch for msm_sdcc host
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
static struct dev_pm_ops ar6k_device_pm_ops = {
-#else
-static struct pm_ops ar6k_device_pm_ops = {
-#endif
.suspend = hifDeviceSuspend,
.resume = hifDeviceResume,
};
@@ -105,6 +107,8 @@ extern A_UINT32 busspeedlow;
extern A_UINT32 debughif;
static void ResetAllCards(void);
+static A_STATUS hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func);
+static A_STATUS hifEnableFunc(HIF_DEVICE *device, struct sdio_func *func);
#ifdef DEBUG
@@ -132,7 +136,7 @@ A_STATUS HIFInit(OSDRV_CALLBACKS *callbacks)
/* Register with bus driver core */
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: HIFInit registering\n"));
registered = 1;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(CONFIG_PM)
+#if defined(CONFIG_PM)
if (callbacks->deviceSuspendHandler && callbacks->deviceResumeHandler) {
ar6k_driver.drv.pm = &ar6k_device_pm_ops;
}
@@ -363,7 +367,7 @@ HIFReadWrite(HIF_DEVICE *device,
AddToAsyncList(device, busrequest);
if (request & HIF_SYNCHRONOUS) {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%X\n", (unsigned int)busrequest));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%lX\n", (unsigned long)busrequest));
/* wait for completion */
up(&device->sem_async);
@@ -372,14 +376,14 @@ HIFReadWrite(HIF_DEVICE *device,
return A_ERROR;
} else {
A_STATUS status = busrequest->status;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freeing 0x%X: 0x%X\n",
- (unsigned int)busrequest, busrequest->status));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freeing 0x%lX: 0x%X\n",
+ (unsigned long)busrequest, busrequest->status));
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: freeing req: 0x%X\n", (unsigned int)request));
hifFreeBusRequest(device, busrequest);
return status;
}
} else {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%X\n", (unsigned int)busrequest));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%lX\n", (unsigned long)busrequest));
up(&device->sem_async);
return A_PENDING;
}
@@ -427,7 +431,7 @@ static int async_task(void *param)
device->asyncreq = NULL;
}
spin_unlock_irqrestore(&device->asynclock, flags);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task processing req: 0x%X\n", (unsigned int)request));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task processing req: 0x%lX\n", (unsigned long)request));
if (request->pScatterReq != NULL) {
A_ASSERT(device->scatter_enabled);
@@ -441,12 +445,12 @@ static int async_task(void *param)
request->length, request->request & ~HIF_SYNCHRONOUS, NULL);
if (request->request & HIF_ASYNCHRONOUS) {
void *context = request->context;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task freeing req: 0x%X\n", (unsigned int)request));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task freeing req: 0x%lX\n", (unsigned long)request));
hifFreeBusRequest(device, request);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task completion routine req: 0x%X\n", (unsigned int)request));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task completion routine req: 0x%lX\n", (unsigned long)request));
device->htcCallbacks.rwCompletionHandler(context, status);
} else {
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task upping req: 0x%X\n", (unsigned int)request));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: async_task upping req: 0x%lX\n", (unsigned long)request));
request->status = status;
up(&request->sem_req);
}
@@ -459,14 +463,239 @@ static int async_task(void *param)
complete_and_exit(&device->async_completion, 0);
return 0;
- }
+}
+
+static A_INT32 IssueSDCommand(HIF_DEVICE *device, A_UINT32 opcode, A_UINT32 arg, A_UINT32 flags, A_UINT32 *resp)
+{
+ struct mmc_command cmd;
+ A_INT32 err;
+ struct mmc_host *host;
+ struct sdio_func *func;
+
+ func = device->func;
+ host = func->card->host;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = opcode;
+ cmd.arg = arg;
+ cmd.flags = flags;
+ err = mmc_wait_for_cmd(host, &cmd, 3);
+
+ if ((!err) && (resp)) {
+ *resp = cmd.resp[0];
+ }
+
+ return err;
+}
+
+A_STATUS ReinitSDIO(HIF_DEVICE *device)
+{
+ A_INT32 err;
+ struct mmc_host *host;
+ struct mmc_card *card;
+ struct sdio_func *func;
+ A_UINT8 cmd52_resp;
+ A_UINT32 clock;
+
+ func = device->func;
+ card = func->card;
+ host = card->host;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +ReinitSDIO \n"));
+ sdio_claim_host(func);
+
+ do {
+ if (!device->is_suspend) {
+ A_UINT32 resp;
+ A_UINT16 rca;
+ A_UINT32 i;
+ int bit = fls(host->ocr_avail) - 1;
+ /* emulate the mmc_power_up(...) */
+ host->ios.vdd = bit;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ host->ops->set_ios(host, &host->ios);
+ /*
+ * This delay should be sufficient to allow the power supply
+ * to reach the minimum voltage.
+ */
+ msleep(2);
+
+ host->ios.clock = host->f_min;
+ host->ios.power_mode = MMC_POWER_ON;
+ host->ops->set_ios(host, &host->ios);
+
+ /*
+ * This delay must be at least 74 clock sizes, or 1 ms, or the
+ * time required to reach a stable voltage.
+ */
+ msleep(2);
+
+ /* Issue CMD0. Goto idle state */
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ops->set_ios(host, &host->ios);
+ msleep(1);
+ err = IssueSDCommand(device, MMC_GO_IDLE_STATE, 0, (MMC_RSP_NONE | MMC_CMD_BC), NULL);
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ops->set_ios(host, &host->ios);
+ msleep(1);
+ host->use_spi_crc = 0;
+
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD0 failed : %d \n",err));
+ break;
+ }
+
+ if (!host->ocr) {
+ /* Issue CMD5, arg = 0 */
+ err = IssueSDCommand(device, SD_IO_SEND_OP_COND, 0, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
+ break;
+ }
+ host->ocr = resp;
+ }
+
+ /* Issue CMD5, arg = ocr. Wait till card is ready */
+ for (i=0;i<100;i++) {
+ err = IssueSDCommand(device, SD_IO_SEND_OP_COND, host->ocr, (MMC_RSP_R4 | MMC_CMD_BCR), &resp);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD5 failed : %d \n",err));
+ break;
+ }
+ if (resp & MMC_CARD_BUSY) {
+ break;
+ }
+ msleep(10);
+ }
+
+ if ((i == 100) || (err)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: card in not ready : %d %d \n",i,err));
+ break;
+ }
+
+ /* Issue CMD3, get RCA */
+ err = IssueSDCommand(device, SD_SEND_RELATIVE_ADDR, 0, MMC_RSP_R6 | MMC_CMD_BCR, &resp);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD3 failed : %d \n",err));
+ break;
+ }
+ rca = resp >> 16;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ host->ops->set_ios(host, &host->ios);
+
+ /* Issue CMD7, select card */
+ err = IssueSDCommand(device, MMC_SELECT_CARD, (rca << 16), MMC_RSP_R1 | MMC_CMD_AC, NULL);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD7 failed : %d \n",err));
+ break;
+ }
+ }
+
+ /* Enable high speed */
+ if (card->host->caps & MMC_CAP_SD_HIGHSPEED) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("ReinitSDIO: Set high speed mode\n"));
+ err = Func0_CMD52ReadByte(card, SDIO_CCCR_SPEED, &cmd52_resp);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 read to CCCR speed register failed : %d \n",err));
+ card->state &= ~MMC_STATE_HIGHSPEED;
+ /* no need to break */
+ } else {
+ err = Func0_CMD52WriteByte(card, SDIO_CCCR_SPEED, (cmd52_resp | SDIO_SPEED_EHS));
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 write to CCCR speed register failed : %d \n",err));
+ break;
+ }
+ mmc_card_set_highspeed(card);
+ host->ios.timing = MMC_TIMING_SD_HS;
+ host->ops->set_ios(host, &host->ios);
+ }
+ }
+
+ /* Set clock */
+ if (mmc_card_highspeed(card)) {
+ clock = 50000000;
+ } else {
+ clock = card->cis.max_dtr;
+ }
+
+ if (clock > host->f_max) {
+ clock = host->f_max;
+ }
+ host->ios.clock = clock;
+ host->ops->set_ios(host, &host->ios);
+
+
+ if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+ /* CMD52: Set bus width & disable card detect resistor */
+ err = Func0_CMD52WriteByte(card, SDIO_CCCR_IF, SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT);
+ if (err) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("ReinitSDIO: CMD52 to set bus mode failed : %d \n",err));
+ break;
+ }
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ host->ops->set_ios(host, &host->ios);
+ }
+ } while (0);
+
+ sdio_release_host(func);
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -ReinitSDIO \n"));
+
+ return (err) ? A_ERROR : A_OK;
+}
+
+A_STATUS
+PowerStateChangeNotify(HIF_DEVICE *device, HIF_DEVICE_POWER_CHANGE_TYPE config)
+{
+ A_STATUS status = A_OK;
+#if defined(CONFIG_PM)
+ struct sdio_func *func = device->func;
+ int old_reset_val;
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +PowerStateChangeNotify %d\n", config));
+ switch (config) {
+ case HIF_DEVICE_POWER_DOWN:
+ case HIF_DEVICE_POWER_CUT:
+ old_reset_val = reset_sdio_on_unload;
+ reset_sdio_on_unload = 1;
+ status = hifDisableFunc(device, func);
+ reset_sdio_on_unload = old_reset_val;
+ if (!device->is_suspend) {
+ struct mmc_host *host = func->card->host;
+ host->ios.clock = 0;
+ host->ios.vdd = 0;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ host->ops->set_ios(host, &host->ios);
+ }
+ break;
+ case HIF_DEVICE_POWER_UP:
+ if (device->powerConfig == HIF_DEVICE_POWER_CUT) {
+ status = ReinitSDIO(device);
+ }
+ if (status == A_OK) {
+ status = hifEnableFunc(device, func);
+ }
+ break;
+ }
+ device->powerConfig = config;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -PowerStateChangeNotify\n"));
+#endif
+ return status;
+}
A_STATUS
HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
void *config, A_UINT32 configLen)
{
A_UINT32 count;
- A_STATUS status;
+ A_STATUS status = A_OK;
switch(opcode) {
case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
@@ -498,18 +727,21 @@ HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
if (A_FAILED(status)) {
device->scatter_enabled = FALSE;
}
- return status;
+ break;
case HIF_DEVICE_GET_OS_DEVICE:
/* pass back a pointer to the SDIO function's "dev" struct */
((HIF_DEVICE_OS_DEVICE_INFO *)config)->pOSDevice = &device->func->dev;
break;
+ case HIF_DEVICE_POWER_STATE_CHANGE:
+ status = PowerStateChangeNotify(device, *(HIF_DEVICE_POWER_CHANGE_TYPE *)config);
+ break;
default:
AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
("AR6000: Unsupported configuration opcode: %d\n", opcode));
- return A_ERROR;
+ status = A_ERROR;
}
- return A_OK;
+ return status;
}
void
@@ -571,28 +803,31 @@ static int startup_task(void *param)
return 0;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(CONFIG_PM)
-/* handle HTC startup via thread*/
-static int resume_task(void *param)
+#if defined(CONFIG_PM)
+static int enable_task(void *param)
{
HIF_DEVICE *device;
device = (HIF_DEVICE *)param;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call HTC from resume_task\n"));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: call from resume_task\n"));
+
/* start up inform DRV layer */
- if (device && device->claimedContext && osdrvCallbacks.deviceResumeHandler &&
- osdrvCallbacks.deviceResumeHandler(device->claimedContext) != A_OK) {
+ if (device &&
+ device->claimedContext &&
+ osdrvCallbacks.devicePowerChangeHandler &&
+ osdrvCallbacks.devicePowerChangeHandler(device->claimedContext, HIF_DEVICE_POWER_UP) != A_OK)
+ {
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device rejected\n"));
}
+
return 0;
}
-#endif /* CONFIG_PM */
+#endif
static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id *id)
{
int ret;
HIF_DEVICE * device;
int count;
- struct task_struct* startup_task_struct;
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
("AR6000: hifDeviceInserted, Function: 0x%X, Vendor ID: 0x%X, Device ID: 0x%X, block size: 0x%X/0x%X\n",
@@ -601,6 +836,9 @@ static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id
addHifDevice(func);
device = getHifDevice(func);
+ device->id = id;
+ device->is_disabled = TRUE;
+
spin_lock_init(&device->lock);
spin_lock_init(&device->asynclock);
@@ -612,75 +850,17 @@ static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id
* unless globally overridden */
device->scatter_enabled = TRUE;
}
-
- /* enable the SDIO function */
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: claim\n"));
- sdio_claim_host(func);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: enable\n"));
- if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) {
- /* enable 4-bit ASYNC interrupt on AR6003 or later devices */
- ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret));
- sdio_release_host(func);
- return ret;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n"));
- }
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
- /* give us some time to enable, in ms */
- func->enable_timeout = 100;
-#endif
- ret = sdio_enable_func(func);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n",
- __FUNCTION__, ret));
- sdio_release_host(func);
- return ret;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: set block size 0x%X\n", HIF_MBOX_BLOCK_SIZE));
- ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
- sdio_release_host(func);
- if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n",
- __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret));
- return ret;
- }
/* Initialize the bus requests to be used later */
A_MEMZERO(device->busRequest, sizeof(device->busRequest));
for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
sema_init(&device->busRequest[count].sem_req, 0);
hifFreeBusRequest(device, &device->busRequest[count]);
}
-
- /* create async I/O thread */
- device->async_shutdown = 0;
- device->async_task = kthread_create(async_task,
- (void *)device,
- "AR6K Async");
- if (IS_ERR(device->async_task)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n", __FUNCTION__));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n"));
sema_init(&device->sem_async, 0);
- wake_up_process(device->async_task );
-
- /* create startup thread */
- startup_task_struct = kthread_create(startup_task,
- (void *)device,
- "AR6K startup");
- if (IS_ERR(startup_task_struct)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create startup task\n", __FUNCTION__));
- return A_ERROR;
- }
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start startup task\n"));
- wake_up_process(startup_task_struct);
+
+ ret = hifEnableFunc(device, func);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: return %d\n", ret));
return ret;
}
@@ -743,7 +923,6 @@ BUS_REQUEST *hifAllocateBusRequest(HIF_DEVICE *device)
{
device->s_busRequestFreeQueue = busrequest->next;
}
-
/* Release lock */
spin_unlock_irqrestore(&device->lock, flag);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifAllocateBusRequest: 0x%p\n", busrequest));
@@ -770,11 +949,12 @@ hifFreeBusRequest(HIF_DEVICE *device, BUS_REQUEST *busrequest)
spin_unlock_irqrestore(&device->lock, flag);
}
-static int hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func)
+static A_STATUS hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func)
{
- int ret = 0;
+ int ret;
+ A_STATUS status = A_OK;
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceRemoved\n"));
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDisableFunc\n"));
device = getHifDevice(func);
if (!IS_ERR(device->async_task)) {
init_completion(&device->async_completion);
@@ -786,6 +966,9 @@ static int hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func)
/* Disable the card */
sdio_claim_host(device->func);
ret = sdio_disable_func(device->func);
+ if (ret) {
+ status = A_ERROR;
+ }
if (reset_sdio_on_unload) {
/* reset the SDIO interface. This is useful in automated testing where the card
@@ -798,121 +981,62 @@ static int hifDisableFunc(HIF_DEVICE *device, struct sdio_func *func)
ret = Func0_CMD52WriteByte(device->func->card, SDIO_CCCR_ABORT, (1 << 3));
if (ret) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret));
+ status = A_ERROR;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: reset failed : %d \n",ret));
}
}
sdio_release_host(device->func);
- return ret;
-}
-
-static void hifDeviceRemoved(struct sdio_func *func)
-{
- A_STATUS status = A_OK;
- HIF_DEVICE *device;
- AR_DEBUG_ASSERT(func != NULL);
-
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceRemoved\n"));
- device = getHifDevice(func);
- if (device->claimedContext != NULL) {
- status = osdrvCallbacks.deviceRemovedHandler(device->claimedContext, device);
- }
-
- if (device->is_suspend) {
- device->is_suspend = FALSE;
- } else {
- if (hifDisableFunc(device, func)!=0) {
- status = A_ERROR;
- }
- }
- CleanupHIFScatterResources(device);
-
- delHifDevice(device);
- AR_DEBUG_ASSERT(status == A_OK);
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceRemoved\n"));
-}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && defined(CONFIG_PM)
-static int hifDeviceSuspend(struct device *dev)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
- A_STATUS status = A_OK;
- HIF_DEVICE *device;
- device = getHifDevice(func);
- if (device && device->claimedContext && osdrvCallbacks.deviceSuspendHandler) {
- status = osdrvCallbacks.deviceSuspendHandler(device->claimedContext);
- }
if (status == A_OK) {
- int oldresetvalue = reset_sdio_on_unload;
- reset_sdio_on_unload = 1;
- hifDisableFunc(device, func);
- reset_sdio_on_unload = oldresetvalue;
- device->is_suspend = TRUE;
- } else if (status == A_EBUSY) {
- A_INT32 cnt = 10;
- A_UINT8 host_int_status;
- do {
- while (atomic_read(&device->irqHandling)) {
- /* wait until irq handler finished all the jobs */
- schedule_timeout(HZ/10);
- }
- /* check if there is any pending irq due to force done */
- host_int_status = 0;
- status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS,
- (A_UINT8 *)&host_int_status, sizeof(host_int_status),
- HIF_RD_SYNC_BYTE_INC, NULL);
- host_int_status = A_SUCCESS(status) ? (host_int_status & (1 << 0)) : 0;
- if (host_int_status) {
- schedule(); /* schedule for next dsrHandler */
- }
- } while (host_int_status && --cnt > 0);
-
- if (host_int_status && cnt == 0) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
- ("AR6000: %s(), Unable clear up pending IRQ before the system suspended\n",
- __FUNCTION__));
- }
-#if 1
- status = A_OK; /* assume that sdio host controller will take care the power of wifi chip */
-#else
- return -EBUSY; /* Return -EBUSY if customer use all android patch of mmc stack provided by us */
-#endif
+ device->is_disabled = TRUE;
}
- return A_SUCCESS(status) ? 0 : status;
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDisableFunc\n"));
+
+ return status;
}
-static int hifDeviceResume(struct device *dev)
+static int hifEnableFunc(HIF_DEVICE *device, struct sdio_func *func)
{
struct task_struct* pTask;
- const char *taskName;
- int (*taskFunc)(void *);
- struct sdio_func *func = dev_to_sdio_func(dev);
- A_STATUS ret = A_OK;
- HIF_DEVICE *device;
+ const char *taskName = NULL;
+ int (*taskFunc)(void *) = NULL;
+ int ret = A_OK;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifEnableFunc\n"));
device = getHifDevice(func);
- if (device->is_suspend) {
+ if (device->is_disabled) {
/* enable the SDIO function */
sdio_claim_host(func);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+
+ if ((device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) {
+ /* enable 4-bit ASYNC interrupt on AR6003 or later devices */
+ ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ);
+ if (ret) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret));
+ sdio_release_host(func);
+ return A_ERROR;
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n"));
+ }
/* give us some time to enable, in ms */
func->enable_timeout = 100;
-#endif
ret = sdio_enable_func(func);
if (ret) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n",
__FUNCTION__, ret));
sdio_release_host(func);
- return ret;
- }
+ return A_ERROR;
+ }
ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE);
sdio_release_host(func);
if (ret) {
AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n",
__FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret));
- return ret;
+ return A_ERROR;
}
- device->is_suspend = FALSE;
+ device->is_disabled = FALSE;
/* create async I/O thread */
if (!device->async_task) {
device->async_shutdown = 0;
@@ -929,25 +1053,135 @@ static int hifDeviceResume(struct device *dev)
}
if (!device->claimedContext) {
- printk("WARNING!!! No claimedContext during resume wlan\n");
taskFunc = startup_task;
taskName = "AR6K startup";
+ ret = A_OK;
+#if defined(CONFIG_PM)
} else {
- taskFunc = resume_task;
- taskName = "AR6K resume";
+ taskFunc = enable_task;
+ taskName = "AR6K enable";
+ ret = A_PENDING;
+#endif /* CONFIG_PM */
}
/* create resume thread */
pTask = kthread_create(taskFunc, (void *)device, taskName);
if (IS_ERR(pTask)) {
- AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create resume task\n", __FUNCTION__));
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create enabel task\n", __FUNCTION__));
return A_ERROR;
}
- AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start resume task\n"));
wake_up_process(pTask);
- return A_SUCCESS(ret) ? 0 : ret;
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifEnableFunc\n"));
+
+ /* task will call the enable func, indicate pending */
+ return ret;
+}
+
+#if defined(CONFIG_PM)
+static int hifDeviceSuspend(struct device *dev)
+{
+ struct sdio_func *func=dev_to_sdio_func(dev);
+ A_STATUS status = A_OK;
+ HIF_DEVICE *device;
+
+ device = getHifDevice(func);
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceSuspend\n"));
+ if (device && device->claimedContext && osdrvCallbacks.deviceSuspendHandler) {
+ device->is_suspend = TRUE; /* set true first for PowerStateChangeNotify(..) */
+ status = osdrvCallbacks.deviceSuspendHandler(device->claimedContext);
+ if (status != A_OK) {
+ device->is_suspend = FALSE;
+ }
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceSuspend\n"));
+
+ switch (status) {
+ case A_OK:
+ return 0;
+ case A_EBUSY:
+ return -EBUSY; /* Hack for kernel in order to support deep sleep and wow */
+ default:
+ return -1;
+ }
+}
+
+static int hifDeviceResume(struct device *dev)
+{
+ struct sdio_func *func=dev_to_sdio_func(dev);
+ A_STATUS status = A_OK;
+ HIF_DEVICE *device;
+
+ device = getHifDevice(func);
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceResume\n"));
+ if (device && device->claimedContext && osdrvCallbacks.deviceSuspendHandler) {
+ status = osdrvCallbacks.deviceResumeHandler(device->claimedContext);
+ if (status == A_OK) {
+ device->is_suspend = FALSE;
+ }
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceResume\n"));
+
+ return A_SUCCESS(status) ? 0 : status;
}
#endif /* CONFIG_PM */
+static void hifDeviceRemoved(struct sdio_func *func)
+{
+ A_STATUS status = A_OK;
+ HIF_DEVICE *device;
+ AR_DEBUG_ASSERT(func != NULL);
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: +hifDeviceRemoved\n"));
+ device = getHifDevice(func);
+ if (device->claimedContext != NULL) {
+ status = osdrvCallbacks.deviceRemovedHandler(device->claimedContext, device);
+ }
+
+ if (device->is_disabled) {
+ device->is_disabled = FALSE;
+ } else {
+ status = hifDisableFunc(device, func);
+ }
+ CleanupHIFScatterResources(device);
+
+ delHifDevice(device);
+ AR_DEBUG_ASSERT(status == A_OK);
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: -hifDeviceRemoved\n"));
+}
+
+/*
+ * This should be moved to AR6K HTC layer.
+ */
+A_STATUS hifWaitForPendingRecv(HIF_DEVICE *device)
+{
+ A_INT32 cnt = 10;
+ A_UINT8 host_int_status;
+ A_STATUS status = A_OK;
+
+ do {
+ while (atomic_read(&device->irqHandling)) {
+ /* wait until irq handler finished all the jobs */
+ schedule_timeout(HZ/10);
+ }
+ /* check if there is any pending irq due to force done */
+ host_int_status = 0;
+ status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS,
+ (A_UINT8 *)&host_int_status, sizeof(host_int_status),
+ HIF_RD_SYNC_BYTE_INC, NULL);
+ host_int_status = A_SUCCESS(status) ? (host_int_status & (1 << 0)) : 0;
+ if (host_int_status) {
+ schedule(); /* schedule for next dsrHandler */
+ }
+ } while (host_int_status && --cnt > 0);
+
+ if (host_int_status && cnt == 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
+ ("AR6000: %s(), Unable clear up pending IRQ before the system suspended\n", __FUNCTION__));
+ }
+
+ return A_OK;
+}
+
+
static HIF_DEVICE *
addHifDevice(struct sdio_func *func)
{
@@ -961,6 +1195,7 @@ addHifDevice(struct sdio_func *func)
AR_DEBUG_ASSERT(hifdevice->dma_buffer != NULL);
#endif
hifdevice->func = func;
+ hifdevice->powerConfig = HIF_DEVICE_POWER_UP;
sdio_set_drvdata(func, hifdevice);
AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: addHifDevice; 0x%p\n", hifdevice));
return hifdevice;
@@ -1041,6 +1276,23 @@ static int Func0_CMD52WriteByte(struct mmc_card *card, unsigned int address, uns
return mmc_wait_for_cmd(card->host, &ioCmd, 0);
}
+static int Func0_CMD52ReadByte(struct mmc_card *card, unsigned int address, unsigned char *byte)
+{
+ struct mmc_command ioCmd;
+ unsigned long arg;
+ A_INT32 err;
+
+ memset(&ioCmd,0,sizeof(ioCmd));
+ SDIO_SET_CMD52_READ_ARG(arg,0,address);
+ ioCmd.opcode = SD_IO_RW_DIRECT;
+ ioCmd.arg = arg;
+ ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &ioCmd, 0);
+ if ((!err) && (byte)) {
+ *byte = ioCmd.resp[0] & 0xFF;
+ }
+ return err;
+}

Powered by Google App Engine
This is Rietveld 408576698