blob: e499c2b8d7df5a7b2b4bc316bf66f6cf6b3b868b [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
Russell Kinga4941192016-08-31 11:17:50 +0100182 if (irq > 0) {
183 if (i == SOC_STAT_RDY)
184 skt->socket.pci_irq = irq;
185 else
186 skt->stat[i].irq = irq;
187 }
Russell Kingd9dc8782011-12-19 22:00:22 +0000188 }
189
190 if (skt->stat[i].irq) {
191 ret = request_irq(skt->stat[i].irq,
192 soc_common_pcmcia_interrupt,
193 IRQF_TRIGGER_NONE,
194 skt->stat[i].name, skt);
195 if (ret) {
Russell Kingd9dc8782011-12-19 22:00:22 +0000196 __soc_pcmcia_hw_shutdown(skt, i);
197 return ret;
198 }
199 }
200 }
201
202 return ret;
203}
204
205static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
206{
207 int i;
208
209 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
210 if (skt->stat[i].irq) {
211 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
212 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
213 }
214}
215
216static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
217{
218 int i;
219
220 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
221 if (skt->stat[i].irq)
222 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
223}
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
226{
227 struct pcmcia_state state;
228 unsigned int stat;
229
230 memset(&state, 0, sizeof(struct pcmcia_state));
231
Russell Kingd9dc8782011-12-19 22:00:22 +0000232 /* Make battery voltage state report 'good' */
233 state.bvd1 = 1;
234 state.bvd2 = 1;
235
236 /* CD is active low by default */
Russell King45ca7532016-08-31 08:49:45 +0100237 if (skt->stat[SOC_STAT_CD].desc)
238 state.detect = !gpiod_get_raw_value(skt->stat[SOC_STAT_CD].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000239
240 /* RDY and BVD are active high by default */
Russell King45ca7532016-08-31 08:49:45 +0100241 if (skt->stat[SOC_STAT_RDY].desc)
242 state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
243 if (skt->stat[SOC_STAT_BVD1].desc)
244 state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
245 if (skt->stat[SOC_STAT_BVD2].desc)
246 state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 skt->ops->socket_state(skt, &state);
249
250 stat = state.detect ? SS_DETECT : 0;
251 stat |= state.ready ? SS_READY : 0;
252 stat |= state.wrprot ? SS_WRPROT : 0;
253 stat |= state.vs_3v ? SS_3VCARD : 0;
254 stat |= state.vs_Xv ? SS_XVCARD : 0;
255
256 /* The power status of individual sockets is not available
257 * explicitly from the hardware, so we just remember the state
258 * and regurgitate it upon request:
259 */
260 stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
261
262 if (skt->cs_state.flags & SS_IOCARD)
Russell Kinga466ebd2016-08-31 08:49:43 +0100263 stat |= state.bvd1 ? 0 : SS_STSCHG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 else {
265 if (state.bvd1 == 0)
266 stat |= SS_BATDEAD;
267 else if (state.bvd2 == 0)
268 stat |= SS_BATWARN;
269 }
270 return stat;
271}
272
273/*
274 * soc_common_pcmcia_config_skt
275 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
276 *
277 * Convert PCMCIA socket state to our socket configure structure.
278 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100279static int soc_common_pcmcia_config_skt(
280 struct soc_pcmcia_socket *skt, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 int ret;
283
284 ret = skt->ops->configure_socket(skt, state);
285 if (ret == 0) {
286 /*
287 * This really needs a better solution. The IRQ
288 * may or may not be claimed by the driver.
289 */
290 if (skt->irq_state != 1 && state->io_irq) {
291 skt->irq_state = 1;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200292 irq_set_irq_type(skt->socket.pci_irq,
293 IRQ_TYPE_EDGE_FALLING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 } else if (skt->irq_state == 1 && state->io_irq == 0) {
295 skt->irq_state = 0;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200296 irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
299 skt->cs_state = *state;
300 }
301
302 if (ret < 0)
303 printk(KERN_ERR "soc_common_pcmcia: unable to configure "
304 "socket %d\n", skt->nr);
305
306 return ret;
307}
308
309/* soc_common_pcmcia_sock_init()
310 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
311 *
312 * (Re-)Initialise the socket, turning on status interrupts
313 * and PCMCIA bus. This must wait for power to stabilise
314 * so that the card status signals report correctly.
315 *
316 * Returns: 0
317 */
318static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
319{
320 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
321
322 debug(skt, 2, "initializing socket\n");
Jonathan Camerona747ce82011-07-13 15:54:56 +0100323 if (skt->ops->socket_init)
324 skt->ops->socket_init(skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000325 soc_pcmcia_hw_enable(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 return 0;
327}
328
329
330/*
331 * soc_common_pcmcia_suspend()
332 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
333 *
334 * Remove power on the socket, disable IRQs from the card.
335 * Turn off status interrupts, and disable the PCMCIA bus.
336 *
337 * Returns: 0
338 */
339static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
340{
341 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
342
343 debug(skt, 2, "suspending socket\n");
344
Russell Kingd9dc8782011-12-19 22:00:22 +0000345 soc_pcmcia_hw_disable(skt);
Jonathan Camerona747ce82011-07-13 15:54:56 +0100346 if (skt->ops->socket_suspend)
347 skt->ops->socket_suspend(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 return 0;
350}
351
352static DEFINE_SPINLOCK(status_lock);
353
354static void soc_common_check_status(struct soc_pcmcia_socket *skt)
355{
356 unsigned int events;
357
358 debug(skt, 4, "entering PCMCIA monitoring thread\n");
359
360 do {
361 unsigned int status;
362 unsigned long flags;
363
364 status = soc_common_pcmcia_skt_state(skt);
365
366 spin_lock_irqsave(&status_lock, flags);
367 events = (status ^ skt->status) & skt->cs_state.csc_mask;
368 skt->status = status;
369 spin_unlock_irqrestore(&status_lock, flags);
370
371 debug(skt, 4, "events: %s%s%s%s%s%s\n",
372 events == 0 ? "<NONE>" : "",
373 events & SS_DETECT ? "DETECT " : "",
374 events & SS_READY ? "READY " : "",
375 events & SS_BATDEAD ? "BATDEAD " : "",
376 events & SS_BATWARN ? "BATWARN " : "",
377 events & SS_STSCHG ? "STSCHG " : "");
378
379 if (events)
380 pcmcia_parse_events(&skt->socket, events);
381 } while (events);
382}
383
384/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
385static void soc_common_pcmcia_poll_event(unsigned long dummy)
386{
387 struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
388 debug(skt, 4, "polling for events\n");
389
390 mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
391
392 soc_common_check_status(skt);
393}
394
395
396/*
397 * Service routine for socket driver interrupts (requested by the
398 * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
399 * The actual interrupt-servicing work is performed by
400 * soc_common_pcmcia_thread(), largely because the Card Services event-
401 * handling code performs scheduling operations which cannot be
402 * executed from within an interrupt context.
403 */
David Howells7d12e782006-10-05 14:55:46 +0100404static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{
406 struct soc_pcmcia_socket *skt = dev;
407
408 debug(skt, 3, "servicing IRQ %d\n", irq);
409
410 soc_common_check_status(skt);
411
412 return IRQ_HANDLED;
413}
414
415
416/*
417 * Implements the get_status() operation for the in-kernel PCMCIA
418 * service (formerly SS_GetStatus in Card Services). Essentially just
419 * fills in bits in `status' according to internal driver state or
420 * the value of the voltage detect chipselect register.
421 *
422 * As a debugging note, during card startup, the PCMCIA core issues
423 * three set_socket() commands in a row the first with RESET deasserted,
424 * the second with RESET asserted, and the last with RESET deasserted
425 * again. Following the third set_socket(), a get_status() command will
426 * be issued. The kernel is looking for the SS_READY flag (see
427 * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
428 *
429 * Returns: 0
430 */
431static int
432soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
433{
434 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
435
436 skt->status = soc_common_pcmcia_skt_state(skt);
437 *status = skt->status;
438
439 return 0;
440}
441
442
443/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 * Implements the set_socket() operation for the in-kernel PCMCIA
445 * service (formerly SS_SetSocket in Card Services). We more or
446 * less punt all of this work and let the kernel handle the details
447 * of power configuration, reset, &c. We also record the value of
448 * `state' in order to regurgitate it to the PCMCIA core later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100450static int soc_common_pcmcia_set_socket(
451 struct pcmcia_socket *sock, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
453 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
454
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100455 debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
456 (state->csc_mask == 0) ? "<NONE> " : "",
457 (state->csc_mask & SS_DETECT) ? "DETECT " : "",
458 (state->csc_mask & SS_READY) ? "READY " : "",
459 (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
460 (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
461 (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
462 (state->flags == 0) ? "<NONE> " : "",
463 (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
464 (state->flags & SS_IOCARD) ? "IOCARD " : "",
465 (state->flags & SS_RESET) ? "RESET " : "",
466 (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
467 (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 state->Vcc, state->Vpp, state->io_irq);
469
470 return soc_common_pcmcia_config_skt(skt, state);
471}
472
473
474/*
475 * Implements the set_io_map() operation for the in-kernel PCMCIA
476 * service (formerly SS_SetIOMap in Card Services). We configure
477 * the map speed as requested, but override the address ranges
478 * supplied by Card Services.
479 *
480 * Returns: 0 on success, -1 on error
481 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100482static int soc_common_pcmcia_set_io_map(
483 struct pcmcia_socket *sock, struct pccard_io_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
486 unsigned short speed = map->speed;
487
Wolfram Sang5f784332009-10-19 11:42:13 +0200488 debug(skt, 2, "map %u speed %u start 0x%08llx stop 0x%08llx\n",
489 map->map, map->speed, (unsigned long long)map->start,
490 (unsigned long long)map->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100492 (map->flags == 0) ? "<NONE>" : "",
493 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
494 (map->flags & MAP_16BIT) ? "16BIT " : "",
495 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
496 (map->flags & MAP_0WS) ? "0WS " : "",
497 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
498 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
499 (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 if (map->map >= MAX_IO_WIN) {
Harvey Harrison2e11cb42008-05-01 04:34:54 -0700502 printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 map->map);
504 return -1;
505 }
506
507 if (map->flags & MAP_ACTIVE) {
508 if (speed == 0)
509 speed = SOC_PCMCIA_IO_ACCESS;
510 } else {
511 speed = 0;
512 }
513
514 skt->spd_io[map->map] = speed;
515 skt->ops->set_timing(skt);
516
517 if (map->stop == 1)
518 map->stop = PAGE_SIZE-1;
519
520 map->stop -= map->start;
521 map->stop += skt->socket.io_offset;
522 map->start = skt->socket.io_offset;
523
524 return 0;
525}
526
527
528/*
529 * Implements the set_mem_map() operation for the in-kernel PCMCIA
530 * service (formerly SS_SetMemMap in Card Services). We configure
531 * the map speed as requested, but override the address ranges
532 * supplied by Card Services.
533 *
Pavel Machek4846d012005-10-14 15:59:02 -0700534 * Returns: 0 on success, -ERRNO on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100536static int soc_common_pcmcia_set_mem_map(
537 struct pcmcia_socket *sock, struct pccard_mem_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
539 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
540 struct resource *res;
541 unsigned short speed = map->speed;
542
543 debug(skt, 2, "map %u speed %u card_start %08x\n",
544 map->map, map->speed, map->card_start);
545 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100546 (map->flags == 0) ? "<NONE>" : "",
547 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
548 (map->flags & MAP_16BIT) ? "16BIT " : "",
549 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
550 (map->flags & MAP_0WS) ? "0WS " : "",
551 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
552 (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
553 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (map->map >= MAX_WIN)
556 return -EINVAL;
557
558 if (map->flags & MAP_ACTIVE) {
559 if (speed == 0)
560 speed = 300;
561 } else {
562 speed = 0;
563 }
564
565 if (map->flags & MAP_ATTRIB) {
566 res = &skt->res_attr;
567 skt->spd_attr[map->map] = speed;
568 skt->spd_mem[map->map] = 0;
569 } else {
570 res = &skt->res_mem;
571 skt->spd_attr[map->map] = 0;
572 skt->spd_mem[map->map] = speed;
573 }
574
575 skt->ops->set_timing(skt);
576
577 map->static_start = res->start + map->card_start;
578
579 return 0;
580}
581
582struct bittbl {
583 unsigned int mask;
584 const char *name;
585};
586
587static struct bittbl status_bits[] = {
588 { SS_WRPROT, "SS_WRPROT" },
589 { SS_BATDEAD, "SS_BATDEAD" },
590 { SS_BATWARN, "SS_BATWARN" },
591 { SS_READY, "SS_READY" },
592 { SS_DETECT, "SS_DETECT" },
593 { SS_POWERON, "SS_POWERON" },
594 { SS_STSCHG, "SS_STSCHG" },
595 { SS_3VCARD, "SS_3VCARD" },
596 { SS_XVCARD, "SS_XVCARD" },
597};
598
599static struct bittbl conf_bits[] = {
600 { SS_PWR_AUTO, "SS_PWR_AUTO" },
601 { SS_IOCARD, "SS_IOCARD" },
602 { SS_RESET, "SS_RESET" },
603 { SS_DMA_MODE, "SS_DMA_MODE" },
604 { SS_SPKR_ENA, "SS_SPKR_ENA" },
605 { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" },
606};
607
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100608static void dump_bits(char **p, const char *prefix,
609 unsigned int val, struct bittbl *bits, int sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 char *b = *p;
612 int i;
613
614 b += sprintf(b, "%-9s:", prefix);
615 for (i = 0; i < sz; i++)
616 if (val & bits[i].mask)
617 b += sprintf(b, " %s", bits[i].name);
618 *b++ = '\n';
619 *p = b;
620}
621
622/*
623 * Implements the /sys/class/pcmcia_socket/??/status file.
624 *
625 * Returns: the number of characters added to the buffer
626 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100627static ssize_t show_status(
628 struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 struct soc_pcmcia_socket *skt =
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200631 container_of(dev, struct soc_pcmcia_socket, socket.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 char *p = buf;
633
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100634 p += sprintf(p, "slot : %d\n", skt->nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 dump_bits(&p, "status", skt->status,
637 status_bits, ARRAY_SIZE(status_bits));
638 dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
639 status_bits, ARRAY_SIZE(status_bits));
640 dump_bits(&p, "cs_flags", skt->cs_state.flags,
641 conf_bits, ARRAY_SIZE(conf_bits));
642
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100643 p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
644 p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
645 p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
Russell King - ARM Linux66024db2009-03-29 22:45:26 +0100646 skt->socket.pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (skt->ops->show_timing)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100648 p += skt->ops->show_timing(skt, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 return p-buf;
651}
Alexey Dobriyane4a3c3f2007-02-13 22:39:27 -0800652static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654
655static struct pccard_operations soc_common_pcmcia_operations = {
656 .init = soc_common_pcmcia_sock_init,
657 .suspend = soc_common_pcmcia_suspend,
658 .get_status = soc_common_pcmcia_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 .set_socket = soc_common_pcmcia_set_socket,
660 .set_io_map = soc_common_pcmcia_set_io_map,
661 .set_mem_map = soc_common_pcmcia_set_mem_map,
662};
663
664
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000665static LIST_HEAD(soc_pcmcia_sockets);
Andrew Morton23d077e2008-05-01 04:34:54 -0700666static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668#ifdef CONFIG_CPU_FREQ
669static int
670soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
671{
672 struct soc_pcmcia_socket *skt;
673 struct cpufreq_freqs *freqs = data;
674 int ret = 0;
675
Andrew Morton23d077e2008-05-01 04:34:54 -0700676 mutex_lock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 list_for_each_entry(skt, &soc_pcmcia_sockets, node)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100678 if (skt->ops->frequency_change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 ret += skt->ops->frequency_change(skt, val, freqs);
Andrew Morton23d077e2008-05-01 04:34:54 -0700680 mutex_unlock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682 return ret;
683}
684
685static struct notifier_block soc_pcmcia_notifier_block = {
686 .notifier_call = soc_pcmcia_notifier
687};
688
689static int soc_pcmcia_cpufreq_register(void)
690{
691 int ret;
692
693 ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block,
694 CPUFREQ_TRANSITION_NOTIFIER);
695 if (ret < 0)
696 printk(KERN_ERR "Unable to register CPU frequency change "
697 "notifier for PCMCIA (%d)\n", ret);
698 return ret;
699}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000700fs_initcall(soc_pcmcia_cpufreq_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702static void soc_pcmcia_cpufreq_unregister(void)
703{
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100704 cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
705 CPUFREQ_TRANSITION_NOTIFIER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000707module_exit(soc_pcmcia_cpufreq_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709#endif
710
Russell Kinge0d21172011-12-19 14:07:31 +0000711void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
712 struct pcmcia_low_level *ops, struct device *dev)
713{
Russell Kingd9dc8782011-12-19 22:00:22 +0000714 int i;
715
Russell Kinge0d21172011-12-19 14:07:31 +0000716 skt->ops = ops;
717 skt->socket.owner = ops->owner;
718 skt->socket.dev.parent = dev;
719 skt->socket.pci_irq = NO_IRQ;
Russell Kingd9dc8782011-12-19 22:00:22 +0000720
721 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
722 skt->stat[i].gpio = -EINVAL;
Russell Kinge0d21172011-12-19 14:07:31 +0000723}
724EXPORT_SYMBOL(soc_pcmcia_init_one);
725
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000726void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
727{
728 mutex_lock(&soc_pcmcia_sockets_lock);
729 del_timer_sync(&skt->poll_timer);
730
731 pcmcia_unregister_socket(&skt->socket);
732
Russell Kingd9dc8782011-12-19 22:00:22 +0000733 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000734
Russell Kingd9dc8782011-12-19 22:00:22 +0000735 /* should not be required; violates some lowlevel drivers */
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000736 soc_common_pcmcia_config_skt(skt, &dead_socket);
737
738 list_del(&skt->node);
739 mutex_unlock(&soc_pcmcia_sockets_lock);
740
741 iounmap(skt->virt_io);
742 skt->virt_io = NULL;
743 release_resource(&skt->res_attr);
744 release_resource(&skt->res_mem);
745 release_resource(&skt->res_io);
746 release_resource(&skt->res_skt);
747}
748EXPORT_SYMBOL(soc_pcmcia_remove_one);
749
750int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
751{
752 int ret;
753
Vaishali Thakkardae6cda2015-02-11 16:25:38 +0530754 setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
755 (unsigned long)skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000756 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
757
758 ret = request_resource(&iomem_resource, &skt->res_skt);
759 if (ret)
760 goto out_err_1;
761
762 ret = request_resource(&skt->res_skt, &skt->res_io);
763 if (ret)
764 goto out_err_2;
765
766 ret = request_resource(&skt->res_skt, &skt->res_mem);
767 if (ret)
768 goto out_err_3;
769
770 ret = request_resource(&skt->res_skt, &skt->res_attr);
771 if (ret)
772 goto out_err_4;
773
774 skt->virt_io = ioremap(skt->res_io.start, 0x10000);
775 if (skt->virt_io == NULL) {
776 ret = -ENOMEM;
777 goto out_err_5;
778 }
779
780 mutex_lock(&soc_pcmcia_sockets_lock);
781
782 list_add(&skt->node, &soc_pcmcia_sockets);
783
784 /*
785 * We initialize default socket timing here, because
786 * we are not guaranteed to see a SetIOMap operation at
787 * runtime.
788 */
789 skt->ops->set_timing(skt);
790
Russell Kingd9dc8782011-12-19 22:00:22 +0000791 ret = soc_pcmcia_hw_init(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000792 if (ret)
793 goto out_err_6;
794
795 skt->socket.ops = &soc_common_pcmcia_operations;
796 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
797 skt->socket.resource_ops = &pccard_static_ops;
798 skt->socket.irq_mask = 0;
799 skt->socket.map_size = PAGE_SIZE;
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000800 skt->socket.io_offset = (unsigned long)skt->virt_io;
801
802 skt->status = soc_common_pcmcia_skt_state(skt);
803
804 ret = pcmcia_register_socket(&skt->socket);
805 if (ret)
806 goto out_err_7;
807
808 add_timer(&skt->poll_timer);
809
810 mutex_unlock(&soc_pcmcia_sockets_lock);
811
812 ret = device_create_file(&skt->socket.dev, &dev_attr_status);
813 if (ret)
814 goto out_err_8;
815
816 return ret;
817
818 out_err_8:
819 mutex_lock(&soc_pcmcia_sockets_lock);
820 del_timer_sync(&skt->poll_timer);
821 pcmcia_unregister_socket(&skt->socket);
822
823 out_err_7:
Russell Kingd9dc8782011-12-19 22:00:22 +0000824 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000825 out_err_6:
826 list_del(&skt->node);
827 mutex_unlock(&soc_pcmcia_sockets_lock);
828 iounmap(skt->virt_io);
829 out_err_5:
830 release_resource(&skt->res_attr);
831 out_err_4:
832 release_resource(&skt->res_mem);
833 out_err_3:
834 release_resource(&skt->res_io);
835 out_err_2:
836 release_resource(&skt->res_skt);
837 out_err_1:
838
839 return ret;
840}
841EXPORT_SYMBOL(soc_pcmcia_add_one);
842
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000843MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
844MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
845MODULE_LICENSE("Dual MPL/GPL");