blob: e07d84a69fccc144dd53a77833f9c16d7b271649 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 Common support code for the PCMCIA control functionality of
4 integrated SOCs like the SA-11x0 and PXA2xx microprocessors.
5
6 The contents of this file are subject to the Mozilla Public
7 License Version 1.1 (the "License"); you may not use this file
8 except in compliance with the License. You may obtain a copy of
9 the License at http://www.mozilla.org/MPL/
10
11 Software distributed under the License is distributed on an "AS
12 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 implied. See the License for the specific language governing
14 rights and limitations under the License.
15
16 The initial developer of the original code is John G. Dorsey
17 <john+@cs.cmu.edu>. Portions created by John G. Dorsey are
18 Copyright (C) 1999 John G. Dorsey. All Rights Reserved.
19
20 Alternatively, the contents of this file may be used under the
21 terms of the GNU Public License version 2 (the "GPL"), in which
22 case the provisions of the GPL are applicable instead of the
23 above. If you wish to allow the use of your version of this file
24 only under the terms of the GPL and not to allow others to use
25 your version of this file under the MPL, indicate your decision
26 by deleting the provisions above and replace them with the notice
27 and other provisions required by the GPL. If you do not delete
28 the provisions above, a recipient may use your version of this
29 file under either the MPL or the GPL.
30
31======================================================================*/
32
33
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +010034#include <linux/cpufreq.h>
Russell Kingd9dc8782011-12-19 22:00:22 +000035#include <linux/gpio.h>
Russell King45ca7532016-08-31 08:49:45 +010036#include <linux/gpio/consumer.h>
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +010037#include <linux/init.h>
38#include <linux/interrupt.h>
39#include <linux/io.h>
40#include <linux/irq.h>
41#include <linux/kernel.h>
42#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/module.h>
44#include <linux/moduleparam.h>
Andrew Morton23d077e2008-05-01 04:34:54 -070045#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/spinlock.h>
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +010047#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Russell Kinga09e64f2008-08-05 16:14:15 +010049#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include "soc_common.h"
52
Russell Kingd9dc8782011-12-19 22:00:22 +000053static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
54
Dominik Brodowski7d16b652008-08-02 21:02:01 +020055#ifdef CONFIG_PCMCIA_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static int pc_debug;
58module_param(pc_debug, int, 0644);
59
60void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
61 int lvl, const char *fmt, ...)
62{
Joe Perches106665d2010-11-09 17:14:01 -080063 struct va_format vaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 va_list args;
65 if (pc_debug > lvl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 va_start(args, fmt);
Joe Perches106665d2010-11-09 17:14:01 -080067
68 vaf.fmt = fmt;
69 vaf.va = &args;
70
71 printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 va_end(args);
74 }
75}
Marcelo Roberto Jimenezb9f515e2010-10-18 22:38:08 +010076EXPORT_SYMBOL(soc_pcmcia_debug);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78#endif
79
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +010080#define to_soc_pcmcia_socket(x) \
81 container_of(x, struct soc_pcmcia_socket, socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83static unsigned short
84calc_speed(unsigned short *spds, int num, unsigned short dflt)
85{
86 unsigned short speed = 0;
87 int i;
88
89 for (i = 0; i < num; i++)
90 if (speed < spds[i])
91 speed = spds[i];
92 if (speed == 0)
93 speed = dflt;
94
95 return speed;
96}
97
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +010098void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
99 struct soc_pcmcia_timing *timing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100101 timing->io =
102 calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
103 timing->mem =
104 calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
105 timing->attr =
106 calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107}
108EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
109
Russell Kingd9dc8782011-12-19 22:00:22 +0000110static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
111 unsigned int nr)
112{
113 unsigned int i;
114
Russell King59ecfef2016-09-04 21:50:47 +0100115 for (i = 0; i < nr; i++)
Russell Kingd9dc8782011-12-19 22:00:22 +0000116 if (skt->stat[i].irq)
117 free_irq(skt->stat[i].irq, skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000118
119 if (skt->ops->hw_shutdown)
120 skt->ops->hw_shutdown(skt);
Dmitry Eremin-Solenikov0821c3b2014-12-03 18:37:10 +0100121
122 clk_disable_unprepare(skt->clk);
Russell Kingd9dc8782011-12-19 22:00:22 +0000123}
124
125static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
126{
127 __soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
128}
129
Russell King45ca7532016-08-31 08:49:45 +0100130int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
131{
132 struct device *dev = skt->socket.dev.parent;
133 struct gpio_desc *desc;
134 int i;
135
136 for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
137 if (!skt->stat[i].name)
138 continue;
139
140 desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN);
141 if (IS_ERR(desc)) {
142 dev_err(dev, "Failed to get GPIO for %s: %ld\n",
143 skt->stat[i].name, PTR_ERR(desc));
144 return PTR_ERR(desc);
145 }
146
147 skt->stat[i].desc = desc;
148 }
149
150 return 0;
151}
152EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
153
Russell Kingd9dc8782011-12-19 22:00:22 +0000154static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
155{
156 int ret = 0, i;
157
Dmitry Eremin-Solenikov0821c3b2014-12-03 18:37:10 +0100158 clk_prepare_enable(skt->clk);
159
Russell Kingd9dc8782011-12-19 22:00:22 +0000160 if (skt->ops->hw_init) {
161 ret = skt->ops->hw_init(skt);
162 if (ret)
163 return ret;
164 }
165
166 for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
167 if (gpio_is_valid(skt->stat[i].gpio)) {
Russell King59ecfef2016-09-04 21:50:47 +0100168 ret = devm_gpio_request_one(skt->socket.dev.parent,
169 skt->stat[i].gpio, GPIOF_IN,
170 skt->stat[i].name);
Russell Kingd9dc8782011-12-19 22:00:22 +0000171 if (ret) {
172 __soc_pcmcia_hw_shutdown(skt, i);
173 return ret;
174 }
175
Russell King45ca7532016-08-31 08:49:45 +0100176 skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
177 }
178
179 if (skt->stat[i].desc) {
180 int irq = gpiod_to_irq(skt->stat[i].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000181
182 if (i == SOC_STAT_RDY)
183 skt->socket.pci_irq = irq;
184 else
185 skt->stat[i].irq = irq;
186 }
187
188 if (skt->stat[i].irq) {
189 ret = request_irq(skt->stat[i].irq,
190 soc_common_pcmcia_interrupt,
191 IRQF_TRIGGER_NONE,
192 skt->stat[i].name, skt);
193 if (ret) {
Russell Kingd9dc8782011-12-19 22:00:22 +0000194 __soc_pcmcia_hw_shutdown(skt, i);
195 return ret;
196 }
197 }
198 }
199
200 return ret;
201}
202
203static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
204{
205 int i;
206
207 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
208 if (skt->stat[i].irq) {
209 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
210 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
211 }
212}
213
214static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
215{
216 int i;
217
218 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
219 if (skt->stat[i].irq)
220 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
221}
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
224{
225 struct pcmcia_state state;
226 unsigned int stat;
227
228 memset(&state, 0, sizeof(struct pcmcia_state));
229
Russell Kingd9dc8782011-12-19 22:00:22 +0000230 /* Make battery voltage state report 'good' */
231 state.bvd1 = 1;
232 state.bvd2 = 1;
233
234 /* CD is active low by default */
Russell King45ca7532016-08-31 08:49:45 +0100235 if (skt->stat[SOC_STAT_CD].desc)
236 state.detect = !gpiod_get_raw_value(skt->stat[SOC_STAT_CD].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000237
238 /* RDY and BVD are active high by default */
Russell King45ca7532016-08-31 08:49:45 +0100239 if (skt->stat[SOC_STAT_RDY].desc)
240 state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
241 if (skt->stat[SOC_STAT_BVD1].desc)
242 state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
243 if (skt->stat[SOC_STAT_BVD2].desc)
244 state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 skt->ops->socket_state(skt, &state);
247
248 stat = state.detect ? SS_DETECT : 0;
249 stat |= state.ready ? SS_READY : 0;
250 stat |= state.wrprot ? SS_WRPROT : 0;
251 stat |= state.vs_3v ? SS_3VCARD : 0;
252 stat |= state.vs_Xv ? SS_XVCARD : 0;
253
254 /* The power status of individual sockets is not available
255 * explicitly from the hardware, so we just remember the state
256 * and regurgitate it upon request:
257 */
258 stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
259
260 if (skt->cs_state.flags & SS_IOCARD)
Russell Kinga466ebd2016-08-31 08:49:43 +0100261 stat |= state.bvd1 ? 0 : SS_STSCHG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 else {
263 if (state.bvd1 == 0)
264 stat |= SS_BATDEAD;
265 else if (state.bvd2 == 0)
266 stat |= SS_BATWARN;
267 }
268 return stat;
269}
270
271/*
272 * soc_common_pcmcia_config_skt
273 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
274 *
275 * Convert PCMCIA socket state to our socket configure structure.
276 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100277static int soc_common_pcmcia_config_skt(
278 struct soc_pcmcia_socket *skt, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 int ret;
281
282 ret = skt->ops->configure_socket(skt, state);
283 if (ret == 0) {
284 /*
285 * This really needs a better solution. The IRQ
286 * may or may not be claimed by the driver.
287 */
288 if (skt->irq_state != 1 && state->io_irq) {
289 skt->irq_state = 1;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200290 irq_set_irq_type(skt->socket.pci_irq,
291 IRQ_TYPE_EDGE_FALLING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 } else if (skt->irq_state == 1 && state->io_irq == 0) {
293 skt->irq_state = 0;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200294 irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296
297 skt->cs_state = *state;
298 }
299
300 if (ret < 0)
301 printk(KERN_ERR "soc_common_pcmcia: unable to configure "
302 "socket %d\n", skt->nr);
303
304 return ret;
305}
306
307/* soc_common_pcmcia_sock_init()
308 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
309 *
310 * (Re-)Initialise the socket, turning on status interrupts
311 * and PCMCIA bus. This must wait for power to stabilise
312 * so that the card status signals report correctly.
313 *
314 * Returns: 0
315 */
316static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
317{
318 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
319
320 debug(skt, 2, "initializing socket\n");
Jonathan Camerona747ce82011-07-13 15:54:56 +0100321 if (skt->ops->socket_init)
322 skt->ops->socket_init(skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000323 soc_pcmcia_hw_enable(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 return 0;
325}
326
327
328/*
329 * soc_common_pcmcia_suspend()
330 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
331 *
332 * Remove power on the socket, disable IRQs from the card.
333 * Turn off status interrupts, and disable the PCMCIA bus.
334 *
335 * Returns: 0
336 */
337static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
338{
339 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
340
341 debug(skt, 2, "suspending socket\n");
342
Russell Kingd9dc8782011-12-19 22:00:22 +0000343 soc_pcmcia_hw_disable(skt);
Jonathan Camerona747ce82011-07-13 15:54:56 +0100344 if (skt->ops->socket_suspend)
345 skt->ops->socket_suspend(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 return 0;
348}
349
350static DEFINE_SPINLOCK(status_lock);
351
352static void soc_common_check_status(struct soc_pcmcia_socket *skt)
353{
354 unsigned int events;
355
356 debug(skt, 4, "entering PCMCIA monitoring thread\n");
357
358 do {
359 unsigned int status;
360 unsigned long flags;
361
362 status = soc_common_pcmcia_skt_state(skt);
363
364 spin_lock_irqsave(&status_lock, flags);
365 events = (status ^ skt->status) & skt->cs_state.csc_mask;
366 skt->status = status;
367 spin_unlock_irqrestore(&status_lock, flags);
368
369 debug(skt, 4, "events: %s%s%s%s%s%s\n",
370 events == 0 ? "<NONE>" : "",
371 events & SS_DETECT ? "DETECT " : "",
372 events & SS_READY ? "READY " : "",
373 events & SS_BATDEAD ? "BATDEAD " : "",
374 events & SS_BATWARN ? "BATWARN " : "",
375 events & SS_STSCHG ? "STSCHG " : "");
376
377 if (events)
378 pcmcia_parse_events(&skt->socket, events);
379 } while (events);
380}
381
382/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
383static void soc_common_pcmcia_poll_event(unsigned long dummy)
384{
385 struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
386 debug(skt, 4, "polling for events\n");
387
388 mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
389
390 soc_common_check_status(skt);
391}
392
393
394/*
395 * Service routine for socket driver interrupts (requested by the
396 * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
397 * The actual interrupt-servicing work is performed by
398 * soc_common_pcmcia_thread(), largely because the Card Services event-
399 * handling code performs scheduling operations which cannot be
400 * executed from within an interrupt context.
401 */
David Howells7d12e782006-10-05 14:55:46 +0100402static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 struct soc_pcmcia_socket *skt = dev;
405
406 debug(skt, 3, "servicing IRQ %d\n", irq);
407
408 soc_common_check_status(skt);
409
410 return IRQ_HANDLED;
411}
412
413
414/*
415 * Implements the get_status() operation for the in-kernel PCMCIA
416 * service (formerly SS_GetStatus in Card Services). Essentially just
417 * fills in bits in `status' according to internal driver state or
418 * the value of the voltage detect chipselect register.
419 *
420 * As a debugging note, during card startup, the PCMCIA core issues
421 * three set_socket() commands in a row the first with RESET deasserted,
422 * the second with RESET asserted, and the last with RESET deasserted
423 * again. Following the third set_socket(), a get_status() command will
424 * be issued. The kernel is looking for the SS_READY flag (see
425 * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
426 *
427 * Returns: 0
428 */
429static int
430soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
431{
432 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
433
434 skt->status = soc_common_pcmcia_skt_state(skt);
435 *status = skt->status;
436
437 return 0;
438}
439
440
441/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 * Implements the set_socket() operation for the in-kernel PCMCIA
443 * service (formerly SS_SetSocket in Card Services). We more or
444 * less punt all of this work and let the kernel handle the details
445 * of power configuration, reset, &c. We also record the value of
446 * `state' in order to regurgitate it to the PCMCIA core later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100448static int soc_common_pcmcia_set_socket(
449 struct pcmcia_socket *sock, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
452
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100453 debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
454 (state->csc_mask == 0) ? "<NONE> " : "",
455 (state->csc_mask & SS_DETECT) ? "DETECT " : "",
456 (state->csc_mask & SS_READY) ? "READY " : "",
457 (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
458 (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
459 (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
460 (state->flags == 0) ? "<NONE> " : "",
461 (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
462 (state->flags & SS_IOCARD) ? "IOCARD " : "",
463 (state->flags & SS_RESET) ? "RESET " : "",
464 (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
465 (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 state->Vcc, state->Vpp, state->io_irq);
467
468 return soc_common_pcmcia_config_skt(skt, state);
469}
470
471
472/*
473 * Implements the set_io_map() operation for the in-kernel PCMCIA
474 * service (formerly SS_SetIOMap in Card Services). We configure
475 * the map speed as requested, but override the address ranges
476 * supplied by Card Services.
477 *
478 * Returns: 0 on success, -1 on error
479 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100480static int soc_common_pcmcia_set_io_map(
481 struct pcmcia_socket *sock, struct pccard_io_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
483 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
484 unsigned short speed = map->speed;
485
Wolfram Sang5f784332009-10-19 11:42:13 +0200486 debug(skt, 2, "map %u speed %u start 0x%08llx stop 0x%08llx\n",
487 map->map, map->speed, (unsigned long long)map->start,
488 (unsigned long long)map->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100490 (map->flags == 0) ? "<NONE>" : "",
491 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
492 (map->flags & MAP_16BIT) ? "16BIT " : "",
493 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
494 (map->flags & MAP_0WS) ? "0WS " : "",
495 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
496 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
497 (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (map->map >= MAX_IO_WIN) {
Harvey Harrison2e11cb42008-05-01 04:34:54 -0700500 printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 map->map);
502 return -1;
503 }
504
505 if (map->flags & MAP_ACTIVE) {
506 if (speed == 0)
507 speed = SOC_PCMCIA_IO_ACCESS;
508 } else {
509 speed = 0;
510 }
511
512 skt->spd_io[map->map] = speed;
513 skt->ops->set_timing(skt);
514
515 if (map->stop == 1)
516 map->stop = PAGE_SIZE-1;
517
518 map->stop -= map->start;
519 map->stop += skt->socket.io_offset;
520 map->start = skt->socket.io_offset;
521
522 return 0;
523}
524
525
526/*
527 * Implements the set_mem_map() operation for the in-kernel PCMCIA
528 * service (formerly SS_SetMemMap in Card Services). We configure
529 * the map speed as requested, but override the address ranges
530 * supplied by Card Services.
531 *
Pavel Machek4846d012005-10-14 15:59:02 -0700532 * Returns: 0 on success, -ERRNO on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100534static int soc_common_pcmcia_set_mem_map(
535 struct pcmcia_socket *sock, struct pccard_mem_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
538 struct resource *res;
539 unsigned short speed = map->speed;
540
541 debug(skt, 2, "map %u speed %u card_start %08x\n",
542 map->map, map->speed, map->card_start);
543 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100544 (map->flags == 0) ? "<NONE>" : "",
545 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
546 (map->flags & MAP_16BIT) ? "16BIT " : "",
547 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
548 (map->flags & MAP_0WS) ? "0WS " : "",
549 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
550 (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
551 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 if (map->map >= MAX_WIN)
554 return -EINVAL;
555
556 if (map->flags & MAP_ACTIVE) {
557 if (speed == 0)
558 speed = 300;
559 } else {
560 speed = 0;
561 }
562
563 if (map->flags & MAP_ATTRIB) {
564 res = &skt->res_attr;
565 skt->spd_attr[map->map] = speed;
566 skt->spd_mem[map->map] = 0;
567 } else {
568 res = &skt->res_mem;
569 skt->spd_attr[map->map] = 0;
570 skt->spd_mem[map->map] = speed;
571 }
572
573 skt->ops->set_timing(skt);
574
575 map->static_start = res->start + map->card_start;
576
577 return 0;
578}
579
580struct bittbl {
581 unsigned int mask;
582 const char *name;
583};
584
585static struct bittbl status_bits[] = {
586 { SS_WRPROT, "SS_WRPROT" },
587 { SS_BATDEAD, "SS_BATDEAD" },
588 { SS_BATWARN, "SS_BATWARN" },
589 { SS_READY, "SS_READY" },
590 { SS_DETECT, "SS_DETECT" },
591 { SS_POWERON, "SS_POWERON" },
592 { SS_STSCHG, "SS_STSCHG" },
593 { SS_3VCARD, "SS_3VCARD" },
594 { SS_XVCARD, "SS_XVCARD" },
595};
596
597static struct bittbl conf_bits[] = {
598 { SS_PWR_AUTO, "SS_PWR_AUTO" },
599 { SS_IOCARD, "SS_IOCARD" },
600 { SS_RESET, "SS_RESET" },
601 { SS_DMA_MODE, "SS_DMA_MODE" },
602 { SS_SPKR_ENA, "SS_SPKR_ENA" },
603 { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" },
604};
605
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100606static void dump_bits(char **p, const char *prefix,
607 unsigned int val, struct bittbl *bits, int sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 char *b = *p;
610 int i;
611
612 b += sprintf(b, "%-9s:", prefix);
613 for (i = 0; i < sz; i++)
614 if (val & bits[i].mask)
615 b += sprintf(b, " %s", bits[i].name);
616 *b++ = '\n';
617 *p = b;
618}
619
620/*
621 * Implements the /sys/class/pcmcia_socket/??/status file.
622 *
623 * Returns: the number of characters added to the buffer
624 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100625static ssize_t show_status(
626 struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 struct soc_pcmcia_socket *skt =
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200629 container_of(dev, struct soc_pcmcia_socket, socket.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 char *p = buf;
631
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100632 p += sprintf(p, "slot : %d\n", skt->nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 dump_bits(&p, "status", skt->status,
635 status_bits, ARRAY_SIZE(status_bits));
636 dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
637 status_bits, ARRAY_SIZE(status_bits));
638 dump_bits(&p, "cs_flags", skt->cs_state.flags,
639 conf_bits, ARRAY_SIZE(conf_bits));
640
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100641 p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
642 p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
643 p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
Russell King - ARM Linux66024db2009-03-29 22:45:26 +0100644 skt->socket.pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (skt->ops->show_timing)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100646 p += skt->ops->show_timing(skt, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 return p-buf;
649}
Alexey Dobriyane4a3c3f2007-02-13 22:39:27 -0800650static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652
653static struct pccard_operations soc_common_pcmcia_operations = {
654 .init = soc_common_pcmcia_sock_init,
655 .suspend = soc_common_pcmcia_suspend,
656 .get_status = soc_common_pcmcia_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 .set_socket = soc_common_pcmcia_set_socket,
658 .set_io_map = soc_common_pcmcia_set_io_map,
659 .set_mem_map = soc_common_pcmcia_set_mem_map,
660};
661
662
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000663static LIST_HEAD(soc_pcmcia_sockets);
Andrew Morton23d077e2008-05-01 04:34:54 -0700664static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#ifdef CONFIG_CPU_FREQ
667static int
668soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
669{
670 struct soc_pcmcia_socket *skt;
671 struct cpufreq_freqs *freqs = data;
672 int ret = 0;
673
Andrew Morton23d077e2008-05-01 04:34:54 -0700674 mutex_lock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 list_for_each_entry(skt, &soc_pcmcia_sockets, node)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100676 if (skt->ops->frequency_change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 ret += skt->ops->frequency_change(skt, val, freqs);
Andrew Morton23d077e2008-05-01 04:34:54 -0700678 mutex_unlock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 return ret;
681}
682
683static struct notifier_block soc_pcmcia_notifier_block = {
684 .notifier_call = soc_pcmcia_notifier
685};
686
687static int soc_pcmcia_cpufreq_register(void)
688{
689 int ret;
690
691 ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block,
692 CPUFREQ_TRANSITION_NOTIFIER);
693 if (ret < 0)
694 printk(KERN_ERR "Unable to register CPU frequency change "
695 "notifier for PCMCIA (%d)\n", ret);
696 return ret;
697}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000698fs_initcall(soc_pcmcia_cpufreq_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700static void soc_pcmcia_cpufreq_unregister(void)
701{
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100702 cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
703 CPUFREQ_TRANSITION_NOTIFIER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000705module_exit(soc_pcmcia_cpufreq_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707#endif
708
Russell Kinge0d21172011-12-19 14:07:31 +0000709void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
710 struct pcmcia_low_level *ops, struct device *dev)
711{
Russell Kingd9dc8782011-12-19 22:00:22 +0000712 int i;
713
Russell Kinge0d21172011-12-19 14:07:31 +0000714 skt->ops = ops;
715 skt->socket.owner = ops->owner;
716 skt->socket.dev.parent = dev;
717 skt->socket.pci_irq = NO_IRQ;
Russell Kingd9dc8782011-12-19 22:00:22 +0000718
719 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
720 skt->stat[i].gpio = -EINVAL;
Russell Kinge0d21172011-12-19 14:07:31 +0000721}
722EXPORT_SYMBOL(soc_pcmcia_init_one);
723
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000724void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
725{
726 mutex_lock(&soc_pcmcia_sockets_lock);
727 del_timer_sync(&skt->poll_timer);
728
729 pcmcia_unregister_socket(&skt->socket);
730
Russell Kingd9dc8782011-12-19 22:00:22 +0000731 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000732
Russell Kingd9dc8782011-12-19 22:00:22 +0000733 /* should not be required; violates some lowlevel drivers */
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000734 soc_common_pcmcia_config_skt(skt, &dead_socket);
735
736 list_del(&skt->node);
737 mutex_unlock(&soc_pcmcia_sockets_lock);
738
739 iounmap(skt->virt_io);
740 skt->virt_io = NULL;
741 release_resource(&skt->res_attr);
742 release_resource(&skt->res_mem);
743 release_resource(&skt->res_io);
744 release_resource(&skt->res_skt);
745}
746EXPORT_SYMBOL(soc_pcmcia_remove_one);
747
748int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
749{
750 int ret;
751
Vaishali Thakkardae6cda2015-02-11 16:25:38 +0530752 setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
753 (unsigned long)skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000754 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
755
756 ret = request_resource(&iomem_resource, &skt->res_skt);
757 if (ret)
758 goto out_err_1;
759
760 ret = request_resource(&skt->res_skt, &skt->res_io);
761 if (ret)
762 goto out_err_2;
763
764 ret = request_resource(&skt->res_skt, &skt->res_mem);
765 if (ret)
766 goto out_err_3;
767
768 ret = request_resource(&skt->res_skt, &skt->res_attr);
769 if (ret)
770 goto out_err_4;
771
772 skt->virt_io = ioremap(skt->res_io.start, 0x10000);
773 if (skt->virt_io == NULL) {
774 ret = -ENOMEM;
775 goto out_err_5;
776 }
777
778 mutex_lock(&soc_pcmcia_sockets_lock);
779
780 list_add(&skt->node, &soc_pcmcia_sockets);
781
782 /*
783 * We initialize default socket timing here, because
784 * we are not guaranteed to see a SetIOMap operation at
785 * runtime.
786 */
787 skt->ops->set_timing(skt);
788
Russell Kingd9dc8782011-12-19 22:00:22 +0000789 ret = soc_pcmcia_hw_init(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000790 if (ret)
791 goto out_err_6;
792
793 skt->socket.ops = &soc_common_pcmcia_operations;
794 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
795 skt->socket.resource_ops = &pccard_static_ops;
796 skt->socket.irq_mask = 0;
797 skt->socket.map_size = PAGE_SIZE;
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000798 skt->socket.io_offset = (unsigned long)skt->virt_io;
799
800 skt->status = soc_common_pcmcia_skt_state(skt);
801
802 ret = pcmcia_register_socket(&skt->socket);
803 if (ret)
804 goto out_err_7;
805
806 add_timer(&skt->poll_timer);
807
808 mutex_unlock(&soc_pcmcia_sockets_lock);
809
810 ret = device_create_file(&skt->socket.dev, &dev_attr_status);
811 if (ret)
812 goto out_err_8;
813
814 return ret;
815
816 out_err_8:
817 mutex_lock(&soc_pcmcia_sockets_lock);
818 del_timer_sync(&skt->poll_timer);
819 pcmcia_unregister_socket(&skt->socket);
820
821 out_err_7:
Russell Kingd9dc8782011-12-19 22:00:22 +0000822 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000823 out_err_6:
824 list_del(&skt->node);
825 mutex_unlock(&soc_pcmcia_sockets_lock);
826 iounmap(skt->virt_io);
827 out_err_5:
828 release_resource(&skt->res_attr);
829 out_err_4:
830 release_resource(&skt->res_mem);
831 out_err_3:
832 release_resource(&skt->res_io);
833 out_err_2:
834 release_resource(&skt->res_skt);
835 out_err_1:
836
837 return ret;
838}
839EXPORT_SYMBOL(soc_pcmcia_add_one);
840
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000841MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
842MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
843MODULE_LICENSE("Dual MPL/GPL");