Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v6.13.7.
  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	default:
 59		break;
 60	}
 61	/* release the reset of this card */
 62	pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
 63
 64	/* supplementory irqs for the socket */
 65	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
 66		if (irqs[i].sock != skt->nr)
 67			continue;
 68		if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) {
 69			pr_err("%s: sock %d unable to request gpio %d\n",
 70				__func__, skt->nr, irq_to_gpio(irqs[i].irq));
 71			ret = -EBUSY;
 72			goto error;
 73		}
 74		if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) {
 75			pr_err("%s: sock %d unable to set input gpio %d\n",
 76				__func__, skt->nr, irq_to_gpio(irqs[i].irq));
 77			ret = -EINVAL;
 78			goto error;
 79		}
 80	}
 81	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
 82
 83error:
 84	for (; i >= 0; i--) {
 85		gpio_free(irq_to_gpio(irqs[i].irq));
 86	}
 87	return (ret);
 88}
 89
 90static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 91{
 92	int i;
 93	/* free allocated gpio's */
 94	gpio_free(GPIO_PRDY);
 95	for (i = 0; i < ARRAY_SIZE(irqs); i++)
 96		gpio_free(irq_to_gpio(irqs[i].irq));
 97}
 98
 99static unsigned long trizeps_pcmcia_status[2];
100
101static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
102				struct pcmcia_state *state)
103{
104	unsigned short status = 0, change;
105	status = CFSR_readw();
106	change = (status ^ trizeps_pcmcia_status[skt->nr]) &
107				ConXS_CFSR_BVD_MASK;
108	if (change) {
109		trizeps_pcmcia_status[skt->nr] = status;
110		if (status & ConXS_CFSR_BVD1) {
111			/* enable_irq empty */
112		} else {
113			/* disable_irq empty */
114		}
115	}
116
117	switch (skt->nr) {
118	case 0:
119		/* just fill in fix states */
120		state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1;
121		state->ready  = gpio_get_value(GPIO_PRDY) ? 1 : 0;
122		state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
123		state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
124		state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
125		state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
126		state->wrprot = 0;	/* not available */
127		break;
128
129#ifndef CONFIG_MACH_TRIZEPS_CONXS
130	/* on ConXS we only have one slot. Second is inactive */
131	case 1:
132		state->detect = 0;
133		state->ready  = 0;
134		state->bvd1   = 0;
135		state->bvd2   = 0;
136		state->vs_3v  = 0;
137		state->vs_Xv  = 0;
138		state->wrprot = 0;
139		break;
140
141#endif
142	}
143}
144
145static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
146				const socket_state_t *state)
147{
148	int ret = 0;
149	unsigned short power = 0;
150
151	/* we do nothing here just check a bit */
152	switch (state->Vcc) {
153	case 0:  power &= 0xfc; break;
154	case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
155	case 50:
156		pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
157		break;
158	default:
159		pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
160		ret = -1;
161	}
162
163	switch (state->Vpp) {
164	case 0:  power &= 0xf3; break;
165	case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
166	case 120:
167		pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
168		break;
169	default:
170		if (state->Vpp != state->Vcc) {
171			pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
172			ret = -1;
173		}
174	}
175
176	switch (skt->nr) {
177	case 0:			 /* we only have 3.3V */
178		board_pcmcia_power(power);
179		break;
180
181#ifndef CONFIG_MACH_TRIZEPS_CONXS
182	/* on ConXS we only have one slot. Second is inactive */
183	case 1:
184#endif
185	default:
186		break;
187	}
188
189	return ret;
190}
191
192static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
193{
194	/* default is on */
195	board_pcmcia_power(0x9);
196}
197
198static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
199{
200	board_pcmcia_power(0x0);
201}
202
203static struct pcmcia_low_level trizeps_pcmcia_ops = {
204	.owner			= THIS_MODULE,
205	.hw_init		= trizeps_pcmcia_hw_init,
206	.hw_shutdown		= trizeps_pcmcia_hw_shutdown,
207	.socket_state		= trizeps_pcmcia_socket_state,
208	.configure_socket	= trizeps_pcmcia_configure_socket,
209	.socket_init		= trizeps_pcmcia_socket_init,
210	.socket_suspend		= trizeps_pcmcia_socket_suspend,
211#ifdef CONFIG_MACH_TRIZEPS_CONXS
212	.nr			= 1,
213#else
214	.nr			= 2,
215#endif
216	.first			= 0,
217};
218
219static struct platform_device *trizeps_pcmcia_device;
220
221static int __init trizeps_pcmcia_init(void)
222{
223	int ret;
224
225	if (!machine_is_trizeps4() && !machine_is_trizeps4wl())
226		return -ENODEV;
227
228	trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
229	if (!trizeps_pcmcia_device)
230		return -ENOMEM;
231
232	ret = platform_device_add_data(trizeps_pcmcia_device,
233			&trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
234
235	if (ret == 0)
236		ret = platform_device_add(trizeps_pcmcia_device);
237
238	if (ret)
239		platform_device_put(trizeps_pcmcia_device);
240
241	return ret;
242}
243
244static void __exit trizeps_pcmcia_exit(void)
245{
246	platform_device_unregister(trizeps_pcmcia_device);
247}
248
249fs_initcall(trizeps_pcmcia_init);
250module_exit(trizeps_pcmcia_exit);
251
252MODULE_LICENSE("GPL");
253MODULE_AUTHOR("Juergen Schindele");
254MODULE_ALIAS("platform:pxa2xx-pcmcia");