sdhci-cns3xxx.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /*
  2. * SDHCI support for CNS3xxx SoC
  3. *
  4. * Copyright 2008 Cavium Networks
  5. * Copyright 2010 MontaVista Software, LLC.
  6. *
  7. * Authors: Scott Shu
  8. * Anton Vorontsov <avorontsov@mvista.com>
  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. #include <linux/delay.h>
  15. #include <linux/device.h>
  16. #include <linux/mmc/host.h>
  17. #include <linux/mmc/sdhci-pltfm.h>
  18. #include <mach/cns3xxx.h>
  19. #include "sdhci.h"
  20. #include "sdhci-pltfm.h"
  21. static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host)
  22. {
  23. return 150000000;
  24. }
  25. static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
  26. {
  27. struct device *dev = mmc_dev(host->mmc);
  28. int div = 1;
  29. u16 clk;
  30. unsigned long timeout;
  31. if (clock == host->clock)
  32. return;
  33. sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
  34. if (clock == 0)
  35. goto out;
  36. while (host->max_clk / div > clock) {
  37. /*
  38. * On CNS3xxx divider grows linearly up to 4, and then
  39. * exponentially up to 256.
  40. */
  41. if (div < 4)
  42. div += 1;
  43. else if (div < 256)
  44. div *= 2;
  45. else
  46. break;
  47. }
  48. dev_dbg(dev, "desired SD clock: %d, actual: %d\n",
  49. clock, host->max_clk / div);
  50. /* Divide by 3 is special. */
  51. if (div != 3)
  52. div >>= 1;
  53. clk = div << SDHCI_DIVIDER_SHIFT;
  54. clk |= SDHCI_CLOCK_INT_EN;
  55. sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
  56. timeout = 20;
  57. while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
  58. & SDHCI_CLOCK_INT_STABLE)) {
  59. if (timeout == 0) {
  60. dev_warn(dev, "clock is unstable");
  61. break;
  62. }
  63. timeout--;
  64. mdelay(1);
  65. }
  66. clk |= SDHCI_CLOCK_CARD_EN;
  67. sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
  68. out:
  69. host->clock = clock;
  70. }
  71. static struct sdhci_ops sdhci_cns3xxx_ops = {
  72. .get_max_clock = sdhci_cns3xxx_get_max_clk,
  73. .set_clock = sdhci_cns3xxx_set_clock,
  74. };
  75. struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
  76. .ops = &sdhci_cns3xxx_ops,
  77. .quirks = SDHCI_QUIRK_BROKEN_DMA |
  78. SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
  79. SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
  80. SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
  81. SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
  82. SDHCI_QUIRK_NONSTANDARD_CLOCK,
  83. };