Blame view

drivers/pcmcia/pxa2xx_viper.c 5.23 KB
20f18ff32   Marc Zyngier   Add support for t...
1
  /*
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
2
   * Viper/Zeus PCMCIA support
20f18ff32   Marc Zyngier   Add support for t...
3
4
5
   *   Copyright 2004 Arcom Control Systems
   *
   * Maintained by Marc Zyngier <maz@misterjones.org>
20f18ff32   Marc Zyngier   Add support for t...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   *
   * Based on:
   *   iPAQ h2200 PCMCIA support
   *   Copyright 2004 Koen Kooi <koen@vestingbar.nl>
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file COPYING in the main directory of this archive for
   * more details.
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/interrupt.h>
  #include <linux/platform_device.h>
  #include <linux/gpio.h>
  
  #include <pcmcia/ss.h>
  
  #include <asm/irq.h>
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
27
  #include <mach/arcom-pcmcia.h>
20f18ff32   Marc Zyngier   Add support for t...
28
29
30
  
  #include "soc_common.h"
  #include "pxa2xx_base.h"
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
31
  static struct platform_device *arcom_pcmcia_dev;
20f18ff32   Marc Zyngier   Add support for t...
32
  static struct pcmcia_irqs irqs[] = {
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
33
34
35
36
  	{
  		.sock	= 0,
  		.str	= "PCMCIA_CD",
  	},
20f18ff32   Marc Zyngier   Add support for t...
37
  };
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
38
39
40
41
  static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
  {
  	return arcom_pcmcia_dev->dev.platform_data;
  }
20f18ff32   Marc Zyngier   Add support for t...
42
43
  static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  {
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
44
  	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
20f18ff32   Marc Zyngier   Add support for t...
45
  	unsigned long flags;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
46
47
  	skt->socket.pci_irq = gpio_to_irq(pdata->rdy_gpio);
  	irqs[0].irq = gpio_to_irq(pdata->cd_gpio);
20f18ff32   Marc Zyngier   Add support for t...
48

c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
49
  	if (gpio_request(pdata->cd_gpio, "CF detect"))
20f18ff32   Marc Zyngier   Add support for t...
50
  		goto err_request_cd;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
51
  	if (gpio_request(pdata->rdy_gpio, "CF ready"))
20f18ff32   Marc Zyngier   Add support for t...
52
  		goto err_request_rdy;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
53
  	if (gpio_request(pdata->pwr_gpio, "CF power"))
20f18ff32   Marc Zyngier   Add support for t...
54
55
56
  		goto err_request_pwr;
  
  	local_irq_save(flags);
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
57
58
59
  	if (gpio_direction_output(pdata->pwr_gpio, 0) ||
  	    gpio_direction_input(pdata->cd_gpio) ||
  	    gpio_direction_input(pdata->rdy_gpio)) {
20f18ff32   Marc Zyngier   Add support for t...
60
61
62
63
64
65
66
67
68
  		local_irq_restore(flags);
  		goto err_dir;
  	}
  
  	local_irq_restore(flags);
  
  	return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
  
  err_dir:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
69
  	gpio_free(pdata->pwr_gpio);
20f18ff32   Marc Zyngier   Add support for t...
70
  err_request_pwr:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
71
  	gpio_free(pdata->rdy_gpio);
20f18ff32   Marc Zyngier   Add support for t...
72
  err_request_rdy:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
73
  	gpio_free(pdata->cd_gpio);
20f18ff32   Marc Zyngier   Add support for t...
74
  err_request_cd:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
75
76
  	dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs
  ");
20f18ff32   Marc Zyngier   Add support for t...
77
78
79
80
81
82
83
84
  	return -1;
  }
  
  /*
   * Release all resources.
   */
  static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  {
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
85
  	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
20f18ff32   Marc Zyngier   Add support for t...
86
  	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
87
88
89
  	gpio_free(pdata->pwr_gpio);
  	gpio_free(pdata->rdy_gpio);
  	gpio_free(pdata->cd_gpio);
20f18ff32   Marc Zyngier   Add support for t...
90
91
92
93
94
  }
  
  static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  				      struct pcmcia_state *state)
  {
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
95
96
97
98
  	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
  
  	state->detect = !gpio_get_value(pdata->cd_gpio);
  	state->ready  = !!gpio_get_value(pdata->rdy_gpio);
20f18ff32   Marc Zyngier   Add support for t...
99
100
101
102
103
104
105
106
107
108
  	state->bvd1   = 1;
  	state->bvd2   = 1;
  	state->wrprot = 0;
  	state->vs_3v  = 1; /* Can only apply 3.3V */
  	state->vs_Xv  = 0;
  }
  
  static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  					 const socket_state_t *state)
  {
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
109
  	struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
20f18ff32   Marc Zyngier   Add support for t...
110
  	/* Silently ignore Vpp, output enable, speaker enable. */
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
111
  	pdata->reset(state->flags & SS_RESET);
20f18ff32   Marc Zyngier   Add support for t...
112
113
114
115
  
  	/* Apply socket voltage */
  	switch (state->Vcc) {
  	case 0:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
116
  		gpio_set_value(pdata->pwr_gpio, 0);
20f18ff32   Marc Zyngier   Add support for t...
117
118
  		break;
  	case 33:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
119
  		gpio_set_value(pdata->pwr_gpio, 1);
20f18ff32   Marc Zyngier   Add support for t...
120
121
  		break;
  	default:
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
122
123
  		dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d
  ", state->Vcc);
20f18ff32   Marc Zyngier   Add support for t...
124
125
126
127
128
129
130
131
132
133
134
135
136
  		return -1;
  	}
  
  	return 0;
  }
  
  static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
  {
  }
  
  static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
  {
  }
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
137
  static struct pcmcia_low_level viper_pcmcia_ops = {
20f18ff32   Marc Zyngier   Add support for t...
138
139
140
141
142
143
144
145
146
147
148
  	.owner          	= THIS_MODULE,
  	.hw_init        	= viper_pcmcia_hw_init,
  	.hw_shutdown		= viper_pcmcia_hw_shutdown,
  	.socket_state		= viper_pcmcia_socket_state,
  	.configure_socket	= viper_pcmcia_configure_socket,
  	.socket_init		= viper_pcmcia_socket_init,
  	.socket_suspend		= viper_pcmcia_socket_suspend,
  	.nr         		= 1,
  };
  
  static struct platform_device *viper_pcmcia_device;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
149
  static int viper_pcmcia_probe(struct platform_device *pdev)
20f18ff32   Marc Zyngier   Add support for t...
150
151
  {
  	int ret;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
152
153
154
155
156
157
  	/* I can't imagine more than one device, but you never know... */
  	if (arcom_pcmcia_dev)
  		return -EEXIST;
  
  	if (!pdev->dev.platform_data)
  		return -EINVAL;
20f18ff32   Marc Zyngier   Add support for t...
158
159
160
161
  
  	viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
  	if (!viper_pcmcia_device)
  		return -ENOMEM;
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
162
163
164
  	arcom_pcmcia_dev = pdev;
  
  	viper_pcmcia_device->dev.parent = &pdev->dev;
20f18ff32   Marc Zyngier   Add support for t...
165
166
167
168
169
170
  	ret = platform_device_add_data(viper_pcmcia_device,
  				       &viper_pcmcia_ops,
  				       sizeof(viper_pcmcia_ops));
  
  	if (!ret)
  		ret = platform_device_add(viper_pcmcia_device);
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
171
  	if (ret) {
20f18ff32   Marc Zyngier   Add support for t...
172
  		platform_device_put(viper_pcmcia_device);
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
173
174
  		arcom_pcmcia_dev = NULL;
  	}
20f18ff32   Marc Zyngier   Add support for t...
175
176
177
  
  	return ret;
  }
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
178
  static int viper_pcmcia_remove(struct platform_device *pdev)
20f18ff32   Marc Zyngier   Add support for t...
179
180
  {
  	platform_device_unregister(viper_pcmcia_device);
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	arcom_pcmcia_dev = NULL;
  	return 0;
  }
  
  static struct platform_device_id viper_pcmcia_id_table[] = {
  	{ .name = "viper-pcmcia", },
  	{ .name = "zeus-pcmcia",  },
  	{ },
  };
  
  static struct platform_driver viper_pcmcia_driver = {
  	.probe		= viper_pcmcia_probe,
  	.remove		= viper_pcmcia_remove,
  	.driver		= {
  		.name	= "arcom-pcmcia",
  		.owner	= THIS_MODULE,
  	},
  	.id_table	= viper_pcmcia_id_table,
  };
  
  static int __init viper_pcmcia_init(void)
  {
  	return platform_driver_register(&viper_pcmcia_driver);
  }
  
  static void __exit viper_pcmcia_exit(void)
  {
  	return platform_driver_unregister(&viper_pcmcia_driver);
20f18ff32   Marc Zyngier   Add support for t...
209
210
211
212
  }
  
  module_init(viper_pcmcia_init);
  module_exit(viper_pcmcia_exit);
c2de1c382   Marc Zyngier   [ARM] pxa/zeus: m...
213
  MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
20f18ff32   Marc Zyngier   Add support for t...
214
  MODULE_LICENSE("GPL");