diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 15:15:53 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 15:15:53 (GMT) |
commit | a8e4def604a9affa04fdd4efa0692da1385ffa3f (patch) | |
tree | ab7c02cbfbd72cc4fe60674cd5da7e3d01035f00 /drivers/mmc/host/sdhci-st.c | |
parent | d429a3639ca967ce2f35e3e8d4e70caec7149ded (diff) | |
parent | c83c8737e3edb33f60101d2d7692675d0cb6bdf1 (diff) | |
download | linux-a8e4def604a9affa04fdd4efa0692da1385ffa3f.tar.xz |
Merge tag 'mmc-v3.17-1' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson:
"Me and Chris Ball decided to try out using my MMC tree as the primary
one, to simplify handling of patches.
This pull does thus contains all the MMC patches for 3.17 rc1, no pull
from Chris this time.
Details:
MMC core:
- forward compatibility for eMMC
- fix some blacklisted cards with broken secure discard
MMC host:
- mmci: Add support for Qualcomm variant
- mmci: Fix regression for arm_variant
- sdhci: Various fixes and cleanups
- sdhci: Improve external VDD regulator support
- sdhci: Support for DDR50 1.8V mode for BayTrail
- sdhci-st: Add driver for ST SDHCI controller
- sh-mmcif: DMA fixes
- omap_hsmmc: Add support for SDIO interrupts
- sdhci-pci: Add support for Intel Quark X1000
- dw_mmc: Update the reset sequence
- s3cmci: port DMA code to dmaengine API"
* tag 'mmc-v3.17-1' of git://git.linaro.org/people/ulf.hansson/mmc: (67 commits)
mmc: dw_mmc: modify the dt-binding for removing slot-node and supports-highspeed
mmc: dw_mmc: Slot quirk "disable-wp" is deprecated.
mmc: mmci: Reverse IRQ handling for the arm_variant
mmc: mmci: Move all CMD irq handling to mmci_cmd_irq()
mmc: mmci: Remove redundant check of status for DATA irq
mmc: dw_mmc: change to use recommended reset procedure
mmc: sdhci-pxav3: Use devm_* managed helpers
mmc: tmio: Configure DMA slave bus width
mmc: sh_mmcif: Configure DMA slave bus width
mmc: sh_mmcif: Fix DMA slave address configuration
mmc: sh_mmcif: Document DT bindings
mmc: sdhci-pci: remove PCI PM functions in suspend/resume callback
mmc: Do not advertise secure discard if it is blacklisted
mmc: sdhci-msm: Get COMPILE_TEST support
mmc: sdhci-msm: Remove unnecessary header file inclusion
mmc: sdhci-msm: Fix the binding example
mmc: sdhci: add DDR50 1.8V mode support for BayTrail eMMC Controller
mmc: sdhci: Preset value not supported in Baytrail eMMC
mmc: MMC_USDHI6ROL0 should depend on HAS_DMA
mmc: MMC_SH_MMCIF should depend on HAS_DMA
...
Diffstat (limited to 'drivers/mmc/host/sdhci-st.c')
-rw-r--r-- | drivers/mmc/host/sdhci-st.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c new file mode 100644 index 0000000..328f348 --- /dev/null +++ b/drivers/mmc/host/sdhci-st.c @@ -0,0 +1,176 @@ +/* + * Support for SDHCI on STMicroelectronics SoCs + * + * Copyright (C) 2014 STMicroelectronics Ltd + * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> + * Contributors: Peter Griffin <peter.griffin@linaro.org> + * + * Based on sdhci-cns3xxx.c + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/mmc/host.h> + +#include "sdhci-pltfm.h" + +static u32 sdhci_st_readl(struct sdhci_host *host, int reg) +{ + u32 ret; + + switch (reg) { + case SDHCI_CAPABILITIES: + ret = readl_relaxed(host->ioaddr + reg); + /* Support 3.3V and 1.8V */ + ret &= ~SDHCI_CAN_VDD_300; + break; + default: + ret = readl_relaxed(host->ioaddr + reg); + } + return ret; +} + +static const struct sdhci_ops sdhci_st_ops = { + .get_max_clock = sdhci_pltfm_clk_get_max_clock, + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .read_l = sdhci_st_readl, + .reset = sdhci_reset, +}; + +static const struct sdhci_pltfm_data sdhci_st_pdata = { + .ops = &sdhci_st_ops, + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +}; + + +static int sdhci_st_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct clk *clk; + int ret = 0; + u16 host_version; + + clk = devm_clk_get(&pdev->dev, "mmc"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Peripheral clk not found\n"); + return PTR_ERR(clk); + } + + host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0); + if (IS_ERR(host)) { + dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); + return PTR_ERR(host); + } + + ret = mmc_of_parse(host->mmc); + + if (ret) { + dev_err(&pdev->dev, "Failed mmc_of_parse\n"); + return ret; + } + + clk_prepare_enable(clk); + + pltfm_host = sdhci_priv(host); + pltfm_host->clk = clk; + + ret = sdhci_add_host(host); + if (ret) { + dev_err(&pdev->dev, "Failed sdhci_add_host\n"); + goto err_out; + } + + platform_set_drvdata(pdev, host); + + host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); + + dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n", + ((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT), + ((host_version & SDHCI_VENDOR_VER_MASK) >> + SDHCI_VENDOR_VER_SHIFT)); + + return 0; + +err_out: + clk_disable_unprepare(clk); + sdhci_pltfm_free(pdev); + + return ret; +} + +static int sdhci_st_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + clk_disable_unprepare(pltfm_host->clk); + + return sdhci_pltfm_unregister(pdev); +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_st_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + int ret = sdhci_suspend_host(host); + + if (ret) + goto out; + + clk_disable_unprepare(pltfm_host->clk); +out: + return ret; +} + +static int sdhci_st_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + clk_prepare_enable(pltfm_host->clk); + + return sdhci_resume_host(host); +} +#endif + +static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume); + +static const struct of_device_id st_sdhci_match[] = { + { .compatible = "st,sdhci" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, st_sdhci_match); + +static struct platform_driver sdhci_st_driver = { + .probe = sdhci_st_probe, + .remove = sdhci_st_remove, + .driver = { + .name = "sdhci-st", + .pm = &sdhci_st_pmops, + .of_match_table = of_match_ptr(st_sdhci_match), + }, +}; + +module_platform_driver(sdhci_st_driver); + +MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs"); +MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:st-sdhci"); |