Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756360Ab3J1U6c (ORCPT ); Mon, 28 Oct 2013 16:58:32 -0400 Received: from tx2ehsobe002.messaging.microsoft.com ([65.55.88.12]:40209 "EHLO tx2outboundpool.messaging.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751479Ab3J1U6a (ORCPT ); Mon, 28 Oct 2013 16:58:30 -0400 X-Forefront-Antispam-Report: CIP:149.199.60.83;KIP:(null);UIP:(null);IPV:NLI;H:xsj-gw1;RD:unknown-60-83.xilinx.com;EFVD:NLI X-SpamScore: 5 X-BigFish: VPS5(zz98dI1432Ic8kzz1f42h208ch1ee6h1de0h1fdah2073h1202h1e76h1d1ah1d2ah1fc6hz70kz1de098h8275bh1de097hz2fh95h839h93fhd24hf0ah119dh1288h12a5h12a9h12bdh137ah13b6h1441h14ddh1504h1537h153bh162dh1631h1758h18e1h1946h19b5h1b0ah1d0ch1d2eh1d3fh1dfeh1dffh1e1dh1fe8h1ff5h209eh2216h906i1155h192ch) Date: Mon, 28 Oct 2013 13:58:20 -0700 From: =?utf-8?B?U8O2cmVu?= Brinkmann To: Rob Herring , Pawel Moll , Mark Rutland , Stephen Warren , Ian Campbell , Rob Landley , Russell King , Chris Ball , Michal Simek , Grant Likely CC: , , , , Subject: Re: [PATCH 1/2] mmc: arasan: Add driver for Arasan SDHCI References: <1381864085-8806-1-git-send-email-soren.brinkmann@xilinx.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Disposition: inline In-Reply-To: <1381864085-8806-1-git-send-email-soren.brinkmann@xilinx.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-RCIS-Action: ALLOW Message-ID: <1f00e71b-6034-4953-9a2f-4dda461fdb73@TX2EHSMHS040.ehs.local> X-OriginatorOrg: xilinx.com X-FOPE-CONNECTOR: Id%0$Dn%*$RO%0$TLS%0$FQDN%$TlsDn% Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 10590 Lines: 333 ping? On Tue, Oct 15, 2013 at 12:08:04PM -0700, Soren Brinkmann wrote: > Add a driver for Arasan's SDHCI controller core. > > Signed-off-by: Soren Brinkmann > --- > .../devicetree/bindings/mmc/arasan,sdhci.txt | 23 +++ > MAINTAINERS | 1 + > drivers/mmc/host/Kconfig | 12 ++ > drivers/mmc/host/Makefile | 1 + > drivers/mmc/host/sdhci-of-arasan.c | 224 +++++++++++++++++++++ > 5 files changed, 261 insertions(+) > create mode 100644 Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > create mode 100644 drivers/mmc/host/sdhci-of-arasan.c > > diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > new file mode 100644 > index 000000000000..20f0fc25e270 > --- /dev/null > +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt > @@ -0,0 +1,23 @@ > +Device Tree Bindings for the Arasan SDCHI Controller > + > + The bindings follow the mmc[1] and the clock bindings[2]. Only deviations are > + documented here. > + > + [1] Documentation/devicetree/bindings/mmc/mmc.txt > + [2] Documentation/devicetree/bindings/clock/clock-bindings.txt > + > +Required Properties: > + - compatible: Compatibility string. Must be 'arasan,sdhci' > + - reg: From mmc bindings: Register location and length. > + - clocks: From clock bindings: Handles to clock inputs. > + - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" > + > +Example: > + sdhci@e0100000 { > + compatible = "arasan,sdhci"; > + reg = <0xe0100000 0x1000>; > + clock-names = "clk_xin", "clk_ahb"; > + clocks = <&clkc 21>, <&clkc 32>; > + interrupt-parent = <&gic>; > + interrupts = <0 24 4>; > + } ; > diff --git a/MAINTAINERS b/MAINTAINERS > index 72b1e5c2378a..e2c99b377f8f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1348,6 +1348,7 @@ T: git git://git.xilinx.com/linux-xlnx.git > S: Supported > F: arch/arm/mach-zynq/ > F: drivers/cpuidle/cpuidle-zynq.c > +F: drivers/mmc/host/sdhci-of-arasan.c > > ARM SMMU DRIVER > M: Will Deacon > diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig > index 7fc5099e44b2..1eb090c187bb 100644 > --- a/drivers/mmc/host/Kconfig > +++ b/drivers/mmc/host/Kconfig > @@ -104,6 +104,18 @@ config MMC_SDHCI_PLTFM > > If unsure, say N. > > +config MMC_SDHCI_OF_ARASAN > + tristate "SDHCI OF support for the Arasan SDHCI controllers" > + depends on MMC_SDHCI_PLTFM > + depends on OF > + help > + This selects the Arasan Secure Digital Host Controller Interface > + (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. > + > + If you have a controller with this interface, say Y or M here. > + > + If unsure, say N. > + > config MMC_SDHCI_OF_ESDHC > tristate "SDHCI OF support for the Freescale eSDHC controller" > depends on MMC_SDHCI_PLTFM > diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile > index c41d0c364509..f93617ec6548 100644 > --- a/drivers/mmc/host/Makefile > +++ b/drivers/mmc/host/Makefile > @@ -57,6 +57,7 @@ obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o > obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o > obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o > obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o > +obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o > obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o > obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o > obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o > diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c > new file mode 100644 > index 000000000000..6ac93c4c2cf5 > --- /dev/null > +++ b/drivers/mmc/host/sdhci-of-arasan.c > @@ -0,0 +1,224 @@ > +/* > + * Arasan Secure Digital Host Controller Interface. > + * Copyright (C) 2011 - 2012 Michal Simek > + * Copyright (c) 2012 Wind River Systems, Inc. > + * Copyright (C) 2013 Pengutronix e.K. > + * Copyright (C) 2013 Xilinx Inc. > + * > + * Based on sdhci-of-esdhc.c > + * > + * Copyright (c) 2007 Freescale Semiconductor, Inc. > + * Copyright (c) 2009 MontaVista Software, Inc. > + * > + * Authors: Xiaobo Xie > + * Anton Vorontsov > + * > + * 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 > +#include "sdhci-pltfm.h" > + > +#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c > + > +#define CLK_CTRL_TIMEOUT_SHIFT 16 > +#define CLK_CTRL_TIMEOUT_MASK (0xf << CLK_CTRL_TIMEOUT_SHIFT) > +#define CLK_CTRL_TIMEOUT_MIN_EXP 13 > + > +/** > + * struct sdhci_arasan_data > + * @clk_ahb: Pointer to the AHB clock > + */ > +struct sdhci_arasan_data { > + struct clk *clk_ahb; > +}; > + > +static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) > +{ > + u32 div; > + unsigned long freq; > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + > + div = readl(host->ioaddr + SDHCI_ARASAN_CLK_CTRL_OFFSET); > + div = (div & CLK_CTRL_TIMEOUT_MASK) >> CLK_CTRL_TIMEOUT_SHIFT; > + > + freq = clk_get_rate(pltfm_host->clk); > + freq /= 1 << (CLK_CTRL_TIMEOUT_MIN_EXP + div); > + > + return freq; > +} > + > +static struct sdhci_ops sdhci_arasan_ops = { > + .get_max_clock = sdhci_pltfm_clk_get_max_clock, > + .get_timeout_clock = sdhci_arasan_get_timeout_clock, > +}; > + > +static struct sdhci_pltfm_data sdhci_arasan_pdata = { > + .ops = &sdhci_arasan_ops, > +}; > + > +#ifdef CONFIG_PM_SLEEP > +/** > + * sdhci_arasan_suspend - Suspend method for the driver > + * @dev: Address of the device structure > + * Returns 0 on success and error value on error > + * > + * Put the device in a low power state. > + */ > +static int sdhci_arasan_suspend(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct sdhci_host *host = platform_get_drvdata(pdev); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; > + int ret; > + > + ret = sdhci_suspend_host(host); > + if (ret) > + return ret; > + > + clk_disable(pltfm_host->clk); > + clk_disable(sdhci_arasan->clk_ahb); > + > + return 0; > +} > + > +/** > + * sdhci_arasan_resume - Resume method for the driver > + * @dev: Address of the device structure > + * Returns 0 on success and error value on error > + * > + * Resume operation after suspend > + */ > +static int sdhci_arasan_resume(struct device *dev) > +{ > + struct platform_device *pdev = to_platform_device(dev); > + struct sdhci_host *host = platform_get_drvdata(pdev); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; > + int ret; > + > + ret = clk_enable(sdhci_arasan->clk_ahb); > + if (ret) { > + dev_err(dev, "Cannot enable AHB clock.\n"); > + return ret; > + } > + > + ret = clk_enable(pltfm_host->clk); > + if (ret) { > + dev_err(dev, "Cannot enable SD clock.\n"); > + clk_disable(sdhci_arasan->clk_ahb); > + return ret; > + } > + > + return sdhci_resume_host(host); > +} > +#endif /* ! CONFIG_PM_SLEEP */ > + > +static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, > + sdhci_arasan_resume); > + > +static int sdhci_arasan_probe(struct platform_device *pdev) > +{ > + int ret; > + struct clk *clk_xin; > + struct sdhci_host *host; > + struct sdhci_pltfm_host *pltfm_host; > + struct sdhci_arasan_data *sdhci_arasan; > + > + sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan), > + GFP_KERNEL); > + if (!sdhci_arasan) > + return -ENOMEM; > + > + sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); > + if (IS_ERR(sdhci_arasan->clk_ahb)) { > + dev_err(&pdev->dev, "clk_ahb clock not found.\n"); > + return PTR_ERR(sdhci_arasan->clk_ahb); > + } > + > + clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); > + if (IS_ERR(clk_xin)) { > + dev_err(&pdev->dev, "clk_xin clock not found.\n"); > + return PTR_ERR(clk_xin); > + } > + > + ret = clk_prepare_enable(sdhci_arasan->clk_ahb); > + if (ret) { > + dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); > + return ret; > + } > + > + ret = clk_prepare_enable(clk_xin); > + if (ret) { > + dev_err(&pdev->dev, "Unable to enable SD clock.\n"); > + goto clk_dis_ahb; > + } > + > + host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0); > + if (IS_ERR(host)) { > + ret = PTR_ERR(host); > + dev_err(&pdev->dev, "platform init failed (%u)\n", ret); > + goto clk_disable_all; > + } > + > + sdhci_get_of_property(pdev); > + pltfm_host = sdhci_priv(host); > + pltfm_host->priv = sdhci_arasan; > + pltfm_host->clk = clk_xin; > + > + ret = sdhci_add_host(host); > + if (ret) { > + dev_err(&pdev->dev, "platform register failed (%u)\n", ret); > + goto err_pltfm_free; > + } > + > + return 0; > + > +err_pltfm_free: > + sdhci_pltfm_free(pdev); > +clk_disable_all: > + clk_disable_unprepare(clk_xin); > +clk_dis_ahb: > + clk_disable_unprepare(sdhci_arasan->clk_ahb); > + > + return ret; > +} > + > +static int sdhci_arasan_remove(struct platform_device *pdev) > +{ > + struct sdhci_host *host = platform_get_drvdata(pdev); > + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); > + struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; > + > + clk_disable_unprepare(pltfm_host->clk); > + clk_disable_unprepare(sdhci_arasan->clk_ahb); > + > + return sdhci_pltfm_unregister(pdev); > +} > + > +static const struct of_device_id sdhci_arasan_of_match[] = { > + { .compatible = "arasan,sdhci" }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); > + > +static struct platform_driver sdhci_arasan_driver = { > + .driver = { > + .name = "sdhci-arasan", > + .owner = THIS_MODULE, > + .of_match_table = sdhci_arasan_of_match, > + .pm = &sdhci_arasan_dev_pm_ops, > + }, > + .probe = sdhci_arasan_probe, > + .remove = sdhci_arasan_remove, > +}; > + > +module_platform_driver(sdhci_arasan_driver); > + > +MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); > +MODULE_AUTHOR("Soeren Brinkmann +MODULE_LICENSE("GPL"); > -- > 1.8.4 > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/