linux/drivers/mmc/host/sdhci-s3c.c
<<
>>
Prefs
   1/* linux/drivers/mmc/host/sdhci-s3c.c
   2 *
   3 * Copyright 2008 Openmoko Inc.
   4 * Copyright 2008 Simtec Electronics
   5 *      Ben Dooks <ben@simtec.co.uk>
   6 *      http://armlinux.simtec.co.uk/
   7 *
   8 * SDHCI (HSMMC) support for Samsung SoC
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#include <linux/delay.h>
  16#include <linux/dma-mapping.h>
  17#include <linux/platform_device.h>
  18#include <linux/clk.h>
  19#include <linux/io.h>
  20
  21#include <linux/mmc/host.h>
  22
  23#include <plat/sdhci.h>
  24#include <plat/regs-sdhci.h>
  25
  26#include "sdhci.h"
  27
  28#define MAX_BUS_CLK     (4)
  29
  30/**
  31 * struct sdhci_s3c - S3C SDHCI instance
  32 * @host: The SDHCI host created
  33 * @pdev: The platform device we where created from.
  34 * @ioarea: The resource created when we claimed the IO area.
  35 * @pdata: The platform data for this controller.
  36 * @cur_clk: The index of the current bus clock.
  37 * @clk_io: The clock for the internal bus interface.
  38 * @clk_bus: The clocks that are available for the SD/MMC bus clock.
  39 */
  40struct sdhci_s3c {
  41        struct sdhci_host       *host;
  42        struct platform_device  *pdev;
  43        struct resource         *ioarea;
  44        struct s3c_sdhci_platdata *pdata;
  45        unsigned int            cur_clk;
  46
  47        struct clk              *clk_io;
  48        struct clk              *clk_bus[MAX_BUS_CLK];
  49};
  50
  51static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
  52{
  53        return sdhci_priv(host);
  54}
  55
  56/**
  57 * get_curclk - convert ctrl2 register to clock source number
  58 * @ctrl2: Control2 register value.
  59 */
  60static u32 get_curclk(u32 ctrl2)
  61{
  62        ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
  63        ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
  64
  65        return ctrl2;
  66}
  67
  68static void sdhci_s3c_check_sclk(struct sdhci_host *host)
  69{
  70        struct sdhci_s3c *ourhost = to_s3c(host);
  71        u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
  72
  73        if (get_curclk(tmp) != ourhost->cur_clk) {
  74                dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n");
  75
  76                tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
  77                tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
  78                writel(tmp, host->ioaddr + 0x80);
  79        }
  80}
  81
  82/**
  83 * sdhci_s3c_get_max_clk - callback to get maximum clock frequency.
  84 * @host: The SDHCI host instance.
  85 *
  86 * Callback to return the maximum clock rate acheivable by the controller.
  87*/
  88static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
  89{
  90        struct sdhci_s3c *ourhost = to_s3c(host);
  91        struct clk *busclk;
  92        unsigned int rate, max;
  93        int clk;
  94
  95        /* note, a reset will reset the clock source */
  96
  97        sdhci_s3c_check_sclk(host);
  98
  99        for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) {
 100                busclk = ourhost->clk_bus[clk];
 101                if (!busclk)
 102                        continue;
 103
 104                rate = clk_get_rate(busclk);
 105                if (rate > max)
 106                        max = rate;
 107        }
 108
 109        return max;
 110}
 111
 112static unsigned int sdhci_s3c_get_timeout_clk(struct sdhci_host *host)
 113{
 114        return sdhci_s3c_get_max_clk(host) / 1000000;
 115}
 116
 117/**
 118 * sdhci_s3c_consider_clock - consider one the bus clocks for current setting
 119 * @ourhost: Our SDHCI instance.
 120 * @src: The source clock index.
 121 * @wanted: The clock frequency wanted.
 122 */
 123static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 124                                             unsigned int src,
 125                                             unsigned int wanted)
 126{
 127        unsigned long rate;
 128        struct clk *clksrc = ourhost->clk_bus[src];
 129        int div;
 130
 131        if (!clksrc)
 132                return UINT_MAX;
 133
 134        rate = clk_get_rate(clksrc);
 135
 136        for (div = 1; div < 256; div *= 2) {
 137                if ((rate / div) <= wanted)
 138                        break;
 139        }
 140
 141        dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
 142                src, rate, wanted, rate / div);
 143
 144        return (wanted - (rate / div));
 145}
 146
 147/**
 148 * sdhci_s3c_set_clock - callback on clock change
 149 * @host: The SDHCI host being changed
 150 * @clock: The clock rate being requested.
 151 *
 152 * When the card's clock is going to be changed, look at the new frequency
 153 * and find the best clock source to go with it.
 154*/
 155static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 156{
 157        struct sdhci_s3c *ourhost = to_s3c(host);
 158        unsigned int best = UINT_MAX;
 159        unsigned int delta;
 160        int best_src = 0;
 161        int src;
 162        u32 ctrl;
 163
 164        /* don't bother if the clock is going off. */
 165        if (clock == 0)
 166                return;
 167
 168        for (src = 0; src < MAX_BUS_CLK; src++) {
 169                delta = sdhci_s3c_consider_clock(ourhost, src, clock);
 170                if (delta < best) {
 171                        best = delta;
 172                        best_src = src;
 173                }
 174        }
 175
 176        dev_dbg(&ourhost->pdev->dev,
 177                "selected source %d, clock %d, delta %d\n",
 178                 best_src, clock, best);
 179
 180        /* select the new clock source */
 181
 182        if (ourhost->cur_clk != best_src) {
 183                struct clk *clk = ourhost->clk_bus[best_src];
 184
 185                /* turn clock off to card before changing clock source */
 186                writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
 187
 188                ourhost->cur_clk = best_src;
 189                host->max_clk = clk_get_rate(clk);
 190                host->timeout_clk = sdhci_s3c_get_timeout_clk(host);
 191
 192                ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
 193                ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
 194                ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
 195                writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
 196        }
 197
 198        /* reconfigure the hardware for new clock rate */
 199
 200        {
 201                struct mmc_ios ios;
 202
 203                ios.clock = clock;
 204
 205                if (ourhost->pdata->cfg_card)
 206                        (ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr,
 207                                                   &ios, NULL);
 208        }
 209}
 210
 211static struct sdhci_ops sdhci_s3c_ops = {
 212        .get_max_clock          = sdhci_s3c_get_max_clk,
 213        .get_timeout_clock      = sdhci_s3c_get_timeout_clk,
 214        .set_clock              = sdhci_s3c_set_clock,
 215};
 216
 217static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
 218{
 219        struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
 220        struct device *dev = &pdev->dev;
 221        struct sdhci_host *host;
 222        struct sdhci_s3c *sc;
 223        struct resource *res;
 224        int ret, irq, ptr, clks;
 225
 226        if (!pdata) {
 227                dev_err(dev, "no device data specified\n");
 228                return -ENOENT;
 229        }
 230
 231        irq = platform_get_irq(pdev, 0);
 232        if (irq < 0) {
 233                dev_err(dev, "no irq specified\n");
 234                return irq;
 235        }
 236
 237        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 238        if (!res) {
 239                dev_err(dev, "no memory specified\n");
 240                return -ENOENT;
 241        }
 242
 243        host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c));
 244        if (IS_ERR(host)) {
 245                dev_err(dev, "sdhci_alloc_host() failed\n");
 246                return PTR_ERR(host);
 247        }
 248
 249        sc = sdhci_priv(host);
 250
 251        sc->host = host;
 252        sc->pdev = pdev;
 253        sc->pdata = pdata;
 254
 255        platform_set_drvdata(pdev, host);
 256
 257        sc->clk_io = clk_get(dev, "hsmmc");
 258        if (IS_ERR(sc->clk_io)) {
 259                dev_err(dev, "failed to get io clock\n");
 260                ret = PTR_ERR(sc->clk_io);
 261                goto err_io_clk;
 262        }
 263
 264        /* enable the local io clock and keep it running for the moment. */
 265        clk_enable(sc->clk_io);
 266
 267        for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
 268                struct clk *clk;
 269                char *name = pdata->clocks[ptr];
 270
 271                if (name == NULL)
 272                        continue;
 273
 274                clk = clk_get(dev, name);
 275                if (IS_ERR(clk)) {
 276                        dev_err(dev, "failed to get clock %s\n", name);
 277                        continue;
 278                }
 279
 280                clks++;
 281                sc->clk_bus[ptr] = clk;
 282                clk_enable(clk);
 283
 284                dev_info(dev, "clock source %d: %s (%ld Hz)\n",
 285                         ptr, name, clk_get_rate(clk));
 286        }
 287
 288        if (clks == 0) {
 289                dev_err(dev, "failed to find any bus clocks\n");
 290                ret = -ENOENT;
 291                goto err_no_busclks;
 292        }
 293
 294        sc->ioarea = request_mem_region(res->start, resource_size(res),
 295                                        mmc_hostname(host->mmc));
 296        if (!sc->ioarea) {
 297                dev_err(dev, "failed to reserve register area\n");
 298                ret = -ENXIO;
 299                goto err_req_regs;
 300        }
 301
 302        host->ioaddr = ioremap_nocache(res->start, resource_size(res));
 303        if (!host->ioaddr) {
 304                dev_err(dev, "failed to map registers\n");
 305                ret = -ENXIO;
 306                goto err_req_regs;
 307        }
 308
 309        /* Ensure we have minimal gpio selected CMD/CLK/Detect */
 310        if (pdata->cfg_gpio)
 311                pdata->cfg_gpio(pdev, pdata->max_width);
 312
 313        host->hw_name = "samsung-hsmmc";
 314        host->ops = &sdhci_s3c_ops;
 315        host->quirks = 0;
 316        host->irq = irq;
 317
 318        /* Setup quirks for the controller */
 319
 320        /* Currently with ADMA enabled we are getting some length
 321         * interrupts that are not being dealt with, do disable
 322         * ADMA until this is sorted out. */
 323        host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 324        host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE;
 325
 326#ifndef CONFIG_MMC_SDHCI_S3C_DMA
 327
 328        /* we currently see overruns on errors, so disable the SDMA
 329         * support as well. */
 330        host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
 331
 332        /* PIO currently has problems with multi-block IO */
 333        host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
 334
 335#endif /* CONFIG_MMC_SDHCI_S3C_DMA */
 336
 337        /* It seems we do not get an DATA transfer complete on non-busy
 338         * transfers, not sure if this is a problem with this specific
 339         * SDHCI block, or a missing configuration that needs to be set. */
 340        host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
 341
 342        host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
 343                         SDHCI_QUIRK_32BIT_DMA_SIZE);
 344
 345        ret = sdhci_add_host(host);
 346        if (ret) {
 347                dev_err(dev, "sdhci_add_host() failed\n");
 348                goto err_add_host;
 349        }
 350
 351        return 0;
 352
 353 err_add_host:
 354        release_resource(sc->ioarea);
 355        kfree(sc->ioarea);
 356
 357 err_req_regs:
 358        for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
 359                clk_disable(sc->clk_bus[ptr]);
 360                clk_put(sc->clk_bus[ptr]);
 361        }
 362
 363 err_no_busclks:
 364        clk_disable(sc->clk_io);
 365        clk_put(sc->clk_io);
 366
 367 err_io_clk:
 368        sdhci_free_host(host);
 369
 370        return ret;
 371}
 372
 373static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
 374{
 375        return 0;
 376}
 377
 378#ifdef CONFIG_PM
 379
 380static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm)
 381{
 382        struct sdhci_host *host = platform_get_drvdata(dev);
 383
 384        sdhci_suspend_host(host, pm);
 385        return 0;
 386}
 387
 388static int sdhci_s3c_resume(struct platform_device *dev)
 389{
 390        struct sdhci_host *host = platform_get_drvdata(dev);
 391
 392        sdhci_resume_host(host);
 393        return 0;
 394}
 395
 396#else
 397#define sdhci_s3c_suspend NULL
 398#define sdhci_s3c_resume NULL
 399#endif
 400
 401static struct platform_driver sdhci_s3c_driver = {
 402        .probe          = sdhci_s3c_probe,
 403        .remove         = __devexit_p(sdhci_s3c_remove),
 404        .suspend        = sdhci_s3c_suspend,
 405        .resume         = sdhci_s3c_resume,
 406        .driver         = {
 407                .owner  = THIS_MODULE,
 408                .name   = "s3c-sdhci",
 409        },
 410};
 411
 412static int __init sdhci_s3c_init(void)
 413{
 414        return platform_driver_register(&sdhci_s3c_driver);
 415}
 416
 417static void __exit sdhci_s3c_exit(void)
 418{
 419        platform_driver_unregister(&sdhci_s3c_driver);
 420}
 421
 422module_init(sdhci_s3c_init);
 423module_exit(sdhci_s3c_exit);
 424
 425MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
 426MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 427MODULE_LICENSE("GPL v2");
 428MODULE_ALIAS("platform:s3c-sdhci");
 429
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.