Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
 28 #include <linux/module.h>
 29 #include <linux/kernel.h>
 30 #include <linux/sched.h>
 31 #include <linux/platform_device.h>
 32 #include <linux/errno.h>
 33 #include <linux/init.h>
 34 #include <linux/delay.h>
 35 #include <linux/interrupt.h>
 36 #include <linux/irq.h>
 37 #include <linux/io.h>
 38 
 39 #include <pcmcia/ss.h>
 40 #include <pcmcia/cisreg.h>
 41 #include <asm/gpio.h>
 42 
 43 #define SZ_1K   0x00000400
 44 #define SZ_8K   0x00002000
 45 #define SZ_2K   (2 * SZ_1K)
 46 
 47 #define POLL_INTERVAL   (2 * HZ)
 48 
 49 #define CF_ATASEL_ENA   0x20311802      /* Inverts RESET */
 50 #define CF_ATASEL_DIS   0x20311800
 51 
 52 #define bfin_cf_present(pfx) (gpio_get_value(pfx))
 53 
 54 /*--------------------------------------------------------------------------*/
 55 
 56 static const char driver_name[] = "bfin_cf_pcmcia";
 57 
 58 struct bfin_cf_socket {
 59         struct pcmcia_socket socket;
 60 
 61         struct timer_list timer;
 62         unsigned present:1;
 63         unsigned active:1;
 64 
 65         struct platform_device *pdev;
 66         unsigned long phys_cf_io;
 67         unsigned long phys_cf_attr;
 68         u_int irq;
 69         u_short cd_pfx;
 70 };
 71 
 72 /*--------------------------------------------------------------------------*/
 73 static int bfin_cf_reset(void)
 74 {
 75         outw(0, CF_ATASEL_ENA);
 76         mdelay(200);
 77         outw(0, CF_ATASEL_DIS);
 78 
 79         return 0;
 80 }
 81 
 82 static int bfin_cf_ss_init(struct pcmcia_socket *s)
 83 {
 84         return 0;
 85 }
 86 
 87 /* the timer is primarily to kick this socket's pccardd */
 88 static void bfin_cf_timer(unsigned long _cf)
 89 {
 90         struct bfin_cf_socket *cf = (void *)_cf;
 91         unsigned short present = bfin_cf_present(cf->cd_pfx);
 92 
 93         if (present != cf->present) {
 94                 cf->present = present;
 95                 dev_dbg(&cf->pdev->dev, ": card %s\n",
 96                          present ? "present" : "gone");
 97                 pcmcia_parse_events(&cf->socket, SS_DETECT);
 98         }
 99 
100         if (cf->active)
101                 mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
102 }
103 
104 static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
105 {
106         struct bfin_cf_socket *cf;
107 
108         if (!sp)
109                 return -EINVAL;
110 
111         cf = container_of(s, struct bfin_cf_socket, socket);
112 
113         if (bfin_cf_present(cf->cd_pfx)) {
114                 *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
115                 s->irq.AssignedIRQ = 0;
116                 s->pci_irq = cf->irq;
117 
118         } else
119                 *sp = 0;
120         return 0;
121 }
122 
123 static int
124 bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
125 {
126 
127         struct bfin_cf_socket *cf;
128         cf = container_of(sock, struct bfin_cf_socket, socket);
129 
130         switch (s->Vcc) {
131         case 0:
132         case 33:
133                 break;
134         case 50:
135                 break;
136         default:
137                 return -EINVAL;
138         }
139 
140         if (s->flags & SS_RESET) {
141                 disable_irq(cf->irq);
142                 bfin_cf_reset();
143                 enable_irq(cf->irq);
144         }
145 
146         dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
147                  s->Vcc, s->io_irq, s->flags, s->csc_mask);
148 
149         return 0;
150 }
151 
152 static int bfin_cf_ss_suspend(struct pcmcia_socket *s)
153 {
154         return bfin_cf_set_socket(s, &dead_socket);
155 }
156 
157 /* regions are 2K each:  mem, attrib, io (and reserved-for-ide) */
158 
159 static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
160 {
161         struct bfin_cf_socket *cf;
162 
163         cf = container_of(s, struct bfin_cf_socket, socket);
164         io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
165         io->start = cf->phys_cf_io;
166         io->stop = io->start + SZ_2K - 1;
167         return 0;
168 }
169 
170 static int
171 bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
172 {
173         struct bfin_cf_socket *cf;
174 
175         if (map->card_start)
176                 return -EINVAL;
177         cf = container_of(s, struct bfin_cf_socket, socket);
178         map->static_start = cf->phys_cf_io;
179         map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
180         if (map->flags & MAP_ATTRIB)
181                 map->static_start = cf->phys_cf_attr;
182 
183         return 0;
184 }
185 
186 static struct pccard_operations bfin_cf_ops = {
187         .init = bfin_cf_ss_init,
188         .suspend = bfin_cf_ss_suspend,
189         .get_status = bfin_cf_get_status,
190         .set_socket = bfin_cf_set_socket,
191         .set_io_map = bfin_cf_set_io_map,
192         .set_mem_map = bfin_cf_set_mem_map,
193 };
194 
195 /*--------------------------------------------------------------------------*/
196 
197 static int __devinit bfin_cf_probe(struct platform_device *pdev)
198 {
199         struct bfin_cf_socket *cf;
200         struct resource *io_mem, *attr_mem;
201         int irq;
202         unsigned short cd_pfx;
203         int status = 0;
204 
205         dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
206 
207         irq = platform_get_irq(pdev, 0);
208         if (!irq)
209                 return -EINVAL;
210 
211         cd_pfx = platform_get_irq(pdev, 1);     /*Card Detect GPIO PIN */
212 
213         if (gpio_request(cd_pfx, "pcmcia: CD")) {
214                 dev_err(&pdev->dev,
215                        "Failed ro request Card Detect GPIO_%d\n",
216                        cd_pfx);
217                 return -EBUSY;
218         }
219         gpio_direction_input(cd_pfx);
220 
221         cf = kzalloc(sizeof *cf, GFP_KERNEL);
222         if (!cf) {
223                 gpio_free(cd_pfx);
224                 return -ENOMEM;
225         }
226 
227         cf->cd_pfx = cd_pfx;
228 
229         setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
230 
231         cf->pdev = pdev;
232         platform_set_drvdata(pdev, cf);
233 
234         cf->irq = irq;
235         cf->socket.pci_irq = irq;
236 
237         set_irq_type(irq, IRQF_TRIGGER_LOW);
238 
239         io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
240         attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
241 
242         if (!io_mem || !attr_mem)
243                 goto fail0;
244 
245         cf->phys_cf_io = io_mem->start;
246         cf->phys_cf_attr = attr_mem->start;
247 
248         /* pcmcia layer only remaps "real" memory */
249         cf->socket.io_offset = (unsigned long)
250             ioremap(cf->phys_cf_io, SZ_2K);
251 
252         if (!cf->socket.io_offset)
253                 goto fail0;
254 
255         dev_err(&pdev->dev, ": on irq %d\n", irq);
256 
257         dev_dbg(&pdev->dev, ": %s\n",
258                  bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)");
259 
260         cf->socket.owner = THIS_MODULE;
261         cf->socket.dev.parent = &pdev->dev;
262         cf->socket.ops = &bfin_cf_ops;
263         cf->socket.resource_ops = &pccard_static_ops;
264         cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
265             | SS_CAP_MEM_ALIGN;
266         cf->socket.map_size = SZ_2K;
267 
268         status = pcmcia_register_socket(&cf->socket);
269         if (status < 0)
270                 goto fail2;
271 
272         cf->active = 1;
273         mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
274         return 0;
275 
276 fail2:
277         iounmap((void __iomem *)cf->socket.io_offset);
278         release_mem_region(cf->phys_cf_io, SZ_8K);
279 
280 fail0:
281         gpio_free(cf->cd_pfx);
282         kfree(cf);
283         platform_set_drvdata(pdev, NULL);
284 
285         return status;
286 }
287 
288 static int __devexit bfin_cf_remove(struct platform_device *pdev)
289 {
290         struct bfin_cf_socket *cf = platform_get_drvdata(pdev);
291 
292         gpio_free(cf->cd_pfx);
293         cf->active = 0;
294         pcmcia_unregister_socket(&cf->socket);
295         del_timer_sync(&cf->timer);
296         iounmap((void __iomem *)cf->socket.io_offset);
297         release_mem_region(cf->phys_cf_io, SZ_8K);
298         platform_set_drvdata(pdev, NULL);
299         kfree(cf);
300         return 0;
301 }
302 
303 static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
304 {
305         return pcmcia_socket_dev_suspend(&pdev->dev);
306 }
307 
308 static int bfin_cf_resume(struct platform_device *pdev)
309 {
310         return pcmcia_socket_dev_resume(&pdev->dev);
311 }
312 
313 static struct platform_driver bfin_cf_driver = {
314         .driver = {
315                    .name = (char *)driver_name,
316                    .owner = THIS_MODULE,
317                    },
318         .probe = bfin_cf_probe,
319         .remove = __devexit_p(bfin_cf_remove),
320         .suspend = bfin_cf_suspend,
321         .resume = bfin_cf_resume,
322 };
323 
324 static int __init bfin_cf_init(void)
325 {
326         return platform_driver_register(&bfin_cf_driver);
327 }
328 
329 static void __exit bfin_cf_exit(void)
330 {
331         platform_driver_unregister(&bfin_cf_driver);
332 }
333 
334 module_init(bfin_cf_init);
335 module_exit(bfin_cf_exit);
336 
337 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
338 MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
339 MODULE_LICENSE("GPL");
340 
  This page was automatically generated by the LXR engine.