core.c revision e6f918bf39773d712ab5b457bff54ade3bda0cb1
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2aaac1b470bd0dccb30912356617069dc6199cc80Pierre Ossman * linux/drivers/mmc/core/core.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2004 Russell King, All Rights Reserved. 55b4fd9aef778e223968dfab1b90f905b3f2bd23dPierre Ossman * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. 6b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. 7bce40a36de574376f41f1ff3c4d212a7da2a3c90Philip Langdale * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/completion.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 21b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman#include <asm/scatterlist.h> 22b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman#include <linux/scatterlist.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/card.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/host.h> 26da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/mmc.h> 27da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/sd.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29aaac1b470bd0dccb30912356617069dc6199cc80Pierre Ossman#include "core.h" 30ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman#include "bus.h" 31ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman#include "host.h" 32e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman#include "sdio_bus.h" 33da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 34da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include "mmc_ops.h" 35da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include "sd_ops.h" 365c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman#include "sdio_ops.h" 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 387ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanextern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); 397ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanextern int mmc_attach_sd(struct mmc_host *host, u32 ocr); 405c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossmanextern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanstatic struct workqueue_struct *workqueue; 43ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 44ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman/* 45ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman * Internal function. Schedule delayed work in the MMC work queue. 46ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman */ 47ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanstatic int mmc_schedule_delayed_work(struct delayed_work *work, 48ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman unsigned long delay) 49ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman{ 50ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman return queue_delayed_work(workqueue, work, delay); 51ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman} 52ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 53ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman/* 54ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman * Internal function. Flush all scheduled work from the MMC work queue. 55ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman */ 56ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanstatic void mmc_flush_scheduled_work(void) 57ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman{ 58ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman flush_workqueue(workqueue); 59ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman} 60ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 62fe10c6abea8bc83291a13e0580b3e4c355710b09Russell King * mmc_request_done - finish processing an MMC request 63fe10c6abea8bc83291a13e0580b3e4c355710b09Russell King * @host: MMC host which completed request 64fe10c6abea8bc83291a13e0580b3e4c355710b09Russell King * @mrq: MMC request which request 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MMC drivers should call this function when they have completed 67fe10c6abea8bc83291a13e0580b3e4c355710b09Russell King * their processing of a request. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command *cmd = mrq->cmd; 72920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King int err = cmd->error; 73920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err && cmd->retries) { 75e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: req failed (CMD%u): %d, retrying...\n", 76e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), cmd->opcode, err); 77e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->retries--; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->error = 0; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ops->request(host, mrq); 81e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman } else { 82e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", 83e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), cmd->opcode, err, 84e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman cmd->resp[0], cmd->resp[1], 85e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman cmd->resp[2], cmd->resp[3]); 86e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 87e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman if (mrq->data) { 88e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: %d bytes transferred: %d\n", 89e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), 90e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->data->bytes_xfered, mrq->data->error); 91e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman } 92e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 93e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman if (mrq->stop) { 94e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n", 95e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), mrq->stop->opcode, 96e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->stop->error, 97e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->stop->resp[0], mrq->stop->resp[1], 98e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->stop->resp[2], mrq->stop->resp[3]); 99e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman } 100e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 101e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman if (mrq->done) 102e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->done(mrq); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_request_done); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunkstatic void 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmc_start_request(struct mmc_host *host, struct mmc_request *mrq) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 111976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman#ifdef CONFIG_MMC_DEBUG 112976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman unsigned int i, sz; 113976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman#endif 114976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman 115920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King pr_debug("%s: starting CMD%u arg %08x flags %08x\n", 116920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_hostname(host), mrq->cmd->opcode, 117920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mrq->cmd->arg, mrq->cmd->flags); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman if (mrq->data) { 120e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: blksz %d blocks %d flags %08x " 121e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman "tsac %d ms nsac %d\n", 122e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), mrq->data->blksz, 123e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->data->blocks, mrq->data->flags, 124ce252edd869ba1fee6a9a6f83e20f349d4c4d669Pierre Ossman mrq->data->timeout_ns / 1000000, 125e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->data->timeout_clks); 126e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman } 127e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 128e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman if (mrq->stop) { 129e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman pr_debug("%s: CMD%u arg %08x flags %08x\n", 130e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mmc_hostname(host), mrq->stop->opcode, 131e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman mrq->stop->arg, mrq->stop->flags); 132e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman } 133e4d217087458914a6d5d9fd034d7237e6530c619Pierre Ossman 134f22ee4edf63e7480511112d9965c71e07be3f8b7Pierre Ossman WARN_ON(!host->claimed); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->cmd->error = 0; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->cmd->mrq = mrq; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->data) { 139fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman BUG_ON(mrq->data->blksz > host->max_blk_size); 14055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman BUG_ON(mrq->data->blocks > host->max_blk_count); 14155db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman BUG_ON(mrq->data->blocks * mrq->data->blksz > 14255db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman host->max_req_size); 143fe4a3c7a20f14d86022a8132adbf6ddb98e7197cPierre Ossman 144976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman#ifdef CONFIG_MMC_DEBUG 145976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman sz = 0; 146976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman for (i = 0;i < mrq->data->sg_len;i++) 147976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman sz += mrq->data->sg[i].length; 148976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman BUG_ON(sz != mrq->data->blocks * mrq->data->blksz); 149976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman#endif 150976d9276c826d6b35e4a2478fd4978dbd63bdd6fPierre Ossman 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->cmd->data = mrq->data; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->error = 0; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->mrq = mrq; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mrq->stop) { 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->data->stop = mrq->stop; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->stop->error = 0; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->stop->mrq = mrq; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ops->request(host, mrq); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_wait_done(struct mmc_request *mrq) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete(mrq->done_data); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16867a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman/** 16967a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * mmc_wait_for_req - start a request and wait for completion 17067a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * @host: MMC host to start command 17167a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * @mrq: MMC request to start 17267a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * 17367a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * Start a new MMC custom command request for a host, and wait 17467a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * for the command to complete. Does not attempt to parse the 17567a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * response. 17667a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman */ 17767a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossmanvoid mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1790afffc723c8041a005134099847ac2a2fd0316a0Ingo Molnar DECLARE_COMPLETION_ONSTACK(complete); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->done_data = &complete; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq->done = mmc_wait_done; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_start_request(host, mrq); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&complete); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_wait_for_req); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mmc_wait_for_cmd - start a command and wait for completion 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: MMC host to start command 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @cmd: MMC command to start 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @retries: maximum number of retries 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start a new MMC command for a host, and wait for the command 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to complete. Return any error that occurred while the command 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * was executing. Do not attempt to parse the response. 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_request mrq; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 205f22ee4edf63e7480511112d9965c71e07be3f8b7Pierre Ossman BUG_ON(!host->claimed); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&mrq, 0, sizeof(struct mmc_request)); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cmd->resp, 0, sizeof(cmd->resp)); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->retries = retries; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq.cmd = cmd; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->data = NULL; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_wait_for_req(host, &mrq); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cmd->error; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_wait_for_cmd); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222335eadf2ef6a1122a720aea98e758e5d431da87dPierre Ossman/** 223d773d7255199a6c8934e197756f54a1115dd127bRussell King * mmc_set_data_timeout - set the timeout for a data command 224d773d7255199a6c8934e197756f54a1115dd127bRussell King * @data: data phase for command 225d773d7255199a6c8934e197756f54a1115dd127bRussell King * @card: the MMC card associated with the data transfer 22667a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * 22767a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * Computes the data timeout parameters according to the 22867a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * correct algorithm given the card type. 229d773d7255199a6c8934e197756f54a1115dd127bRussell King */ 230b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossmanvoid mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) 231d773d7255199a6c8934e197756f54a1115dd127bRussell King{ 232d773d7255199a6c8934e197756f54a1115dd127bRussell King unsigned int mult; 233d773d7255199a6c8934e197756f54a1115dd127bRussell King 234d773d7255199a6c8934e197756f54a1115dd127bRussell King /* 235e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman * SDIO cards only define an upper 1 s limit on access. 236e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman */ 237e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman if (mmc_card_sdio(card)) { 238e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman data->timeout_ns = 1000000000; 239e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman data->timeout_clks = 0; 240e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman return; 241e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman } 242e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman 243e6f918bf39773d712ab5b457bff54ade3bda0cb1Pierre Ossman /* 244d773d7255199a6c8934e197756f54a1115dd127bRussell King * SD cards use a 100 multiplier rather than 10 245d773d7255199a6c8934e197756f54a1115dd127bRussell King */ 246d773d7255199a6c8934e197756f54a1115dd127bRussell King mult = mmc_card_sd(card) ? 100 : 10; 247d773d7255199a6c8934e197756f54a1115dd127bRussell King 248d773d7255199a6c8934e197756f54a1115dd127bRussell King /* 249d773d7255199a6c8934e197756f54a1115dd127bRussell King * Scale up the multiplier (and therefore the timeout) by 250d773d7255199a6c8934e197756f54a1115dd127bRussell King * the r2w factor for writes. 251d773d7255199a6c8934e197756f54a1115dd127bRussell King */ 252b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman if (data->flags & MMC_DATA_WRITE) 253d773d7255199a6c8934e197756f54a1115dd127bRussell King mult <<= card->csd.r2w_factor; 254d773d7255199a6c8934e197756f54a1115dd127bRussell King 255d773d7255199a6c8934e197756f54a1115dd127bRussell King data->timeout_ns = card->csd.tacc_ns * mult; 256d773d7255199a6c8934e197756f54a1115dd127bRussell King data->timeout_clks = card->csd.tacc_clks * mult; 257d773d7255199a6c8934e197756f54a1115dd127bRussell King 258d773d7255199a6c8934e197756f54a1115dd127bRussell King /* 259d773d7255199a6c8934e197756f54a1115dd127bRussell King * SD cards also have an upper limit on the timeout. 260d773d7255199a6c8934e197756f54a1115dd127bRussell King */ 261d773d7255199a6c8934e197756f54a1115dd127bRussell King if (mmc_card_sd(card)) { 262d773d7255199a6c8934e197756f54a1115dd127bRussell King unsigned int timeout_us, limit_us; 263d773d7255199a6c8934e197756f54a1115dd127bRussell King 264d773d7255199a6c8934e197756f54a1115dd127bRussell King timeout_us = data->timeout_ns / 1000; 265d773d7255199a6c8934e197756f54a1115dd127bRussell King timeout_us += data->timeout_clks * 1000 / 266d773d7255199a6c8934e197756f54a1115dd127bRussell King (card->host->ios.clock / 1000); 267d773d7255199a6c8934e197756f54a1115dd127bRussell King 268b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman if (data->flags & MMC_DATA_WRITE) 269d773d7255199a6c8934e197756f54a1115dd127bRussell King limit_us = 250000; 270d773d7255199a6c8934e197756f54a1115dd127bRussell King else 271d773d7255199a6c8934e197756f54a1115dd127bRussell King limit_us = 100000; 272d773d7255199a6c8934e197756f54a1115dd127bRussell King 273fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale /* 274fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale * SDHC cards always use these fixed values. 275fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale */ 276fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale if (timeout_us > limit_us || mmc_card_blockaddr(card)) { 277d773d7255199a6c8934e197756f54a1115dd127bRussell King data->timeout_ns = limit_us * 1000; 278d773d7255199a6c8934e197756f54a1115dd127bRussell King data->timeout_clks = 0; 279d773d7255199a6c8934e197756f54a1115dd127bRussell King } 280d773d7255199a6c8934e197756f54a1115dd127bRussell King } 281d773d7255199a6c8934e197756f54a1115dd127bRussell King} 282d773d7255199a6c8934e197756f54a1115dd127bRussell KingEXPORT_SYMBOL(mmc_set_data_timeout); 283d773d7255199a6c8934e197756f54a1115dd127bRussell King 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2852342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * __mmc_claim_host - exclusively claim a host 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: mmc host to claim 2872342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * @abort: whether or not the operation should be aborted 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2892342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * Claim a host for a set of operations. If @abort is non null and 2902342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * dereference a non-zero value then this will return prematurely with 2912342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * that non-zero value without acquiring the lock. Returns zero 2922342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre * with the lock held otherwise. 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2942342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitreint __mmc_claim_host(struct mmc_host *host, atomic_t *abort) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2982342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre int stop; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 300cf795bfb3ad4e2f8f6bb346aa8edb8272d4c70a2Pierre Ossman might_sleep(); 301cf795bfb3ad4e2f8f6bb346aa8edb8272d4c70a2Pierre Ossman 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&host->wq, &wait); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&host->lock, flags); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 3062342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre stop = abort ? atomic_read(abort) : 0; 3072342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre if (stop || !host->claimed) 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&host->lock, flags); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&host->lock, flags); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_current_state(TASK_RUNNING); 3142342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre if (!stop) 3152342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre host->claimed = 1; 3162342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre else 3172342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre wake_up(&host->wq); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&host->lock, flags); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&host->wq, &wait); 3202342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas Pitre return stop; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3232342f3323c9a76367a1d7f9a35525ee3cb3911dfNicolas PitreEXPORT_SYMBOL(__mmc_claim_host); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mmc_release_host - release a host 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: mmc host to release 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release a MMC host, allowing others to claim the host 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for their operations. 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid mmc_release_host(struct mmc_host *host) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 336f22ee4edf63e7480511112d9965c71e07be3f8b7Pierre Ossman BUG_ON(!host->claimed); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&host->lock, flags); 339f22ee4edf63e7480511112d9965c71e07be3f8b7Pierre Ossman host->claimed = 0; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&host->lock, flags); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&host->wq); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_release_host); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3477ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 3487ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Internal function that does the actual ios call to the host driver, 3497ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * optionally printing some debug output. 3507ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 351920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell Kingstatic inline void mmc_set_ios(struct mmc_host *host) 352920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King{ 353920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King struct mmc_ios *ios = &host->ios; 354920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King 355cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " 356cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman "width %u timing %u\n", 357920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_hostname(host), ios->clock, ios->bus_mode, 358920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King ios->power_mode, ios->chip_select, ios->vdd, 359cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman ios->bus_width, ios->timing); 360fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale 361920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King host->ops->set_ios(host, ios); 362920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King} 363920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King 3647ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 3657ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Control chip select pin on a host. 3667ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 367da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanvoid mmc_set_chip_select(struct mmc_host *host, int mode) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 369da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman host->ios.chip_select = mode; 370da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mmc_set_ios(host); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3747ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Sets the host clock to the highest possible frequency that 3757ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * is below "hz". 3767ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 3777ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_set_clock(struct mmc_host *host, unsigned int hz) 3787ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman{ 3797ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman WARN_ON(hz < host->f_min); 3807ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 3817ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (hz > host->f_max) 3827ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman hz = host->f_max; 3837ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 3847ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->ios.clock = hz; 3857ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_set_ios(host); 3867ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman} 3877ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 3887ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 3897ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Change the bus mode (open drain/push-pull) of a host. 3907ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 3917ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) 3927ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman{ 3937ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->ios.bus_mode = mode; 3947ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_set_ios(host); 3957ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman} 3967ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 3977ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 3987ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Change data bus width of a host. 3997ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 4007ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_set_bus_width(struct mmc_host *host, unsigned int width) 4017ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman{ 4027ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->ios.bus_width = width; 4037ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_set_ios(host); 4047ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman} 4057ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 4067ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mask off any voltages we don't support and select 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the lowest voltage 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4107ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanu32 mmc_select_voltage(struct mmc_host *host, u32 ocr) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bit; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ocr &= host->ocr_avail; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bit = ffs(ocr); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bit) { 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bit -= 1; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42063ef731aa6a81e286de78dcc92241d123424ed39Timo Teras ocr &= 3 << bit; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.vdd = bit; 423920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_set_ios(host); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ocr = 0; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ocr; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4327ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Select timing parameters for host. 433b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman */ 4347ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_set_timing(struct mmc_host *host, unsigned int timing) 435b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman{ 4367ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->ios.timing = timing; 4377ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_set_ios(host); 438b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman} 439b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman 440b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman/* 44145f8245b972e360c19aec9032e2a2033b8ac3719Russell King * Apply power to the MMC stack. This is a two-stage process. 44245f8245b972e360c19aec9032e2a2033b8ac3719Russell King * First, we enable power to the card without the clock running. 44345f8245b972e360c19aec9032e2a2033b8ac3719Russell King * We then wait a bit for the power to stabilise. Finally, 44445f8245b972e360c19aec9032e2a2033b8ac3719Russell King * enable the bus drivers and clock to the card. 44545f8245b972e360c19aec9032e2a2033b8ac3719Russell King * 44645f8245b972e360c19aec9032e2a2033b8ac3719Russell King * We must _NOT_ enable the clock prior to power stablising. 44745f8245b972e360c19aec9032e2a2033b8ac3719Russell King * 44845f8245b972e360c19aec9032e2a2033b8ac3719Russell King * If a host does all the power sequencing itself, ignore the 44945f8245b972e360c19aec9032e2a2033b8ac3719Russell King * initial MMC_POWER_UP stage. 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_power_up(struct mmc_host *host) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bit = fls(host->ocr_avail) - 1; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.vdd = bit; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; 457865e9f13c94891daed4f6a5f69c5d6ec04d4932fPierre Ossman host->ios.chip_select = MMC_CS_DONTCARE; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.power_mode = MMC_POWER_UP; 459f218278a456b3c272b480443c89004c3d2a49f18Pierre Ossman host->ios.bus_width = MMC_BUS_WIDTH_1; 460cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman host->ios.timing = MMC_TIMING_LEGACY; 461920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_set_ios(host); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_delay(1); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.clock = host->f_min; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.power_mode = MMC_POWER_ON; 467920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_set_ios(host); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_delay(2); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_power_off(struct mmc_host *host) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.clock = 0; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.vdd = 0; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; 477865e9f13c94891daed4f6a5f69c5d6ec04d4932fPierre Ossman host->ios.chip_select = MMC_CS_DONTCARE; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ios.power_mode = MMC_POWER_OFF; 479f218278a456b3c272b480443c89004c3d2a49f18Pierre Ossman host->ios.bus_width = MMC_BUS_WIDTH_1; 480cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman host->ios.timing = MMC_TIMING_LEGACY; 481920e70c5c603ada05dd480ca0ccc0ae12a5fdc39Russell King mmc_set_ios(host); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 485393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk * Cleanup when the last reference to the bus operator is dropped. 486393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk */ 487393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunkvoid __mmc_release_bus(struct mmc_host *host) 488393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk{ 489393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk BUG_ON(!host); 490393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk BUG_ON(host->bus_refs); 491393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk BUG_ON(!host->bus_dead); 492393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 493393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk host->bus_ops = NULL; 494393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk} 495393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 496393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk/* 497393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk * Increase reference count of bus operator 498393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk */ 499393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunkstatic inline void mmc_bus_get(struct mmc_host *host) 500393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk{ 501393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk unsigned long flags; 502393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 503393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk spin_lock_irqsave(&host->lock, flags); 504393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk host->bus_refs++; 505393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk spin_unlock_irqrestore(&host->lock, flags); 506393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk} 507393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 508393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk/* 509393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk * Decrease reference count of bus operator and free it if 510393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk * it is the last reference. 511393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk */ 512393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunkstatic inline void mmc_bus_put(struct mmc_host *host) 513393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk{ 514393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk unsigned long flags; 515393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 516393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk spin_lock_irqsave(&host->lock, flags); 517393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk host->bus_refs--; 518393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk if ((host->bus_refs == 0) && host->bus_ops) 519393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk __mmc_release_bus(host); 520393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk spin_unlock_irqrestore(&host->lock, flags); 521393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk} 522393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 523393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk/* 5247ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Assign a mmc bus handler to a host. Only one bus handler may control a 5257ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * host at any given time. 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5277ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5297ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman unsigned long flags; 530e45a1bd20fa5b920901879e85cdf5eda21f78d7cPhilip Langdale 5317ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!host); 5327ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!ops); 533b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman 5347ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!host->claimed); 535bce40a36de574376f41f1ff3c4d212a7da2a3c90Philip Langdale 5367ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman spin_lock_irqsave(&host->lock, flags); 537bce40a36de574376f41f1ff3c4d212a7da2a3c90Philip Langdale 5387ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(host->bus_ops); 5397ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(host->bus_refs); 540b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman 5417ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_ops = ops; 5427ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_refs = 1; 5437ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_dead = 0; 544b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman 5457ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman spin_unlock_irqrestore(&host->lock, flags); 546b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman} 547b57c43ad81602589afca3948a5a7121e40026e17Pierre Ossman 5487ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman/* 5497ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Remove the current bus handler from a host. Assumes that there are 5507ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * no interesting cards left, so the bus is powered down. 5517ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman */ 5527ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossmanvoid mmc_detach_bus(struct mmc_host *host) 5537ccd266e676a3f0c6f8f897f58b684cac3dd1650Pierre Ossman{ 5547ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman unsigned long flags; 5557ccd266e676a3f0c6f8f897f58b684cac3dd1650Pierre Ossman 5567ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!host); 5577ccd266e676a3f0c6f8f897f58b684cac3dd1650Pierre Ossman 5587ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!host->claimed); 5597ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(!host->bus_ops); 560cd9277c011a99769fa371521b460ed57f6d280b1Pierre Ossman 5617ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman spin_lock_irqsave(&host->lock, flags); 5627ccd266e676a3f0c6f8f897f58b684cac3dd1650Pierre Ossman 5637ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_dead = 1; 5647ccd266e676a3f0c6f8f897f58b684cac3dd1650Pierre Ossman 5657ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman spin_unlock_irqrestore(&host->lock, flags); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5677ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_power_off(host); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5697ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_put(host); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mmc_detect_change - process change of state on a MMC socket 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: host which changed state. 5758dc003359cc3996abad9e53a7b2280b272610283Richard Purdie * @delay: optional delay to wait before detection (jiffies) 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 57767a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * MMC drivers should call this when they detect a card has been 57867a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * inserted or removed. The MMC layer will confirm that any 57967a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * present card is still functional, and initialize any newly 58067a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * inserted. 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5828dc003359cc3996abad9e53a7b2280b272610283Richard Purdievoid mmc_detect_change(struct mmc_host *host, unsigned long delay) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5843b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman#ifdef CONFIG_MMC_DEBUG 5851efd48b3ae8f89a1d04f1e36be96764d7bf43ae9Pierre Ossman unsigned long flags; 58601f41ec7b36e14da18a4e162ef697ae358f36e37Andrew Morton spin_lock_irqsave(&host->lock, flags); 5873b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman BUG_ON(host->removed); 58801f41ec7b36e14da18a4e162ef697ae358f36e37Andrew Morton spin_unlock_irqrestore(&host->lock, flags); 5893b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman#endif 5903b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman 591c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells mmc_schedule_delayed_work(&host->detect, delay); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_detect_change); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 597b93931a61a119575f84c33af2438b9384fde9eb7Pierre Ossmanvoid mmc_rescan(struct work_struct *work) 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 599c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct mmc_host *host = 600c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells container_of(work, struct mmc_host, detect.work); 6017ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman u32 ocr; 6027ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman int err; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6047ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_get(host); 605b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman 6067ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (host->bus_ops == NULL) { 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6087ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * Only we can add a new handler, so it's safe to 6097ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman * release the lock here. 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6117ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_put(host); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6137ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_claim_host(host); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6157ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_power_up(host); 6167ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_go_idle(host); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6187ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_send_if_cond(host, host->ocr_avail); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6205c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman /* 6215c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman * First we search for SDIO... 6225c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman */ 6235c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman err = mmc_send_io_op_cond(host, 0, &ocr); 6245c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman if (!err) { 6255c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman if (mmc_attach_sdio(host, ocr)) 6265c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman mmc_power_off(host); 6275c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman return; 6285c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman } 6295c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman 6305c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman /* 6315c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman * ...then normal SD... 6325c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman */ 6337ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman err = mmc_send_app_op_cond(host, 0, &ocr); 63417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!err) { 6357ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (mmc_attach_sd(host, ocr)) 6367ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_power_off(host); 6375c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman return; 6385c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman } 6395c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman 6405c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman /* 6415c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman * ...and finally MMC. 6425c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman */ 6435c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman err = mmc_send_op_cond(host, 0, &ocr); 6445c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman if (!err) { 6455c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman if (mmc_attach_mmc(host, ocr)) 6467ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_power_off(host); 6475c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman return; 6487ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman } 6495c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman 6505c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman mmc_release_host(host); 6515c4e6f1301649d5b29dd0f70e6da83e728ab5ca5Pierre Ossman mmc_power_off(host); 6527ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman } else { 6537ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (host->bus_ops->detect && !host->bus_dead) 6547ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_ops->detect(host); 6557ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 6567ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_put(host); 6577ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman } 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 660b93931a61a119575f84c33af2438b9384fde9eb7Pierre Ossmanvoid mmc_start_host(struct mmc_host *host) 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 662b93931a61a119575f84c33af2438b9384fde9eb7Pierre Ossman mmc_power_off(host); 663b93931a61a119575f84c33af2438b9384fde9eb7Pierre Ossman mmc_detect_change(host, 0); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 666b93931a61a119575f84c33af2438b9384fde9eb7Pierre Ossmanvoid mmc_stop_host(struct mmc_host *host) 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6683b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman#ifdef CONFIG_MMC_DEBUG 6691efd48b3ae8f89a1d04f1e36be96764d7bf43ae9Pierre Ossman unsigned long flags; 6701efd48b3ae8f89a1d04f1e36be96764d7bf43ae9Pierre Ossman spin_lock_irqsave(&host->lock, flags); 6713b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman host->removed = 1; 6721efd48b3ae8f89a1d04f1e36be96764d7bf43ae9Pierre Ossman spin_unlock_irqrestore(&host->lock, flags); 6733b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman#endif 6743b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman 6753b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman mmc_flush_scheduled_work(); 6763b91e5507cddaca53bccf1524ff11a0ac5c85531Pierre Ossman 6777ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_get(host); 6787ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (host->bus_ops && !host->bus_dead) { 6797ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (host->bus_ops->remove) 6807ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman host->bus_ops->remove(host); 6817ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 6827ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_claim_host(host); 6837ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_detach_bus(host); 6847ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_release_host(host); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6867ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_put(host); 6877ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 6887ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman BUG_ON(host->card); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_power_off(host); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mmc_suspend_host - suspend a host 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: mmc host 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @state: suspend mode (PM_SUSPEND_xxx) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 700e5378ca8c0ab684bd9339dc6827dd5a042f9e6fcPavel Machekint mmc_suspend_host(struct mmc_host *host, pm_message_t state) 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 702b5af25bee2de2f6cd1ac74ba737cbc4f3d303e5dPierre Ossman mmc_flush_scheduled_work(); 703b5af25bee2de2f6cd1ac74ba737cbc4f3d303e5dPierre Ossman 7047ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_get(host); 7057ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman if (host->bus_ops && !host->bus_dead) { 7066abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman if (host->bus_ops->suspend) 7076abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman host->bus_ops->suspend(host); 7086abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman if (!host->bus_ops->resume) { 7096abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman if (host->bus_ops->remove) 7106abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman host->bus_ops->remove(host); 7116abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman 7126abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_claim_host(host); 7136abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_detach_bus(host); 7146abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_release_host(host); 7156abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman } 716b5af25bee2de2f6cd1ac74ba737cbc4f3d303e5dPierre Ossman } 7177ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman mmc_bus_put(host); 7187ea239d9e6d6993469a6a8ca83ff23834dfc3fcePierre Ossman 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_power_off(host); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_suspend_host); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mmc_resume_host - resume a previously suspended host 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @host: mmc host 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint mmc_resume_host(struct mmc_host *host) 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7326abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_bus_get(host); 7336abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman if (host->bus_ops && !host->bus_dead) { 7346abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_power_up(host); 7356abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman BUG_ON(!host->bus_ops->resume); 7366abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman host->bus_ops->resume(host); 7376abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman } 7386abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_bus_put(host); 7396abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman 7406abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman /* 7416abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman * We add a slight delay here so that resume can progress 7426abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman * in parallel. 7436abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman */ 7446abaa0c9fec563538f2a28a682af8c89bb9b125cPierre Ossman mmc_detect_change(host, 1); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(mmc_resume_host); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 753ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanstatic int __init mmc_init(void) 754ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman{ 755ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman int ret; 756ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 757ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman workqueue = create_singlethread_workqueue("kmmcd"); 758ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman if (!workqueue) 759ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman return -ENOMEM; 760ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 761ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman ret = mmc_register_bus(); 762e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (ret) 763e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman goto destroy_workqueue; 764e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 765e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman ret = mmc_register_host_class(); 766e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (ret) 767e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman goto unregister_bus; 768e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 769e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman ret = sdio_register_bus(); 770e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman if (ret) 771e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman goto unregister_host_class; 772e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 773e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman return 0; 774e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 775e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanunregister_host_class: 776e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman mmc_unregister_host_class(); 777e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmanunregister_bus: 778e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman mmc_unregister_bus(); 779e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossmandestroy_workqueue: 780e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman destroy_workqueue(workqueue); 781e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman 782ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman return ret; 783ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman} 784ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 785ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanstatic void __exit mmc_exit(void) 786ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman{ 787e29a7d73f4277eb92aa64e17017dea33460828efPierre Ossman sdio_unregister_bus(); 788ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman mmc_unregister_host_class(); 789ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman mmc_unregister_bus(); 790ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman destroy_workqueue(workqueue); 791ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman} 792ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 79326074962e8f547b96614dbe248748ba2a1996ca3Nicolas Pitresubsys_initcall(mmc_init); 794ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossmanmodule_exit(mmc_exit); 795ffce2e7e7060c949ccd703dacc9b3dd81b377373Pierre Ossman 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 797