blob: 4036454b27853d4f0dfb9b635e209ff539c17f53 [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 King7bfe4972016-08-31 08:49:45 +0100168 unsigned long flags = GPIOF_IN;
169
170 /* CD is active low by default */
171 if (i == SOC_STAT_CD)
172 flags |= GPIOF_ACTIVE_LOW;
173
Russell King59ecfef2016-09-04 21:50:47 +0100174 ret = devm_gpio_request_one(skt->socket.dev.parent,
Russell King7bfe4972016-08-31 08:49:45 +0100175 skt->stat[i].gpio, flags,
Russell King59ecfef2016-09-04 21:50:47 +0100176 skt->stat[i].name);
Russell Kingd9dc8782011-12-19 22:00:22 +0000177 if (ret) {
178 __soc_pcmcia_hw_shutdown(skt, i);
179 return ret;
180 }
181
Russell King45ca7532016-08-31 08:49:45 +0100182 skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
183 }
184
185 if (skt->stat[i].desc) {
186 int irq = gpiod_to_irq(skt->stat[i].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000187
Russell Kinga4941192016-08-31 11:17:50 +0100188 if (irq > 0) {
189 if (i == SOC_STAT_RDY)
190 skt->socket.pci_irq = irq;
191 else
192 skt->stat[i].irq = irq;
193 }
Russell Kingd9dc8782011-12-19 22:00:22 +0000194 }
195
196 if (skt->stat[i].irq) {
197 ret = request_irq(skt->stat[i].irq,
198 soc_common_pcmcia_interrupt,
199 IRQF_TRIGGER_NONE,
200 skt->stat[i].name, skt);
201 if (ret) {
Russell Kingd9dc8782011-12-19 22:00:22 +0000202 __soc_pcmcia_hw_shutdown(skt, i);
203 return ret;
204 }
205 }
206 }
207
208 return ret;
209}
210
211static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
212{
213 int i;
214
215 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
216 if (skt->stat[i].irq) {
217 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
218 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
219 }
220}
221
222static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
223{
224 int i;
225
226 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
227 if (skt->stat[i].irq)
228 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
229}
230
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
232{
233 struct pcmcia_state state;
234 unsigned int stat;
235
236 memset(&state, 0, sizeof(struct pcmcia_state));
237
Russell Kingd9dc8782011-12-19 22:00:22 +0000238 /* Make battery voltage state report 'good' */
239 state.bvd1 = 1;
240 state.bvd2 = 1;
241
Russell King45ca7532016-08-31 08:49:45 +0100242 if (skt->stat[SOC_STAT_CD].desc)
Russell King7bfe4972016-08-31 08:49:45 +0100243 state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc);
Russell King45ca7532016-08-31 08:49:45 +0100244 if (skt->stat[SOC_STAT_RDY].desc)
245 state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
246 if (skt->stat[SOC_STAT_BVD1].desc)
247 state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
248 if (skt->stat[SOC_STAT_BVD2].desc)
249 state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 skt->ops->socket_state(skt, &state);
252
253 stat = state.detect ? SS_DETECT : 0;
254 stat |= state.ready ? SS_READY : 0;
255 stat |= state.wrprot ? SS_WRPROT : 0;
256 stat |= state.vs_3v ? SS_3VCARD : 0;
257 stat |= state.vs_Xv ? SS_XVCARD : 0;
258
259 /* The power status of individual sockets is not available
260 * explicitly from the hardware, so we just remember the state
261 * and regurgitate it upon request:
262 */
263 stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
264
265 if (skt->cs_state.flags & SS_IOCARD)
Russell Kinga466ebd2016-08-31 08:49:43 +0100266 stat |= state.bvd1 ? 0 : SS_STSCHG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 else {
268 if (state.bvd1 == 0)
269 stat |= SS_BATDEAD;
270 else if (state.bvd2 == 0)
271 stat |= SS_BATWARN;
272 }
273 return stat;
274}
275
276/*
277 * soc_common_pcmcia_config_skt
278 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
279 *
280 * Convert PCMCIA socket state to our socket configure structure.
281 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100282static int soc_common_pcmcia_config_skt(
283 struct soc_pcmcia_socket *skt, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int ret;
286
287 ret = skt->ops->configure_socket(skt, state);
288 if (ret == 0) {
289 /*
290 * This really needs a better solution. The IRQ
291 * may or may not be claimed by the driver.
292 */
293 if (skt->irq_state != 1 && state->io_irq) {
294 skt->irq_state = 1;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200295 irq_set_irq_type(skt->socket.pci_irq,
296 IRQ_TYPE_EDGE_FALLING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 } else if (skt->irq_state == 1 && state->io_irq == 0) {
298 skt->irq_state = 0;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200299 irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301
302 skt->cs_state = *state;
303 }
304
305 if (ret < 0)
306 printk(KERN_ERR "soc_common_pcmcia: unable to configure "
307 "socket %d\n", skt->nr);
308
309 return ret;
310}
311
312/* soc_common_pcmcia_sock_init()
313 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
314 *
315 * (Re-)Initialise the socket, turning on status interrupts
316 * and PCMCIA bus. This must wait for power to stabilise
317 * so that the card status signals report correctly.
318 *
319 * Returns: 0
320 */
321static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
322{
323 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
324
325 debug(skt, 2, "initializing socket\n");
Jonathan Camerona747ce82011-07-13 15:54:56 +0100326 if (skt->ops->socket_init)
327 skt->ops->socket_init(skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000328 soc_pcmcia_hw_enable(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return 0;
330}
331
332
333/*
334 * soc_common_pcmcia_suspend()
335 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
336 *
337 * Remove power on the socket, disable IRQs from the card.
338 * Turn off status interrupts, and disable the PCMCIA bus.
339 *
340 * Returns: 0
341 */
342static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
343{
344 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
345
346 debug(skt, 2, "suspending socket\n");
347
Russell Kingd9dc8782011-12-19 22:00:22 +0000348 soc_pcmcia_hw_disable(skt);
Jonathan Camerona747ce82011-07-13 15:54:56 +0100349 if (skt->ops->socket_suspend)
350 skt->ops->socket_suspend(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
352 return 0;
353}
354
355static DEFINE_SPINLOCK(status_lock);
356
357static void soc_common_check_status(struct soc_pcmcia_socket *skt)
358{
359 unsigned int events;
360
361 debug(skt, 4, "entering PCMCIA monitoring thread\n");
362
363 do {
364 unsigned int status;
365 unsigned long flags;
366
367 status = soc_common_pcmcia_skt_state(skt);
368
369 spin_lock_irqsave(&status_lock, flags);
370 events = (status ^ skt->status) & skt->cs_state.csc_mask;
371 skt->status = status;
372 spin_unlock_irqrestore(&status_lock, flags);
373
374 debug(skt, 4, "events: %s%s%s%s%s%s\n",
375 events == 0 ? "<NONE>" : "",
376 events & SS_DETECT ? "DETECT " : "",
377 events & SS_READY ? "READY " : "",
378 events & SS_BATDEAD ? "BATDEAD " : "",
379 events & SS_BATWARN ? "BATWARN " : "",
380 events & SS_STSCHG ? "STSCHG " : "");
381
382 if (events)
383 pcmcia_parse_events(&skt->socket, events);
384 } while (events);
385}
386
387/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
388static void soc_common_pcmcia_poll_event(unsigned long dummy)
389{
390 struct soc_pcmcia_socket *skt = (struct soc_pcmcia_socket *)dummy;
391 debug(skt, 4, "polling for events\n");
392
393 mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
394
395 soc_common_check_status(skt);
396}
397
398
399/*
400 * Service routine for socket driver interrupts (requested by the
401 * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
402 * The actual interrupt-servicing work is performed by
403 * soc_common_pcmcia_thread(), largely because the Card Services event-
404 * handling code performs scheduling operations which cannot be
405 * executed from within an interrupt context.
406 */
David Howells7d12e782006-10-05 14:55:46 +0100407static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 struct soc_pcmcia_socket *skt = dev;
410
411 debug(skt, 3, "servicing IRQ %d\n", irq);
412
413 soc_common_check_status(skt);
414
415 return IRQ_HANDLED;
416}
417
418
419/*
420 * Implements the get_status() operation for the in-kernel PCMCIA
421 * service (formerly SS_GetStatus in Card Services). Essentially just
422 * fills in bits in `status' according to internal driver state or
423 * the value of the voltage detect chipselect register.
424 *
425 * As a debugging note, during card startup, the PCMCIA core issues
426 * three set_socket() commands in a row the first with RESET deasserted,
427 * the second with RESET asserted, and the last with RESET deasserted
428 * again. Following the third set_socket(), a get_status() command will
429 * be issued. The kernel is looking for the SS_READY flag (see
430 * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
431 *
432 * Returns: 0
433 */
434static int
435soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
436{
437 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
438
439 skt->status = soc_common_pcmcia_skt_state(skt);
440 *status = skt->status;
441
442 return 0;
443}
444
445
446/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 * Implements the set_socket() operation for the in-kernel PCMCIA
448 * service (formerly SS_SetSocket in Card Services). We more or
449 * less punt all of this work and let the kernel handle the details
450 * of power configuration, reset, &c. We also record the value of
451 * `state' in order to regurgitate it to the PCMCIA core later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100453static int soc_common_pcmcia_set_socket(
454 struct pcmcia_socket *sock, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
457
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100458 debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
459 (state->csc_mask == 0) ? "<NONE> " : "",
460 (state->csc_mask & SS_DETECT) ? "DETECT " : "",
461 (state->csc_mask & SS_READY) ? "READY " : "",
462 (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
463 (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
464 (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
465 (state->flags == 0) ? "<NONE> " : "",
466 (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
467 (state->flags & SS_IOCARD) ? "IOCARD " : "",
468 (state->flags & SS_RESET) ? "RESET " : "",
469 (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
470 (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 state->Vcc, state->Vpp, state->io_irq);
472
473 return soc_common_pcmcia_config_skt(skt, state);
474}
475
476
477/*
478 * Implements the set_io_map() operation for the in-kernel PCMCIA
479 * service (formerly SS_SetIOMap in Card Services). We configure
480 * the map speed as requested, but override the address ranges
481 * supplied by Card Services.
482 *
483 * Returns: 0 on success, -1 on error
484 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100485static int soc_common_pcmcia_set_io_map(
486 struct pcmcia_socket *sock, struct pccard_io_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
489 unsigned short speed = map->speed;
490
Wolfram Sang5f784332009-10-19 11:42:13 +0200491 debug(skt, 2, "map %u speed %u start 0x%08llx stop 0x%08llx\n",
492 map->map, map->speed, (unsigned long long)map->start,
493 (unsigned long long)map->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100495 (map->flags == 0) ? "<NONE>" : "",
496 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
497 (map->flags & MAP_16BIT) ? "16BIT " : "",
498 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
499 (map->flags & MAP_0WS) ? "0WS " : "",
500 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
501 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
502 (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
504 if (map->map >= MAX_IO_WIN) {
Harvey Harrison2e11cb42008-05-01 04:34:54 -0700505 printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 map->map);
507 return -1;
508 }
509
510 if (map->flags & MAP_ACTIVE) {
511 if (speed == 0)
512 speed = SOC_PCMCIA_IO_ACCESS;
513 } else {
514 speed = 0;
515 }
516
517 skt->spd_io[map->map] = speed;
518 skt->ops->set_timing(skt);
519
520 if (map->stop == 1)
521 map->stop = PAGE_SIZE-1;
522
523 map->stop -= map->start;
524 map->stop += skt->socket.io_offset;
525 map->start = skt->socket.io_offset;
526
527 return 0;
528}
529
530
531/*
532 * Implements the set_mem_map() operation for the in-kernel PCMCIA
533 * service (formerly SS_SetMemMap in Card Services). We configure
534 * the map speed as requested, but override the address ranges
535 * supplied by Card Services.
536 *
Pavel Machek4846d012005-10-14 15:59:02 -0700537 * Returns: 0 on success, -ERRNO on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100539static int soc_common_pcmcia_set_mem_map(
540 struct pcmcia_socket *sock, struct pccard_mem_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
543 struct resource *res;
544 unsigned short speed = map->speed;
545
546 debug(skt, 2, "map %u speed %u card_start %08x\n",
547 map->map, map->speed, map->card_start);
548 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100549 (map->flags == 0) ? "<NONE>" : "",
550 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
551 (map->flags & MAP_16BIT) ? "16BIT " : "",
552 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
553 (map->flags & MAP_0WS) ? "0WS " : "",
554 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
555 (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
556 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 if (map->map >= MAX_WIN)
559 return -EINVAL;
560
561 if (map->flags & MAP_ACTIVE) {
562 if (speed == 0)
563 speed = 300;
564 } else {
565 speed = 0;
566 }
567
568 if (map->flags & MAP_ATTRIB) {
569 res = &skt->res_attr;
570 skt->spd_attr[map->map] = speed;
571 skt->spd_mem[map->map] = 0;
572 } else {
573 res = &skt->res_mem;
574 skt->spd_attr[map->map] = 0;
575 skt->spd_mem[map->map] = speed;
576 }
577
578 skt->ops->set_timing(skt);
579
580 map->static_start = res->start + map->card_start;
581
582 return 0;
583}
584
585struct bittbl {
586 unsigned int mask;
587 const char *name;
588};
589
590static struct bittbl status_bits[] = {
591 { SS_WRPROT, "SS_WRPROT" },
592 { SS_BATDEAD, "SS_BATDEAD" },
593 { SS_BATWARN, "SS_BATWARN" },
594 { SS_READY, "SS_READY" },
595 { SS_DETECT, "SS_DETECT" },
596 { SS_POWERON, "SS_POWERON" },
597 { SS_STSCHG, "SS_STSCHG" },
598 { SS_3VCARD, "SS_3VCARD" },
599 { SS_XVCARD, "SS_XVCARD" },
600};
601
602static struct bittbl conf_bits[] = {
603 { SS_PWR_AUTO, "SS_PWR_AUTO" },
604 { SS_IOCARD, "SS_IOCARD" },
605 { SS_RESET, "SS_RESET" },
606 { SS_DMA_MODE, "SS_DMA_MODE" },
607 { SS_SPKR_ENA, "SS_SPKR_ENA" },
608 { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" },
609};
610
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100611static void dump_bits(char **p, const char *prefix,
612 unsigned int val, struct bittbl *bits, int sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
614 char *b = *p;
615 int i;
616
617 b += sprintf(b, "%-9s:", prefix);
618 for (i = 0; i < sz; i++)
619 if (val & bits[i].mask)
620 b += sprintf(b, " %s", bits[i].name);
621 *b++ = '\n';
622 *p = b;
623}
624
625/*
626 * Implements the /sys/class/pcmcia_socket/??/status file.
627 *
628 * Returns: the number of characters added to the buffer
629 */
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100630static ssize_t show_status(
631 struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
633 struct soc_pcmcia_socket *skt =
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200634 container_of(dev, struct soc_pcmcia_socket, socket.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 char *p = buf;
636
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100637 p += sprintf(p, "slot : %d\n", skt->nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 dump_bits(&p, "status", skt->status,
640 status_bits, ARRAY_SIZE(status_bits));
641 dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
642 status_bits, ARRAY_SIZE(status_bits));
643 dump_bits(&p, "cs_flags", skt->cs_state.flags,
644 conf_bits, ARRAY_SIZE(conf_bits));
645
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100646 p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
647 p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
648 p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
Russell King - ARM Linux66024db2009-03-29 22:45:26 +0100649 skt->socket.pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 if (skt->ops->show_timing)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100651 p += skt->ops->show_timing(skt, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 return p-buf;
654}
Alexey Dobriyane4a3c3f2007-02-13 22:39:27 -0800655static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657
658static struct pccard_operations soc_common_pcmcia_operations = {
659 .init = soc_common_pcmcia_sock_init,
660 .suspend = soc_common_pcmcia_suspend,
661 .get_status = soc_common_pcmcia_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 .set_socket = soc_common_pcmcia_set_socket,
663 .set_io_map = soc_common_pcmcia_set_io_map,
664 .set_mem_map = soc_common_pcmcia_set_mem_map,
665};
666
667
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000668static LIST_HEAD(soc_pcmcia_sockets);
Andrew Morton23d077e2008-05-01 04:34:54 -0700669static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671#ifdef CONFIG_CPU_FREQ
672static int
673soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data)
674{
675 struct soc_pcmcia_socket *skt;
676 struct cpufreq_freqs *freqs = data;
677 int ret = 0;
678
Andrew Morton23d077e2008-05-01 04:34:54 -0700679 mutex_lock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 list_for_each_entry(skt, &soc_pcmcia_sockets, node)
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100681 if (skt->ops->frequency_change)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 ret += skt->ops->frequency_change(skt, val, freqs);
Andrew Morton23d077e2008-05-01 04:34:54 -0700683 mutex_unlock(&soc_pcmcia_sockets_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 return ret;
686}
687
688static struct notifier_block soc_pcmcia_notifier_block = {
689 .notifier_call = soc_pcmcia_notifier
690};
691
692static int soc_pcmcia_cpufreq_register(void)
693{
694 int ret;
695
696 ret = cpufreq_register_notifier(&soc_pcmcia_notifier_block,
697 CPUFREQ_TRANSITION_NOTIFIER);
698 if (ret < 0)
699 printk(KERN_ERR "Unable to register CPU frequency change "
700 "notifier for PCMCIA (%d)\n", ret);
701 return ret;
702}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000703fs_initcall(soc_pcmcia_cpufreq_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705static void soc_pcmcia_cpufreq_unregister(void)
706{
Marcelo Roberto Jimenez17b38eb2010-10-18 22:39:05 +0100707 cpufreq_unregister_notifier(&soc_pcmcia_notifier_block,
708 CPUFREQ_TRANSITION_NOTIFIER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000710module_exit(soc_pcmcia_cpufreq_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712#endif
713
Russell Kinge0d21172011-12-19 14:07:31 +0000714void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
715 struct pcmcia_low_level *ops, struct device *dev)
716{
Russell Kingd9dc8782011-12-19 22:00:22 +0000717 int i;
718
Russell Kinge0d21172011-12-19 14:07:31 +0000719 skt->ops = ops;
720 skt->socket.owner = ops->owner;
721 skt->socket.dev.parent = dev;
722 skt->socket.pci_irq = NO_IRQ;
Russell Kingd9dc8782011-12-19 22:00:22 +0000723
724 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
725 skt->stat[i].gpio = -EINVAL;
Russell Kinge0d21172011-12-19 14:07:31 +0000726}
727EXPORT_SYMBOL(soc_pcmcia_init_one);
728
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000729void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
730{
731 mutex_lock(&soc_pcmcia_sockets_lock);
732 del_timer_sync(&skt->poll_timer);
733
734 pcmcia_unregister_socket(&skt->socket);
735
Russell Kingd9dc8782011-12-19 22:00:22 +0000736 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000737
Russell Kingd9dc8782011-12-19 22:00:22 +0000738 /* should not be required; violates some lowlevel drivers */
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000739 soc_common_pcmcia_config_skt(skt, &dead_socket);
740
741 list_del(&skt->node);
742 mutex_unlock(&soc_pcmcia_sockets_lock);
743
744 iounmap(skt->virt_io);
745 skt->virt_io = NULL;
746 release_resource(&skt->res_attr);
747 release_resource(&skt->res_mem);
748 release_resource(&skt->res_io);
749 release_resource(&skt->res_skt);
750}
751EXPORT_SYMBOL(soc_pcmcia_remove_one);
752
753int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
754{
755 int ret;
756
Vaishali Thakkardae6cda2015-02-11 16:25:38 +0530757 setup_timer(&skt->poll_timer, soc_common_pcmcia_poll_event,
758 (unsigned long)skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000759 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
760
761 ret = request_resource(&iomem_resource, &skt->res_skt);
762 if (ret)
763 goto out_err_1;
764
765 ret = request_resource(&skt->res_skt, &skt->res_io);
766 if (ret)
767 goto out_err_2;
768
769 ret = request_resource(&skt->res_skt, &skt->res_mem);
770 if (ret)
771 goto out_err_3;
772
773 ret = request_resource(&skt->res_skt, &skt->res_attr);
774 if (ret)
775 goto out_err_4;
776
777 skt->virt_io = ioremap(skt->res_io.start, 0x10000);
778 if (skt->virt_io == NULL) {
779 ret = -ENOMEM;
780 goto out_err_5;
781 }
782
783 mutex_lock(&soc_pcmcia_sockets_lock);
784
785 list_add(&skt->node, &soc_pcmcia_sockets);
786
787 /*
788 * We initialize default socket timing here, because
789 * we are not guaranteed to see a SetIOMap operation at
790 * runtime.
791 */
792 skt->ops->set_timing(skt);
793
Russell Kingd9dc8782011-12-19 22:00:22 +0000794 ret = soc_pcmcia_hw_init(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000795 if (ret)
796 goto out_err_6;
797
798 skt->socket.ops = &soc_common_pcmcia_operations;
799 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
800 skt->socket.resource_ops = &pccard_static_ops;
801 skt->socket.irq_mask = 0;
802 skt->socket.map_size = PAGE_SIZE;
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000803 skt->socket.io_offset = (unsigned long)skt->virt_io;
804
805 skt->status = soc_common_pcmcia_skt_state(skt);
806
807 ret = pcmcia_register_socket(&skt->socket);
808 if (ret)
809 goto out_err_7;
810
811 add_timer(&skt->poll_timer);
812
813 mutex_unlock(&soc_pcmcia_sockets_lock);
814
815 ret = device_create_file(&skt->socket.dev, &dev_attr_status);
816 if (ret)
817 goto out_err_8;
818
819 return ret;
820
821 out_err_8:
822 mutex_lock(&soc_pcmcia_sockets_lock);
823 del_timer_sync(&skt->poll_timer);
824 pcmcia_unregister_socket(&skt->socket);
825
826 out_err_7:
Russell Kingd9dc8782011-12-19 22:00:22 +0000827 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000828 out_err_6:
829 list_del(&skt->node);
830 mutex_unlock(&soc_pcmcia_sockets_lock);
831 iounmap(skt->virt_io);
832 out_err_5:
833 release_resource(&skt->res_attr);
834 out_err_4:
835 release_resource(&skt->res_mem);
836 out_err_3:
837 release_resource(&skt->res_io);
838 out_err_2:
839 release_resource(&skt->res_skt);
840 out_err_1:
841
842 return ret;
843}
844EXPORT_SYMBOL(soc_pcmcia_add_one);
845
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000846MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
847MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
848MODULE_LICENSE("Dual MPL/GPL");