• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/pcmcia/
1/*
2 * linux/drivers/pcmcia/pxa2xx_trizeps4.c
3 *
4 * TRIZEPS PCMCIA specific routines.
5 *
6 * Author:	J��rgen Schindele
7 * Created:	20 02, 2006
8 * Copyright:	J��rgen Schindele
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/gpio.h>
19#include <linux/interrupt.h>
20#include <linux/platform_device.h>
21
22#include <asm/mach-types.h>
23#include <asm/irq.h>
24
25#include <mach/pxa2xx-regs.h>
26#include <mach/trizeps4.h>
27
28#include "soc_common.h"
29
30extern void board_pcmcia_power(int power);
31
32static struct pcmcia_irqs irqs[] = {
33	{ 0, IRQ_GPIO(GPIO_PCD), "cs0_cd" }
34	/* on other baseboards we can have more inputs */
35};
36
37static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
38{
39	int ret, i;
40	/* we dont have voltage/card/ready detection
41	 * so we dont need interrupts for it
42	 */
43	switch (skt->nr) {
44	case 0:
45		if (gpio_request(GPIO_PRDY, "cf_irq") < 0) {
46			pr_err("%s: sock %d unable to request gpio %d\n", __func__,
47				skt->nr, GPIO_PRDY);
48			return -EBUSY;
49		}
50		if (gpio_direction_input(GPIO_PRDY) < 0) {
51			pr_err("%s: sock %d unable to set input gpio %d\n", __func__,
52				skt->nr, GPIO_PRDY);
53			gpio_free(GPIO_PRDY);
54			return -EINVAL;
55		}
56		skt->socket.pci_irq = IRQ_GPIO(GPIO_PRDY);
57		break;
58
59#ifndef CONFIG_MACH_TRIZEPS_CONXS
60	case 1:
61#endif
62	default:
63		break;
64	}
65	/* release the reset of this card */
66	pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
67
68	/* supplementory irqs for the socket */
69	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
70		if (irqs[i].sock != skt->nr)
71			continue;
72		if (gpio_request(IRQ_TO_GPIO(irqs[i].irq), irqs[i].str) < 0) {
73			pr_err("%s: sock %d unable to request gpio %d\n",
74				__func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
75			ret = -EBUSY;
76			goto error;
77		}
78		if (gpio_direction_input(IRQ_TO_GPIO(irqs[i].irq)) < 0) {
79			pr_err("%s: sock %d unable to set input gpio %d\n",
80				__func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq));
81			ret = -EINVAL;
82			goto error;
83		}
84	}
85	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
86
87error:
88	for (; i >= 0; i--) {
89		gpio_free(IRQ_TO_GPIO(irqs[i].irq));
90	}
91	return (ret);
92}
93
94static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
95{
96	int i;
97	/* free allocated gpio's */
98	gpio_free(GPIO_PRDY);
99	for (i = 0; i < ARRAY_SIZE(irqs); i++)
100		gpio_free(IRQ_TO_GPIO(irqs[i].irq));
101}
102
103static unsigned long trizeps_pcmcia_status[2];
104
105static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
106				struct pcmcia_state *state)
107{
108	unsigned short status = 0, change;
109	status = CFSR_readw();
110	change = (status ^ trizeps_pcmcia_status[skt->nr]) &
111				ConXS_CFSR_BVD_MASK;
112	if (change) {
113		trizeps_pcmcia_status[skt->nr] = status;
114		if (status & ConXS_CFSR_BVD1) {
115			/* enable_irq empty */
116		} else {
117			/* disable_irq empty */
118		}
119	}
120
121	switch (skt->nr) {
122	case 0:
123		/* just fill in fix states */
124		state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1;
125		state->ready  = gpio_get_value(GPIO_PRDY) ? 1 : 0;
126		state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
127		state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
128		state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
129		state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
130		state->wrprot = 0;	/* not available */
131		break;
132
133#ifndef CONFIG_MACH_TRIZEPS_CONXS
134	/* on ConXS we only have one slot. Second is inactive */
135	case 1:
136		state->detect = 0;
137		state->ready  = 0;
138		state->bvd1   = 0;
139		state->bvd2   = 0;
140		state->vs_3v  = 0;
141		state->vs_Xv  = 0;
142		state->wrprot = 0;
143		break;
144
145#endif
146	}
147}
148
149static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
150				const socket_state_t *state)
151{
152	int ret = 0;
153	unsigned short power = 0;
154
155	/* we do nothing here just check a bit */
156	switch (state->Vcc) {
157	case 0:  power &= 0xfc; break;
158	case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
159	case 50:
160		pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
161		break;
162	default:
163		pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
164		ret = -1;
165	}
166
167	switch (state->Vpp) {
168	case 0:  power &= 0xf3; break;
169	case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
170	case 120:
171		pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
172		break;
173	default:
174		if (state->Vpp != state->Vcc) {
175			pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
176			ret = -1;
177		}
178	}
179
180	switch (skt->nr) {
181	case 0:			 /* we only have 3.3V */
182		board_pcmcia_power(power);
183		break;
184
185#ifndef CONFIG_MACH_TRIZEPS_CONXS
186	/* on ConXS we only have one slot. Second is inactive */
187	case 1:
188#endif
189	default:
190		break;
191	}
192
193	return ret;
194}
195
196static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
197{
198	/* default is on */
199	board_pcmcia_power(0x9);
200}
201
202static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
203{
204	board_pcmcia_power(0x0);
205}
206
207static struct pcmcia_low_level trizeps_pcmcia_ops = {
208	.owner			= THIS_MODULE,
209	.hw_init		= trizeps_pcmcia_hw_init,
210	.hw_shutdown		= trizeps_pcmcia_hw_shutdown,
211	.socket_state		= trizeps_pcmcia_socket_state,
212	.configure_socket	= trizeps_pcmcia_configure_socket,
213	.socket_init		= trizeps_pcmcia_socket_init,
214	.socket_suspend		= trizeps_pcmcia_socket_suspend,
215#ifdef CONFIG_MACH_TRIZEPS_CONXS
216	.nr			= 1,
217#else
218	.nr			= 2,
219#endif
220	.first			= 0,
221};
222
223static struct platform_device *trizeps_pcmcia_device;
224
225static int __init trizeps_pcmcia_init(void)
226{
227	int ret;
228
229	trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
230	if (!trizeps_pcmcia_device)
231		return -ENOMEM;
232
233	ret = platform_device_add_data(trizeps_pcmcia_device,
234			&trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
235
236	if (ret == 0)
237		ret = platform_device_add(trizeps_pcmcia_device);
238
239	if (ret)
240		platform_device_put(trizeps_pcmcia_device);
241
242	return ret;
243}
244
245static void __exit trizeps_pcmcia_exit(void)
246{
247	platform_device_unregister(trizeps_pcmcia_device);
248}
249
250fs_initcall(trizeps_pcmcia_init);
251module_exit(trizeps_pcmcia_exit);
252
253MODULE_LICENSE("GPL");
254MODULE_AUTHOR("Juergen Schindele");
255MODULE_ALIAS("platform:pxa2xx-pcmcia");
256