Back to home page

OSCL-LXR

 
 

    


0001 /*======================================================================
0002 
0003     Device driver for the PCMCIA control functionality of StrongARM
0004     SA-1100 microprocessors.
0005 
0006     The contents of this file are subject to the Mozilla Public
0007     License Version 1.1 (the "License"); you may not use this file
0008     except in compliance with the License. You may obtain a copy of
0009     the License at http://www.mozilla.org/MPL/
0010 
0011     Software distributed under the License is distributed on an "AS
0012     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0013     implied. See the License for the specific language governing
0014     rights and limitations under the License.
0015 
0016     The initial developer of the original code is John G. Dorsey
0017     <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
0018     Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
0019 
0020     Alternatively, the contents of this file may be used under the
0021     terms of the GNU Public License version 2 (the "GPL"), in which
0022     case the provisions of the GPL are applicable instead of the
0023     above.  If you wish to allow the use of your version of this file
0024     only under the terms of the GPL and not to allow others to use
0025     your version of this file under the MPL, indicate your decision
0026     by deleting the provisions above and replace them with the notice
0027     and other provisions required by the GPL.  If you do not delete
0028     the provisions above, a recipient may use your version of this
0029     file under either the MPL or the GPL.
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  * sa1100_pcmcia_default_mecr_timing
0051  * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0052  *
0053  * Calculate MECR clock wait states for given CPU clock
0054  * speed and command wait state. This function can be over-
0055  * written by a board specific version.
0056  *
0057  * The default is to simply calculate the BS values as specified in
0058  * the INTEL SA1100 development manual
0059  * "Expansion Memory (PCMCIA) Configuration Register (MECR)"
0060  * that's section 10.2.5 in _my_ version of the manual ;)
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 /* sa1100_pcmcia_set_mecr()
0071  * ^^^^^^^^^^^^^^^^^^^^^^^^
0072  *
0073  * set MECR value for socket <sock> based on this sockets
0074  * io, mem and attribute space access speed.
0075  * Call board specific BS value calculation to allow boards
0076  * to tweak the BS values.
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      * set default MECR calculation if the board specific
0203      * code did not specify one...
0204      */
0205     if (!ops->get_timing)
0206         ops->get_timing = sa1100_pcmcia_default_mecr_timing;
0207 
0208     /* Provide our SA11x0 specific timing routines. */
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     /* Initialize processor specific parameters */
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");