]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/ssb/bridge_pcmcia_80211.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.git] / drivers / ssb / bridge_pcmcia_80211.c
1 /*
2  * Broadcom 43xx PCMCIA-SSB bridge module
3  *
4  * Copyright (c) 2007 Michael Buesch <m@bues.ch>
5  *
6  * Licensed under the GNU/GPL. See COPYING for details.
7  */
8
9 #include <linux/ssb/ssb.h>
10 #include <linux/slab.h>
11 #include <linux/module.h>
12
13 #include <pcmcia/cistpl.h>
14 #include <pcmcia/ciscode.h>
15 #include <pcmcia/ds.h>
16 #include <pcmcia/cisreg.h>
17
18 #include "ssb_private.h"
19
20 static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
21         PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
22         PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
23         PCMCIA_DEVICE_NULL,
24 };
25
26 MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
27
28 static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
29 {
30         struct ssb_bus *ssb;
31         int err = -ENOMEM;
32         int res = 0;
33
34         ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
35         if (!ssb)
36                 goto out_error;
37
38         err = -ENODEV;
39
40         dev->config_flags |= CONF_ENABLE_IRQ;
41
42         dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |
43                          WIN_USE_WAIT;
44         dev->resource[2]->start = 0;
45         dev->resource[2]->end = SSB_CORE_SIZE;
46         res = pcmcia_request_window(dev, dev->resource[2], 250);
47         if (res != 0)
48                 goto err_kfree_ssb;
49
50         res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
51         if (res != 0)
52                 goto err_disable;
53
54         if (!dev->irq)
55                 goto err_disable;
56
57         res = pcmcia_enable_device(dev);
58         if (res != 0)
59                 goto err_disable;
60
61         err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
62         if (err)
63                 goto err_disable;
64         dev->priv = ssb;
65
66         return 0;
67
68 err_disable:
69         pcmcia_disable_device(dev);
70 err_kfree_ssb:
71         kfree(ssb);
72 out_error:
73         ssb_err("Initialization failed (%d, %d)\n", res, err);
74         return err;
75 }
76
77 static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
78 {
79         struct ssb_bus *ssb = dev->priv;
80
81         ssb_bus_unregister(ssb);
82         pcmcia_disable_device(dev);
83         kfree(ssb);
84         dev->priv = NULL;
85 }
86
87 #ifdef CONFIG_PM
88 static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
89 {
90         struct ssb_bus *ssb = dev->priv;
91
92         return ssb_bus_suspend(ssb);
93 }
94
95 static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
96 {
97         struct ssb_bus *ssb = dev->priv;
98
99         return ssb_bus_resume(ssb);
100 }
101 #else /* CONFIG_PM */
102 # define ssb_host_pcmcia_suspend                NULL
103 # define ssb_host_pcmcia_resume         NULL
104 #endif /* CONFIG_PM */
105
106 static struct pcmcia_driver ssb_host_pcmcia_driver = {
107         .owner          = THIS_MODULE,
108         .name           = "ssb-pcmcia",
109         .id_table       = ssb_host_pcmcia_tbl,
110         .probe          = ssb_host_pcmcia_probe,
111         .remove         = ssb_host_pcmcia_remove,
112         .suspend        = ssb_host_pcmcia_suspend,
113         .resume         = ssb_host_pcmcia_resume,
114 };
115
116 /*
117  * These are not module init/exit functions!
118  * The module_pcmcia_driver() helper cannot be used here.
119  */
120 int ssb_host_pcmcia_init(void)
121 {
122         return pcmcia_register_driver(&ssb_host_pcmcia_driver);
123 }
124
125 void ssb_host_pcmcia_exit(void)
126 {
127         pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
128 }