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
40#include <mach/hardware.h>
41#include <asm/io.h>
42#include <asm/irq.h>
43#include <asm/system.h>
44
45#include "soc_common.h"
46#include "sa11xx_base.h"
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62static unsigned int
63sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
64 unsigned int cpu_speed,
65 unsigned int cmd_time)
66{
67 return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
68}
69
70
71
72
73
74
75
76
77
78static int
79sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
80{
81 struct soc_pcmcia_timing timing;
82 u32 mecr, old_mecr;
83 unsigned long flags;
84 unsigned int bs_io, bs_mem, bs_attr;
85
86 soc_common_pcmcia_get_timing(skt, &timing);
87
88 bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
89 bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
90 bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
91
92 local_irq_save(flags);
93
94 old_mecr = mecr = MECR;
95 MECR_FAST_SET(mecr, skt->nr, 0);
96 MECR_BSIO_SET(mecr, skt->nr, bs_io);
97 MECR_BSA_SET(mecr, skt->nr, bs_attr);
98 MECR_BSM_SET(mecr, skt->nr, bs_mem);
99 if (old_mecr != mecr)
100 MECR = mecr;
101
102 local_irq_restore(flags);
103
104 debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n",
105 MECR_FAST_GET(mecr, skt->nr),
106 MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
107 MECR_BSIO_GET(mecr, skt->nr));
108
109 return 0;
110}
111
112#ifdef CONFIG_CPU_FREQ
113static int
114sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
115 unsigned long val,
116 struct cpufreq_freqs *freqs)
117{
118 switch (val) {
119 case CPUFREQ_PRECHANGE:
120 if (freqs->new > freqs->old)
121 sa1100_pcmcia_set_mecr(skt, freqs->new);
122 break;
123
124 case CPUFREQ_POSTCHANGE:
125 if (freqs->new < freqs->old)
126 sa1100_pcmcia_set_mecr(skt, freqs->new);
127 break;
128 case CPUFREQ_RESUMECHANGE:
129 sa1100_pcmcia_set_mecr(skt, freqs->new);
130 break;
131 }
132
133 return 0;
134}
135
136#endif
137
138static int
139sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
140{
141 return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
142}
143
144static int
145sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
146{
147 struct soc_pcmcia_timing timing;
148 unsigned int clock = cpufreq_get(0);
149 unsigned long mecr = MECR;
150 char *p = buf;
151
152 soc_common_pcmcia_get_timing(skt, &timing);
153
154 p+=sprintf(p, "I/O : %u (%u)\n", timing.io,
155 sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
156
157 p+=sprintf(p, "attribute: %u (%u)\n", timing.attr,
158 sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
159
160 p+=sprintf(p, "common : %u (%u)\n", timing.mem,
161 sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
162
163 return p - buf;
164}
165
166int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
167 int first, int nr)
168{
169
170
171
172
173 if (!ops->get_timing)
174 ops->get_timing = sa1100_pcmcia_default_mecr_timing;
175
176
177 ops->set_timing = sa1100_pcmcia_set_timing;
178 ops->show_timing = sa1100_pcmcia_show_timing;
179#ifdef CONFIG_CPU_FREQ
180 ops->frequency_change = sa1100_pcmcia_frequency_change;
181#endif
182
183 return soc_common_drv_pcmcia_probe(dev, ops, first, nr);
184}
185EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
186
187static int __init sa11xx_pcmcia_init(void)
188{
189 return 0;
190}
191fs_initcall(sa11xx_pcmcia_init);
192
193static void __exit sa11xx_pcmcia_exit(void) {}
194
195module_exit(sa11xx_pcmcia_exit);
196
197MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
198MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
199MODULE_LICENSE("Dual MPL/GPL");
200