* [PATCH v4 0/3] mmc: dw_mmc: add dw_mmc-k3
@ 2013-12-11 14:02 Zhangfei Gao
2013-12-11 14:02 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
` (2 more replies)
0 siblings, 3 replies; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-11 14:02 UTC (permalink / raw)
To: linux-arm-kernel
v4:
Follow Arnd's suggestion abstracting specific tuning to clock,
also because new version ip use different method and not use same tuning registers.
0001 acked by Jaehoon
v3:
0001:
Put set/clear_bit DW_MMC_CARD_PRESENT in dw_mci_get_cd,
Since dw_mci_request will check DW_MMC_CARD_PRESENT before sending cmd
0002:
Follow suggestion from Chris, Kumar and Seungwon
Sync to latest mmc-next, which is 3.12-rc2
Remove enum dw_mci_k3_type etc
v2:
Follow Jaehoon's suggestion
Use slot-gpio.c handle cd pin
Move table out to dts
other suggestion
Zhangfei Gao (3):
mmc: dw_mmc: use slot-gpio to handle cd pin
mmc: dw_mmc: add dw_mmc-k3 for k3 platform
clk: hisilicon: add hi3620_mmc_clks
.../bindings/arm/hisilicon/hisilicon.txt | 14 ++
.../devicetree/bindings/clock/hi3620-clock.txt | 1 +
.../devicetree/bindings/mmc/k3-dw-mshc.txt | 51 ++++
drivers/clk/hisilicon/clk-hi3620.c | 266 ++++++++++++++++++++
drivers/mmc/host/Kconfig | 10 +
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-k3.c | 136 ++++++++++
drivers/mmc/host/dw_mmc.c | 48 +++-
include/dt-bindings/clock/hi3620-clock.h | 5 +
9 files changed, 519 insertions(+), 13 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
create mode 100644 drivers/mmc/host/dw_mmc-k3.c
--
1.7.9.5
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2013-12-11 14:02 [PATCH v4 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
@ 2013-12-11 14:02 ` Zhangfei Gao
2013-12-11 14:02 ` [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform Zhangfei Gao
2013-12-11 14:02 ` [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks Zhangfei Gao
2 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-11 14:02 UTC (permalink / raw)
To: linux-arm-kernel
Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bce0deec362..a776f24f4311 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -36,6 +36,7 @@
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/mmc/slot-gpio.h>
#include "dw_mmc.h"
@@ -1032,20 +1033,26 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
+ int gpio_cd = !mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
+ else if (!IS_ERR_VALUE(gpio_cd))
+ present = !!gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
- if (present)
+ if (present) {
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is present\n");
- else
+ } else {
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is not present\n");
+ }
return present;
}
@@ -1926,10 +1933,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Card change detected */
slot->last_detect_state = present;
- /* Mark card as present if applicable */
- if (present != 0)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clean up queue if present */
mrq = slot->mrq;
if (mrq) {
@@ -1977,8 +1980,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Power down slot */
if (present == 0) {
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clear down the FIFO */
dw_mci_fifo_reset(host);
#ifdef CONFIG_MMC_DW_IDMAC
@@ -2079,6 +2080,26 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
return gpio;
}
+
+/* find the cd gpio for a given slot; or -1 if none specified */
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+ int gpio;
+
+ if (!np)
+ return;
+
+ gpio = of_get_named_gpio(np, "cd-gpios", 0);
+
+ /* Having a missing entry is valid; return silently */
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (mmc_gpio_request_cd(mmc, gpio, 0))
+ dev_warn(dev, "gpio [%d] request failed\n", gpio);
+}
#else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
@@ -2096,6 +2117,11 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
return -EINVAL;
}
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ return;
+}
#endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2197,12 +2223,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- if (dw_mci_get_cd(mmc))
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
+ dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
ret = mmc_add_host(mmc);
if (ret)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 14:02 [PATCH v4 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2013-12-11 14:02 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
@ 2013-12-11 14:02 ` Zhangfei Gao
2013-12-11 14:49 ` Arnd Bergmann
2013-12-11 14:02 ` [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks Zhangfei Gao
2 siblings, 1 reply; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-11 14:02 UTC (permalink / raw)
To: linux-arm-kernel
Add dw_mmc-k3.c for k3v2, support sd/emmc
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Tested-by: Zhigang Wang <brooke.wangzhigang@huawei.com>
---
.../devicetree/bindings/mmc/k3-dw-mshc.txt | 51 ++++++++
drivers/mmc/host/Kconfig | 10 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-k3.c | 136 ++++++++++++++++++++
4 files changed, 198 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
create mode 100644 drivers/mmc/host/dw_mmc-k3.c
diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
new file mode 100644
index 000000000000..d816b89c386a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
@@ -0,0 +1,51 @@
+* Hisilicon specific extensions to the Synopsys Designware Mobile
+ Storage Host Controller
+
+Read synopsys-dw-mshc.txt for more details
+
+The Synopsys designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Hisilicon specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be one of the following.
+ - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions.
+* clk-table-num: should be number of clks in clk-table required by each mmc timing
+* clk-table: should clock list required by each mmc timing
+
+Example:
+
+ /* for Hi3620 */
+
+ /* SoC portion */
+ dwmmc_0: dwmmc0 at fcd03000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd03000 0x1000>;
+ interrupts = <0 16 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmc_clock HI3620_SD_CIUCLK>, <&clock HI3620_DDRC_PER_CLK>;
+ clock-names = "ciu", "biu";
+ clk-table-num = <8>;
+ clk-table =
+ <13000000 50000000 0 0 13000000 50000000 0 100000000>;
+ };
+
+ /* Board portion */
+ dwmmc0 at fcd03000 {
+ num-slots = <1>;
+ vmmc-supply = <&ldo12>;
+ fifo-depth = <0x100>;
+ supports-highspeed;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>;
+ slot at 0 {
+ reg = <0>;
+ bus-width = <4>;
+ disable-wp;
+ cd-gpios = <&gpio10 3 0>;
+ };
+ };
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fc5099e44b2..45aaa2de0f58 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -575,6 +575,16 @@ config MMC_DW_SOCFPGA
This selects support for Altera SoCFPGA specific extensions to the
Synopsys DesignWare Memory Card Interface driver.
+config MMC_DW_K3
+ tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ select MMC_DW_IDMAC
+ help
+ This selects support for Hisilicon K3 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on Hisilicon K3 SoC's.
+
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c41d0c364509..64f5f8d35839 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_SOCFPGA) += dw_mmc-socfpga.o
+obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c
new file mode 100644
index 000000000000..08fd7d7bbb23
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-k3.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/of_address.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define MAX_NUMS 10
+struct dw_mci_k3_priv_data {
+ u32 clk_table[MAX_NUMS];
+};
+
+static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+
+ clk_set_rate(host->ciu_clk, priv->clk_table[ios->timing]);
+}
+
+static int dw_mci_k3_parse_dt(struct dw_mci *host)
+{
+ struct dw_mci_k3_priv_data *priv;
+ int ret = 0, num = 0;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+ host->priv = priv;
+
+ ret = of_property_read_u32(host->dev->of_node, "clk-table-num", &num);
+ if (ret < 0) {
+ dev_err(host->dev, "not found clk-table-num\n");
+ return ret;
+ }
+ if (num > MAX_NUMS) {
+ dev_err(host->dev, "clk-table-num too big\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(host->dev->of_node, "clk-table",
+ priv->clk_table, num);
+ if (ret) {
+ dev_err(host->dev, "not found clk-table\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static unsigned long k3_dwmmc_caps[4] = {
+ MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED,
+ MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED,
+ 0,
+ 0,
+};
+
+static const struct dw_mci_drv_data k3_drv_data = {
+ .caps = k3_dwmmc_caps,
+ .set_ios = dw_mci_k3_set_ios,
+ .parse_dt = dw_mci_k3_parse_dt,
+};
+
+static const struct of_device_id dw_mci_k3_match[] = {
+ { .compatible = "hisilicon,hi4511-dw-mshc",
+ .data = &k3_drv_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_k3_match);
+
+static int dw_mci_k3_probe(struct platform_device *pdev)
+{
+ const struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+
+ match = of_match_node(dw_mci_k3_match, pdev->dev.of_node);
+ drv_data = match->data;
+
+ return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static int dw_mci_k3_suspend(struct device *dev)
+{
+ struct dw_mci *host = dev_get_drvdata(dev);
+
+ if (!IS_ERR(host->ciu_clk))
+ clk_disable_unprepare(host->ciu_clk);
+
+ return dw_mci_suspend(host);
+}
+
+static int dw_mci_k3_resume(struct device *dev)
+{
+ struct dw_mci *host = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = clk_prepare_enable(host->ciu_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable ciu clock\n");
+ return ret;
+ }
+
+ return dw_mci_resume(host);
+}
+
+SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
+
+static struct platform_driver dw_mci_k3_pltfm_driver = {
+ .probe = dw_mci_k3_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = "dwmmc_k3",
+ .of_match_table = dw_mci_k3_match,
+ .pm = &dw_mci_k3_pmops,
+ },
+};
+
+module_platform_driver(dw_mci_k3_pltfm_driver);
+
+MODULE_DESCRIPTION("K3 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-k3");
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks
2013-12-11 14:02 [PATCH v4 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2013-12-11 14:02 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2013-12-11 14:02 ` [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform Zhangfei Gao
@ 2013-12-11 14:02 ` Zhangfei Gao
2013-12-11 14:44 ` Arnd Bergmann
2 siblings, 1 reply; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-11 14:02 UTC (permalink / raw)
To: linux-arm-kernel
hi3620_mmc_clks is added to handle mmc clock specifically on hi3620
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
.../bindings/arm/hisilicon/hisilicon.txt | 14 ++
.../devicetree/bindings/clock/hi3620-clock.txt | 1 +
drivers/clk/hisilicon/clk-hi3620.c | 262 ++++++++++++++++++++
include/dt-bindings/clock/hi3620-clock.h | 5 +
4 files changed, 282 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 8c7a4653508d..df0a452b8526 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -30,3 +30,17 @@ Example:
resume-offset = <0x308>;
reboot-offset = <0x4>;
};
+
+PCTRL: Peripheral misc control register
+
+Required Properties:
+- compatible: "hisilicon,pctrl"
+- reg: Address and size of pctrl.
+
+Example:
+
+ /* for Hi3620 */
+ pctrl: pctrl at fca09000 {
+ compatible = "hisilicon,pctrl";
+ reg = <0xfca09000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
index 4b71ab41be53..dad6269f52c5 100644
--- a/Documentation/devicetree/bindings/clock/hi3620-clock.txt
+++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt
@@ -7,6 +7,7 @@ Required Properties:
- compatible: should be one of the following.
- "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
+ - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc.
- reg: physical base address of the controller and length of memory mapped
region.
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index f24ad6a3a797..eeb89b7a3507 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -240,3 +240,265 @@ static void __init hi3620_clk_init(struct device_node *np)
base);
}
CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init);
+
+struct hisi_mmc_clock {
+ unsigned int id;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ u32 clken_reg;
+ u32 clken_bit;
+ u32 div_reg;
+ u32 div_off;
+ u32 div_bits;
+ u32 drv_reg;
+ u32 drv_off;
+ u32 drv_bits;
+ u32 sam_reg;
+ u32 sam_off;
+ u32 sam_bits;
+};
+
+struct clk_mmc {
+ struct clk_hw hw;
+ u32 id;
+ void __iomem *clken_reg;
+ u32 clken_bit;
+ void __iomem *div_reg;
+ u32 div_off;
+ u32 div_bits;
+ void __iomem *drv_reg;
+ u32 drv_off;
+ u32 drv_bits;
+ void __iomem *sam_reg;
+ u32 sam_off;
+ u32 sam_bits;
+};
+
+#define to_mmc(_hw) container_of(_hw, struct clk_mmc, hw)
+
+static struct hisi_mmc_clock hi3620_mmc_clks[] __initdata = {
+ { HI3620_SD_CIUCLK, "sd_bclk1", "sd_clk", CLK_SET_RATE_PARENT, 0x1f8, 0, 0x1f8, 1, 3, 0x1f8, 4, 4, 0x1f8, 8, 4},
+ { HI3620_MMC_CIUCLK1, "mmc_bclk1", "mmc_clk1", CLK_SET_RATE_PARENT, 0x1f8, 12, 0x1f8, 13, 3, 0x1f8, 16, 4, 0x1f8, 20, 4},
+ { HI3620_MMC_CIUCLK2, "mmc_bclk2", "mmc_clk2", CLK_SET_RATE_PARENT, 0x1f8, 24, 0x1f8, 25, 3, 0x1f8, 28, 4, 0x1fc, 0, 4},
+ { HI3620_MMC_CIUCLK3, "mmc_bclk3", "mmc_clk3", CLK_SET_RATE_PARENT, 0x1fc, 4, 0x1fc, 5, 3, 0x1fc, 8, 4, 0x1fc, 12, 4},
+};
+
+static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ switch (parent_rate) {
+ case 26000000:
+ return 13000000;
+ case 180000000:
+ return 25000000;
+ case 360000000:
+ return 50000000;
+ case 720000000:
+ return 100000000;
+ default:
+ return parent_rate;
+ }
+}
+
+static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ unsigned long best = 0;
+
+ if (rate <= 13000000) {
+ rate = 13000000;
+ best = 26000000;
+ } else if (rate <= 25000000) {
+ rate = 25000000;
+ best = 180000000;
+ } else if (rate <= 50000000) {
+ rate = 50000000;
+ best = 360000000;
+ } else if (rate <= 100000000) {
+ rate = 100000000;
+ best = 720000000;
+ }
+ *best_parent_rate = best;
+ return rate;
+}
+
+static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
+{
+ u32 i;
+
+ if (para >= 0) {
+ for (i = 0; i < len; i++) {
+ if (para % 2)
+ val |= 1 << (off + i);
+ else
+ val &= ~(1 << (off + i));
+ para = para >> 1;
+ }
+ }
+ return val;
+}
+
+static int mmc_clk_set_timing(struct clk_hw *hw, unsigned long rate)
+{
+ struct clk_mmc *mclk = to_mmc(hw);
+ unsigned long flags;
+ u32 sam, drv, div, val;
+ static DEFINE_SPINLOCK(mmc_clk_lock);
+
+ switch (rate) {
+ case 13000000:
+ sam = 3;
+ drv = 1;
+ div = 1;
+ break;
+ case 25000000:
+ sam = 13;
+ drv = 6;
+ div = 6;
+ break;
+ case 50000000:
+ sam = 3;
+ drv = 6;
+ div = 6;
+ break;
+ case 100000000:
+ sam = 6;
+ drv = 4;
+ div = 6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mmc_clk_lock, flags);
+
+ val = readl_relaxed(mclk->clken_reg);
+ val &= ~(1 << mclk->clken_bit);
+ writel_relaxed(val, mclk->clken_reg);
+
+ val = readl_relaxed(mclk->sam_reg);
+ val = mmc_clk_delay(val, sam, mclk->sam_off, mclk->sam_bits);
+ writel_relaxed(val, mclk->sam_reg);
+
+ val = readl_relaxed(mclk->drv_reg);
+ val = mmc_clk_delay(val, drv, mclk->drv_off, mclk->drv_bits);
+ writel_relaxed(val, mclk->drv_reg);
+
+ val = readl_relaxed(mclk->div_reg);
+ val = mmc_clk_delay(val, div, mclk->div_off, mclk->div_bits);
+ writel_relaxed(val, mclk->div_reg);
+
+ val = readl_relaxed(mclk->clken_reg);
+ val |= 1 << mclk->clken_bit;
+ writel_relaxed(val, mclk->clken_reg);
+
+ spin_unlock_irqrestore(&mmc_clk_lock, flags);
+
+ return 0;
+}
+
+static int mmc_clk_prepare(struct clk_hw *hw)
+{
+ struct clk_mmc *mclk = to_mmc(hw);
+ unsigned long rate;
+
+ if (mclk->id == HI3620_SD_CIUCLK)
+ rate = 13000000;
+ else
+ rate = 25000000;
+
+ return mmc_clk_set_timing(hw, rate);
+}
+
+static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return mmc_clk_set_timing(hw, rate);
+}
+
+static struct clk_ops clk_mmc_ops = {
+ .prepare = mmc_clk_prepare,
+ .determine_rate = mmc_clk_determine_rate,
+ .set_rate = mmc_clk_set_rate,
+ .recalc_rate = mmc_clk_recalc_rate,
+};
+
+static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk,
+ void __iomem *base, struct device_node *np)
+{
+ struct clk_mmc *mclk;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ mclk = kzalloc(sizeof(*mclk), GFP_KERNEL);
+ if (!mclk) {
+ pr_err("%s: fail to allocate mmc clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = mmc_clk->name;
+ init.ops = &clk_mmc_ops;
+ init.flags = mmc_clk->flags | CLK_IS_BASIC;
+ init.parent_names = (mmc_clk->parent_name ? &mmc_clk->parent_name : NULL);
+ init.num_parents = (mmc_clk->parent_name ? 1 : 0);
+ mclk->hw.init = &init;
+
+ mclk->id = mmc_clk->id;
+ mclk->clken_reg = base + mmc_clk->clken_reg;
+ mclk->clken_bit = mmc_clk->clken_bit;
+ mclk->div_reg = base + mmc_clk->div_reg;
+ mclk->div_off = mmc_clk->div_off;
+ mclk->div_bits = mmc_clk->div_bits;
+ mclk->drv_reg = base + mmc_clk->drv_reg;
+ mclk->drv_off = mmc_clk->drv_off;
+ mclk->drv_bits = mmc_clk->drv_bits;
+ mclk->sam_reg = base + mmc_clk->sam_reg;
+ mclk->sam_off = mmc_clk->sam_off;
+ mclk->sam_bits = mmc_clk->sam_bits;
+
+ clk = clk_register(NULL, &mclk->hw);
+ if (WARN_ON(IS_ERR(clk)))
+ kfree(mclk);
+ return clk;
+}
+
+static void __init hi3620_mmc_clk_init(struct device_node *node)
+{
+ void __iomem *base;
+ int i, num = ARRAY_SIZE(hi3620_mmc_clks);
+ struct clk_onecell_data *clk_data;
+
+ if (!node) {
+ pr_err("failed to find pctrl node in DTS\n");
+ return;
+ }
+
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("failed to map pctrl\n");
+ return;
+ }
+
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (WARN_ON(!clk_data))
+ return;
+
+ clk_data->clks = kzalloc(sizeof(struct clk *) * num, GFP_KERNEL);
+ if (!clk_data->clks) {
+ pr_err("%s: fail to allocate mmc clk\n", __func__);
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
+ clk_data->clks[mmc_clk->id] =
+ hisi_register_clk_mmc(mmc_clk, base, node);
+ }
+
+ clk_data->clk_num = num;
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+CLK_OF_DECLARE(hi3620_mmc_clk, "hisilicon,hi3620-mmc-clock", hi3620_mmc_clk_init);
diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h
index 6eaa6a45e110..21b9d0e2eb0c 100644
--- a/include/dt-bindings/clock/hi3620-clock.h
+++ b/include/dt-bindings/clock/hi3620-clock.h
@@ -147,6 +147,11 @@
#define HI3620_MMC_CLK3 217
#define HI3620_MCU_CLK 218
+#define HI3620_SD_CIUCLK 0
+#define HI3620_MMC_CIUCLK1 1
+#define HI3620_MMC_CIUCLK2 2
+#define HI3620_MMC_CIUCLK3 3
+
#define HI3620_NR_CLKS 219
#endif /* __DTS_HI3620_CLOCK_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks
2013-12-11 14:02 ` [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks Zhangfei Gao
@ 2013-12-11 14:44 ` Arnd Bergmann
2013-12-11 15:40 ` zhangfei
0 siblings, 1 reply; 22+ messages in thread
From: Arnd Bergmann @ 2013-12-11 14:44 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 11 December 2013, Zhangfei Gao wrote:
> +PCTRL: Peripheral misc control register
> +
> +Required Properties:
> +- compatible: "hisilicon,pctrl"
> +- reg: Address and size of pctrl.
> +
> +Example:
> +
> + /* for Hi3620 */
> + pctrl: pctrl at fca09000 {
> + compatible = "hisilicon,pctrl";
> + reg = <0xfca09000 0x1000>;
> + };
It seems you are missing the clock specific parts of the binding:
You should document the required value of #clock-cells as well as
the possible values for the clock specifier.
Arnd
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 14:02 ` [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform Zhangfei Gao
@ 2013-12-11 14:49 ` Arnd Bergmann
2013-12-11 15:36 ` zhangfei
0 siblings, 1 reply; 22+ messages in thread
From: Arnd Bergmann @ 2013-12-11 14:49 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 11 December 2013, Zhangfei Gao wrote:
> Add dw_mmc-k3.c for k3v2, support sd/emmc
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> Tested-by: Zhigang Wang <brooke.wangzhigang@huawei.com>
> ---
> .../devicetree/bindings/mmc/k3-dw-mshc.txt | 51 ++++++++
> drivers/mmc/host/Kconfig | 10 ++
> drivers/mmc/host/Makefile | 1 +
> drivers/mmc/host/dw_mmc-k3.c | 136 ++++++++++++++++++++
> 4 files changed, 198 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
> create mode 100644 drivers/mmc/host/dw_mmc-k3.c
>
> diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
> new file mode 100644
> index 000000000000..d816b89c386a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
> @@ -0,0 +1,51 @@
> +* Hisilicon specific extensions to the Synopsys Designware Mobile
> + Storage Host Controller
> +
> +Read synopsys-dw-mshc.txt for more details
> +
> +The Synopsys designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
> +differences between the core Synopsys dw mshc controller properties described
> +by synopsys-dw-mshc.txt and the properties used by the Hisilicon specific
> +extensions to the Synopsys Designware Mobile Storage Host Controller.
> +
> +Required Properties:
> +
> +* compatible: should be one of the following.
> + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions.
> +* clk-table-num: should be number of clks in clk-table required by each mmc timing
> +* clk-table: should clock list required by each mmc timing
I have not seen "clk-table" and "clk-table-num" before. Are these standard
properties? What are the units that are used here, what does the index mean?
Arnd
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 14:49 ` Arnd Bergmann
@ 2013-12-11 15:36 ` zhangfei
2013-12-11 15:53 ` zhangfei
2013-12-11 20:12 ` Arnd Bergmann
0 siblings, 2 replies; 22+ messages in thread
From: zhangfei @ 2013-12-11 15:36 UTC (permalink / raw)
To: linux-arm-kernel
On 12/11/2013 10:49 PM, Arnd Bergmann wrote:
> On Wednesday 11 December 2013, Zhangfei Gao wrote:
>> +Required Properties:
>> +
>> +* compatible: should be one of the following.
>> + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions.
>> +* clk-table-num: should be number of clks in clk-table required by each mmc timing
>> +* clk-table: should clock list required by each mmc timing
>
> I have not seen "clk-table" and "clk-table-num" before. Are these standard
> properties? What are the units that are used here, what does the index mean?
>
"clk-table" and "clk-table-num" are private properties.
Instead simply on/off, the ip need different ciu clock for each timing mode.
Take emmc as example,
clk-table-num = <8>;
clk-table =
<13000000 50000000 0 0 13000000 50000000 0 100000000>;
MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M,
MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M
"clk-table" list all clocks to be set in all supported timing one by one.
"clk-table-num" is the table number, since not find function getting
table number.
For example, next version will support MMC_TIMING_MMC_HS200 mode, the
clk-table-num = <9> with 9 clocks in the "clk-table"
Thanks
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks
2013-12-11 14:44 ` Arnd Bergmann
@ 2013-12-11 15:40 ` zhangfei
0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2013-12-11 15:40 UTC (permalink / raw)
To: linux-arm-kernel
On 12/11/2013 10:44 PM, Arnd Bergmann wrote:
> On Wednesday 11 December 2013, Zhangfei Gao wrote:
>> +PCTRL: Peripheral misc control register
>> +
>> +Required Properties:
>> +- compatible: "hisilicon,pctrl"
>> +- reg: Address and size of pctrl.
>> +
>> +Example:
>> +
>> + /* for Hi3620 */
>> + pctrl: pctrl at fca09000 {
>> + compatible = "hisilicon,pctrl";
>> + reg = <0xfca09000 0x1000>;
>> + };
>
> It seems you are missing the clock specific parts of the binding:
> You should document the required value of #clock-cells as well as
> the possible values for the clock specifier.
>
It is reuse Documentation/devicetree/bindings/clock/hi3620-clock.txt via
adding hisilicon,hi3620-mmc-clock"
- compatible: should be one of the following.
- "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC.
+ - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc.
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
Thanks
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 15:36 ` zhangfei
@ 2013-12-11 15:53 ` zhangfei
2013-12-11 20:12 ` Arnd Bergmann
1 sibling, 0 replies; 22+ messages in thread
From: zhangfei @ 2013-12-11 15:53 UTC (permalink / raw)
To: linux-arm-kernel
On 12/11/2013 11:36 PM, zhangfei wrote:
>
>
> On 12/11/2013 10:49 PM, Arnd Bergmann wrote:
>> On Wednesday 11 December 2013, Zhangfei Gao wrote:
>
>>> +Required Properties:
>>> +
>>> +* compatible: should be one of the following.
>>> + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific
>>> extentions.
>>> +* clk-table-num: should be number of clks in clk-table required by
>>> each mmc timing
>>> +* clk-table: should clock list required by each mmc timing
>>
>> I have not seen "clk-table" and "clk-table-num" before. Are these
>> standard
>> properties? What are the units that are used here, what does the index
>> mean?
>>
>
> "clk-table" and "clk-table-num" are private properties.
> Instead simply on/off, the ip need different ciu clock for each timing
> mode.
> Take emmc as example,
> clk-table-num = <8>;
> clk-table =
My bad, this is for sd.
> <13000000 50000000 0 0 13000000 50000000 0 100000000>;
<25000000 0 50000000 25000000 50000000 100000000 0 50000000>;
> MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M,
> MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M
>
> "clk-table" list all clocks to be set in all supported timing one by one.
> "clk-table-num" is the table number, since not find function getting
> table number.
> For example, next version will support MMC_TIMING_MMC_HS200 mode, the
> clk-table-num = <9> with 9 clocks in the "clk-table"
>
> Thanks
>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 15:36 ` zhangfei
2013-12-11 15:53 ` zhangfei
@ 2013-12-11 20:12 ` Arnd Bergmann
2013-12-12 13:27 ` zhangfei
1 sibling, 1 reply; 22+ messages in thread
From: Arnd Bergmann @ 2013-12-11 20:12 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 11 December 2013, zhangfei wrote:
> >
> > I have not seen "clk-table" and "clk-table-num" before. Are these standard
> > properties? What are the units that are used here, what does the index mean?
> >
>
> "clk-table" and "clk-table-num" are private properties.
> Instead simply on/off, the ip need different ciu clock for each timing mode.
But aren't the times fixed for each mode? Why do you need to specify them in
the DT? I would expect that the clock rates for each mode are set in the
MMC and SD specifications. When you call clk_set_rate(), it should normally
be enough to ask for the clock you actually want and let the clk subsystem
figure out how to set up the parents and multipliers on the way.
> Take emmc as example,
> clk-table-num = <8>;
> clk-table =
> <13000000 50000000 0 0 13000000 50000000 0 100000000>;
> MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M,
> MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M
>
> "clk-table" list all clocks to be set in all supported timing one by one.
> "clk-table-num" is the table number, since not find function getting
> table number.
> For example, next version will support MMC_TIMING_MMC_HS200 mode, the
> clk-table-num = <9> with 9 clocks in the "clk-table"
If you have a property with an array, you can use of_find_property()
to get to the 'struct property' and then read the 'length' member
of that struct, or you can use of_property_for_each_u32() to iterate
through each value.
While I still hope that you don't even need this array as per the reasoning
above, if you actually need it, you should specify exactly what each
value means, such as
1. CIU clock rate in HZ for 20MHz SPI mode operation
2. CIU clock rate in HZ for 25MHz SD card operation
3. CIU clock rate in HZ for 26MHz MMC card operation
4. CIU clock rate in HZ for 50MHz SD card operation
...
Arnd
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-11 20:12 ` Arnd Bergmann
@ 2013-12-12 13:27 ` zhangfei
2013-12-12 14:13 ` Zhangfei Gao
2013-12-12 20:40 ` Arnd Bergmann
0 siblings, 2 replies; 22+ messages in thread
From: zhangfei @ 2013-12-12 13:27 UTC (permalink / raw)
To: linux-arm-kernel
Dear Arnd
On 12/12/2013 04:12 AM, Arnd Bergmann wrote:
> On Wednesday 11 December 2013, zhangfei wrote:
>>>
>>> I have not seen "clk-table" and "clk-table-num" before. Are these standard
>>> properties? What are the units that are used here, what does the index mean?
>>>
>>
>> "clk-table" and "clk-table-num" are private properties.
>> Instead simply on/off, the ip need different ciu clock for each timing mode.
>
> But aren't the times fixed for each mode? Why do you need to specify them in
> the DT? I would expect that the clock rates for each mode are set in the
> MMC and SD specifications. When you call clk_set_rate(), it should normally
> be enough to ask for the clock you actually want and let the clk subsystem
> figure out how to set up the parents and multipliers on the way.
Yes. that's will be perfect.
However, currently this ip still has no such capability.
1. Input rate for init are diferent for different controller, not the
init 400K, some are 13M, others are 25M, since different clock source.
This can be easily solved by clock-freq-init = <25000000>
2. There is maxmum limit, also can be easily solved by define CLK_MAX.
3. However some mode can not use the max speed from ios->clock
for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may
be reached, at least currently.
>
>> Take emmc as example,
>> clk-table-num = <8>;
>> clk-table =
>> <13000000 50000000 0 0 13000000 50000000 0 100000000>;
>> MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M,
>> MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M
>>
>> "clk-table" list all clocks to be set in all supported timing one by one.
>> "clk-table-num" is the table number, since not find function getting
>> table number.
>> For example, next version will support MMC_TIMING_MMC_HS200 mode, the
>> clk-table-num = <9> with 9 clocks in the "clk-table"
>
> If you have a property with an array, you can use of_find_property()
> to get to the 'struct property' and then read the 'length' member
> of that struct, or you can use of_property_for_each_u32() to iterate
> through each value.
Great, this works.
>
> While I still hope that you don't even need this array as per the reasoning
> above, if you actually need it, you should specify exactly what each
> value means, such as
>
> 1. CIU clock rate in HZ for 20MHz SPI mode operation
> 2. CIU clock rate in HZ for 25MHz SD card operation
> 3. CIU clock rate in HZ for 26MHz MMC card operation
> 4. CIU clock rate in HZ for 50MHz SD card operation
> ...
How about this desc
* clock-freq-table: should be the frequency (in Hz) array of the ciu
clock
in each supported timing.
1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode
2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode
3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode
5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode
6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode
7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode
8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode
Thanks
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-12 13:27 ` zhangfei
@ 2013-12-12 14:13 ` Zhangfei Gao
2013-12-12 20:40 ` Arnd Bergmann
1 sibling, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-12 14:13 UTC (permalink / raw)
To: linux-arm-kernel
Add dw_mmc-k3.c for k3v2, support sd/emmc
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: Zhigang Wang <brooke.wangzhigang@huawei.com>
---
.../devicetree/bindings/mmc/k3-dw-mshc.txt | 59 +++++++++
drivers/mmc/host/Kconfig | 10 ++
drivers/mmc/host/Makefile | 1 +
drivers/mmc/host/dw_mmc-k3.c | 128 ++++++++++++++++++++
4 files changed, 198 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
create mode 100644 drivers/mmc/host/dw_mmc-k3.c
diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
new file mode 100644
index 000000000000..5501c7c1138f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
@@ -0,0 +1,59 @@
+* Hisilicon specific extensions to the Synopsys Designware Mobile
+ Storage Host Controller
+
+Read synopsys-dw-mshc.txt for more details
+
+The Synopsys designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Hisilicon specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be one of the following.
+ - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions.
+* clock-freq-table: should be the frequency (in Hz) array of the ciu clock
+ in each supported timing mode.
+ 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode
+ 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode
+ 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
+ 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode
+ 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode
+ 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode
+ 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode
+ 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
+ 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode
+
+Example:
+
+ /* for Hi3620 */
+
+ /* SoC portion */
+ dwmmc_0: dwmmc0 at fcd03000 {
+ compatible = "hisilicon,hi4511-dw-mshc";
+ reg = <0xfcd03000 0x1000>;
+ interrupts = <0 16 4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mmc_clock HI3620_SD_CIUCLK>, <&clock HI3620_DDRC_PER_CLK>;
+ clock-names = "ciu", "biu";
+ clk-table =
+ <25000000 0 50000000 25000000 50000000 100000000 0 50000000>;
+ };
+
+ /* Board portion */
+ dwmmc0 at fcd03000 {
+ num-slots = <1>;
+ vmmc-supply = <&ldo12>;
+ fifo-depth = <0x100>;
+ supports-highspeed;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>;
+ slot at 0 {
+ reg = <0>;
+ bus-width = <4>;
+ disable-wp;
+ cd-gpios = <&gpio10 3 0>;
+ };
+ };
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 7fc5099e44b2..45aaa2de0f58 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -575,6 +575,16 @@ config MMC_DW_SOCFPGA
This selects support for Altera SoCFPGA specific extensions to the
Synopsys DesignWare Memory Card Interface driver.
+config MMC_DW_K3
+ tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ select MMC_DW_IDMAC
+ help
+ This selects support for Hisilicon K3 SoC specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver. Select this option
+ for platforms based on Hisilicon K3 SoC's.
+
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c41d0c364509..64f5f8d35839 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_SOCFPGA) += dw_mmc-socfpga.o
+obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c
new file mode 100644
index 000000000000..54b2503b211f
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-k3.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/of_address.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define MAX_NUMS 10
+struct dw_mci_k3_priv_data {
+ u32 clk_table[MAX_NUMS];
+};
+
+static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_k3_priv_data *priv = host->priv;
+
+ clk_set_rate(host->ciu_clk, priv->clk_table[ios->timing]);
+ host->bus_hz = clk_get_rate(host->ciu_clk);
+}
+
+static int dw_mci_k3_parse_dt(struct dw_mci *host)
+{
+ struct dw_mci_k3_priv_data *priv;
+ struct device_node *node = host->dev->of_node;
+ struct property *prop;
+ const __be32 *cur;
+ u32 val, num = 0;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(host->dev, "mem alloc failed for private data\n");
+ return -ENOMEM;
+ }
+ host->priv = priv;
+
+ of_property_for_each_u32(node, "clock-freq-table", prop, cur, val) {
+ if (num >= MAX_NUMS)
+ break;
+ priv->clk_table[num++] = val;
+ }
+ return 0;
+}
+
+static unsigned long k3_dwmmc_caps[4] = {
+ MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED,
+ MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED,
+ 0,
+ 0,
+};
+
+static const struct dw_mci_drv_data k3_drv_data = {
+ .caps = k3_dwmmc_caps,
+ .set_ios = dw_mci_k3_set_ios,
+ .parse_dt = dw_mci_k3_parse_dt,
+};
+
+static const struct of_device_id dw_mci_k3_match[] = {
+ { .compatible = "hisilicon,hi4511-dw-mshc",
+ .data = &k3_drv_data, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_k3_match);
+
+static int dw_mci_k3_probe(struct platform_device *pdev)
+{
+ const struct dw_mci_drv_data *drv_data;
+ const struct of_device_id *match;
+
+ match = of_match_node(dw_mci_k3_match, pdev->dev.of_node);
+ drv_data = match->data;
+
+ return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static int dw_mci_k3_suspend(struct device *dev)
+{
+ struct dw_mci *host = dev_get_drvdata(dev);
+
+ if (!IS_ERR(host->ciu_clk))
+ clk_disable_unprepare(host->ciu_clk);
+
+ return dw_mci_suspend(host);
+}
+
+static int dw_mci_k3_resume(struct device *dev)
+{
+ struct dw_mci *host = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = clk_prepare_enable(host->ciu_clk);
+ if (ret) {
+ dev_err(host->dev, "failed to enable ciu clock\n");
+ return ret;
+ }
+
+ return dw_mci_resume(host);
+}
+
+SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
+
+static struct platform_driver dw_mci_k3_pltfm_driver = {
+ .probe = dw_mci_k3_probe,
+ .remove = dw_mci_pltfm_remove,
+ .driver = {
+ .name = "dwmmc_k3",
+ .of_match_table = dw_mci_k3_match,
+ .pm = &dw_mci_k3_pmops,
+ },
+};
+
+module_platform_driver(dw_mci_k3_pltfm_driver);
+
+MODULE_DESCRIPTION("K3 Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-k3");
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-12 13:27 ` zhangfei
2013-12-12 14:13 ` Zhangfei Gao
@ 2013-12-12 20:40 ` Arnd Bergmann
2013-12-13 2:57 ` zhangfei
1 sibling, 1 reply; 22+ messages in thread
From: Arnd Bergmann @ 2013-12-12 20:40 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 12 December 2013, zhangfei wrote:
> On 12/12/2013 04:12 AM, Arnd Bergmann wrote:
> > On Wednesday 11 December 2013, zhangfei wrote:
> >
> > But aren't the times fixed for each mode? Why do you need to specify them in
> > the DT? I would expect that the clock rates for each mode are set in the
> > MMC and SD specifications. When you call clk_set_rate(), it should normally
> > be enough to ask for the clock you actually want and let the clk subsystem
> > figure out how to set up the parents and multipliers on the way.
>
> Yes. that's will be perfect.
>
> However, currently this ip still has no such capability.
> Input rate for init are diferent for different controller, not the
> init 400K, some are 13M, others are 25M, since different clock source.
> This can be easily solved by clock-freq-init = <25000000>
> 2. There is maxmum limit, also can be easily solved by define CLK_MAX.
> 3. However some mode can not use the max speed from ios->clock
> for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may
> be reached, at least currently.
I don't fully understand the explanation, but if some of the other
people with interest in dw-mmc (I've added some more to Cc now) think
this makes sense, I'm fine with it too.
> How about this desc
>
> * clock-freq-table: should be the frequency (in Hz) array of the ciu
> clock
> in each supported timing.
>
> 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode
>
> 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode
> 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
> 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode
>
> 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode
>
> 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode
>
> 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode
>
> 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
>
> 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode
>
Yes, that is much better. but please avoid using Linux internal
identifiers (e.g. MMC_TIMING_LEGACY) and instead use the terminology from
the MMC and SD specs. Also 'Hz' is the official symbol for Hertz, not 'HZ'.
Arnd
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform
2013-12-12 20:40 ` Arnd Bergmann
@ 2013-12-13 2:57 ` zhangfei
0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2013-12-13 2:57 UTC (permalink / raw)
To: linux-arm-kernel
On 12/13/2013 04:40 AM, Arnd Bergmann wrote:
> On Thursday 12 December 2013, zhangfei wrote:
>> On 12/12/2013 04:12 AM, Arnd Bergmann wrote:
>>> On Wednesday 11 December 2013, zhangfei wrote:
>>>
>>> But aren't the times fixed for each mode? Why do you need to specify them in
>>> the DT? I would expect that the clock rates for each mode are set in the
>>> MMC and SD specifications. When you call clk_set_rate(), it should normally
>>> be enough to ask for the clock you actually want and let the clk subsystem
>>> figure out how to set up the parents and multipliers on the way.
>>
>> Yes. that's will be perfect.
>>
>> However, currently this ip still has no such capability.
>> Input rate for init are diferent for different controller, not the
>> init 400K, some are 13M, others are 25M, since different clock source.
>> This can be easily solved by clock-freq-init = <25000000>
>> 2. There is maxmum limit, also can be easily solved by define CLK_MAX.
>> 3. However some mode can not use the max speed from ios->clock
>> for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may
>> be reached, at least currently.
>
> I don't fully understand the explanation,
This is the ip's limitation currently, that some mode can only operate
at limited freq, rather than the max freq from spec.
Will upgrade to use ios->clock once the limitation is solved.
but if some of the other
> people with interest in dw-mmc (I've added some more to Cc now) think
> this makes sense, I'm fine with it too.
>
Could I treat this as Ack or Partially Ack for the next version :)
>> How about this desc
>>
>> * clock-freq-table: should be the frequency (in Hz) array of the ciu
>> clock
>> in each supported timing.
>>
>> 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode
>>
>> 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode
>> 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
>> 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode
>>
>> 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode
>>
>> 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode
>>
>> 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode
>>
>> 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode
>>
>> 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode
>>
>
> Yes, that is much better. but please avoid using Linux internal
> identifiers (e.g. MMC_TIMING_LEGACY) and instead use the terminology from
> the MMC and SD specs. Also 'Hz' is the official symbol for Hertz, not 'HZ'.
>
Update to
* clock-freq-table: should be the frequency (in Hz) array of the ciu clock
in each supported mode.
0. CIU clock rate in Hz for DS mode
1. CIU clock rate in Hz for MMC HS mode
2. CIU clock rate in Hz for SD HS mode
3. CIU clock rate in Hz for SDR12 mode
4. CIU clock rate in Hz for SDR25 mode
5. CIU clock rate in Hz for SDR50 mode
6. CIU clock rate in Hz for SDR104 mode
7. CIU clock rate in Hz for DDR50 mode
8. CIU clock rate in Hz for HS200 mode
Thanks
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2013-12-14 2:12 [PATCH v5 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
@ 2013-12-14 2:12 ` Zhangfei Gao
0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-14 2:12 UTC (permalink / raw)
To: linux-arm-kernel
Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bce0deec362..a776f24f4311 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -36,6 +36,7 @@
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/mmc/slot-gpio.h>
#include "dw_mmc.h"
@@ -1032,20 +1033,26 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
+ int gpio_cd = !mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
+ else if (!IS_ERR_VALUE(gpio_cd))
+ present = !!gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
- if (present)
+ if (present) {
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is present\n");
- else
+ } else {
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is not present\n");
+ }
return present;
}
@@ -1926,10 +1933,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Card change detected */
slot->last_detect_state = present;
- /* Mark card as present if applicable */
- if (present != 0)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clean up queue if present */
mrq = slot->mrq;
if (mrq) {
@@ -1977,8 +1980,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Power down slot */
if (present == 0) {
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clear down the FIFO */
dw_mci_fifo_reset(host);
#ifdef CONFIG_MMC_DW_IDMAC
@@ -2079,6 +2080,26 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
return gpio;
}
+
+/* find the cd gpio for a given slot; or -1 if none specified */
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+ int gpio;
+
+ if (!np)
+ return;
+
+ gpio = of_get_named_gpio(np, "cd-gpios", 0);
+
+ /* Having a missing entry is valid; return silently */
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (mmc_gpio_request_cd(mmc, gpio, 0))
+ dev_warn(dev, "gpio [%d] request failed\n", gpio);
+}
#else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
@@ -2096,6 +2117,11 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
return -EINVAL;
}
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ return;
+}
#endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2197,12 +2223,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- if (dw_mci_get_cd(mmc))
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
+ dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
ret = mmc_add_host(mmc);
if (ret)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2013-12-28 14:34 [PATCH v6 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
@ 2013-12-28 14:34 ` Zhangfei Gao
0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2013-12-28 14:34 UTC (permalink / raw)
To: linux-arm-kernel
Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bce0deec362..a776f24f4311 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -36,6 +36,7 @@
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/mmc/slot-gpio.h>
#include "dw_mmc.h"
@@ -1032,20 +1033,26 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
+ int gpio_cd = !mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
+ else if (!IS_ERR_VALUE(gpio_cd))
+ present = !!gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
- if (present)
+ if (present) {
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is present\n");
- else
+ } else {
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is not present\n");
+ }
return present;
}
@@ -1926,10 +1933,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Card change detected */
slot->last_detect_state = present;
- /* Mark card as present if applicable */
- if (present != 0)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clean up queue if present */
mrq = slot->mrq;
if (mrq) {
@@ -1977,8 +1980,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Power down slot */
if (present == 0) {
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clear down the FIFO */
dw_mci_fifo_reset(host);
#ifdef CONFIG_MMC_DW_IDMAC
@@ -2079,6 +2080,26 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
return gpio;
}
+
+/* find the cd gpio for a given slot; or -1 if none specified */
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+ int gpio;
+
+ if (!np)
+ return;
+
+ gpio = of_get_named_gpio(np, "cd-gpios", 0);
+
+ /* Having a missing entry is valid; return silently */
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (mmc_gpio_request_cd(mmc, gpio, 0))
+ dev_warn(dev, "gpio [%d] request failed\n", gpio);
+}
#else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
@@ -2096,6 +2117,11 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
return -EINVAL;
}
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ return;
+}
#endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2197,12 +2223,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- if (dw_mci_get_cd(mmc))
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
+ dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
ret = mmc_add_host(mmc);
if (ret)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-09 14:35 [PATCH v7 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
@ 2014-01-09 14:35 ` Zhangfei Gao
2014-01-09 14:38 ` Arnd Bergmann
2014-01-14 15:58 ` Kevin Hilman
0 siblings, 2 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-01-09 14:35 UTC (permalink / raw)
To: linux-arm-kernel
Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 4bce0deec362..a776f24f4311 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -36,6 +36,7 @@
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/mmc/slot-gpio.h>
#include "dw_mmc.h"
@@ -1032,20 +1033,26 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
+ int gpio_cd = !mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
+ else if (!IS_ERR_VALUE(gpio_cd))
+ present = !!gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
== 0 ? 1 : 0;
- if (present)
+ if (present) {
+ set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is present\n");
- else
+ } else {
+ clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
dev_dbg(&mmc->class_dev, "card is not present\n");
+ }
return present;
}
@@ -1926,10 +1933,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Card change detected */
slot->last_detect_state = present;
- /* Mark card as present if applicable */
- if (present != 0)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clean up queue if present */
mrq = slot->mrq;
if (mrq) {
@@ -1977,8 +1980,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
/* Power down slot */
if (present == 0) {
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
/* Clear down the FIFO */
dw_mci_fifo_reset(host);
#ifdef CONFIG_MMC_DW_IDMAC
@@ -2079,6 +2080,26 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
return gpio;
}
+
+/* find the cd gpio for a given slot; or -1 if none specified */
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+ int gpio;
+
+ if (!np)
+ return;
+
+ gpio = of_get_named_gpio(np, "cd-gpios", 0);
+
+ /* Having a missing entry is valid; return silently */
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (mmc_gpio_request_cd(mmc, gpio, 0))
+ dev_warn(dev, "gpio [%d] request failed\n", gpio);
+}
#else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
@@ -2096,6 +2117,11 @@ static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
return -EINVAL;
}
+static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
+ struct mmc_host *mmc)
+{
+ return;
+}
#endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@@ -2197,12 +2223,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- if (dw_mci_get_cd(mmc))
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
+ dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
ret = mmc_add_host(mmc);
if (ret)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-09 14:35 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
@ 2014-01-09 14:38 ` Arnd Bergmann
2014-01-14 15:58 ` Kevin Hilman
1 sibling, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-01-09 14:38 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 09 January 2014, Zhangfei Gao wrote:
> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
> ---
> drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++------------
> 1 file changed, 35 insertions(+), 13 deletions(-)
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-09 14:35 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2014-01-09 14:38 ` Arnd Bergmann
@ 2014-01-14 15:58 ` Kevin Hilman
2014-01-14 17:23 ` Olof Johansson
1 sibling, 1 reply; 22+ messages in thread
From: Kevin Hilman @ 2014-01-14 15:58 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Jan 9, 2014 at 6:35 AM, Zhangfei Gao <zhangfei.gao@linaro.org> wrote:
> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
The Samsung Arndale board started failing boot from MMC root tests
starting with next-20140113 and I bisected it down to this patch.
Reverting this patch on top of next-20140114 gets Arndale booting
again from MMC. Is there some supporting DT data that's missing for
Arndale?
Kevin
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-14 15:58 ` Kevin Hilman
@ 2014-01-14 17:23 ` Olof Johansson
2014-01-15 1:09 ` zhangfei
0 siblings, 1 reply; 22+ messages in thread
From: Olof Johansson @ 2014-01-14 17:23 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 14, 2014 at 7:58 AM, Kevin Hilman <khilman@linaro.org> wrote:
> On Thu, Jan 9, 2014 at 6:35 AM, Zhangfei Gao <zhangfei.gao@linaro.org> wrote:
>> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
>> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
>> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>>
>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>
> The Samsung Arndale board started failing boot from MMC root tests
> starting with next-20140113 and I bisected it down to this patch.
> Reverting this patch on top of next-20140114 gets Arndale booting
> again from MMC. Is there some supporting DT data that's missing for
> Arndale?
Rather, it looks like this patch changes behaviour and no longer uses
dw_mci_get_cd() to find out if there's a card attached -- it switches
to rely only on GPIO (see the last chunk in the patch). That seems
broken?
-Olof
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-14 17:23 ` Olof Johansson
@ 2014-01-15 1:09 ` zhangfei
2014-01-15 5:16 ` zhangfei
0 siblings, 1 reply; 22+ messages in thread
From: zhangfei @ 2014-01-15 1:09 UTC (permalink / raw)
To: linux-arm-kernel
On 01/15/2014 01:23 AM, Olof Johansson wrote:
> On Tue, Jan 14, 2014 at 7:58 AM, Kevin Hilman <khilman@linaro.org> wrote:
>> On Thu, Jan 9, 2014 at 6:35 AM, Zhangfei Gao <zhangfei.gao@linaro.org> wrote:
>>> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
>>> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
>>> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>>>
>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>>
>> The Samsung Arndale board started failing boot from MMC root tests
>> starting with next-20140113 and I bisected it down to this patch.
>> Reverting this patch on top of next-20140114 gets Arndale booting
>> again from MMC. Is there some supporting DT data that's missing for
>> Arndale?
>
> Rather, it looks like this patch changes behaviour and no longer uses
> dw_mci_get_cd() to find out if there's a card attached -- it switches
> to rely only on GPIO (see the last chunk in the patch). That seems
> broken?
>
Oops,
Change using dw_mci_get_cd set flag DW_MMC_CARD_PRESENT.
And dw_mci_get_cd is called from mmc_rescan, a litter later than
dw_mci_probe.
Is that too late?
Thanks
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin
2014-01-15 1:09 ` zhangfei
@ 2014-01-15 5:16 ` zhangfei
0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-01-15 5:16 UTC (permalink / raw)
To: linux-arm-kernel
Dear Kevin
On 01/15/2014 09:09 AM, zhangfei wrote:
>
>
> On 01/15/2014 01:23 AM, Olof Johansson wrote:
>> On Tue, Jan 14, 2014 at 7:58 AM, Kevin Hilman <khilman@linaro.org> wrote:
>>> On Thu, Jan 9, 2014 at 6:35 AM, Zhangfei Gao
>>> <zhangfei.gao@linaro.org> wrote:
>>>> Suggested by Jaehoon: Use slot-gpio to handle cd-gpio
>>>> Add function dw_mci_of_get_cd_gpio to check "cd-gpios" from dts.
>>>> mmc_gpio_request_cd and mmc_gpio_get_cd are used to handle cd pin
>>>>
>>>> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
>>>> Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
>>>
>>> The Samsung Arndale board started failing boot from MMC root tests
>>> starting with next-20140113 and I bisected it down to this patch.
>>> Reverting this patch on top of next-20140114 gets Arndale booting
>>> again from MMC. Is there some supporting DT data that's missing for
>>> Arndale?
>>
>> Rather, it looks like this patch changes behaviour and no longer uses
>> dw_mci_get_cd() to find out if there's a card attached -- it switches
>> to rely only on GPIO (see the last chunk in the patch). That seems
>> broken?
>>
> Oops,
> Change using dw_mci_get_cd set flag DW_MMC_CARD_PRESENT.
> And dw_mci_get_cd is called from mmc_rescan, a litter later than
> dw_mci_probe.
> Is that too late?
Should have found the issue, CDETECT is ignored since IS_ERR_VALUE does
not workable to !mmc_gpio_get_cd(mmc), which used for adding debounce.
Sorry for that.
However, with this change the debounce seems not stable as before.
In the test of plug-in-out, sometimes sd detect will return timeout
although present indicates as 1, while next time it can be detected again.
Still want to check more.
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index a776f24f4311..f1683ba194ee 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1033,7 +1033,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
int present;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
- int gpio_cd = !mmc_gpio_get_cd(mmc);
+ int gpio_cd = mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
@@ -1041,7 +1041,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
else if (!IS_ERR_VALUE(gpio_cd))
- present = !!gpio_cd;
+ present = !gpio_cd;
else
present = (mci_readl(slot->host, CDETECT) & (1 <<
slot->id))
== 0 ? 1 : 0;
^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2014-01-15 5:16 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-11 14:02 [PATCH v4 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2013-12-11 14:02 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2013-12-11 14:02 ` [PATCH 2/3] mmc: dw_mmc: add dw_mmc-k3 for k3 platform Zhangfei Gao
2013-12-11 14:49 ` Arnd Bergmann
2013-12-11 15:36 ` zhangfei
2013-12-11 15:53 ` zhangfei
2013-12-11 20:12 ` Arnd Bergmann
2013-12-12 13:27 ` zhangfei
2013-12-12 14:13 ` Zhangfei Gao
2013-12-12 20:40 ` Arnd Bergmann
2013-12-13 2:57 ` zhangfei
2013-12-11 14:02 ` [PATCH 3/3] clk: hisilicon: add hi3620_mmc_clks Zhangfei Gao
2013-12-11 14:44 ` Arnd Bergmann
2013-12-11 15:40 ` zhangfei
-- strict thread matches above, loose matches on Subject: below --
2013-12-14 2:12 [PATCH v5 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2013-12-14 2:12 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2013-12-28 14:34 [PATCH v6 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2013-12-28 14:34 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2014-01-09 14:35 [PATCH v7 0/3] mmc: dw_mmc: add dw_mmc-k3 Zhangfei Gao
2014-01-09 14:35 ` [PATCH 1/3] mmc: dw_mmc: use slot-gpio to handle cd pin Zhangfei Gao
2014-01-09 14:38 ` Arnd Bergmann
2014-01-14 15:58 ` Kevin Hilman
2014-01-14 17:23 ` Olof Johansson
2014-01-15 1:09 ` zhangfei
2014-01-15 5:16 ` zhangfei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).