hh.org updates
[hh.org.git] / arch / arm / mach-pxa / aximx5 / aximx5_pcmcia.c
blobb422674d4f3d1dbdc16d73cb9fb9c5e96e14388c
1 /*
2 * Dell Axim X5 PCMCIA support
4 * Copyright © 2004 Andrew Zabolotny <zap@homelink.ru>
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
8 * more details.
9 */
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/interrupt.h>
15 #include <linux/init.h>
16 #include <linux/device.h>
17 #include <linux/delay.h>
18 #include <linux/soc-old.h>
19 #include <linux/platform_device.h>
21 #include <asm/mach-types.h>
22 #include <asm/hardware.h>
23 #include <../drivers/pcmcia/soc_common.h>
24 #include <asm/arch/pxa-regs.h>
25 #include <asm/arch/aximx5-gpio.h>
26 #include <asm/irq.h>
28 #include "../drivers/soc/mq11xx.h"
30 #if 0
31 # define debug_out(s, args...) printk (KERN_INFO s, ##args)
32 #else
33 # define debug_out(s, args...)
34 #endif
35 #define debug_func(s, args...) debug_out ("%s: " s, __FUNCTION__, ##args)
37 /* PCMCIA interrupt number, multiplexed off the MediaQ chip */
38 #define IRQ_PCMCIA (mq_base->irq_base + IRQ_MQ_GPIO_2)
40 static struct mediaq11xx_base *mq_base;
42 static struct pcmcia_irqs aximx5_cd_irqs[] = {
43 { 0, AXIMX5_IRQ (PCMCIA_DETECT_N), "PCMCIA CD" }
46 static void aximx5_cf_rst (int state)
48 debug_func ("%d\n", state);
50 SET_AXIMX5_GPIO (PCMCIA_RESET, state);
53 static int aximx5_pcmcia_hw_init (struct soc_pcmcia_socket *skt)
55 debug_func ("\n");
57 skt->irq = IRQ_PCMCIA;
59 /* GPIOs are configured in machine initialization code */
61 return soc_pcmcia_request_irqs(skt, aximx5_cd_irqs,
62 ARRAY_SIZE(aximx5_cd_irqs));
66 * Release all resources.
68 static void aximx5_pcmcia_hw_shutdown (struct soc_pcmcia_socket *skt)
70 debug_func ("\n");
71 soc_pcmcia_free_irqs(skt, aximx5_cd_irqs, ARRAY_SIZE(aximx5_cd_irqs));
74 static void
75 aximx5_pcmcia_socket_state (struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
77 state->detect = GET_AXIMX5_GPIO (PCMCIA_DETECT_N) ? 0 : 1;
78 state->ready = mq_base->get_GPIO (mq_base, 2) ? 1 : 0;
79 state->bvd1 = GET_AXIMX5_GPIO (PCMCIA_BVD1) ? 1 : 0;
80 state->bvd2 = GET_AXIMX5_GPIO (PCMCIA_BVD2) ? 1 : 0;
81 state->wrprot = 0;
82 state->vs_3v = mq_base->get_GPIO (mq_base, 65) ? 1 : 0;
83 state->vs_Xv = 0;
85 debug_out ("detect:%d ready:%d vcc:%d bvd1:%d bvd2:%d\n",
86 state->detect, state->ready, state->vs_3v, state->bvd1, state->bvd2);
89 static int
90 aximx5_pcmcia_configure_socket (struct soc_pcmcia_socket *skt, const socket_state_t *state)
92 /* Don't enable MediaQ power more than once as it keeps a on/off
93 * counter and this can prevent from powering the device off when
94 * it is no longer in use.
96 static int mq_power_state = 0;
98 /* Silently ignore Vpp, output enable, speaker enable. */
99 debug_func ("Reset:%d Vcc:%d\n", (state->flags & SS_RESET) ? 1 : 0,
100 state->Vcc);
102 aximx5_cf_rst (state->flags & SS_RESET);
104 /* Apply socket voltage */
105 switch (state->Vcc) {
106 case 0:
107 mq_base->set_GPIO (mq_base, 65, MQ_GPIO_IN | MQ_GPIO_OUT0);
108 /* Power off the SPI subdevice */
109 if (mq_power_state) {
110 mq_base->set_power (mq_base, MEDIAQ_11XX_SPI_DEVICE_ID, 0);
111 mq_power_state = 0;
113 /* Disable PCMCIA address bus and buffer */
114 SET_AXIMX5_GPIO_N (PCMCIA_BUFF_EN, 0);
115 SET_AXIMX5_GPIO_N (PCMCIA_ADD_EN, 0);
116 break;
117 case 50:
118 case 33:
119 /* Power on the SPI subdevice as it is responsible for mqGPIO65 */
120 if (!mq_power_state) {
121 mq_base->set_power (mq_base, MEDIAQ_11XX_SPI_DEVICE_ID, 1);
122 mq_power_state = 1;
124 /* Enable PCMCIA address bus and buffer */
125 SET_AXIMX5_GPIO_N (PCMCIA_BUFF_EN, 1);
126 SET_AXIMX5_GPIO_N (PCMCIA_ADD_EN, 1);
127 /* Apply power to socket */
128 mq_base->set_GPIO (mq_base, 65, MQ_GPIO_IN | MQ_GPIO_OUT1);
129 break;
130 default:
131 printk (KERN_ERR "%s: Unsupported Vcc:%d\n",
132 __FUNCTION__, state->Vcc);
135 return 0;
139 * Enable card status IRQs on (re-)initialisation. This can
140 * be called at initialisation, power management event, or
141 * pcmcia event.
143 static void aximx5_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
145 debug_func ("\n");
146 soc_pcmcia_enable_irqs (skt, aximx5_cd_irqs, ARRAY_SIZE(aximx5_cd_irqs));
150 * Disable card status IRQs on suspend.
152 static void aximx5_pcmcia_socket_suspend (struct soc_pcmcia_socket *skt)
154 debug_func ("\n");
155 aximx5_cf_rst (1);
156 soc_pcmcia_disable_irqs(skt, aximx5_cd_irqs, ARRAY_SIZE(aximx5_cd_irqs));
159 static struct pcmcia_low_level aximx5_pcmcia_ops = {
160 .owner = THIS_MODULE,
162 .first = 0,
163 .nr = 1,
165 .hw_init = aximx5_pcmcia_hw_init,
166 .hw_shutdown = aximx5_pcmcia_hw_shutdown,
168 .socket_state = aximx5_pcmcia_socket_state,
169 .configure_socket = aximx5_pcmcia_configure_socket,
171 .socket_init = aximx5_pcmcia_socket_init,
172 .socket_suspend = aximx5_pcmcia_socket_suspend,
175 static void aximx5_pcmcia_release (struct device * dev)
177 /* No need to free the structure since it is a static variable */
180 static struct platform_device aximx5_pcmcia_device = {
181 .name = "pxa2xx-pcmcia",
182 .id = 0,
183 .dev = {
184 .platform_data = &aximx5_pcmcia_ops,
185 .release = aximx5_pcmcia_release
189 static int __init
190 aximx5_pcmcia_init(void)
192 debug_func ("\n");
194 if(!machine_is_aximx5())
195 return -ENODEV;
197 if (mq_driver_get ()) {
198 debug_out ("MediaQ base driver not found\n");
199 return -ENODEV;
202 if (mq_device_enum (&mq_base, 1) <= 0) {
203 mq_driver_put ();
204 debug_out ("MediaQ 1132 chip not found\n");
205 return -ENODEV;
208 return platform_device_register (&aximx5_pcmcia_device);
211 static void __exit
212 aximx5_pcmcia_exit(void)
214 platform_device_unregister (&aximx5_pcmcia_device);
215 mq_driver_put ();
218 module_init(aximx5_pcmcia_init);
219 module_exit(aximx5_pcmcia_exit);
221 MODULE_AUTHOR("Andrew Zabolotny <zap@homelink.ru>");
222 MODULE_DESCRIPTION("Dell Axim X5 PCMCIA platform-specific driver");
223 MODULE_LICENSE("GPL");