aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDong Aisheng <b29396@freescale.com>2013-09-13 07:11:35 -0400
committerChris Ball <cjb@laptop.org>2013-09-26 07:57:28 -0400
commitad93220de7da1f5bd8f9e4be1f1eeefba5eed0ad (patch)
tree59112a988cc32fafddc87b36eaa9bd17f180f85b
parent0322191e62984b94d1b2ae5ff322112e1fa1ef1a (diff)
mmc: sdhci-esdhc-imx: change pinctrl state according to uhs mode
Without proper pinctrl state, the card may not be able to work on high speed stablely. e.g. SDR104. This patch add pinctrl state switch code according to different uhs mode include 100mhz sate, 200mhz sate and normal state (50Mhz and below). Signed-off-by: Dong Aisheng <b29396@freescale.com> Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c96
-rw-r--r--include/linux/platform_data/mmc-esdhc-imx.h4
2 files changed, 99 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index f906c206901d..ed00d6ddd5fd 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -53,6 +53,10 @@
53 53
54#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64 54#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
55 55
56/* pinctrl state */
57#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
58#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
59
56/* 60/*
57 * Our interpretation of the SDHCI_HOST_CONTROL register 61 * Our interpretation of the SDHCI_HOST_CONTROL register
58 */ 62 */
@@ -94,6 +98,9 @@ struct pltfm_imx_data {
94 u32 scratchpad; 98 u32 scratchpad;
95 enum imx_esdhc_type devtype; 99 enum imx_esdhc_type devtype;
96 struct pinctrl *pinctrl; 100 struct pinctrl *pinctrl;
101 struct pinctrl_state *pins_default;
102 struct pinctrl_state *pins_100mhz;
103 struct pinctrl_state *pins_200mhz;
97 struct esdhc_platform_data boarddata; 104 struct esdhc_platform_data boarddata;
98 struct clk *clk_ipg; 105 struct clk *clk_ipg;
99 struct clk *clk_ahb; 106 struct clk *clk_ahb;
@@ -693,6 +700,62 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
693 return ret; 700 return ret;
694} 701}
695 702
703static int esdhc_change_pinstate(struct sdhci_host *host,
704 unsigned int uhs)
705{
706 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
707 struct pltfm_imx_data *imx_data = pltfm_host->priv;
708 struct pinctrl_state *pinctrl;
709
710 dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
711
712 if (IS_ERR(imx_data->pinctrl) ||
713 IS_ERR(imx_data->pins_default) ||
714 IS_ERR(imx_data->pins_100mhz) ||
715 IS_ERR(imx_data->pins_200mhz))
716 return -EINVAL;
717
718 switch (uhs) {
719 case MMC_TIMING_UHS_SDR50:
720 pinctrl = imx_data->pins_100mhz;
721 break;
722 case MMC_TIMING_UHS_SDR104:
723 pinctrl = imx_data->pins_200mhz;
724 break;
725 default:
726 /* back to default state for other legacy timing */
727 pinctrl = imx_data->pins_default;
728 }
729
730 return pinctrl_select_state(imx_data->pinctrl, pinctrl);
731}
732
733static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
734{
735 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
736 struct pltfm_imx_data *imx_data = pltfm_host->priv;
737
738 switch (uhs) {
739 case MMC_TIMING_UHS_SDR12:
740 imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
741 break;
742 case MMC_TIMING_UHS_SDR25:
743 imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
744 break;
745 case MMC_TIMING_UHS_SDR50:
746 imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
747 break;
748 case MMC_TIMING_UHS_SDR104:
749 imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
750 break;
751 case MMC_TIMING_UHS_DDR50:
752 imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
753 break;
754 }
755
756 return esdhc_change_pinstate(host, uhs);
757}
758
696static const struct sdhci_ops sdhci_esdhc_ops = { 759static const struct sdhci_ops sdhci_esdhc_ops = {
697 .read_l = esdhc_readl_le, 760 .read_l = esdhc_readl_le,
698 .read_w = esdhc_readw_le, 761 .read_w = esdhc_readw_le,
@@ -704,6 +767,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
704 .get_min_clock = esdhc_pltfm_get_min_clock, 767 .get_min_clock = esdhc_pltfm_get_min_clock,
705 .get_ro = esdhc_pltfm_get_ro, 768 .get_ro = esdhc_pltfm_get_ro,
706 .platform_bus_width = esdhc_pltfm_bus_width, 769 .platform_bus_width = esdhc_pltfm_bus_width,
770 .set_uhs_signaling = esdhc_set_uhs_signaling,
707 .platform_execute_tuning = esdhc_executing_tuning, 771 .platform_execute_tuning = esdhc_executing_tuning,
708}; 772};
709 773
@@ -746,6 +810,11 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
746 810
747 of_property_read_u32(np, "max-frequency", &boarddata->f_max); 811 of_property_read_u32(np, "max-frequency", &boarddata->f_max);
748 812
813 if (of_find_property(np, "no-1-8-v", NULL))
814 boarddata->support_vsel = false;
815 else
816 boarddata->support_vsel = true;
817
749 return 0; 818 return 0;
750} 819}
751#else 820#else
@@ -808,12 +877,20 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
808 clk_prepare_enable(imx_data->clk_ipg); 877 clk_prepare_enable(imx_data->clk_ipg);
809 clk_prepare_enable(imx_data->clk_ahb); 878 clk_prepare_enable(imx_data->clk_ahb);
810 879
811 imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 880 imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
812 if (IS_ERR(imx_data->pinctrl)) { 881 if (IS_ERR(imx_data->pinctrl)) {
813 err = PTR_ERR(imx_data->pinctrl); 882 err = PTR_ERR(imx_data->pinctrl);
814 goto disable_clk; 883 goto disable_clk;
815 } 884 }
816 885
886 imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
887 PINCTRL_STATE_DEFAULT);
888 if (IS_ERR(imx_data->pins_default)) {
889 err = PTR_ERR(imx_data->pins_default);
890 dev_err(mmc_dev(host->mmc), "could not get default state\n");
891 goto disable_clk;
892 }
893
817 host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 894 host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
818 895
819 if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) 896 if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
@@ -890,6 +967,23 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
890 break; 967 break;
891 } 968 }
892 969
970 /* sdr50 and sdr104 needs work on 1.8v signal voltage */
971 if ((boarddata->support_vsel) && is_imx6q_usdhc(imx_data)) {
972 imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
973 ESDHC_PINCTRL_STATE_100MHZ);
974 imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
975 ESDHC_PINCTRL_STATE_200MHZ);
976 if (IS_ERR(imx_data->pins_100mhz) ||
977 IS_ERR(imx_data->pins_200mhz)) {
978 dev_warn(mmc_dev(host->mmc),
979 "could not get ultra high speed state, work on normal mode\n");
980 /* fall back to not support uhs by specify no 1.8v quirk */
981 host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
982 }
983 } else {
984 host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
985 }
986
893 err = sdhci_add_host(host); 987 err = sdhci_add_host(host);
894 if (err) 988 if (err)
895 goto disable_clk; 989 goto disable_clk;
diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h
index d44912d81578..a0f5a8f9b3bc 100644
--- a/include/linux/platform_data/mmc-esdhc-imx.h
+++ b/include/linux/platform_data/mmc-esdhc-imx.h
@@ -10,6 +10,8 @@
10#ifndef __ASM_ARCH_IMX_ESDHC_H 10#ifndef __ASM_ARCH_IMX_ESDHC_H
11#define __ASM_ARCH_IMX_ESDHC_H 11#define __ASM_ARCH_IMX_ESDHC_H
12 12
13#include <linux/types.h>
14
13enum wp_types { 15enum wp_types {
14 ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ 16 ESDHC_WP_NONE, /* no WP, neither controller nor gpio */
15 ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ 17 ESDHC_WP_CONTROLLER, /* mmc controller internal WP */
@@ -32,6 +34,7 @@ enum cd_types {
32 * @cd_gpio: gpio for card_detect interrupt 34 * @cd_gpio: gpio for card_detect interrupt
33 * @wp_type: type of write_protect method (see wp_types enum above) 35 * @wp_type: type of write_protect method (see wp_types enum above)
34 * @cd_type: type of card_detect method (see cd_types enum above) 36 * @cd_type: type of card_detect method (see cd_types enum above)
37 * @support_vsel: indicate it supports 1.8v switching
35 */ 38 */
36 39
37struct esdhc_platform_data { 40struct esdhc_platform_data {
@@ -41,5 +44,6 @@ struct esdhc_platform_data {
41 enum cd_types cd_type; 44 enum cd_types cd_type;
42 int max_bus_width; 45 int max_bus_width;
43 unsigned int f_max; 46 unsigned int f_max;
47 bool support_vsel;
44}; 48};
45#endif /* __ASM_ARCH_IMX_ESDHC_H */ 49#endif /* __ASM_ARCH_IMX_ESDHC_H */