Merge tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC update from Chris Ball: "MMC highlights for 3.9: Core: - Support for packed commands in eMMC 4.5. (This requires a host capability to be turned on. It increases write throughput by 20%+, but may also increase average write latency; more testing needed.) - Add DT bindings for capability flags. - Add mmc_of_parse() for shared DT parsing between drivers. Drivers: - android-goldfish: New MMC driver for the Android Goldfish emulator. - mvsdio: Add DT bindings, pinctrl, use slot-gpio for card detection. - omap_hsmmc: Fix boot hangs with RPMB partitions. - sdhci-bcm2835: New driver for controller used by Raspberry Pi. - sdhci-esdhc-imx: Add 8-bit data, auto CMD23 support, use slot-gpio. - sh_mmcif: Add support for eMMC DDR, bundled MMCIF IRQs. - tmio_mmc: Add DT bindings, support for vccq regulator" * tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (92 commits) mmc: tegra: assume CONFIG_OF, remove platform data mmc: add DT bindings for more MMC capability flags mmc: tmio: add support for the VccQ regulator mmc: tmio: remove unused and deprecated symbols mmc: sh_mobile_sdhi: use managed resource allocations mmc: sh_mobile_sdhi: remove unused .pdata field mmc: tmio-mmc: parse device-tree bindings mmc: tmio-mmc: define device-tree bindings mmc: sh_mmcif: use mmc_of_parse() to parse standard MMC DT bindings mmc: (cosmetic) remove "extern" from function declarations mmc: provide a standard MMC device-tree binding parser centrally mmc: detailed definition of CD and WP MMC line polarities in DT mmc: sdhi, tmio: only check flags in tmio-mmc driver proper mmc: sdhci: Fix parameter of sdhci_do_start_signal_voltage_switch() mmc: sdhci: check voltage range only on regulators aware of voltage value mmc: bcm2835: set SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK mmc: support packed write command for eMMC4.5 devices mmc: add packed command feature of eMMC4.5 mmc: rtsx: remove driving adjustment mmc: use regulator_can_change_voltage() instead of regulator_count_voltages ...
This commit is contained in:
@@ -321,6 +321,7 @@ int mmc_add_card(struct mmc_card *card)
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_add_card_debugfs(card);
|
||||
#endif
|
||||
mmc_init_context_info(card->host);
|
||||
|
||||
ret = device_add(&card->dev);
|
||||
if (ret)
|
||||
|
@@ -319,11 +319,45 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_start_bkops);
|
||||
|
||||
/*
|
||||
* mmc_wait_data_done() - done callback for data request
|
||||
* @mrq: done data request
|
||||
*
|
||||
* Wakes up mmc context, passed as a callback to host controller driver
|
||||
*/
|
||||
static void mmc_wait_data_done(struct mmc_request *mrq)
|
||||
{
|
||||
mrq->host->context_info.is_done_rcv = true;
|
||||
wake_up_interruptible(&mrq->host->context_info.wait);
|
||||
}
|
||||
|
||||
static void mmc_wait_done(struct mmc_request *mrq)
|
||||
{
|
||||
complete(&mrq->completion);
|
||||
}
|
||||
|
||||
/*
|
||||
*__mmc_start_data_req() - starts data request
|
||||
* @host: MMC host to start the request
|
||||
* @mrq: data request to start
|
||||
*
|
||||
* Sets the done callback to be called when request is completed by the card.
|
||||
* Starts data mmc request execution
|
||||
*/
|
||||
static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
mrq->done = mmc_wait_data_done;
|
||||
mrq->host = host;
|
||||
if (mmc_card_removed(host->card)) {
|
||||
mrq->cmd->error = -ENOMEDIUM;
|
||||
mmc_wait_data_done(mrq);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
mmc_start_request(host, mrq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
init_completion(&mrq->completion);
|
||||
@@ -337,6 +371,62 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mmc_wait_for_data_req_done() - wait for request completed
|
||||
* @host: MMC host to prepare the command.
|
||||
* @mrq: MMC request to wait for
|
||||
*
|
||||
* Blocks MMC context till host controller will ack end of data request
|
||||
* execution or new request notification arrives from the block layer.
|
||||
* Handles command retries.
|
||||
*
|
||||
* Returns enum mmc_blk_status after checking errors.
|
||||
*/
|
||||
static int mmc_wait_for_data_req_done(struct mmc_host *host,
|
||||
struct mmc_request *mrq,
|
||||
struct mmc_async_req *next_req)
|
||||
{
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_context_info *context_info = &host->context_info;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
while (1) {
|
||||
wait_event_interruptible(context_info->wait,
|
||||
(context_info->is_done_rcv ||
|
||||
context_info->is_new_req));
|
||||
spin_lock_irqsave(&context_info->lock, flags);
|
||||
context_info->is_waiting_last_req = false;
|
||||
spin_unlock_irqrestore(&context_info->lock, flags);
|
||||
if (context_info->is_done_rcv) {
|
||||
context_info->is_done_rcv = false;
|
||||
context_info->is_new_req = false;
|
||||
cmd = mrq->cmd;
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card)) {
|
||||
err = host->areq->err_check(host->card,
|
||||
host->areq);
|
||||
break; /* return err */
|
||||
} else {
|
||||
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
|
||||
mmc_hostname(host),
|
||||
cmd->opcode, cmd->error);
|
||||
cmd->retries--;
|
||||
cmd->error = 0;
|
||||
host->ops->request(host, mrq);
|
||||
continue; /* wait for done/new event again */
|
||||
}
|
||||
} else if (context_info->is_new_req) {
|
||||
context_info->is_new_req = false;
|
||||
if (!next_req) {
|
||||
err = MMC_BLK_NEW_REQUEST;
|
||||
break; /* return err */
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mmc_wait_for_req_done(struct mmc_host *host,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
@@ -426,8 +516,16 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
mmc_pre_req(host, areq->mrq, !host->areq);
|
||||
|
||||
if (host->areq) {
|
||||
mmc_wait_for_req_done(host, host->areq->mrq);
|
||||
err = host->areq->err_check(host->card, host->areq);
|
||||
err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
|
||||
if (err == MMC_BLK_NEW_REQUEST) {
|
||||
if (error)
|
||||
*error = err;
|
||||
/*
|
||||
* The previous request was not completed,
|
||||
* nothing to return
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Check BKOPS urgency for each R1 response
|
||||
*/
|
||||
@@ -439,14 +537,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
}
|
||||
|
||||
if (!err && areq)
|
||||
start_err = __mmc_start_req(host, areq->mrq);
|
||||
start_err = __mmc_start_data_req(host, areq->mrq);
|
||||
|
||||
if (host->areq)
|
||||
mmc_post_req(host, host->areq->mrq, 0);
|
||||
|
||||
/* Cancel a prepared request if it was not started. */
|
||||
if ((err || start_err) && areq)
|
||||
mmc_post_req(host, areq->mrq, -EINVAL);
|
||||
mmc_post_req(host, areq->mrq, -EINVAL);
|
||||
|
||||
if (err)
|
||||
host->areq = NULL;
|
||||
@@ -1137,7 +1235,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
|
||||
*/
|
||||
voltage = regulator_get_voltage(supply);
|
||||
|
||||
if (regulator_count_voltages(supply) == 1)
|
||||
if (!regulator_can_change_voltage(supply))
|
||||
min_uV = max_uV = voltage;
|
||||
|
||||
if (voltage < 0)
|
||||
@@ -1219,10 +1317,30 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
return ocr;
|
||||
}
|
||||
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
|
||||
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
{
|
||||
int err = 0;
|
||||
int old_signal_voltage = host->ios.signal_voltage;
|
||||
|
||||
host->ios.signal_voltage = signal_voltage;
|
||||
if (host->ops->start_signal_voltage_switch) {
|
||||
mmc_host_clk_hold(host);
|
||||
err = host->ops->start_signal_voltage_switch(host, &host->ios);
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
if (err)
|
||||
host->ios.signal_voltage = old_signal_voltage;
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err = 0;
|
||||
u32 clock;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
@@ -1230,27 +1348,81 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
|
||||
* Send CMD11 only if the request is to switch the card to
|
||||
* 1.8V signalling.
|
||||
*/
|
||||
if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
|
||||
cmd.opcode = SD_SWITCH_VOLTAGE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
|
||||
return __mmc_set_signal_voltage(host, signal_voltage);
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* If we cannot switch voltages, return failure so the caller
|
||||
* can continue without UHS mode
|
||||
*/
|
||||
if (!host->ops->start_signal_voltage_switch)
|
||||
return -EPERM;
|
||||
if (!host->ops->card_busy)
|
||||
pr_warning("%s: cannot verify signal voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
cmd.opcode = SD_SWITCH_VOLTAGE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
|
||||
mmc_host_clk_hold(host);
|
||||
/*
|
||||
* The card should drive cmd and dat[0:3] low immediately
|
||||
* after the response of cmd11, but wait 1 ms to be sure
|
||||
*/
|
||||
mmc_delay(1);
|
||||
if (host->ops->card_busy && !host->ops->card_busy(host)) {
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
/*
|
||||
* During a signal voltage level switch, the clock must be gated
|
||||
* for 5 ms according to the SD spec
|
||||
*/
|
||||
clock = host->ios.clock;
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (__mmc_set_signal_voltage(host, signal_voltage)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
*/
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
host->ios.signal_voltage = signal_voltage;
|
||||
/* Keep clock gated for at least 5 ms */
|
||||
mmc_delay(5);
|
||||
host->ios.clock = clock;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (host->ops->start_signal_voltage_switch) {
|
||||
mmc_host_clk_hold(host);
|
||||
err = host->ops->start_signal_voltage_switch(host, &host->ios);
|
||||
mmc_host_clk_release(host);
|
||||
/* Wait for at least 1 ms according to spec */
|
||||
mmc_delay(1);
|
||||
|
||||
/*
|
||||
* Failure to switch is indicated by the card holding
|
||||
* dat[0:3] low
|
||||
*/
|
||||
if (host->ops->card_busy && host->ops->card_busy(host))
|
||||
err = -EAGAIN;
|
||||
|
||||
power_cycle:
|
||||
if (err) {
|
||||
pr_debug("%s: Signal voltage switch failed, "
|
||||
"power cycling card\n", mmc_hostname(host));
|
||||
mmc_power_cycle(host);
|
||||
}
|
||||
|
||||
mmc_host_clk_release(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1314,7 +1486,7 @@ static void mmc_power_up(struct mmc_host *host)
|
||||
mmc_set_ios(host);
|
||||
|
||||
/* Set signal voltage to 3.3V */
|
||||
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
|
||||
__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
@@ -1372,6 +1544,14 @@ void mmc_power_off(struct mmc_host *host)
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
void mmc_power_cycle(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_off(host);
|
||||
/* Wait at least 1 ms according to SD spec */
|
||||
mmc_delay(1);
|
||||
mmc_power_up(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup when the last reference to the bus operator is dropped.
|
||||
*/
|
||||
@@ -2388,6 +2568,7 @@ EXPORT_SYMBOL(mmc_flush_cache);
|
||||
* Turn the cache ON/OFF.
|
||||
* Turning the cache OFF shall trigger flushing of the data
|
||||
* to the non-volatile storage.
|
||||
* This function should be called with host claimed
|
||||
*/
|
||||
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
{
|
||||
@@ -2399,7 +2580,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
mmc_card_is_removable(host))
|
||||
return err;
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (card && mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0)) {
|
||||
enable = !!enable;
|
||||
@@ -2417,7 +2597,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
card->ext_csd.cache_ctrl = enable;
|
||||
}
|
||||
}
|
||||
mmc_release_host(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -2436,10 +2615,6 @@ int mmc_suspend_host(struct mmc_host *host)
|
||||
cancel_delayed_work(&host->detect);
|
||||
mmc_flush_scheduled_work();
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
if (host->bus_ops->suspend) {
|
||||
@@ -2581,6 +2756,23 @@ int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* mmc_init_context_info() - init synchronization context
|
||||
* @host: mmc host
|
||||
*
|
||||
* Init struct context_info needed to implement asynchronous
|
||||
* request mechanism, used by mmc core, host driver and mmc requests
|
||||
* supplier.
|
||||
*/
|
||||
void mmc_init_context_info(struct mmc_host *host)
|
||||
{
|
||||
spin_lock_init(&host->context_info.lock);
|
||||
host->context_info.is_new_req = false;
|
||||
host->context_info.is_done_rcv = false;
|
||||
host->context_info.is_waiting_last_req = false;
|
||||
init_waitqueue_head(&host->context_info.wait);
|
||||
}
|
||||
|
||||
static int __init mmc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@@ -40,11 +40,12 @@ void mmc_set_ungated(struct mmc_host *host);
|
||||
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
|
||||
bool cmd11);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
void mmc_power_off(struct mmc_host *host);
|
||||
void mmc_power_cycle(struct mmc_host *host);
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
@@ -76,5 +77,6 @@ void mmc_remove_host_debugfs(struct mmc_host *host);
|
||||
void mmc_add_card_debugfs(struct mmc_card *card);
|
||||
void mmc_remove_card_debugfs(struct mmc_card *card);
|
||||
|
||||
void mmc_init_context_info(struct mmc_host *host);
|
||||
#endif
|
||||
|
||||
|
@@ -15,6 +15,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/leds.h>
|
||||
@@ -23,6 +25,7 @@
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "host.h"
|
||||
@@ -294,6 +297,126 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* mmc_of_parse() - parse host's device-tree node
|
||||
* @host: host whose node should be parsed.
|
||||
*
|
||||
* To keep the rest of the MMC subsystem unaware of whether DT has been
|
||||
* used to to instantiate and configure this host instance or not, we
|
||||
* parse the properties and set respective generic mmc-host flags and
|
||||
* parameters.
|
||||
*/
|
||||
void mmc_of_parse(struct mmc_host *host)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 bus_width;
|
||||
bool explicit_inv_wp, gpio_inv_wp = false;
|
||||
enum of_gpio_flags flags;
|
||||
int len, ret, gpio;
|
||||
|
||||
if (!host->parent || !host->parent->of_node)
|
||||
return;
|
||||
|
||||
np = host->parent->of_node;
|
||||
|
||||
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
|
||||
if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
|
||||
dev_dbg(host->parent,
|
||||
"\"bus-width\" property is missing, assuming 1 bit.\n");
|
||||
bus_width = 1;
|
||||
}
|
||||
|
||||
switch (bus_width) {
|
||||
case 8:
|
||||
host->caps |= MMC_CAP_8_BIT_DATA;
|
||||
/* Hosts capable of 8-bit transfers can also do 4 bits */
|
||||
case 4:
|
||||
host->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
dev_err(host->parent,
|
||||
"Invalid \"bus-width\" value %ud!\n", bus_width);
|
||||
}
|
||||
|
||||
/* f_max is obtained from the optional "max-frequency" property */
|
||||
of_property_read_u32(np, "max-frequency", &host->f_max);
|
||||
|
||||
/*
|
||||
* Configure CD and WP pins. They are both by default active low to
|
||||
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
|
||||
* mmc-gpio helpers are used to attach, configure and use them. If
|
||||
* polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH
|
||||
* and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the
|
||||
* "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability
|
||||
* is set. If the "non-removable" property is found, the
|
||||
* MMC_CAP_NONREMOVABLE capability is set and no card-detection
|
||||
* configuration is performed.
|
||||
*/
|
||||
|
||||
/* Parse Card Detection */
|
||||
if (of_find_property(np, "non-removable", &len)) {
|
||||
host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
} else {
|
||||
bool explicit_inv_cd, gpio_inv_cd = false;
|
||||
|
||||
explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
|
||||
|
||||
if (of_find_property(np, "broken-cd", &len))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
gpio_inv_cd = true;
|
||||
|
||||
ret = mmc_gpio_request_cd(host, gpio);
|
||||
if (ret < 0)
|
||||
dev_err(host->parent,
|
||||
"Failed to request CD GPIO #%d: %d!\n",
|
||||
gpio, ret);
|
||||
else
|
||||
dev_info(host->parent, "Got CD GPIO #%d.\n",
|
||||
gpio);
|
||||
}
|
||||
|
||||
if (explicit_inv_cd ^ gpio_inv_cd)
|
||||
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
|
||||
}
|
||||
|
||||
/* Parse Write Protection */
|
||||
explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
|
||||
|
||||
gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
gpio_inv_wp = true;
|
||||
|
||||
ret = mmc_gpio_request_ro(host, gpio);
|
||||
if (ret < 0)
|
||||
dev_err(host->parent,
|
||||
"Failed to request WP GPIO: %d!\n", ret);
|
||||
}
|
||||
if (explicit_inv_wp ^ gpio_inv_wp)
|
||||
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
if (of_find_property(np, "cap-sd-highspeed", &len))
|
||||
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-mmc-highspeed", &len))
|
||||
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-power-off-card", &len))
|
||||
host->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
if (of_find_property(np, "cap-sdio-irq", &len))
|
||||
host->caps |= MMC_CAP_SDIO_IRQ;
|
||||
if (of_find_property(np, "keep-power-in-suspend", &len))
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (of_find_property(np, "enable-sdio-wakeup", &len))
|
||||
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mmc_of_parse);
|
||||
|
||||
/**
|
||||
* mmc_alloc_host - initialise the per-host structure.
|
||||
* @extra: sizeof private data structure
|
||||
|
@@ -496,7 +496,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
* RPMB regions are defined in multiples of 128K.
|
||||
*/
|
||||
card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
|
||||
if (ext_csd[EXT_CSD_RPMB_MULT]) {
|
||||
if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) {
|
||||
mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
|
||||
EXT_CSD_PART_CONFIG_ACC_RPMB,
|
||||
"rpmb", 0, false,
|
||||
@@ -538,6 +538,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
} else {
|
||||
card->ext_csd.data_tag_unit_size = 0;
|
||||
}
|
||||
|
||||
card->ext_csd.max_packed_writes =
|
||||
ext_csd[EXT_CSD_MAX_PACKED_WRITES];
|
||||
card->ext_csd.max_packed_reads =
|
||||
ext_csd[EXT_CSD_MAX_PACKED_READS];
|
||||
} else {
|
||||
card->ext_csd.data_sector_size = 512;
|
||||
}
|
||||
@@ -769,11 +774,11 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
|
||||
if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
|
||||
host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
|
||||
host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0);
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* If fails try again during next card power cycle */
|
||||
if (err)
|
||||
@@ -1221,8 +1226,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
* WARNING: eMMC rules are NOT the same as SD DDR
|
||||
*/
|
||||
if (ddr == MMC_1_2V_DDR_MODE) {
|
||||
err = mmc_set_signal_voltage(host,
|
||||
MMC_SIGNAL_VOLTAGE_120, 0);
|
||||
err = __mmc_set_signal_voltage(host,
|
||||
MMC_SIGNAL_VOLTAGE_120);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
@@ -1275,6 +1280,29 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The mandatory minimum values are defined for packed command.
|
||||
* read: 5, write: 3
|
||||
*/
|
||||
if (card->ext_csd.max_packed_writes >= 3 &&
|
||||
card->ext_csd.max_packed_reads >= 5 &&
|
||||
host->caps2 & MMC_CAP2_PACKED_CMD) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_EXP_EVENTS_CTRL,
|
||||
EXT_CSD_PACKED_EVENT_EN,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
if (err) {
|
||||
pr_warn("%s: Enabling packed event failed\n",
|
||||
mmc_hostname(card->host));
|
||||
card->ext_csd.packed_event_en = 0;
|
||||
err = 0;
|
||||
} else {
|
||||
card->ext_csd.packed_event_en = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
@@ -1379,6 +1407,11 @@ static int mmc_suspend(struct mmc_host *host)
|
||||
BUG_ON(!host->card);
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (mmc_can_poweroff_notify(host->card))
|
||||
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
|
||||
else if (mmc_card_can_sleep(host))
|
||||
@@ -1386,8 +1419,9 @@ static int mmc_suspend(struct mmc_host *host)
|
||||
else if (!mmc_host_is_spi(host))
|
||||
err = mmc_deselect_cards(host);
|
||||
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
|
||||
mmc_release_host(host);
|
||||
|
||||
out:
|
||||
mmc_release_host(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@@ -363,6 +363,7 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
|
||||
ext_csd, 512);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
|
||||
|
||||
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
|
||||
{
|
||||
|
@@ -444,8 +444,7 @@ static void sd_update_bus_speed_mode(struct mmc_card *card)
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
* default speed.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
|
||||
if (!mmc_host_uhs(card->host)) {
|
||||
card->sd_bus_speed = 0;
|
||||
return;
|
||||
}
|
||||
@@ -713,6 +712,14 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
{
|
||||
int err;
|
||||
u32 max_current;
|
||||
int retries = 10;
|
||||
|
||||
try_again:
|
||||
if (!retries) {
|
||||
ocr &= ~SD_OCR_S18R;
|
||||
pr_warning("%s: Skipping voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we're changing the OCR value, we seem to
|
||||
@@ -734,10 +741,10 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
|
||||
/*
|
||||
* If the host supports one of UHS-I modes, request the card
|
||||
* to switch to 1.8V signaling level.
|
||||
* to switch to 1.8V signaling level. If the card has failed
|
||||
* repeatedly to switch however, skip this.
|
||||
*/
|
||||
if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
|
||||
if (retries && mmc_host_uhs(host))
|
||||
ocr |= SD_OCR_S18R;
|
||||
|
||||
/*
|
||||
@@ -748,7 +755,6 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
if (max_current > 150)
|
||||
ocr |= SD_OCR_XPC;
|
||||
|
||||
try_again:
|
||||
err = mmc_send_app_op_cond(host, ocr, rocr);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -759,9 +765,12 @@ try_again:
|
||||
*/
|
||||
if (!mmc_host_is_spi(host) && rocr &&
|
||||
((*rocr & 0x41000000) == 0x41000000)) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
|
||||
if (err) {
|
||||
ocr &= ~SD_OCR_S18R;
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
if (err == -EAGAIN) {
|
||||
retries--;
|
||||
goto try_again;
|
||||
} else if (err) {
|
||||
retries = 0;
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
@@ -960,16 +969,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
|
||||
/* Card is an ultra-high-speed card */
|
||||
mmc_card_set_uhs(card);
|
||||
|
||||
/*
|
||||
* Since initialization is now complete, enable preset
|
||||
* value registers for UHS-I cards.
|
||||
*/
|
||||
if (host->ops->enable_preset_value) {
|
||||
mmc_host_clk_hold(card->host);
|
||||
host->ops->enable_preset_value(host, true);
|
||||
mmc_host_clk_release(card->host);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Attempt to change to high-speed (if supported)
|
||||
@@ -1148,13 +1147,6 @@ int mmc_attach_sd(struct mmc_host *host)
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
/* Disable preset value enable if already set since last time */
|
||||
if (host->ops->enable_preset_value) {
|
||||
mmc_host_clk_hold(host);
|
||||
host->ops->enable_preset_value(host, false);
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
err = mmc_send_app_op_cond(host, 0, &ocr);
|
||||
if (err)
|
||||
return err;
|
||||
|
@@ -157,10 +157,7 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (card->host->caps &
|
||||
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_DDR50)) {
|
||||
if (mmc_host_uhs(card->host)) {
|
||||
if (data & SDIO_UHS_DDR50)
|
||||
card->sw_caps.sd3_bus_mode
|
||||
|= SD_MODE_UHS_DDR50;
|
||||
@@ -478,8 +475,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
* default speed.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
|
||||
if (!mmc_host_uhs(card->host))
|
||||
return 0;
|
||||
|
||||
bus_speed = SDIO_SPEED_SDR12;
|
||||
@@ -489,23 +485,27 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
bus_speed = SDIO_SPEED_SDR104;
|
||||
timing = MMC_TIMING_UHS_SDR104;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
|
||||
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
|
||||
bus_speed = SDIO_SPEED_DDR50;
|
||||
timing = MMC_TIMING_UHS_DDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
|
||||
SD_MODE_UHS_SDR50)) {
|
||||
bus_speed = SDIO_SPEED_SDR50;
|
||||
timing = MMC_TIMING_UHS_SDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
|
||||
bus_speed = SDIO_SPEED_SDR25;
|
||||
timing = MMC_TIMING_UHS_SDR25;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
|
||||
@@ -513,6 +513,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
bus_speed = SDIO_SPEED_SDR12;
|
||||
timing = MMC_TIMING_UHS_SDR12;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
|
||||
}
|
||||
|
||||
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
|
||||
@@ -583,10 +584,19 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
||||
{
|
||||
struct mmc_card *card;
|
||||
int err;
|
||||
int retries = 10;
|
||||
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
try_again:
|
||||
if (!retries) {
|
||||
pr_warning("%s: Skipping voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
ocr &= ~R4_18V_PRESENT;
|
||||
host->ocr &= ~R4_18V_PRESENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform the card of the voltage
|
||||
*/
|
||||
@@ -645,14 +655,16 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
||||
* systems that claim 1.8v signalling in fact do not support
|
||||
* it.
|
||||
*/
|
||||
if ((ocr & R4_18V_PRESENT) &&
|
||||
(host->caps &
|
||||
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_DDR50))) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
|
||||
true);
|
||||
if (err) {
|
||||
if (!powered_resume && (ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
if (err == -EAGAIN) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->ocr_avail);
|
||||
mmc_remove_card(card);
|
||||
retries--;
|
||||
goto try_again;
|
||||
} else if (err) {
|
||||
ocr &= ~R4_18V_PRESENT;
|
||||
host->ocr &= ~R4_18V_PRESENT;
|
||||
}
|
||||
@@ -937,10 +949,12 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
||||
mmc_claim_host(host);
|
||||
|
||||
/* No need to reinitialize powered-resumed nonremovable cards */
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
err = mmc_sdio_init_card(host, host->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
||||
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
||||
/* We may have switched to 1-bit mode during suspend */
|
||||
err = sdio_enable_4bit_bus(host->card);
|
||||
if (err > 0) {
|
||||
@@ -1020,6 +1034,10 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mmc_host_uhs(host))
|
||||
/* to query card if 1.8V signalling is supported */
|
||||
host->ocr |= R4_18V_PRESENT;
|
||||
|
||||
ret = mmc_sdio_init_card(host, host->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
if (!ret && host->sdio_irqs)
|
||||
@@ -1085,6 +1103,10 @@ int mmc_attach_sdio(struct mmc_host *host)
|
||||
/*
|
||||
* Detect and init the card.
|
||||
*/
|
||||
if (mmc_host_uhs(host))
|
||||
/* to query card if 1.8V signalling is supported */
|
||||
host->ocr |= R4_18V_PRESENT;
|
||||
|
||||
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
|
||||
if (err) {
|
||||
if (err == -EAGAIN) {
|
||||
|
@@ -92,6 +92,20 @@ int mmc_gpio_get_cd(struct mmc_host *host)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_get_cd);
|
||||
|
||||
/**
|
||||
* mmc_gpio_request_ro - request a gpio for write-protection
|
||||
* @host: mmc host
|
||||
* @gpio: gpio number requested
|
||||
*
|
||||
* As devm_* managed functions are used in mmc_gpio_request_ro(), client
|
||||
* drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up,
|
||||
* if the requesting and freeing are only needed at probing and unbinding time
|
||||
* for once. However, if client drivers do something special like runtime
|
||||
* switching for write-protection, they are responsible for calling
|
||||
* mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
@@ -106,7 +120,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
|
||||
ctx = host->slot.handler_priv;
|
||||
|
||||
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
|
||||
ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
|
||||
ctx->ro_label);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -116,6 +131,20 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_request_ro);
|
||||
|
||||
/**
|
||||
* mmc_gpio_request_cd - request a gpio for card-detection
|
||||
* @host: mmc host
|
||||
* @gpio: gpio number requested
|
||||
*
|
||||
* As devm_* managed functions are used in mmc_gpio_request_cd(), client
|
||||
* drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up,
|
||||
* if the requesting and freeing are only needed at probing and unbinding time
|
||||
* for once. However, if client drivers do something special like runtime
|
||||
* switching for card-detection, they are responsible for calling
|
||||
* mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
@@ -128,7 +157,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
|
||||
ctx = host->slot.handler_priv;
|
||||
|
||||
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
|
||||
ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
|
||||
ctx->cd_label);
|
||||
if (ret < 0)
|
||||
/*
|
||||
* don't bother freeing memory. It might still get used by other
|
||||
@@ -146,7 +176,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
irq = -EINVAL;
|
||||
|
||||
if (irq >= 0) {
|
||||
ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
|
||||
ret = devm_request_threaded_irq(&host->class_dev, irq,
|
||||
NULL, mmc_gpio_cd_irqt,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
ctx->cd_label, host);
|
||||
if (ret < 0)
|
||||
@@ -164,6 +195,13 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_request_cd);
|
||||
|
||||
/**
|
||||
* mmc_gpio_free_ro - free the write-protection gpio
|
||||
* @host: mmc host
|
||||
*
|
||||
* It's provided only for cases that client drivers need to manually free
|
||||
* up the write-protection gpio requested by mmc_gpio_request_ro().
|
||||
*/
|
||||
void mmc_gpio_free_ro(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
@@ -175,10 +213,17 @@ void mmc_gpio_free_ro(struct mmc_host *host)
|
||||
gpio = ctx->ro_gpio;
|
||||
ctx->ro_gpio = -EINVAL;
|
||||
|
||||
gpio_free(gpio);
|
||||
devm_gpio_free(&host->class_dev, gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_free_ro);
|
||||
|
||||
/**
|
||||
* mmc_gpio_free_cd - free the card-detection gpio
|
||||
* @host: mmc host
|
||||
*
|
||||
* It's provided only for cases that client drivers need to manually free
|
||||
* up the card-detection gpio requested by mmc_gpio_request_cd().
|
||||
*/
|
||||
void mmc_gpio_free_cd(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
@@ -188,13 +233,13 @@ void mmc_gpio_free_cd(struct mmc_host *host)
|
||||
return;
|
||||
|
||||
if (host->slot.cd_irq >= 0) {
|
||||
free_irq(host->slot.cd_irq, host);
|
||||
devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
|
||||
host->slot.cd_irq = -EINVAL;
|
||||
}
|
||||
|
||||
gpio = ctx->cd_gpio;
|
||||
ctx->cd_gpio = -EINVAL;
|
||||
|
||||
gpio_free(gpio);
|
||||
devm_gpio_free(&host->class_dev, gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_free_cd);
|
||||
|
Reference in New Issue
Block a user