1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/module.h>
34#include <linux/gpio/consumer.h>
35#include <linux/init.h>
36#include <linux/regulator/consumer.h>
37#include <linux/slab.h>
38#include <linux/platform_device.h>
39
40#include <pcmcia/ss.h>
41
42#include <asm/hardware/scoop.h>
43
44#include "sa1100_generic.h"
45
46static const char *sa11x0_cf_gpio_names[] = {
47 [SOC_STAT_CD] = "detect",
48 [SOC_STAT_BVD1] = "bvd1",
49 [SOC_STAT_BVD2] = "bvd2",
50 [SOC_STAT_RDY] = "ready",
51};
52
53static int sa11x0_cf_hw_init(struct soc_pcmcia_socket *skt)
54{
55 struct device *dev = skt->socket.dev.parent;
56 int i;
57
58 skt->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
59 if (IS_ERR(skt->gpio_reset))
60 return PTR_ERR(skt->gpio_reset);
61
62 skt->gpio_bus_enable = devm_gpiod_get_optional(dev, "bus-enable",
63 GPIOD_OUT_HIGH);
64 if (IS_ERR(skt->gpio_bus_enable))
65 return PTR_ERR(skt->gpio_bus_enable);
66
67 skt->vcc.reg = devm_regulator_get_optional(dev, "vcc");
68 if (IS_ERR(skt->vcc.reg))
69 return PTR_ERR(skt->vcc.reg);
70
71 if (!skt->vcc.reg)
72 dev_warn(dev,
73 "no Vcc regulator provided, ignoring Vcc controls\n");
74
75 for (i = 0; i < ARRAY_SIZE(sa11x0_cf_gpio_names); i++) {
76 skt->stat[i].name = sa11x0_cf_gpio_names[i];
77 skt->stat[i].desc = devm_gpiod_get_optional(dev,
78 sa11x0_cf_gpio_names[i], GPIOD_IN);
79 if (IS_ERR(skt->stat[i].desc))
80 return PTR_ERR(skt->stat[i].desc);
81 }
82 return 0;
83}
84
85static int sa11x0_cf_configure_socket(struct soc_pcmcia_socket *skt,
86 const socket_state_t *state)
87{
88 return soc_pcmcia_regulator_set(skt, &skt->vcc, state->Vcc);
89}
90
91static struct pcmcia_low_level sa11x0_cf_ops = {
92 .owner = THIS_MODULE,
93 .hw_init = sa11x0_cf_hw_init,
94 .socket_state = soc_common_cf_socket_state,
95 .configure_socket = sa11x0_cf_configure_socket,
96};
97
98int __init pcmcia_collie_init(struct device *dev);
99
100static int (*sa11x0_pcmcia_legacy_hw_init[])(struct device *dev) = {
101#if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
102 pcmcia_h3600_init,
103#endif
104#ifdef CONFIG_SA1100_SIMPAD
105 pcmcia_simpad_init,
106#endif
107#ifdef CONFIG_SA1100_COLLIE
108 pcmcia_collie_init,
109#endif
110};
111
112static int sa11x0_drv_pcmcia_legacy_probe(struct platform_device *dev)
113{
114 int i, ret = -ENODEV;
115
116
117
118
119 for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_legacy_hw_init); i++) {
120 ret = sa11x0_pcmcia_legacy_hw_init[i](&dev->dev);
121 if (ret == 0)
122 break;
123 }
124
125 return ret;
126}
127
128static int sa11x0_drv_pcmcia_legacy_remove(struct platform_device *dev)
129{
130 struct skt_dev_info *sinfo = platform_get_drvdata(dev);
131 int i;
132
133 platform_set_drvdata(dev, NULL);
134
135 for (i = 0; i < sinfo->nskt; i++)
136 soc_pcmcia_remove_one(&sinfo->skt[i]);
137
138 return 0;
139}
140
141static int sa11x0_drv_pcmcia_probe(struct platform_device *pdev)
142{
143 struct soc_pcmcia_socket *skt;
144 struct device *dev = &pdev->dev;
145
146 if (pdev->id == -1)
147 return sa11x0_drv_pcmcia_legacy_probe(pdev);
148
149 skt = devm_kzalloc(dev, sizeof(*skt), GFP_KERNEL);
150 if (!skt)
151 return -ENOMEM;
152
153 platform_set_drvdata(pdev, skt);
154
155 skt->nr = pdev->id;
156 skt->clk = devm_clk_get(dev, NULL);
157 if (IS_ERR(skt->clk))
158 return PTR_ERR(skt->clk);
159
160 sa11xx_drv_pcmcia_ops(&sa11x0_cf_ops);
161 soc_pcmcia_init_one(skt, &sa11x0_cf_ops, dev);
162
163 return sa11xx_drv_pcmcia_add_one(skt);
164}
165
166static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
167{
168 struct soc_pcmcia_socket *skt;
169
170 if (dev->id == -1)
171 return sa11x0_drv_pcmcia_legacy_remove(dev);
172
173 skt = platform_get_drvdata(dev);
174
175 soc_pcmcia_remove_one(skt);
176
177 return 0;
178}
179
180static struct platform_driver sa11x0_pcmcia_driver = {
181 .driver = {
182 .name = "sa11x0-pcmcia",
183 },
184 .probe = sa11x0_drv_pcmcia_probe,
185 .remove = sa11x0_drv_pcmcia_remove,
186};
187
188
189
190
191
192
193
194
195
196static int __init sa11x0_pcmcia_init(void)
197{
198 return platform_driver_register(&sa11x0_pcmcia_driver);
199}
200
201
202
203
204
205
206static void __exit sa11x0_pcmcia_exit(void)
207{
208 platform_driver_unregister(&sa11x0_pcmcia_driver);
209}
210
211MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
212MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
213MODULE_LICENSE("Dual MPL/GPL");
214
215fs_initcall(sa11x0_pcmcia_init);
216module_exit(sa11x0_pcmcia_exit);
217