Blame view

drivers/pcmcia/sa1100_h3600.c 5.79 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   * drivers/pcmcia/sa1100_h3600.c
   *
   * PCMCIA implementation routines for H3600
   *
   */
  #include <linux/module.h>
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/device.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
  #include <linux/delay.h>
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
13
  #include <linux/gpio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

a09e64fbc   Russell King   [ARM] Move includ...
15
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <asm/irq.h>
  #include <asm/mach-types.h>
8715b29db   Dmitry Artamonow   ARM: 5819/1: SA11...
18
  #include <mach/h3xxx.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  
  #include "sa1100_generic.h"
  
  static struct pcmcia_irqs irqs[] = {
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
23
24
  	{ .sock = 0, .str = "PCMCIA CD0" }, /* .irq will be filled later */
  	{ .sock = 1, .str = "PCMCIA CD1" }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  };
  
  static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  {
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
29
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  	switch (skt->nr) {
  	case 0:
  		err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ0, "PCMCIA IRQ0");
  		if (err)
  			goto err00;
  		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ0);
  		if (err)
  			goto err01;
  		skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ0);
  
  		err = gpio_request(H3XXX_GPIO_PCMCIA_CD0, "PCMCIA CD0");
  		if (err)
  			goto err01;
  		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD0);
  		if (err)
  			goto err02;
  		irqs[0].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD0);
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
48
  		err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON");
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
49
50
  		if (err)
  			goto err02;
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  		err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
  		if (err)
  			goto err03;
  		err = gpio_request(H3XXX_EGPIO_OPT_ON, "OPT ON");
  		if (err)
  			goto err03;
  		err = gpio_direction_output(H3XXX_EGPIO_OPT_ON, 0);
  		if (err)
  			goto err04;
  		err = gpio_request(H3XXX_EGPIO_OPT_RESET, "OPT RESET");
  		if (err)
  			goto err04;
  		err = gpio_direction_output(H3XXX_EGPIO_OPT_RESET, 0);
  		if (err)
  			goto err05;
  		err = gpio_request(H3XXX_EGPIO_CARD_RESET, "PCMCIA CARD RESET");
  		if (err)
  			goto err05;
  		err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0);
  		if (err)
  			goto err06;
  		err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
  		if (err)
  			goto err06;
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  		break;
  	case 1:
  		err = gpio_request(H3XXX_GPIO_PCMCIA_IRQ1, "PCMCIA IRQ1");
  		if (err)
  			goto err10;
  		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_IRQ1);
  		if (err)
  			goto err11;
  		skt->socket.pci_irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_IRQ1);
  
  		err = gpio_request(H3XXX_GPIO_PCMCIA_CD1, "PCMCIA CD1");
  		if (err)
  			goto err11;
  		err = gpio_direction_input(H3XXX_GPIO_PCMCIA_CD1);
  		if (err)
  			goto err12;
  		irqs[1].irq = gpio_to_irq(H3XXX_GPIO_PCMCIA_CD1);
  
  		err = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
  		if (err)
  			goto err12;
  		break;
  	}
  	return 0;
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
99
100
101
102
  err06:	gpio_free(H3XXX_EGPIO_CARD_RESET);
  err05:	gpio_free(H3XXX_EGPIO_OPT_RESET);
  err04:	gpio_free(H3XXX_EGPIO_OPT_ON);
  err03:	gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
103
104
105
  err02:	gpio_free(H3XXX_GPIO_PCMCIA_CD0);
  err01:	gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
  err00:	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
107
108
109
  err12:	gpio_free(H3XXX_GPIO_PCMCIA_CD0);
  err11:	gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
  err10:	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
  }
  
  static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  {
  	soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
    
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
116
117
  	switch (skt->nr) {
  	case 0:
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
118
119
120
121
122
123
124
125
126
  		/* Disable CF bus: */
  		gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
  		gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
  		gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
  
  		gpio_free(H3XXX_EGPIO_CARD_RESET);
  		gpio_free(H3XXX_EGPIO_OPT_RESET);
  		gpio_free(H3XXX_EGPIO_OPT_ON);
  		gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON);
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
127
128
129
130
131
132
133
134
  		gpio_free(H3XXX_GPIO_PCMCIA_CD0);
  		gpio_free(H3XXX_GPIO_PCMCIA_IRQ0);
  		break;
  	case 1:
  		gpio_free(H3XXX_GPIO_PCMCIA_CD1);
  		gpio_free(H3XXX_GPIO_PCMCIA_IRQ1);
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
  }
  
  static void
  h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	switch (skt->nr) {
  	case 0:
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
142
143
  		state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD0);
  		state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
150
151
  		state->bvd1 = 0;
  		state->bvd2 = 0;
  		state->wrprot = 0; /* Not available on H3600. */
  		state->vs_3v = 0;
  		state->vs_Xv = 0;
  		break;
  
  	case 1:
2a8370919   Dmitry Artamonow   ARM: 5811/2: pcmc...
152
153
  		state->detect = !gpio_get_value(H3XXX_GPIO_PCMCIA_CD1);
  		state->ready = !!gpio_get_value(H3XXX_GPIO_PCMCIA_IRQ1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  		state->bvd1 = 0;
  		state->bvd2 = 0;
  		state->wrprot = 0; /* Not available on H3600. */
  		state->vs_3v = 0;
  		state->vs_Xv = 0;
  		break;
  	}
  }
  
  static int
  h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
  {
  	if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) {
  		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV
  ",
  		       state->Vcc / 10, state->Vcc % 10);
  		return -1;
  	}
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
172
  	gpio_set_value(H3XXX_EGPIO_CARD_RESET, !!(state->flags & SS_RESET));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
  
  	/* Silently ignore Vpp, output enable, speaker enable. */
  
  	return 0;
  }
  
  static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
  {
  	/* Enable CF bus: */
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
182
183
184
  	gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 1);
  	gpio_set_value(H3XXX_EGPIO_OPT_ON, 1);
  	gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  
  	msleep(10);
  
  	soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
  }
  
  static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
  {
  	soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
  
  	/*
  	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
  	 * the generic PCMCIA layer to deal with the idea of two sockets
  	 * on one bus.  We rely on the cs.c behaviour shutting down
  	 * socket 0 then socket 1.
  	 */
  	if (skt->nr == 1) {
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
202
203
  		gpio_set_value(H3XXX_EGPIO_OPT_ON, 0);
  		gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  		/* hmm, does this suck power? */
22f974055   Dmitry Artamonow   ARM: 5814/1: SA11...
205
  		gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
210
211
212
213
214
215
216
217
218
  	}
  }
  
  struct pcmcia_low_level h3600_pcmcia_ops = { 
  	.owner			= THIS_MODULE,
  	.hw_init		= h3600_pcmcia_hw_init,
  	.hw_shutdown		= h3600_pcmcia_hw_shutdown,
  	.socket_state		= h3600_pcmcia_socket_state,
  	.configure_socket	= h3600_pcmcia_configure_socket,
  
  	.socket_init		= h3600_pcmcia_socket_init,
  	.socket_suspend		= h3600_pcmcia_socket_suspend,
  };
5b85e04e9   Uwe Kleine-König   pcmcia/sa1100: do...
219
  int __devinit pcmcia_h3600_init(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  {
  	int ret = -ENODEV;
e7435f866   Dmitry Artamonow   ARM: 5824/1: SA11...
222
  	if (machine_is_h3600() || machine_is_h3100())
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
  		ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2);
  
  	return ret;
  }