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/init.h>
35#include <linux/cpufreq.h>
36#include <linux/ioport.h>
37#include <linux/kernel.h>
38#include <linux/spinlock.h>
39#include <linux/io.h>
40#include <linux/slab.h>
41
42#include <mach/hardware.h>
43#include <asm/irq.h>
44#include <asm/system.h>
45
46#include "soc_common.h"
47#include "sa11xx_base.h"
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63static unsigned int
64sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
65 unsigned int cpu_speed,
66 unsigned int cmd_time)
67{
68 return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
69}
70
71
72
73
74
75
76
77
78
79static int
80sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
81{
82 struct soc_pcmcia_timing timing;
83 u32 mecr, old_mecr;
84 unsigned long flags;
85 unsigned int bs_io, bs_mem, bs_attr;
86
87 soc_common_pcmcia_get_timing(skt, &timing);
88
89 bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
90 bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
91 bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
92
93 local_irq_save(flags);
94
95 old_mecr = mecr = MECR;
96 MECR_FAST_SET(mecr, skt->nr, 0);
97 MECR_BSIO_SET(mecr, skt->nr, bs_io);
98 MECR_BSA_SET(mecr, skt->nr, bs_attr);
99 MECR_BSM_SET(mecr, skt->nr, bs_mem);
100 if (old_mecr != mecr)
101 MECR = mecr;
102
103 local_irq_restore(flags);
104
105 debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n",
106 MECR_FAST_GET(mecr, skt->nr),
107 MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
108 MECR_BSIO_GET(mecr, skt->nr));
109
110 return 0;
111}
112
113#ifdef CONFIG_CPU_FREQ
114static int
115sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
116 unsigned long val,
117 struct cpufreq_freqs *freqs)
118{
119 switch (val) {
120 case CPUFREQ_PRECHANGE:
121 if (freqs->new > freqs->old)
122 sa1100_pcmcia_set_mecr(skt, freqs->new);
123 break;
124
125 case CPUFREQ_POSTCHANGE:
126 if (freqs->new < freqs->old)
127 sa1100_pcmcia_set_mecr(skt, freqs->new);
128 break;
129 case CPUFREQ_RESUMECHANGE:
130 sa1100_pcmcia_set_mecr(skt, freqs->new);
131 break;
132 }
133
134 return 0;
135}
136
137#endif
138
139static int
140sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
141{
142 return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
143}
144
145static int
146sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
147{
148 struct soc_pcmcia_timing timing;
149 unsigned int clock = cpufreq_get(0);
150 unsigned long mecr = MECR;
151 char *p = buf;
152
153 soc_common_pcmcia_get_timing(skt, &timing);
154
155 p+=sprintf(p, "I/O : %u (%u)\n", timing.io,
156 sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
157
158 p+=sprintf(p, "attribute: %u (%u)\n", timing.attr,
159 sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
160
161 p+=sprintf(p, "common : %u (%u)\n", timing.mem,
162 sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
163
164 return p - buf;
165}
166
167static const char *skt_names[] = {
168 "PCMCIA socket 0",
169 "PCMCIA socket 1",
170};
171
172#define SKT_DEV_INFO_SIZE(n) \
173 (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
174
175int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
176{
177 skt->res_skt.start = _PCMCIA(skt->nr);
178 skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
179 skt->res_skt.name = skt_names[skt->nr];
180 skt->res_skt.flags = IORESOURCE_MEM;
181
182 skt->res_io.start = _PCMCIAIO(skt->nr);
183 skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
184 skt->res_io.name = "io";
185 skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
186
187 skt->res_mem.start = _PCMCIAMem(skt->nr);
188 skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
189 skt->res_mem.name = "memory";
190 skt->res_mem.flags = IORESOURCE_MEM;
191
192 skt->res_attr.start = _PCMCIAAttr(skt->nr);
193 skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
194 skt->res_attr.name = "attribute";
195 skt->res_attr.flags = IORESOURCE_MEM;
196
197 return soc_pcmcia_add_one(skt);
198}
199EXPORT_SYMBOL(sa11xx_drv_pcmcia_add_one);
200
201void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
202{
203
204
205
206
207 if (!ops->get_timing)
208 ops->get_timing = sa1100_pcmcia_default_mecr_timing;
209
210
211 ops->set_timing = sa1100_pcmcia_set_timing;
212 ops->show_timing = sa1100_pcmcia_show_timing;
213#ifdef CONFIG_CPU_FREQ
214 ops->frequency_change = sa1100_pcmcia_frequency_change;
215#endif
216}
217EXPORT_SYMBOL(sa11xx_drv_pcmcia_ops);
218
219int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
220 int first, int nr)
221{
222 struct skt_dev_info *sinfo;
223 struct soc_pcmcia_socket *skt;
224 int i, ret = 0;
225
226 sa11xx_drv_pcmcia_ops(ops);
227
228 sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
229 if (!sinfo)
230 return -ENOMEM;
231
232 sinfo->nskt = nr;
233
234
235 for (i = 0; i < nr; i++) {
236 skt = &sinfo->skt[i];
237
238 skt->nr = first + i;
239 skt->ops = ops;
240 skt->socket.owner = ops->owner;
241 skt->socket.dev.parent = dev;
242 skt->socket.pci_irq = NO_IRQ;
243
244 ret = sa11xx_drv_pcmcia_add_one(skt);
245 if (ret)
246 break;
247 }
248
249 if (ret) {
250 while (--i >= 0)
251 soc_pcmcia_remove_one(&sinfo->skt[i]);
252 kfree(sinfo);
253 } else {
254 dev_set_drvdata(dev, sinfo);
255 }
256
257 return ret;
258}
259EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
260
261static int __init sa11xx_pcmcia_init(void)
262{
263 return 0;
264}
265fs_initcall(sa11xx_pcmcia_init);
266
267static void __exit sa11xx_pcmcia_exit(void) {}
268
269module_exit(sa11xx_pcmcia_exit);
270
271MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
272MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
273MODULE_LICENSE("Dual MPL/GPL");
274