Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 844ce9f2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mmc-fixes-for-3.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC fixes from Chris Ball:
 - sdhci-acpi: Fix initial runtime PM status, add more ACPI IDs
 - atmel-mci, omap_hsmmc: DT handling fixes
 - esdhc-imx: Fix SDIO IRQs, fix multiblock reads (both h/w errata)

* tag 'mmc-fixes-for-3.10-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: omap_hsmmc: Skip platform_get_resource_byname() for dt case
  mmc: omap_hsmmc: convert to dma_request_slave_channel_compat
  mmc: omap_hsmmc: Fix the DT pbias workaround for MMC controllers 2 to 5
  mmc: sdhci-pci: add more device ids
  mmc: sdhci-acpi: add more device ids
  mmc: sdhci-acpi: fix initial runtime pm status
  mmc: atmel-mci: convert to dma_request_slave_channel_compat()
  mmc: sdhci-esdhc-imx: fix multiblock reads on i.MX53
  mmc: sdhci-esdhc-imx: Fix SDIO interrupts
parents bb762929 4a29b559
Loading
Loading
Loading
Loading
+12 −13
Original line number Original line Diff line number Diff line
@@ -2230,10 +2230,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
	mmc_free_host(slot->mmc);
	mmc_free_host(slot->mmc);
}
}


static bool atmci_filter(struct dma_chan *chan, void *slave)
static bool atmci_filter(struct dma_chan *chan, void *pdata)
{
{
	struct mci_dma_data	*sl = slave;
	struct mci_platform_data *sl_pdata = pdata;
	struct mci_dma_data *sl;


	if (!sl_pdata)
		return false;

	sl = sl_pdata->dma_slave;
	if (sl && find_slave_dev(sl) == chan->device->dev) {
	if (sl && find_slave_dev(sl) == chan->device->dev) {
		chan->private = slave_data_ptr(sl);
		chan->private = slave_data_ptr(sl);
		return true;
		return true;
@@ -2245,24 +2250,18 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
static bool atmci_configure_dma(struct atmel_mci *host)
static bool atmci_configure_dma(struct atmel_mci *host)
{
{
	struct mci_platform_data	*pdata;
	struct mci_platform_data	*pdata;
	dma_cap_mask_t mask;


	if (host == NULL)
	if (host == NULL)
		return false;
		return false;


	pdata = host->pdev->dev.platform_data;
	pdata = host->pdev->dev.platform_data;


	if (!pdata)
		return false;

	if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) {
		dma_cap_mask_t mask;

		/* Try to grab a DMA channel */
	dma_cap_zero(mask);
	dma_cap_zero(mask);
	dma_cap_set(DMA_SLAVE, mask);
	dma_cap_set(DMA_SLAVE, mask);
		host->dma.chan =

			dma_request_channel(mask, atmci_filter, pdata->dma_slave);
	host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
	}
							  &host->pdev->dev, "rxtx");
	if (!host->dma.chan) {
	if (!host->dma.chan) {
		dev_warn(&host->pdev->dev, "no DMA channel available\n");
		dev_warn(&host->pdev->dev, "no DMA channel available\n");
		return false;
		return false;
+32 −19
Original line number Original line Diff line number Diff line
@@ -161,6 +161,7 @@ struct omap_hsmmc_host {
	 */
	 */
	struct	regulator	*vcc;
	struct	regulator	*vcc;
	struct	regulator	*vcc_aux;
	struct	regulator	*vcc_aux;
	int			pbias_disable;
	void	__iomem		*base;
	void	__iomem		*base;
	resource_size_t		mapbase;
	resource_size_t		mapbase;
	spinlock_t		irq_lock; /* Prevent races with irq handler */
	spinlock_t		irq_lock; /* Prevent races with irq handler */
@@ -255,11 +256,11 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
	if (!host->vcc)
	if (!host->vcc)
		return 0;
		return 0;
	/*
	/*
	 * With DT, never turn OFF the regulator. This is because
	 * With DT, never turn OFF the regulator for MMC1. This is because
	 * the pbias cell programming support is still missing when
	 * the pbias cell programming support is still missing when
	 * booting with Device tree
	 * booting with Device tree
	 */
	 */
	if (dev->of_node && !vdd)
	if (host->pbias_disable && !vdd)
		return 0;
		return 0;


	if (mmc_slot(host).before_set_reg)
	if (mmc_slot(host).before_set_reg)
@@ -1520,10 +1521,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
			(ios->vdd == DUAL_VOLT_OCR_BIT) &&
			(ios->vdd == DUAL_VOLT_OCR_BIT) &&
			/*
			/*
			 * With pbias cell programming missing, this
			 * With pbias cell programming missing, this
			 * can't be allowed when booting with device
			 * can't be allowed on MMC1 when booting with device
			 * tree.
			 * tree.
			 */
			 */
			!host->dev->of_node) {
			!host->pbias_disable) {
				/*
				/*
				 * The mmc_select_voltage fn of the core does
				 * The mmc_select_voltage fn of the core does
				 * not seem to set the power_mode to
				 * not seem to set the power_mode to
@@ -1871,6 +1872,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)


	omap_hsmmc_context_save(host);
	omap_hsmmc_context_save(host);


	/* This can be removed once we support PBIAS with DT */
	if (host->dev->of_node && host->mapbase == 0x4809c000)
		host->pbias_disable = 1;

	host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
	host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
	/*
	/*
	 * MMC can still work without debounce clock.
	 * MMC can still work without debounce clock.
@@ -1906,6 +1911,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)


	omap_hsmmc_conf_bus_power(host);
	omap_hsmmc_conf_bus_power(host);


	if (!pdev->dev.of_node) {
		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
		res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
		if (!res) {
		if (!res) {
			dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
			dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
@@ -1921,18 +1927,25 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
			goto err_irq;
			goto err_irq;
		}
		}
		rx_req = res->start;
		rx_req = res->start;
	}


	dma_cap_zero(mask);
	dma_cap_zero(mask);
	dma_cap_set(DMA_SLAVE, mask);
	dma_cap_set(DMA_SLAVE, mask);


	host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req);
	host->rx_chan =
		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
						 &rx_req, &pdev->dev, "rx");

	if (!host->rx_chan) {
	if (!host->rx_chan) {
		dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
		dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
		ret = -ENXIO;
		ret = -ENXIO;
		goto err_irq;
		goto err_irq;
	}
	}


	host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req);
	host->tx_chan =
		dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
						 &tx_req, &pdev->dev, "tx");

	if (!host->tx_chan) {
	if (!host->tx_chan) {
		dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
		dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
		ret = -ENXIO;
		ret = -ENXIO;
+60 −9
Original line number Original line Diff line number Diff line
@@ -87,6 +87,12 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = {
	.enable_dma = sdhci_acpi_enable_dma,
	.enable_dma = sdhci_acpi_enable_dma,
};
};


static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
	.caps2   = MMC_CAP2_HC_ERASE_SZ,
	.flags   = SDHCI_ACPI_RUNTIME_PM,
};

static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
@@ -94,23 +100,67 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
	.pm_caps = MMC_PM_KEEP_POWER,
	.pm_caps = MMC_PM_KEEP_POWER,
};
};


static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
};

struct sdhci_acpi_uid_slot {
	const char *hid;
	const char *uid;
	const struct sdhci_acpi_slot *slot;
};

static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
	{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
	{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
	{ "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
	{ "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
	{ "PNP0D40"  },
	{ },
};

static const struct acpi_device_id sdhci_acpi_ids[] = {
static const struct acpi_device_id sdhci_acpi_ids[] = {
	{ "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio },
	{ "80860F14" },
	{ "INT33BB"  },
	{ "INT33C6"  },
	{ "PNP0D40"  },
	{ "PNP0D40"  },
	{ },
	{ },
};
};
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);


static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid)
static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid,
								const char *uid)
{
{
	const struct acpi_device_id *id;
	const struct sdhci_acpi_uid_slot *u;


	for (id = sdhci_acpi_ids; id->id[0]; id++)
	for (u = sdhci_acpi_uids; u->hid; u++) {
		if (!strcmp(id->id, hid))
		if (strcmp(u->hid, hid))
			return (const struct sdhci_acpi_slot *)id->driver_data;
			continue;
		if (!u->uid)
			return u->slot;
		if (uid && !strcmp(u->uid, uid))
			return u->slot;
	}
	return NULL;
	return NULL;
}
}


static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
							 const char *hid)
{
	const struct sdhci_acpi_slot *slot;
	struct acpi_device_info *info;
	const char *uid = NULL;
	acpi_status status;

	status = acpi_get_object_info(handle, &info);
	if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID))
		uid = info->unique_id.string;

	slot = sdhci_acpi_get_slot_by_ids(hid, uid);

	kfree(info);
	return slot;
}

static int sdhci_acpi_probe(struct platform_device *pdev)
static int sdhci_acpi_probe(struct platform_device *pdev)
{
{
	struct device *dev = &pdev->dev;
	struct device *dev = &pdev->dev;
@@ -148,7 +198,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)


	c = sdhci_priv(host);
	c = sdhci_priv(host);
	c->host = host;
	c->host = host;
	c->slot = sdhci_acpi_get_slot(hid);
	c->slot = sdhci_acpi_get_slot(handle, hid);
	c->pdev = pdev;
	c->pdev = pdev;
	c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
	c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);


@@ -202,6 +252,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
		goto err_free;
		goto err_free;


	if (c->use_runtime_pm) {
	if (c->use_runtime_pm) {
		pm_runtime_set_active(dev);
		pm_suspend_ignore_children(dev, 1);
		pm_suspend_ignore_children(dev, 1);
		pm_runtime_set_autosuspend_delay(dev, 50);
		pm_runtime_set_autosuspend_delay(dev, 50);
		pm_runtime_use_autosuspend(dev);
		pm_runtime_use_autosuspend(dev);
+37 −4
Original line number Original line Diff line number Diff line
@@ -85,6 +85,12 @@ struct pltfm_imx_data {
	struct clk *clk_ipg;
	struct clk *clk_ipg;
	struct clk *clk_ahb;
	struct clk *clk_ahb;
	struct clk *clk_per;
	struct clk *clk_per;
	enum {
		NO_CMD_PENDING,      /* no multiblock command pending*/
		MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
		WAIT_FOR_INT,        /* sent CMD12, waiting for response INT */
	} multiblock_status;

};
};


static struct platform_device_id imx_esdhc_devtype[] = {
static struct platform_device_id imx_esdhc_devtype[] = {
@@ -154,6 +160,8 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i


static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct pltfm_imx_data *imx_data = pltfm_host->priv;
	u32 val = readl(host->ioaddr + reg);
	u32 val = readl(host->ioaddr + reg);


	if (unlikely(reg == SDHCI_CAPABILITIES)) {
	if (unlikely(reg == SDHCI_CAPABILITIES)) {
@@ -175,6 +183,18 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
			val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
			val |= SDHCI_INT_ADMA_ERROR;
			val |= SDHCI_INT_ADMA_ERROR;
		}
		}

		/*
		 * mask off the interrupt we get in response to the manually
		 * sent CMD12
		 */
		if ((imx_data->multiblock_status == WAIT_FOR_INT) &&
		    ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) {
			val &= ~SDHCI_INT_RESPONSE;
			writel(SDHCI_INT_RESPONSE, host->ioaddr +
						   SDHCI_INT_STATUS);
			imx_data->multiblock_status = NO_CMD_PENDING;
		}
	}
	}


	return val;
	return val;
@@ -211,6 +231,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
			v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
			v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
			v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
			writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);

			if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS)
			{
				/* send a manual CMD12 with RESPTYP=none */
				data = MMC_STOP_TRANSMISSION << 24 |
				       SDHCI_CMD_ABORTCMD << 16;
				writel(data, host->ioaddr + SDHCI_TRANSFER_MODE);
				imx_data->multiblock_status = WAIT_FOR_INT;
			}
	}
	}


	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
@@ -277,11 +306,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
		}
		}
		return;
		return;
	case SDHCI_COMMAND:
	case SDHCI_COMMAND:
		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
		if (host->cmd->opcode == MMC_STOP_TRANSMISSION)
		     host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
	            (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
			val |= SDHCI_CMD_ABORTCMD;
			val |= SDHCI_CMD_ABORTCMD;


		if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
		    (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
			imx_data->multiblock_status = MULTIBLK_IN_PROCESS;

		if (is_imx6q_usdhc(imx_data))
		if (is_imx6q_usdhc(imx_data))
			writel(val << 16,
			writel(val << 16,
			       host->ioaddr + SDHCI_TRANSFER_MODE);
			       host->ioaddr + SDHCI_TRANSFER_MODE);
@@ -324,8 +355,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
		/*
		/*
		 * Do not touch buswidth bits here. This is done in
		 * Do not touch buswidth bits here. This is done in
		 * esdhc_pltfm_bus_width.
		 * esdhc_pltfm_bus_width.
		 * Do not touch the D3CD bit either which is used for the
		 * SDIO interrupt errata workaround.
		 */
		 */
		mask = 0xffff & ~ESDHC_CTRL_BUSWIDTH_MASK;
		mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);


		esdhc_clrset_le(host, mask, new_val, reg);
		esdhc_clrset_le(host, mask, new_val, reg);
		return;
		return;
+54 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,9 @@
 */
 */
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0	0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0	0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1	0x880a
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1	0x880a
#define PCI_DEVICE_ID_INTEL_BYT_EMMC	0x0f14
#define PCI_DEVICE_ID_INTEL_BYT_SDIO	0x0f15
#define PCI_DEVICE_ID_INTEL_BYT_SD	0x0f16


/*
/*
 * PCI registers
 * PCI registers
@@ -304,6 +307,33 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
	.probe_slot	= pch_hc_probe_slot,
	.probe_slot	= pch_hc_probe_slot,
};
};


static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
	slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
	return 0;
}

static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
{
	slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
	return 0;
}

static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
	.allow_runtime_pm = true,
	.probe_slot	= byt_emmc_probe_slot,
};

static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
	.quirks2	= SDHCI_QUIRK2_HOST_OFF_CARD_ON,
	.allow_runtime_pm = true,
	.probe_slot	= byt_sdio_probe_slot,
};

static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
};

/* O2Micro extra registers */
/* O2Micro extra registers */
#define O2_SD_LOCK_WP		0xD3
#define O2_SD_LOCK_WP		0xD3
#define O2_SD_MULTI_VCC3V	0xEE
#define O2_SD_MULTI_VCC3V	0xEE
@@ -855,6 +885,30 @@ static const struct pci_device_id pci_ids[] = {
		.driver_data	= (kernel_ulong_t)&sdhci_intel_pch_sdio,
		.driver_data	= (kernel_ulong_t)&sdhci_intel_pch_sdio,
	},
	},


	{
		.vendor		= PCI_VENDOR_ID_INTEL,
		.device		= PCI_DEVICE_ID_INTEL_BYT_EMMC,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_emmc,
	},

	{
		.vendor		= PCI_VENDOR_ID_INTEL,
		.device		= PCI_DEVICE_ID_INTEL_BYT_SDIO,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_sdio,
	},

	{
		.vendor		= PCI_VENDOR_ID_INTEL,
		.device		= PCI_DEVICE_ID_INTEL_BYT_SD,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
		.driver_data	= (kernel_ulong_t)&sdhci_intel_byt_sd,
	},

	{
	{
		.vendor		= PCI_VENDOR_ID_O2,
		.vendor		= PCI_VENDOR_ID_O2,
		.device		= PCI_DEVICE_ID_O2_8120,
		.device		= PCI_DEVICE_ID_O2_8120,