Commit | Line | Data |
---|---|---|
399500da RM |
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 | } |