MMC core:
- Add TRACE support to be able to debug request flow - Extend/improve reset support for (e)MMC - Convert MMC pwrseq to platform device drivers - Use IDA for indexes - Some additional minor improvements MMC host: - sdhci: Re-factoring, clean-ups and improvements - sdhci-acpi|pci: Use MMC_CAP_AGGRESSIVE_PM for Broxton - omap/omap_hsmmc: Convert to use dma_request_chan() - usdhi6rol0: Add support for UHS modes - sh_mmcif: Update runtime PM support - tmio: Wolfram Sang steps in as maintainer - tmio: Add UHS-I mode support - sh_mobile_sdhi: Add UHS-I mode support - tmio/sdhi: Re-factoring, clean-ups and improvements - dw_mmc: Re-factoring and clean-ups - davinci: Convert to use dma_request_chan() -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXObOWAAoJEP4mhCVzWIwp3P4QANEb2z7NgUOw3DTti87r05gj N3PNafNIn7EjrtuBenaVNZUkGnjnzVanNYEMArGFIdeVhJ/ZCCJY1fUOK161NUmO 1zRCOSufD9mRmhNtKb7jKu1YboXPRyKDaPVBTSSVrQPBw699tALGHCyAFvgFFKPD RvTPHSvH1vTy0VF50/ao/vl1ci89nxp6PBG/5xe1rorBHH1CYaiPgWtniMqc09Ix LiAO8Ox7fNd4WgK1tO56xJgEN2WA+Pbqy/7UabO+OjXoAMbPmO/l8vP0/9MqlBaX WZyDVwusQ9VhyDMsQ6tpZa6k8G3u3LOeolZWHKQqHpJYbNuwP+szh4gdJRb838CC AIz9UWC35ERn7yYD0aL5ok0TQhf4NJhJZibbGT2zNtnUVaSJnrJsqNtQOtEVLI9v KxzSiKsAAC0fGpyvze3/yU4JXc1yJd8EXm1iakF5KYBimC+wzVRqQmuDUPrLjTG5 iypctu+yqb2OXmKbedsCruJ7nnLYAcGFKAaUSvCxn7AO4e44YEU7VIeWdC+NO6+s vf9HNfKwiorw2mkYNcfnJgTjzqXhimOp+94WAOUBMhi1w+OZ1TUlSriTyBbK3s1G rb4I37T7oLZIpDitfvmra9ORqNyUr0AlG3728BScN/Rc3731uEIBRd11h32hUoXk b8a9ORVfHZHMrv5+5T0N =89kT -----END PGP SIGNATURE----- Merge tag 'mmc-v4.7' of git://git.linaro.org/people/ulf.hansson/mmc Pull MMC updates from Ulf Hansson: "MMC core: - Add TRACE support to be able to debug request flow - Extend/improve reset support for (e)MMC - Convert MMC pwrseq to platform device drivers - Use IDA for indexes - Some additional minor improvements MMC host: - sdhci: Re-factoring, clean-ups and improvements - sdhci-acpi|pci: Use MMC_CAP_AGGRESSIVE_PM for Broxton - omap/omap_hsmmc: Convert to use dma_request_chan() - usdhi6rol0: Add support for UHS modes - sh_mmcif: Update runtime PM support - tmio: Wolfram Sang steps in as maintainer - tmio: Add UHS-I mode support - sh_mobile_sdhi: Add UHS-I mode support - tmio/sdhi: Re-factoring, clean-ups and improvements - dw_mmc: Re-factoring and clean-ups - davinci: Convert to use dma_request_chan()" * tag 'mmc-v4.7' of git://git.linaro.org/people/ulf.hansson/mmc: (99 commits) mmc: mmc: Fix partition switch timeout for some eMMCs mmc: sh_mobile_sdhi: enable SDIO IRQs for RCar Gen3 mmc: sdio: fall back to SDIO 1.0 for broken 1.1 cards mmc: sdhci-st: correct name of sd-uhs-sdr50 property MAINTAINERS: update entry for TMIO MMC driver mmc: block: improve logging of handling emmc timeouts mmc: sdhci: removed unneeded function wrappers mmc: core: remove the invalid message in mmc_select_timing mmc: core: fix using wrong io voltage if mmc_select_hs200 fails mmc: sdhci-of-arasan: fix set_clock when a phy is supported mmc: omap: Use dma_request_chan() for requesting DMA channel mmc: mmc: Attempt to flush cache before reset mmc: sh_mobile_sdhi: check return value when changing clk mmc: sh_mobile_sdhi: only change the clock on RCar Gen2+ mmc: tmio/sdhi: introduce flag for RCar 2+ specific features mmc: sh_mobile_sdhi: make clk_update function more compact mmc: omap_hsmmc: Use dma_request_chan() for requesting DMA channel mmc: sdhci-of-at91: add presets setup mmc: usdhi6rol0: add pinctrl to set pin drive strength mmc: usdhi6rol0: add support for UHS modes ...
This commit is contained in:
commit
3e21e5dda4
|
@ -38,7 +38,7 @@ Optional properties:
|
|||
- bus-width: Number of data lines.
|
||||
See: Documentation/devicetree/bindings/mmc/mmc.txt.
|
||||
|
||||
- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for
|
||||
- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for
|
||||
configuring the CCONFIG3 in the mmcss.
|
||||
See: Documentation/devicetree/bindings/mmc/mmc.txt.
|
||||
|
||||
|
@ -48,7 +48,7 @@ Optional properties:
|
|||
- vqmmc-supply: Phandle to the regulator dt node, mentioned as the vcc/vdd
|
||||
supply in eMMC/SD specs.
|
||||
|
||||
- sd-uhs--sdr50: To enable the SDR50 in the mmcss.
|
||||
- sd-uhs-sdr50: To enable the SDR50 in the mmcss.
|
||||
See: Documentation/devicetree/bindings/mmc/mmc.txt.
|
||||
|
||||
- sd-uhs-sdr104: To enable the SDR104 in the mmcss.
|
||||
|
|
|
@ -26,3 +26,6 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
|
||||
- pinctrl-names: should be "default", "state_uhs"
|
||||
- pinctrl-0: should contain default/high speed pin ctrl
|
||||
- pinctrl-1: should contain uhs mode pin ctrl
|
||||
|
|
|
@ -12,6 +12,12 @@ Optional properties:
|
|||
|
||||
- vmmc-supply: a phandle of a regulator, supplying Vcc to the card
|
||||
- vqmmc-supply: a phandle of a regulator, supplying VccQ to the card
|
||||
- pinctrl-names: Can contain a "default" entry and a "state_uhs"
|
||||
entry. The state_uhs entry is used together with the default
|
||||
entry when the board requires distinct settings for UHS speeds.
|
||||
|
||||
- pinctrl-N: One property for each name listed in pinctrl-names, see
|
||||
../pinctrl/pinctrl-bindings.txt.
|
||||
|
||||
Additionally any standard mmc bindings from mmc.txt can be used.
|
||||
|
||||
|
|
|
@ -11246,14 +11246,13 @@ S: Maintained
|
|||
F: drivers/media/i2c/tc358743*
|
||||
F: include/media/i2c/tc358743.h
|
||||
|
||||
TMIO MMC DRIVER
|
||||
M: Ian Molton <ian@mnementh.co.uk>
|
||||
TMIO/SDHI MMC DRIVER
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Supported
|
||||
F: drivers/mmc/host/tmio_mmc*
|
||||
F: drivers/mmc/host/sh_mobile_sdhi.c
|
||||
F: include/linux/mmc/tmio.h
|
||||
F: include/linux/mmc/sh_mobile_sdhi.h
|
||||
F: include/linux/mfd/tmio.h
|
||||
|
||||
TMP401 HARDWARE MONITOR DRIVER
|
||||
M: Guenter Roeck <linux@roeck-us.net>
|
||||
|
|
|
@ -751,16 +751,6 @@ static struct resource da8xx_mmcsd0_resources[] = {
|
|||
.end = IRQ_DA8XX_MMCSDINT0,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{ /* DMA RX */
|
||||
.start = DA8XX_DMA_MMCSD0_RX,
|
||||
.end = DA8XX_DMA_MMCSD0_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
{ /* DMA TX */
|
||||
.start = DA8XX_DMA_MMCSD0_TX,
|
||||
.end = DA8XX_DMA_MMCSD0_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device da8xx_mmcsd0_device = {
|
||||
|
@ -788,16 +778,6 @@ static struct resource da850_mmcsd1_resources[] = {
|
|||
.end = IRQ_DA850_MMCSDINT0_1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{ /* DMA RX */
|
||||
.start = DA850_DMA_MMCSD1_RX,
|
||||
.end = DA850_DMA_MMCSD1_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
{ /* DMA TX */
|
||||
.start = DA850_DMA_MMCSD1_TX,
|
||||
.end = DA850_DMA_MMCSD1_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device da850_mmcsd1_device = {
|
||||
|
|
|
@ -144,14 +144,6 @@ static struct resource mmcsd0_resources[] = {
|
|||
.start = IRQ_SDIOINT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
/* DMA channels: RX, then TX */
|
||||
{
|
||||
.start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCRXEVT),
|
||||
.flags = IORESOURCE_DMA,
|
||||
}, {
|
||||
.start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCTXEVT),
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device davinci_mmcsd0_device = {
|
||||
|
@ -181,14 +173,6 @@ static struct resource mmcsd1_resources[] = {
|
|||
.start = IRQ_DM355_SDIOINT1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
/* DMA channels: RX, then TX */
|
||||
{
|
||||
.start = EDMA_CTLR_CHAN(0, 30), /* rx */
|
||||
.flags = IORESOURCE_DMA,
|
||||
}, {
|
||||
.start = EDMA_CTLR_CHAN(0, 31), /* tx */
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device davinci_mmcsd1_device = {
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mmcif.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/sh_eth.h>
|
||||
#include <linux/sh_intc.h>
|
||||
#include <linux/usb/renesas_usbhs.h>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/sh_flctl.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mmcif.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mtd/onenand.h>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/input/sh_keysc.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/capability.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/idr.h>
|
||||
|
||||
#include <linux/mmc/ioctl.h>
|
||||
#include <linux/mmc/card.h>
|
||||
|
@ -78,14 +79,14 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
|
|||
/*
|
||||
* We've only got one major, so number of mmcblk devices is
|
||||
* limited to (1 << 20) / number of minors per device. It is also
|
||||
* currently limited by the size of the static bitmaps below.
|
||||
* limited by the MAX_DEVICES below.
|
||||
*/
|
||||
static int max_devices;
|
||||
|
||||
#define MAX_DEVICES 256
|
||||
|
||||
/* TODO: Replace these with struct ida */
|
||||
static DECLARE_BITMAP(dev_use, MAX_DEVICES);
|
||||
static DEFINE_IDA(mmc_blk_ida);
|
||||
static DEFINE_SPINLOCK(mmc_blk_lock);
|
||||
|
||||
/*
|
||||
* There is one mmc_blk_data per slot.
|
||||
|
@ -178,7 +179,9 @@ static void mmc_blk_put(struct mmc_blk_data *md)
|
|||
int devidx = mmc_get_devidx(md->disk);
|
||||
blk_cleanup_queue(md->queue.queue);
|
||||
|
||||
__clear_bit(devidx, dev_use);
|
||||
spin_lock(&mmc_blk_lock);
|
||||
ida_remove(&mmc_blk_ida, devidx);
|
||||
spin_unlock(&mmc_blk_lock);
|
||||
|
||||
put_disk(md->disk);
|
||||
kfree(md);
|
||||
|
@ -945,16 +948,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
|
|||
req->rq_disk->disk_name, "timed out", name, status);
|
||||
|
||||
/* If the status cmd initially failed, retry the r/w cmd */
|
||||
if (!status_valid)
|
||||
if (!status_valid) {
|
||||
pr_err("%s: status not valid, retrying timeout\n",
|
||||
req->rq_disk->disk_name);
|
||||
return ERR_RETRY;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it was a r/w cmd crc error, or illegal command
|
||||
* (eg, issued in wrong state) then retry - we should
|
||||
* have corrected the state problem above.
|
||||
*/
|
||||
if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND))
|
||||
if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
|
||||
pr_err("%s: command error, retrying timeout\n",
|
||||
req->rq_disk->disk_name);
|
||||
return ERR_RETRY;
|
||||
}
|
||||
|
||||
/* Otherwise abort the command */
|
||||
return ERR_ABORT;
|
||||
|
@ -2189,10 +2198,23 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
|||
struct mmc_blk_data *md;
|
||||
int devidx, ret;
|
||||
|
||||
devidx = find_first_zero_bit(dev_use, max_devices);
|
||||
if (devidx >= max_devices)
|
||||
return ERR_PTR(-ENOSPC);
|
||||
__set_bit(devidx, dev_use);
|
||||
again:
|
||||
if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&mmc_blk_lock);
|
||||
ret = ida_get_new(&mmc_blk_ida, &devidx);
|
||||
spin_unlock(&mmc_blk_lock);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
else if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (devidx >= max_devices) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
|
||||
if (!md) {
|
||||
|
@ -2289,6 +2311,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
|||
err_kfree:
|
||||
kfree(md);
|
||||
out:
|
||||
spin_lock(&mmc_blk_lock);
|
||||
ida_remove(&mmc_blk_ida, devidx);
|
||||
spin_unlock(&mmc_blk_lock);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
#
|
||||
# MMC core configuration
|
||||
#
|
||||
config PWRSEQ_EMMC
|
||||
tristate "HW reset support for eMMC"
|
||||
default y
|
||||
depends on OF
|
||||
help
|
||||
This selects Hardware reset support aka pwrseq-emmc for eMMC
|
||||
devices. By default this option is set to y.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pwrseq_emmc.
|
||||
|
||||
config PWRSEQ_SIMPLE
|
||||
tristate "Simple HW reset support for MMC"
|
||||
default y
|
||||
depends on OF
|
||||
help
|
||||
This selects simple hardware reset support aka pwrseq-simple for MMC
|
||||
devices. By default this option is set to y.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pwrseq_simple.
|
||||
|
|
|
@ -8,5 +8,7 @@ mmc_core-y := core.o bus.o host.o \
|
|||
sdio.o sdio_ops.o sdio_bus.o \
|
||||
sdio_cis.o sdio_io.o sdio_irq.o \
|
||||
quirks.o slot-gpio.o
|
||||
mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o
|
||||
mmc_core-$(CONFIG_OF) += pwrseq.o
|
||||
obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o
|
||||
obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o
|
||||
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
|
||||
|
|
|
@ -36,6 +36,9 @@
|
|||
#include <linux/mmc/sd.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/mmc.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "bus.h"
|
||||
#include "host.h"
|
||||
|
@ -140,6 +143,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
|||
cmd->retries = 0;
|
||||
}
|
||||
|
||||
trace_mmc_request_done(host, mrq);
|
||||
|
||||
if (err && cmd->retries && !mmc_card_removed(host->card)) {
|
||||
/*
|
||||
* Request starter must handle retries - see
|
||||
|
@ -215,6 +220,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
|||
}
|
||||
}
|
||||
|
||||
trace_mmc_request_start(host, mrq);
|
||||
|
||||
host->ops->request(host, mrq);
|
||||
}
|
||||
|
||||
|
@ -2449,8 +2456,9 @@ int mmc_hw_reset(struct mmc_host *host)
|
|||
ret = host->bus_ops->reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret != -EOPNOTSUPP)
|
||||
pr_warn("%s: tried to reset card\n", mmc_hostname(host));
|
||||
if (ret)
|
||||
pr_warn("%s: tried to reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -33,14 +33,14 @@
|
|||
|
||||
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
|
||||
|
||||
static DEFINE_IDR(mmc_host_idr);
|
||||
static DEFINE_IDA(mmc_host_ida);
|
||||
static DEFINE_SPINLOCK(mmc_host_lock);
|
||||
|
||||
static void mmc_host_classdev_release(struct device *dev)
|
||||
{
|
||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||
spin_lock(&mmc_host_lock);
|
||||
idr_remove(&mmc_host_idr, host->index);
|
||||
ida_remove(&mmc_host_ida, host->index);
|
||||
spin_unlock(&mmc_host_lock);
|
||||
kfree(host);
|
||||
}
|
||||
|
@ -321,14 +321,20 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
|||
|
||||
/* scanning will be enabled when we're ready */
|
||||
host->rescan_disable = 1;
|
||||
idr_preload(GFP_KERNEL);
|
||||
|
||||
again:
|
||||
if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) {
|
||||
kfree(host);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock(&mmc_host_lock);
|
||||
err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT);
|
||||
if (err >= 0)
|
||||
host->index = err;
|
||||
err = ida_get_new(&mmc_host_ida, &host->index);
|
||||
spin_unlock(&mmc_host_lock);
|
||||
idr_preload_end();
|
||||
if (err < 0) {
|
||||
|
||||
if (err == -EAGAIN) {
|
||||
goto again;
|
||||
} else if (err) {
|
||||
kfree(host);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -333,6 +333,9 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
|
|||
}
|
||||
}
|
||||
|
||||
/* Minimum partition switch timeout in milliseconds */
|
||||
#define MMC_MIN_PART_SWITCH_TIME 300
|
||||
|
||||
/*
|
||||
* Decode extended CSD.
|
||||
*/
|
||||
|
@ -397,6 +400,10 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
|||
|
||||
/* EXT_CSD value is in units of 10ms, but we store in ms */
|
||||
card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
|
||||
/* Some eMMC set the value too low so set a minimum */
|
||||
if (card->ext_csd.part_time &&
|
||||
card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME)
|
||||
card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME;
|
||||
|
||||
/* Sleep / awake timeout in 100ns units */
|
||||
if (sa_shift > 0 && sa_shift <= 0x17)
|
||||
|
@ -1244,10 +1251,11 @@ static int mmc_select_hs200(struct mmc_card *card)
|
|||
{
|
||||
struct mmc_host *host = card->host;
|
||||
bool send_status = true;
|
||||
unsigned int old_timing;
|
||||
unsigned int old_timing, old_signal_voltage;
|
||||
int err = -EINVAL;
|
||||
u8 val;
|
||||
|
||||
old_signal_voltage = host->ios.signal_voltage;
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
|
@ -1256,7 +1264,7 @@ static int mmc_select_hs200(struct mmc_card *card)
|
|||
|
||||
/* If fails try again during next card power cycle */
|
||||
if (err)
|
||||
goto err;
|
||||
return err;
|
||||
|
||||
mmc_select_driver_type(card);
|
||||
|
||||
|
@ -1290,9 +1298,14 @@ static int mmc_select_hs200(struct mmc_card *card)
|
|||
}
|
||||
}
|
||||
err:
|
||||
if (err)
|
||||
if (err) {
|
||||
/* fall back to the old signal voltage, if fails report error */
|
||||
if (__mmc_set_signal_voltage(host, old_signal_voltage))
|
||||
err = -EIO;
|
||||
|
||||
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
|
||||
__func__, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1314,21 +1327,13 @@ static int mmc_select_timing(struct mmc_card *card)
|
|||
if (err && err != -EBADMSG)
|
||||
return err;
|
||||
|
||||
if (err) {
|
||||
pr_warn("%s: switch to %s failed\n",
|
||||
mmc_card_hs(card) ? "high-speed" :
|
||||
(mmc_card_hs200(card) ? "hs200" : ""),
|
||||
mmc_hostname(card->host));
|
||||
err = 0;
|
||||
}
|
||||
|
||||
bus_speed:
|
||||
/*
|
||||
* Set the bus speed to the selected bus timing.
|
||||
* If timing is not selected, backward compatible is the default.
|
||||
*/
|
||||
mmc_set_bus_speed(card);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1483,12 +1488,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|||
if (err)
|
||||
goto free_card;
|
||||
|
||||
/* If doing byte addressing, check if required to do sector
|
||||
/*
|
||||
* If doing byte addressing, check if required to do sector
|
||||
* addressing. Handle the case of <2GB cards needing sector
|
||||
* addressing. See section 8.1 JEDEC Standard JED84-A441;
|
||||
* ocr register has bit 30 set for sector addressing.
|
||||
*/
|
||||
if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30)))
|
||||
if (rocr & BIT(30))
|
||||
mmc_card_set_blockaddr(card);
|
||||
|
||||
/* Erase size depends on CSD and Extended CSD */
|
||||
|
@ -1957,19 +1963,23 @@ static int mmc_reset(struct mmc_host *host)
|
|||
{
|
||||
struct mmc_card *card = host->card;
|
||||
|
||||
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!mmc_can_reset(card))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mmc_set_clock(host, host->f_init);
|
||||
|
||||
host->ops->hw_reset(host);
|
||||
|
||||
/* Set initial state and call mmc_set_ios */
|
||||
mmc_set_initial_state(host);
|
||||
/*
|
||||
* In the case of recovery, we can't expect flushing the cache to work
|
||||
* always, but we have a go and ignore errors.
|
||||
*/
|
||||
mmc_flush_cache(host->card);
|
||||
|
||||
if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
|
||||
mmc_can_reset(card)) {
|
||||
/* If the card accept RST_n signal, send it. */
|
||||
mmc_set_clock(host, host->f_init);
|
||||
host->ops->hw_reset(host);
|
||||
/* Set initial state and call mmc_set_ios */
|
||||
mmc_set_initial_state(host);
|
||||
} else {
|
||||
/* Do a brute force power cycle */
|
||||
mmc_power_cycle(host, card->ocr);
|
||||
}
|
||||
return mmc_init_card(host, card->ocr, card);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,88 +8,55 @@
|
|||
* MMC power sequence management
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include "pwrseq.h"
|
||||
|
||||
struct mmc_pwrseq_match {
|
||||
const char *compatible;
|
||||
struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);
|
||||
};
|
||||
|
||||
static struct mmc_pwrseq_match pwrseq_match[] = {
|
||||
{
|
||||
.compatible = "mmc-pwrseq-simple",
|
||||
.alloc = mmc_pwrseq_simple_alloc,
|
||||
}, {
|
||||
.compatible = "mmc-pwrseq-emmc",
|
||||
.alloc = mmc_pwrseq_emmc_alloc,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np)
|
||||
{
|
||||
struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) {
|
||||
if (of_device_is_compatible(np, pwrseq_match[i].compatible)) {
|
||||
match = &pwrseq_match[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
static DEFINE_MUTEX(pwrseq_list_mutex);
|
||||
static LIST_HEAD(pwrseq_list);
|
||||
|
||||
int mmc_pwrseq_alloc(struct mmc_host *host)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct device_node *np;
|
||||
struct mmc_pwrseq_match *match;
|
||||
struct mmc_pwrseq *pwrseq;
|
||||
int ret = 0;
|
||||
struct mmc_pwrseq *p;
|
||||
|
||||
np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
pdev = of_find_device_by_node(np);
|
||||
if (!pdev) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
mutex_lock(&pwrseq_list_mutex);
|
||||
list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
|
||||
if (p->dev->of_node == np) {
|
||||
if (!try_module_get(p->owner))
|
||||
dev_err(host->parent,
|
||||
"increasing module refcount failed\n");
|
||||
else
|
||||
host->pwrseq = p;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match = mmc_pwrseq_find(np);
|
||||
if (IS_ERR(match)) {
|
||||
ret = PTR_ERR(match);
|
||||
goto err;
|
||||
}
|
||||
of_node_put(np);
|
||||
mutex_unlock(&pwrseq_list_mutex);
|
||||
|
||||
pwrseq = match->alloc(host, &pdev->dev);
|
||||
if (IS_ERR(pwrseq)) {
|
||||
ret = PTR_ERR(pwrseq);
|
||||
goto err;
|
||||
}
|
||||
if (!host->pwrseq)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
host->pwrseq = pwrseq;
|
||||
dev_info(host->parent, "allocated mmc-pwrseq\n");
|
||||
|
||||
err:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mmc_pwrseq_pre_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on)
|
||||
if (pwrseq && pwrseq->ops->pre_power_on)
|
||||
pwrseq->ops->pre_power_on(host);
|
||||
}
|
||||
|
||||
|
@ -97,7 +64,7 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host)
|
|||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on)
|
||||
if (pwrseq && pwrseq->ops->post_power_on)
|
||||
pwrseq->ops->post_power_on(host);
|
||||
}
|
||||
|
||||
|
@ -105,7 +72,7 @@ void mmc_pwrseq_power_off(struct mmc_host *host)
|
|||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
if (pwrseq && pwrseq->ops && pwrseq->ops->power_off)
|
||||
if (pwrseq && pwrseq->ops->power_off)
|
||||
pwrseq->ops->power_off(host);
|
||||
}
|
||||
|
||||
|
@ -113,8 +80,31 @@ void mmc_pwrseq_free(struct mmc_host *host)
|
|||
{
|
||||
struct mmc_pwrseq *pwrseq = host->pwrseq;
|
||||
|
||||
if (pwrseq && pwrseq->ops && pwrseq->ops->free)
|
||||
pwrseq->ops->free(host);
|
||||
|
||||
host->pwrseq = NULL;
|
||||
if (pwrseq) {
|
||||
module_put(pwrseq->owner);
|
||||
host->pwrseq = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
|
||||
{
|
||||
if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&pwrseq_list_mutex);
|
||||
list_add(&pwrseq->pwrseq_node, &pwrseq_list);
|
||||
mutex_unlock(&pwrseq_list_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
|
||||
|
||||
void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
|
||||
{
|
||||
if (pwrseq) {
|
||||
mutex_lock(&pwrseq_list_mutex);
|
||||
list_del(&pwrseq->pwrseq_node);
|
||||
mutex_unlock(&pwrseq_list_mutex);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
|
||||
|
|
|
@ -8,32 +8,39 @@
|
|||
#ifndef _MMC_CORE_PWRSEQ_H
|
||||
#define _MMC_CORE_PWRSEQ_H
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
struct mmc_pwrseq_ops {
|
||||
void (*pre_power_on)(struct mmc_host *host);
|
||||
void (*post_power_on)(struct mmc_host *host);
|
||||
void (*power_off)(struct mmc_host *host);
|
||||
void (*free)(struct mmc_host *host);
|
||||
};
|
||||
|
||||
struct mmc_pwrseq {
|
||||
const struct mmc_pwrseq_ops *ops;
|
||||
struct device *dev;
|
||||
struct list_head pwrseq_node;
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq);
|
||||
void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq);
|
||||
|
||||
int mmc_pwrseq_alloc(struct mmc_host *host);
|
||||
void mmc_pwrseq_pre_power_on(struct mmc_host *host);
|
||||
void mmc_pwrseq_post_power_on(struct mmc_host *host);
|
||||
void mmc_pwrseq_power_off(struct mmc_host *host);
|
||||
void mmc_pwrseq_free(struct mmc_host *host);
|
||||
|
||||
struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
|
||||
struct device *dev);
|
||||
struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
||||
struct device *dev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) {}
|
||||
static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
|
||||
static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
|
||||
static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -25,6 +28,8 @@ struct mmc_pwrseq_emmc {
|
|||
struct gpio_desc *reset_gpio;
|
||||
};
|
||||
|
||||
#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq)
|
||||
|
||||
static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
|
||||
{
|
||||
gpiod_set_value(pwrseq->reset_gpio, 1);
|
||||
|
@ -35,27 +40,11 @@ static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
|
|||
|
||||
static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_emmc, pwrseq);
|
||||
struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq);
|
||||
|
||||
__mmc_pwrseq_emmc_reset(pwrseq);
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_emmc_free(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_emmc, pwrseq);
|
||||
|
||||
unregister_restart_handler(&pwrseq->reset_nb);
|
||||
gpiod_put(pwrseq->reset_gpio);
|
||||
kfree(pwrseq);
|
||||
}
|
||||
|
||||
static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
.post_power_on = mmc_pwrseq_emmc_reset,
|
||||
.free = mmc_pwrseq_emmc_free,
|
||||
};
|
||||
|
||||
static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
|
@ -66,21 +55,22 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
||||
struct device *dev)
|
||||
static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
|
||||
.post_power_on = mmc_pwrseq_emmc_reset,
|
||||
};
|
||||
|
||||
static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_emmc *pwrseq;
|
||||
int ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
|
||||
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
|
||||
if (!pwrseq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
pwrseq->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pwrseq->reset_gpio)) {
|
||||
ret = PTR_ERR(pwrseq->reset_gpio);
|
||||
goto free;
|
||||
}
|
||||
pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pwrseq->reset_gpio))
|
||||
return PTR_ERR(pwrseq->reset_gpio);
|
||||
|
||||
/*
|
||||
* register reset handler to ensure emmc reset also from
|
||||
|
@ -92,9 +82,38 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
|
|||
register_restart_handler(&pwrseq->reset_nb);
|
||||
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
|
||||
pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.owner = THIS_MODULE;
|
||||
platform_set_drvdata(pdev, pwrseq);
|
||||
|
||||
return &pwrseq->pwrseq;
|
||||
free:
|
||||
kfree(pwrseq);
|
||||
return ERR_PTR(ret);
|
||||
return mmc_pwrseq_register(&pwrseq->pwrseq);
|
||||
}
|
||||
|
||||
static int mmc_pwrseq_emmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev);
|
||||
|
||||
unregister_restart_handler(&pwrseq->reset_nb);
|
||||
mmc_pwrseq_unregister(&pwrseq->pwrseq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mmc_pwrseq_emmc_of_match[] = {
|
||||
{ .compatible = "mmc-pwrseq-emmc",},
|
||||
{/* sentinel */},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
|
||||
|
||||
static struct platform_driver mmc_pwrseq_emmc_driver = {
|
||||
.probe = mmc_pwrseq_emmc_probe,
|
||||
.remove = mmc_pwrseq_emmc_remove,
|
||||
.driver = {
|
||||
.name = "pwrseq_emmc",
|
||||
.of_match_table = mmc_pwrseq_emmc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(mmc_pwrseq_emmc_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
* Simple MMC power sequence management
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -25,6 +28,8 @@ struct mmc_pwrseq_simple {
|
|||
struct gpio_descs *reset_gpios;
|
||||
};
|
||||
|
||||
#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
|
||||
|
||||
static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
int value)
|
||||
{
|
||||
|
@ -44,8 +49,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
|||
|
||||
static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_simple, pwrseq);
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
|
||||
clk_prepare_enable(pwrseq->ext_clk);
|
||||
|
@ -57,16 +61,14 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
|||
|
||||
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_simple, pwrseq);
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_simple, pwrseq);
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
|
||||
|
@ -76,59 +78,64 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
static void mmc_pwrseq_simple_free(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
|
||||
struct mmc_pwrseq_simple, pwrseq);
|
||||
|
||||
if (!IS_ERR(pwrseq->reset_gpios))
|
||||
gpiod_put_array(pwrseq->reset_gpios);
|
||||
|
||||
if (!IS_ERR(pwrseq->ext_clk))
|
||||
clk_put(pwrseq->ext_clk);
|
||||
|
||||
kfree(pwrseq);
|
||||
}
|
||||
|
||||
static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
|
||||
.pre_power_on = mmc_pwrseq_simple_pre_power_on,
|
||||
.post_power_on = mmc_pwrseq_simple_post_power_on,
|
||||
.power_off = mmc_pwrseq_simple_power_off,
|
||||
.free = mmc_pwrseq_simple_free,
|
||||
};
|
||||
|
||||
struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
|
||||
struct device *dev)
|
||||
static const struct of_device_id mmc_pwrseq_simple_of_match[] = {
|
||||
{ .compatible = "mmc-pwrseq-simple",},
|
||||
{/* sentinel */},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mmc_pwrseq_simple_of_match);
|
||||
|
||||
static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq;
|
||||
int ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL);
|
||||
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
|
||||
if (!pwrseq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
|
||||
pwrseq->ext_clk = clk_get(dev, "ext_clock");
|
||||
if (IS_ERR(pwrseq->ext_clk) &&
|
||||
PTR_ERR(pwrseq->ext_clk) != -ENOENT) {
|
||||
ret = PTR_ERR(pwrseq->ext_clk);
|
||||
goto free;
|
||||
}
|
||||
pwrseq->ext_clk = devm_clk_get(dev, "ext_clock");
|
||||
if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
|
||||
return PTR_ERR(pwrseq->ext_clk);
|
||||
|
||||
pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
|
||||
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pwrseq->reset_gpios) &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
|
||||
ret = PTR_ERR(pwrseq->reset_gpios);
|
||||
goto clk_put;
|
||||
return PTR_ERR(pwrseq->reset_gpios);
|
||||
}
|
||||
|
||||
pwrseq->pwrseq.dev = dev;
|
||||
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
|
||||
pwrseq->pwrseq.owner = THIS_MODULE;
|
||||
platform_set_drvdata(pdev, pwrseq);
|
||||
|
||||
return &pwrseq->pwrseq;
|
||||
clk_put:
|
||||
if (!IS_ERR(pwrseq->ext_clk))
|
||||
clk_put(pwrseq->ext_clk);
|
||||
free:
|
||||
kfree(pwrseq);
|
||||
return ERR_PTR(ret);
|
||||
return mmc_pwrseq_register(&pwrseq->pwrseq);
|
||||
}
|
||||
|
||||
static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
|
||||
|
||||
mmc_pwrseq_unregister(&pwrseq->pwrseq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mmc_pwrseq_simple_driver = {
|
||||
.probe = mmc_pwrseq_simple_probe,
|
||||
.remove = mmc_pwrseq_simple_remove,
|
||||
.driver = {
|
||||
.name = "pwrseq_simple",
|
||||
.of_match_table = mmc_pwrseq_simple_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(mmc_pwrseq_simple_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -177,8 +177,13 @@ static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func,
|
|||
vsn = func->card->cccr.sdio_vsn;
|
||||
min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
|
||||
|
||||
if (size < min_size)
|
||||
if (size == 28 && vsn == SDIO_SDIO_REV_1_10) {
|
||||
pr_warn("%s: card has broken SDIO 1.1 CIS, forcing SDIO 1.0\n",
|
||||
mmc_hostname(card->host));
|
||||
vsn = SDIO_SDIO_REV_1_00;
|
||||
} else if (size < min_size) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* TPLFE_MAX_BLK_SIZE */
|
||||
func->max_blksize = buf[12] | (buf[13] << 8);
|
||||
|
|
|
@ -677,9 +677,9 @@ config MMC_SH_MMCIF
|
|||
depends on HAS_DMA
|
||||
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
|
||||
help
|
||||
This selects the MMC Host Interface controller (MMCIF).
|
||||
This selects the MMC Host Interface controller (MMCIF) found in various
|
||||
Renesas SoCs for SH and ARM architectures.
|
||||
|
||||
This driver supports MMCIF in sh7724/sh7757/sh7372.
|
||||
|
||||
config MMC_JZ4740
|
||||
tristate "JZ4740 SD/Multimedia Card Interface support"
|
||||
|
|
|
@ -1410,8 +1410,6 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
WARN_ON(slot->mrq);
|
||||
dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
|
||||
|
||||
pm_runtime_get_sync(&host->pdev->dev);
|
||||
|
||||
/*
|
||||
* We may "know" the card is gone even though there's still an
|
||||
* electrical connection. If so, we really need to communicate
|
||||
|
@ -1442,8 +1440,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
struct atmel_mci *host = slot->host;
|
||||
unsigned int i;
|
||||
|
||||
pm_runtime_get_sync(&host->pdev->dev);
|
||||
|
||||
slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
|
||||
switch (ios->bus_width) {
|
||||
case MMC_BUS_WIDTH_1:
|
||||
|
@ -1576,8 +1572,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
break;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(&host->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&host->pdev->dev);
|
||||
}
|
||||
|
||||
static int atmci_get_ro(struct mmc_host *mmc)
|
||||
|
@ -1669,9 +1663,6 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
|
|||
spin_unlock(&host->lock);
|
||||
mmc_request_done(prev_mmc, mrq);
|
||||
spin_lock(&host->lock);
|
||||
|
||||
pm_runtime_mark_last_busy(&host->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&host->pdev->dev);
|
||||
}
|
||||
|
||||
static void atmci_command_complete(struct atmel_mci *host,
|
||||
|
|
|
@ -32,12 +32,10 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/edma.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/edma.h>
|
||||
#include <linux/platform_data/mmc-davinci.h>
|
||||
|
||||
/*
|
||||
|
@ -202,7 +200,6 @@ struct mmc_davinci_host {
|
|||
u32 buffer_bytes_left;
|
||||
u32 bytes_left;
|
||||
|
||||
u32 rxdma, txdma;
|
||||
struct dma_chan *dma_tx;
|
||||
struct dma_chan *dma_rx;
|
||||
bool use_dma;
|
||||
|
@ -513,35 +510,20 @@ davinci_release_dma_channels(struct mmc_davinci_host *host)
|
|||
|
||||
static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
|
||||
{
|
||||
int r;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
host->dma_tx =
|
||||
dma_request_slave_channel_compat(mask, edma_filter_fn,
|
||||
&host->txdma, mmc_dev(host->mmc), "tx");
|
||||
if (!host->dma_tx) {
|
||||
host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx");
|
||||
if (IS_ERR(host->dma_tx)) {
|
||||
dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n");
|
||||
return -ENODEV;
|
||||
return PTR_ERR(host->dma_tx);
|
||||
}
|
||||
|
||||
host->dma_rx =
|
||||
dma_request_slave_channel_compat(mask, edma_filter_fn,
|
||||
&host->rxdma, mmc_dev(host->mmc), "rx");
|
||||
if (!host->dma_rx) {
|
||||
host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx");
|
||||
if (IS_ERR(host->dma_rx)) {
|
||||
dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n");
|
||||
r = -ENODEV;
|
||||
goto free_master_write;
|
||||
dma_release_channel(host->dma_tx);
|
||||
return PTR_ERR(host->dma_rx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_master_write:
|
||||
dma_release_channel(host->dma_tx);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -1223,7 +1205,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
|||
struct mmc_davinci_host *host = NULL;
|
||||
struct mmc_host *mmc = NULL;
|
||||
struct resource *r, *mem = NULL;
|
||||
int ret = 0, irq = 0;
|
||||
int ret, irq;
|
||||
size_t mem_size;
|
||||
const struct platform_device_id *id_entry;
|
||||
|
||||
|
@ -1233,50 +1215,40 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = -ENODEV;
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!r || irq == NO_IRQ)
|
||||
goto out;
|
||||
return -ENODEV;
|
||||
|
||||
ret = -EBUSY;
|
||||
mem_size = resource_size(r);
|
||||
mem = request_mem_region(r->start, mem_size, pdev->name);
|
||||
mem = devm_request_mem_region(&pdev->dev, r->start, mem_size,
|
||||
pdev->name);
|
||||
if (!mem)
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
|
||||
ret = -ENOMEM;
|
||||
mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev);
|
||||
if (!mmc)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->mmc = mmc; /* Important */
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
dev_warn(&pdev->dev, "RX DMA resource not specified\n");
|
||||
else
|
||||
host->rxdma = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
dev_warn(&pdev->dev, "TX DMA resource not specified\n");
|
||||
else
|
||||
host->txdma = r->start;
|
||||
|
||||
host->mem_res = mem;
|
||||
host->base = ioremap(mem->start, mem_size);
|
||||
if (!host->base)
|
||||
goto out;
|
||||
host->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
|
||||
if (!host->base) {
|
||||
ret = -ENOMEM;
|
||||
goto ioremap_fail;
|
||||
}
|
||||
|
||||
ret = -ENXIO;
|
||||
host->clk = clk_get(&pdev->dev, "MMCSDCLK");
|
||||
host->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
ret = PTR_ERR(host->clk);
|
||||
goto out;
|
||||
goto clk_get_fail;
|
||||
}
|
||||
clk_enable(host->clk);
|
||||
ret = clk_prepare_enable(host->clk);
|
||||
if (ret)
|
||||
goto clk_prepare_enable_fail;
|
||||
|
||||
host->mmc_input_clk = clk_get_rate(host->clk);
|
||||
|
||||
init_mmcsd_host(host);
|
||||
|
@ -1291,8 +1263,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
|||
host->mmc_irq = irq;
|
||||
host->sdio_irq = platform_get_irq(pdev, 1);
|
||||
|
||||
if (host->use_dma && davinci_acquire_dma_channels(host) != 0)
|
||||
host->use_dma = 0;
|
||||
if (host->use_dma) {
|
||||
ret = davinci_acquire_dma_channels(host);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto dma_probe_defer;
|
||||
else if (ret)
|
||||
host->use_dma = 0;
|
||||
}
|
||||
|
||||
/* REVISIT: someday, support IRQ-driven card detection. */
|
||||
mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
@ -1346,15 +1323,17 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
|||
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto mmc_add_host_fail;
|
||||
|
||||
ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host);
|
||||
ret = devm_request_irq(&pdev->dev, irq, mmc_davinci_irq, 0,
|
||||
mmc_hostname(mmc), host);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto request_irq_fail;
|
||||
|
||||
if (host->sdio_irq >= 0) {
|
||||
ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0,
|
||||
mmc_hostname(mmc), host);
|
||||
ret = devm_request_irq(&pdev->dev, host->sdio_irq,
|
||||
mmc_davinci_sdio_irq, 0,
|
||||
mmc_hostname(mmc), host);
|
||||
if (!ret)
|
||||
mmc->caps |= MMC_CAP_SDIO_IRQ;
|
||||
}
|
||||
|
@ -1367,28 +1346,18 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
request_irq_fail:
|
||||
mmc_remove_host(mmc);
|
||||
mmc_add_host_fail:
|
||||
mmc_davinci_cpufreq_deregister(host);
|
||||
cpu_freq_fail:
|
||||
if (host) {
|
||||
davinci_release_dma_channels(host);
|
||||
|
||||
if (host->clk) {
|
||||
clk_disable(host->clk);
|
||||
clk_put(host->clk);
|
||||
}
|
||||
|
||||
if (host->base)
|
||||
iounmap(host->base);
|
||||
}
|
||||
|
||||
if (mmc)
|
||||
mmc_free_host(mmc);
|
||||
|
||||
if (mem)
|
||||
release_resource(mem);
|
||||
|
||||
dev_dbg(&pdev->dev, "probe err %d\n", ret);
|
||||
davinci_release_dma_channels(host);
|
||||
dma_probe_defer:
|
||||
clk_disable_unprepare(host->clk);
|
||||
clk_prepare_enable_fail:
|
||||
clk_get_fail:
|
||||
ioremap_fail:
|
||||
mmc_free_host(mmc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1397,25 +1366,11 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
|
||||
|
||||
if (host) {
|
||||
mmc_davinci_cpufreq_deregister(host);
|
||||
|
||||
mmc_remove_host(host->mmc);
|
||||
free_irq(host->mmc_irq, host);
|
||||
if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
|
||||
free_irq(host->sdio_irq, host);
|
||||
|
||||
davinci_release_dma_channels(host);
|
||||
|
||||
clk_disable(host->clk);
|
||||
clk_put(host->clk);
|
||||
|
||||
iounmap(host->base);
|
||||
|
||||
release_resource(host->mem_res);
|
||||
|
||||
mmc_free_host(host->mmc);
|
||||
}
|
||||
mmc_remove_host(host->mmc);
|
||||
mmc_davinci_cpufreq_deregister(host);
|
||||
davinci_release_dma_channels(host);
|
||||
clk_disable_unprepare(host->clk);
|
||||
mmc_free_host(host->mmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -91,10 +91,14 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
|
|||
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
|
||||
}
|
||||
|
||||
static int dw_mci_exynos_priv_init(struct dw_mci *host)
|
||||
static void dw_mci_exynos_config_smu(struct dw_mci *host)
|
||||
{
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
|
||||
/*
|
||||
* If Exynos is provided the Security management,
|
||||
* set for non-ecryption mode at this time.
|
||||
*/
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
|
||||
mci_writel(host, MPSBEGIN0, 0);
|
||||
|
@ -104,6 +108,13 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
|
|||
SDMMC_MPSCTRL_VALID |
|
||||
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
static int dw_mci_exynos_priv_init(struct dw_mci *host)
|
||||
{
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
|
||||
dw_mci_exynos_config_smu(host);
|
||||
|
||||
if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
|
||||
priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
|
||||
|
@ -115,13 +126,6 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
|
|||
DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_mci_exynos_setup_clock(struct dw_mci *host)
|
||||
{
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
|
||||
host->bus_hz /= (priv->ciu_div + 1);
|
||||
|
||||
return 0;
|
||||
|
@ -169,7 +173,7 @@ static int dw_mci_exynos_resume(struct device *dev)
|
|||
{
|
||||
struct dw_mci *host = dev_get_drvdata(dev);
|
||||
|
||||
dw_mci_exynos_priv_init(host);
|
||||
dw_mci_exynos_config_smu(host);
|
||||
return dw_mci_resume(host);
|
||||
}
|
||||
|
||||
|
@ -489,7 +493,6 @@ static unsigned long exynos_dwmmc_caps[4] = {
|
|||
static const struct dw_mci_drv_data exynos_drv_data = {
|
||||
.caps = exynos_dwmmc_caps,
|
||||
.init = dw_mci_exynos_priv_init,
|
||||
.setup_clock = dw_mci_exynos_setup_clock,
|
||||
.set_ios = dw_mci_exynos_set_ios,
|
||||
.parse_dt = dw_mci_exynos_parse_dt,
|
||||
.execute_tuning = dw_mci_exynos_execute_tuning,
|
||||
|
|
|
@ -26,13 +26,6 @@ struct dw_mci_rockchip_priv_data {
|
|||
int default_sample_phase;
|
||||
};
|
||||
|
||||
static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
|
||||
{
|
||||
host->bus_hz /= RK3288_CLKGEN_DIV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||
{
|
||||
struct dw_mci_rockchip_priv_data *priv = host->priv;
|
||||
|
@ -231,18 +224,30 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
|
|||
/* It needs this quirk on all Rockchip SoCs */
|
||||
host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO;
|
||||
|
||||
if (of_device_is_compatible(host->dev->of_node,
|
||||
"rockchip,rk3288-dw-mshc"))
|
||||
host->bus_hz /= RK3288_CLKGEN_DIV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common capabilities of RK3288 SoC */
|
||||
static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
|
||||
MMC_CAP_ERASE,
|
||||
MMC_CAP_ERASE,
|
||||
MMC_CAP_ERASE,
|
||||
MMC_CAP_ERASE,
|
||||
};
|
||||
|
||||
static const struct dw_mci_drv_data rk2928_drv_data = {
|
||||
.init = dw_mci_rockchip_init,
|
||||
};
|
||||
|
||||
static const struct dw_mci_drv_data rk3288_drv_data = {
|
||||
.caps = dw_mci_rk3288_dwmmc_caps,
|
||||
.set_ios = dw_mci_rk3288_set_ios,
|
||||
.execute_tuning = dw_mci_rk3288_execute_tuning,
|
||||
.parse_dt = dw_mci_rk3288_parse_dt,
|
||||
.setup_clock = dw_mci_rk3288_setup_clock,
|
||||
.init = dw_mci_rockchip_init,
|
||||
};
|
||||
|
||||
|
@ -269,33 +274,13 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev)
|
|||
return dw_mci_pltfm_register(pdev, drv_data);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dw_mci_rockchip_suspend(struct device *dev)
|
||||
{
|
||||
struct dw_mci *host = dev_get_drvdata(dev);
|
||||
|
||||
return dw_mci_suspend(host);
|
||||
}
|
||||
|
||||
static int dw_mci_rockchip_resume(struct device *dev)
|
||||
{
|
||||
struct dw_mci *host = dev_get_drvdata(dev);
|
||||
|
||||
return dw_mci_resume(host);
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops,
|
||||
dw_mci_rockchip_suspend,
|
||||
dw_mci_rockchip_resume);
|
||||
|
||||
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
|
||||
.probe = dw_mci_rockchip_probe,
|
||||
.remove = dw_mci_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_rockchip",
|
||||
.of_match_table = dw_mci_rockchip_match,
|
||||
.pm = &dw_mci_rockchip_pmops,
|
||||
.pm = &dw_mci_pltfm_pmops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -680,7 +680,7 @@ static const struct dw_mci_dma_ops dw_mci_idmac_ops = {
|
|||
|
||||
static void dw_mci_edmac_stop_dma(struct dw_mci *host)
|
||||
{
|
||||
dmaengine_terminate_all(host->dms->ch);
|
||||
dmaengine_terminate_async(host->dms->ch);
|
||||
}
|
||||
|
||||
static int dw_mci_edmac_start_dma(struct dw_mci *host,
|
||||
|
@ -3003,15 +3003,6 @@ int dw_mci_probe(struct dw_mci *host)
|
|||
}
|
||||
}
|
||||
|
||||
if (drv_data && drv_data->setup_clock) {
|
||||
ret = drv_data->setup_clock(host);
|
||||
if (ret) {
|
||||
dev_err(host->dev,
|
||||
"implementation specific clock setup failed\n");
|
||||
goto err_clk_ciu;
|
||||
}
|
||||
}
|
||||
|
||||
setup_timer(&host->cmd11_timer,
|
||||
dw_mci_cmd11_timer, (unsigned long)host);
|
||||
|
||||
|
|
|
@ -277,7 +277,6 @@ struct dw_mci_slot {
|
|||
* dw_mci driver data - dw-mshc implementation specific driver data.
|
||||
* @caps: mmc subsystem specified capabilities of the controller(s).
|
||||
* @init: early implementation specific initialization.
|
||||
* @setup_clock: implementation specific clock configuration.
|
||||
* @set_ios: handle bus specific extensions.
|
||||
* @parse_dt: parse implementation specific device tree properties.
|
||||
* @execute_tuning: implementation specific tuning procedure.
|
||||
|
@ -289,7 +288,6 @@ struct dw_mci_slot {
|
|||
struct dw_mci_drv_data {
|
||||
unsigned long *caps;
|
||||
int (*init)(struct dw_mci *host);
|
||||
int (*setup_clock)(struct dw_mci *host);
|
||||
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
|
||||
int (*parse_dt)(struct dw_mci *host);
|
||||
int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);
|
||||
|
|
|
@ -226,16 +226,11 @@ static int mmci_card_busy(struct mmc_host *mmc)
|
|||
unsigned long flags;
|
||||
int busy = 0;
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
|
||||
busy = 1;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
|
||||
return busy;
|
||||
}
|
||||
|
||||
|
@ -381,9 +376,6 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
|
|||
host->cmd = NULL;
|
||||
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(host->mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(host->mmc));
|
||||
}
|
||||
|
||||
static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
|
||||
|
@ -1290,8 +1282,6 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
return;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
host->mrq = mrq;
|
||||
|
@ -1318,8 +1308,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
if (host->plat->ios_handler &&
|
||||
host->plat->ios_handler(mmc_dev(mmc), ios))
|
||||
dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
|
||||
|
@ -1414,9 +1402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
mmci_reg_delay(host);
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
}
|
||||
|
||||
static int mmci_get_cd(struct mmc_host *mmc)
|
||||
|
@ -1440,8 +1425,6 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
|
||||
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
switch (ios->signal_voltage) {
|
||||
case MMC_SIGNAL_VOLTAGE_330:
|
||||
ret = regulator_set_voltage(mmc->supply.vqmmc,
|
||||
|
@ -1459,9 +1442,6 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
|
||||
if (ret)
|
||||
dev_warn(mmc_dev(mmc), "Voltage switch failed\n");
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -736,9 +736,6 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
|
|||
if (mrq->data)
|
||||
msdc_unprepare_data(host, mrq);
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
}
|
||||
|
||||
/* returns true if command is fully handled; returns false otherwise */
|
||||
|
@ -886,8 +883,6 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
WARN_ON(host->mrq);
|
||||
host->mrq = mrq;
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
|
||||
if (mrq->data)
|
||||
msdc_prepare_data(host, mrq);
|
||||
|
||||
|
@ -1201,8 +1196,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
struct msdc_host *host = mmc_priv(mmc);
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
|
||||
msdc_set_buswidth(host, ios->bus_width);
|
||||
|
||||
/* Suspend/Resume will do power off/on */
|
||||
|
@ -1214,7 +1207,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
ios->vdd);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Failed to set vmmc power!\n");
|
||||
goto end;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1242,10 +1235,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
|
||||
if (host->mclk != ios->clock || host->timing != ios->timing)
|
||||
msdc_set_mclk(host, ios->timing, ios->clock);
|
||||
|
||||
end:
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
}
|
||||
|
||||
static u32 test_delay_bit(u32 delay, u32 bit)
|
||||
|
@ -1408,19 +1397,15 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
struct msdc_host *host = mmc_priv(mmc);
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
ret = msdc_tune_response(mmc, opcode);
|
||||
if (ret == -EIO) {
|
||||
dev_err(host->dev, "Tune response fail!\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
ret = msdc_tune_data(mmc, opcode);
|
||||
if (ret == -EIO)
|
||||
dev_err(host->dev, "Tune data fail!\n");
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/omap-dma.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
|
@ -1321,8 +1320,6 @@ static int mmc_omap_probe(struct platform_device *pdev)
|
|||
struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct mmc_omap_host *host = NULL;
|
||||
struct resource *res;
|
||||
dma_cap_mask_t mask;
|
||||
unsigned sig = 0;
|
||||
int i, ret = 0;
|
||||
int irq;
|
||||
|
||||
|
@ -1382,29 +1379,34 @@ static int mmc_omap_probe(struct platform_device *pdev)
|
|||
goto err_free_iclk;
|
||||
}
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
host->dma_tx_burst = -1;
|
||||
host->dma_rx_burst = -1;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
|
||||
if (res)
|
||||
sig = res->start;
|
||||
host->dma_tx = dma_request_slave_channel_compat(mask,
|
||||
omap_dma_filter_fn, &sig, &pdev->dev, "tx");
|
||||
if (!host->dma_tx)
|
||||
dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n",
|
||||
sig);
|
||||
host->dma_tx = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(host->dma_tx)) {
|
||||
ret = PTR_ERR(host->dma_tx);
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
clk_put(host->fclk);
|
||||
goto err_free_iclk;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
|
||||
if (res)
|
||||
sig = res->start;
|
||||
host->dma_rx = dma_request_slave_channel_compat(mask,
|
||||
omap_dma_filter_fn, &sig, &pdev->dev, "rx");
|
||||
if (!host->dma_rx)
|
||||
dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n",
|
||||
sig);
|
||||
host->dma_tx = NULL;
|
||||
dev_warn(host->dev, "TX DMA channel request failed\n");
|
||||
}
|
||||
|
||||
host->dma_rx = dma_request_chan(&pdev->dev, "rx");
|
||||
if (IS_ERR(host->dma_rx)) {
|
||||
ret = PTR_ERR(host->dma_rx);
|
||||
if (ret == -EPROBE_DEFER) {
|
||||
if (host->dma_tx)
|
||||
dma_release_channel(host->dma_tx);
|
||||
clk_put(host->fclk);
|
||||
goto err_free_iclk;
|
||||
}
|
||||
|
||||
host->dma_rx = NULL;
|
||||
dev_warn(host->dev, "RX DMA channel request failed\n");
|
||||
}
|
||||
|
||||
ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
|
||||
if (ret)
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/omap-dmaengine.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/core.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
|
@ -351,15 +350,14 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
|
||||
static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
|
||||
int vdd)
|
||||
{
|
||||
struct omap_hsmmc_host *host =
|
||||
platform_get_drvdata(to_platform_device(dev));
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int ret = 0;
|
||||
|
||||
if (mmc_pdata(host)->set_power)
|
||||
return mmc_pdata(host)->set_power(dev, power_on, vdd);
|
||||
return mmc_pdata(host)->set_power(host->dev, power_on, vdd);
|
||||
|
||||
/*
|
||||
* If we don't see a Vcc regulator, assume it's a fixed
|
||||
|
@ -369,7 +367,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
|
|||
return 0;
|
||||
|
||||
if (mmc_pdata(host)->before_set_reg)
|
||||
mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
|
||||
mmc_pdata(host)->before_set_reg(host->dev, power_on, vdd);
|
||||
|
||||
ret = omap_hsmmc_set_pbias(host, false, 0);
|
||||
if (ret)
|
||||
|
@ -403,7 +401,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
|
|||
}
|
||||
|
||||
if (mmc_pdata(host)->after_set_reg)
|
||||
mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
|
||||
mmc_pdata(host)->after_set_reg(host->dev, power_on, vdd);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -968,8 +966,6 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
|
|||
return;
|
||||
host->mrq = NULL;
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1250,17 +1246,15 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
|
|||
int ret;
|
||||
|
||||
/* Disable the clocks */
|
||||
pm_runtime_put_sync(host->dev);
|
||||
if (host->dbclk)
|
||||
clk_disable_unprepare(host->dbclk);
|
||||
|
||||
/* Turn the power off */
|
||||
ret = omap_hsmmc_set_power(host->dev, 0, 0);
|
||||
ret = omap_hsmmc_set_power(host, 0, 0);
|
||||
|
||||
/* Turn the power ON with given VDD 1.8 or 3.0v */
|
||||
if (!ret)
|
||||
ret = omap_hsmmc_set_power(host->dev, 1, vdd);
|
||||
pm_runtime_get_sync(host->dev);
|
||||
ret = omap_hsmmc_set_power(host, 1, vdd);
|
||||
if (host->dbclk)
|
||||
clk_prepare_enable(host->dbclk);
|
||||
|
||||
|
@ -1368,8 +1362,6 @@ static void omap_hsmmc_dma_callback(void *param)
|
|||
|
||||
host->mrq = NULL;
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1602,7 +1594,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
|
||||
BUG_ON(host->req_in_progress);
|
||||
BUG_ON(host->dma_ch != -1);
|
||||
pm_runtime_get_sync(host->dev);
|
||||
if (host->protect_card) {
|
||||
if (host->reqs_blocked < 3) {
|
||||
/*
|
||||
|
@ -1619,8 +1610,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
req->data->error = -EBADF;
|
||||
req->cmd->retries = 0;
|
||||
mmc_request_done(mmc, req);
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
return;
|
||||
} else if (host->reqs_blocked)
|
||||
host->reqs_blocked = 0;
|
||||
|
@ -1634,8 +1623,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
req->data->error = err;
|
||||
host->mrq = NULL;
|
||||
mmc_request_done(mmc, req);
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
return;
|
||||
}
|
||||
if (req->sbc && !(host->flags & AUTO_CMD23)) {
|
||||
|
@ -1653,15 +1640,13 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
struct omap_hsmmc_host *host = mmc_priv(mmc);
|
||||
int do_send_init_stream = 0;
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
|
||||
if (ios->power_mode != host->power_mode) {
|
||||
switch (ios->power_mode) {
|
||||
case MMC_POWER_OFF:
|
||||
omap_hsmmc_set_power(host->dev, 0, 0);
|
||||
omap_hsmmc_set_power(host, 0, 0);
|
||||
break;
|
||||
case MMC_POWER_UP:
|
||||
omap_hsmmc_set_power(host->dev, 1, ios->vdd);
|
||||
omap_hsmmc_set_power(host, 1, ios->vdd);
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
do_send_init_stream = 1;
|
||||
|
@ -1698,8 +1683,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
send_init_stream(host);
|
||||
|
||||
omap_hsmmc_set_bus_mode(host);
|
||||
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
}
|
||||
|
||||
static int omap_hsmmc_get_cd(struct mmc_host *mmc)
|
||||
|
@ -1962,13 +1945,17 @@ MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
|
|||
|
||||
static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
|
||||
{
|
||||
struct omap_hsmmc_platform_data *pdata;
|
||||
struct omap_hsmmc_platform_data *pdata, *legacy;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM); /* out of memory */
|
||||
|
||||
legacy = dev_get_platdata(dev);
|
||||
if (legacy && legacy->name)
|
||||
pdata->name = legacy->name;
|
||||
|
||||
if (of_find_property(np, "ti,dual-volt", NULL))
|
||||
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
|
||||
|
||||
|
@ -2005,8 +1992,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int ret, irq;
|
||||
const struct of_device_id *match;
|
||||
dma_cap_mask_t mask;
|
||||
unsigned tx_req, rx_req;
|
||||
const struct omap_mmc_of_data *data;
|
||||
void __iomem *base;
|
||||
|
||||
|
@ -2136,44 +2121,17 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
|||
|
||||
omap_hsmmc_conf_bus_power(host);
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
|
||||
if (!res) {
|
||||
dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
|
||||
ret = -ENXIO;
|
||||
goto err_irq;
|
||||
}
|
||||
tx_req = res->start;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
|
||||
if (!res) {
|
||||
dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
|
||||
ret = -ENXIO;
|
||||
goto err_irq;
|
||||
}
|
||||
rx_req = res->start;
|
||||
}
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
host->rx_chan =
|
||||
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
|
||||
&rx_req, &pdev->dev, "rx");
|
||||
|
||||
if (!host->rx_chan) {
|
||||
dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n");
|
||||
ret = -ENXIO;
|
||||
host->rx_chan = dma_request_chan(&pdev->dev, "rx");
|
||||
if (IS_ERR(host->rx_chan)) {
|
||||
dev_err(mmc_dev(host->mmc), "RX DMA channel request failed\n");
|
||||
ret = PTR_ERR(host->rx_chan);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
host->tx_chan =
|
||||
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
|
||||
&tx_req, &pdev->dev, "tx");
|
||||
|
||||
if (!host->tx_chan) {
|
||||
dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n");
|
||||
ret = -ENXIO;
|
||||
host->tx_chan = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(host->tx_chan)) {
|
||||
dev_err(mmc_dev(host->mmc), "TX DMA channel request failed\n");
|
||||
ret = PTR_ERR(host->tx_chan);
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
|
@ -2231,9 +2189,9 @@ err_slot_name:
|
|||
mmc_remove_host(mmc);
|
||||
err_irq:
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
if (host->tx_chan)
|
||||
if (!IS_ERR_OR_NULL(host->tx_chan))
|
||||
dma_release_channel(host->tx_chan);
|
||||
if (host->rx_chan)
|
||||
if (!IS_ERR_OR_NULL(host->rx_chan))
|
||||
dma_release_channel(host->rx_chan);
|
||||
pm_runtime_dont_use_autosuspend(host->dev);
|
||||
pm_runtime_put_sync(host->dev);
|
||||
|
|
|
@ -200,8 +200,6 @@ static int bxt_get_cd(struct mmc_host *mmc)
|
|||
if (!gpio_cd)
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(mmc->parent);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
if (host->flags & SDHCI_DEVICE_DEAD)
|
||||
|
@ -211,9 +209,6 @@ static int bxt_get_cd(struct mmc_host *mmc)
|
|||
out:
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc->parent);
|
||||
pm_runtime_put_autosuspend(mmc->parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -267,8 +262,10 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
|
|||
|
||||
/* Platform specific code during sd probe slot goes here */
|
||||
|
||||
if (hid && !strcmp(hid, "80865ACA"))
|
||||
if (hid && !strcmp(hid, "80865ACA")) {
|
||||
host->mmc_host_ops.get_cd = bxt_get_cd;
|
||||
host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -55,8 +55,32 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
|
|||
return freq;
|
||||
}
|
||||
|
||||
static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
|
||||
bool ctrl_phy = false;
|
||||
|
||||
if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
|
||||
ctrl_phy = true;
|
||||
|
||||
if (ctrl_phy) {
|
||||
spin_unlock_irq(&host->lock);
|
||||
phy_power_off(sdhci_arasan->phy);
|
||||
spin_lock_irq(&host->lock);
|
||||
}
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
|
||||
if (ctrl_phy) {
|
||||
spin_unlock_irq(&host->lock);
|
||||
phy_power_on(sdhci_arasan->phy);
|
||||
spin_lock_irq(&host->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_arasan_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_arasan_set_clock,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
.get_timeout_clock = sdhci_arasan_get_timeout_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -31,14 +33,60 @@
|
|||
#define SDMMC_CACR_CAPWREN BIT(0)
|
||||
#define SDMMC_CACR_KEY (0x46 << 8)
|
||||
|
||||
#define SDHCI_AT91_PRESET_COMMON_CONF 0x400 /* drv type B, programmable clock mode */
|
||||
|
||||
struct sdhci_at91_priv {
|
||||
struct clk *hclock;
|
||||
struct clk *gck;
|
||||
struct clk *mainck;
|
||||
};
|
||||
|
||||
static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
u16 clk;
|
||||
unsigned long timeout;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
/*
|
||||
* There is no requirement to disable the internal clock before
|
||||
* changing the SD clock configuration. Moreover, disabling the
|
||||
* internal clock, changing the configuration and re-enabling the
|
||||
* internal clock causes some bugs. It can prevent to get the internal
|
||||
* clock stable flag ready and an unexpected switch to the base clock
|
||||
* when using presets.
|
||||
*/
|
||||
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
clk &= SDHCI_CLOCK_INT_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
|
||||
|
||||
clk |= SDHCI_CLOCK_INT_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
/* Wait max 20 ms */
|
||||
timeout = 20;
|
||||
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
|
||||
& SDHCI_CLOCK_INT_STABLE)) {
|
||||
if (timeout == 0) {
|
||||
pr_err("%s: Internal clock never stabilised.\n",
|
||||
mmc_hostname(host->mmc));
|
||||
return;
|
||||
}
|
||||
timeout--;
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
clk |= SDHCI_CLOCK_CARD_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_at91_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
|
@ -46,7 +94,6 @@ static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
|
|||
|
||||
static const struct sdhci_pltfm_data soc_data_sama5d2 = {
|
||||
.ops = &sdhci_at91_sama5d2_ops,
|
||||
.quirks2 = SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST,
|
||||
};
|
||||
|
||||
static const struct of_device_id sdhci_at91_dt_match[] = {
|
||||
|
@ -119,6 +166,7 @@ static int sdhci_at91_probe(struct platform_device *pdev)
|
|||
unsigned int clk_base, clk_mul;
|
||||
unsigned int gck_rate, real_gck_rate;
|
||||
int ret;
|
||||
unsigned int preset_div;
|
||||
|
||||
match = of_match_device(sdhci_at91_dt_match, &pdev->dev);
|
||||
if (!match)
|
||||
|
@ -186,6 +234,28 @@ static int sdhci_at91_probe(struct platform_device *pdev)
|
|||
clk_mul, real_gck_rate);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to set preset values because it depends on the clk_mul
|
||||
* value. Moreover, SDR104 is supported in a degraded mode since the
|
||||
* maximum sd clock value is 120 MHz instead of 208 MHz. For that
|
||||
* reason, we need to use presets to support SDR104.
|
||||
*/
|
||||
preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1;
|
||||
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
|
||||
host->ioaddr + SDHCI_PRESET_FOR_SDR12);
|
||||
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
|
||||
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
|
||||
host->ioaddr + SDHCI_PRESET_FOR_SDR25);
|
||||
preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1;
|
||||
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
|
||||
host->ioaddr + SDHCI_PRESET_FOR_SDR50);
|
||||
preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1;
|
||||
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
|
||||
host->ioaddr + SDHCI_PRESET_FOR_SDR104);
|
||||
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
|
||||
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
|
||||
host->ioaddr + SDHCI_PRESET_FOR_DDR50);
|
||||
|
||||
clk_prepare_enable(priv->mainck);
|
||||
clk_prepare_enable(priv->gck);
|
||||
|
||||
|
|
|
@ -340,8 +340,6 @@ static int bxt_get_cd(struct mmc_host *mmc)
|
|||
if (!gpio_cd)
|
||||
return 0;
|
||||
|
||||
pm_runtime_get_sync(mmc->parent);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
if (host->flags & SDHCI_DEVICE_DEAD)
|
||||
|
@ -351,9 +349,6 @@ static int bxt_get_cd(struct mmc_host *mmc)
|
|||
out:
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc->parent);
|
||||
pm_runtime_put_autosuspend(mmc->parent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -391,8 +386,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
|
|||
slot->cd_override_level = true;
|
||||
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
|
||||
slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD ||
|
||||
slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD)
|
||||
slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD) {
|
||||
slot->host->mmc_host_ops.get_cd = bxt_get_cd;
|
||||
slot->host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -243,7 +243,6 @@ MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table);
|
|||
static struct platform_driver pic32_sdhci_driver = {
|
||||
.driver = {
|
||||
.name = "pic32-sdhci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(pic32_sdhci_id_table),
|
||||
},
|
||||
.probe = pic32_sdhci_probe,
|
||||
|
|
|
@ -119,16 +119,22 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
|||
{
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
int ret;
|
||||
void __iomem *ioaddr;
|
||||
int irq, ret;
|
||||
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iomem) {
|
||||
ret = -ENOMEM;
|
||||
ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
|
||||
if (IS_ERR(ioaddr)) {
|
||||
ret = PTR_ERR(ioaddr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (resource_size(iomem) < 0x100)
|
||||
dev_err(&pdev->dev, "Invalid iomem size!\n");
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get IRQ number\n");
|
||||
ret = irq;
|
||||
goto err;
|
||||
}
|
||||
|
||||
host = sdhci_alloc_host(&pdev->dev,
|
||||
sizeof(struct sdhci_pltfm_host) + priv_size);
|
||||
|
@ -138,6 +144,8 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
|||
goto err;
|
||||
}
|
||||
|
||||
host->ioaddr = ioaddr;
|
||||
host->irq = irq;
|
||||
host->hw_name = dev_name(&pdev->dev);
|
||||
if (pdata && pdata->ops)
|
||||
host->ops = pdata->ops;
|
||||
|
@ -148,22 +156,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
|||
host->quirks2 = pdata->quirks2;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!request_mem_region(iomem->start, resource_size(iomem),
|
||||
mmc_hostname(host->mmc))) {
|
||||
dev_err(&pdev->dev, "cannot request region\n");
|
||||
ret = -EBUSY;
|
||||
goto err_request;
|
||||
}
|
||||
|
||||
host->ioaddr = ioremap(iomem->start, resource_size(iomem));
|
||||
if (!host->ioaddr) {
|
||||
dev_err(&pdev->dev, "failed to remap registers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_remap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some platforms need to probe the controller to be able to
|
||||
* determine which caps should be used.
|
||||
|
@ -174,11 +166,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
|||
platform_set_drvdata(pdev, host);
|
||||
|
||||
return host;
|
||||
|
||||
err_remap:
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
err_request:
|
||||
sdhci_free_host(host);
|
||||
err:
|
||||
dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
|
||||
return ERR_PTR(ret);
|
||||
|
@ -188,10 +175,7 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_init);
|
|||
void sdhci_pltfm_free(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
iounmap(host->ioaddr);
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
sdhci_free_host(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
#define DBG(f, x...) \
|
||||
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
|
||||
|
||||
#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
|
||||
defined(CONFIG_MMC_SDHCI_MODULE))
|
||||
#define SDHCI_USE_LEDS_CLASS
|
||||
#endif
|
||||
|
||||
#define MAX_TUNING_LOOP 40
|
||||
|
||||
static unsigned int debug_quirks = 0;
|
||||
|
@ -53,29 +48,7 @@ static void sdhci_finish_data(struct sdhci_host *);
|
|||
static void sdhci_finish_command(struct sdhci_host *);
|
||||
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
|
||||
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
|
||||
static int sdhci_do_get_cd(struct sdhci_host *host);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_runtime_pm_get(struct sdhci_host *host);
|
||||
static int sdhci_runtime_pm_put(struct sdhci_host *host);
|
||||
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
|
||||
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
|
||||
#else
|
||||
static inline int sdhci_runtime_pm_get(struct sdhci_host *host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
|
||||
{
|
||||
}
|
||||
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
static int sdhci_get_cd(struct mmc_host *mmc);
|
||||
|
||||
static void sdhci_dumpregs(struct sdhci_host *host)
|
||||
{
|
||||
|
@ -171,6 +144,22 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
|
|||
sdhci_set_card_detection(host, false);
|
||||
}
|
||||
|
||||
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
|
||||
{
|
||||
if (host->bus_on)
|
||||
return;
|
||||
host->bus_on = true;
|
||||
pm_runtime_get_noresume(host->mmc->parent);
|
||||
}
|
||||
|
||||
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
|
||||
{
|
||||
if (!host->bus_on)
|
||||
return;
|
||||
host->bus_on = false;
|
||||
pm_runtime_put_noidle(host->mmc->parent);
|
||||
}
|
||||
|
||||
void sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
@ -204,7 +193,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
|
|||
static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
||||
if (!sdhci_do_get_cd(host))
|
||||
if (!sdhci_get_cd(host->mmc))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -252,7 +241,7 @@ static void sdhci_reinit(struct sdhci_host *host)
|
|||
sdhci_enable_card_detection(host);
|
||||
}
|
||||
|
||||
static void sdhci_activate_led(struct sdhci_host *host)
|
||||
static void __sdhci_led_activate(struct sdhci_host *host)
|
||||
{
|
||||
u8 ctrl;
|
||||
|
||||
|
@ -261,7 +250,7 @@ static void sdhci_activate_led(struct sdhci_host *host)
|
|||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
}
|
||||
|
||||
static void sdhci_deactivate_led(struct sdhci_host *host)
|
||||
static void __sdhci_led_deactivate(struct sdhci_host *host)
|
||||
{
|
||||
u8 ctrl;
|
||||
|
||||
|
@ -270,9 +259,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
|
|||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
}
|
||||
|
||||
#ifdef SDHCI_USE_LEDS_CLASS
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
|
||||
static void sdhci_led_control(struct led_classdev *led,
|
||||
enum led_brightness brightness)
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct sdhci_host *host = container_of(led, struct sdhci_host, led);
|
||||
unsigned long flags;
|
||||
|
@ -283,12 +272,62 @@ static void sdhci_led_control(struct led_classdev *led,
|
|||
goto out;
|
||||
|
||||
if (brightness == LED_OFF)
|
||||
sdhci_deactivate_led(host);
|
||||
__sdhci_led_deactivate(host);
|
||||
else
|
||||
sdhci_activate_led(host);
|
||||
__sdhci_led_activate(host);
|
||||
out:
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
static int sdhci_led_register(struct sdhci_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
snprintf(host->led_name, sizeof(host->led_name),
|
||||
"%s::", mmc_hostname(mmc));
|
||||
|
||||
host->led.name = host->led_name;
|
||||
host->led.brightness = LED_OFF;
|
||||
host->led.default_trigger = mmc_hostname(mmc);
|
||||
host->led.brightness_set = sdhci_led_control;
|
||||
|
||||
return led_classdev_register(mmc_dev(mmc), &host->led);
|
||||
}
|
||||
|
||||
static void sdhci_led_unregister(struct sdhci_host *host)
|
||||
{
|
||||
led_classdev_unregister(&host->led);
|
||||
}
|
||||
|
||||
static inline void sdhci_led_activate(struct sdhci_host *host)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void sdhci_led_deactivate(struct sdhci_host *host)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int sdhci_led_register(struct sdhci_host *host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void sdhci_led_unregister(struct sdhci_host *host)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void sdhci_led_activate(struct sdhci_host *host)
|
||||
{
|
||||
__sdhci_led_activate(host);
|
||||
}
|
||||
|
||||
static inline void sdhci_led_deactivate(struct sdhci_host *host)
|
||||
{
|
||||
__sdhci_led_deactivate(host);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************\
|
||||
|
@ -1091,23 +1130,14 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
|
|||
return preset;
|
||||
}
|
||||
|
||||
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
|
||||
unsigned int *actual_clock)
|
||||
{
|
||||
int div = 0; /* Initialized for compiler warning */
|
||||
int real_div = div, clk_mul = 1;
|
||||
u16 clk = 0;
|
||||
unsigned long timeout;
|
||||
bool switch_base_clk = false;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST)
|
||||
mdelay(1);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
if (host->version >= SDHCI_SPEC_300) {
|
||||
if (host->preset_enabled) {
|
||||
u16 pre_val;
|
||||
|
@ -1184,10 +1214,29 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||
|
||||
clock_set:
|
||||
if (real_div)
|
||||
host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
|
||||
*actual_clock = (host->max_clk * clk_mul) / real_div;
|
||||
clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
|
||||
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
|
||||
<< SDHCI_DIVIDER_HI_SHIFT;
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_calc_clk);
|
||||
|
||||
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
u16 clk;
|
||||
unsigned long timeout;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
|
||||
|
||||
clk |= SDHCI_CLOCK_INT_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
|
@ -1319,8 +1368,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
|
||||
host = mmc_priv(mmc);
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
|
||||
/* Firstly check card presence */
|
||||
present = mmc->ops->get_cd(mmc);
|
||||
|
||||
|
@ -1328,9 +1375,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
|
||||
WARN_ON(host->mrq != NULL);
|
||||
|
||||
#ifndef SDHCI_USE_LEDS_CLASS
|
||||
sdhci_activate_led(host);
|
||||
#endif
|
||||
sdhci_led_activate(host);
|
||||
|
||||
/*
|
||||
* Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
|
||||
|
@ -1405,11 +1450,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
|
||||
|
||||
static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
|
||||
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
unsigned long flags;
|
||||
u8 ctrl;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
|
@ -1563,18 +1608,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
|
|||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
static int sdhci_get_cd(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
sdhci_do_set_ios(host, ios);
|
||||
sdhci_runtime_pm_put(host);
|
||||
}
|
||||
|
||||
static int sdhci_do_get_cd(struct sdhci_host *host)
|
||||
{
|
||||
int gpio_cd = mmc_gpio_get_cd(host->mmc);
|
||||
int gpio_cd = mmc_gpio_get_cd(mmc);
|
||||
|
||||
if (host->flags & SDHCI_DEVICE_DEAD)
|
||||
return 0;
|
||||
|
@ -1598,17 +1635,6 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
|
|||
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
|
||||
}
|
||||
|
||||
static int sdhci_get_cd(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int ret;
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
ret = sdhci_do_get_cd(host);
|
||||
sdhci_runtime_pm_put(host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_check_ro(struct sdhci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -1633,8 +1659,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
|
|||
|
||||
#define SAMPLE_COUNT 5
|
||||
|
||||
static int sdhci_do_get_ro(struct sdhci_host *host)
|
||||
static int sdhci_get_ro(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int i, ro_count;
|
||||
|
||||
if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
|
||||
|
@ -1659,17 +1686,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
|
|||
host->ops->hw_reset(host);
|
||||
}
|
||||
|
||||
static int sdhci_get_ro(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int ret;
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
ret = sdhci_do_get_ro(host);
|
||||
sdhci_runtime_pm_put(host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
|
||||
{
|
||||
if (!(host->flags & SDHCI_DEVICE_DEAD)) {
|
||||
|
@ -1689,8 +1705,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
|||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
unsigned long flags;
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
if (enable)
|
||||
host->flags |= SDHCI_SDIO_IRQ_ENABLED;
|
||||
|
@ -1699,14 +1713,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
|||
|
||||
sdhci_enable_sdio_irq_nolock(host, enable);
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
sdhci_runtime_pm_put(host);
|
||||
}
|
||||
|
||||
static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
|
||||
struct mmc_ios *ios)
|
||||
static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u16 ctrl;
|
||||
int ret;
|
||||
|
||||
|
@ -1794,29 +1806,13 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
|
|||
}
|
||||
}
|
||||
|
||||
static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int err;
|
||||
|
||||
if (host->version < SDHCI_SPEC_300)
|
||||
return 0;
|
||||
sdhci_runtime_pm_get(host);
|
||||
err = sdhci_do_start_signal_voltage_switch(host, ios);
|
||||
sdhci_runtime_pm_put(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sdhci_card_busy(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u32 present_state;
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
/* Check whether DAT[3:0] is 0000 */
|
||||
present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
||||
sdhci_runtime_pm_put(host);
|
||||
|
||||
return !(present_state & SDHCI_DATA_LVL_MASK);
|
||||
}
|
||||
|
@ -1843,7 +1839,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
unsigned int tuning_count = 0;
|
||||
bool hs400_tuning;
|
||||
|
||||
sdhci_runtime_pm_get(host);
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
hs400_tuning = host->flags & SDHCI_HS400_TUNING;
|
||||
|
@ -1879,8 +1874,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
break;
|
||||
|
||||
case MMC_TIMING_UHS_SDR50:
|
||||
if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
|
||||
host->flags & SDHCI_SDR104_NEEDS_TUNING)
|
||||
if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
|
@ -1891,7 +1885,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
if (host->ops->platform_execute_tuning) {
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
err = host->ops->platform_execute_tuning(host, opcode);
|
||||
sdhci_runtime_pm_put(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2023,8 +2016,6 @@ out:
|
|||
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
sdhci_runtime_pm_put(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2105,7 +2096,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
|
|||
if (host->ops->card_event)
|
||||
host->ops->card_event(host);
|
||||
|
||||
present = sdhci_do_get_cd(host);
|
||||
present = sdhci_get_cd(host->mmc);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
|
@ -2214,15 +2205,12 @@ static void sdhci_tasklet_finish(unsigned long param)
|
|||
host->cmd = NULL;
|
||||
host->data = NULL;
|
||||
|
||||
#ifndef SDHCI_USE_LEDS_CLASS
|
||||
sdhci_deactivate_led(host);
|
||||
#endif
|
||||
sdhci_led_deactivate(host);
|
||||
|
||||
mmiowb();
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
sdhci_runtime_pm_put(host);
|
||||
}
|
||||
|
||||
static void sdhci_timeout_timer(unsigned long data)
|
||||
|
@ -2679,7 +2667,7 @@ int sdhci_resume_host(struct sdhci_host *host)
|
|||
sdhci_init(host, 0);
|
||||
host->pwr = 0;
|
||||
host->clock = 0;
|
||||
sdhci_do_set_ios(host, &host->mmc->ios);
|
||||
sdhci_set_ios(host->mmc, &host->mmc->ios);
|
||||
} else {
|
||||
sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
|
||||
mmiowb();
|
||||
|
@ -2703,33 +2691,6 @@ int sdhci_resume_host(struct sdhci_host *host)
|
|||
|
||||
EXPORT_SYMBOL_GPL(sdhci_resume_host);
|
||||
|
||||
static int sdhci_runtime_pm_get(struct sdhci_host *host)
|
||||
{
|
||||
return pm_runtime_get_sync(host->mmc->parent);
|
||||
}
|
||||
|
||||
static int sdhci_runtime_pm_put(struct sdhci_host *host)
|
||||
{
|
||||
pm_runtime_mark_last_busy(host->mmc->parent);
|
||||
return pm_runtime_put_autosuspend(host->mmc->parent);
|
||||
}
|
||||
|
||||
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
|
||||
{
|
||||
if (host->bus_on)
|
||||
return;
|
||||
host->bus_on = true;
|
||||
pm_runtime_get_noresume(host->mmc->parent);
|
||||
}
|
||||
|
||||
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
|
||||
{
|
||||
if (!host->bus_on)
|
||||
return;
|
||||
host->bus_on = false;
|
||||
pm_runtime_put_noidle(host->mmc->parent);
|
||||
}
|
||||
|
||||
int sdhci_runtime_suspend_host(struct sdhci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -2768,8 +2729,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
|
|||
/* Force clock and power re-program */
|
||||
host->pwr = 0;
|
||||
host->clock = 0;
|
||||
sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
|
||||
sdhci_do_set_ios(host, &host->mmc->ios);
|
||||
sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios);
|
||||
sdhci_set_ios(host->mmc, &host->mmc->ios);
|
||||
|
||||
if ((host_flags & SDHCI_PV_ENABLED) &&
|
||||
!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
|
||||
|
@ -3014,7 +2975,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
if (!host->ops->get_max_clock) {
|
||||
pr_err("%s: Hardware doesn't specify base clock frequency.\n",
|
||||
mmc_hostname(mmc));
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto undma;
|
||||
}
|
||||
host->max_clk = host->ops->get_max_clock(host);
|
||||
}
|
||||
|
@ -3051,7 +3013,7 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
} else
|
||||
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
|
||||
|
||||
if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk)))
|
||||
if (!mmc->f_max || mmc->f_max > max_clk)
|
||||
mmc->f_max = max_clk;
|
||||
|
||||
if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
|
||||
|
@ -3064,7 +3026,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
} else {
|
||||
pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
|
||||
mmc_hostname(mmc));
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto undma;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3118,8 +3081,9 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
/* If there are external regulators, get them */
|
||||
if (mmc_regulator_get_supply(mmc) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto undma;
|
||||
|
||||
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
|
||||
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||
|
@ -3174,10 +3138,6 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
if (caps[1] & SDHCI_USE_SDR50_TUNING)
|
||||
host->flags |= SDHCI_SDR50_NEEDS_TUNING;
|
||||
|
||||
/* Does the host need tuning for SDR104 / HS200? */
|
||||
if (mmc->caps2 & MMC_CAP2_HS200)
|
||||
host->flags |= SDHCI_SDR104_NEEDS_TUNING;
|
||||
|
||||
/* Driver Type(s) (A, C, D) supported by the host */
|
||||
if (caps[1] & SDHCI_DRIVER_TYPE_A)
|
||||
mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
|
||||
|
@ -3276,7 +3236,8 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
if (mmc->ocr_avail == 0) {
|
||||
pr_err("%s: Hardware doesn't report any support voltages.\n",
|
||||
mmc_hostname(mmc));
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto unreg;
|
||||
}
|
||||
|
||||
spin_lock_init(&host->lock);
|
||||
|
@ -3360,25 +3321,18 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
sdhci_dumpregs(host);
|
||||
#endif
|
||||
|
||||
#ifdef SDHCI_USE_LEDS_CLASS
|
||||
snprintf(host->led_name, sizeof(host->led_name),
|
||||
"%s::", mmc_hostname(mmc));
|
||||
host->led.name = host->led_name;
|
||||
host->led.brightness = LED_OFF;
|
||||
host->led.default_trigger = mmc_hostname(mmc);
|
||||
host->led.brightness_set = sdhci_led_control;
|
||||
|
||||
ret = led_classdev_register(mmc_dev(mmc), &host->led);
|
||||
ret = sdhci_led_register(host);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to register LED device: %d\n",
|
||||
mmc_hostname(mmc), ret);
|
||||
goto reset;
|
||||
goto unirq;
|
||||
}
|
||||
#endif
|
||||
|
||||
mmiowb();
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto unled;
|
||||
|
||||
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
|
||||
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
|
||||
|
@ -3390,15 +3344,25 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
|
||||
return 0;
|
||||
|
||||
#ifdef SDHCI_USE_LEDS_CLASS
|
||||
reset:
|
||||
unled:
|
||||
sdhci_led_unregister(host);
|
||||
unirq:
|
||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
||||
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
|
||||
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
|
||||
free_irq(host->irq, host);
|
||||
#endif
|
||||
untasklet:
|
||||
tasklet_kill(&host->finish_tasklet);
|
||||
unreg:
|
||||
if (!IS_ERR(mmc->supply.vqmmc))
|
||||
regulator_disable(mmc->supply.vqmmc);
|
||||
undma:
|
||||
if (host->align_buffer)
|
||||
dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
|
||||
host->adma_table_sz, host->align_buffer,
|
||||
host->align_addr);
|
||||
host->adma_table = NULL;
|
||||
host->align_buffer = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -3430,9 +3394,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
|
|||
|
||||
mmc_remove_host(mmc);
|
||||
|
||||
#ifdef SDHCI_USE_LEDS_CLASS
|
||||
led_classdev_unregister(&host->led);
|
||||
#endif
|
||||
sdhci_led_unregister(host);
|
||||
|
||||
if (!dead)
|
||||
sdhci_do_reset(host, SDHCI_RESET_ALL);
|
||||
|
|
|
@ -417,11 +417,6 @@ struct sdhci_host {
|
|||
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
|
||||
/* Broken Clock divider zero in controller */
|
||||
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
|
||||
/*
|
||||
* When internal clock is disabled, a delay is needed before modifying the
|
||||
* SD clock frequency or enabling back the internal clock.
|
||||
*/
|
||||
#define SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST (1<<16)
|
||||
|
||||
int irq; /* Device IRQ */
|
||||
void __iomem *ioaddr; /* Mapped address */
|
||||
|
@ -433,7 +428,7 @@ struct sdhci_host {
|
|||
struct mmc_host_ops mmc_host_ops; /* MMC host ops */
|
||||
u64 dma_mask; /* custom DMA mask */
|
||||
|
||||
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS)
|
||||
struct led_classdev led; /* LED control */
|
||||
char led_name[32];
|
||||
#endif
|
||||
|
@ -450,7 +445,6 @@ struct sdhci_host {
|
|||
#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
|
||||
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
|
||||
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
|
||||
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
|
||||
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
|
||||
#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
|
||||
|
||||
|
@ -661,6 +655,8 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
|
|||
return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
|
||||
}
|
||||
|
||||
u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
|
||||
unsigned int *actual_clock);
|
||||
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
|
||||
void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd);
|
||||
|
|
|
@ -248,7 +248,6 @@ struct sh_mmcif_host {
|
|||
int sg_idx;
|
||||
int sg_blkidx;
|
||||
bool power;
|
||||
bool card_present;
|
||||
bool ccs_enable; /* Command Completion Signal support */
|
||||
bool clk_ctrl2_enable;
|
||||
struct mutex thread_lock;
|
||||
|
@ -1064,16 +1063,6 @@ static void sh_mmcif_clk_setup(struct sh_mmcif_host *host)
|
|||
host->mmc->f_max, host->mmc->f_min);
|
||||
}
|
||||
|
||||
static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
if (!IS_ERR(mmc->supply.vmmc))
|
||||
/* Errors ignored... */
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
|
||||
ios->power_mode ? ios->vdd : 0);
|
||||
}
|
||||
|
||||
static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct sh_mmcif_host *host = mmc_priv(mmc);
|
||||
|
@ -1091,42 +1080,32 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
host->state = STATE_IOS;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
if (ios->power_mode == MMC_POWER_UP) {
|
||||
if (!host->card_present) {
|
||||
/* See if we also get DMA */
|
||||
sh_mmcif_request_dma(host);
|
||||
host->card_present = true;
|
||||
}
|
||||
sh_mmcif_set_power(host, ios);
|
||||
} else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
|
||||
/* clock stop */
|
||||
sh_mmcif_clock_control(host, 0);
|
||||
if (ios->power_mode == MMC_POWER_OFF) {
|
||||
if (host->card_present) {
|
||||
sh_mmcif_release_dma(host);
|
||||
host->card_present = false;
|
||||
}
|
||||
}
|
||||
if (host->power) {
|
||||
pm_runtime_put_sync(dev);
|
||||
clk_disable_unprepare(host->clk);
|
||||
host->power = false;
|
||||
if (ios->power_mode == MMC_POWER_OFF)
|
||||
sh_mmcif_set_power(host, ios);
|
||||
}
|
||||
host->state = STATE_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ios->clock) {
|
||||
switch (ios->power_mode) {
|
||||
case MMC_POWER_UP:
|
||||
if (!IS_ERR(mmc->supply.vmmc))
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
|
||||
if (!host->power) {
|
||||
clk_prepare_enable(host->clk);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
host->power = true;
|
||||
sh_mmcif_sync_reset(host);
|
||||
sh_mmcif_request_dma(host);
|
||||
host->power = true;
|
||||
}
|
||||
break;
|
||||
case MMC_POWER_OFF:
|
||||
if (!IS_ERR(mmc->supply.vmmc))
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
||||
if (host->power) {
|
||||
sh_mmcif_clock_control(host, 0);
|
||||
sh_mmcif_release_dma(host);
|
||||
pm_runtime_put(dev);
|
||||
clk_disable_unprepare(host->clk);
|
||||
host->power = false;
|
||||
}
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
sh_mmcif_clock_control(host, ios->clock);
|
||||
break;
|
||||
}
|
||||
|
||||
host->timing = ios->timing;
|
||||
|
@ -1519,23 +1498,23 @@ static int sh_mmcif_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
host->power = false;
|
||||
|
||||
host->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
ret = PTR_ERR(host->clk);
|
||||
dev_err(dev, "cannot get clock: %d\n", ret);
|
||||
goto err_pm;
|
||||
goto err_host;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(host->clk);
|
||||
if (ret < 0)
|
||||
goto err_pm;
|
||||
goto err_host;
|
||||
|
||||
sh_mmcif_clk_setup(host);
|
||||
|
||||
ret = pm_runtime_resume(dev);
|
||||
pm_runtime_enable(dev);
|
||||
host->power = false;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
goto err_clk;
|
||||
|
||||
|
@ -1579,12 +1558,13 @@ static int sh_mmcif_probe(struct platform_device *pdev)
|
|||
sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0xffff,
|
||||
clk_get_rate(host->clk) / 1000000UL);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
clk_disable_unprepare(host->clk);
|
||||
return ret;
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(host->clk);
|
||||
err_pm:
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
err_host:
|
||||
mmc_free_host(mmc);
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/sh_mobile_sdhi.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl-state.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "tmio_mmc.h"
|
||||
|
||||
|
@ -48,10 +50,8 @@ struct sh_mobile_sdhi_of_data {
|
|||
unsigned bus_shift;
|
||||
};
|
||||
|
||||
static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
|
||||
{
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
|
||||
},
|
||||
static const struct sh_mobile_sdhi_of_data of_default_cfg = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
|
||||
};
|
||||
|
||||
static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
|
||||
|
@ -62,7 +62,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
|
|||
|
||||
static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
|
||||
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG,
|
||||
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
|
||||
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.dma_rx_offset = 0x2000,
|
||||
|
@ -70,17 +70,16 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
|
|||
|
||||
static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
|
||||
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED,
|
||||
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
|
||||
.bus_shift = 2,
|
||||
};
|
||||
|
||||
static const struct of_device_id sh_mobile_sdhi_of_match[] = {
|
||||
{ .compatible = "renesas,sdhi-shmobile" },
|
||||
{ .compatible = "renesas,sdhi-sh7372" },
|
||||
{ .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
|
||||
{ .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
|
||||
{ .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
|
||||
{ .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
|
||||
{ .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
|
||||
{ .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
|
||||
{ .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
|
||||
{ .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
|
||||
{ .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
|
||||
|
@ -97,6 +96,8 @@ struct sh_mobile_sdhi {
|
|||
struct clk *clk;
|
||||
struct tmio_mmc_data mmc_data;
|
||||
struct tmio_mmc_dma dma_priv;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default, *pins_uhs;
|
||||
};
|
||||
|
||||
static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
|
||||
|
@ -131,16 +132,28 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
|
|||
sd_ctrl_write16(host, EXT_ACC, val);
|
||||
}
|
||||
|
||||
static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
|
||||
static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
struct sh_mobile_sdhi *priv = host_to_priv(host);
|
||||
int ret = clk_prepare_enable(priv->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*f = clk_get_rate(priv->clk);
|
||||
/*
|
||||
* The clock driver may not know what maximum frequency
|
||||
* actually works, so it should be set with the max-frequency
|
||||
* property which will already have been read to f_max. If it
|
||||
* was missing, assume the current frequency is the maximum.
|
||||
*/
|
||||
if (!mmc->f_max)
|
||||
mmc->f_max = clk_get_rate(priv->clk);
|
||||
|
||||
/*
|
||||
* Minimum frequency is the minimum input clock frequency
|
||||
* divided by our maximum divider.
|
||||
*/
|
||||
mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L);
|
||||
|
||||
/* enable 16bit data access on SDBUF as default */
|
||||
sh_mobile_sdhi_sdbuf_width(host, 16);
|
||||
|
@ -148,19 +161,92 @@ static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
|
||||
static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host,
|
||||
unsigned int new_clock)
|
||||
{
|
||||
struct sh_mobile_sdhi *priv = host_to_priv(host);
|
||||
unsigned int freq, diff, best_freq = 0, diff_min = ~0;
|
||||
int i, ret;
|
||||
|
||||
/* tested only on RCar Gen2+ currently; may work for others */
|
||||
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
|
||||
return clk_get_rate(priv->clk);
|
||||
|
||||
/*
|
||||
* We want the bus clock to be as close as possible to, but no
|
||||
* greater than, new_clock. As we can divide by 1 << i for
|
||||
* any i in [0, 9] we want the input clock to be as close as
|
||||
* possible, but no greater than, new_clock << i.
|
||||
*/
|
||||
for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) {
|
||||
freq = clk_round_rate(priv->clk, new_clock << i);
|
||||
if (freq > (new_clock << i)) {
|
||||
/* Too fast; look for a slightly slower option */
|
||||
freq = clk_round_rate(priv->clk,
|
||||
(new_clock << i) / 4 * 3);
|
||||
if (freq > (new_clock << i))
|
||||
continue;
|
||||
}
|
||||
|
||||
diff = new_clock - (freq >> i);
|
||||
if (diff <= diff_min) {
|
||||
best_freq = freq;
|
||||
diff_min = diff;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_set_rate(priv->clk, best_freq);
|
||||
|
||||
return ret == 0 ? best_freq : clk_get_rate(priv->clk);
|
||||
}
|
||||
|
||||
static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct sh_mobile_sdhi *priv = host_to_priv(host);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct sh_mobile_sdhi *priv = host_to_priv(host);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
struct pinctrl_state *pin_state;
|
||||
int ret;
|
||||
|
||||
switch (ios->signal_voltage) {
|
||||
case MMC_SIGNAL_VOLTAGE_330:
|
||||
pin_state = priv->pins_default;
|
||||
break;
|
||||
case MMC_SIGNAL_VOLTAGE_180:
|
||||
pin_state = priv->pins_uhs;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If anything is missing, assume signal voltage is fixed at
|
||||
* 3.3V and succeed/fail accordingly.
|
||||
*/
|
||||
if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state))
|
||||
return ios->signal_voltage ==
|
||||
MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL;
|
||||
|
||||
ret = mmc_regulator_set_vqmmc(host->mmc, ios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pinctrl_select_state(priv->pinctrl, pin_state);
|
||||
}
|
||||
|
||||
static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
|
||||
{
|
||||
int timeout = 1000;
|
||||
|
||||
while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13)))
|
||||
while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS)
|
||||
& TMIO_STAT_SCLKDIVEN))
|
||||
udelay(1);
|
||||
|
||||
if (!timeout) {
|
||||
|
@ -226,7 +312,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
|
|||
struct tmio_mmc_host *host;
|
||||
struct resource *res;
|
||||
int irq, ret, i = 0;
|
||||
bool multiplexed_isr = true;
|
||||
struct tmio_mmc_dma *dma_priv;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -247,6 +332,14 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
|
|||
goto eprobe;
|
||||
}
|
||||
|
||||
priv->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (!IS_ERR(priv->pinctrl)) {
|
||||
priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
|
||||
PINCTRL_STATE_DEFAULT);
|
||||
priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl,
|
||||
"state_uhs");
|
||||
}
|
||||
|
||||
host = tmio_mmc_host_alloc(pdev);
|
||||
if (!host) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -267,8 +360,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
|
|||
host->dma = dma_priv;
|
||||
host->write16_hook = sh_mobile_sdhi_write16_hook;
|
||||
host->clk_enable = sh_mobile_sdhi_clk_enable;
|
||||
host->clk_update = sh_mobile_sdhi_clk_update;
|
||||
host->clk_disable = sh_mobile_sdhi_clk_disable;
|
||||
host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
|
||||
host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch;
|
||||
|
||||
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
|
||||
if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */
|
||||
|
@ -308,63 +403,24 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto efree;
|
||||
|
||||
/*
|
||||
* Allow one or more specific (named) ISRs or
|
||||
* one or more multiplexed (un-named) ISRs.
|
||||
*/
|
||||
|
||||
irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
|
||||
if (irq >= 0) {
|
||||
multiplexed_isr = false;
|
||||
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_card_detect_irq, 0,
|
||||
while (1) {
|
||||
irq = platform_get_irq(pdev, i);
|
||||
if (irq < 0)
|
||||
break;
|
||||
i++;
|
||||
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
|
||||
dev_name(&pdev->dev), host);
|
||||
if (ret)
|
||||
goto eirq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
|
||||
if (irq >= 0) {
|
||||
multiplexed_isr = false;
|
||||
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_sdio_irq, 0,
|
||||
dev_name(&pdev->dev), host);
|
||||
if (ret)
|
||||
goto eirq;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD);
|
||||
if (irq >= 0) {
|
||||
multiplexed_isr = false;
|
||||
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_sdcard_irq, 0,
|
||||
dev_name(&pdev->dev), host);
|
||||
if (ret)
|
||||
goto eirq;
|
||||
} else if (!multiplexed_isr) {
|
||||
dev_err(&pdev->dev,
|
||||
"Principal SD-card IRQ is missing among named interrupts\n");
|
||||
/* There must be at least one IRQ source */
|
||||
if (!i) {
|
||||
ret = irq;
|
||||
goto eirq;
|
||||
}
|
||||
|
||||
if (multiplexed_isr) {
|
||||
while (1) {
|
||||
irq = platform_get_irq(pdev, i);
|
||||
if (irq < 0)
|
||||
break;
|
||||
i++;
|
||||
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
|
||||
dev_name(&pdev->dev), host);
|
||||
if (ret)
|
||||
goto eirq;
|
||||
}
|
||||
|
||||
/* There must be at least one IRQ source */
|
||||
if (!i) {
|
||||
ret = irq;
|
||||
goto eirq;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
|
||||
dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n",
|
||||
mmc_hostname(host->mmc), (unsigned long)
|
||||
(platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
|
||||
host->mmc->f_max / 1000000);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/*
|
||||
* linux/drivers/mmc/host/tmio_mmc.h
|
||||
*
|
||||
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
|
||||
* Copyright (C) 2015-16 Renesas Electronics Corporation
|
||||
* Copyright (C) 2007 Ian Molton
|
||||
* Copyright (C) 2004 Ian Molton
|
||||
*
|
||||
|
@ -18,12 +20,67 @@
|
|||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/mmc/tmio.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define CTL_SD_CMD 0x00
|
||||
#define CTL_ARG_REG 0x04
|
||||
#define CTL_STOP_INTERNAL_ACTION 0x08
|
||||
#define CTL_XFER_BLK_COUNT 0xa
|
||||
#define CTL_RESPONSE 0x0c
|
||||
/* driver merges STATUS and following STATUS2 */
|
||||
#define CTL_STATUS 0x1c
|
||||
/* driver merges IRQ_MASK and following IRQ_MASK2 */
|
||||
#define CTL_IRQ_MASK 0x20
|
||||
#define CTL_SD_CARD_CLK_CTL 0x24
|
||||
#define CTL_SD_XFER_LEN 0x26
|
||||
#define CTL_SD_MEM_CARD_OPT 0x28
|
||||
#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
|
||||
#define CTL_SD_DATA_PORT 0x30
|
||||
#define CTL_TRANSACTION_CTL 0x34
|
||||
#define CTL_SDIO_STATUS 0x36
|
||||
#define CTL_SDIO_IRQ_MASK 0x38
|
||||
#define CTL_DMA_ENABLE 0xd8
|
||||
#define CTL_RESET_SD 0xe0
|
||||
#define CTL_VERSION 0xe2
|
||||
#define CTL_SDIO_REGS 0x100
|
||||
#define CTL_CLK_AND_WAIT_CTL 0x138
|
||||
#define CTL_RESET_SDIO 0x1e0
|
||||
|
||||
/* Definitions for values the CTRL_STATUS register can take. */
|
||||
#define TMIO_STAT_CMDRESPEND BIT(0)
|
||||
#define TMIO_STAT_DATAEND BIT(2)
|
||||
#define TMIO_STAT_CARD_REMOVE BIT(3)
|
||||
#define TMIO_STAT_CARD_INSERT BIT(4)
|
||||
#define TMIO_STAT_SIGSTATE BIT(5)
|
||||
#define TMIO_STAT_WRPROTECT BIT(7)
|
||||
#define TMIO_STAT_CARD_REMOVE_A BIT(8)
|
||||
#define TMIO_STAT_CARD_INSERT_A BIT(9)
|
||||
#define TMIO_STAT_SIGSTATE_A BIT(10)
|
||||
|
||||
/* These belong technically to CTRL_STATUS2, but the driver merges them */
|
||||
#define TMIO_STAT_CMD_IDX_ERR BIT(16)
|
||||
#define TMIO_STAT_CRCFAIL BIT(17)
|
||||
#define TMIO_STAT_STOPBIT_ERR BIT(18)
|
||||
#define TMIO_STAT_DATATIMEOUT BIT(19)
|
||||
#define TMIO_STAT_RXOVERFLOW BIT(20)
|
||||
#define TMIO_STAT_TXUNDERRUN BIT(21)
|
||||
#define TMIO_STAT_CMDTIMEOUT BIT(22)
|
||||
#define TMIO_STAT_DAT0 BIT(23) /* only known on R-Car so far */
|
||||
#define TMIO_STAT_RXRDY BIT(24)
|
||||
#define TMIO_STAT_TXRQ BIT(25)
|
||||
#define TMIO_STAT_ILL_FUNC BIT(29) /* only when !TMIO_MMC_HAS_IDLE_WAIT */
|
||||
#define TMIO_STAT_SCLKDIVEN BIT(29) /* only when TMIO_MMC_HAS_IDLE_WAIT */
|
||||
#define TMIO_STAT_CMD_BUSY BIT(30)
|
||||
#define TMIO_STAT_ILL_ACCESS BIT(31)
|
||||
|
||||
#define CLK_CTL_DIV_MASK 0xff
|
||||
#define CLK_CTL_SCLKEN BIT(8)
|
||||
|
||||
#define TMIO_BBS 512 /* Boot block size */
|
||||
|
||||
/* Definitions for values the CTRL_SDIO_STATUS register can take. */
|
||||
#define TMIO_SDIO_STAT_IOIRQ 0x0001
|
||||
#define TMIO_SDIO_STAT_EXPUB52 0x4000
|
||||
|
@ -95,10 +152,14 @@ struct tmio_mmc_host {
|
|||
bool sdio_irq_enabled;
|
||||
|
||||
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
|
||||
int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
|
||||
void (*clk_disable)(struct platform_device *pdev);
|
||||
int (*clk_enable)(struct tmio_mmc_host *host);
|
||||
unsigned int (*clk_update)(struct tmio_mmc_host *host,
|
||||
unsigned int new_clock);
|
||||
void (*clk_disable)(struct tmio_mmc_host *host);
|
||||
int (*multi_io_quirk)(struct mmc_card *card,
|
||||
unsigned int direction, int blk_size);
|
||||
int (*start_signal_voltage_switch)(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios);
|
||||
};
|
||||
|
||||
struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
|
||||
|
@ -111,9 +172,6 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
|
|||
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
||||
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
||||
irqreturn_t tmio_mmc_irq(int irq, void *devid);
|
||||
irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
|
||||
irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
|
||||
irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
|
||||
|
||||
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
|
||||
unsigned long *flags)
|
||||
|
@ -177,7 +235,7 @@ static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
|
|||
readsw(host->ctl + (addr << host->bus_shift), buf, count);
|
||||
}
|
||||
|
||||
static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
|
||||
static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host, int addr)
|
||||
{
|
||||
return readw(host->ctl + (addr << host->bus_shift)) |
|
||||
readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
|
||||
|
@ -199,11 +257,10 @@ static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
|
|||
writesw(host->ctl + (addr << host->bus_shift), buf, count);
|
||||
}
|
||||
|
||||
static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
|
||||
static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val)
|
||||
{
|
||||
writew(val, host->ctl + (addr << host->bus_shift));
|
||||
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/dmaengine.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/tmio.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/mmc/tmio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -56,18 +55,18 @@
|
|||
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
|
||||
{
|
||||
host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
|
||||
sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
|
||||
}
|
||||
|
||||
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
|
||||
{
|
||||
host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ);
|
||||
sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
|
||||
}
|
||||
|
||||
static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
|
||||
{
|
||||
sd_ctrl_write32(host, CTL_STATUS, ~i);
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, ~i);
|
||||
}
|
||||
|
||||
static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
|
||||
|
@ -154,31 +153,16 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
|||
}
|
||||
}
|
||||
|
||||
static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
|
||||
unsigned int new_clock)
|
||||
static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
|
||||
{
|
||||
u32 clk = 0, clock;
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 1 : 10);
|
||||
|
||||
if (new_clock) {
|
||||
for (clock = host->mmc->f_min, clk = 0x80000080;
|
||||
new_clock >= (clock << 1);
|
||||
clk >>= 1)
|
||||
clock <<= 1;
|
||||
|
||||
/* 1/1 clock is option */
|
||||
if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) &&
|
||||
((clk >> 22) & 0x1))
|
||||
clk |= 0xff;
|
||||
}
|
||||
|
||||
if (host->set_clk_div)
|
||||
host->set_clk_div(host->pdev, (clk >> 22) & 1);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
|
||||
if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG))
|
||||
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
|
||||
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
|
||||
msleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
|
||||
|
@ -190,19 +174,41 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
|
|||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10);
|
||||
msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 5 : 10);
|
||||
}
|
||||
|
||||
static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
|
||||
static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
|
||||
unsigned int new_clock)
|
||||
{
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10);
|
||||
u32 clk = 0, clock;
|
||||
|
||||
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
|
||||
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
|
||||
msleep(10);
|
||||
if (new_clock == 0) {
|
||||
tmio_mmc_clk_stop(host);
|
||||
return;
|
||||
}
|
||||
|
||||
if (host->clk_update)
|
||||
clock = host->clk_update(host, new_clock) / 512;
|
||||
else
|
||||
clock = host->mmc->f_min;
|
||||
|
||||
for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
|
||||
clock <<= 1;
|
||||
|
||||
/* 1/1 clock is option */
|
||||
if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1))
|
||||
clk |= 0xff;
|
||||
|
||||
if (host->set_clk_div)
|
||||
host->set_clk_div(host->pdev, (clk >> 22) & 1);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
|
||||
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
|
||||
msleep(10);
|
||||
|
||||
tmio_mmc_clk_start(host);
|
||||
}
|
||||
|
||||
static void tmio_mmc_reset(struct tmio_mmc_host *host)
|
||||
|
@ -264,9 +270,6 @@ static void tmio_mmc_reset_work(struct work_struct *work)
|
|||
|
||||
tmio_mmc_abort_dma(host);
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(host->mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(host->mmc));
|
||||
}
|
||||
|
||||
/* called with host->lock held, interrupts disabled */
|
||||
|
@ -296,9 +299,6 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
|
|||
tmio_mmc_abort_dma(host);
|
||||
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(host->mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(host->mmc));
|
||||
}
|
||||
|
||||
static void tmio_mmc_done_work(struct work_struct *work)
|
||||
|
@ -375,7 +375,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
|
|||
tmio_mmc_enable_mmc_irqs(host, irq_mask);
|
||||
|
||||
/* Fire off the command */
|
||||
sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_ARG_REG, cmd->arg);
|
||||
sd_ctrl_write16(host, CTL_SD_CMD, c);
|
||||
|
||||
return 0;
|
||||
|
@ -530,7 +530,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
|
|||
goto out;
|
||||
|
||||
if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
|
||||
u32 status = sd_ctrl_read32(host, CTL_STATUS);
|
||||
u32 status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
|
||||
bool done = false;
|
||||
|
||||
/*
|
||||
|
@ -542,7 +542,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
|
|||
* waiting for one more interrupt fixes the problem.
|
||||
*/
|
||||
if (host->pdata->flags & TMIO_MMC_HAS_IDLE_WAIT) {
|
||||
if (status & TMIO_STAT_ILL_FUNC)
|
||||
if (status & TMIO_STAT_SCLKDIVEN)
|
||||
done = true;
|
||||
} else {
|
||||
if (!(status & TMIO_STAT_CMD_BUSY))
|
||||
|
@ -585,7 +585,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
|
|||
*/
|
||||
|
||||
for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
|
||||
cmd->resp[i] = sd_ctrl_read32(host, addr);
|
||||
cmd->resp[i] = sd_ctrl_read16_and_16_as_32(host, addr);
|
||||
|
||||
if (cmd->flags & MMC_RSP_136) {
|
||||
cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24);
|
||||
|
@ -625,19 +625,6 @@ out:
|
|||
spin_unlock(&host->lock);
|
||||
}
|
||||
|
||||
static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
|
||||
int *ireg, int *status)
|
||||
{
|
||||
*status = sd_ctrl_read32(host, CTL_STATUS);
|
||||
*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
|
||||
|
||||
pr_debug_status(*status);
|
||||
pr_debug_status(*ireg);
|
||||
|
||||
/* Clear the status except the interrupt status */
|
||||
sd_ctrl_write32(host, CTL_STATUS, TMIO_MASK_IRQ);
|
||||
}
|
||||
|
||||
static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
|
||||
int ireg, int status)
|
||||
{
|
||||
|
@ -657,18 +644,6 @@ static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
|
|||
return false;
|
||||
}
|
||||
|
||||
irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
|
||||
{
|
||||
unsigned int ireg, status;
|
||||
struct tmio_mmc_host *host = devid;
|
||||
|
||||
tmio_mmc_card_irq_status(host, &ireg, &status);
|
||||
__tmio_mmc_card_detect_irq(host, ireg, status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
|
||||
|
||||
static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
|
||||
int ireg, int status)
|
||||
{
|
||||
|
@ -698,19 +673,7 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
|
|||
return false;
|
||||
}
|
||||
|
||||
irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
|
||||
{
|
||||
unsigned int ireg, status;
|
||||
struct tmio_mmc_host *host = devid;
|
||||
|
||||
tmio_mmc_card_irq_status(host, &ireg, &status);
|
||||
__tmio_mmc_sdcard_irq(host, ireg, status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
|
||||
|
||||
irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
|
||||
static void tmio_mmc_sdio_irq(int irq, void *devid)
|
||||
{
|
||||
struct tmio_mmc_host *host = devid;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
@ -719,7 +682,7 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
|
|||
unsigned int sdio_status;
|
||||
|
||||
if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
|
||||
return IRQ_HANDLED;
|
||||
return;
|
||||
|
||||
status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
|
||||
ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
|
||||
|
@ -732,19 +695,22 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
|
|||
|
||||
if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
|
||||
mmc_signal_sdio_irq(mmc);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL(tmio_mmc_sdio_irq);
|
||||
|
||||
irqreturn_t tmio_mmc_irq(int irq, void *devid)
|
||||
{
|
||||
struct tmio_mmc_host *host = devid;
|
||||
unsigned int ireg, status;
|
||||
|
||||
pr_debug("MMC IRQ begin\n");
|
||||
status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS);
|
||||
ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
|
||||
|
||||
pr_debug_status(status);
|
||||
pr_debug_status(ireg);
|
||||
|
||||
/* Clear the status except the interrupt status */
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, TMIO_MASK_IRQ);
|
||||
|
||||
tmio_mmc_card_irq_status(host, &ireg, &status);
|
||||
if (__tmio_mmc_card_detect_irq(host, ireg, status))
|
||||
return IRQ_HANDLED;
|
||||
if (__tmio_mmc_sdcard_irq(host, ireg, status))
|
||||
|
@ -812,8 +778,6 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
if (mrq->data) {
|
||||
ret = tmio_mmc_start_data(host, mrq->data);
|
||||
if (ret)
|
||||
|
@ -832,24 +796,14 @@ fail:
|
|||
host->mrq = NULL;
|
||||
mrq->cmd->error = ret;
|
||||
mmc_request_done(mmc, mrq);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
}
|
||||
|
||||
static int tmio_mmc_clk_update(struct tmio_mmc_host *host)
|
||||
static int tmio_mmc_clk_enable(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int ret;
|
||||
|
||||
if (!host->clk_enable)
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = host->clk_enable(host->pdev, &mmc->f_max);
|
||||
if (!ret)
|
||||
mmc->f_min = mmc->f_max / 512;
|
||||
|
||||
return ret;
|
||||
return host->clk_enable(host);
|
||||
}
|
||||
|
||||
static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
|
||||
|
@ -925,8 +879,6 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
struct device *dev = &host->pdev->dev;
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
|
||||
mutex_lock(&host->ios_lock);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
@ -959,14 +911,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
tmio_mmc_clk_stop(host);
|
||||
break;
|
||||
case MMC_POWER_UP:
|
||||
tmio_mmc_set_clock(host, ios->clock);
|
||||
tmio_mmc_power_on(host, ios->vdd);
|
||||
tmio_mmc_clk_start(host);
|
||||
tmio_mmc_set_clock(host, ios->clock);
|
||||
tmio_mmc_set_bus_width(host, ios->bus_width);
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
tmio_mmc_set_clock(host, ios->clock);
|
||||
tmio_mmc_clk_start(host);
|
||||
tmio_mmc_set_bus_width(host, ios->bus_width);
|
||||
break;
|
||||
}
|
||||
|
@ -983,9 +933,6 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
host->clk_cache = ios->clock;
|
||||
|
||||
mutex_unlock(&host->ios_lock);
|
||||
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
}
|
||||
|
||||
static int tmio_mmc_get_ro(struct mmc_host *mmc)
|
||||
|
@ -996,11 +943,8 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
|
|||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
pm_runtime_get_sync(mmc_dev(mmc));
|
||||
ret = !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
|
||||
(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
|
||||
pm_runtime_mark_last_busy(mmc_dev(mmc));
|
||||
pm_runtime_put_autosuspend(mmc_dev(mmc));
|
||||
(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1016,12 +960,20 @@ static int tmio_multi_io_quirk(struct mmc_card *card,
|
|||
return blk_size;
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops tmio_mmc_ops = {
|
||||
static int tmio_mmc_card_busy(struct mmc_host *mmc)
|
||||
{
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
|
||||
return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
|
||||
}
|
||||
|
||||
static struct mmc_host_ops tmio_mmc_ops = {
|
||||
.request = tmio_mmc_request,
|
||||
.set_ios = tmio_mmc_set_ios,
|
||||
.get_ro = tmio_mmc_get_ro,
|
||||
.get_cd = mmc_gpio_get_cd,
|
||||
.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
|
||||
.card_busy = tmio_mmc_card_busy,
|
||||
.multi_io_quirk = tmio_multi_io_quirk,
|
||||
};
|
||||
|
||||
|
@ -1120,7 +1072,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
|
|||
goto host_free;
|
||||
}
|
||||
|
||||
tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch;
|
||||
mmc->ops = &tmio_mmc_ops;
|
||||
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
|
||||
mmc->caps2 |= pdata->capabilities2;
|
||||
mmc->max_segs = 32;
|
||||
|
@ -1135,7 +1089,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
|
|||
mmc->caps & MMC_CAP_NONREMOVABLE ||
|
||||
mmc->slot.cd_irq >= 0);
|
||||
|
||||
if (tmio_mmc_clk_update(_host) < 0) {
|
||||
if (tmio_mmc_clk_enable(_host) < 0) {
|
||||
mmc->f_max = pdata->hclk;
|
||||
mmc->f_min = mmc->f_max / 512;
|
||||
}
|
||||
|
@ -1159,7 +1113,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
|
|||
tmio_mmc_clk_stop(_host);
|
||||
tmio_mmc_reset(_host);
|
||||
|
||||
_host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
|
||||
_host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK);
|
||||
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
|
||||
|
||||
/* Unmask the IRQs we want to know about */
|
||||
|
@ -1251,7 +1205,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
|
|||
tmio_mmc_clk_stop(host);
|
||||
|
||||
if (host->clk_disable)
|
||||
host->clk_disable(host->pdev);
|
||||
host->clk_disable(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1263,12 +1217,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
|
|||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
|
||||
tmio_mmc_reset(host);
|
||||
tmio_mmc_clk_update(host);
|
||||
tmio_mmc_clk_enable(host);
|
||||
|
||||
if (host->clk_cache) {
|
||||
if (host->clk_cache)
|
||||
tmio_mmc_set_clock(host, host->clk_cache);
|
||||
tmio_mmc_clk_start(host);
|
||||
}
|
||||
|
||||
tmio_mmc_enable_dma(host, true);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/string.h>
|
||||
|
@ -198,6 +199,11 @@ struct usdhi6_host {
|
|||
struct dma_chan *chan_rx;
|
||||
struct dma_chan *chan_tx;
|
||||
bool dma_active;
|
||||
|
||||
/* Pin control */
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct pinctrl_state *pins_uhs;
|
||||
};
|
||||
|
||||
/* I/O primitives */
|
||||
|
@ -1147,12 +1153,45 @@ static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
|||
}
|
||||
}
|
||||
|
||||
static int usdhi6_set_pinstates(struct usdhi6_host *host, int voltage)
|
||||
{
|
||||
if (IS_ERR(host->pins_uhs))
|
||||
return 0;
|
||||
|
||||
switch (voltage) {
|
||||
case MMC_SIGNAL_VOLTAGE_180:
|
||||
case MMC_SIGNAL_VOLTAGE_120:
|
||||
return pinctrl_select_state(host->pinctrl,
|
||||
host->pins_uhs);
|
||||
|
||||
default:
|
||||
return pinctrl_select_state(host->pinctrl,
|
||||
host->pins_default);
|
||||
}
|
||||
}
|
||||
|
||||
static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mmc_regulator_set_vqmmc(mmc, ios);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = usdhi6_set_pinstates(mmc_priv(mmc), ios->signal_voltage);
|
||||
if (ret)
|
||||
dev_warn_once(mmc_dev(mmc),
|
||||
"Failed to set pinstate err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct mmc_host_ops usdhi6_ops = {
|
||||
.request = usdhi6_request,
|
||||
.set_ios = usdhi6_set_ios,
|
||||
.get_cd = usdhi6_get_cd,
|
||||
.get_ro = usdhi6_get_ro,
|
||||
.enable_sdio_irq = usdhi6_enable_sdio_irq,
|
||||
.start_signal_voltage_switch = usdhi6_sig_volt_switch,
|
||||
};
|
||||
|
||||
/* State machine handlers */
|
||||
|
@ -1730,6 +1769,25 @@ static int usdhi6_probe(struct platform_device *pdev)
|
|||
host->wait = USDHI6_WAIT_FOR_REQUEST;
|
||||
host->timeout = msecs_to_jiffies(4000);
|
||||
|
||||
host->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(host->pinctrl)) {
|
||||
ret = PTR_ERR(host->pinctrl);
|
||||
goto e_free_mmc;
|
||||
}
|
||||
|
||||
host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
|
||||
if (!IS_ERR(host->pins_uhs)) {
|
||||
host->pins_default = pinctrl_lookup_state(host->pinctrl,
|
||||
PINCTRL_STATE_DEFAULT);
|
||||
|
||||
if (IS_ERR(host->pins_default)) {
|
||||
dev_err(dev,
|
||||
"UHS pinctrl requires a default pin state.\n");
|
||||
ret = PTR_ERR(host->pins_default);
|
||||
goto e_free_mmc;
|
||||
}
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(host->base)) {
|
||||
|
@ -1785,7 +1843,7 @@ static int usdhi6_probe(struct platform_device *pdev)
|
|||
|
||||
mmc->ops = &usdhi6_ops;
|
||||
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ;
|
||||
MMC_CAP_SDIO_IRQ;
|
||||
/* Set .max_segs to some random number. Feel free to adjust. */
|
||||
mmc->max_segs = 32;
|
||||
mmc->max_blk_size = 512;
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
*/
|
||||
#define TMIO_MMC_SDIO_IRQ (1 << 2)
|
||||
|
||||
/* Some controllers don't need to wait 10ms for clock changes */
|
||||
#define TMIO_MMC_FAST_CLK_CHG (1 << 3)
|
||||
/* Some features are only available or tested on RCar Gen2 or later */
|
||||
#define TMIO_MMC_MIN_RCAR2 (1 << 3)
|
||||
|
||||
/*
|
||||
* Some controllers require waiting for the SD bus to become
|
||||
|
|
|
@ -36,7 +36,6 @@ enum {
|
|||
EVENT_XFER_COMPLETE,
|
||||
EVENT_DATA_COMPLETE,
|
||||
EVENT_DATA_ERROR,
|
||||
EVENT_XFER_ERROR
|
||||
};
|
||||
|
||||
struct mmc_data;
|
||||
|
@ -55,6 +54,7 @@ struct dw_mci_dma_slave {
|
|||
/**
|
||||
* struct dw_mci - MMC controller state shared between all slots
|
||||
* @lock: Spinlock protecting the queue and associated data.
|
||||
* @irq_lock: Spinlock protecting the INTMASK setting.
|
||||
* @regs: Pointer to MMIO registers.
|
||||
* @fifo_reg: Pointer to MMIO registers for data FIFO
|
||||
* @sg: Scatterlist entry currently being processed by PIO code, if any.
|
||||
|
@ -65,6 +65,9 @@ struct dw_mci_dma_slave {
|
|||
* @cmd: The command currently being sent to the card, or NULL.
|
||||
* @data: The data currently being transferred, or NULL if no data
|
||||
* transfer is in progress.
|
||||
* @stop_abort: The command currently prepared for stoping transfer.
|
||||
* @prev_blksz: The former transfer blksz record.
|
||||
* @timing: Record of current ios timing.
|
||||
* @use_dma: Whether DMA channel is initialized or not.
|
||||
* @using_dma: Whether DMA is in use for the current transfer.
|
||||
* @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
|
||||
|
@ -72,7 +75,10 @@ struct dw_mci_dma_slave {
|
|||
* @sg_cpu: Virtual address of DMA buffer.
|
||||
* @dma_ops: Pointer to platform-specific DMA callbacks.
|
||||
* @cmd_status: Snapshot of SR taken upon completion of the current
|
||||
* @ring_size: Buffer size for idma descriptors.
|
||||
* command. Only valid when EVENT_CMD_COMPLETE is pending.
|
||||
* @dms: structure of slave-dma private data.
|
||||
* @phy_regs: physical address of controller's register map
|
||||
* @data_status: Snapshot of SR taken upon completion of the current
|
||||
* data transfer. Only valid when EVENT_DATA_COMPLETE or
|
||||
* EVENT_DATA_ERROR is pending.
|
||||
|
@ -80,7 +86,6 @@ struct dw_mci_dma_slave {
|
|||
* to be sent.
|
||||
* @dir_status: Direction of current transfer.
|
||||
* @tasklet: Tasklet running the request state machine.
|
||||
* @card_tasklet: Tasklet handling card detect.
|
||||
* @pending_events: Bitmask of events flagged by the interrupt handler
|
||||
* to be processed by the tasklet.
|
||||
* @completed_events: Bitmask of events which the state machine has
|
||||
|
@ -91,6 +96,7 @@ struct dw_mci_dma_slave {
|
|||
* rate and timeout calculations.
|
||||
* @current_speed: Configured rate of the controller.
|
||||
* @num_slots: Number of slots available.
|
||||
* @fifoth_val: The value of FIFOTH register.
|
||||
* @verid: Denote Version ID.
|
||||
* @dev: Device associated with the MMC controller.
|
||||
* @pdata: Platform data associated with the MMC controller.
|
||||
|
@ -107,9 +113,11 @@ struct dw_mci_dma_slave {
|
|||
* @push_data: Pointer to FIFO push function.
|
||||
* @pull_data: Pointer to FIFO pull function.
|
||||
* @quirks: Set of quirks that apply to specific versions of the IP.
|
||||
* @vqmmc_enabled: Status of vqmmc, should be true or false.
|
||||
* @irq_flags: The flags to be passed to request_irq.
|
||||
* @irq: The irq value to be passed to request_irq.
|
||||
* @sdio_id0: Number of slot0 in the SDIO interrupt registers.
|
||||
* @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
|
||||
* @dto_timer: Timer for broken data transfer over scheme.
|
||||
*
|
||||
* Locking
|
||||
|
|
|
@ -93,28 +93,39 @@ struct mmc_host_ops {
|
|||
void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
|
||||
bool is_first_req);
|
||||
void (*request)(struct mmc_host *host, struct mmc_request *req);
|
||||
|
||||
/*
|
||||
* Avoid calling the next 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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Notes to the set_ios callback:
|
||||
* ios->clock might be 0. For some controllers, setting 0Hz
|
||||
* as any other frequency works. However, some controllers
|
||||
* explicitly need to disable the clock. Otherwise e.g. voltage
|
||||
* switching might fail because the SDCLK is not really quiet.
|
||||
*/
|
||||
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
|
||||
|
||||
/*
|
||||
* 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!
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
int (*get_ro)(struct mmc_host *host);
|
||||
|
||||
/*
|
||||
* Return values for the get_cd callback should be:
|
||||
* 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
|
||||
*/
|
||||
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
|
||||
int (*get_ro)(struct mmc_host *host);
|
||||
int (*get_cd)(struct mmc_host *host);
|
||||
|
||||
void (*enable_sdio_irq)(struct mmc_host *host, int enable);
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef LINUX_MMC_SH_MOBILE_SDHI_H
|
||||
#define LINUX_MMC_SH_MOBILE_SDHI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SH_MOBILE_SDHI_IRQ_CARD_DETECT "card_detect"
|
||||
#define SH_MOBILE_SDHI_IRQ_SDCARD "sdcard"
|
||||
#define SH_MOBILE_SDHI_IRQ_SDIO "sdio"
|
||||
|
||||
#endif /* LINUX_MMC_SH_MOBILE_SDHI_H */
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* include/linux/mmc/tmio.h
|
||||
*
|
||||
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
|
||||
* Copyright (C) 2015-16 Renesas Electronics Corporation
|
||||
* Copyright (C) 2007 Ian Molton
|
||||
* Copyright (C) 2004 Ian Molton
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Driver for the MMC / SD / SDIO cell found in:
|
||||
*
|
||||
* TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
|
||||
*/
|
||||
#ifndef LINUX_MMC_TMIO_H
|
||||
#define LINUX_MMC_TMIO_H
|
||||
|
||||
#define CTL_SD_CMD 0x00
|
||||
#define CTL_ARG_REG 0x04
|
||||
#define CTL_STOP_INTERNAL_ACTION 0x08
|
||||
#define CTL_XFER_BLK_COUNT 0xa
|
||||
#define CTL_RESPONSE 0x0c
|
||||
#define CTL_STATUS 0x1c
|
||||
#define CTL_STATUS2 0x1e
|
||||
#define CTL_IRQ_MASK 0x20
|
||||
#define CTL_SD_CARD_CLK_CTL 0x24
|
||||
#define CTL_SD_XFER_LEN 0x26
|
||||
#define CTL_SD_MEM_CARD_OPT 0x28
|
||||
#define CTL_SD_ERROR_DETAIL_STATUS 0x2c
|
||||
#define CTL_SD_DATA_PORT 0x30
|
||||
#define CTL_TRANSACTION_CTL 0x34
|
||||
#define CTL_SDIO_STATUS 0x36
|
||||
#define CTL_SDIO_IRQ_MASK 0x38
|
||||
#define CTL_DMA_ENABLE 0xd8
|
||||
#define CTL_RESET_SD 0xe0
|
||||
#define CTL_VERSION 0xe2
|
||||
#define CTL_SDIO_REGS 0x100
|
||||
#define CTL_CLK_AND_WAIT_CTL 0x138
|
||||
#define CTL_RESET_SDIO 0x1e0
|
||||
|
||||
/* Definitions for values the CTRL_STATUS register can take. */
|
||||
#define TMIO_STAT_CMDRESPEND 0x00000001
|
||||
#define TMIO_STAT_DATAEND 0x00000004
|
||||
#define TMIO_STAT_CARD_REMOVE 0x00000008
|
||||
#define TMIO_STAT_CARD_INSERT 0x00000010
|
||||
#define TMIO_STAT_SIGSTATE 0x00000020
|
||||
#define TMIO_STAT_WRPROTECT 0x00000080
|
||||
#define TMIO_STAT_CARD_REMOVE_A 0x00000100
|
||||
#define TMIO_STAT_CARD_INSERT_A 0x00000200
|
||||
#define TMIO_STAT_SIGSTATE_A 0x00000400
|
||||
#define TMIO_STAT_CMD_IDX_ERR 0x00010000
|
||||
#define TMIO_STAT_CRCFAIL 0x00020000
|
||||
#define TMIO_STAT_STOPBIT_ERR 0x00040000
|
||||
#define TMIO_STAT_DATATIMEOUT 0x00080000
|
||||
#define TMIO_STAT_RXOVERFLOW 0x00100000
|
||||
#define TMIO_STAT_TXUNDERRUN 0x00200000
|
||||
#define TMIO_STAT_CMDTIMEOUT 0x00400000
|
||||
#define TMIO_STAT_RXRDY 0x01000000
|
||||
#define TMIO_STAT_TXRQ 0x02000000
|
||||
#define TMIO_STAT_ILL_FUNC 0x20000000
|
||||
#define TMIO_STAT_CMD_BUSY 0x40000000
|
||||
#define TMIO_STAT_ILL_ACCESS 0x80000000
|
||||
|
||||
#define CLK_CTL_DIV_MASK 0xff
|
||||
#define CLK_CTL_SCLKEN BIT(8)
|
||||
|
||||
#define TMIO_BBS 512 /* Boot block size */
|
||||
|
||||
#endif /* LINUX_MMC_TMIO_H */
|
|
@ -0,0 +1,182 @@
|
|||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM mmc
|
||||
|
||||
#if !defined(_TRACE_MMC_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _TRACE_MMC_H
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/mmc/core.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
TRACE_EVENT(mmc_request_start,
|
||||
|
||||
TP_PROTO(struct mmc_host *host, struct mmc_request *mrq),
|
||||
|
||||
TP_ARGS(host, mrq),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cmd_opcode)
|
||||
__field(u32, cmd_arg)
|
||||
__field(unsigned int, cmd_flags)
|
||||
__field(unsigned int, cmd_retries)
|
||||
__field(u32, stop_opcode)
|
||||
__field(u32, stop_arg)
|
||||
__field(unsigned int, stop_flags)
|
||||
__field(unsigned int, stop_retries)
|
||||
__field(u32, sbc_opcode)
|
||||
__field(u32, sbc_arg)
|
||||
__field(unsigned int, sbc_flags)
|
||||
__field(unsigned int, sbc_retries)
|
||||
__field(unsigned int, blocks)
|
||||
__field(unsigned int, blksz)
|
||||
__field(unsigned int, data_flags)
|
||||
__field(unsigned int, can_retune)
|
||||
__field(unsigned int, doing_retune)
|
||||
__field(unsigned int, retune_now)
|
||||
__field(int, need_retune)
|
||||
__field(int, hold_retune)
|
||||
__field(unsigned int, retune_period)
|
||||
__field(struct mmc_request *, mrq)
|
||||
__string(name, mmc_hostname(host))
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cmd_opcode = mrq->cmd->opcode;
|
||||
__entry->cmd_arg = mrq->cmd->arg;
|
||||
__entry->cmd_flags = mrq->cmd->flags;
|
||||
__entry->cmd_retries = mrq->cmd->retries;
|
||||
__entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0;
|
||||
__entry->stop_arg = mrq->stop ? mrq->stop->arg : 0;
|
||||
__entry->stop_flags = mrq->stop ? mrq->stop->flags : 0;
|
||||
__entry->stop_retries = mrq->stop ? mrq->stop->retries : 0;
|
||||
__entry->sbc_opcode = mrq->sbc ? mrq->sbc->opcode : 0;
|
||||
__entry->sbc_arg = mrq->sbc ? mrq->sbc->arg : 0;
|
||||
__entry->sbc_flags = mrq->sbc ? mrq->sbc->flags : 0;
|
||||
__entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0;
|
||||
__entry->blksz = mrq->data ? mrq->data->blksz : 0;
|
||||
__entry->blocks = mrq->data ? mrq->data->blocks : 0;
|
||||
__entry->data_flags = mrq->data ? mrq->data->flags : 0;
|
||||
__entry->can_retune = host->can_retune;
|
||||
__entry->doing_retune = host->doing_retune;
|
||||
__entry->retune_now = host->retune_now;
|
||||
__entry->need_retune = host->need_retune;
|
||||
__entry->hold_retune = host->hold_retune;
|
||||
__entry->retune_period = host->retune_period;
|
||||
__assign_str(name, mmc_hostname(host));
|
||||
__entry->mrq = mrq;
|
||||
),
|
||||
|
||||
TP_printk("%s: start struct mmc_request[%p]: "
|
||||
"cmd_opcode=%u cmd_arg=0x%x cmd_flags=0x%x cmd_retries=%u "
|
||||
"stop_opcode=%u stop_arg=0x%x stop_flags=0x%x stop_retries=%u "
|
||||
"sbc_opcode=%u sbc_arg=0x%x sbc_flags=0x%x sbc_retires=%u "
|
||||
"blocks=%u block_size=%u data_flags=0x%x "
|
||||
"can_retune=%u doing_retune=%u retune_now=%u "
|
||||
"need_retune=%d hold_retune=%d retune_period=%u",
|
||||
__get_str(name), __entry->mrq,
|
||||
__entry->cmd_opcode, __entry->cmd_arg,
|
||||
__entry->cmd_flags, __entry->cmd_retries,
|
||||
__entry->stop_opcode, __entry->stop_arg,
|
||||
__entry->stop_flags, __entry->stop_retries,
|
||||
__entry->sbc_opcode, __entry->sbc_arg,
|
||||
__entry->sbc_flags, __entry->sbc_retries,
|
||||
__entry->blocks, __entry->blksz, __entry->data_flags,
|
||||
__entry->can_retune, __entry->doing_retune,
|
||||
__entry->retune_now, __entry->need_retune,
|
||||
__entry->hold_retune, __entry->retune_period)
|
||||
);
|
||||
|
||||
TRACE_EVENT(mmc_request_done,
|
||||
|
||||
TP_PROTO(struct mmc_host *host, struct mmc_request *mrq),
|
||||
|
||||
TP_ARGS(host, mrq),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, cmd_opcode)
|
||||
__field(int, cmd_err)
|
||||
__array(u32, cmd_resp, 4)
|
||||
__field(unsigned int, cmd_retries)
|
||||
__field(u32, stop_opcode)
|
||||
__field(int, stop_err)
|
||||
__array(u32, stop_resp, 4)
|
||||
__field(unsigned int, stop_retries)
|
||||
__field(u32, sbc_opcode)
|
||||
__field(int, sbc_err)
|
||||
__array(u32, sbc_resp, 4)
|
||||
__field(unsigned int, sbc_retries)
|
||||
__field(unsigned int, bytes_xfered)
|
||||
__field(int, data_err)
|
||||
__field(unsigned int, can_retune)
|
||||
__field(unsigned int, doing_retune)
|
||||
__field(unsigned int, retune_now)
|
||||
__field(int, need_retune)
|
||||
__field(int, hold_retune)
|
||||
__field(unsigned int, retune_period)
|
||||
__field(struct mmc_request *, mrq)
|
||||
__string(name, mmc_hostname(host))
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cmd_opcode = mrq->cmd->opcode;
|
||||
__entry->cmd_err = mrq->cmd->error;
|
||||
memcpy(__entry->cmd_resp, mrq->cmd->resp, 4);
|
||||
__entry->cmd_retries = mrq->cmd->retries;
|
||||
__entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0;
|
||||
__entry->stop_err = mrq->stop ? mrq->stop->error : 0;
|
||||
__entry->stop_resp[0] = mrq->stop ? mrq->stop->resp[0] : 0;
|
||||
__entry->stop_resp[1] = mrq->stop ? mrq->stop->resp[1] : 0;
|
||||
__entry->stop_resp[2] = mrq->stop ? mrq->stop->resp[2] : 0;
|
||||
__entry->stop_resp[3] = mrq->stop ? mrq->stop->resp[3] : 0;
|
||||
__entry->stop_retries = mrq->stop ? mrq->stop->retries : 0;
|
||||
__entry->sbc_opcode = mrq->sbc ? mrq->sbc->opcode : 0;
|
||||
__entry->sbc_err = mrq->sbc ? mrq->sbc->error : 0;
|
||||
__entry->sbc_resp[0] = mrq->sbc ? mrq->sbc->resp[0] : 0;
|
||||
__entry->sbc_resp[1] = mrq->sbc ? mrq->sbc->resp[1] : 0;
|
||||
__entry->sbc_resp[2] = mrq->sbc ? mrq->sbc->resp[2] : 0;
|
||||
__entry->sbc_resp[3] = mrq->sbc ? mrq->sbc->resp[3] : 0;
|
||||
__entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0;
|
||||
__entry->bytes_xfered = mrq->data ? mrq->data->bytes_xfered : 0;
|
||||
__entry->data_err = mrq->data ? mrq->data->error : 0;
|
||||
__entry->can_retune = host->can_retune;
|
||||
__entry->doing_retune = host->doing_retune;
|
||||
__entry->retune_now = host->retune_now;
|
||||
__entry->need_retune = host->need_retune;
|
||||
__entry->hold_retune = host->hold_retune;
|
||||
__entry->retune_period = host->retune_period;
|
||||
__assign_str(name, mmc_hostname(host));
|
||||
__entry->mrq = mrq;
|
||||
),
|
||||
|
||||
TP_printk("%s: end struct mmc_request[%p]: "
|
||||
"cmd_opcode=%u cmd_err=%d cmd_resp=0x%x 0x%x 0x%x 0x%x "
|
||||
"cmd_retries=%u stop_opcode=%u stop_err=%d "
|
||||
"stop_resp=0x%x 0x%x 0x%x 0x%x stop_retries=%u "
|
||||
"sbc_opcode=%u sbc_err=%d sbc_resp=0x%x 0x%x 0x%x 0x%x "
|
||||
"sbc_retries=%u bytes_xfered=%u data_err=%d "
|
||||
"can_retune=%u doing_retune=%u retune_now=%u need_retune=%d "
|
||||
"hold_retune=%d retune_period=%u",
|
||||
__get_str(name), __entry->mrq,
|
||||
__entry->cmd_opcode, __entry->cmd_err,
|
||||
__entry->cmd_resp[0], __entry->cmd_resp[1],
|
||||
__entry->cmd_resp[2], __entry->cmd_resp[3],
|
||||
__entry->cmd_retries,
|
||||
__entry->stop_opcode, __entry->stop_err,
|
||||
__entry->stop_resp[0], __entry->stop_resp[1],
|
||||
__entry->stop_resp[2], __entry->stop_resp[3],
|
||||
__entry->stop_retries,
|
||||
__entry->sbc_opcode, __entry->sbc_err,
|
||||
__entry->sbc_resp[0], __entry->sbc_resp[1],
|
||||
__entry->sbc_resp[2], __entry->sbc_resp[3],
|
||||
__entry->sbc_retries,
|
||||
__entry->bytes_xfered, __entry->data_err,
|
||||
__entry->can_retune, __entry->doing_retune,
|
||||
__entry->retune_now, __entry->need_retune,
|
||||
__entry->hold_retune, __entry->retune_period)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_MMC_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
Loading…
Reference in New Issue