bfin_cf_pcmcia.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. * file: drivers/pcmcia/bfin_cf.c
  3. *
  4. * based on: drivers/pcmcia/omap_cf.c
  5. * omap_cf.c -- OMAP 16xx CompactFlash controller driver
  6. *
  7. * Copyright (c) 2005 David Brownell
  8. * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc.
  9. *
  10. * bugs: enter bugs at http://blackfin.uclinux.org/
  11. *
  12. * this program is free software; you can redistribute it and/or modify
  13. * it under the terms of the gnu general public license as published by
  14. * the free software foundation; either version 2, or (at your option)
  15. * any later version.
  16. *
  17. * this program is distributed in the hope that it will be useful,
  18. * but without any warranty; without even the implied warranty of
  19. * merchantability or fitness for a particular purpose. see the
  20. * gnu general public license for more details.
  21. *
  22. * you should have received a copy of the gnu general public license
  23. * along with this program; see the file copying.
  24. * if not, write to the free software foundation,
  25. * 59 temple place - suite 330, boston, ma 02111-1307, usa.
  26. */
  27. #include <linux/module.h>
  28. #include <linux/kernel.h>
  29. #include <linux/sched.h>
  30. #include <linux/platform_device.h>
  31. #include <linux/errno.h>
  32. #include <linux/init.h>
  33. #include <linux/slab.h>
  34. #include <linux/delay.h>
  35. #include <linux/interrupt.h>
  36. #include <linux/irq.h>
  37. #include <linux/io.h>
  38. #include <pcmcia/ss.h>
  39. #include <pcmcia/cisreg.h>
  40. #include <asm/gpio.h>
  41. #define SZ_1K 0x00000400
  42. #define SZ_8K 0x00002000
  43. #define SZ_2K (2 * SZ_1K)
  44. #define POLL_INTERVAL (2 * HZ)
  45. #define CF_ATASEL_ENA 0x20311802 /* Inverts RESET */
  46. #define CF_ATASEL_DIS 0x20311800
  47. #define bfin_cf_present(pfx) (gpio_get_value(pfx))
  48. /*--------------------------------------------------------------------------*/
  49. static const char driver_name[] = "bfin_cf_pcmcia";
  50. struct bfin_cf_socket {
  51. struct pcmcia_socket socket;
  52. struct timer_list timer;
  53. unsigned present:1;
  54. unsigned active:1;
  55. struct platform_device *pdev;
  56. unsigned long phys_cf_io;
  57. unsigned long phys_cf_attr;
  58. u_int irq;
  59. u_short cd_pfx;
  60. };
  61. /*--------------------------------------------------------------------------*/
  62. static int bfin_cf_reset(void)
  63. {
  64. outw(0, CF_ATASEL_ENA);
  65. mdelay(200);
  66. outw(0, CF_ATASEL_DIS);
  67. return 0;
  68. }
  69. static int bfin_cf_ss_init(struct pcmcia_socket *s)
  70. {
  71. return 0;
  72. }
  73. /* the timer is primarily to kick this socket's pccardd */
  74. static void bfin_cf_timer(unsigned long _cf)
  75. {
  76. struct bfin_cf_socket *cf = (void *)_cf;
  77. unsigned short present = bfin_cf_present(cf->cd_pfx);
  78. if (present != cf->present) {
  79. cf->present = present;
  80. dev_dbg(&cf->pdev->dev, ": card %s\n",
  81. present ? "present" : "gone");
  82. pcmcia_parse_events(&cf->socket, SS_DETECT);
  83. }
  84. if (cf->active)
  85. mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
  86. }
  87. static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
  88. {
  89. struct bfin_cf_socket *cf;
  90. if (!sp)
  91. return -EINVAL;
  92. cf = container_of(s, struct bfin_cf_socket, socket);
  93. if (bfin_cf_present(cf->cd_pfx)) {
  94. *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
  95. s->pcmcia_irq = 0;
  96. s->pci_irq = cf->irq;
  97. } else
  98. *sp = 0;
  99. return 0;
  100. }
  101. static int
  102. bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
  103. {
  104. struct bfin_cf_socket *cf;
  105. cf = container_of(sock, struct bfin_cf_socket, socket);
  106. switch (s->Vcc) {
  107. case 0:
  108. case 33:
  109. break;
  110. case 50:
  111. break;
  112. default:
  113. return -EINVAL;
  114. }
  115. if (s->flags & SS_RESET) {
  116. disable_irq(cf->irq);
  117. bfin_cf_reset();
  118. enable_irq(cf->irq);
  119. }
  120. dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
  121. s->Vcc, s->io_irq, s->flags, s->csc_mask);
  122. return 0;
  123. }
  124. static int bfin_cf_ss_suspend(struct pcmcia_socket *s)
  125. {
  126. return bfin_cf_set_socket(s, &dead_socket);
  127. }
  128. /* regions are 2K each: mem, attrib, io (and reserved-for-ide) */
  129. static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
  130. {
  131. struct bfin_cf_socket *cf;
  132. cf = container_of(s, struct bfin_cf_socket, socket);
  133. io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
  134. io->start = cf->phys_cf_io;
  135. io->stop = io->start + SZ_2K - 1;
  136. return 0;
  137. }
  138. static int
  139. bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
  140. {
  141. struct bfin_cf_socket *cf;
  142. if (map->card_start)
  143. return -EINVAL;
  144. cf = container_of(s, struct bfin_cf_socket, socket);
  145. map->static_start = cf->phys_cf_io;
  146. map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
  147. if (map->flags & MAP_ATTRIB)
  148. map->static_start = cf->phys_cf_attr;
  149. return 0;
  150. }
  151. static struct pccard_operations bfin_cf_ops = {
  152. .init = bfin_cf_ss_init,
  153. .suspend = bfin_cf_ss_suspend,
  154. .get_status = bfin_cf_get_status,
  155. .set_socket = bfin_cf_set_socket,
  156. .set_io_map = bfin_cf_set_io_map,
  157. .set_mem_map = bfin_cf_set_mem_map,
  158. };
  159. /*--------------------------------------------------------------------------*/
  160. static int bfin_cf_probe(struct platform_device *pdev)
  161. {
  162. struct bfin_cf_socket *cf;
  163. struct resource *io_mem, *attr_mem;
  164. int irq;
  165. unsigned short cd_pfx;
  166. int status = 0;
  167. dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
  168. irq = platform_get_irq(pdev, 0);
  169. if (irq <= 0)
  170. return -EINVAL;
  171. cd_pfx = platform_get_irq(pdev, 1); /*Card Detect GPIO PIN */
  172. if (gpio_request(cd_pfx, "pcmcia: CD")) {
  173. dev_err(&pdev->dev,
  174. "Failed ro request Card Detect GPIO_%d\n",
  175. cd_pfx);
  176. return -EBUSY;
  177. }
  178. gpio_direction_input(cd_pfx);
  179. cf = kzalloc(sizeof *cf, GFP_KERNEL);
  180. if (!cf) {
  181. gpio_free(cd_pfx);
  182. return -ENOMEM;
  183. }
  184. cf->cd_pfx = cd_pfx;
  185. setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
  186. cf->pdev = pdev;
  187. platform_set_drvdata(pdev, cf);
  188. cf->irq = irq;
  189. cf->socket.pci_irq = irq;
  190. irq_set_irq_type(irq, IRQF_TRIGGER_LOW);
  191. io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  192. attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  193. if (!io_mem || !attr_mem)
  194. goto fail0;
  195. cf->phys_cf_io = io_mem->start;
  196. cf->phys_cf_attr = attr_mem->start;
  197. /* pcmcia layer only remaps "real" memory */
  198. cf->socket.io_offset = (unsigned long)
  199. ioremap(cf->phys_cf_io, SZ_2K);
  200. if (!cf->socket.io_offset)
  201. goto fail0;
  202. dev_err(&pdev->dev, ": on irq %d\n", irq);
  203. dev_dbg(&pdev->dev, ": %s\n",
  204. bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)");
  205. cf->socket.owner = THIS_MODULE;
  206. cf->socket.dev.parent = &pdev->dev;
  207. cf->socket.ops = &bfin_cf_ops;
  208. cf->socket.resource_ops = &pccard_static_ops;
  209. cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
  210. | SS_CAP_MEM_ALIGN;
  211. cf->socket.map_size = SZ_2K;
  212. status = pcmcia_register_socket(&cf->socket);
  213. if (status < 0)
  214. goto fail2;
  215. cf->active = 1;
  216. mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
  217. return 0;
  218. fail2:
  219. iounmap((void __iomem *)cf->socket.io_offset);
  220. release_mem_region(cf->phys_cf_io, SZ_8K);
  221. fail0:
  222. gpio_free(cf->cd_pfx);
  223. kfree(cf);
  224. platform_set_drvdata(pdev, NULL);
  225. return status;
  226. }
  227. static int bfin_cf_remove(struct platform_device *pdev)
  228. {
  229. struct bfin_cf_socket *cf = platform_get_drvdata(pdev);
  230. gpio_free(cf->cd_pfx);
  231. cf->active = 0;
  232. pcmcia_unregister_socket(&cf->socket);
  233. del_timer_sync(&cf->timer);
  234. iounmap((void __iomem *)cf->socket.io_offset);
  235. release_mem_region(cf->phys_cf_io, SZ_8K);
  236. platform_set_drvdata(pdev, NULL);
  237. kfree(cf);
  238. return 0;
  239. }
  240. static struct platform_driver bfin_cf_driver = {
  241. .driver = {
  242. .name = driver_name,
  243. },
  244. .probe = bfin_cf_probe,
  245. .remove = bfin_cf_remove,
  246. };
  247. module_platform_driver(bfin_cf_driver);
  248. MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
  249. MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
  250. MODULE_LICENSE("GPL");