All of lore.kernel.org
 help / color / mirror / Atom feed
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.

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.