11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Device driver for the PCMCIA control functionality of StrongARM
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    SA-1100 microprocessors.
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The contents of this file are subject to the Mozilla Public
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    License Version 1.1 (the "License"); you may not use this file
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    except in compliance with the License. You may obtain a copy of
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the License at http://www.mozilla.org/MPL/
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Software distributed under the License is distributed on an "AS
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    implied. See the License for the specific language governing
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    rights and limitations under the License.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The initial developer of the original code is John G. Dorsey
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Alternatively, the contents of this file may be used under the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    terms of the GNU Public License version 2 (the "GPL"), in which
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    case the provisions of the GPL are applicable instead of the
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    above.  If you wish to allow the use of your version of this file
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    only under the terms of the GPL and not to allow others to use
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    your version of this file under the MPL, indicate your decision
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    by deleting the provisions above and replace them with the notice
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    and other provisions required by the GPL.  If you do not delete
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the provisions above, a recipient may use your version of this
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    file under either the MPL or the GPL.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cpufreq.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
39997302259f386bca8fe1db67c50296ca426c438fRussell King#include <linux/io.h>
405a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "soc_common.h"
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sa11xx_base.h"
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sa1100_pcmcia_default_mecr_timing
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate MECR clock wait states for given CPU clock
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * speed and command wait state. This function can be over-
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * written by a board specific version.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The default is to simply calculate the BS values as specified in
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the INTEL SA1100 development manual
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "Expansion Memory (PCMCIA) Configuration Register (MECR)"
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that's section 10.2.5 in _my_ version of the manual ;)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  unsigned int cpu_speed,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  unsigned int cmd_time)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sa1100_pcmcia_set_mecr()
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^^
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set MECR value for socket <sock> based on this sockets
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * io, mem and attribute space access speed.
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call board specific BS value calculation to allow boards
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to tweak the BS values.
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct soc_pcmcia_timing timing;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 mecr, old_mecr;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int bs_io, bs_mem, bs_attr;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	soc_common_pcmcia_get_timing(skt, &timing);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_save(flags);
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_mecr = mecr = MECR;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MECR_FAST_SET(mecr, skt->nr, 0);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MECR_BSIO_SET(mecr, skt->nr, bs_io);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MECR_BSA_SET(mecr, skt->nr, bs_attr);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MECR_BSM_SET(mecr, skt->nr, bs_mem);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_mecr != mecr)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MECR = mecr;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq_restore(flags);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	debug(skt, 2, "FAST %X  BSM %X  BSA %X  BSIO %X\n",
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      MECR_FAST_GET(mecr, skt->nr),
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr),
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      MECR_BSIO_GET(mecr, skt->nr));
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_FREQ
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       unsigned long val,
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct cpufreq_freqs *freqs)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (val) {
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_PRECHANGE:
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (freqs->new > freqs->old)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100_pcmcia_set_mecr(skt, freqs->new);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_POSTCHANGE:
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (freqs->new < freqs->old)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa1100_pcmcia_set_mecr(skt, freqs->new);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CPUFREQ_RESUMECHANGE:
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sa1100_pcmcia_set_mecr(skt, freqs->new);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct soc_pcmcia_timing timing;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int clock = cpufreq_get(0);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long mecr = MECR;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *p = buf;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	soc_common_pcmcia_get_timing(skt, &timing);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p+=sprintf(p, "I/O      : %u (%u)\n", timing.io,
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p+=sprintf(p, "attribute: %u (%u)\n", timing.attr,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p+=sprintf(p, "common   : %u (%u)\n", timing.mem,
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return p - buf;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
167b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miaostatic const char *skt_names[] = {
168b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao	"PCMCIA socket 0",
169b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao	"PCMCIA socket 1",
170b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao};
171b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao
172b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao#define SKT_DEV_INFO_SIZE(n) \
173b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao	(sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
174b393c69652333be31ad7a8205761c0d5b7f3e167Eric Miao
175701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linuxint sa11xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
176da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux{
177da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_skt.start = _PCMCIA(skt->nr);
178da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
179da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_skt.name = skt_names[skt->nr];
180da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_skt.flags = IORESOURCE_MEM;
181da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
182da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_io.start = _PCMCIAIO(skt->nr);
183da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
184da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_io.name = "io";
185da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
186da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
187da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_mem.start = _PCMCIAMem(skt->nr);
188da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
189da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_mem.name = "memory";
190da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_mem.flags = IORESOURCE_MEM;
191da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
192da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_attr.start = _PCMCIAAttr(skt->nr);
193da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
194da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_attr.name = "attribute";
195da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	skt->res_attr.flags = IORESOURCE_MEM;
196da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
197da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	return soc_pcmcia_add_one(skt);
198da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux}
199701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM LinuxEXPORT_SYMBOL(sa11xx_drv_pcmcia_add_one);
200da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
201701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linuxvoid sa11xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * set default MECR calculation if the board specific
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * code did not specify one...
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ops->get_timing)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ops->get_timing = sa1100_pcmcia_default_mecr_timing;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Provide our SA11x0 specific timing routines. */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops->set_timing  = sa1100_pcmcia_set_timing;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops->show_timing = sa1100_pcmcia_show_timing;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CPU_FREQ
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ops->frequency_change = sa1100_pcmcia_frequency_change;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
216701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux}
217701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM LinuxEXPORT_SYMBOL(sa11xx_drv_pcmcia_ops);
218701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux
219701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linuxint sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
220701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux			    int first, int nr)
221701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux{
222701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux	struct skt_dev_info *sinfo;
223701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux	struct soc_pcmcia_socket *skt;
224701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux	int i, ret = 0;
225701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux
226701a5dc05ad99a06958b3f97cb69d99b47cebee3Russell King - ARM Linux	sa11xx_drv_pcmcia_ops(ops);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
228da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
229da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	if (!sinfo)
230da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		return -ENOMEM;
231da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
232da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	sinfo->nskt = nr;
233da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
234421f91d21ad6f799dc7b489bb33cc560ccc56f98Uwe Kleine-König	/* Initialize processor specific parameters */
235da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	for (i = 0; i < nr; i++) {
236da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		skt = &sinfo->skt[i];
237da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
238da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		skt->nr = first + i;
239da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		skt->ops = ops;
240da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		skt->socket.owner = ops->owner;
241da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		skt->socket.dev.parent = dev;
24266024db57d5b9011e274b314affad68f370c0d6fRussell King - ARM Linux		skt->socket.pci_irq = NO_IRQ;
243da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
244da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		ret = sa11xx_drv_pcmcia_add_one(skt);
245da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		if (ret)
246da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux			break;
247da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	}
248da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
249da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	if (ret) {
250da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		while (--i >= 0)
251da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux			soc_pcmcia_remove_one(&sinfo->skt[i]);
252da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		kfree(sinfo);
253da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	} else {
254da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux		dev_set_drvdata(dev, sinfo);
255da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	}
256da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux
257da4f007375197d6683461b995d404b01a7fdf2f5Russell King - ARM Linux	return ret;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(sa11xx_drv_pcmcia_probe);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sa11xx_pcmcia_init(void)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
265f36598aeca4c2dbaa607bf6f774e38eb965402f2Richard Purdiefs_initcall(sa11xx_pcmcia_init);
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sa11xx_pcmcia_exit(void) {}
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sa11xx_pcmcia_exit);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver");
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual MPL/GPL");
274