kirkwood_spi.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * (C) Copyright 2009
  3. * Marvell Semiconductor <www.marvell.com>
  4. * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
  5. *
  6. * Derived from drivers/spi/mpc8xxx_spi.c
  7. *
  8. * SPDX-License-Identifier: GPL-2.0+
  9. */
  10. #include <common.h>
  11. #include <malloc.h>
  12. #include <spi.h>
  13. #include <asm/io.h>
  14. #include <asm/arch/kirkwood.h>
  15. #include <asm/arch/spi.h>
  16. #include <asm/arch/mpp.h>
  17. static struct kwspi_registers *spireg = (struct kwspi_registers *)KW_SPI_BASE;
  18. u32 cs_spi_mpp_back[2];
  19. struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
  20. unsigned int max_hz, unsigned int mode)
  21. {
  22. struct spi_slave *slave;
  23. u32 data;
  24. static const u32 kwspi_mpp_config[2][2] = {
  25. { MPP0_SPI_SCn, 0 }, /* if cs == 0 */
  26. { MPP7_SPI_SCn, 0 } /* if cs != 0 */
  27. };
  28. if (!spi_cs_is_valid(bus, cs))
  29. return NULL;
  30. slave = spi_alloc_slave_base(bus, cs);
  31. if (!slave)
  32. return NULL;
  33. writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
  34. /* calculate spi clock prescaller using max_hz */
  35. data = ((CONFIG_SYS_TCLK / 2) / max_hz) + 0x10;
  36. data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data;
  37. data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data;
  38. /* program spi clock prescaller using max_hz */
  39. writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
  40. debug("data = 0x%08x \n", data);
  41. writel(KWSPI_SMEMRDIRQ, &spireg->irq_cause);
  42. writel(KWSPI_IRQMASK, &spireg->irq_mask);
  43. /* program mpp registers to select SPI_CSn */
  44. kirkwood_mpp_conf(kwspi_mpp_config[cs ? 1 : 0], cs_spi_mpp_back);
  45. return slave;
  46. }
  47. void spi_free_slave(struct spi_slave *slave)
  48. {
  49. kirkwood_mpp_conf(cs_spi_mpp_back, NULL);
  50. free(slave);
  51. }
  52. #if defined(CONFIG_SYS_KW_SPI_MPP)
  53. u32 spi_mpp_backup[4];
  54. #endif
  55. __attribute__((weak)) int board_spi_claim_bus(struct spi_slave *slave)
  56. {
  57. return 0;
  58. }
  59. int spi_claim_bus(struct spi_slave *slave)
  60. {
  61. #if defined(CONFIG_SYS_KW_SPI_MPP)
  62. u32 config;
  63. u32 spi_mpp_config[4];
  64. config = CONFIG_SYS_KW_SPI_MPP;
  65. if (config & MOSI_MPP6)
  66. spi_mpp_config[0] = MPP6_SPI_MOSI;
  67. else
  68. spi_mpp_config[0] = MPP1_SPI_MOSI;
  69. if (config & SCK_MPP10)
  70. spi_mpp_config[1] = MPP10_SPI_SCK;
  71. else
  72. spi_mpp_config[1] = MPP2_SPI_SCK;
  73. if (config & MISO_MPP11)
  74. spi_mpp_config[2] = MPP11_SPI_MISO;
  75. else
  76. spi_mpp_config[2] = MPP3_SPI_MISO;
  77. spi_mpp_config[3] = 0;
  78. spi_mpp_backup[3] = 0;
  79. /* set new spi mpp and save current mpp config */
  80. kirkwood_mpp_conf(spi_mpp_config, spi_mpp_backup);
  81. #endif
  82. return board_spi_claim_bus(slave);
  83. }
  84. __attribute__((weak)) void board_spi_release_bus(struct spi_slave *slave)
  85. {
  86. }
  87. void spi_release_bus(struct spi_slave *slave)
  88. {
  89. #if defined(CONFIG_SYS_KW_SPI_MPP)
  90. kirkwood_mpp_conf(spi_mpp_backup, NULL);
  91. #endif
  92. board_spi_release_bus(slave);
  93. }
  94. #ifndef CONFIG_SPI_CS_IS_VALID
  95. /*
  96. * you can define this function board specific
  97. * define above CONFIG in board specific config file and
  98. * provide the function in board specific src file
  99. */
  100. int spi_cs_is_valid(unsigned int bus, unsigned int cs)
  101. {
  102. return (bus == 0 && (cs == 0 || cs == 1));
  103. }
  104. #endif
  105. void spi_init(void)
  106. {
  107. }
  108. void spi_cs_activate(struct spi_slave *slave)
  109. {
  110. writel(readl(&spireg->ctrl) | KWSPI_IRQUNMASK, &spireg->ctrl);
  111. }
  112. void spi_cs_deactivate(struct spi_slave *slave)
  113. {
  114. writel(readl(&spireg->ctrl) & KWSPI_IRQMASK, &spireg->ctrl);
  115. }
  116. int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
  117. void *din, unsigned long flags)
  118. {
  119. unsigned int tmpdout, tmpdin;
  120. int tm, isread = 0;
  121. debug("spi_xfer: slave %u:%u dout %p din %p bitlen %u\n",
  122. slave->bus, slave->cs, dout, din, bitlen);
  123. if (flags & SPI_XFER_BEGIN)
  124. spi_cs_activate(slave);
  125. /*
  126. * handle data in 8-bit chunks
  127. * TBD: 2byte xfer mode to be enabled
  128. */
  129. writel(((readl(&spireg->cfg) & ~KWSPI_XFERLEN_MASK) |
  130. KWSPI_XFERLEN_1BYTE), &spireg->cfg);
  131. while (bitlen > 4) {
  132. debug("loopstart bitlen %d\n", bitlen);
  133. tmpdout = 0;
  134. /* Shift data so it's msb-justified */
  135. if (dout)
  136. tmpdout = *(u32 *) dout & 0x0ff;
  137. writel(~KWSPI_SMEMRDIRQ, &spireg->irq_cause);
  138. writel(tmpdout, &spireg->dout); /* Write the data out */
  139. debug("*** spi_xfer: ... %08x written, bitlen %d\n",
  140. tmpdout, bitlen);
  141. /*
  142. * Wait for SPI transmit to get out
  143. * or time out (1 second = 1000 ms)
  144. * The NE event must be read and cleared first
  145. */
  146. for (tm = 0, isread = 0; tm < KWSPI_TIMEOUT; ++tm) {
  147. if (readl(&spireg->irq_cause) & KWSPI_SMEMRDIRQ) {
  148. isread = 1;
  149. tmpdin = readl(&spireg->din);
  150. debug
  151. ("spi_xfer: din %p..%08x read\n",
  152. din, tmpdin);
  153. if (din) {
  154. *((u8 *) din) = (u8) tmpdin;
  155. din += 1;
  156. }
  157. if (dout)
  158. dout += 1;
  159. bitlen -= 8;
  160. }
  161. if (isread)
  162. break;
  163. }
  164. if (tm >= KWSPI_TIMEOUT)
  165. printf("*** spi_xfer: Time out during SPI transfer\n");
  166. debug("loopend bitlen %d\n", bitlen);
  167. }
  168. if (flags & SPI_XFER_END)
  169. spi_cs_deactivate(slave);
  170. return 0;
  171. }