From: Mike Rapoport <mike@compulab.co.il>
To: Olof Johansson <olof@lixom.net>
Cc: Chris Ball <cjb@laptop.org>,
linux-mmc@vger.kernel.org, linux-tegra@vger.kernel.org,
Yvonne Yip <y@palm.com>, Gary King <gking@nvidia.com>,
Todd Poynor <toddpoynor@google.com>,
Dmitry Shmidt <dimitrysh@google.com>,
Rhyland Klein <rklein@nvidia.com>,
Mike Rapoport <mike@compulab.co.il>
Subject: Re: [PATCH 4/4] mmc: add sdhci-tegra driver for Tegra SoCs
Date: Wed, 15 Dec 2010 13:23:58 +0200 [thread overview]
Message-ID: <4D08A54E.9070103@compulab.co.il> (raw)
In-Reply-To: <1292388576-25600-5-git-send-email-olof@lixom.net>
Hi Olof,
Overall looks good, just some nitpicking comments.
On 12/15/10 06:49, Olof Johansson wrote:
> SDHCI driver for Tegra. Pretty straight forward, a few pieces of
> functionality left to fill in but nothing that stops it from going
> upstream. Board enablement submitted separately.
>
> This driver is based on an original one from:
>
> Signed-off-by: Yvonne Yip <y@palm.com>
>
> Misc fixes and suspend/resume by:
>
> Signed-off-by: Gary King <gking@nvidia.com>
> Signed-off-by: Todd Poynor <toddpoynor@google.com>
> Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
>
> GPIO write protect plumbing:
>
> Signed-off-by: Rhyland Klein <rklein@nvidia.com>
>
> Quirk rework and cleanups before submission:
>
> Signed-off-by: Olof Johansson <olof@lixom.net>
> ---
> arch/arm/mach-tegra/include/mach/sdhci.h | 28 +++
> drivers/mmc/host/Kconfig | 10 +
> drivers/mmc/host/Makefile | 1 +
> drivers/mmc/host/sdhci-tegra.c | 267 ++++++++++++++++++++++++++++++
> 4 files changed, 306 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-tegra/include/mach/sdhci.h
> create mode 100644 drivers/mmc/host/sdhci-tegra.c
>
> diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h
> new file mode 100644
> index 0000000..8ca9539
> --- /dev/null
> +++ b/arch/arm/mach-tegra/include/mach/sdhci.h
> @@ -0,0 +1,28 @@
> +/*
> + * include/asm-arm/arch-tegra/include/mach/sdhci.h
> + *
> + * Copyright (C) 2009 Palm, Inc.
> + * Author: Yvonne Yip <y@palm.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +#ifndef __ASM_ARM_ARCH_TEGRA_SDHCI_H
> +#define __ASM_ARM_ARCH_TEGRA_SDHCI_H
> +
> +#include <linux/mmc/host.h>
> +
> +struct tegra_sdhci_platform_data {
> + int cd_gpio;
> + int wp_gpio;
> + int power_gpio;
The power_gpio seems to be unused...
> +};
> +
> +#endif
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index d618e86..bd69bf9 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -189,6 +189,16 @@ config MMC_SDHCI_S3C_DMA
>
> YMMV.
>
> +config MMC_SDHCI_TEGRA
> + tristate "Tegra SD/MMC Controller Support"
> + depends on ARCH_TEGRA && MMC_SDHCI
> + select MMC_SDHCI_IO_ACCESSORS
> + help
> + This selects the Tegra SD/MMC controller. If you have a Tegra
> + platform with SD or MMC devices, say Y or M here.
> +
> + If unsure, say N.
> +
> config MMC_OMAP
> tristate "TI OMAP Multimedia Card Interface support"
> depends on ARCH_OMAP
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index 7b645ff..a096f7f 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
> obj-$(CONFIG_MMC_SDHCI_PXA) += sdhci-pxa.o
> obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
> obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
> +obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
> obj-$(CONFIG_MMC_WBSD) += wbsd.o
> obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
> obj-$(CONFIG_MMC_OMAP) += omap.o
> diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
> new file mode 100644
> index 0000000..eb6b952
> --- /dev/null
> +++ b/drivers/mmc/host/sdhci-tegra.c
> @@ -0,0 +1,267 @@
> +/*
> + * drivers/mmc/host/sdhci-tegra.c
> + *
> + * Copyright (C) 2009 Palm, Inc.
> + * Author: Yvonne Yip <y@palm.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/gpio.h>
> +#include <linux/mmc/card.h>
> +
> +#include <mach/sdhci.h>
> +
> +#include "sdhci.h"
> +
> +#define DRIVER_NAME "sdhci-tegra"
> +
> +struct tegra_sdhci_host {
> + struct sdhci_host *sdhci;
> + struct clk *clk;
> + int wp_gpio;
> +};
> +
> +
> +static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
> +{
> + u32 val;
> +
> + if (unlikely(reg == SDHCI_PRESENT_STATE)) {
> + /* Use wp_gpio here instead? */
> + val = readl(host->ioaddr + reg);
> + return val | SDHCI_WRITE_PROTECT;
> + }
> +
> + return readl(host->ioaddr + reg);
> +}
> +
> +static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
> +{
> + if (unlikely(reg == SDHCI_HOST_VERSION)) {
> + /* Erratum: Version register is invalid in HW. */
> + return SDHCI_SPEC_200;
> + }
> +
> + return readw(host->ioaddr + reg);
> +}
> +
> +static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
> +{
> + writel(val, host->ioaddr + reg);
> + if (unlikely(reg == SDHCI_INT_ENABLE)) {
> + /* Erratum: Must enable block gap interrupt detection */
> + u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
> + if (val & SDHCI_INT_CARD_INT)
> + gap_ctrl |= 0x8;
> + else
> + gap_ctrl &= ~0x8;
> + writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
> + }
> +}
> +
> +static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
> +{
> + struct tegra_sdhci_host *host = sdhci_priv(sdhci);
> +
> + if (host->wp_gpio != -1)
if (gpio_is_valid(host->wp_gpio)) whould be better IMO.
> + return gpio_get_value(host->wp_gpio);
> +
> + return -1;
> +}
> +
> +static irqreturn_t carddetect_irq(int irq, void *data)
> +{
> + struct sdhci_host *sdhost = (struct sdhci_host *)data;
> +
> + tasklet_schedule(&sdhost->card_tasklet);
> + return IRQ_HANDLED;
> +};
> +
> +static int tegra_sdhci_enable_dma(struct sdhci_host *host)
> +{
> + return 0;
> +}
> +
> +static struct sdhci_ops tegra_sdhci_ops = {
> + .enable_dma = tegra_sdhci_enable_dma,
> + .get_ro = tegra_sdhci_get_ro,
> + .read_l = tegra_sdhci_readl,
> + .read_w = tegra_sdhci_readw,
> + .write_l = tegra_sdhci_writel,
> +};
> +
> +static int __devinit tegra_sdhci_probe(struct platform_device *pdev)
> +{
> + int rc;
> + struct tegra_sdhci_platform_data *plat;
> + struct sdhci_host *sdhci;
> + struct tegra_sdhci_host *host;
> + struct resource *res;
> + int irq;
> + void __iomem *ioaddr;
> +
> + plat = pdev->dev.platform_data;
> + if (plat == NULL)
> + return -ENXIO;
> +
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (res == NULL)
> + return -ENODEV;
> +
> + irq = res->start;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (res == NULL)
> + return -ENODEV;
> +
> + ioaddr = ioremap(res->start, res->end - res->start);
> +
> + sdhci = sdhci_alloc_host(&pdev->dev, sizeof(struct tegra_sdhci_host));
> + if (IS_ERR(sdhci)) {
> + rc = PTR_ERR(sdhci);
> + goto err_unmap;
> + }
> +
> + host = sdhci_priv(sdhci);
> + host->sdhci = sdhci;
> +
> + host->clk = clk_get(&pdev->dev, NULL);
> + if (IS_ERR(host->clk)) {
> + rc = PTR_ERR(host->clk);
> + goto err_free_host;
> + }
> +
> + rc = clk_enable(host->clk);
> + if (rc != 0)
> + goto err_clkput;
> +
> + host->wp_gpio = plat->wp_gpio;
> +
> + sdhci->hw_name = "tegra";
> + sdhci->ops = &tegra_sdhci_ops;
> + sdhci->irq = irq;
> + sdhci->ioaddr = ioaddr;
> + sdhci->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
> + SDHCI_QUIRK_SINGLE_POWER_WRITE |
> + SDHCI_QUIRK_NO_HISPD_BIT |
> + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
> + SDHCI_QUIRK_NO_SDIO_IRQ;
> +
> + rc = sdhci_add_host(sdhci);
> + if (rc)
> + goto err_clk_disable;
> +
> + platform_set_drvdata(pdev, host);
> +
> + if (plat->cd_gpio != -1) {
if (gpio_is_valid(host->wp_gpio)) whould be better IMO.
> + rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
> + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
> + mmc_hostname(sdhci->mmc), sdhci);
> +
> + if (rc)
> + goto err_remove_host;
> + }
It seems to me that the tegra_sdhci_probe should handle gpio initialization,
rather then keep gpio_request etc calls in the board files.
> + printk(KERN_INFO "sdhci%d: initialized irq %d ioaddr %p\n", pdev->id,
> + sdhci->irq, sdhci->ioaddr);
> +
dev_info?
> + return 0;
> +
> +err_remove_host:
> + sdhci_remove_host(sdhci, 1);
> +err_clk_disable:
> + clk_disable(host->clk);
> +err_clkput:
> + clk_put(host->clk);
> +err_free_host:
> + if (sdhci)
> + sdhci_free_host(sdhci);
> +err_unmap:
> + iounmap(sdhci->ioaddr);
> +
> + return rc;
> +}
> +
> +static int tegra_sdhci_remove(struct platform_device *pdev)
> +{
> + struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
> + if (host) {
> + struct tegra_sdhci_platform_data *plat;
> + plat = pdev->dev.platform_data;
> +
> + sdhci_remove_host(host->sdhci, 0);
> + sdhci_free_host(host->sdhci);
> + }
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
> + int ret;
> +
> + ret = sdhci_suspend_host(host->sdhci, state);
> + if (ret)
> + pr_err("%s: failed, error = %d\n", __func__, ret);
> +
> + return ret;
> +}
> +
> +static int tegra_sdhci_resume(struct platform_device *pdev)
> +{
> + struct tegra_sdhci_host *host = platform_get_drvdata(pdev);
> + int ret;
> +
> + ret = sdhci_resume_host(host->sdhci);
> + if (ret)
> + pr_err("%s: failed, error = %d\n", __func__, ret);
> +
> + return ret;
> +}
> +#else
> +#define tegra_sdhci_suspend NULL
> +#define tegra_sdhci_resume NULL
> +#endif
> +
> +static struct platform_driver tegra_sdhci_driver = {
> + .probe = tegra_sdhci_probe,
> + .remove = tegra_sdhci_remove,
> + .suspend = tegra_sdhci_suspend,
> + .resume = tegra_sdhci_resume,
> + .driver = {
> + .name = DRIVER_NAME,
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init tegra_sdhci_init(void)
> +{
> + return platform_driver_register(&tegra_sdhci_driver);
> +}
> +
> +static void __exit tegra_sdhci_exit(void)
> +{
> + platform_driver_unregister(&tegra_sdhci_driver);
> +}
> +
> +module_init(tegra_sdhci_init);
> +module_exit(tegra_sdhci_exit);
> +
> +MODULE_DESCRIPTION("Tegra SDHCI controller driver");
> +MODULE_LICENSE("GPL");
--
Sincerely yours,
Mike.
next prev parent reply other threads:[~2010-12-15 11:24 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-15 4:49 [PATCH 0/4] Add SDHCI driver for Tegra Olof Johansson
2010-12-15 4:49 ` [PATCH 1/4] sdhci: add quirk for max len ADMA descriptors Olof Johansson
2010-12-15 4:49 ` [PATCH 2/4] sdhci: add quirk for broken sdio irq Olof Johansson
2010-12-15 10:42 ` zhangfei gao
2010-12-15 10:54 ` Olof Johansson
2010-12-15 11:03 ` Wolfram Sang
2010-12-15 11:24 ` Olof Johansson
2010-12-15 11:44 ` Wolfram Sang
2010-12-15 10:57 ` Wolfram Sang
2010-12-15 11:34 ` Olof Johansson
2010-12-15 4:49 ` [PATCH 3/4] sdhci: don't finish commands in flight Olof Johansson
2010-12-15 4:49 ` [PATCH 4/4] mmc: add sdhci-tegra driver for Tegra SoCs Olof Johansson
2010-12-15 8:35 ` Wolfram Sang
2010-12-15 8:43 ` Olof Johansson
2010-12-15 8:46 ` Olof Johansson
2010-12-15 10:37 ` Wolfram Sang
2010-12-15 11:40 ` Olof Johansson
2010-12-15 11:59 ` Wolfram Sang
2010-12-15 13:03 ` Olof Johansson
2010-12-15 13:40 ` Wolfram Sang
2010-12-15 11:23 ` Mike Rapoport [this message]
2010-12-15 11:31 ` Olof Johansson
2010-12-15 11:33 ` Pavan Kondeti
2010-12-15 11:35 ` Olof Johansson
2010-12-15 11:37 ` Wolfram Sang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4D08A54E.9070103@compulab.co.il \
--to=mike@compulab.co.il \
--cc=cjb@laptop.org \
--cc=dimitrysh@google.com \
--cc=gking@nvidia.com \
--cc=linux-mmc@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=olof@lixom.net \
--cc=rklein@nvidia.com \
--cc=toddpoynor@google.com \
--cc=y@palm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox