From patchwork Thu Aug 23 17:10:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: thomas.abraham@linaro.org X-Patchwork-Id: 10911 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id DBC2823E53 for ; Thu, 23 Aug 2012 16:53:29 +0000 (UTC) Received: from mail-ob0-f180.google.com (mail-ob0-f180.google.com [209.85.214.180]) by fiordland.canonical.com (Postfix) with ESMTP id 6B3C5A1814E for ; Thu, 23 Aug 2012 16:53:14 +0000 (UTC) Received: by obceq6 with SMTP id eq6so2117529obc.11 for ; Thu, 23 Aug 2012 09:53:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:x-auditid :from:to:cc:subject:date:message-id:x-mailer:x-brightmail-tracker :x-tm-as-mml:x-gm-message-state; bh=dwL0dawXq+zO/Mr4kms8mTJ4YHXODi3PwTBbbWJVEis=; b=mn/o33a+livWt/KzzwMQQW82b7Rhld/xnrIdVX8upKAHrjm8agAYxWDfThZLJeJbiN QBH/Wqm3mNRd+8tseOvGecJKzQHelfwGhuaKZRmmBxs94CPq5W0hm2toxeZYXOpYzNRc SYr4EP1l/MyK2BlDX5B9wOyOVyYn8OcpnHNi1ubfx3d4vbp9OMQuBlxzpzqmhsMoSFuU GUoYsPABahaLGnEmpNS3oazR+DVgrllEskNu7xyHh1Cwv+vANuc+BaW5Z1oEXhkKQPvg oTu/5l+Zp7xL2XkCwOz5eYbUUopN0OEpFq0N5Vl/PXC55BoT98agiTyOmigaPZUI2NyG nASg== Received: by 10.50.159.196 with SMTP id xe4mr6654664igb.43.1345740808294; Thu, 23 Aug 2012 09:53:28 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.184.232 with SMTP id ex8csp272770igc; Thu, 23 Aug 2012 09:53:27 -0700 (PDT) Received: by 10.68.197.202 with SMTP id iw10mr5986853pbc.161.1345740806725; Thu, 23 Aug 2012 09:53:26 -0700 (PDT) Received: from mailout4.samsung.com (mailout4.samsung.com. [203.254.224.34]) by mx.google.com with ESMTP id kt9si13837322pbc.170.2012.08.23.09.53.25; Thu, 23 Aug 2012 09:53:26 -0700 (PDT) Received-SPF: neutral (google.com: 203.254.224.34 is neither permitted nor denied by best guess record for domain of thomas.abraham@linaro.org) client-ip=203.254.224.34; Authentication-Results: mx.google.com; spf=neutral (google.com: 203.254.224.34 is neither permitted nor denied by best guess record for domain of thomas.abraham@linaro.org) smtp.mail=thomas.abraham@linaro.org Received: from epcpsbgm2.samsung.com (mailout4.samsung.com [203.254.224.34]) by mailout4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0M970063GW8PBFG0@mailout4.samsung.com> for patches@linaro.org; Fri, 24 Aug 2012 01:53:24 +0900 (KST) X-AuditID: cbfee61b-b7faf6d00000476a-d5-50366004f58e Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 99.19.18282.40066305; Fri, 24 Aug 2012 01:53:24 +0900 (KST) Received: from localhost.localdomain ([107.108.73.37]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0M97004HXW6YJQ50@mmp1.samsung.com> for patches@linaro.org; Fri, 24 Aug 2012 01:53:24 +0900 (KST) From: Thomas Abraham To: linux-mmc@vger.kernel.org, devicetree-discuss@lists.ozlabs.org Cc: cjb@laptop.org, grant.likely@secretlab.ca, rob.herring@calxeda.com, linux-samsung-soc@vger.kernel.org, kgene.kim@samsung.com, ben-linux@fluff.org, wmb@firmworks.com, patches@linaro.org Subject: [PATCH v5] mmc: sdhci-s3c: Add device tree support Date: Thu, 23 Aug 2012 22:40:09 +0530 Message-id: <1345741809-18599-1-git-send-email-thomas.abraham@linaro.org> X-Mailer: git-send-email 1.6.6.rc2 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrJJMWRmVeSWpSXmKPExsVy+t9jAV2WBLMAgz3TtSymHP7C4sDocefa HrYAxigum5TUnMyy1CJ9uwSujP7Zy1gLvkRVPLui38B40bOLkZNDQsBEYsry16wQtpjEhXvr 2boYuTiEBBYxShzbtIMJJCEkMJdJordHGsRmEzCQeLTwHTuILSLgJLFk7gRmkAZmgQOMEru/ 32AGSQgLWEvs2r8crIhFQFViydJTQDYHB6+Ap8S72UwQy5QkNvQeZZrAyL2AkWEVo2hqQXJB cVJ6rpFecWJucWleul5yfu4mRrAHn0nvYFzVYHGIUYCDUYmHN+CeaYAQa2JZcWXuIUYJDmYl EV4vTrMAId6UxMqq1KL8+KLSnNTiQ4zSHCxK4rz8fYYBQgLpiSWp2ampBalFMFkmDk6pBkam F7z//1S9Xfrfy4hN44021z3/H8xPJl3LVC5WEGmf2fIxb/K7CZOjjCwtVTv0fD9aTnHSfyjI fVpjaqL07p4rSb78pSlZ2keNGiP3LIrjuHXumNP3v8cXz7t76Lxle9UrvvT2zV7t32Qda+7N Oeh+pGe9pWQIO7//oadiN194v9hz0pvfbKoSS3FGoqEWc1FxIgAnl+PT3AEAAA== X-TM-AS-MML: No X-Gm-Message-State: ALoCoQkFKbdFy5scUYaK20Z2xk1th3MY1h86U75wdCZbosjPXRTgc35c+L69wb393xosgF41uApe Add device tree based discovery support for Samsung's sdhci controller Cc: Ben Dooks Cc: Kukjin Kim Cc: Chris Ball Signed-off-by: Thomas Abraham --- Changes since v4: Adapted to new mmc core card detection bindings as specfied in the patch: [PATCH] mmc: dt: Add card-detection properties to core binding and extends it "samsung,cd-pinmux-gpio" property as suggested by Mitch Bradley Changes since v3: The patch series that adds device tree support for Samsung sdhci controller had six patches in total, of which, the first five patches have been accepted. The sixth patch in the series was dropped since it was using custom Samsung properties for descrbing the bus-width and card-detect gpio, but had otherwise addressed all the comments. This patch reworks the sixth patch in v3 of the sdhci device tree support patch series. The only change in this patch from the v3 version is the use of generic mmc bindings for descrbing the bus-width and card-detect gpio. .../devicetree/bindings/mmc/samsung-sdhci.txt | 53 +++++++ drivers/mmc/host/sdhci-s3c.c | 162 +++++++++++++++++++- 2 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/samsung-sdhci.txt diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt new file mode 100644 index 0000000..361c2ee --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt @@ -0,0 +1,53 @@ +* Samsung's SDHCI Controller device tree bindings + +Samsung's SDHCI controller is used as a connectivity interface with external +MMC, SD and eMMC storage mediums. This file documents differences between the +core mmc properties described by mmc.txt and the properties used by the +Samsung implmentation of the SDHCI controller. + +Note: The mmc core bindings documentation states that if none of the core +card-detect bindings are used, then the standard sdhci card detect mechanism +is used. The Samsung's SDHCI controller bindings extends this as listed below. + +[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the + "Optional Board Specific Properties" section below. + +[B] If core card-detect bindings and "samsung,cd-pinmux-gpio" property + is not specified, it is assumed that there is no card detection + mechanism used. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci + controller. + - "samsung,exynos4210-sdhci": For controllers compatible with Exynos4 sdhci + controller. + +Required Board Specific Properties: +- gpios: Should specify the gpios used for clock, command and data lines. The + gpio specifier format depends on the gpio controller. + +Optional Board Specific Properties: +- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed + through a pinmux to the card-detect pin of the card slot. This property + should be used only if none of the mmc core card-detect properties are + used. + +Example: + sdhci@12530000 { + compatible = "samsung,exynos4210-sdhci"; + reg = <0x12530000 0x100>; + interrupts = <0 75 0>; + bus-width = <4>; + cd-gpios = <&gpk2 2 2 3 3>; + gpios = <&gpk2 0 2 0 3>, /* clock line */ + <&gpk2 1 2 0 3>, /* command line */ + <&gpk2 3 2 3 3>, /* data line 0 */ + <&gpk2 4 2 3 3>, /* data line 1 */ + <&gpk2 5 2 3 3>, /* data line 2 */ + <&gpk2 6 2 3 3>; /* data line 3 */ + }; + + Note: This example shows both SoC specific and board specific properties + in a single device node. The properties can be actually be seperated + into SoC specific node and board specific node. diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a50c205..445910e 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -34,6 +34,9 @@ #define MAX_BUS_CLK (4) +/* Number of gpio's used is max data bus width + command and clock lines */ +#define NUM_GPIOS(x) (x + 2) + /** * struct sdhci_s3c - S3C SDHCI instance * @host: The SDHCI host created @@ -41,6 +44,7 @@ * @ioarea: The resource created when we claimed the IO area. * @pdata: The platform data for this controller. * @cur_clk: The index of the current bus clock. + * @gpios: List of gpio numbers parsed from device tree. * @clk_io: The clock for the internal bus interface. * @clk_bus: The clocks that are available for the SD/MMC bus clock. */ @@ -52,6 +56,7 @@ struct sdhci_s3c { unsigned int cur_clk; int ext_cd_irq; int ext_cd_gpio; + int *gpios; struct clk *clk_io; struct clk *clk_bus[MAX_BUS_CLK]; @@ -419,9 +424,125 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) } } +#ifdef CONFIG_OF +static int __devinit sdhci_s3c_parse_dt(struct device *dev, + struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) +{ + struct device_node *node = dev->of_node; + struct sdhci_s3c *ourhost = to_s3c(host); + u32 max_width; + int gpio, cnt, ret; + + /* if the bus-width property is not specified, assume width as 1 */ + if (of_property_read_u32(node, "bus-width", &max_width)) + max_width = 1; + pdata->max_width = max_width; + + ourhost->gpios = devm_kzalloc(dev, NUM_GPIOS(pdata->max_width) * + sizeof(int), GFP_KERNEL); + if (!ourhost->gpios) + return -ENOMEM; + + /* get the card detection method */ + if (of_get_property(node, "broken-cd", 0)) { + pdata->cd_type = S3C_SDHCI_CD_NONE; + goto setup_bus; + } + + if (of_get_property(node, "non-removable", 0)) { + pdata->cd_type = S3C_SDHCI_CD_PERMANENT; + goto setup_bus; + } + + gpio = of_get_named_gpio(node, "cd-gpios", 0); + if (gpio_is_valid(gpio)) { + pdata->cd_type = S3C_SDHCI_CD_GPIO; + goto found_cd; + } else { + if (gpio != -ENOENT) { + dev_err(dev, "invalid card detect gpio specified\n"); + return -EINVAL; + } + } + + gpio = of_get_named_gpio(node, "samsung,cd-pinmux-gpio", 0); + if (gpio_is_valid(gpio)) { + pdata->cd_type = S3C_SDHCI_CD_INTERNAL; + goto found_cd; + } else { + if (gpio != -ENOENT) { + dev_err(dev, "invalid card detect gpio specified\n"); + return -EINVAL; + } + } + + dev_info(dev, "assuming no card detect line available\n"); + pdata->cd_type = S3C_SDHCI_CD_NONE; + + found_cd: + if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { + pdata->ext_cd_gpio = gpio; + ourhost->ext_cd_gpio = -1; + if (of_get_property(node, "cd-inverted", NULL)) + pdata->ext_cd_gpio_invert = 1; + } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { + ret = gpio_request(gpio, "sdhci-cd"); + if (ret) { + dev_err(dev, "card detect gpio request failed\n"); + return -EINVAL; + } + ourhost->ext_cd_gpio = gpio; + } + + setup_bus: + /* get the gpios for command, clock and data lines */ + for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { + gpio = of_get_gpio(node, cnt); + if (!gpio_is_valid(gpio)) { + dev_err(dev, "invalid gpio[%d]\n", cnt); + goto err_free_dt_cd_gpio; + } + ourhost->gpios[cnt] = gpio; + } + + for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { + ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio"); + if (ret) { + dev_err(dev, "gpio[%d] request failed\n", cnt); + goto err_free_dt_gpios; + } + } + + return 0; + + err_free_dt_gpios: + while (--cnt >= 0) + gpio_free(ourhost->gpios[cnt]); + err_free_dt_cd_gpio: + if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) + gpio_free(ourhost->ext_cd_gpio); + return -EINVAL; +} +#else +static int __devinit sdhci_s3c_parse_dt(struct device *dev, + struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) +{ + return -EINVAL; +} +#endif + +static const struct of_device_id sdhci_s3c_dt_match[]; + static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( struct platform_device *pdev) { +#ifdef CONFIG_OF + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(sdhci_s3c_dt_match, pdev->dev.of_node); + return (struct sdhci_s3c_drv_data *)match->data; + } +#endif return (struct sdhci_s3c_drv_data *) platform_get_device_id(pdev)->driver_data; } @@ -436,7 +557,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) struct resource *res; int ret, irq, ptr, clks; - if (!pdev->dev.platform_data) { + if (!pdev->dev.platform_data && !pdev->dev.of_node) { dev_err(dev, "no device data specified\n"); return -ENOENT; } @@ -452,21 +573,28 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) dev_err(dev, "sdhci_alloc_host() failed\n"); return PTR_ERR(host); } + sc = sdhci_priv(host); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { ret = -ENOMEM; - goto err_io_clk; + goto err_pdata; + } + + if (pdev->dev.of_node) { + ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); + if (ret) + goto err_pdata; + } else { + memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + sc->ext_cd_gpio = -1; /* invalid gpio number */ } - memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); drv_data = sdhci_s3c_get_driver_data(pdev); - sc = sdhci_priv(host); sc->host = host; sc->pdev = pdev; sc->pdata = pdata; - sc->ext_cd_gpio = -1; /* invalid gpio number */ platform_set_drvdata(pdev, host); @@ -631,6 +759,12 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) clk_put(sc->clk_io); err_io_clk: + for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) + gpio_free(sc->gpios[ptr]); + if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) + gpio_free(sc->ext_cd_gpio); + + err_pdata: sdhci_free_host(host); return ret; @@ -638,9 +772,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) static int __devexit sdhci_s3c_remove(struct platform_device *pdev) { - struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data; struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_s3c *sc = sdhci_priv(host); + struct s3c_sdhci_platdata *pdata = sc->pdata; int ptr; if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup) @@ -665,6 +799,11 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) clk_disable(sc->clk_io); clk_put(sc->clk_io); + if (pdev->dev.of_node) { + for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) + gpio_free(sc->gpios[ptr]); + } + sdhci_free_host(host); platform_set_drvdata(pdev, NULL); @@ -737,6 +876,16 @@ static struct platform_device_id sdhci_s3c_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); +#ifdef CONFIG_OF +static const struct of_device_id sdhci_s3c_dt_match[] = { + { .compatible = "samsung,s3c6410-sdhci", }, + { .compatible = "samsung,exynos4210-sdhci", + .data = (void *)EXYNOS4_SDHCI_DRV_DATA }, + {}, +}; +MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match); +#endif + static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, .remove = __devexit_p(sdhci_s3c_remove), @@ -744,6 +893,7 @@ static struct platform_driver sdhci_s3c_driver = { .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", + .of_match_table = of_match_ptr(sdhci_s3c_dt_match), .pm = SDHCI_S3C_PMOPS, }, };