Merge tag 'mmc-v4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC fixes from Ulf Hansson: "A couple of MMC host fixes intended for v4.12 rc3: - sdhci-xenon: Don't free data for phy allocated by devm* - sdhci-iproc: Suppress spurious interrupts - cavium: Fix probing race with regulator - cavium: Prevent crash with incomplete DT - cavium-octeon: Use proper GPIO name for power control - cavium-octeon: Fix interrupt enable code" * tag 'mmc-v4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: sdhci-iproc: suppress spurious interrupt with Multiblock read mmc: cavium: Fix probing race with regulator of/platform: Make of_platform_device_destroy globally visible mmc: cavium: Prevent crash with incomplete DT mmc: cavium-octeon: Use proper GPIO name for power control mmc: cavium-octeon: Fix interrupt enable code mmc: sdhci-xenon: kill xenon_clean_phy()
This commit is contained in:
@@ -108,7 +108,7 @@ static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
|
|||||||
static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
|
static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
|
||||||
{
|
{
|
||||||
writeq(val, host->base + MIO_EMM_INT(host));
|
writeq(val, host->base + MIO_EMM_INT(host));
|
||||||
if (!host->dma_active || (host->dma_active && !host->has_ciu3))
|
if (!host->has_ciu3)
|
||||||
writeq(val, host->base + MIO_EMM_INT_EN(host));
|
writeq(val, host->base + MIO_EMM_INT_EN(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +267,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev,
|
host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev,
|
||||||
"power-gpios",
|
"power",
|
||||||
GPIOD_OUT_HIGH);
|
GPIOD_OUT_HIGH);
|
||||||
if (IS_ERR(host->global_pwr_gpiod)) {
|
if (IS_ERR(host->global_pwr_gpiod)) {
|
||||||
dev_err(&pdev->dev, "Invalid power GPIO\n");
|
dev_err(&pdev->dev, "Invalid power GPIO\n");
|
||||||
@@ -288,11 +288,20 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Error populating slots\n");
|
dev_err(&pdev->dev, "Error populating slots\n");
|
||||||
octeon_mmc_set_shared_power(host, 0);
|
octeon_mmc_set_shared_power(host, 0);
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||||
|
if (host->slot[i])
|
||||||
|
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||||
|
if (host->slot_pdev[i])
|
||||||
|
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int octeon_mmc_remove(struct platform_device *pdev)
|
static int octeon_mmc_remove(struct platform_device *pdev)
|
||||||
|
|||||||
@@ -146,6 +146,12 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
for (i = 0; i < CAVIUM_MAX_MMC; i++) {
|
||||||
|
if (host->slot[i])
|
||||||
|
cvm_mmc_of_slot_remove(host->slot[i]);
|
||||||
|
if (host->slot_pdev[i])
|
||||||
|
of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
|
||||||
|
}
|
||||||
clk_disable_unprepare(host->clk);
|
clk_disable_unprepare(host->clk);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -839,14 +839,14 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||||||
cvm_mmc_reset_bus(slot);
|
cvm_mmc_reset_bus(slot);
|
||||||
if (host->global_pwr_gpiod)
|
if (host->global_pwr_gpiod)
|
||||||
host->set_shared_power(host, 0);
|
host->set_shared_power(host, 0);
|
||||||
else
|
else if (!IS_ERR(mmc->supply.vmmc))
|
||||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MMC_POWER_UP:
|
case MMC_POWER_UP:
|
||||||
if (host->global_pwr_gpiod)
|
if (host->global_pwr_gpiod)
|
||||||
host->set_shared_power(host, 1);
|
host->set_shared_power(host, 1);
|
||||||
else
|
else if (!IS_ERR(mmc->supply.vmmc))
|
||||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
|
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -968,20 +968,15 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
|
ret = mmc_regulator_get_supply(mmc);
|
||||||
if (IS_ERR(mmc->supply.vmmc)) {
|
if (ret == -EPROBE_DEFER)
|
||||||
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
|
return ret;
|
||||||
return -EPROBE_DEFER;
|
|
||||||
/*
|
/*
|
||||||
* Legacy Octeon firmware has no regulator entry, fall-back to
|
* Legacy Octeon firmware has no regulator entry, fall-back to
|
||||||
* a hard-coded voltage to get a sane OCR.
|
* a hard-coded voltage to get a sane OCR.
|
||||||
*/
|
*/
|
||||||
|
if (IS_ERR(mmc->supply.vmmc))
|
||||||
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||||
} else {
|
|
||||||
ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
|
|
||||||
if (ret > 0)
|
|
||||||
mmc->ocr_avail = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Common MMC bindings */
|
/* Common MMC bindings */
|
||||||
ret = mmc_of_parse(mmc);
|
ret = mmc_of_parse(mmc);
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ static const struct sdhci_iproc_data iproc_cygnus_data = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
|
static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
|
||||||
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
|
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
||||||
|
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
|
||||||
.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
|
.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
|
||||||
.ops = &sdhci_iproc_ops,
|
.ops = &sdhci_iproc_ops,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -787,14 +787,6 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xenon_clean_phy(struct sdhci_host *host)
|
|
||||||
{
|
|
||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
||||||
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
|
||||||
|
|
||||||
kfree(priv->phy_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
||||||
const char *phy_name)
|
const char *phy_name)
|
||||||
{
|
{
|
||||||
@@ -819,11 +811,7 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
|
return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
|
||||||
if (ret)
|
|
||||||
xenon_clean_phy(host);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
|
int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ static int xenon_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
err = xenon_sdhc_prepare(host);
|
err = xenon_sdhc_prepare(host);
|
||||||
if (err)
|
if (err)
|
||||||
goto clean_phy_param;
|
goto err_clk;
|
||||||
|
|
||||||
err = sdhci_add_host(host);
|
err = sdhci_add_host(host);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -496,8 +496,6 @@ static int xenon_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
remove_sdhc:
|
remove_sdhc:
|
||||||
xenon_sdhc_unprepare(host);
|
xenon_sdhc_unprepare(host);
|
||||||
clean_phy_param:
|
|
||||||
xenon_clean_phy(host);
|
|
||||||
err_clk:
|
err_clk:
|
||||||
clk_disable_unprepare(pltfm_host->clk);
|
clk_disable_unprepare(pltfm_host->clk);
|
||||||
free_pltfm:
|
free_pltfm:
|
||||||
@@ -510,8 +508,6 @@ static int xenon_remove(struct platform_device *pdev)
|
|||||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
|
|
||||||
xenon_clean_phy(host);
|
|
||||||
|
|
||||||
sdhci_remove_host(host, 0);
|
sdhci_remove_host(host, 0);
|
||||||
|
|
||||||
xenon_sdhc_unprepare(host);
|
xenon_sdhc_unprepare(host);
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ struct xenon_priv {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
|
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
|
||||||
void xenon_clean_phy(struct sdhci_host *host);
|
|
||||||
int xenon_phy_parse_dt(struct device_node *np,
|
int xenon_phy_parse_dt(struct device_node *np,
|
||||||
struct sdhci_host *host);
|
struct sdhci_host *host);
|
||||||
void xenon_soc_pad_ctrl(struct sdhci_host *host,
|
void xenon_soc_pad_ctrl(struct sdhci_host *host,
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ static int __init of_platform_default_populate_init(void)
|
|||||||
arch_initcall_sync(of_platform_default_populate_init);
|
arch_initcall_sync(of_platform_default_populate_init);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int of_platform_device_destroy(struct device *dev, void *data)
|
int of_platform_device_destroy(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
/* Do not touch devices not populated from the device tree */
|
/* Do not touch devices not populated from the device tree */
|
||||||
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
|
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
|
||||||
@@ -544,6 +544,7 @@ static int of_platform_device_destroy(struct device *dev, void *data)
|
|||||||
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
|
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(of_platform_device_destroy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* of_platform_depopulate() - Remove devices populated from device tree
|
* of_platform_depopulate() - Remove devices populated from device tree
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ extern struct platform_device *of_platform_device_create(struct device_node *np,
|
|||||||
const char *bus_id,
|
const char *bus_id,
|
||||||
struct device *parent);
|
struct device *parent);
|
||||||
|
|
||||||
|
extern int of_platform_device_destroy(struct device *dev, void *data);
|
||||||
extern int of_platform_bus_probe(struct device_node *root,
|
extern int of_platform_bus_probe(struct device_node *root,
|
||||||
const struct of_device_id *matches,
|
const struct of_device_id *matches,
|
||||||
struct device *parent);
|
struct device *parent);
|
||||||
|
|||||||
Reference in New Issue
Block a user