0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/module.h>
0034 #include <linux/init.h>
0035 #include <linux/cpufreq.h>
0036 #include <linux/ioport.h>
0037 #include <linux/kernel.h>
0038 #include <linux/spinlock.h>
0039 #include <linux/io.h>
0040 #include <linux/slab.h>
0041
0042 #include <mach/hardware.h>
0043 #include <asm/irq.h>
0044
0045 #include "soc_common.h"
0046 #include "sa11xx_base.h"
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 static unsigned int
0063 sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
0064 unsigned int cpu_speed,
0065 unsigned int cmd_time)
0066 {
0067 return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
0068 }
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 static int
0079 sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
0080 {
0081 struct soc_pcmcia_timing timing;
0082 u32 mecr, old_mecr;
0083 unsigned long flags;
0084 unsigned int bs_io, bs_mem, bs_attr;
0085
0086 soc_common_pcmcia_get_timing(skt, &timing);
0087
0088 bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
0089 bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
0090 bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
0091
0092 local_irq_save(flags);
0093
0094 old_mecr = mecr = MECR;
0095 MECR_FAST_SET(mecr, skt->nr, 0);
0096 MECR_BSIO_SET(mecr, skt->nr, bs_io);
0097 MECR_BSA_SET(mecr, skt->nr, bs_attr);
0098 MECR_BSM_SET(mecr, skt->nr, bs_mem);
0099 if (old_mecr != mecr)
0100 MECR = mecr;
0101
0102 local_irq_restore(flags);
0103
0104 debug(skt, 2, "FAST %X BSM %X BSA %X BSIO %X\n",
0105 MECR_FAST_GET(mecr, skt->nr),
0106 MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
0107 MECR_BSIO_GET(mecr, skt->nr));
0108
0109 return 0;
0110 }
0111
0112 #ifdef CONFIG_CPU_FREQ
0113 static int
0114 sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
0115 unsigned long val,
0116 struct cpufreq_freqs *freqs)
0117 {
0118 switch (val) {
0119 case CPUFREQ_PRECHANGE:
0120 if (freqs->new > freqs->old)
0121 sa1100_pcmcia_set_mecr(skt, freqs->new);
0122 break;
0123
0124 case CPUFREQ_POSTCHANGE:
0125 if (freqs->new < freqs->old)
0126 sa1100_pcmcia_set_mecr(skt, freqs->new);
0127 break;
0128 }
0129
0130 return 0;
0131 }
0132
0133 #endif
0134
0135 static int
0136 sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
0137 {
0138 unsigned long clk = clk_get_rate(skt->clk);
0139
0140 return sa1100_pcmcia_set_mecr(skt, clk / 1000);
0141 }
0142
0143 static int
0144 sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
0145 {
0146 struct soc_pcmcia_timing timing;
0147 unsigned int clock = clk_get_rate(skt->clk) / 1000;
0148 unsigned long mecr = MECR;
0149 char *p = buf;
0150
0151 soc_common_pcmcia_get_timing(skt, &timing);
0152
0153 p+=sprintf(p, "I/O : %uns (%uns)\n", timing.io,
0154 sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
0155
0156 p+=sprintf(p, "attribute: %uns (%uns)\n", timing.attr,
0157 sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
0158
0159 p+=sprintf(p, "common : %uns (%uns)\n", timing.mem,
0160 sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
0161
0162 return p - buf;
0163 }
0164
0165 static const char *skt_names[] = {
0166 "PCMCIA socket 0",
0167 "PCMCIA socket 1",
0168 };
0169
0170 #define SKT_DEV_INFO_SIZE(n) \
0171 (sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
0172
0173 int sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
0174 {
0175 skt->res_skt.start = _PCMCIA(skt->nr);
0176 skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
0177 skt->res_skt.name = skt_names[skt->nr];
0178 skt->res_skt.flags = IORESOURCE_MEM;
0179
0180 skt->res_io.start = _PCMCIAIO(skt->nr);
0181 skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
0182 skt->res_io.name = "io";
0183 skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0184
0185 skt->res_mem.start = _PCMCIAMem(skt->nr);
0186 skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
0187 skt->res_mem.name = "memory";
0188 skt->res_mem.flags = IORESOURCE_MEM;
0189
0190 skt->res_attr.start = _PCMCIAAttr(skt->nr);
0191 skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
0192 skt->res_attr.name = "attribute";
0193 skt->res_attr.flags = IORESOURCE_MEM;
0194
0195 return soc_pcmcia_add_one(skt);
0196 }
0197 EXPORT_SYMBOL(sa11xx_drv_pcmcia_add_one);
0198
0199 void sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
0200 {
0201
0202
0203
0204
0205 if (!ops->get_timing)
0206 ops->get_timing = sa1100_pcmcia_default_mecr_timing;
0207
0208
0209 ops->set_timing = sa1100_pcmcia_set_timing;
0210 ops->show_timing = sa1100_pcmcia_show_timing;
0211 #ifdef CONFIG_CPU_FREQ
0212 ops->frequency_change = sa1100_pcmcia_frequency_change;
0213 #endif
0214 }
0215 EXPORT_SYMBOL(sa11xx_drv_pcmcia_ops);
0216
0217 int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
0218 int first, int nr)
0219 {
0220 struct skt_dev_info *sinfo;
0221 struct soc_pcmcia_socket *skt;
0222 int i, ret = 0;
0223 struct clk *clk;
0224
0225 clk = devm_clk_get(dev, NULL);
0226 if (IS_ERR(clk))
0227 return PTR_ERR(clk);
0228
0229 sa11xx_drv_pcmcia_ops(ops);
0230
0231 sinfo = devm_kzalloc(dev, SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
0232 if (!sinfo)
0233 return -ENOMEM;
0234
0235 sinfo->nskt = nr;
0236
0237
0238 for (i = 0; i < nr; i++) {
0239 skt = &sinfo->skt[i];
0240
0241 skt->nr = first + i;
0242 skt->clk = clk;
0243 soc_pcmcia_init_one(skt, ops, dev);
0244
0245 ret = sa11xx_drv_pcmcia_add_one(skt);
0246 if (ret)
0247 break;
0248 }
0249
0250 if (ret) {
0251 while (--i >= 0)
0252 soc_pcmcia_remove_one(&sinfo->skt[i]);
0253 } else {
0254 dev_set_drvdata(dev, sinfo);
0255 }
0256
0257 return ret;
0258 }
0259 EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
0260
0261 MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
0262 MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
0263 MODULE_LICENSE("Dual MPL/GPL");