mcp-sa11x0.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. * linux/drivers/mfd/mcp-sa11x0.c
  3. *
  4. * Copyright (C) 2001-2005 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License.
  9. *
  10. * SA11x0 MCP (Multimedia Communications Port) driver.
  11. *
  12. * MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/init.h>
  16. #include <linux/errno.h>
  17. #include <linux/kernel.h>
  18. #include <linux/delay.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/mfd/mcp.h>
  22. #include <linux/io.h>
  23. #include <mach/dma.h>
  24. #include <mach/hardware.h>
  25. #include <asm/mach-types.h>
  26. #include <asm/system.h>
  27. #include <mach/mcp.h>
  28. /* Register offsets */
  29. #define MCCR0 0x00
  30. #define MCDR0 0x08
  31. #define MCDR1 0x0C
  32. #define MCDR2 0x10
  33. #define MCSR 0x18
  34. #define MCCR1 0x00
  35. struct mcp_sa11x0 {
  36. u32 mccr0;
  37. u32 mccr1;
  38. unsigned char *mccr0_base;
  39. unsigned char *mccr1_base;
  40. };
  41. #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
  42. static void
  43. mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
  44. {
  45. struct mcp_sa11x0 *priv = priv(mcp);
  46. divisor /= 32;
  47. priv->mccr0 &= ~0x00007f00;
  48. priv->mccr0 |= divisor << 8;
  49. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  50. }
  51. static void
  52. mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
  53. {
  54. struct mcp_sa11x0 *priv = priv(mcp);
  55. divisor /= 32;
  56. priv->mccr0 &= ~0x0000007f;
  57. priv->mccr0 |= divisor;
  58. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  59. }
  60. /*
  61. * Write data to the device. The bit should be set after 3 subframe
  62. * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
  63. * We really should try doing something more productive while we
  64. * wait.
  65. */
  66. static void
  67. mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
  68. {
  69. int ret = -ETIME;
  70. int i;
  71. u32 mcpreg;
  72. struct mcp_sa11x0 *priv = priv(mcp);
  73. mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
  74. __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
  75. for (i = 0; i < 2; i++) {
  76. udelay(mcp->rw_timeout);
  77. mcpreg = __raw_readl(priv->mccr0_base + MCSR);
  78. if (mcpreg & MCSR_CWC) {
  79. ret = 0;
  80. break;
  81. }
  82. }
  83. if (ret < 0)
  84. printk(KERN_WARNING "mcp: write timed out\n");
  85. }
  86. /*
  87. * Read data from the device. The bit should be set after 3 subframe
  88. * times (each frame is 64 clocks). We wait a maximum of 6 subframes.
  89. * We really should try doing something more productive while we
  90. * wait.
  91. */
  92. static unsigned int
  93. mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
  94. {
  95. int ret = -ETIME;
  96. int i;
  97. u32 mcpreg;
  98. struct mcp_sa11x0 *priv = priv(mcp);
  99. mcpreg = reg << 17 | MCDR2_Rd;
  100. __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
  101. for (i = 0; i < 2; i++) {
  102. udelay(mcp->rw_timeout);
  103. mcpreg = __raw_readl(priv->mccr0_base + MCSR);
  104. if (mcpreg & MCSR_CRC) {
  105. ret = __raw_readl(priv->mccr0_base + MCDR2)
  106. & 0xffff;
  107. break;
  108. }
  109. }
  110. if (ret < 0)
  111. printk(KERN_WARNING "mcp: read timed out\n");
  112. return ret;
  113. }
  114. static void mcp_sa11x0_enable(struct mcp *mcp)
  115. {
  116. struct mcp_sa11x0 *priv = priv(mcp);
  117. __raw_writel(-1, priv->mccr0_base + MCSR);
  118. priv->mccr0 |= MCCR0_MCE;
  119. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  120. }
  121. static void mcp_sa11x0_disable(struct mcp *mcp)
  122. {
  123. struct mcp_sa11x0 *priv = priv(mcp);
  124. priv->mccr0 &= ~MCCR0_MCE;
  125. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  126. }
  127. /*
  128. * Our methods.
  129. */
  130. static struct mcp_ops mcp_sa11x0 = {
  131. .set_telecom_divisor = mcp_sa11x0_set_telecom_divisor,
  132. .set_audio_divisor = mcp_sa11x0_set_audio_divisor,
  133. .reg_write = mcp_sa11x0_write,
  134. .reg_read = mcp_sa11x0_read,
  135. .enable = mcp_sa11x0_enable,
  136. .disable = mcp_sa11x0_disable,
  137. };
  138. static int mcp_sa11x0_probe(struct platform_device *pdev)
  139. {
  140. struct mcp_plat_data *data = pdev->dev.platform_data;
  141. struct mcp *mcp;
  142. int ret;
  143. struct mcp_sa11x0 *priv;
  144. struct resource *res_mem0, *res_mem1;
  145. u32 size0, size1;
  146. if (!data)
  147. return -ENODEV;
  148. if (!data->codec)
  149. return -ENODEV;
  150. res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  151. if (!res_mem0)
  152. return -ENODEV;
  153. size0 = res_mem0->end - res_mem0->start + 1;
  154. res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  155. if (!res_mem1)
  156. return -ENODEV;
  157. size1 = res_mem1->end - res_mem1->start + 1;
  158. if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
  159. return -EBUSY;
  160. if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
  161. ret = -EBUSY;
  162. goto release;
  163. }
  164. mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
  165. if (!mcp) {
  166. ret = -ENOMEM;
  167. goto release2;
  168. }
  169. priv = priv(mcp);
  170. mcp->owner = THIS_MODULE;
  171. mcp->ops = &mcp_sa11x0;
  172. mcp->sclk_rate = data->sclk_rate;
  173. mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0)
  174. + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
  175. mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0)
  176. + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
  177. mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1)
  178. + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
  179. mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1)
  180. + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
  181. mcp->codec = data->codec;
  182. platform_set_drvdata(pdev, mcp);
  183. /*
  184. * Initialise device. Note that we initially
  185. * set the sampling rate to minimum.
  186. */
  187. priv->mccr0_base = ioremap(res_mem0->start, size0);
  188. priv->mccr1_base = ioremap(res_mem1->start, size1);
  189. __raw_writel(-1, priv->mccr0_base + MCSR);
  190. priv->mccr1 = data->mccr1;
  191. priv->mccr0 = data->mccr0 | 0x7f7f;
  192. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  193. __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
  194. /*
  195. * Calculate the read/write timeout (us) from the bit clock
  196. * rate. This is the period for 3 64-bit frames. Always
  197. * round this time up.
  198. */
  199. mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
  200. mcp->sclk_rate;
  201. ret = mcp_host_register(mcp, data->codec_pdata);
  202. if (ret == 0)
  203. goto out;
  204. release2:
  205. release_mem_region(res_mem1->start, size1);
  206. release:
  207. release_mem_region(res_mem0->start, size0);
  208. platform_set_drvdata(pdev, NULL);
  209. out:
  210. return ret;
  211. }
  212. static int mcp_sa11x0_remove(struct platform_device *pdev)
  213. {
  214. struct mcp *mcp = platform_get_drvdata(pdev);
  215. struct mcp_sa11x0 *priv = priv(mcp);
  216. struct resource *res_mem;
  217. u32 size;
  218. platform_set_drvdata(pdev, NULL);
  219. mcp_host_unregister(mcp);
  220. res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  221. if (res_mem) {
  222. size = res_mem->end - res_mem->start + 1;
  223. release_mem_region(res_mem->start, size);
  224. }
  225. res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  226. if (res_mem) {
  227. size = res_mem->end - res_mem->start + 1;
  228. release_mem_region(res_mem->start, size);
  229. }
  230. iounmap(priv->mccr0_base);
  231. iounmap(priv->mccr1_base);
  232. return 0;
  233. }
  234. static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
  235. {
  236. struct mcp *mcp = platform_get_drvdata(dev);
  237. struct mcp_sa11x0 *priv = priv(mcp);
  238. u32 mccr0;
  239. mccr0 = priv->mccr0 & ~MCCR0_MCE;
  240. __raw_writel(mccr0, priv->mccr0_base + MCCR0);
  241. return 0;
  242. }
  243. static int mcp_sa11x0_resume(struct platform_device *dev)
  244. {
  245. struct mcp *mcp = platform_get_drvdata(dev);
  246. struct mcp_sa11x0 *priv = priv(mcp);
  247. __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
  248. __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
  249. return 0;
  250. }
  251. /*
  252. * The driver for the SA11x0 MCP port.
  253. */
  254. MODULE_ALIAS("platform:sa11x0-mcp");
  255. static struct platform_driver mcp_sa11x0_driver = {
  256. .probe = mcp_sa11x0_probe,
  257. .remove = mcp_sa11x0_remove,
  258. .suspend = mcp_sa11x0_suspend,
  259. .resume = mcp_sa11x0_resume,
  260. .driver = {
  261. .name = "sa11x0-mcp",
  262. .owner = THIS_MODULE,
  263. },
  264. };
  265. /*
  266. * This needs re-working
  267. */
  268. module_platform_driver(mcp_sa11x0_driver);
  269. MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
  270. MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
  271. MODULE_LICENSE("GPL");