1960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut/*
2960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * linux/drivers/pcmcia/pxa2xx_colibri.c
3960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut *
4960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * Driver for Toradex Colibri PXA270 CF socket
5960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut *
6960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
7960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut *
8960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * This program is free software; you can redistribute it and/or modify
9960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * it under the terms of the GNU General Public License version 2 as
10960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut * published by the Free Software Foundation.
11960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut *
12960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut */
13960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
14960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include <linux/module.h>
15960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include <linux/platform_device.h>
16960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include <linux/delay.h>
17960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include <linux/gpio.h>
18960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
19960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include <asm/mach-types.h>
20960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
21960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#include "soc_common.h"
22960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
23960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_RESET_GPIO	53
24960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_PPEN_GPIO	107
25960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_BVD1_GPIO	83
26960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_BVD2_GPIO	82
27960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_DETECT_GPIO	84
28960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut#define	COLIBRI270_READY_GPIO	1
29960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
30fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_RESET_GPIO	77
31fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_PPEN_GPIO	57
32fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_BVD1_GPIO	53
33fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_BVD2_GPIO	79
34fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_DETECT_GPIO	81
35fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut#define	COLIBRI320_READY_GPIO	29
36fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut
37e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasutenum {
38e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	DETECT = 0,
39e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	READY = 1,
40e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	BVD1 = 2,
41e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	BVD2 = 3,
42e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	PPEN = 4,
43e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	RESET = 5,
44e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut};
45e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut
46e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut/* Contents of this array are configured on-the-fly in init function */
47e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasutstatic struct gpio colibri_pcmcia_gpios[] = {
48e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_IN,	"PCMCIA Detect" },
49e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_IN,	"PCMCIA Ready" },
50e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_IN,	"PCMCIA BVD1" },
51e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_IN,	"PCMCIA BVD2" },
52e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_INIT_LOW,	"PCMCIA PPEN" },
53e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	{ 0,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
54e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut};
55960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
56960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
57960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
58960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	int ret;
59960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
60e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	ret = gpio_request_array(colibri_pcmcia_gpios,
61e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut				ARRAY_SIZE(colibri_pcmcia_gpios));
62960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	if (ret)
63960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut		goto err1;
64960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
65e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio);
66a9bb5a4bf9f84256499c802fd397d56d55227e4fRussell King	skt->stat[SOC_STAT_CD].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
67a9bb5a4bf9f84256499c802fd397d56d55227e4fRussell King	skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
68960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
69960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasuterr1:
70960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	return ret;
71960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
72960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
73960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
74960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
75e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	gpio_free_array(colibri_pcmcia_gpios,
76e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut			ARRAY_SIZE(colibri_pcmcia_gpios));
77960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
78960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
79960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
80960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut					struct pcmcia_state *state)
81960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
82960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
83e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	state->detect = !!gpio_get_value(colibri_pcmcia_gpios[DETECT].gpio);
84e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	state->ready  = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio);
85e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	state->bvd1   = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio);
86e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	state->bvd2   = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio);
87960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	state->vs_3v  = 1;
88960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	state->vs_Xv  = 0;
89960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
90960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
91960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic int
92960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutcolibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
93960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut				const socket_state_t *state)
94960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
95e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	gpio_set_value(colibri_pcmcia_gpios[PPEN].gpio,
96960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut			!(state->Vcc == 33 && state->Vpp < 50));
97e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut	gpio_set_value(colibri_pcmcia_gpios[RESET].gpio,
98e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut			state->flags & SS_RESET);
99960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	return 0;
100960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
101960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
102960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic struct pcmcia_low_level colibri_pcmcia_ops = {
103960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.owner			= THIS_MODULE,
104960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
105960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.first			= 0,
106960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.nr			= 1,
107960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
108960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.hw_init		= colibri_pcmcia_hw_init,
109960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.hw_shutdown		= colibri_pcmcia_hw_shutdown,
110960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
111960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.socket_state		= colibri_pcmcia_socket_state,
112960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	.configure_socket	= colibri_pcmcia_configure_socket,
113960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut};
114960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
115960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic struct platform_device *colibri_pcmcia_device;
116960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
117960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic int __init colibri_pcmcia_init(void)
118960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
119960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	int ret;
120960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
1218d9bd9002dc8c3a05e11c5f40d95d06e15e83f71Dmitry Eremin-Solenikov	if (!machine_is_colibri() && !machine_is_colibri320())
1228d9bd9002dc8c3a05e11c5f40d95d06e15e83f71Dmitry Eremin-Solenikov		return -ENODEV;
1238d9bd9002dc8c3a05e11c5f40d95d06e15e83f71Dmitry Eremin-Solenikov
124960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
125960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	if (!colibri_pcmcia_device)
126960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut		return -ENOMEM;
127960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
128960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	/* Colibri PXA270 */
129960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	if (machine_is_colibri()) {
130e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[RESET].gpio	= COLIBRI270_RESET_GPIO;
131e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[PPEN].gpio		= COLIBRI270_PPEN_GPIO;
132e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[BVD1].gpio		= COLIBRI270_BVD1_GPIO;
133e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[BVD2].gpio		= COLIBRI270_BVD2_GPIO;
134e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[DETECT].gpio	= COLIBRI270_DETECT_GPIO;
135e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[READY].gpio	= COLIBRI270_READY_GPIO;
136fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut	/* Colibri PXA320 */
137fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek Vasut	} else if (machine_is_colibri320()) {
138e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[RESET].gpio	= COLIBRI320_RESET_GPIO;
139e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[PPEN].gpio		= COLIBRI320_PPEN_GPIO;
140e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[BVD1].gpio		= COLIBRI320_BVD1_GPIO;
141e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[BVD2].gpio		= COLIBRI320_BVD2_GPIO;
142e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[DETECT].gpio	= COLIBRI320_DETECT_GPIO;
143e593106ca409e5e37d18121d922fc4f449c60d41Marek Vasut		colibri_pcmcia_gpios[READY].gpio	= COLIBRI320_READY_GPIO;
144960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	}
145960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
146960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	ret = platform_device_add_data(colibri_pcmcia_device,
147960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut		&colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops));
148960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
149960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	if (!ret)
150960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut		ret = platform_device_add(colibri_pcmcia_device);
151960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
152960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	if (ret)
153960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut		platform_device_put(colibri_pcmcia_device);
154960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
155960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	return ret;
156960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
157960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
158960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutstatic void __exit colibri_pcmcia_exit(void)
159960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut{
160960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut	platform_device_unregister(colibri_pcmcia_device);
161960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut}
162960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
163960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutmodule_init(colibri_pcmcia_init);
164960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasutmodule_exit(colibri_pcmcia_exit);
165960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek Vasut
166960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek VasutMODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
167fd62999bad9fc3b176ef6bc9d2a71be940efd908Marek VasutMODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320");
168960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek VasutMODULE_ALIAS("platform:pxa2xx-pcmcia");
169960c0acaabf603e39b121ae5c0580aaca6f8aa7bMarek VasutMODULE_LICENSE("GPL");
170