From 356c21aec7dcc9046d27c43323cf031e794c4a75 Mon Sep 17 00:00:00 2001 From: Haijun Zhang Date: Mon, 16 Sep 2013 19:25:26 +0800 Subject: mmc: Add support to get voltage from device-tree Add function to support get voltage from device-tree. If there are voltage-range specified in device-tree node, this function will parse it and return the available voltage mask. Signed-off-by: Haijun Zhang Change-Id: I3ec8dd6cb0c628ada3533163c602c9b752a45657 Reviewed-on: http://git.am.freescale.net:8181/4764 Tested-by: Review Code-CDREVIEW Reviewed-by: Xie Xiaobo-R63061 Reviewed-by: Rivera Jose-B46482 diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt index bd9be0b..b7943f3 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt @@ -19,6 +19,9 @@ Optional properties: "bus-width = <1>" property. - sdhci,auto-cmd12: specifies that a controller can only handle auto CMD12. + - voltage-ranges : two cells are required, first cell specifies minimum + slot voltage (mV), second cell specifies maximum slot voltage (mV). + Several ranges could be specified. Example: @@ -29,4 +32,5 @@ sdhci@2e000 { interrupt-parent = <&ipic>; /* Filled in by U-Boot */ clock-frequency = <0>; + voltage-ranges = <3300 3300>; }; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index e74504e..395e558 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1068,6 +1069,49 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) } EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); +#ifdef CONFIG_OF + +/** + * mmc_of_parse_voltage - return mask of supported voltages + * @np: The device node need to be parsed. + * @mask: mask of voltages available for MMC/SD/SDIO + * + * 1. Return zero on success. + * 2. Return negative errno: voltage-range is invalid. + */ +int mmc_of_parse_voltage(struct device_node *np, u32 *mask) +{ + const u32 *voltage_ranges; + int num_ranges, i; + + voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); + num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; + if (!voltage_ranges || !num_ranges) { + pr_info("%s: voltage-ranges unspecified\n", np->full_name); + return -EINVAL; + } + + for (i = 0; i < num_ranges; i++) { + const int j = i * 2; + u32 ocr_mask; + + ocr_mask = mmc_vddrange_to_ocrmask( + be32_to_cpu(voltage_ranges[j]), + be32_to_cpu(voltage_ranges[j + 1])); + if (!ocr_mask) { + pr_err("%s: voltage-range #%d is invalid\n", + np->full_name, i); + return -EINVAL; + } + *mask |= ocr_mask; + } + + return 0; +} +EXPORT_SYMBOL(mmc_of_parse_voltage); + +#endif /* CONFIG_OF */ + #ifdef CONFIG_REGULATOR /** diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 7ade389..47586c6 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -212,13 +212,16 @@ int sdhci_pltfm_register(struct platform_device *pdev, struct sdhci_pltfm_data *pdata) { struct sdhci_host *host; + struct device_node *np; int ret = 0; + np = pdev->dev.of_node; host = sdhci_pltfm_init(pdev, pdata); if (IS_ERR(host)) return PTR_ERR(host); sdhci_get_of_property(pdev); + mmc_of_parse_voltage(np, &host->ocr_mask); ret = sdhci_add_host(host); if (ret) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 644b4fc..79db375 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3031,6 +3031,9 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_MAX_CURRENT_MULTIPLIER; } + if (host->ocr_mask) + ocr_avail = host->ocr_mask; + mmc->ocr_avail = ocr_avail; mmc->ocr_avail_sdio = ocr_avail; if (host->ocr_avail_sdio) diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 5bf7c22..cfddace 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -198,6 +198,8 @@ static inline void mmc_claim_host(struct mmc_host *host) __mmc_claim_host(host, NULL); } +struct device_node; extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); +extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask); #endif /* LINUX_MMC_CORE_H */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 5bd07a1..fd33e44 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -175,6 +175,7 @@ struct sdhci_host { unsigned int ocr_avail_sdio; /* OCR bit masks */ unsigned int ocr_avail_sd; unsigned int ocr_avail_mmc; + u32 ocr_mask; /* available voltages */ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ -- cgit v0.10.2