Blame view

drivers/pcmcia/soc_common.c 23.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  /*======================================================================
  
      Common support code for the PCMCIA control functionality of
      integrated SOCs like the SA-11x0 and PXA2xx microprocessors.
  
      The contents of this file are subject to the Mozilla Public
      License Version 1.1 (the "License"); you may not use this file
      except in compliance with the License. You may obtain a copy of
      the License at http://www.mozilla.org/MPL/
  
      Software distributed under the License is distributed on an "AS
      IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
      implied. See the License for the specific language governing
      rights and limitations under the License.
  
      The initial developer of the original code is John G. Dorsey
      <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
      Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
  
      Alternatively, the contents of this file may be used under the
      terms of the GNU Public License version 2 (the "GPL"), in which
      case the provisions of the GPL are applicable instead of the
      above.  If you wish to allow the use of your version of this file
      only under the terms of the GPL and not to allow others to use
      your version of this file under the MPL, indicate your decision
      by deleting the provisions above and replace them with the notice
      and other provisions required by the GPL.  If you do not delete
      the provisions above, a recipient may use your version of this
      file under either the MPL or the GPL.
  
  ======================================================================*/
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
32
  #include <linux/cpufreq.h>
d9dc87876   Russell King   PCMCIA: soc_commo...
33
  #include <linux/gpio.h>
45ca7536d   Russell King   pcmcia: soc_commo...
34
  #include <linux/gpio/consumer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #include <linux/init.h>
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
36
37
38
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/irq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include <linux/mm.h>
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
41
42
  #include <linux/module.h>
  #include <linux/moduleparam.h>
23d077e28   Andrew Morton   drivers/pcmcia/so...
43
  #include <linux/mutex.h>
ac61b6001   Russell King   pcmcia: soc_commo...
44
  #include <linux/regulator/consumer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #include <linux/spinlock.h>
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
46
  #include <linux/timer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

a09e64fbc   Russell King   [ARM] Move includ...
48
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
  
  #include "soc_common.h"
d9dc87876   Russell King   PCMCIA: soc_commo...
51
  static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
7d16b658b   Dominik Brodowski   pcmcia: don't add...
52
  #ifdef CONFIG_PCMCIA_DEBUG
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
59
  
  static int pc_debug;
  module_param(pc_debug, int, 0644);
  
  void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
  		      int lvl, const char *fmt, ...)
  {
106665d93   Joe Perches   drivers/pcmcia/so...
60
  	struct va_format vaf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  	va_list args;
  	if (pc_debug > lvl) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  		va_start(args, fmt);
106665d93   Joe Perches   drivers/pcmcia/so...
64
65
66
67
68
  
  		vaf.fmt = fmt;
  		vaf.va = &args;
  
  		printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
  		va_end(args);
  	}
  }
b9f515e3e   Marcelo Roberto Jimenez   ARM: 6456/1: Fix ...
72
  EXPORT_SYMBOL(soc_pcmcia_debug);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  
  #endif
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
75
76
  #define to_soc_pcmcia_socket(x)	\
  	container_of(x, struct soc_pcmcia_socket, socket)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

ac61b6001   Russell King   pcmcia: soc_commo...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
  	struct soc_pcmcia_regulator *r, int v)
  {
  	bool on;
  	int ret;
  
  	if (!r->reg)
  		return 0;
  
  	on = v != 0;
  	if (r->on == on)
  		return 0;
  
  	if (on) {
  		ret = regulator_set_voltage(r->reg, v * 100000, v * 100000);
  		if (ret) {
  			int vout = regulator_get_voltage(r->reg) / 100000;
  
  			dev_warn(&skt->socket.dev,
  				 "CS requested %s=%u.%uV, applying %u.%uV
  ",
  				 r == &skt->vcc ? "Vcc" : "Vpp",
  				 v / 10, v % 10, vout / 10, vout % 10);
  		}
  
  		ret = regulator_enable(r->reg);
  	} else {
75ed26878   Arnd Bergmann   pcmcia: fix retur...
105
  		ret = regulator_disable(r->reg);
ac61b6001   Russell King   pcmcia: soc_commo...
106
107
108
109
110
111
112
  	}
  	if (ret == 0)
  		r->on = on;
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(soc_pcmcia_regulator_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  static unsigned short
  calc_speed(unsigned short *spds, int num, unsigned short dflt)
  {
  	unsigned short speed = 0;
  	int i;
  
  	for (i = 0; i < num; i++)
  		if (speed < spds[i])
  			speed = spds[i];
  	if (speed == 0)
  		speed = dflt;
  
  	return speed;
  }
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
127
128
  void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
  	struct soc_pcmcia_timing *timing)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  {
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
130
131
132
133
134
135
  	timing->io =
  		calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
  	timing->mem =
  		calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
  	timing->attr =
  		calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  }
  EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
d9dc87876   Russell King   PCMCIA: soc_commo...
138
139
140
141
  static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
  	unsigned int nr)
  {
  	unsigned int i;
59ecfefad   Russell King   pcmcia: soc_commo...
142
  	for (i = 0; i < nr; i++)
d9dc87876   Russell King   PCMCIA: soc_commo...
143
144
  		if (skt->stat[i].irq)
  			free_irq(skt->stat[i].irq, skt);
d9dc87876   Russell King   PCMCIA: soc_commo...
145
146
147
  
  	if (skt->ops->hw_shutdown)
  		skt->ops->hw_shutdown(skt);
0821c3bc5   Dmitry Eremin-Solenikov   ARM: 8245/1: pcmc...
148
149
  
  	clk_disable_unprepare(skt->clk);
d9dc87876   Russell King   PCMCIA: soc_commo...
150
151
152
153
154
155
  }
  
  static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  {
  	__soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
  }
45ca7536d   Russell King   pcmcia: soc_commo...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
  {
  	struct device *dev = skt->socket.dev.parent;
  	struct gpio_desc *desc;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
  		if (!skt->stat[i].name)
  			continue;
  
  		desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN);
  		if (IS_ERR(desc)) {
  			dev_err(dev, "Failed to get GPIO for %s: %ld
  ",
  				skt->stat[i].name, PTR_ERR(desc));
  			return PTR_ERR(desc);
  		}
  
  		skt->stat[i].desc = desc;
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
d9dc87876   Russell King   PCMCIA: soc_commo...
180
181
182
  static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  {
  	int ret = 0, i;
d3fdd7012   Arvind Yadav   pcmcia: soc_commo...
183
184
185
  	ret = clk_prepare_enable(skt->clk);
  	if (ret)
  		return ret;
0821c3bc5   Dmitry Eremin-Solenikov   ARM: 8245/1: pcmc...
186

d9dc87876   Russell King   PCMCIA: soc_commo...
187
188
  	if (skt->ops->hw_init) {
  		ret = skt->ops->hw_init(skt);
d3fdd7012   Arvind Yadav   pcmcia: soc_commo...
189
190
  		if (ret) {
  			clk_disable_unprepare(skt->clk);
d9dc87876   Russell King   PCMCIA: soc_commo...
191
  			return ret;
d3fdd7012   Arvind Yadav   pcmcia: soc_commo...
192
  		}
d9dc87876   Russell King   PCMCIA: soc_commo...
193
194
195
196
  	}
  
  	for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
  		if (gpio_is_valid(skt->stat[i].gpio)) {
7bfe49785   Russell King   pcmcia: soc_commo...
197
198
199
200
201
  			unsigned long flags = GPIOF_IN;
  
  			/* CD is active low by default */
  			if (i == SOC_STAT_CD)
  				flags |= GPIOF_ACTIVE_LOW;
59ecfefad   Russell King   pcmcia: soc_commo...
202
  			ret = devm_gpio_request_one(skt->socket.dev.parent,
7bfe49785   Russell King   pcmcia: soc_commo...
203
  						    skt->stat[i].gpio, flags,
59ecfefad   Russell King   pcmcia: soc_commo...
204
  						    skt->stat[i].name);
d9dc87876   Russell King   PCMCIA: soc_commo...
205
206
207
208
  			if (ret) {
  				__soc_pcmcia_hw_shutdown(skt, i);
  				return ret;
  			}
45ca7536d   Russell King   pcmcia: soc_commo...
209
210
  			skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
  		}
5805271d9   Russell King   pcmcia: soc_commo...
211
  		if (i < SOC_STAT_VS1 && skt->stat[i].desc) {
45ca7536d   Russell King   pcmcia: soc_commo...
212
  			int irq = gpiod_to_irq(skt->stat[i].desc);
d9dc87876   Russell King   PCMCIA: soc_commo...
213

a49411912   Russell King   pcmcia: soc_commo...
214
215
216
217
218
219
  			if (irq > 0) {
  				if (i == SOC_STAT_RDY)
  					skt->socket.pci_irq = irq;
  				else
  					skt->stat[i].irq = irq;
  			}
d9dc87876   Russell King   PCMCIA: soc_commo...
220
221
222
223
224
225
226
227
  		}
  
  		if (skt->stat[i].irq) {
  			ret = request_irq(skt->stat[i].irq,
  					  soc_common_pcmcia_interrupt,
  					  IRQF_TRIGGER_NONE,
  					  skt->stat[i].name, skt);
  			if (ret) {
d9dc87876   Russell King   PCMCIA: soc_commo...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  				__soc_pcmcia_hw_shutdown(skt, i);
  				return ret;
  			}
  		}
  	}
  
  	return ret;
  }
  
  static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
  		if (skt->stat[i].irq) {
  			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
  			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
  		}
  }
  
  static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
  		if (skt->stat[i].irq)
  			irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
  }
a1d050026   Russell King   pcmcia: soc_commo...
256
257
258
259
260
261
262
263
264
265
266
  /*
   * The CF 3.0 specification says that cards tie VS1 to ground and leave
   * VS2 open.  Many implementations do not wire up the VS signals, so we
   * provide hard-coded values as per the CF 3.0 spec.
   */
  void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
  	struct pcmcia_state *state)
  {
  	state->vs_3v = 1;
  }
  EXPORT_SYMBOL_GPL(soc_common_cf_socket_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
  static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
  {
  	struct pcmcia_state state;
  	unsigned int stat;
  
  	memset(&state, 0, sizeof(struct pcmcia_state));
d9dc87876   Russell King   PCMCIA: soc_commo...
273
274
275
  	/* Make battery voltage state report 'good' */
  	state.bvd1 = 1;
  	state.bvd2 = 1;
45ca7536d   Russell King   pcmcia: soc_commo...
276
  	if (skt->stat[SOC_STAT_CD].desc)
7bfe49785   Russell King   pcmcia: soc_commo...
277
  		state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc);
45ca7536d   Russell King   pcmcia: soc_commo...
278
279
280
281
282
283
  	if (skt->stat[SOC_STAT_RDY].desc)
  		state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
  	if (skt->stat[SOC_STAT_BVD1].desc)
  		state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
  	if (skt->stat[SOC_STAT_BVD2].desc)
  		state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
5805271d9   Russell King   pcmcia: soc_commo...
284
285
286
287
  	if (skt->stat[SOC_STAT_VS1].desc)
  		state.vs_3v = !!gpiod_get_value(skt->stat[SOC_STAT_VS1].desc);
  	if (skt->stat[SOC_STAT_VS2].desc)
  		state.vs_Xv = !!gpiod_get_value(skt->stat[SOC_STAT_VS2].desc);
d9dc87876   Russell King   PCMCIA: soc_commo...
288

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  	skt->ops->socket_state(skt, &state);
  
  	stat = state.detect  ? SS_DETECT : 0;
  	stat |= state.ready  ? SS_READY  : 0;
  	stat |= state.wrprot ? SS_WRPROT : 0;
  	stat |= state.vs_3v  ? SS_3VCARD : 0;
  	stat |= state.vs_Xv  ? SS_XVCARD : 0;
  
  	/* The power status of individual sockets is not available
  	 * explicitly from the hardware, so we just remember the state
  	 * and regurgitate it upon request:
  	 */
  	stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
  
  	if (skt->cs_state.flags & SS_IOCARD)
a466ebd2f   Russell King   pcmcia: soc_commo...
304
  		stat |= state.bvd1 ? 0 : SS_STSCHG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  	else {
  		if (state.bvd1 == 0)
  			stat |= SS_BATDEAD;
  		else if (state.bvd2 == 0)
  			stat |= SS_BATWARN;
  	}
  	return stat;
  }
  
  /*
   * soc_common_pcmcia_config_skt
   * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   *
   * Convert PCMCIA socket state to our socket configure structure.
   */
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
320
321
  static int soc_common_pcmcia_config_skt(
  	struct soc_pcmcia_socket *skt, socket_state_t *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
  {
  	int ret;
  
  	ret = skt->ops->configure_socket(skt, state);
6ac95d821   Russell King   pcmcia: soc_commo...
326
327
328
329
330
331
332
333
  	if (ret < 0) {
  		pr_err("soc_common_pcmcia: unable to configure socket %d
  ",
  		       skt->nr);
  		/* restore the previous state */
  		WARN_ON(skt->ops->configure_socket(skt, &skt->cs_state));
  		return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  	if (ret == 0) {
535e0abc0   Russell King   pcmcia: soc_commo...
335
  		struct gpio_desc *descs[2];
b9762bebc   Janusz Krzysztofik   gpiolib: Pass bit...
336
337
  		DECLARE_BITMAP(values, 2);
  		int n = 0;
535e0abc0   Russell King   pcmcia: soc_commo...
338
339
340
  
  		if (skt->gpio_reset) {
  			descs[n] = skt->gpio_reset;
b9762bebc   Janusz Krzysztofik   gpiolib: Pass bit...
341
  			__assign_bit(n++, values, state->flags & SS_RESET);
535e0abc0   Russell King   pcmcia: soc_commo...
342
343
344
  		}
  		if (skt->gpio_bus_enable) {
  			descs[n] = skt->gpio_bus_enable;
b9762bebc   Janusz Krzysztofik   gpiolib: Pass bit...
345
  			__assign_bit(n++, values, state->flags & SS_OUTPUT_ENA);
535e0abc0   Russell King   pcmcia: soc_commo...
346
347
348
  		}
  
  		if (n)
77588c14a   Janusz Krzysztofik   gpiolib: Pass arr...
349
  			gpiod_set_array_value_cansleep(n, descs, NULL, values);
535e0abc0   Russell King   pcmcia: soc_commo...
350

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
355
356
  		/*
  		 * This really needs a better solution.  The IRQ
  		 * may or may not be claimed by the driver.
  		 */
  		if (skt->irq_state != 1 && state->io_irq) {
  			skt->irq_state = 1;
dced35aeb   Thomas Gleixner   drivers: Final ir...
357
358
  			irq_set_irq_type(skt->socket.pci_irq,
  					 IRQ_TYPE_EDGE_FALLING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  		} else if (skt->irq_state == 1 && state->io_irq == 0) {
  			skt->irq_state = 0;
dced35aeb   Thomas Gleixner   drivers: Final ir...
361
  			irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
  		}
  
  		skt->cs_state = *state;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	return ret;
  }
  
  /* soc_common_pcmcia_sock_init()
   * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   *
   * (Re-)Initialise the socket, turning on status interrupts
   * and PCMCIA bus.  This must wait for power to stabilise
   * so that the card status signals report correctly.
   *
   * Returns: 0
   */
  static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
  
  	debug(skt, 2, "initializing socket
  ");
a747ce835   Jonathan Cameron   drivers:pcmcia:so...
384
385
  	if (skt->ops->socket_init)
  		skt->ops->socket_init(skt);
d9dc87876   Russell King   PCMCIA: soc_commo...
386
  	soc_pcmcia_hw_enable(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  	return 0;
  }
  
  
  /*
   * soc_common_pcmcia_suspend()
   * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   *
   * Remove power on the socket, disable IRQs from the card.
   * Turn off status interrupts, and disable the PCMCIA bus.
   *
   * Returns: 0
   */
  static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
  
  	debug(skt, 2, "suspending socket
  ");
d9dc87876   Russell King   PCMCIA: soc_commo...
406
  	soc_pcmcia_hw_disable(skt);
a747ce835   Jonathan Cameron   drivers:pcmcia:so...
407
408
  	if (skt->ops->socket_suspend)
  		skt->ops->socket_suspend(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  
  	return 0;
  }
  
  static DEFINE_SPINLOCK(status_lock);
  
  static void soc_common_check_status(struct soc_pcmcia_socket *skt)
  {
  	unsigned int events;
  
  	debug(skt, 4, "entering PCMCIA monitoring thread
  ");
  
  	do {
  		unsigned int status;
  		unsigned long flags;
  
  		status = soc_common_pcmcia_skt_state(skt);
  
  		spin_lock_irqsave(&status_lock, flags);
  		events = (status ^ skt->status) & skt->cs_state.csc_mask;
  		skt->status = status;
  		spin_unlock_irqrestore(&status_lock, flags);
  
  		debug(skt, 4, "events: %s%s%s%s%s%s
  ",
  			events == 0         ? "<NONE>"   : "",
  			events & SS_DETECT  ? "DETECT "  : "",
  			events & SS_READY   ? "READY "   : "",
  			events & SS_BATDEAD ? "BATDEAD " : "",
  			events & SS_BATWARN ? "BATWARN " : "",
  			events & SS_STSCHG  ? "STSCHG "  : "");
  
  		if (events)
  			pcmcia_parse_events(&skt->socket, events);
  	} while (events);
  }
  
  /* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
41760d0e0   Kees Cook   drivers/pcmcia: C...
448
  static void soc_common_pcmcia_poll_event(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  {
41760d0e0   Kees Cook   drivers/pcmcia: C...
450
  	struct soc_pcmcia_socket *skt = from_timer(skt, t, poll_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  	debug(skt, 4, "polling for events
  ");
  
  	mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
  
  	soc_common_check_status(skt);
  }
  
  
  /*
   * Service routine for socket driver interrupts (requested by the
   * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
   * The actual interrupt-servicing work is performed by
   * soc_common_pcmcia_thread(), largely because the Card Services event-
   * handling code performs scheduling operations which cannot be
   * executed from within an interrupt context.
   */
7d12e780e   David Howells   IRQ: Maintain reg...
468
  static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  {
  	struct soc_pcmcia_socket *skt = dev;
  
  	debug(skt, 3, "servicing IRQ %d
  ", irq);
  
  	soc_common_check_status(skt);
  
  	return IRQ_HANDLED;
  }
  
  
  /*
   *  Implements the get_status() operation for the in-kernel PCMCIA
   * service (formerly SS_GetStatus in Card Services). Essentially just
   * fills in bits in `status' according to internal driver state or
   * the value of the voltage detect chipselect register.
   *
   * As a debugging note, during card startup, the PCMCIA core issues
   * three set_socket() commands in a row the first with RESET deasserted,
   * the second with RESET asserted, and the last with RESET deasserted
   * again. Following the third set_socket(), a get_status() command will
   * be issued. The kernel is looking for the SS_READY flag (see
   * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
   *
   * Returns: 0
   */
  static int
  soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
  
  	skt->status = soc_common_pcmcia_skt_state(skt);
  	*status = skt->status;
  
  	return 0;
  }
  
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
   * Implements the set_socket() operation for the in-kernel PCMCIA
   * service (formerly SS_SetSocket in Card Services). We more or
   * less punt all of this work and let the kernel handle the details
   * of power configuration, reset, &c. We also record the value of
   * `state' in order to regurgitate it to the PCMCIA core later.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
   */
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
515
516
  static int soc_common_pcmcia_set_socket(
  	struct pcmcia_socket *sock, socket_state_t *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  	debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d
  ",
  			(state->csc_mask == 0)		? "<NONE> " :	"",
  			(state->csc_mask & SS_DETECT)	? "DETECT " :	"",
  			(state->csc_mask & SS_READY)	? "READY " :	"",
  			(state->csc_mask & SS_BATDEAD)	? "BATDEAD " :	"",
  			(state->csc_mask & SS_BATWARN)	? "BATWARN " :	"",
  			(state->csc_mask & SS_STSCHG)	? "STSCHG " :	"",
  			(state->flags == 0)		? "<NONE> " :	"",
  			(state->flags & SS_PWR_AUTO)	? "PWR_AUTO " :	"",
  			(state->flags & SS_IOCARD)	? "IOCARD " :	"",
  			(state->flags & SS_RESET)	? "RESET " :	"",
  			(state->flags & SS_SPKR_ENA)	? "SPKR_ENA " :	"",
  			(state->flags & SS_OUTPUT_ENA)	? "OUTPUT_ENA " : "",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  			state->Vcc, state->Vpp, state->io_irq);
  
  	return soc_common_pcmcia_config_skt(skt, state);
  }
  
  
  /*
   * Implements the set_io_map() operation for the in-kernel PCMCIA
   * service (formerly SS_SetIOMap in Card Services). We configure
   * the map speed as requested, but override the address ranges
   * supplied by Card Services.
   *
   * Returns: 0 on success, -1 on error
   */
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
547
548
  static int soc_common_pcmcia_set_io_map(
  	struct pcmcia_socket *sock, struct pccard_io_map *map)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
  	unsigned short speed = map->speed;
5f784336d   Wolfram Sang   pcmcia: Fix possi...
552
553
554
555
  	debug(skt, 2, "map %u  speed %u start 0x%08llx stop 0x%08llx
  ",
  		map->map, map->speed, (unsigned long long)map->start,
  		(unsigned long long)map->stop);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s
  ",
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
558
559
560
561
562
563
564
565
  		(map->flags == 0)		? "<NONE>"	: "",
  		(map->flags & MAP_ACTIVE)	? "ACTIVE "	: "",
  		(map->flags & MAP_16BIT)	? "16BIT "	: "",
  		(map->flags & MAP_AUTOSZ)	? "AUTOSZ "	: "",
  		(map->flags & MAP_0WS)		? "0WS "	: "",
  		(map->flags & MAP_WRPROT)	? "WRPROT "	: "",
  		(map->flags & MAP_USE_WAIT)	? "USE_WAIT "	: "",
  		(map->flags & MAP_PREFETCH)	? "PREFETCH "	: "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
  
  	if (map->map >= MAX_IO_WIN) {
2e11cb4c5   Harvey Harrison   pcmcia: replace r...
568
569
  		printk(KERN_ERR "%s(): map (%d) out of range
  ", __func__,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  		       map->map);
  		return -1;
  	}
  
  	if (map->flags & MAP_ACTIVE) {
  		if (speed == 0)
  			speed = SOC_PCMCIA_IO_ACCESS;
  	} else {
  		speed = 0;
  	}
  
  	skt->spd_io[map->map] = speed;
  	skt->ops->set_timing(skt);
  
  	if (map->stop == 1)
  		map->stop = PAGE_SIZE-1;
  
  	map->stop -= map->start;
  	map->stop += skt->socket.io_offset;
  	map->start = skt->socket.io_offset;
  
  	return 0;
  }
  
  
  /*
   * Implements the set_mem_map() operation for the in-kernel PCMCIA
   * service (formerly SS_SetMemMap in Card Services). We configure
   * the map speed as requested, but override the address ranges
   * supplied by Card Services.
   *
4846d0172   Pavel Machek   [PATCH] zaurus: f...
601
   * Returns: 0 on success, -ERRNO on error
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
   */
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
603
604
  static int soc_common_pcmcia_set_mem_map(
  	struct pcmcia_socket *sock, struct pccard_mem_map *map)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
611
612
613
614
  {
  	struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
  	struct resource *res;
  	unsigned short speed = map->speed;
  
  	debug(skt, 2, "map %u speed %u card_start %08x
  ",
  		map->map, map->speed, map->card_start);
  	debug(skt, 2, "flags: %s%s%s%s%s%s%s%s
  ",
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
615
616
617
618
619
620
621
622
  		(map->flags == 0)		? "<NONE>"	: "",
  		(map->flags & MAP_ACTIVE)	? "ACTIVE "	: "",
  		(map->flags & MAP_16BIT)	? "16BIT "	: "",
  		(map->flags & MAP_AUTOSZ)	? "AUTOSZ "	: "",
  		(map->flags & MAP_0WS)		? "0WS "	: "",
  		(map->flags & MAP_WRPROT)	? "WRPROT "	: "",
  		(map->flags & MAP_ATTRIB)	? "ATTRIB "	: "",
  		(map->flags & MAP_USE_WAIT)	? "USE_WAIT "	: "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
  
  	if (map->map >= MAX_WIN)
  		return -EINVAL;
  
  	if (map->flags & MAP_ACTIVE) {
  		if (speed == 0)
  			speed = 300;
  	} else {
  		speed = 0;
  	}
  
  	if (map->flags & MAP_ATTRIB) {
  		res = &skt->res_attr;
  		skt->spd_attr[map->map] = speed;
  		skt->spd_mem[map->map] = 0;
  	} else {
  		res = &skt->res_mem;
  		skt->spd_attr[map->map] = 0;
  		skt->spd_mem[map->map] = speed;
  	}
  
  	skt->ops->set_timing(skt);
  
  	map->static_start = res->start + map->card_start;
  
  	return 0;
  }
  
  struct bittbl {
  	unsigned int mask;
  	const char *name;
  };
  
  static struct bittbl status_bits[] = {
  	{ SS_WRPROT,		"SS_WRPROT"	},
  	{ SS_BATDEAD,		"SS_BATDEAD"	},
  	{ SS_BATWARN,		"SS_BATWARN"	},
  	{ SS_READY,		"SS_READY"	},
  	{ SS_DETECT,		"SS_DETECT"	},
  	{ SS_POWERON,		"SS_POWERON"	},
  	{ SS_STSCHG,		"SS_STSCHG"	},
  	{ SS_3VCARD,		"SS_3VCARD"	},
  	{ SS_XVCARD,		"SS_XVCARD"	},
  };
  
  static struct bittbl conf_bits[] = {
  	{ SS_PWR_AUTO,		"SS_PWR_AUTO"	},
  	{ SS_IOCARD,		"SS_IOCARD"	},
  	{ SS_RESET,		"SS_RESET"	},
  	{ SS_DMA_MODE,		"SS_DMA_MODE"	},
  	{ SS_SPKR_ENA,		"SS_SPKR_ENA"	},
  	{ SS_OUTPUT_ENA,	"SS_OUTPUT_ENA"	},
  };
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
676
677
  static void dump_bits(char **p, const char *prefix,
  	unsigned int val, struct bittbl *bits, int sz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  {
  	char *b = *p;
  	int i;
  
  	b += sprintf(b, "%-9s:", prefix);
  	for (i = 0; i < sz; i++)
  		if (val & bits[i].mask)
  			b += sprintf(b, " %s", bits[i].name);
  	*b++ = '
  ';
  	*p = b;
  }
  
  /*
   * Implements the /sys/class/pcmcia_socket/??/status file.
   *
   * Returns: the number of characters added to the buffer
   */
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
696
697
  static ssize_t show_status(
  	struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
  {
  	struct soc_pcmcia_socket *skt =
873733188   Greg Kroah-Hartman   Driver core: conv...
700
  		container_of(dev, struct soc_pcmcia_socket, socket.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	char *p = buf;
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
702
703
  	p += sprintf(p, "slot     : %d
  ", skt->nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
710
  
  	dump_bits(&p, "status", skt->status,
  		  status_bits, ARRAY_SIZE(status_bits));
  	dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
  		  status_bits, ARRAY_SIZE(status_bits));
  	dump_bits(&p, "cs_flags", skt->cs_state.flags,
  		  conf_bits, ARRAY_SIZE(conf_bits));
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
711
712
713
714
715
716
  	p += sprintf(p, "Vcc      : %d
  ", skt->cs_state.Vcc);
  	p += sprintf(p, "Vpp      : %d
  ", skt->cs_state.Vpp);
  	p += sprintf(p, "IRQ      : %d (%d)
  ", skt->cs_state.io_irq,
66024db57   Russell King - ARM Linux   PCMCIA: stop dupl...
717
  		skt->socket.pci_irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  	if (skt->ops->show_timing)
17b38ebb6   Marcelo Roberto Jimenez   ARM: 6457/1: pcmc...
719
  		p += skt->ops->show_timing(skt, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
  
  	return p-buf;
  }
e4a3c3f09   Alexey Dobriyan   pcmcia: some clas...
723
  static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
727
728
729
  
  
  static struct pccard_operations soc_common_pcmcia_operations = {
  	.init			= soc_common_pcmcia_sock_init,
  	.suspend		= soc_common_pcmcia_suspend,
  	.get_status		= soc_common_pcmcia_get_status,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
  	.set_socket		= soc_common_pcmcia_set_socket,
  	.set_io_map		= soc_common_pcmcia_set_io_map,
  	.set_mem_map		= soc_common_pcmcia_set_mem_map,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  #ifdef CONFIG_CPU_FREQ
fb8c9959a   Russell King   pcmcia: soc_commo...
735
736
  static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb,
  	unsigned long val, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
  {
fb8c9959a   Russell King   pcmcia: soc_commo...
738
  	struct soc_pcmcia_socket *skt = container_of(nb, struct soc_pcmcia_socket, cpufreq_nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
  	struct cpufreq_freqs *freqs = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740

fb8c9959a   Russell King   pcmcia: soc_commo...
741
  	return skt->ops->frequency_change(skt, val, freqs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  #endif
e0d21178c   Russell King   PCMCIA: soc_commo...
744
  void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
c8f9ce556   Russell King   pcmcia: soc_commo...
745
  	const struct pcmcia_low_level *ops, struct device *dev)
e0d21178c   Russell King   PCMCIA: soc_commo...
746
  {
d9dc87876   Russell King   PCMCIA: soc_commo...
747
  	int i;
e0d21178c   Russell King   PCMCIA: soc_commo...
748
749
750
751
  	skt->ops = ops;
  	skt->socket.owner = ops->owner;
  	skt->socket.dev.parent = dev;
  	skt->socket.pci_irq = NO_IRQ;
d9dc87876   Russell King   PCMCIA: soc_commo...
752
753
754
  
  	for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
  		skt->stat[i].gpio = -EINVAL;
e0d21178c   Russell King   PCMCIA: soc_commo...
755
756
  }
  EXPORT_SYMBOL(soc_pcmcia_init_one);
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
757
  void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  {
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
759
  	del_timer_sync(&skt->poll_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
761
  	pcmcia_unregister_socket(&skt->socket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762

fb8c9959a   Russell King   pcmcia: soc_commo...
763
764
765
766
767
  #ifdef CONFIG_CPU_FREQ
  	if (skt->ops->frequency_change)
  		cpufreq_unregister_notifier(&skt->cpufreq_nb,
  					    CPUFREQ_TRANSITION_NOTIFIER);
  #endif
d9dc87876   Russell King   PCMCIA: soc_commo...
768
  	soc_pcmcia_hw_shutdown(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769

d9dc87876   Russell King   PCMCIA: soc_commo...
770
  	/* should not be required; violates some lowlevel drivers */
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
771
  	soc_common_pcmcia_config_skt(skt, &dead_socket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
773
774
775
776
777
778
779
780
  	iounmap(skt->virt_io);
  	skt->virt_io = NULL;
  	release_resource(&skt->res_attr);
  	release_resource(&skt->res_mem);
  	release_resource(&skt->res_io);
  	release_resource(&skt->res_skt);
  }
  EXPORT_SYMBOL(soc_pcmcia_remove_one);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
782
783
784
  int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
  {
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785

6ac95d821   Russell King   pcmcia: soc_commo...
786
  	skt->cs_state = dead_socket;
41760d0e0   Kees Cook   drivers/pcmcia: C...
787
  	timer_setup(&skt->poll_timer, soc_common_pcmcia_poll_event, 0);
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
788
  	skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
790
791
792
  	ret = request_resource(&iomem_resource, &skt->res_skt);
  	if (ret)
  		goto out_err_1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
794
795
796
  	ret = request_resource(&skt->res_skt, &skt->res_io);
  	if (ret)
  		goto out_err_2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
798
799
800
  	ret = request_resource(&skt->res_skt, &skt->res_mem);
  	if (ret)
  		goto out_err_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
802
803
804
  	ret = request_resource(&skt->res_skt, &skt->res_attr);
  	if (ret)
  		goto out_err_4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
806
807
808
809
810
  	skt->virt_io = ioremap(skt->res_io.start, 0x10000);
  	if (skt->virt_io == NULL) {
  		ret = -ENOMEM;
  		goto out_err_5;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
812
813
814
815
816
817
  	/*
  	 * We initialize default socket timing here, because
  	 * we are not guaranteed to see a SetIOMap operation at
  	 * runtime.
  	 */
  	skt->ops->set_timing(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818

d9dc87876   Russell King   PCMCIA: soc_commo...
819
  	ret = soc_pcmcia_hw_init(skt);
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
820
821
  	if (ret)
  		goto out_err_6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
823
824
825
826
827
  	skt->socket.ops = &soc_common_pcmcia_operations;
  	skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
  	skt->socket.resource_ops = &pccard_static_ops;
  	skt->socket.irq_mask = 0;
  	skt->socket.map_size = PAGE_SIZE;
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
828
  	skt->socket.io_offset = (unsigned long)skt->virt_io;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829

097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
830
  	skt->status = soc_common_pcmcia_skt_state(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831

fb8c9959a   Russell King   pcmcia: soc_commo...
832
833
834
835
836
837
838
839
840
841
842
843
844
  #ifdef CONFIG_CPU_FREQ
  	if (skt->ops->frequency_change) {
  		skt->cpufreq_nb.notifier_call = soc_common_pcmcia_cpufreq_nb;
  
  		ret = cpufreq_register_notifier(&skt->cpufreq_nb,
  						CPUFREQ_TRANSITION_NOTIFIER);
  		if (ret < 0)
  			dev_err(skt->socket.dev.parent,
  				"unable to register CPU frequency change notifier for PCMCIA (%d)
  ",
  				ret);
  	}
  #endif
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
845
846
847
  	ret = pcmcia_register_socket(&skt->socket);
  	if (ret)
  		goto out_err_7;
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
848
849
850
851
852
  	ret = device_create_file(&skt->socket.dev, &dev_attr_status);
  	if (ret)
  		goto out_err_8;
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853

632480ea6   Jürgen Schindele   [ARM] 5245/1: Fix...
854
   out_err_8:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
855
856
  	del_timer_sync(&skt->poll_timer);
  	pcmcia_unregister_socket(&skt->socket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
  
   out_err_7:
d9dc87876   Russell King   PCMCIA: soc_commo...
859
  	soc_pcmcia_hw_shutdown(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
   out_err_6:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
861
  	iounmap(skt->virt_io);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
   out_err_5:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
863
  	release_resource(&skt->res_attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
   out_err_4:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
865
  	release_resource(&skt->res_mem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
   out_err_3:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
867
  	release_resource(&skt->res_io);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
   out_err_2:
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
869
  	release_resource(&skt->res_skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
   out_err_1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
  	return ret;
  }
097e296d6   Russell King - ARM Linux   PCMCIA: soc_commo...
874
  EXPORT_SYMBOL(soc_pcmcia_add_one);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875

0f767de6a   Russell King - ARM Linux   PCMCIA: soc_commo...
876
877
878
  MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
  MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
  MODULE_LICENSE("Dual MPL/GPL");