summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Scherzer <John.Scherzer@bluto.localdomain>2008-06-09 11:07:21 -0400
committerJustin Waters <justin.waters@timesys.com>2008-09-16 10:16:08 -0400
commit7dfe8145a9788da7dd0fc055f4fe0b22511eb357 (patch)
tree219cd185e6f844f1f42e14405f609f04ab61ddb6
parent2831f192f840def7d1f516db64722788bf4d2656 (diff)
Add sd and cf to acknowledge cards. You still can not mount the sd or cf cards, but the are recognized.
-rw-r--r--arch/arm/mach-mx27/devices.c18
-rw-r--r--arch/arm/mach-mx27/mx27lite.c2
-rw-r--r--arch/arm/mach-mx27/mx27lite_gpio.c120
-rw-r--r--arch/arm/tools/mach-types2
-rw-r--r--drivers/net/fec.c22
-rw-r--r--drivers/pcmcia/Kconfig8
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/mx27lite-pcmcia.c1362
-rw-r--r--drivers/pcmcia/mx27lite-pcmcia.h157
9 files changed, 1682 insertions, 10 deletions
diff --git a/arch/arm/mach-mx27/devices.c b/arch/arm/mach-mx27/devices.c
index e8fec3357487..ae1a35cf42cd 100644
--- a/arch/arm/mach-mx27/devices.c
+++ b/arch/arm/mach-mx27/devices.c
@@ -527,6 +527,23 @@ static inline void mxc_init_i2c(void)
}
#endif
+#if defined(CONFIG_PCMCIA_MX27LITE) || defined(CONFIG_PCMCIA_MX27LITE_MODULE)
+
+static struct platform_device mx27lite_device = {
+ .name = "Mx27lite_pcmcia_soc",
+ .id = 0,
+ .dev.release = mxc_nop_release,
+};
+static inline void mxc_init_pcmcia(void)
+{
+ platform_device_register(&mx27lite_device);
+}
+#else
+static inline void mxc_init_pcmcia(void)
+{
+}
+#endif
+
#ifdef CONFIG_MXC_VPU
/*! Platform Data for MXC VPU */
static struct platform_device mxcvpu_device = {
@@ -676,6 +693,7 @@ static int __init mxc_init_devices(void)
mxc_init_rtc();
mxc_init_scc();
mxc_init_owire();
+ mxc_init_pcmcia();
mxc_init_vpu();
mxc_init_pata();
diff --git a/arch/arm/mach-mx27/mx27lite.c b/arch/arm/mach-mx27/mx27lite.c
index 9200116efc6a..04c5e0649240 100644
--- a/arch/arm/mach-mx27/mx27lite.c
+++ b/arch/arm/mach-mx27/mx27lite.c
@@ -308,7 +308,7 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
* initialize __mach_desc_MX27LITE data structure.
*/
/* *INDENT-OFF* */
-MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
+MACHINE_START(MX27LITE, "LogicPD i.MX27LITE")
/* maintainer: TimeSys, Inc. */
.phys_io = AIPI_BASE_ADDR,
.io_pg_offst = ((AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
diff --git a/arch/arm/mach-mx27/mx27lite_gpio.c b/arch/arm/mach-mx27/mx27lite_gpio.c
index 16a921f4de33..cc8a4857e99b 100644
--- a/arch/arm/mach-mx27/mx27lite_gpio.c
+++ b/arch/arm/mach-mx27/mx27lite_gpio.c
@@ -186,7 +186,6 @@ int gpio_usbh1_active(void)
gpio_request_mux(MX27_PIN_USBH1_RXDM, GPIO_MUX_PRIMARY) ||
gpio_request_mux(MX27_PIN_USBH1_RXDP, GPIO_MUX_PRIMARY))
return -EINVAL;
-
return 0;
}
@@ -311,7 +310,6 @@ int gpio_usbotg_hs_active(void)
mxc_set_gpio_direction(MX27_PIN_USBH1_TXDM, 0); /* USB1_PWR_nEN */
mxc_set_gpio_direction(MX27_PIN_USBH1_TXDP, 1); /* USB1_nOC */
mxc_set_gpio_dataout(MX27_PIN_USBH1_TXDM, 0);
-
return 0;
}
@@ -732,6 +730,7 @@ void gpio_keypad_inactive(void)
*/
void gpio_ata_active(void)
{
+ printk("\n\nATA active, don't think this is right\n\n");
gpio_request_mux(MX27_PIN_ATA_DATA0, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_ATA_DATA1, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_ATA_DATA2, GPIO_MUX_PRIMARY);
@@ -1167,6 +1166,121 @@ int sdhc_init_card_det(int id)
return ret;
}
+int gpio_pcmcia_active(void)
+{
+ printk("Setting all pcmcia pins \n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x"
+ "\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x"
+ "\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_PC_CD1_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_CD2_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_WAIT_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_READY),
+ mxc_get_gpio_datain(MX27_PIN_PC_PWRON),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS1),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS1),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS2),
+ mxc_get_gpio_datain(MX27_PIN_PC_BVD1),
+ mxc_get_gpio_datain(MX27_PIN_PC_BVD2),
+ mxc_get_gpio_datain(MX27_PIN_PC_RST),
+ mxc_get_gpio_datain(MX27_PIN_IOIS16),
+ mxc_get_gpio_datain(MX27_PIN_PC_RW_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_POE));
+
+ printk("OUTPUT values 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_TOUT),
+ mxc_get_gpio_datain(MX27_PIN_TIN),
+ mxc_get_gpio_datain(MX27_PIN_SSI4_FS),
+ mxc_get_gpio_datain(MX27_PIN_SSI4_RXDAT) );
+ gpio_request_mux(MX27_PIN_SSI4_FS,GPIO_MUX_GPIO);
+ gpio_request_mux(MX27_PIN_SSI4_RXDAT,GPIO_MUX_GPIO);
+ mxc_set_gpio_direction( MX27_PIN_SSI4_FS, 0 );
+ mxc_set_gpio_direction( MX27_PIN_SSI4_RXDAT, 0 );
+ printk("OUTPUT values 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_TOUT),
+ mxc_get_gpio_datain(MX27_PIN_TIN),
+ mxc_get_gpio_datain(MX27_PIN_SSI4_FS),
+ mxc_get_gpio_datain(MX27_PIN_SSI4_RXDAT) );
+
+ printk("OUTPUT values 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_SSI3_FS),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_RXDAT),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_TXDAT),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_CLK) );
+ gpio_request_mux( MX27_PIN_SSI3_FS, GPIO_MUX_OUTPUT1);
+ gpio_request_mux( MX27_PIN_SSI3_RXDAT, GPIO_MUX_OUTPUT1);
+ gpio_request_mux( MX27_PIN_SSI3_TXDAT, GPIO_MUX_OUTPUT1);
+ gpio_request_mux( MX27_PIN_SSI3_CLK, GPIO_MUX_OUTPUT1);
+ mxc_set_gpio_direction( MX27_PIN_SSI3_FS, 1);
+ mxc_set_gpio_direction( MX27_PIN_SSI3_RXDAT, 1);
+ mxc_set_gpio_direction( MX27_PIN_SSI3_TXDAT, 1);
+ mxc_set_gpio_direction( MX27_PIN_SSI3_CLK, 1);
+ mxc_set_gpio_dataout( MX27_PIN_SSI3_FS, 1);
+ mxc_set_gpio_dataout( MX27_PIN_SSI3_RXDAT, 1);
+ mxc_set_gpio_dataout( MX27_PIN_SSI3_TXDAT, 1);
+ mxc_set_gpio_dataout( MX27_PIN_SSI3_CLK, 1);
+ printk("OUTPUT values 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_SSI3_FS),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_RXDAT),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_TXDAT),
+ mxc_get_gpio_datain(MX27_PIN_SSI3_CLK) );
+
+ if (
+ gpio_request_mux(MX27_PIN_PC_CD1_B, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_CD2_B, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_WAIT_B, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_READY, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_PWRON, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_VS1, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_VS2, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_BVD1, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_BVD2, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_RST, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_IOIS16, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_RW_B, GPIO_MUX_PRIMARY) ||
+ gpio_request_mux(MX27_PIN_PC_POE, GPIO_MUX_PRIMARY)
+ )
+ return -EINVAL;
+ printk("Setting all pcmcia pins \n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x"
+ "\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x"
+ "\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n\t0x%08x\n",
+ mxc_get_gpio_datain(MX27_PIN_PC_CD1_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_CD2_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_WAIT_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_READY),
+ mxc_get_gpio_datain(MX27_PIN_PC_PWRON),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS1),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS1),
+ mxc_get_gpio_datain(MX27_PIN_PC_VS2),
+ mxc_get_gpio_datain(MX27_PIN_PC_BVD1),
+ mxc_get_gpio_datain(MX27_PIN_PC_BVD2),
+ mxc_get_gpio_datain(MX27_PIN_PC_RST),
+ mxc_get_gpio_datain(MX27_PIN_IOIS16),
+ mxc_get_gpio_datain(MX27_PIN_PC_RW_B),
+ mxc_get_gpio_datain(MX27_PIN_PC_POE));
+
+ return 0;
+}
+
+/*!
+ * Setup GPIO for pcmcia to be inactive
+ */
+void gpio_pcmcia_inactive(void)
+{
+ gpio_free_mux(MX27_PIN_IOIS16);
+ gpio_free_mux(MX27_PIN_PC_BVD1);
+ gpio_free_mux(MX27_PIN_PC_BVD2);
+ gpio_free_mux(MX27_PIN_PC_CD1_B);
+ gpio_free_mux(MX27_PIN_PC_CD2_B);
+ gpio_free_mux(MX27_PIN_PC_POE);
+ gpio_free_mux(MX27_PIN_PC_PWRON);
+ gpio_free_mux(MX27_PIN_PC_READY);
+ gpio_free_mux(MX27_PIN_PC_RST);
+ gpio_free_mux(MX27_PIN_PC_RW_B);
+ gpio_free_mux(MX27_PIN_PC_VS1);
+ gpio_free_mux(MX27_PIN_PC_VS2);
+ gpio_free_mux(MX27_PIN_PC_WAIT_B);
+}
+
/* --------------------------------------------------------------------
* Miscellaneous
@@ -1233,5 +1347,7 @@ EXPORT_SYMBOL(gpio_sdhc_inactive);
EXPORT_SYMBOL(sdhc_get_card_det_status);
EXPORT_SYMBOL(sdhc_init_card_det);
EXPORT_SYMBOL(board_power_lcd);
+EXPORT_SYMBOL(gpio_pcmcia_active);
+EXPORT_SYMBOL(gpio_pcmcia_inactive);
EXPORT_SYMBOL(gpio_owire_active);
EXPORT_SYMBOL(gpio_owire_inactive);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index ca2a8c10be30..305adea1cfaa 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1694,7 +1694,7 @@ g900 MACH_G900 G900 1697
apf27 MACH_APF27 APF27 1698
ggus2000 MACH_GGUS2000 GGUS2000 1699
omap_2430_mimic MACH_OMAP_2430_MIMIC OMAP_2430_MIMIC 1700
-imx27lite MACH_IMX27LITE IMX27LITE 1701
+mx27lite MACH_MX27LITE MX27LITE 1701
almex MACH_ALMEX ALMEX 1702
control MACH_CONTROL CONTROL 1703
mba2410 MACH_MBA2410 MBA2410 1704
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index bb518fec9c10..3cd357cd99ac 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -2618,8 +2618,17 @@ mii_discover_phy3(uint mii_reg, struct net_device *dev)
if (phy_info[i])
printk(" -- %s\n", phy_info[i]->name);
- else
- printk(" -- unknown PHY!\n");
+ else {
+ printk(" -- unknown PHY!, forcing LAN8700\n");
+ for(i = 0; phy_info[i]; i++) {
+ if(phy_info[i]->id == 0x7c0c)
+ break;
+ }
+ if (phy_info[i])
+ printk(" -- %s\n", phy_info[i]->name);
+ else
+ printk(" Still -- unknown PHY!\n");
+ }
fep->phy = phy_info[i];
fep->phy_id_done = 1;
@@ -2637,9 +2646,8 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
fep = netdev_priv(dev);
fecp = fep->hwp;
-
if (fep->phy_addr < 32) {
- if ((phytype = (mii_reg & 0x3fff)) != 0x3fff && phytype != 0) {
+ if ((phytype = (mii_reg & 0x7fff)) != 0x7fff && phytype != 0) {
/* Got first part of ID, now get remainder.
*/
@@ -2653,9 +2661,11 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
}
} else {
printk("FEC: No PHY device found.\n");
+ mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
+ mii_discover_phy3);
/* Disable external MII interface */
- fecp->fec_mii_speed = fep->phy_speed = 0;
- fec_disable_phy_intr();
+ //fecp->fec_mii_speed = fep->phy_speed = 0;
+ //fec_disable_phy_intr();
}
}
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 2f18b6a7edef..f1f1b58d5d29 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -283,6 +283,14 @@ config PCMCIA_MX31ADS
This driver is also available as a module called mx31ads_pcmcia.
+config PCMCIA_MX27LITE
+ tristate "MX27LITE PCMCIA support"
+ depends on ARM && ARCH_MX27 && PCMCIA
+ help
+ Say Y here to include support for the Freescale i.MX27 PCMCIA controller.
+
+ This driver is also available as a module called mx27lite_pcmcia.
+
config PCCARD_NONSTATIC
tristate
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 8509609b3ba2..bb8363493bf4 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
obj-$(CONFIG_PCMCIA_MX31ADS) += mx31ads-pcmcia.o
+obj-$(CONFIG_PCMCIA_MX27LITE) += mx27lite-pcmcia.o
sa11xx_core-y += soc_common.o sa11xx_base.o
pxa2xx_core-y += soc_common.o pxa2xx_base.o
diff --git a/drivers/pcmcia/mx27lite-pcmcia.c b/drivers/pcmcia/mx27lite-pcmcia.c
new file mode 100644
index 000000000000..9d314781fac2
--- /dev/null
+++ b/drivers/pcmcia/mx27lite-pcmcia.c
@@ -0,0 +1,1362 @@
+/*======================================================================
+ drivers/pcmcia/mx27lite-pcmica.c
+
+ Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+
+ Device driver for the PCMCIA control functionality of i.Mx27
+ microprocessors.
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is John G. Dorsey
+ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are
+ Copyright (C) 1999 John G. Dorsey. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <asm/mach-types.h>
+#include <asm/arch/pcmcia.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "mx27lite-pcmcia.h"
+#include <linux/irq.h>
+
+#define MX27LITE_PCMCIA_IRQ INT_PCMCIA
+
+/*
+ * The mapping of window size to bank size value
+ */
+static bsize_map_t bsize_map[] = {
+ /* Window size Bank size */
+ {POR_1, POR_BSIZE_1},
+ {POR_2, POR_BSIZE_2},
+ {POR_4, POR_BSIZE_4},
+ {POR_8, POR_BSIZE_8},
+ {POR_16, POR_BSIZE_16},
+ {POR_32, POR_BSIZE_32},
+ {POR_64, POR_BSIZE_64},
+ {POR_128, POR_BSIZE_128},
+ {POR_256, POR_BSIZE_256},
+ {POR_512, POR_BSIZE_512},
+
+ {POR_1K, POR_BSIZE_1K},
+ {POR_2K, POR_BSIZE_2K},
+ {POR_4K, POR_BSIZE_4K},
+ {POR_8K, POR_BSIZE_8K},
+ {POR_16K, POR_BSIZE_16K},
+ {POR_32K, POR_BSIZE_32K},
+ {POR_64K, POR_BSIZE_64K},
+ {POR_128K, POR_BSIZE_128K},
+ {POR_256K, POR_BSIZE_256K},
+ {POR_512K, POR_BSIZE_512K},
+
+ {POR_1M, POR_BSIZE_1M},
+ {POR_2M, POR_BSIZE_2M},
+ {POR_4M, POR_BSIZE_4M},
+ {POR_8M, POR_BSIZE_8M},
+ {POR_16M, POR_BSIZE_16M},
+ {POR_32M, POR_BSIZE_32M},
+ {POR_64M, POR_BSIZE_64M}
+};
+
+#define to_mx27lite_pcmcia_socket(x) container_of(x, struct mx27lite_pcmcia_socket, socket)
+
+/* mx27lite_pcmcia_find_bsize()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Find the bsize according to the window size passed in
+ *
+ * Return:
+ */
+static int mx27lite_pcmcia_find_bsize(unsigned long win_size)
+{
+ int i, nr = sizeof(bsize_map) / sizeof(bsize_map_t);
+ int bsize = -1;
+
+ for (i = 0; i < nr; i++) {
+ if (bsize_map[i].win_size == win_size) {
+ bsize = bsize_map[i].bsize;
+ break;
+ }
+ }
+
+ pr_debug(KERN_INFO "nr = %d bsize = 0x%0x\n", nr, bsize);
+ if (bsize < 0 || i > nr) {
+ pr_debug(KERN_INFO "No such bsize\n");
+ return -ENODEV;
+ }
+
+ return bsize;
+}
+
+/* mx27lite_common_pcmcia_sock_init()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus. This must wait for power to stabilise
+ * so that the card status signals report correctly.
+ *
+ * Returns: 0
+ */
+static int mx27lite_common_pcmcia_sock_init(struct pcmcia_socket *sock)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+
+ printk("\n\n\nINIT mx27lite_pcmcia_socket CALLED\n\n\n");
+ pr_debug(KERN_INFO "initializing socket\n");
+
+ skt->ops->socket_init(skt);
+ return 0;
+}
+
+/*
+ * mx27lite_common_pcmcia_config_skt
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Convert PCMCIA socket state to our socket configure structure.
+ */
+static int
+mx27lite_common_pcmcia_config_skt(struct mx27lite_pcmcia_socket *skt,
+ socket_state_t * state)
+{
+ int ret;
+ printk("mx27lite_common_pcmcia_config_skt called \n\n");
+ ret = skt->ops->configure_socket(skt, state);
+ if (ret == 0) {
+ /*
+ * This really needs a better solution. The IRQ
+ * may or may not be claimed by the driver.
+ */
+ if (skt->irq_state != 1 && state->io_irq) {
+ printk("set falling\n");
+ skt->irq_state = 1;
+ set_irq_type(skt->irq, IRQF_TRIGGER_FALLING);
+ } else if (1){//skt->irq_state == 1 && state->io_irq == 0) {
+ printk("set rising\n");
+ skt->irq_state = 0;
+ set_irq_type(skt->irq, IRQF_TRIGGER_RISING);
+ }
+ printk("maybe nothing\n");
+
+ skt->cs_state = *state;
+ }
+
+ if (ret < 0)
+ pr_debug(KERN_ERR "mx27lite_common_pcmcia: unable to configure"
+ " socket\n");
+
+ return ret;
+}
+
+/*
+ * mx27lite_common_pcmcia_suspend()
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
+ *
+ * Returns: 0
+ */
+static int mx27lite_common_pcmcia_suspend(struct pcmcia_socket *sock)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+ int ret;
+
+ pr_debug(KERN_INFO "suspending socket\n");
+
+ ret = mx27lite_common_pcmcia_config_skt(skt, &dead_socket);
+ if (ret == 0)
+ skt->ops->socket_suspend(skt);
+
+ return ret;
+}
+
+static unsigned int mx27lite_common_pcmcia_skt_state(struct mx27lite_pcmcia_socket
+ *skt)
+{
+ struct pcmcia_state state;
+ unsigned int stat;
+
+ memset(&state, 0, sizeof(struct pcmcia_state));
+
+ skt->ops->socket_state(skt, &state);
+
+ stat = state.detect ? SS_DETECT : 0;
+ stat |= state.ready ? SS_READY : 0;
+ stat |= state.wrprot ? SS_WRPROT : 0;
+ stat |= state.vs_3v ? SS_3VCARD : 0;
+ stat |= state.vs_Xv ? SS_XVCARD : 0;
+
+ /* The power status of individual sockets is not available
+ * explicitly from the hardware, so we just remember the state
+ * and regurgitate it upon request:
+ */
+ stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
+
+ if (skt->cs_state.flags & SS_IOCARD)
+ stat |= state.bvd1 ? SS_STSCHG : 0;
+ else {
+ if (state.bvd1 == 0)
+ stat |= SS_BATDEAD;
+ else if (state.bvd2 == 0)
+ stat |= SS_BATWARN;
+ }
+
+ pr_debug(KERN_INFO "stat = 0x%08x\n", stat);
+
+ return stat;
+}
+
+/*
+ * Implements the get_status() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetStatus in Card Services). Essentially just
+ * fills in bits in `status' according to internal driver state or
+ * the value of the voltage detect chipselect register.
+ *
+ * As a debugging note, during card startup, the PCMCIA core issues
+ * three set_socket() commands in a row the first with RESET deasserted,
+ * the second with RESET asserted, and the last with RESET deasserted
+ * again. Following the third set_socket(), a get_status() command will
+ * be issued. The kernel is looking for the SS_READY flag (see
+ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
+ *
+ * Returns: 0
+ */
+static int mx27lite_common_pcmcia_get_status(struct pcmcia_socket *sock,
+ unsigned int *status)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+
+ skt->status = mx27lite_common_pcmcia_skt_state(skt);
+ *status = skt->status;
+ printk("called get_status = %d\n",skt->status);
+ printk("\nREGISTER VALUES\n\tPIPR=0x%08lx\n\tPSCR=0x%08lx\n\tPER=0x%08lx"
+ "\n\tPGCR=0x%08lx\n\tPGSR=0x%08lx\n\n",
+ _reg_PCMCIA_PIPR,_reg_PCMCIA_PSCR,_reg_PCMCIA_PER,
+ _reg_PCMCIA_PGCR,_reg_PCMCIA_PGSR);
+
+ return 0;
+}
+
+/*
+ * Implements the set_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetSocket in Card Services). We more or
+ * less punt all of this work and let the kernel handle the details
+ * of power configuration, reset, &c. We also record the value of
+ * `state' in order to regurgitate it to the PCMCIA core later.
+ *
+ * Returns: 0
+ */
+static int mx27lite_common_pcmcia_set_socket(struct pcmcia_socket *sock,
+ socket_state_t * state)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+
+ pr_debug(KERN_INFO
+ "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
+ (state->csc_mask == 0) ? "<NONE> " : "",
+ (state->csc_mask & SS_DETECT) ? "DETECT " : "",
+ (state->csc_mask & SS_READY) ? "READY " : "",
+ (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
+ (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
+ (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
+ (state->flags == 0) ? "<NONE> " : "",
+ (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
+ (state->flags & SS_IOCARD) ? "IOCARD " : "",
+ (state->flags & SS_RESET) ? "RESET " : "",
+ (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
+ (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
+ state->Vcc, state->Vpp, state->io_irq);
+
+ pr_debug(KERN_INFO
+ "csc_mask: %08x flags: %08x Vcc: %d Vpp: %d io_irq: %d\n",
+ state->csc_mask, state->flags, state->Vcc, state->Vpp,
+ state->io_irq);
+ printk("mx27lite_common_pcmcia_set_socket called\n");
+ printk(KERN_INFO
+ "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
+ (state->csc_mask == 0) ? "<NONE> " : "",
+ (state->csc_mask & SS_DETECT) ? "DETECT " : "",
+ (state->csc_mask & SS_READY) ? "READY " : "",
+ (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
+ (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
+ (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
+ (state->flags == 0) ? "<NONE> " : "",
+ (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
+ (state->flags & SS_IOCARD) ? "IOCARD " : "",
+ (state->flags & SS_RESET) ? "RESET " : "",
+ (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
+ (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
+ state->Vcc, state->Vpp, state->io_irq);
+
+ printk(KERN_INFO
+ "csc_mask: %08x flags: %08x Vcc: %d Vpp: %d io_irq: %d\n",
+ state->csc_mask, state->flags, state->Vcc, state->Vpp,
+ state->io_irq);
+
+ return mx27lite_common_pcmcia_config_skt(skt, state);
+}
+
+/*
+ * Set address and profile to window registers PBR, POR, POFR
+ */
+static int mx27lite_pcmcia_set_window_reg(ulong start, ulong end, u_int window)
+{
+ int bsize;
+ ulong size = end - start + 1;
+
+ bsize = mx27lite_pcmcia_find_bsize(size);
+ if (bsize < 0) {
+ pr_debug("Cannot set the window register\n");
+ return -1;
+ }
+ /* Disable the window */
+ _reg_PCMCIA_POR(window) &= ~PCMCIA_POR_PV;
+
+ /* Set PBR, POR, POFR */
+ _reg_PCMCIA_PBR(window) = start;
+ _reg_PCMCIA_POR(window) &= ~(PCMCIA_POR_PRS_MASK
+ | PCMCIA_POR_WPEN
+ | PCMCIA_POR_WP
+ | PCMCIA_POR_BSIZE_MASK
+ | PCMCIA_POR_PPS_8);
+ _reg_PCMCIA_POR(window) |= bsize | PCMCIA_POR_PPS_16;
+
+ switch (window) {
+ case IO_WINDOW:
+ _reg_PCMCIA_POR(window) |= PCMCIA_POR_PRS(PCMCIA_POR_PRS_IO);
+ break;
+
+ case ATTRIBUTE_MEMORY_WINDOW:
+ _reg_PCMCIA_POR(window) |=
+ PCMCIA_POR_PRS(PCMCIA_POR_PRS_ATTRIBUTE);
+ break;
+
+ case COMMON_MEMORY_WINDOW:
+ _reg_PCMCIA_POR(window) |=
+ PCMCIA_POR_PRS(PCMCIA_POR_PRS_COMMON);
+ break;
+
+ default:
+ pr_debug("Window %d is not support\n", window);
+ return -1;
+ }
+ _reg_PCMCIA_POFR(window) = 0;
+
+ /* Enable the window */
+ _reg_PCMCIA_POR(window) |= PCMCIA_POR_PV;
+
+ return 0;
+}
+
+/*
+ * Implements the set_io_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetIOMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int
+mx27lite_common_pcmcia_set_io_map(struct pcmcia_socket *sock,
+ struct pccard_io_map *map)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+ unsigned short speed = map->speed;
+
+ pr_debug("map %u speed %u start 0x%08lx stop 0x%08lx\n",
+ map->map, map->speed, map->start, map->stop);
+ pr_debug("flags: %s%s%s%s%s%s%s%s\n",
+ (map->flags == 0) ? "<NONE>" : "",
+ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+ (map->flags & MAP_16BIT) ? "16BIT " : "",
+ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+ (map->flags & MAP_0WS) ? "0WS " : "",
+ (map->flags & MAP_WRPROT) ? "WRPROT " : "",
+ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
+ (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
+
+ if (map->map >= MAX_IO_WIN) {
+ pr_debug(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+ map->map);
+ return -1;
+ }
+
+ if (map->flags & MAP_ACTIVE) {
+ if (speed == 0)
+ speed = PCMCIA_IO_ACCESS;
+ } else {
+ speed = 0;
+ }
+
+ skt->spd_io[map->map] = speed;
+ skt->ops->set_timing(skt);
+
+ if (map->stop == 1)
+ map->stop = PAGE_SIZE - 1;
+
+ skt->socket.io_offset = (unsigned long)skt->virt_io;
+ map->stop -= map->start;
+ map->stop += (unsigned long)skt->virt_io;
+ map->start = (unsigned long)skt->virt_io;
+
+ mx27lite_pcmcia_set_window_reg(skt->res_io.start, skt->res_io.end,
+ IO_WINDOW);
+
+ pr_debug(KERN_ERR "IO window: _reg_PCMCIA_PBR(%d) = %08x\n",
+ IO_WINDOW, _reg_PCMCIA_PBR(IO_WINDOW));
+ pr_debug(KERN_ERR "IO window: _reg_PCMCIA_POR(%d) = %08x\n",
+ IO_WINDOW, _reg_PCMCIA_POR(IO_WINDOW));
+
+ return 0;
+}
+
+/*
+ * Implements the set_mem_map() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetMemMap in Card Services). We configure
+ * the map speed as requested, but override the address ranges
+ * supplied by Card Services.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int
+mx27lite_common_pcmcia_set_mem_map(struct pcmcia_socket *sock,
+ struct pccard_mem_map *map)
+{
+ struct mx27lite_pcmcia_socket *skt = to_mx27lite_pcmcia_socket(sock);
+ struct resource *res;
+ unsigned short speed = map->speed;
+
+ pr_debug
+ (KERN_INFO
+ "map %u speed %u card_start %08x flags%08x static_start %08lx\n",
+ map->map, map->speed, map->card_start, map->flags,
+ map->static_start);
+ pr_debug(KERN_INFO "flags: %s%s%s%s%s%s%s%s\n",
+ (map->flags == 0) ? "<NONE>" : "",
+ (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+ (map->flags & MAP_16BIT) ? "16BIT " : "",
+ (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+ (map->flags & MAP_0WS) ? "0WS " : "",
+ (map->flags & MAP_WRPROT) ? "WRPROT " : "",
+ (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
+ (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
+
+ if (map->map >= MAX_WIN)
+ return -EINVAL;
+
+ if (map->flags & MAP_ACTIVE) {
+ if (speed == 0)
+ speed = 300;
+ } else {
+ speed = 0;
+ }
+
+ if (map->flags & MAP_ATTRIB) {
+ res = &skt->res_attr;
+ skt->spd_attr[map->map] = speed;
+ skt->spd_mem[map->map] = 0;
+ mx27lite_pcmcia_set_window_reg(res->start, res->end,
+ ATTRIBUTE_MEMORY_WINDOW);
+
+ pr_debug(KERN_INFO "Attr window: _reg_PCMCIA_PBR(%d) = %08x\n",
+ ATTRIBUTE_MEMORY_WINDOW,
+ _reg_PCMCIA_PBR(ATTRIBUTE_MEMORY_WINDOW));
+ pr_debug(KERN_INFO "_reg_PCMCIA_POR(%d) = %08x\n",
+ ATTRIBUTE_MEMORY_WINDOW,
+ _reg_PCMCIA_POR(ATTRIBUTE_MEMORY_WINDOW));
+
+ } else {
+ res = &skt->res_mem;
+ skt->spd_attr[map->map] = 0;
+ skt->spd_mem[map->map] = speed;
+ mx27lite_pcmcia_set_window_reg(res->start, res->end,
+ COMMON_MEMORY_WINDOW);
+
+ pr_debug(KERN_INFO "Com window: _reg_PCMCIA_PBR(%d) = %08x\n",
+ COMMON_MEMORY_WINDOW,
+ _reg_PCMCIA_PBR(COMMON_MEMORY_WINDOW));
+ pr_debug(KERN_INFO "Com window: _reg_PCMCIA_POR(%d) = %08x\n",
+ COMMON_MEMORY_WINDOW,
+ _reg_PCMCIA_POR(COMMON_MEMORY_WINDOW));
+ }
+
+ skt->ops->set_timing(skt);
+
+ map->static_start = res->start + map->card_start;
+
+ return 0;
+}
+
+static struct pccard_operations mx27lite_common_pcmcia_operations = {
+ .init = mx27lite_common_pcmcia_sock_init,
+ .suspend = mx27lite_common_pcmcia_suspend,
+ .get_status = mx27lite_common_pcmcia_get_status,
+ .set_socket = mx27lite_common_pcmcia_set_socket,
+ .set_io_map = mx27lite_common_pcmcia_set_io_map,
+ .set_mem_map = mx27lite_common_pcmcia_set_mem_map,
+};
+
+/* ============================================================================== */
+
+static inline void mx27lite_pcmcia_irq_config(void)
+{
+ printk("\n\nmx27lite_pcmcia_irq_config\n\n");
+ /* Setup irq */
+ _reg_PCMCIA_PER =
+ (PCMCIA_PER_ERRINTEN | PCMCIA_PER_CDE1 | PCMCIA_PER_CDE2);
+}
+
+static inline void mx27lite_pcmcia_invalidate_windows(void)
+{
+ int i;
+
+ for (i = 0; i < PCMCIA_WINDOWS; i++) {
+ _reg_PCMCIA_PBR(i) = 0;
+ _reg_PCMCIA_POR(i) = 0;
+ _reg_PCMCIA_POFR(i) = 0;
+ }
+}
+
+extern int gpio_pcmcia_active(void);
+extern void gpio_pcmcia_inactive(void);
+
+static int mx27lite_pcmcia_hw_init(struct mx27lite_pcmcia_socket *skt)
+{
+ printk("\n\nmx27lite_pcmcia_hw_init\n\n");
+ /* Configure the pins for PCMCIA */
+ if ( gpio_pcmcia_active() )
+ {
+ printk("\n\nGPIO PIN ERROR\n\n");
+ }
+
+ /*
+ * enabling interrupts at this time causes a flood of interrupts
+ * if a card is present, so wait for configure_socket
+ * to enable them when requested.
+ *
+ * mx27lite_pcmcia_irq_config();
+ */
+ mx27lite_pcmcia_invalidate_windows();
+
+ /* Register interrupt. */
+ skt->irq = MX27LITE_PCMCIA_IRQ;
+
+ return 0;
+}
+
+static void mx27lite_pcmcia_free_irq(struct mx27lite_pcmcia_socket *skt,
+ unsigned int irq)
+{
+ free_irq(irq, skt);
+}
+
+static void mx27lite_pcmcia_hw_shutdown(struct mx27lite_pcmcia_socket *skt)
+{
+ printk("\n\nmx27lite_pcmcia_hw_shutodwn\n\n");
+ mx27lite_pcmcia_invalidate_windows();
+ mx27lite_pcmcia_free_irq(skt, MX27LITE_PCMCIA_IRQ);
+
+ /* Disable the pins */
+ gpio_pcmcia_inactive();
+}
+
+/*
+ * Get the socket state
+ */
+static void
+mx27lite_pcmcia_socket_state(struct mx27lite_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ unsigned long pins;
+
+ pins = _reg_PCMCIA_PIPR;
+ pr_debug(KERN_INFO "_reg_PCMCIA_PIPR = 0x%08lx\n", pins);
+ //printk("_reg_PCMCIA_PIPR=0x%08lx, %x, %x, %x,%x,%x,%x\n",
+ // pins,PCMCIA_PIPR_RDY,PCMCIA_PIPR_BVD2,
+ // PCMCIA_PIPR_BVD1,PCMCIA_PIPR_CD,PCMCIA_PIPR_POWERON,
+ // PCMCIA_PIPR_VS_5V);
+
+ state->ready = (pins & PCMCIA_PIPR_RDY) ? 1 : 0;
+ state->bvd2 = (pins & PCMCIA_PIPR_BVD2) ? 1 : 0;
+ state->bvd1 = (pins & PCMCIA_PIPR_BVD1) ? 1 : 0;
+
+ if ((pins & PCMCIA_PIPR_CD) == PCMCIA_PIPR_CD) {
+ state->detect = 0;
+ skt->cs_state.csc_mask |= SS_INSERTION;
+ } else {
+ state->detect = 1;
+ }
+ state->detect = (pins & PCMCIA_PIPR_CD) ? 0 : 1;
+ state->wrprot = (pins & PCMCIA_PIPR_WP) ? 1 : 0;
+ state->poweron = (pins & PCMCIA_PIPR_POWERON) ? 1 : 0;
+#if 0
+ if ((pins & PCMCIA_PIPR_CD) == PCMCIA_PIPR_CD) {
+ state->detect = 0;
+ skt->cs_state.csc_mask |= SS_INSERTION;
+ } else {
+ state->detect = 1;
+ }
+ if (pins & PCMCIA_PIPR_VS_5V) {
+ state->vs_3v = 0;
+ skt->cs_state.Vcc = 33;
+ } else {
+ state->vs_3v = 1;
+ skt->cs_state.Vcc = 50;
+ }
+#endif
+ state->vs_3v = (pins & PCMCIA_PIPR_VS_5V) ? 0 : 1;
+ state->vs_Xv = 0;
+}
+
+static __inline__ void mx27lite_pcmcia_low_power(bool enable)
+{
+ if (enable)
+ _reg_PCMCIA_PGCR |= PCMCIA_PGCR_LPMEN;
+ else
+ _reg_PCMCIA_PGCR &= ~PCMCIA_PGCR_LPMEN;
+}
+
+static __inline__ void mx27lite_pcmcia_soft_reset(void)
+{
+ _reg_PCMCIA_PGCR |= PCMCIA_PGCR_RESET;
+ msleep(2);
+
+ _reg_PCMCIA_PGCR &= ~(PCMCIA_PGCR_RESET | PCMCIA_PGCR_LPMEN);
+ _reg_PCMCIA_PGCR |= PCMCIA_PGCR_POE;
+ msleep(2);
+ pr_debug(KERN_INFO "_reg_PCMCIA_PGCR = %08x\n", _reg_PCMCIA_PGCR);
+}
+
+static int
+mx27lite_pcmcia_configure_socket(struct mx27lite_pcmcia_socket *skt,
+ const socket_state_t * state)
+{
+ int ret = 0;
+
+ if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) {
+ pr_debug(KERN_ERR "mx27lite-pcmcia: unrecognized Vcc %d\n",
+ state->Vcc);
+ return -1;
+ }
+
+ pr_debug(KERN_INFO "PIPR = %x, desired Vcc = %d.%dV\n",
+ _reg_PCMCIA_PIPR, state->Vcc / 10, state->Vcc % 10);
+ printk( "PIPR = %x, desired Vcc = %d.%dV\n",
+ _reg_PCMCIA_PIPR, state->Vcc / 10, state->Vcc % 10);
+
+ if (!(skt->socket.state & SOCKET_PRESENT) && (skt->pre_stat == 1)) {
+ pr_debug(KERN_INFO "Socket enter low power mode\n");
+ skt->pre_stat = 0;
+ mx27lite_pcmcia_low_power(1);
+ }
+
+ if (state->flags & SS_RESET) {
+ printk("soft_reset called from configure_socket\n");
+ mx27lite_pcmcia_soft_reset();
+
+ /* clean out previous tenant's trash */
+ _reg_PCMCIA_PGSR = (PCMCIA_PGSR_NWINE
+ | PCMCIA_PGSR_LPE
+ | PCMCIA_PGSR_SE
+ | PCMCIA_PGSR_CDE | PCMCIA_PGSR_WPE);
+ }
+ /* enable interrupts if requested, else turn 'em off */
+ if (skt->irq)
+ mx27lite_pcmcia_irq_config();
+ else
+ _reg_PCMCIA_PER = 0;
+
+ if (skt->socket.state & SOCKET_PRESENT) {
+ skt->pre_stat = 1;
+ }
+ return ret;
+}
+
+static void mx27lite_pcmcia_enable_irq(struct mx27lite_pcmcia_socket *skt,
+ unsigned int irq)
+{
+ printk("\n\nonable irq=%d\n\n",irq);
+ set_irq_type(irq, IRQF_TRIGGER_RISING);
+ //set_irq_type(irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING);
+}
+
+static void mx27lite_pcmcia_disable_irq(struct mx27lite_pcmcia_socket *skt,
+ unsigned int irq)
+{
+ printk("\n\nDisable irq=%d\n\n",irq);
+ set_irq_type(irq, IRQF_TRIGGER_NONE);
+}
+
+/*
+ * Enable card status IRQs on (re-)initialisation. This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+static void mx27lite_pcmcia_socket_init(struct mx27lite_pcmcia_socket *skt)
+{
+ printk("soft reset called frmo socket_init\n");
+ mx27lite_pcmcia_soft_reset();
+
+ mx27lite_pcmcia_enable_irq(skt, MX27LITE_PCMCIA_IRQ);
+}
+
+/*
+ * Disable card status IRQ on suspend.
+ */
+static void mx27lite_pcmcia_socket_suspend(struct mx27lite_pcmcia_socket *skt)
+{
+ mx27lite_pcmcia_disable_irq(skt, MX27LITE_PCMCIA_IRQ);
+ mx27lite_pcmcia_low_power(1);
+}
+
+/* ==================================================================================== */
+
+/*
+ * PCMCIA strobe hold time
+ */
+static inline u_int mx27lite_pcmcia_por_psht(u_int pcmcia_cycle_ns,
+ u_int hclk_cycle_ns)
+{
+ u_int psht;
+
+ return psht = pcmcia_cycle_ns / hclk_cycle_ns;
+}
+
+/*
+ * PCMCIA strobe set up time
+ */
+static inline u_int mx27lite_pcmcia_por_psst(u_int pcmcia_cycle_ns,
+ u_int hclk_cycle_ns)
+{
+ u_int psst;
+
+ return psst = pcmcia_cycle_ns / hclk_cycle_ns;
+}
+
+/*
+ * PCMCIA strobe length time
+ */
+static inline u_int mx27lite_pcmcia_por_pslt(u_int pcmcia_cycle_ns,
+ u_int hclk_cycle_ns)
+{
+ u_int pslt;
+
+ return pslt = pcmcia_cycle_ns / hclk_cycle_ns + 2;
+}
+
+/*
+ * mx27lite_pcmcia_default_mecr_timing
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * Calculate MECR clock wait states for given CPU clock
+ * speed and command wait state. This function can be over-
+ * written by a board specific version.
+ *
+ * The default is to simply calculate the BS values as specified in
+ * the INTEL SA1100 development manual
+ * "Expansion Memory (PCMCIA) Configuration Register (MECR)"
+ * that's section 10.2.5 in _my_ version of the manual ;)
+ */
+static unsigned int mx27lite_pcmcia_default_mecr_timing(struct
+ mx27lite_pcmcia_socket
+ *skt,
+ unsigned int cpu_speed,
+ unsigned int cmd_time)
+{
+ return 0;
+}
+
+/*
+ * Calculate the timing code
+ */
+static u_int mx27lite_pcmcia_cal_code(u_int speed_ns, u_int clk_ns)
+{
+ u_int code;
+
+ code = PCMCIA_POR_PSHT(mx27lite_pcmcia_por_psht(speed_ns, clk_ns))
+ | PCMCIA_POR_PSST(mx27lite_pcmcia_por_psst(speed_ns, clk_ns))
+ | PCMCIA_POR_PSL(mx27lite_pcmcia_por_pslt(speed_ns, clk_ns));
+
+ return code;
+}
+
+/*
+ * set MECR value for socket <sock> based on this sockets
+ * io, mem and attribute space access speed.
+ * Call board specific BS value calculation to allow boards
+ * to tweak the BS values.
+ */
+static int mx27lite_pcmcia_set_window_timing(u_int speed_ns, u_int window,
+ u_int clk_ns)
+{
+ u_int code = 0;
+
+ switch (window) {
+ case IO_WINDOW:
+ code = mx27lite_pcmcia_cal_code(speed_ns, clk_ns);
+ break;
+ case COMMON_MEMORY_WINDOW:
+ code = mx27lite_pcmcia_cal_code(speed_ns, clk_ns);
+ break;
+ case ATTRIBUTE_MEMORY_WINDOW:
+ code = mx27lite_pcmcia_cal_code(speed_ns, clk_ns);
+ break;
+ default:
+ break;
+ }
+
+ /* Disable the window */
+ _reg_PCMCIA_POR(window) &= ~PCMCIA_POR_PV;
+
+ /* Clear the register fisrt */
+ _reg_PCMCIA_POR(window) &= ~(PCMCIA_POR_PSST_MASK
+ | PCMCIA_POR_PSL_MASK
+ | PCMCIA_POR_PSHT_MASK);
+ /* And then set the register */
+ _reg_PCMCIA_POR(window) |= code;
+
+ /* Enable the window */
+ _reg_PCMCIA_POR(window) |= PCMCIA_POR_PV;
+
+ return 0;
+}
+
+static unsigned short calc_speed(unsigned short *spds, int num,
+ unsigned short dflt)
+{
+ unsigned short speed = 0;
+ int i;
+
+ for (i = 0; i < num; i++)
+ if (speed < spds[i])
+ speed = spds[i];
+ if (speed == 0)
+ speed = dflt;
+
+ return speed;
+}
+
+static void
+mx27lite_common_pcmcia_get_timing(struct mx27lite_pcmcia_socket *skt,
+ struct mx27lite_pcmcia_timing *timing)
+{
+ timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, PCMCIA_IO_ACCESS);
+ timing->mem = calc_speed(skt->spd_mem, MAX_WIN, PCMCIA_3V_MEM_ACCESS);
+ timing->attr =
+ calc_speed(skt->spd_attr, MAX_WIN, PCMCIA_ATTR_MEM_ACCESS);
+}
+
+static int mx27lite_pcmcia_set_timing(struct mx27lite_pcmcia_socket *skt)
+{
+ u_int clk_ns;
+ struct mx27lite_pcmcia_timing timing;
+
+ /* How many nanoseconds */
+ clk_ns = (1000 * 1000 * 1000) / clk_get_rate(skt->clk);
+ pr_debug(KERN_INFO "clk_ns = %d\n", clk_ns);
+
+ mx27lite_common_pcmcia_get_timing(skt, &timing);
+ pr_debug(KERN_INFO "timing: io %d, mem %d, attr %d\n", timing.io,
+ timing.mem, timing.attr);
+
+ mx27lite_pcmcia_set_window_timing(timing.io, IO_WINDOW, clk_ns);
+ mx27lite_pcmcia_set_window_timing(timing.mem, COMMON_MEMORY_WINDOW,
+ clk_ns);
+ mx27lite_pcmcia_set_window_timing(timing.attr, ATTRIBUTE_MEMORY_WINDOW,
+ clk_ns);
+
+ return 0;
+}
+
+static int mx27lite_pcmcia_show_timing(struct mx27lite_pcmcia_socket *skt,
+ char *buf)
+{
+ return 0;
+}
+
+static struct pcmcia_low_level mx27lite_pcmcia_ops = {
+ .owner = THIS_MODULE,
+ .hw_init = mx27lite_pcmcia_hw_init,
+ .hw_shutdown = mx27lite_pcmcia_hw_shutdown,
+ .socket_state = mx27lite_pcmcia_socket_state,
+ .configure_socket = mx27lite_pcmcia_configure_socket,
+
+ .socket_init = mx27lite_pcmcia_socket_init,
+ .socket_suspend = mx27lite_pcmcia_socket_suspend,
+
+ .get_timing = mx27lite_pcmcia_default_mecr_timing,
+ .set_timing = mx27lite_pcmcia_set_timing,
+ .show_timing = mx27lite_pcmcia_show_timing,
+};
+
+/* =================================================================================== */
+
+LIST_HEAD(mx27lite_pcmcia_sockets);
+DECLARE_MUTEX(mx27lite_pcmcia_sockets_lock);
+
+static DEFINE_SPINLOCK(status_lock);
+
+struct bittbl {
+ unsigned int mask;
+ const char *name;
+};
+
+static struct bittbl status_bits[] = {
+ {SS_WRPROT, "SS_WRPROT"},
+ {SS_BATDEAD, "SS_BATDEAD"},
+ {SS_BATWARN, "SS_BATWARN"},
+ {SS_READY, "SS_READY"},
+ {SS_DETECT, "SS_DETECT"},
+ {SS_POWERON, "SS_POWERON"},
+ {SS_STSCHG, "SS_STSCHG"},
+ {SS_3VCARD, "SS_3VCARD"},
+ {SS_XVCARD, "SS_XVCARD"},
+};
+
+static struct bittbl conf_bits[] = {
+ {SS_PWR_AUTO, "SS_PWR_AUTO"},
+ {SS_IOCARD, "SS_IOCARD"},
+ {SS_RESET, "SS_RESET"},
+ {SS_DMA_MODE, "SS_DMA_MODE"},
+ {SS_SPKR_ENA, "SS_SPKR_ENA"},
+ {SS_OUTPUT_ENA, "SS_OUTPUT_ENA"},
+};
+
+static void
+dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits,
+ int sz)
+{
+ char *b = *p;
+ int i;
+
+ b += sprintf(b, "%-9s:", prefix);
+ for (i = 0; i < sz; i++)
+ if (val & bits[i].mask)
+ b += sprintf(b, " %s", bits[i].name);
+ *b++ = '\n';
+ *p = b;
+}
+
+/*
+ * Implements the /sys/class/pcmcia_socket/??/status file.
+ *
+ * Returns: the number of characters added to the buffer
+ */
+static ssize_t show_status(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mx27lite_pcmcia_socket *skt =
+ container_of(dev, struct mx27lite_pcmcia_socket, socket.dev);
+ char *p = buf;
+
+ p += sprintf(p, "slot : %d\n", skt->nr);
+
+ dump_bits(&p, "status", skt->status,
+ status_bits, ARRAY_SIZE(status_bits));
+ dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
+ status_bits, ARRAY_SIZE(status_bits));
+ dump_bits(&p, "cs_flags", skt->cs_state.flags,
+ conf_bits, ARRAY_SIZE(conf_bits));
+
+ p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
+ p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
+ p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq);
+ if (skt->ops->show_timing)
+ p += skt->ops->show_timing(skt, p);
+
+ return p - buf;
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static void mx27lite_common_check_status(struct mx27lite_pcmcia_socket *skt)
+{
+ unsigned int events;
+
+ pr_debug(KERN_INFO "entering PCMCIA monitoring thread\n");
+
+ do {
+ unsigned int status;
+ unsigned long flags;
+
+ status = mx27lite_common_pcmcia_skt_state(skt);
+
+ spin_lock_irqsave(&status_lock, flags);
+ events = (status ^ skt->status) & skt->cs_state.csc_mask;
+ skt->status = status;
+ spin_unlock_irqrestore(&status_lock, flags);
+
+ pr_debug(KERN_INFO "events: %s%s%s%s%s%s\n",
+ events == 0 ? "<NONE>" : "",
+ events & SS_DETECT ? "DETECT " : "",
+ events & SS_READY ? "READY " : "",
+ events & SS_BATDEAD ? "BATDEAD " : "",
+ events & SS_BATWARN ? "BATWARN " : "",
+ events & SS_STSCHG ? "STSCHG " : "");
+
+ if (events)
+ pcmcia_parse_events(&skt->socket, events);
+ } while (events);
+}
+
+/*
+ * Service routine for socket driver interrupts (requested by the
+ * low-level PCMCIA init() operation via mx27lite_common_pcmcia_thread()).
+ * The actual interrupt-servicing work is performed by
+ * mx27lite_common_pcmcia_thread(), largely because the Card Services event-
+ * handling code performs scheduling operations which cannot be
+ * executed from within an interrupt context.
+ */
+static irqreturn_t mx27lite_common_pcmcia_interrupt(int irq, void *dev)
+{
+ struct mx27lite_pcmcia_socket *skt = dev;
+ volatile u32 pscr, pgsr;
+
+ dev_dbg(dev, "servicing IRQ %d\n", irq);
+
+ /* clear interrupt states */
+ pscr = _reg_PCMCIA_PSCR;
+ _reg_PCMCIA_PSCR = pscr;
+
+ pgsr = _reg_PCMCIA_PGSR;
+ _reg_PCMCIA_PGSR = pgsr;
+ printk( "\n\nservicing IRQ %d, 0x%08x, 0x%08x\n", irq, pscr,pgsr);
+
+ mx27lite_common_check_status(skt);
+
+ return IRQ_HANDLED;
+}
+
+/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
+static void mx27lite_common_pcmcia_poll_event(unsigned long dummy)
+{
+ struct mx27lite_pcmcia_socket *skt =
+ (struct mx27lite_pcmcia_socket *)dummy;
+ pr_debug(KERN_INFO "polling for events\n");
+ //printk("polling for events\n");
+ //printk("\nREGISTER VALUES\n\tPIPR=0x%08lx\n\tPSCR=0x%08lx\n\tPER=0x%08lx"
+ // "\n\tPGCR=0x%08lx\n\tPGSR=0x%08lx\n\n",
+ // _reg_PCMCIA_PIPR,_reg_PCMCIA_PSCR,_reg_PCMCIA_PER,
+ // _reg_PCMCIA_PGCR,_reg_PCMCIA_PGSR);
+
+ mod_timer(&skt->poll_timer, jiffies + PCMCIA_POLL_PERIOD);
+
+ mx27lite_common_check_status(skt);
+}
+
+#define mx27lite_pcmcia_cpufreq_register()
+#define mx27lite_pcmcia_cpufreq_unregister()
+
+static int mx27lite_common_drv_pcmcia_probe(struct platform_device *pdev,
+ struct pcmcia_low_level *ops)
+{
+ struct mx27lite_pcmcia_socket *skt;
+ int vs, value, ret;
+ struct pccard_io_map map;
+
+ down(&mx27lite_pcmcia_sockets_lock);
+
+ printk("\n\n\nGETTING PROBED\n\n\n");
+
+ printk("\nREGISTER VALUES\n\tPIPR=0x%08lx\n\tPSCR=0x%08lx\n\tPER=0x%08lx"
+ "\n\tPGCR=0x%08lx\n\tPGSR=0x%08lx\n\n",
+ _reg_PCMCIA_PIPR,_reg_PCMCIA_PSCR,_reg_PCMCIA_PER,
+ _reg_PCMCIA_PGCR,_reg_PCMCIA_PGSR);
+
+ skt = kmalloc(sizeof(struct mx27lite_pcmcia_socket), GFP_KERNEL);
+ if (!skt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(skt, 0, sizeof(struct mx27lite_pcmcia_socket));
+
+ /*
+ * Initialise the socket structure.
+ */
+ skt->socket.ops = &mx27lite_common_pcmcia_operations;
+ skt->socket.owner = ops->owner;
+ skt->socket.driver_data = skt;
+
+ init_timer(&skt->poll_timer);
+ skt->poll_timer.function = mx27lite_common_pcmcia_poll_event;
+ skt->poll_timer.data = (unsigned long)skt;
+ skt->poll_timer.expires = jiffies + PCMCIA_POLL_PERIOD;
+
+ skt->irq = MX27LITE_PCMCIA_IRQ;
+ skt->socket.dev.parent = pdev->dev.parent;
+ skt->ops = ops;
+
+ skt->clk = clk_get(NULL, "ahb_clk");
+
+ skt->res_skt.start = _PCMCIA(0);
+ skt->res_skt.end = _PCMCIA(0) + PCMCIASp - 1;
+ skt->res_skt.name = MX27LITE_PCMCIA;
+ skt->res_skt.flags = IORESOURCE_MEM;
+
+ ret = request_resource(&iomem_resource, &skt->res_skt);
+ if (ret)
+ goto out_err_1;
+
+ skt->res_io.start = _PCMCIAIO(0);
+ skt->res_io.end = _PCMCIAIO(0) + PCMCIAIOSp - 1;
+ skt->res_io.name = "io";
+ skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+ ret = request_resource(&skt->res_skt, &skt->res_io);
+ if (ret)
+ goto out_err_2;
+
+ skt->res_mem.start = _PCMCIAMem(0);
+ skt->res_mem.end = _PCMCIAMem(0) + PCMCIAMemSp - 1;
+ skt->res_mem.name = "memory";
+ skt->res_mem.flags = IORESOURCE_MEM;
+
+ ret = request_resource(&skt->res_skt, &skt->res_mem);
+ if (ret)
+ goto out_err_3;
+
+ skt->res_attr.start = _PCMCIAAttr(0);
+ skt->res_attr.end = _PCMCIAAttr(0) + PCMCIAAttrSp - 1;
+ skt->res_attr.name = "attribute";
+ skt->res_attr.flags = IORESOURCE_MEM;
+
+ ret = request_resource(&skt->res_skt, &skt->res_attr);
+ if (ret)
+ goto out_err_4;
+
+ skt->virt_io = ioremap(skt->res_io.start, 0x10000);
+ if (skt->virt_io == NULL) {
+ ret = -ENOMEM;
+ goto out_err_5;
+ }
+
+ if (list_empty(&mx27lite_pcmcia_sockets))
+ mx27lite_pcmcia_cpufreq_register();
+ list_add(&skt->node, &mx27lite_pcmcia_sockets);
+
+ /*
+ * We initialize default socket timing here, because
+ * we are not guaranteed to see a SetIOMap operation at
+ * runtime.
+ */
+ ops->set_timing(skt);
+
+ ret = ops->hw_init(skt);
+ if (ret)
+ goto out_err_6;
+
+ ret = request_irq(skt->irq, mx27lite_common_pcmcia_interrupt,
+ IRQF_SHARED | IRQF_DISABLED, "PCMCIA IRQ", skt);
+ if (ret)
+ goto out_err_6;
+ set_irq_type(skt->irq, IRQT_NOEDGE);
+
+ skt->socket.features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+ skt->socket.resource_ops = &pccard_static_ops;
+ skt->socket.irq_mask = 0;
+ skt->socket.map_size = PCMCIAPrtSp;
+ skt->socket.pci_irq = skt->irq;
+ skt->socket.io_offset = (unsigned long)skt->virt_io;
+
+ skt->status = mx27lite_common_pcmcia_skt_state(skt);
+ skt->pre_stat = 0;
+ ret = pcmcia_register_socket(&skt->socket);
+ if (ret)
+ goto out_err_7;
+ /* FIXED ME workaround for binding with ide-cs. ide usage io port 0x100~0x107 and 0x10e */
+ map.map = 0;
+ map.flags = MAP_ACTIVE | MAP_16BIT;
+ map.start = 0;
+ map.stop = PCMCIAIOSp - 1;
+ map.speed = 0;
+ mx27lite_common_pcmcia_set_io_map(&skt->socket, &map);
+
+ vs = _reg_PCMCIA_PIPR & PCMCIA_PIPR_VS;
+ value = vs & PCMCIA_PIPR_VS_5V ? 50 : 33;
+ dev_dbg(&pdev->dev, "PCMCIA: Voltage the card supports: %d.%dV\n",
+ value / 10, value % 10);
+
+ add_timer(&skt->poll_timer);
+
+ ret = device_create_file(&skt->socket.dev, &dev_attr_status);
+ if (ret < 0)
+ goto out_err_8;
+
+ platform_set_drvdata(pdev, skt);
+ ret = 0;
+ goto out;
+
+ out_err_8:
+ printk("8\n");
+ del_timer_sync(&skt->poll_timer);
+ pcmcia_unregister_socket(&skt->socket);
+
+ out_err_7:
+ printk("7\n");
+ flush_scheduled_work();
+ free_irq(skt->irq, skt);
+ ops->hw_shutdown(skt);
+ out_err_6:
+ printk("6\n");
+ list_del(&skt->node);
+ iounmap(skt->virt_io);
+ out_err_5:
+ printk("5\n");
+ release_resource(&skt->res_attr);
+ out_err_4:
+ printk("4\n");
+ release_resource(&skt->res_mem);
+ out_err_3:
+ printk("3\n");
+ release_resource(&skt->res_io);
+ out_err_2:
+ printk("2\n");
+ release_resource(&skt->res_skt);
+ out_err_1:
+ printk("1\n");
+ kfree(skt);
+ out:
+ up(&mx27lite_pcmcia_sockets_lock);
+ return ret;
+}
+
+static int mx27lite_drv_pcmcia_remove(struct platform_device *pdev)
+{
+ struct mx27lite_pcmcia_socket *skt = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ down(&mx27lite_pcmcia_sockets_lock);
+
+ del_timer_sync(&skt->poll_timer);
+
+ pcmcia_unregister_socket(&skt->socket);
+
+ flush_scheduled_work();
+
+ skt->ops->hw_shutdown(skt);
+
+ mx27lite_common_pcmcia_config_skt(skt, &dead_socket);
+
+ list_del(&skt->node);
+ iounmap(skt->virt_io);
+ skt->virt_io = NULL;
+ release_resource(&skt->res_attr);
+ release_resource(&skt->res_mem);
+ release_resource(&skt->res_io);
+ release_resource(&skt->res_skt);
+
+ if (list_empty(&mx27lite_pcmcia_sockets))
+ mx27lite_pcmcia_cpufreq_unregister();
+
+ up(&mx27lite_pcmcia_sockets_lock);
+
+ kfree(skt);
+
+ return 0;
+}
+
+static int mx27lite_drv_pcmcia_probe(struct platform_device *pdev)
+{
+ if (!machine_is_mx27lite())
+ return -ENODEV;
+
+ return mx27lite_common_drv_pcmcia_probe(pdev, &mx27lite_pcmcia_ops);
+}
+
+static int mx27lite_drv_pcmcia_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return pcmcia_socket_dev_suspend(&pdev->dev, state);
+}
+
+static int mx27lite_drv_pcmcia_resume(struct platform_device *pdev)
+{
+ return pcmcia_socket_dev_resume(&pdev->dev);
+}
+
+/*
+ * Low level functions
+ */
+static struct platform_driver mx27lite_pcmcia_driver = {
+ .driver = {
+ .name = MX27LITE_PCMCIA,
+ },
+ .probe = mx27lite_drv_pcmcia_probe,
+ .remove = mx27lite_drv_pcmcia_remove,
+ .suspend = mx27lite_drv_pcmcia_suspend,
+ .resume = mx27lite_drv_pcmcia_resume,
+};
+
+/* mx27lite_pcmcia_init()
+ *
+ */
+static int __init mx27lite_pcmcia_init(void)
+{
+ int ret;
+ //printk("\n\n\nmx27lite_pcmcia_init called\n\n\n");
+ if ((ret = platform_driver_register(&mx27lite_pcmcia_driver))){
+ printk("Failure during init %d\n\n\n",ret);
+ return ret;
+ }
+ printk(KERN_INFO "PCMCIA: Initialize i.Mx27 pcmcia socket\n");
+
+ return ret;
+}
+
+/* mx27lite_pcmcia_exit()
+ *
+ */
+static void __exit mx27lite_pcmcia_exit(void)
+{
+ platform_driver_unregister(&mx27lite_pcmcia_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX27 PCMCIA Socket Controller");
+MODULE_LICENSE("GPL");
+
+module_init(mx27lite_pcmcia_init);
+module_exit(mx27lite_pcmcia_exit);
diff --git a/drivers/pcmcia/mx27lite-pcmcia.h b/drivers/pcmcia/mx27lite-pcmcia.h
new file mode 100644
index 000000000000..afa610ebd089
--- /dev/null
+++ b/drivers/pcmcia/mx27lite-pcmcia.h
@@ -0,0 +1,157 @@
+/*
+ * linux/drivers/pcmcia/mx27lite-pcmcia.h
+ *
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This file contains definitions for the PCMCIA support code common to
+ * integrated SOCs like the i.Mx27 microprocessors.
+ */
+#ifndef _ASM_ARCH_PCMCIA
+#define _ASM_ARCH_PCMCIA
+
+/* include the world */
+#include <linux/cpufreq.h>
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+#define MX27LITE_PCMCIA "Mx27lite_pcmcia_soc"//Name must match device.c
+
+struct device;
+struct pcmcia_low_level;
+
+/*
+ * This structure encapsulates per-socket state which we might need to
+ * use when responding to a Card Services query of some kind.
+ */
+struct mx27lite_pcmcia_socket {
+ struct pcmcia_socket socket;
+
+ /*
+ * Info from low level handler
+ */
+ struct device *dev;
+ unsigned int nr;
+ unsigned int irq;
+
+ struct clk *clk;
+
+ /*
+ * Core PCMCIA state
+ */
+ struct pcmcia_low_level *ops;
+
+ unsigned int status;
+ unsigned int pre_stat;
+ socket_state_t cs_state;
+
+ unsigned short spd_io[MAX_IO_WIN];
+ unsigned short spd_mem[MAX_WIN];
+ unsigned short spd_attr[MAX_WIN];
+
+ struct resource res_skt;
+ struct resource res_io;
+ struct resource res_mem;
+ struct resource res_attr;
+ void *virt_io;
+
+ unsigned int irq_state;
+
+ struct timer_list poll_timer;
+ struct list_head node;
+};
+
+struct pcmcia_state {
+ unsigned detect:1,
+ ready:1, bvd1:1, bvd2:1, wrprot:1, vs_3v:1, vs_Xv:1, poweron:1;
+};
+
+struct pcmcia_low_level {
+ struct module *owner;
+
+ /* first socket in system */
+ int first;
+ /* nr of sockets */
+ int nr;
+
+ int (*hw_init) (struct mx27lite_pcmcia_socket *);
+ void (*hw_shutdown) (struct mx27lite_pcmcia_socket *);
+
+ void (*socket_state) (struct mx27lite_pcmcia_socket *,
+ struct pcmcia_state *);
+ int (*configure_socket) (struct mx27lite_pcmcia_socket *,
+ const socket_state_t *);
+
+ /*
+ * Enable card status IRQs on (re-)initialisation. This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+ void (*socket_init) (struct mx27lite_pcmcia_socket *);
+
+ /*
+ * Disable card status IRQs and PCMCIA bus on suspend.
+ */
+ void (*socket_suspend) (struct mx27lite_pcmcia_socket *);
+
+ /*
+ * Hardware specific timing routines.
+ * If provided, the get_timing routine overrides the SOC default.
+ */
+ unsigned int (*get_timing) (struct mx27lite_pcmcia_socket *,
+ unsigned int, unsigned int);
+ int (*set_timing) (struct mx27lite_pcmcia_socket *);
+ int (*show_timing) (struct mx27lite_pcmcia_socket *, char *);
+
+#ifdef CONFIG_CPU_FREQ
+ /*
+ * CPUFREQ support.
+ */
+ int (*frequency_change) (struct mx27lite_pcmcia_socket *, unsigned long,
+ struct cpufreq_freqs *);
+#endif
+};
+
+struct mx27lite_pcmcia_timing {
+ unsigned short io;
+ unsigned short mem;
+ unsigned short attr;
+};
+
+typedef struct {
+ ulong win_size;
+ int bsize;
+} bsize_map_t;
+
+/*
+ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD
+ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has
+ * a minimum value of 165ns, as well. Section 4.7.2 (describing
+ * common and attribute memory write timing) says that twWE has a
+ * minimum value of 150ns for a 250ns cycle time (for 5V operation;
+ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V
+ * operation, also section 4.7.4). Section 4.7.3 says that taOE
+ * has a maximum value of 150ns for a 300ns cycle time (for 5V
+ * operation), or 300ns for a 600ns cycle time (for 3.3V operation).
+ *
+ * When configuring memory maps, Card Services appears to adopt the policy
+ * that a memory access time of "0" means "use the default." The default
+ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute
+ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and
+ * memory command width time is 300ns.
+ */
+#define PCMCIA_IO_ACCESS (165)
+#define PCMCIA_5V_MEM_ACCESS (150)
+#define PCMCIA_3V_MEM_ACCESS (300)
+#define PCMCIA_ATTR_MEM_ACCESS (300)
+
+/*
+ * The socket driver actually works nicely in interrupt-driven form,
+ * so the (relatively infrequent) polling is "just to be sure."
+ */
+#define PCMCIA_POLL_PERIOD (2*HZ)
+#endif