2005-04-16 15:20:36 -07:00
|
|
|
/*
|
|
|
|
* linux/include/linux/mmc/host.h
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* Host driver specific definitions.
|
|
|
|
*/
|
|
|
|
#ifndef LINUX_MMC_HOST_H
|
|
|
|
#define LINUX_MMC_HOST_H
|
|
|
|
|
2007-09-24 07:15:48 +02:00
|
|
|
#include <linux/leds.h>
|
2012-05-01 16:51:38 +02:00
|
|
|
#include <linux/mutex.h>
|
2015-05-07 13:10:12 +03:00
|
|
|
#include <linux/timer.h>
|
2009-10-07 17:09:06 +04:00
|
|
|
#include <linux/sched.h>
|
2012-01-30 11:46:54 -05:00
|
|
|
#include <linux/device.h>
|
2015-05-18 12:12:48 +03:00
|
|
|
#include <linux/devfreq.h>
|
2011-08-19 14:52:37 +02:00
|
|
|
#include <linux/fault-inject.h>
|
2016-08-25 18:31:01 -07:00
|
|
|
#include <linux/blkdev.h>
|
2007-09-24 07:15:48 +02:00
|
|
|
|
2007-02-28 15:33:10 +01:00
|
|
|
#include <linux/mmc/core.h>
|
2014-04-23 17:07:35 +09:00
|
|
|
#include <linux/mmc/card.h>
|
2010-03-05 13:43:31 -08:00
|
|
|
#include <linux/mmc/pm.h>
|
2016-11-24 18:08:26 +05:30
|
|
|
#include <linux/mmc/ring_buffer.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2015-06-24 19:51:58 +03:00
|
|
|
#define MMC_AUTOSUSPEND_DELAY_MS 3000
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
struct mmc_ios {
|
|
|
|
unsigned int clock; /* clock rate */
|
2013-02-14 08:13:52 +05:30
|
|
|
unsigned int old_rate; /* saved clock rate */
|
|
|
|
unsigned long clk_ts; /* time stamp of last updated clock */
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned short vdd;
|
|
|
|
|
2007-03-11 17:15:15 -07:00
|
|
|
/* vdd stores the bit number of the selected voltage range from below. */
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
unsigned char bus_mode; /* command output mode */
|
|
|
|
|
|
|
|
#define MMC_BUSMODE_OPENDRAIN 1
|
|
|
|
#define MMC_BUSMODE_PUSHPULL 2
|
|
|
|
|
2005-09-03 16:45:02 +01:00
|
|
|
unsigned char chip_select; /* SPI chip select */
|
|
|
|
|
|
|
|
#define MMC_CS_DONTCARE 0
|
|
|
|
#define MMC_CS_HIGH 1
|
|
|
|
#define MMC_CS_LOW 2
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned char power_mode; /* power supply mode */
|
|
|
|
|
|
|
|
#define MMC_POWER_OFF 0
|
|
|
|
#define MMC_POWER_UP 1
|
|
|
|
#define MMC_POWER_ON 2
|
2014-09-24 17:07:13 +08:00
|
|
|
#define MMC_POWER_UNDEFINED 3
|
2005-09-06 15:18:55 -07:00
|
|
|
|
|
|
|
unsigned char bus_width; /* data bus width */
|
|
|
|
|
|
|
|
#define MMC_BUS_WIDTH_1 0
|
|
|
|
#define MMC_BUS_WIDTH_4 2
|
2008-11-17 14:35:21 +02:00
|
|
|
#define MMC_BUS_WIDTH_8 3
|
2007-02-18 12:07:47 +01:00
|
|
|
|
|
|
|
unsigned char timing; /* timing specification used */
|
|
|
|
|
|
|
|
#define MMC_TIMING_LEGACY 0
|
|
|
|
#define MMC_TIMING_MMC_HS 1
|
|
|
|
#define MMC_TIMING_SD_HS 2
|
2012-10-17 19:04:46 +08:00
|
|
|
#define MMC_TIMING_UHS_SDR12 3
|
|
|
|
#define MMC_TIMING_UHS_SDR25 4
|
|
|
|
#define MMC_TIMING_UHS_SDR50 5
|
|
|
|
#define MMC_TIMING_UHS_SDR104 6
|
|
|
|
#define MMC_TIMING_UHS_DDR50 7
|
2014-03-14 21:11:56 +09:00
|
|
|
#define MMC_TIMING_MMC_DDR52 8
|
|
|
|
#define MMC_TIMING_MMC_HS200 9
|
2014-04-23 17:14:58 +09:00
|
|
|
#define MMC_TIMING_MMC_HS400 10
|
2010-08-24 13:20:26 +03:00
|
|
|
|
mmc: sd: add support for signal voltage switch procedure
Host Controller v3.00 adds another Capabilities register. Apart
from other things, this new register indicates whether the Host
Controller supports SDR50, SDR104, and DDR50 UHS-I modes. The spec
doesn't mention about explicit support for SDR12 and SDR25 UHS-I
modes, so the Host Controller v3.00 should support them by default.
Also if the controller supports SDR104 mode, it will also support
SDR50 mode as well. So depending on the host support, we set the
corresponding MMC_CAP_* flags. One more new register. Host Control2
is added in v3.00, which is used during Signal Voltage Switch
procedure described below.
Since as per v3.00 spec, UHS-I supported hosts should set S18R
to 1, we set S18R (bit 24) of OCR before sending ACMD41. We also
need to set XPC (bit 28) of OCR in case the host can supply >150mA.
This support is indicated by the Maximum Current Capabilities
register of the Host Controller.
If the response of ACMD41 has both CCS and S18A set, we start the
signal voltage switch procedure, which if successfull, will switch
the card from 3.3V signalling to 1.8V signalling. Signal voltage
switch procedure adds support for a new command CMD11 in the
Physical Layer Spec v3.01. As part of this procedure, we need to
set 1.8V Signalling Enable (bit 3) of Host Control2 register, which
if remains set after 5ms, means the switch to 1.8V signalling is
successfull. Otherwise, we clear bit 24 of OCR and retry the
initialization sequence. When we remove the card, and insert the
same or another card, we need to make sure that we start with 3.3V
signalling voltage. So we call mmc_set_signal_voltage() with
MMC_SIGNAL_VOLTAGE_330 set so that we are back to 3.3V signalling
voltage before we actually start initializing the card.
Tested by Zhangfei Gao with a Toshiba uhs card and general hs card,
on mmp2 in SDMA mode.
Signed-off-by: Arindam Nath <arindam.nath@amd.com>
Reviewed-by: Philip Rakity <prakity@marvell.com>
Tested-by: Philip Rakity <prakity@marvell.com>
Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
2011-05-05 12:18:57 +05:30
|
|
|
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
|
|
|
|
|
|
|
|
#define MMC_SIGNAL_VOLTAGE_330 0
|
|
|
|
#define MMC_SIGNAL_VOLTAGE_180 1
|
2011-05-13 11:17:18 +05:30
|
|
|
#define MMC_SIGNAL_VOLTAGE_120 2
|
2011-05-05 12:18:59 +05:30
|
|
|
|
|
|
|
unsigned char drv_type; /* driver type (A, B, C, D) */
|
|
|
|
|
|
|
|
#define MMC_SET_DRIVER_TYPE_B 0
|
|
|
|
#define MMC_SET_DRIVER_TYPE_A 1
|
|
|
|
#define MMC_SET_DRIVER_TYPE_C 2
|
|
|
|
#define MMC_SET_DRIVER_TYPE_D 3
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
2013-06-19 20:15:37 +05:30
|
|
|
/* states to represent load on the host */
|
|
|
|
enum mmc_load {
|
|
|
|
MMC_LOAD_HIGH,
|
|
|
|
MMC_LOAD_LOW,
|
|
|
|
};
|
|
|
|
|
2015-05-21 13:43:24 +05:30
|
|
|
struct mmc_cmdq_host_ops {
|
2015-09-29 16:05:39 +03:00
|
|
|
int (*init)(struct mmc_host *host);
|
2015-05-21 13:43:24 +05:30
|
|
|
int (*enable)(struct mmc_host *host);
|
|
|
|
void (*disable)(struct mmc_host *host, bool soft);
|
2015-05-29 16:51:43 -07:00
|
|
|
int (*request)(struct mmc_host *host, struct mmc_request *mrq);
|
2015-09-27 21:51:01 +05:30
|
|
|
void (*post_req)(struct mmc_host *host, int tag, int err);
|
2015-05-21 17:21:07 +05:30
|
|
|
int (*halt)(struct mmc_host *host, bool halt);
|
2015-05-20 16:52:04 +05:30
|
|
|
void (*reset)(struct mmc_host *host, bool soft);
|
2015-03-02 23:14:05 +05:30
|
|
|
void (*dumpstate)(struct mmc_host *host);
|
2015-05-21 13:43:24 +05:30
|
|
|
};
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
struct mmc_host_ops {
|
2015-09-29 16:57:21 +03:00
|
|
|
int (*init)(struct mmc_host *host);
|
2016-04-27 17:19:29 -07:00
|
|
|
/*
|
|
|
|
* 'enable' is called when the host is claimed and 'disable' is called
|
|
|
|
* when the host is released. 'enable' and 'disable' are deprecated.
|
|
|
|
*/
|
|
|
|
int (*enable)(struct mmc_host *host);
|
|
|
|
int (*disable)(struct mmc_host *host);
|
2011-07-01 18:55:22 +02:00
|
|
|
/*
|
|
|
|
* It is optional for the host to implement pre_req and post_req in
|
|
|
|
* order to support double buffering of requests (prepare one
|
|
|
|
* request while another request is active).
|
2011-08-29 15:35:58 +02:00
|
|
|
* pre_req() must always be followed by a post_req().
|
|
|
|
* To undo a call made to pre_req(), call post_req() with
|
|
|
|
* a nonzero err condition.
|
2011-07-01 18:55:22 +02:00
|
|
|
*/
|
|
|
|
void (*post_req)(struct mmc_host *host, struct mmc_request *req,
|
|
|
|
int err);
|
|
|
|
void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
|
|
|
|
bool is_first_req);
|
2005-04-16 15:20:36 -07:00
|
|
|
void (*request)(struct mmc_host *host, struct mmc_request *req);
|
2008-06-17 18:17:15 +04:00
|
|
|
/*
|
|
|
|
* Avoid calling these three functions too often or in a "fast path",
|
|
|
|
* since underlaying controller might implement them in an expensive
|
|
|
|
* and/or slow way.
|
|
|
|
*
|
|
|
|
* Also note that these functions might sleep, so don't call them
|
|
|
|
* in the atomic contexts!
|
2008-06-17 18:17:39 +04:00
|
|
|
*
|
|
|
|
* Return values for the get_ro callback should be:
|
|
|
|
* 0 for a read/write card
|
|
|
|
* 1 for a read-only card
|
|
|
|
* -ENOSYS when not supported (equal to NULL callback)
|
|
|
|
* or a negative errno value when something bad happened
|
|
|
|
*
|
2008-09-02 10:14:13 +02:00
|
|
|
* Return values for the get_cd callback should be:
|
2008-06-17 18:17:39 +04:00
|
|
|
* 0 for a absent card
|
|
|
|
* 1 for a present card
|
|
|
|
* -ENOSYS when not supported (equal to NULL callback)
|
|
|
|
* or a negative errno value when something bad happened
|
2008-06-17 18:17:15 +04:00
|
|
|
*/
|
2005-04-16 15:20:36 -07:00
|
|
|
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
|
2005-09-06 15:18:52 -07:00
|
|
|
int (*get_ro)(struct mmc_host *host);
|
2008-06-17 18:17:15 +04:00
|
|
|
int (*get_cd)(struct mmc_host *host);
|
|
|
|
|
2007-07-24 02:09:39 -04:00
|
|
|
void (*enable_sdio_irq)(struct mmc_host *host, int enable);
|
2010-04-01 10:03:25 +02:00
|
|
|
|
|
|
|
/* optional callback for HC quirks */
|
|
|
|
void (*init_card)(struct mmc_host *host, struct mmc_card *card);
|
mmc: sd: add support for signal voltage switch procedure
Host Controller v3.00 adds another Capabilities register. Apart
from other things, this new register indicates whether the Host
Controller supports SDR50, SDR104, and DDR50 UHS-I modes. The spec
doesn't mention about explicit support for SDR12 and SDR25 UHS-I
modes, so the Host Controller v3.00 should support them by default.
Also if the controller supports SDR104 mode, it will also support
SDR50 mode as well. So depending on the host support, we set the
corresponding MMC_CAP_* flags. One more new register. Host Control2
is added in v3.00, which is used during Signal Voltage Switch
procedure described below.
Since as per v3.00 spec, UHS-I supported hosts should set S18R
to 1, we set S18R (bit 24) of OCR before sending ACMD41. We also
need to set XPC (bit 28) of OCR in case the host can supply >150mA.
This support is indicated by the Maximum Current Capabilities
register of the Host Controller.
If the response of ACMD41 has both CCS and S18A set, we start the
signal voltage switch procedure, which if successfull, will switch
the card from 3.3V signalling to 1.8V signalling. Signal voltage
switch procedure adds support for a new command CMD11 in the
Physical Layer Spec v3.01. As part of this procedure, we need to
set 1.8V Signalling Enable (bit 3) of Host Control2 register, which
if remains set after 5ms, means the switch to 1.8V signalling is
successfull. Otherwise, we clear bit 24 of OCR and retry the
initialization sequence. When we remove the card, and insert the
same or another card, we need to make sure that we start with 3.3V
signalling voltage. So we call mmc_set_signal_voltage() with
MMC_SIGNAL_VOLTAGE_330 set so that we are back to 3.3V signalling
voltage before we actually start initializing the card.
Tested by Zhangfei Gao with a Toshiba uhs card and general hs card,
on mmp2 in SDMA mode.
Signed-off-by: Arindam Nath <arindam.nath@amd.com>
Reviewed-by: Philip Rakity <prakity@marvell.com>
Tested-by: Philip Rakity <prakity@marvell.com>
Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
2011-05-05 12:18:57 +05:30
|
|
|
|
|
|
|
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
|
2012-01-11 14:04:52 -05:00
|
|
|
|
2013-01-28 15:08:26 +01:00
|
|
|
/* Check if the card is pulling dat[0:3] low */
|
|
|
|
int (*card_busy)(struct mmc_host *host);
|
|
|
|
|
2012-01-11 14:04:52 -05:00
|
|
|
/* The tuning command opcode value is different for SD and eMMC cards */
|
|
|
|
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
|
2014-04-23 17:14:58 +09:00
|
|
|
|
|
|
|
/* Prepare HS400 target operating frequency depending host driver */
|
|
|
|
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
|
2015-06-10 17:20:00 -07:00
|
|
|
int (*enhanced_strobe)(struct mmc_host *host);
|
2015-02-06 14:12:54 +02:00
|
|
|
int (*select_drive_strength)(struct mmc_card *card,
|
|
|
|
unsigned int max_dtr, int host_drv,
|
2015-02-06 14:12:52 +02:00
|
|
|
int card_drv, int *drv_type);
|
2011-08-29 16:42:11 +03:00
|
|
|
void (*hw_reset)(struct mmc_host *host);
|
2012-12-04 16:51:32 +01:00
|
|
|
void (*card_event)(struct mmc_host *host);
|
2014-09-02 19:08:53 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Optional callback to support controllers with HW issues for multiple
|
|
|
|
* I/O. Returns the number of supported blocks for the request.
|
|
|
|
*/
|
|
|
|
int (*multi_io_quirk)(struct mmc_card *card,
|
|
|
|
unsigned int direction, int blk_size);
|
2014-12-04 09:57:23 +02:00
|
|
|
|
|
|
|
unsigned long (*get_max_frequency)(struct mmc_host *host);
|
|
|
|
unsigned long (*get_min_frequency)(struct mmc_host *host);
|
|
|
|
|
2013-06-19 20:15:37 +05:30
|
|
|
int (*notify_load)(struct mmc_host *, enum mmc_load);
|
2015-06-25 09:33:24 +03:00
|
|
|
void (*notify_halt)(struct mmc_host *mmc, bool halt);
|
2015-09-15 15:57:35 -07:00
|
|
|
void (*force_err_irq)(struct mmc_host *host, u64 errmask);
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
struct mmc_card;
|
|
|
|
struct device;
|
|
|
|
|
2015-05-29 16:51:43 -07:00
|
|
|
struct mmc_cmdq_req {
|
|
|
|
unsigned int cmd_flags;
|
|
|
|
u32 blk_addr;
|
|
|
|
/* active mmc request */
|
|
|
|
struct mmc_request mrq;
|
|
|
|
struct mmc_data data;
|
|
|
|
struct mmc_command cmd;
|
|
|
|
#define DCMD (1 << 0)
|
|
|
|
#define QBR (1 << 1)
|
|
|
|
#define DIR (1 << 2)
|
|
|
|
#define PRIO (1 << 3)
|
|
|
|
#define REL_WR (1 << 4)
|
|
|
|
#define DAT_TAG (1 << 5)
|
|
|
|
#define FORCED_PRG (1 << 6)
|
|
|
|
unsigned int cmdq_req_flags;
|
2015-05-20 16:52:04 +05:30
|
|
|
|
|
|
|
unsigned int resp_idx;
|
|
|
|
unsigned int resp_arg;
|
|
|
|
unsigned int dev_pend_tasks;
|
|
|
|
bool resp_err;
|
2016-12-11 20:38:20 +05:30
|
|
|
bool skip_err_handling;
|
2015-05-29 16:51:43 -07:00
|
|
|
int tag; /* used for command queuing */
|
|
|
|
u8 ctx_id;
|
|
|
|
};
|
|
|
|
|
2011-07-01 18:55:22 +02:00
|
|
|
struct mmc_async_req {
|
|
|
|
/* active mmc request */
|
|
|
|
struct mmc_request *mrq;
|
|
|
|
/*
|
|
|
|
* Check error status of completed mmc request.
|
|
|
|
* Returns 0 if success otherwise non zero.
|
|
|
|
*/
|
|
|
|
int (*err_check) (struct mmc_card *, struct mmc_async_req *);
|
|
|
|
};
|
|
|
|
|
2012-05-01 15:40:15 +02:00
|
|
|
/**
|
|
|
|
* struct mmc_slot - MMC slot functions
|
|
|
|
*
|
|
|
|
* @cd_irq: MMC/SD-card slot hotplug detection IRQ or -EINVAL
|
|
|
|
* @handler_priv: MMC/SD-card slot context
|
|
|
|
*
|
|
|
|
* Some MMC/SD host controllers implement slot-functions like card and
|
|
|
|
* write-protect detection natively. However, a large number of controllers
|
|
|
|
* leave these functions to the CPU. This struct provides a hook to attach
|
|
|
|
* such slot-function drivers.
|
|
|
|
*/
|
|
|
|
struct mmc_slot {
|
|
|
|
int cd_irq;
|
2011-12-25 20:40:03 -05:00
|
|
|
void *handler_priv;
|
|
|
|
};
|
|
|
|
|
2015-05-21 13:29:51 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* mmc_cmdq_context_info - describes the contexts of cmdq
|
|
|
|
* @active_reqs requests being processed
|
2015-06-29 10:50:19 +03:00
|
|
|
* @data_active_reqs data requests being processed
|
2015-05-21 13:29:51 +05:30
|
|
|
* @curr_state state of cmdq engine
|
|
|
|
* @cmdq_ctx_lock acquire this before accessing this structure
|
2015-06-29 10:50:19 +03:00
|
|
|
* @queue_empty_wq workqueue for waiting for all
|
|
|
|
* the outstanding requests to be completed
|
2015-08-12 17:53:21 -07:00
|
|
|
* @wait waiting for all conditions described in
|
|
|
|
* mmc_cmdq_ready_wait to be satisified before
|
|
|
|
* issuing the new request to LLD.
|
2015-05-21 13:29:51 +05:30
|
|
|
*/
|
|
|
|
struct mmc_cmdq_context_info {
|
|
|
|
unsigned long active_reqs; /* in-flight requests */
|
2015-06-29 10:50:19 +03:00
|
|
|
unsigned long data_active_reqs; /* in-flight data requests */
|
2015-05-21 13:29:51 +05:30
|
|
|
unsigned long curr_state;
|
|
|
|
#define CMDQ_STATE_ERR 0
|
2015-04-23 16:00:45 +05:30
|
|
|
#define CMDQ_STATE_DCMD_ACTIVE 1
|
2015-05-21 17:21:07 +05:30
|
|
|
#define CMDQ_STATE_HALT 2
|
2015-10-27 11:51:25 +05:30
|
|
|
#define CMDQ_STATE_CQ_DISABLE 3
|
2015-10-07 16:42:47 +05:30
|
|
|
#define CMDQ_STATE_REQ_TIMED_OUT 4
|
2015-06-29 10:50:19 +03:00
|
|
|
wait_queue_head_t queue_empty_wq;
|
2015-08-12 17:53:21 -07:00
|
|
|
wait_queue_head_t wait;
|
2015-11-13 12:15:53 -08:00
|
|
|
int active_small_sector_read_reqs;
|
2015-05-21 13:29:51 +05:30
|
|
|
};
|
|
|
|
|
2013-01-14 14:28:17 -05:00
|
|
|
/**
|
|
|
|
* mmc_context_info - synchronization details for mmc context
|
|
|
|
* @is_done_rcv wake up reason was done request
|
|
|
|
* @is_new_req wake up reason was new request
|
|
|
|
* @is_waiting_last_req mmc context waiting for single running request
|
|
|
|
* @wait wait queue
|
|
|
|
* @lock lock to protect data fields
|
|
|
|
*/
|
|
|
|
struct mmc_context_info {
|
|
|
|
bool is_done_rcv;
|
|
|
|
bool is_new_req;
|
|
|
|
bool is_waiting_last_req;
|
|
|
|
wait_queue_head_t wait;
|
|
|
|
spinlock_t lock;
|
|
|
|
};
|
|
|
|
|
2012-06-20 02:28:43 -04:00
|
|
|
struct regulator;
|
2014-11-28 14:38:36 +01:00
|
|
|
struct mmc_pwrseq;
|
2012-06-20 02:28:43 -04:00
|
|
|
|
|
|
|
struct mmc_supply {
|
|
|
|
struct regulator *vmmc; /* Card power supply */
|
|
|
|
struct regulator *vqmmc; /* Optional Vccq supply */
|
|
|
|
};
|
|
|
|
|
2014-12-04 23:05:50 +02:00
|
|
|
enum dev_state {
|
|
|
|
DEV_SUSPENDING = 1,
|
|
|
|
DEV_SUSPENDED,
|
|
|
|
DEV_RESUMED,
|
|
|
|
};
|
|
|
|
|
2015-05-18 12:12:48 +03:00
|
|
|
/**
|
|
|
|
* struct mmc_devfeq_clk_scaling - main context for MMC clock scaling logic
|
|
|
|
*
|
|
|
|
* @lock: spinlock to protect statistics
|
|
|
|
* @devfreq: struct that represent mmc-host as a client for devfreq
|
|
|
|
* @devfreq_profile: MMC device profile, mostly polling interval and callbacks
|
|
|
|
* @ondemand_gov_data: struct supplied to ondemmand governor (thresholds)
|
|
|
|
* @state: load state, can be HIGH or LOW. used to notify mmc_host_ops callback
|
|
|
|
* @start_busy: timestamped armed once a data request is started
|
|
|
|
* @measure_interval_start: timestamped armed once a measure interval started
|
|
|
|
* @devfreq_abort: flag to sync between different contexts relevant to devfreq
|
|
|
|
* @skip_clk_scale_freq_update: flag that enable/disable frequency change
|
|
|
|
* @freq_table_sz: table size of frequencies supplied to devfreq
|
|
|
|
* @freq_table: frequencies table supplied to devfreq
|
|
|
|
* @curr_freq: current frequency
|
|
|
|
* @polling_delay_ms: polling interval for status collection used by devfreq
|
|
|
|
* @upthreshold: up-threshold supplied to ondemand governor
|
|
|
|
* @downthreshold: down-threshold supplied to ondemand governor
|
|
|
|
* @need_freq_change: flag indicating if a frequency change is required
|
|
|
|
* @clk_scaling_in_progress: flag indicating if there's ongoing frequency change
|
|
|
|
* @is_busy_started: flag indicating if a request is handled by the HW
|
|
|
|
* @enable: flag indicating if the clock scaling logic is enabled for this host
|
|
|
|
*/
|
|
|
|
struct mmc_devfeq_clk_scaling {
|
|
|
|
spinlock_t lock;
|
|
|
|
struct devfreq *devfreq;
|
|
|
|
struct devfreq_dev_profile devfreq_profile;
|
|
|
|
struct devfreq_simple_ondemand_data ondemand_gov_data;
|
|
|
|
enum mmc_load state;
|
|
|
|
ktime_t start_busy;
|
|
|
|
ktime_t measure_interval_start;
|
|
|
|
atomic_t devfreq_abort;
|
|
|
|
bool skip_clk_scale_freq_update;
|
|
|
|
int freq_table_sz;
|
2017-05-30 20:34:46 +05:30
|
|
|
int pltfm_freq_table_sz;
|
2015-05-18 12:12:48 +03:00
|
|
|
u32 *freq_table;
|
2017-05-30 20:34:46 +05:30
|
|
|
u32 *pltfm_freq_table;
|
2015-05-18 12:12:48 +03:00
|
|
|
unsigned long total_busy_time_us;
|
|
|
|
unsigned long target_freq;
|
|
|
|
unsigned long curr_freq;
|
|
|
|
unsigned long polling_delay_ms;
|
|
|
|
unsigned int upthreshold;
|
|
|
|
unsigned int downthreshold;
|
2015-12-09 10:48:18 +05:30
|
|
|
unsigned int lower_bus_speed_mode;
|
|
|
|
#define MMC_SCALING_LOWER_DDR52_MODE 1
|
2015-05-18 12:12:48 +03:00
|
|
|
bool need_freq_change;
|
|
|
|
bool clk_scaling_in_progress;
|
|
|
|
bool is_busy_started;
|
|
|
|
bool enable;
|
|
|
|
};
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
struct mmc_host {
|
2006-09-12 17:00:10 +02:00
|
|
|
struct device *parent;
|
|
|
|
struct device class_dev;
|
2015-05-18 12:12:48 +03:00
|
|
|
struct mmc_devfeq_clk_scaling clk_scaling;
|
2005-08-19 09:42:52 +01:00
|
|
|
int index;
|
2006-09-03 06:43:33 -07:00
|
|
|
const struct mmc_host_ops *ops;
|
2015-05-21 13:43:24 +05:30
|
|
|
const struct mmc_cmdq_host_ops *cmdq_ops;
|
2014-11-28 14:38:36 +01:00
|
|
|
struct mmc_pwrseq *pwrseq;
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned int f_min;
|
|
|
|
unsigned int f_max;
|
2010-09-06 09:37:19 +08:00
|
|
|
unsigned int f_init;
|
2005-04-16 15:20:36 -07:00
|
|
|
u32 ocr_avail;
|
2010-12-08 10:04:30 +01:00
|
|
|
u32 ocr_avail_sdio; /* SDIO-specific OCR */
|
|
|
|
u32 ocr_avail_sd; /* SD-specific OCR */
|
|
|
|
u32 ocr_avail_mmc; /* MMC-specific OCR */
|
mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume
If you don't use CONFIG_MMC_UNSAFE_RESUME, as soon as you attempt to
suspend, the card will be removed, therefore this patch doesn't change the
behavior of this option.
However the removal will be done by pm notifier, which runs while
userspace is still not frozen and thus can freely use del_gendisk, without
the risk of deadlock which would happen otherwise.
Card detect workqueue is now disabled while userspace is frozen, Therefore
if you do use CONFIG_MMC_UNSAFE_RESUME, and remove the card during
suspend, the removal will be detected as soon as userspace is unfrozen,
again at the moment it is safe to call del_gendisk.
Tested with and without CONFIG_MMC_UNSAFE_RESUME with suspend and hibernate.
[akpm@linux-foundation.org: clean up function prototype]
[akpm@linux-foundation.org: fix CONFIG_PM-n linkage, small cleanups]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-08-10 18:01:41 -07:00
|
|
|
struct notifier_block pm_notify;
|
2012-07-04 13:31:48 +08:00
|
|
|
u32 max_current_330;
|
|
|
|
u32 max_current_300;
|
|
|
|
u32 max_current_180;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-03-16 19:39:00 -07:00
|
|
|
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
|
2007-02-09 22:49:31 +01:00
|
|
|
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
|
|
|
|
#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
|
|
|
|
#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
|
|
|
|
#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
|
|
|
|
#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
|
|
|
|
#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
|
|
|
|
#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
|
|
|
|
#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
|
|
|
|
#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
|
|
|
|
#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
|
|
|
|
#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
|
|
|
|
#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
|
|
|
|
#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
|
|
|
|
#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
|
|
|
|
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
|
|
|
|
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
|
|
|
|
|
2012-11-14 12:35:51 +00:00
|
|
|
u32 caps; /* Host capabilities */
|
2005-09-06 15:18:55 -07:00
|
|
|
|
|
|
|
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
|
2008-07-06 01:10:27 +02:00
|
|
|
#define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
|
|
|
|
#define MMC_CAP_SD_HIGHSPEED (1 << 2) /* Can do SD high-speed timing */
|
|
|
|
#define MMC_CAP_SDIO_IRQ (1 << 3) /* Can signal pending SDIO IRQs */
|
|
|
|
#define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
|
|
|
|
#define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
|
2008-11-17 14:35:21 +02:00
|
|
|
#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
|
2013-05-02 14:02:39 +02:00
|
|
|
#define MMC_CAP_AGGRESSIVE_PM (1 << 7) /* Suspend (e)MMC/SD at idle */
|
2009-09-22 16:44:32 -07:00
|
|
|
#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
|
2009-09-22 16:44:34 -07:00
|
|
|
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
|
mmc: add erase, secure erase, trim and secure trim operations
SD/MMC cards tend to support an erase operation. In addition, eMMC v4.4
cards can support secure erase, trim and secure trim operations that are
all variants of the basic erase command.
SD/MMC device attributes "erase_size" and "preferred_erase_size" have been
added.
"erase_size" is the minimum size, in bytes, of an erase operation. For
MMC, "erase_size" is the erase group size reported by the card. Note that
"erase_size" does not apply to trim or secure trim operations where the
minimum size is always one 512 byte sector. For SD, "erase_size" is 512
if the card is block-addressed, 0 otherwise.
SD/MMC cards can erase an arbitrarily large area up to and
including the whole card. When erasing a large area it may
be desirable to do it in smaller chunks for three reasons:
1. A single erase command will make all other I/O on the card
wait. This is not a problem if the whole card is being erased, but
erasing one partition will make I/O for another partition on the
same card wait for the duration of the erase - which could be a
several minutes.
2. To be able to inform the user of erase progress.
3. The erase timeout becomes too large to be very useful.
Because the erase timeout contains a margin which is multiplied by
the size of the erase area, the value can end up being several
minutes for large areas.
"erase_size" is not the most efficient unit to erase (especially for SD
where it is just one sector), hence "preferred_erase_size" provides a good
chunk size for erasing large areas.
For MMC, "preferred_erase_size" is the high-capacity erase size if a card
specifies one, otherwise it is based on the capacity of the card.
For SD, "preferred_erase_size" is the allocation unit size specified by
the card.
"preferred_erase_size" is in bytes.
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Acked-by: Jens Axboe <axboe@kernel.dk>
Cc: Kyungmin Park <kmpark@infradead.org>
Cc: Madhusudhan Chikkature <madhu.cr@ti.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Ben Gardiner <bengardiner@nanometrics.ca>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-08-11 14:17:46 -07:00
|
|
|
#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
|
2010-09-30 17:37:23 -04:00
|
|
|
#define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
|
|
|
|
/* DDR mode at 1.8V */
|
|
|
|
#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
|
|
|
|
/* DDR mode at 1.2V */
|
2010-11-19 09:29:09 +02:00
|
|
|
#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
|
2010-12-15 08:14:24 +01:00
|
|
|
#define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */
|
mmc: sd: add support for signal voltage switch procedure
Host Controller v3.00 adds another Capabilities register. Apart
from other things, this new register indicates whether the Host
Controller supports SDR50, SDR104, and DDR50 UHS-I modes. The spec
doesn't mention about explicit support for SDR12 and SDR25 UHS-I
modes, so the Host Controller v3.00 should support them by default.
Also if the controller supports SDR104 mode, it will also support
SDR50 mode as well. So depending on the host support, we set the
corresponding MMC_CAP_* flags. One more new register. Host Control2
is added in v3.00, which is used during Signal Voltage Switch
procedure described below.
Since as per v3.00 spec, UHS-I supported hosts should set S18R
to 1, we set S18R (bit 24) of OCR before sending ACMD41. We also
need to set XPC (bit 28) of OCR in case the host can supply >150mA.
This support is indicated by the Maximum Current Capabilities
register of the Host Controller.
If the response of ACMD41 has both CCS and S18A set, we start the
signal voltage switch procedure, which if successfull, will switch
the card from 3.3V signalling to 1.8V signalling. Signal voltage
switch procedure adds support for a new command CMD11 in the
Physical Layer Spec v3.01. As part of this procedure, we need to
set 1.8V Signalling Enable (bit 3) of Host Control2 register, which
if remains set after 5ms, means the switch to 1.8V signalling is
successfull. Otherwise, we clear bit 24 of OCR and retry the
initialization sequence. When we remove the card, and insert the
same or another card, we need to make sure that we start with 3.3V
signalling voltage. So we call mmc_set_signal_voltage() with
MMC_SIGNAL_VOLTAGE_330 set so that we are back to 3.3V signalling
voltage before we actually start initializing the card.
Tested by Zhangfei Gao with a Toshiba uhs card and general hs card,
on mmp2 in SDMA mode.
Signed-off-by: Arindam Nath <arindam.nath@amd.com>
Reviewed-by: Philip Rakity <prakity@marvell.com>
Tested-by: Philip Rakity <prakity@marvell.com>
Acked-by: Zhangfei Gao <zhangfei.gao@marvell.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
2011-05-05 12:18:57 +05:30
|
|
|
#define MMC_CAP_UHS_SDR12 (1 << 15) /* Host supports UHS SDR12 mode */
|
|
|
|
#define MMC_CAP_UHS_SDR25 (1 << 16) /* Host supports UHS SDR25 mode */
|
|
|
|
#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
|
|
|
|
#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
|
|
|
|
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
|
2013-10-10 17:22:23 +02:00
|
|
|
#define MMC_CAP_RUNTIME_RESUME (1 << 20) /* Resume at runtime_resume. */
|
2011-05-05 12:18:59 +05:30
|
|
|
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
|
|
|
|
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
|
|
|
|
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
|
2011-05-23 15:06:36 -05:00
|
|
|
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
|
2011-08-29 16:42:11 +03:00
|
|
|
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
|
2005-09-06 15:18:55 -07:00
|
|
|
|
2012-11-14 12:35:51 +00:00
|
|
|
u32 caps2; /* More host capabilities */
|
2011-09-23 12:48:21 +03:00
|
|
|
|
|
|
|
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
|
2013-06-10 17:03:46 +02:00
|
|
|
#define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */
|
2012-01-11 14:04:52 -05:00
|
|
|
#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */
|
|
|
|
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
|
|
|
|
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
|
|
|
|
MMC_CAP2_HS200_1_2V_SDR)
|
2012-03-13 05:19:13 -04:00
|
|
|
#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
|
2012-05-01 15:49:52 +02:00
|
|
|
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
|
|
|
|
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
|
2013-02-06 17:01:43 +09:00
|
|
|
#define MMC_CAP2_PACKED_RD (1 << 12) /* Allow packed read */
|
|
|
|
#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
|
|
|
|
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
|
|
|
|
MMC_CAP2_PACKED_WR)
|
2013-04-04 16:41:06 +03:00
|
|
|
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
|
2014-04-23 17:14:58 +09:00
|
|
|
#define MMC_CAP2_HS400_1_8V (1 << 15) /* Can support HS400 1.8V */
|
|
|
|
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
|
|
|
|
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
|
|
|
|
MMC_CAP2_HS400_1_2V)
|
2014-11-06 15:19:05 +02:00
|
|
|
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
|
2014-04-25 12:55:30 +01:00
|
|
|
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
|
2015-05-06 20:31:19 +02:00
|
|
|
#define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */
|
2014-12-03 23:38:06 +02:00
|
|
|
#define MMC_CAP2_PACKED_WR_CONTROL (1 << 19) /* Allow write packing control */
|
2014-12-04 09:57:23 +02:00
|
|
|
#define MMC_CAP2_CLK_SCALE (1 << 20) /* Allow dynamic clk scaling */
|
2014-12-04 21:42:45 +02:00
|
|
|
/* Allows Asynchronous SDIO irq while card is in 4-bit mode */
|
|
|
|
#define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 21)
|
2015-01-09 15:11:57 -08:00
|
|
|
/* Some hosts need additional tuning */
|
|
|
|
#define MMC_CAP2_HS400_POST_TUNING (1 << 22)
|
2014-08-20 16:42:55 +08:00
|
|
|
#define MMC_CAP2_NONHOTPLUG (1 << 25) /*Don't support hotplug*/
|
2015-05-21 13:29:51 +05:30
|
|
|
#define MMC_CAP2_CMD_QUEUE (1 << 26) /* support eMMC command queue */
|
2015-08-24 18:56:22 +05:30
|
|
|
#define MMC_CAP2_SANITIZE (1 << 27) /* Support Sanitize */
|
2015-09-29 17:34:03 +03:00
|
|
|
#define MMC_CAP2_SLEEP_AWAKE (1 << 28) /* Use Sleep/Awake (CMD5) */
|
2015-09-26 17:38:26 -07:00
|
|
|
/* use max discard ignoring max_busy_timeout parameter */
|
|
|
|
#define MMC_CAP2_MAX_DISCARD_SIZE (1 << 29)
|
2015-09-29 17:34:03 +03:00
|
|
|
|
2010-03-05 13:43:31 -08:00
|
|
|
mmc_pm_flag_t pm_caps; /* supported pm features */
|
|
|
|
|
2016-04-19 16:21:16 -07:00
|
|
|
#ifdef CONFIG_MMC_CLKGATE
|
|
|
|
int clk_requests; /* internal reference counter */
|
|
|
|
unsigned int clk_delay; /* number of MCI clk hold cycles */
|
|
|
|
bool clk_gated; /* clock gated */
|
|
|
|
struct delayed_work clk_gate_work; /* delayed clock gate */
|
|
|
|
unsigned int clk_old; /* old clock value cache */
|
|
|
|
spinlock_t clk_lock; /* lock for clk fields */
|
|
|
|
struct mutex clk_gate_mutex; /* mutex for clock gating */
|
|
|
|
struct device_attribute clkgate_delay_attr;
|
|
|
|
unsigned long clkgate_delay;
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
/* host specific block data */
|
|
|
|
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
|
2010-09-10 01:33:59 -04:00
|
|
|
unsigned short max_segs; /* see blk_queue_max_segments */
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned short unused;
|
2006-11-21 17:55:45 +01:00
|
|
|
unsigned int max_req_size; /* maximum number of bytes in one req */
|
2006-11-21 17:54:23 +01:00
|
|
|
unsigned int max_blk_size; /* maximum size of one mmc block */
|
2006-11-21 17:55:45 +01:00
|
|
|
unsigned int max_blk_count; /* maximum number of blocks in one req */
|
2013-12-18 09:57:38 +01:00
|
|
|
unsigned int max_busy_timeout; /* max busy timeout in ms */
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* private data */
|
2006-12-31 00:11:32 +01:00
|
|
|
spinlock_t lock; /* lock for claim and bus ops */
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
struct mmc_ios ios; /* current io bus settings */
|
2015-09-29 17:34:03 +03:00
|
|
|
struct mmc_ios cached_ios;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-08-08 09:09:01 -07:00
|
|
|
/* group bitfields together to minimize padding */
|
|
|
|
unsigned int use_spi_crc:1;
|
|
|
|
unsigned int claimed:1; /* host exclusively claimed */
|
|
|
|
unsigned int bus_dead:1; /* bus has been released */
|
|
|
|
#ifdef CONFIG_MMC_DEBUG
|
|
|
|
unsigned int removed:1; /* host is being removed */
|
|
|
|
#endif
|
2015-05-07 13:10:12 +03:00
|
|
|
unsigned int can_retune:1; /* re-tuning can be used */
|
|
|
|
unsigned int doing_retune:1; /* re-tuning in progress */
|
|
|
|
unsigned int retune_now:1; /* do re-tuning at next req */
|
2007-08-08 09:09:01 -07:00
|
|
|
|
mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume
If you don't use CONFIG_MMC_UNSAFE_RESUME, as soon as you attempt to
suspend, the card will be removed, therefore this patch doesn't change the
behavior of this option.
However the removal will be done by pm notifier, which runs while
userspace is still not frozen and thus can freely use del_gendisk, without
the risk of deadlock which would happen otherwise.
Card detect workqueue is now disabled while userspace is frozen, Therefore
if you do use CONFIG_MMC_UNSAFE_RESUME, and remove the card during
suspend, the removal will be detected as soon as userspace is unfrozen,
again at the moment it is safe to call del_gendisk.
Tested with and without CONFIG_MMC_UNSAFE_RESUME with suspend and hibernate.
[akpm@linux-foundation.org: clean up function prototype]
[akpm@linux-foundation.org: fix CONFIG_PM-n linkage, small cleanups]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-08-10 18:01:41 -07:00
|
|
|
int rescan_disable; /* disable card detection */
|
2012-08-23 13:40:55 +02:00
|
|
|
int rescan_entered; /* used with nonremovable devices */
|
2009-09-22 16:44:29 -07:00
|
|
|
|
2015-05-07 13:10:12 +03:00
|
|
|
int need_retune; /* re-tuning is needed */
|
|
|
|
int hold_retune; /* hold off re-tuning */
|
|
|
|
unsigned int retune_period; /* re-tuning period in secs */
|
|
|
|
struct timer_list retune_timer; /* for periodic re-tuning */
|
|
|
|
|
2014-04-08 15:19:43 -07:00
|
|
|
bool trigger_card_event; /* card_event necessary */
|
|
|
|
|
2007-01-03 19:47:29 +01:00
|
|
|
struct mmc_card *card; /* device attached to this host */
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
wait_queue_head_t wq;
|
2009-09-22 16:44:30 -07:00
|
|
|
struct task_struct *claimer; /* task that has host claimed */
|
2011-02-17 21:37:48 +05:30
|
|
|
struct task_struct *suspend_task;
|
2009-09-22 16:44:30 -07:00
|
|
|
int claim_cnt; /* "claim" nesting count */
|
2006-12-26 15:11:23 +01:00
|
|
|
|
2006-11-22 14:57:56 +00:00
|
|
|
struct delayed_work detect;
|
2011-11-28 16:22:00 +02:00
|
|
|
int detect_change; /* card detect flag */
|
2012-05-01 15:40:15 +02:00
|
|
|
struct mmc_slot slot;
|
2005-09-08 22:46:00 +01:00
|
|
|
|
2006-12-31 00:11:32 +01:00
|
|
|
const struct mmc_bus_ops *bus_ops; /* current bus driver */
|
|
|
|
unsigned int bus_refs; /* reference counter */
|
|
|
|
|
2009-07-30 07:55:28 -07:00
|
|
|
unsigned int bus_resume_flags;
|
|
|
|
#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0)
|
|
|
|
#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1)
|
2017-08-07 14:58:15 +05:30
|
|
|
bool ignore_bus_resume_flags;
|
2009-07-30 07:55:28 -07:00
|
|
|
|
2007-06-30 16:29:41 +02:00
|
|
|
unsigned int sdio_irqs;
|
|
|
|
struct task_struct *sdio_irq_thread;
|
2012-04-16 19:16:54 -04:00
|
|
|
bool sdio_irq_pending;
|
2007-06-30 16:29:41 +02:00
|
|
|
atomic_t sdio_irq_thread_abort;
|
|
|
|
|
2010-03-05 13:43:31 -08:00
|
|
|
mmc_pm_flag_t pm_flags; /* requested pm features */
|
|
|
|
|
2007-09-24 07:15:48 +02:00
|
|
|
struct led_trigger *led; /* activity led */
|
|
|
|
|
2010-09-29 01:08:27 -04:00
|
|
|
#ifdef CONFIG_REGULATOR
|
|
|
|
bool regulator_enabled; /* regulator state */
|
|
|
|
#endif
|
2012-06-20 02:28:43 -04:00
|
|
|
struct mmc_supply supply;
|
2010-09-29 01:08:27 -04:00
|
|
|
|
2008-07-24 14:18:57 +02:00
|
|
|
struct dentry *debugfs_root;
|
|
|
|
|
2016-12-03 10:34:26 +08:00
|
|
|
bool err_occurred;
|
|
|
|
|
2011-07-01 18:55:22 +02:00
|
|
|
struct mmc_async_req *areq; /* active async req */
|
2013-01-14 14:28:17 -05:00
|
|
|
struct mmc_context_info context_info; /* async synchronization info */
|
2011-07-01 18:55:22 +02:00
|
|
|
|
2011-08-19 14:52:37 +02:00
|
|
|
#ifdef CONFIG_FAIL_MMC_REQUEST
|
|
|
|
struct fault_attr fail_mmc_request;
|
|
|
|
#endif
|
|
|
|
|
2011-11-04 13:53:19 +01:00
|
|
|
unsigned int actual_clock; /* Actual HC clock rate */
|
|
|
|
|
2013-03-05 11:24:52 +08:00
|
|
|
unsigned int slotno; /* used for sdio acpi binding */
|
|
|
|
|
2014-08-19 10:45:51 +02:00
|
|
|
int dsr_req; /* DSR value is valid */
|
|
|
|
u32 dsr; /* optional driver stage (DSR) value */
|
|
|
|
|
2008-04-14 15:22:49 -07:00
|
|
|
#ifdef CONFIG_MMC_EMBEDDED_SDIO
|
|
|
|
struct {
|
|
|
|
struct sdio_cis *cis;
|
|
|
|
struct sdio_cccr *cccr;
|
|
|
|
struct sdio_embedded_func *funcs;
|
|
|
|
int num_funcs;
|
|
|
|
} embedded_sdio_data;
|
|
|
|
#endif
|
2013-08-20 15:32:09 +05:30
|
|
|
/*
|
|
|
|
* Set to 1 to just stop the SDCLK to the card without
|
|
|
|
* actually disabling the clock from it's source.
|
|
|
|
*/
|
|
|
|
bool card_clock_off;
|
2010-06-11 18:13:05 +05:30
|
|
|
|
|
|
|
#ifdef CONFIG_MMC_PERF_PROFILING
|
|
|
|
struct {
|
|
|
|
|
|
|
|
unsigned long rbytes_drv; /* Rd bytes MMC Host */
|
|
|
|
unsigned long wbytes_drv; /* Wr bytes MMC Host */
|
|
|
|
ktime_t rtime_drv; /* Rd time MMC Host */
|
|
|
|
ktime_t wtime_drv; /* Wr time MMC Host */
|
|
|
|
ktime_t start;
|
|
|
|
} perf;
|
2012-03-25 11:15:41 +05:30
|
|
|
bool perf_enable;
|
2010-06-11 18:13:05 +05:30
|
|
|
#endif
|
2016-11-24 18:08:26 +05:30
|
|
|
struct mmc_trace_buffer trace_buf;
|
2014-12-04 23:05:50 +02:00
|
|
|
enum dev_state dev_status;
|
2015-03-10 16:00:56 +02:00
|
|
|
bool wakeup_on_idle;
|
2015-05-21 13:29:51 +05:30
|
|
|
struct mmc_cmdq_context_info cmdq_ctx;
|
2015-10-27 11:51:25 +05:30
|
|
|
int num_cq_slots;
|
|
|
|
int dcmd_cq_slot;
|
2015-09-28 18:53:18 -07:00
|
|
|
bool cmdq_thist_enabled;
|
2015-05-29 17:25:46 -07:00
|
|
|
/*
|
|
|
|
* several cmdq supporting host controllers are extensions
|
|
|
|
* of legacy controllers. This variable can be used to store
|
|
|
|
* a reference to the cmdq extension of the existing host
|
|
|
|
* controller.
|
|
|
|
*/
|
|
|
|
void *cmdq_private;
|
2015-05-20 16:52:04 +05:30
|
|
|
struct mmc_request *err_mrq;
|
2016-09-07 17:39:42 -07:00
|
|
|
#ifdef CONFIG_BLOCK
|
2016-08-25 18:31:01 -07:00
|
|
|
int latency_hist_enabled;
|
2017-12-21 09:57:41 -08:00
|
|
|
struct io_latency_state io_lat_read;
|
|
|
|
struct io_latency_state io_lat_write;
|
2016-09-07 17:39:42 -07:00
|
|
|
#endif
|
2016-08-25 18:31:01 -07:00
|
|
|
|
2017-03-31 16:50:59 -07:00
|
|
|
bool sdr104_wa;
|
2005-09-08 22:46:00 +01:00
|
|
|
unsigned long private[0] ____cacheline_aligned;
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
2013-02-15 16:13:53 +01:00
|
|
|
struct mmc_host *mmc_alloc_host(int extra, struct device *);
|
2014-12-03 11:12:14 +02:00
|
|
|
extern bool mmc_host_may_gate_card(struct mmc_card *);
|
2013-02-15 16:13:53 +01:00
|
|
|
int mmc_add_host(struct mmc_host *);
|
|
|
|
void mmc_remove_host(struct mmc_host *);
|
|
|
|
void mmc_free_host(struct mmc_host *);
|
2013-06-09 22:14:11 +02:00
|
|
|
int mmc_of_parse(struct mmc_host *host);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2008-04-14 15:22:49 -07:00
|
|
|
#ifdef CONFIG_MMC_EMBEDDED_SDIO
|
|
|
|
extern void mmc_set_embedded_sdio_data(struct mmc_host *host,
|
|
|
|
struct sdio_cis *cis,
|
|
|
|
struct sdio_cccr *cccr,
|
|
|
|
struct sdio_embedded_func *funcs,
|
|
|
|
int num_funcs);
|
|
|
|
#endif
|
|
|
|
|
2005-09-08 22:46:00 +01:00
|
|
|
static inline void *mmc_priv(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return (void *)host->private;
|
|
|
|
}
|
|
|
|
|
2015-05-29 17:25:46 -07:00
|
|
|
static inline void *mmc_cmdq_private(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->cmdq_private;
|
|
|
|
}
|
|
|
|
|
2007-08-08 09:09:01 -07:00
|
|
|
#define mmc_host_is_spi(host) ((host)->caps & MMC_CAP_SPI)
|
|
|
|
|
2006-09-12 17:00:10 +02:00
|
|
|
#define mmc_dev(x) ((x)->parent)
|
2007-01-14 01:41:45 +01:00
|
|
|
#define mmc_classdev(x) (&(x)->class_dev)
|
2008-11-08 21:37:46 +01:00
|
|
|
#define mmc_hostname(x) (dev_name(&(x)->class_dev))
|
2009-07-30 07:55:28 -07:00
|
|
|
#define mmc_bus_needs_resume(host) ((host)->bus_resume_flags & \
|
|
|
|
MMC_BUSRESUME_NEEDS_RESUME)
|
2010-10-14 15:20:21 -07:00
|
|
|
#define mmc_bus_manual_resume(host) ((host)->bus_resume_flags & \
|
|
|
|
MMC_BUSRESUME_MANUAL_RESUME)
|
2009-07-30 07:55:28 -07:00
|
|
|
|
|
|
|
static inline void mmc_set_bus_resume_policy(struct mmc_host *host, int manual)
|
|
|
|
{
|
|
|
|
if (manual)
|
|
|
|
host->bus_resume_flags |= MMC_BUSRESUME_MANUAL_RESUME;
|
|
|
|
else
|
|
|
|
host->bus_resume_flags &= ~MMC_BUSRESUME_MANUAL_RESUME;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int mmc_resume_bus(struct mmc_host *host);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2013-02-15 16:13:53 +01:00
|
|
|
int mmc_power_save_host(struct mmc_host *host);
|
|
|
|
int mmc_power_restore_host(struct mmc_host *host);
|
2009-09-22 16:44:33 -07:00
|
|
|
|
2013-02-15 16:13:53 +01:00
|
|
|
void mmc_detect_change(struct mmc_host *, unsigned long delay);
|
|
|
|
void mmc_request_done(struct mmc_host *, struct mmc_request *);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-07-24 02:09:39 -04:00
|
|
|
static inline void mmc_signal_sdio_irq(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
host->ops->enable_sdio_irq(host, 0);
|
2012-04-16 19:16:54 -04:00
|
|
|
host->sdio_irq_pending = true;
|
2015-07-10 11:36:45 +08:00
|
|
|
if (host->sdio_irq_thread)
|
|
|
|
wake_up_process(host->sdio_irq_thread);
|
2007-07-24 02:09:39 -04:00
|
|
|
}
|
|
|
|
|
2014-04-25 12:55:30 +01:00
|
|
|
void sdio_run_irqs(struct mmc_host *host);
|
|
|
|
|
2010-09-29 01:08:27 -04:00
|
|
|
#ifdef CONFIG_REGULATOR
|
2009-03-11 03:30:43 -08:00
|
|
|
int mmc_regulator_get_ocrmask(struct regulator *supply);
|
2010-09-29 01:08:27 -04:00
|
|
|
int mmc_regulator_set_ocr(struct mmc_host *mmc,
|
|
|
|
struct regulator *supply,
|
|
|
|
unsigned short vdd_bit);
|
2015-10-12 14:48:25 +02:00
|
|
|
int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios);
|
2010-09-29 01:08:27 -04:00
|
|
|
#else
|
|
|
|
static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
|
|
|
|
struct regulator *supply,
|
|
|
|
unsigned short vdd_bit)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-10-12 14:48:25 +02:00
|
|
|
|
|
|
|
static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
|
|
|
|
struct mmc_ios *ios)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2010-09-29 01:08:27 -04:00
|
|
|
#endif
|
2009-03-11 03:30:43 -08:00
|
|
|
|
2014-05-06 15:57:01 -07:00
|
|
|
int mmc_regulator_get_supply(struct mmc_host *mmc);
|
|
|
|
|
mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume
If you don't use CONFIG_MMC_UNSAFE_RESUME, as soon as you attempt to
suspend, the card will be removed, therefore this patch doesn't change the
behavior of this option.
However the removal will be done by pm notifier, which runs while
userspace is still not frozen and thus can freely use del_gendisk, without
the risk of deadlock which would happen otherwise.
Card detect workqueue is now disabled while userspace is frozen, Therefore
if you do use CONFIG_MMC_UNSAFE_RESUME, and remove the card during
suspend, the removal will be detected as soon as userspace is unfrozen,
again at the moment it is safe to call del_gendisk.
Tested with and without CONFIG_MMC_UNSAFE_RESUME with suspend and hibernate.
[akpm@linux-foundation.org: clean up function prototype]
[akpm@linux-foundation.org: fix CONFIG_PM-n linkage, small cleanups]
[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-08-10 18:01:41 -07:00
|
|
|
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
|
2009-09-22 16:44:29 -07:00
|
|
|
|
2010-09-27 09:42:19 +01:00
|
|
|
static inline int mmc_card_is_removable(struct mmc_host *host)
|
|
|
|
{
|
2013-10-30 01:00:18 +01:00
|
|
|
return !(host->caps & MMC_CAP_NONREMOVABLE);
|
2010-09-27 09:42:19 +01:00
|
|
|
}
|
|
|
|
|
2011-04-05 17:43:20 +03:00
|
|
|
static inline int mmc_card_keep_power(struct mmc_host *host)
|
2010-11-28 07:21:29 +02:00
|
|
|
{
|
|
|
|
return host->pm_flags & MMC_PM_KEEP_POWER;
|
|
|
|
}
|
|
|
|
|
2011-04-05 17:43:21 +03:00
|
|
|
static inline int mmc_card_wake_sdio_irq(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->pm_flags & MMC_PM_WAKE_SDIO_IRQ;
|
|
|
|
}
|
2011-05-23 15:06:36 -05:00
|
|
|
|
|
|
|
static inline int mmc_host_cmd23(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->caps & MMC_CAP_CMD23;
|
|
|
|
}
|
2011-09-23 12:48:21 +03:00
|
|
|
|
|
|
|
static inline int mmc_boot_partition_access(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
|
|
|
|
}
|
|
|
|
|
2015-11-25 10:37:21 +05:30
|
|
|
static inline bool mmc_card_and_host_support_async_int(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return ((host->caps2 & MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) &&
|
|
|
|
(host->card->cccr.async_intr_sup));
|
|
|
|
}
|
|
|
|
|
2012-12-04 17:06:19 +05:30
|
|
|
static inline int mmc_host_uhs(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->caps &
|
|
|
|
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
|
|
|
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
|
|
|
|
MMC_CAP_UHS_DDR50);
|
|
|
|
}
|
|
|
|
|
2017-03-30 14:41:16 -07:00
|
|
|
static inline void mmc_host_clear_sdr104(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
host->caps &= ~MMC_CAP_UHS_SDR104;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mmc_host_set_sdr104(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
host->caps |= MMC_CAP_UHS_SDR104;
|
|
|
|
}
|
|
|
|
|
2013-02-06 17:02:46 +09:00
|
|
|
static inline int mmc_host_packed_wr(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->caps2 & MMC_CAP2_PACKED_WR;
|
|
|
|
}
|
|
|
|
|
2015-05-21 17:21:07 +05:30
|
|
|
static inline void mmc_host_set_halt(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
set_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mmc_host_clr_halt(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
clear_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mmc_host_halt(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return test_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
2015-10-27 11:51:25 +05:30
|
|
|
static inline void mmc_host_set_cq_disable(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
set_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mmc_host_clr_cq_disable(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
clear_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mmc_host_cq_disable(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return test_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
|
|
|
|
}
|
|
|
|
|
2016-04-19 16:21:16 -07:00
|
|
|
#ifdef CONFIG_MMC_CLKGATE
|
|
|
|
void mmc_host_clk_hold(struct mmc_host *host);
|
|
|
|
void mmc_host_clk_release(struct mmc_host *host);
|
|
|
|
unsigned int mmc_host_clk_rate(struct mmc_host *host);
|
|
|
|
|
|
|
|
#else
|
|
|
|
static inline void mmc_host_clk_hold(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mmc_host_clk_release(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
return host->ios.clock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-04-23 17:07:35 +09:00
|
|
|
static inline int mmc_card_hs(struct mmc_card *card)
|
|
|
|
{
|
|
|
|
return card->host->ios.timing == MMC_TIMING_SD_HS ||
|
|
|
|
card->host->ios.timing == MMC_TIMING_MMC_HS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int mmc_card_uhs(struct mmc_card *card)
|
|
|
|
{
|
|
|
|
return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
|
|
|
|
card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool mmc_card_hs200(struct mmc_card *card)
|
|
|
|
{
|
|
|
|
return card->host->ios.timing == MMC_TIMING_MMC_HS200;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool mmc_card_ddr52(struct mmc_card *card)
|
|
|
|
{
|
|
|
|
return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
|
|
|
|
}
|
2014-04-23 17:14:58 +09:00
|
|
|
|
|
|
|
static inline bool mmc_card_hs400(struct mmc_card *card)
|
|
|
|
{
|
|
|
|
return card->host->ios.timing == MMC_TIMING_MMC_HS400;
|
|
|
|
}
|
|
|
|
|
2017-06-08 23:04:42 +05:30
|
|
|
void mmc_retune_enable(struct mmc_host *host);
|
|
|
|
void mmc_retune_disable(struct mmc_host *host);
|
2015-05-07 13:10:12 +03:00
|
|
|
void mmc_retune_timer_stop(struct mmc_host *host);
|
|
|
|
|
|
|
|
static inline void mmc_retune_needed(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
if (host->can_retune)
|
|
|
|
host->need_retune = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mmc_retune_recheck(struct mmc_host *host)
|
|
|
|
{
|
|
|
|
if (host->hold_retune <= 1)
|
|
|
|
host->retune_now = 1;
|
|
|
|
}
|
|
|
|
|
2011-05-27 16:04:03 -04:00
|
|
|
#endif /* LINUX_MMC_HOST_H */
|