blob: 3a8c84bb174d73992570cd89a0f8ea4c3fce1983 [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 Jimenez17b38ebb2010-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 Jimenez17b38ebb2010-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>
Russell Kingac61b602016-08-31 08:49:46 +010046#include <linux/regulator/consumer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/spinlock.h>
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +010048#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Russell Kinga09e64f2008-08-05 16:14:15 +010050#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include "soc_common.h"
53
Russell Kingd9dc8782011-12-19 22:00:22 +000054static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev);
55
Dominik Brodowski7d16b652008-08-02 21:02:01 +020056#ifdef CONFIG_PCMCIA_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58static int pc_debug;
59module_param(pc_debug, int, 0644);
60
61void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
62 int lvl, const char *fmt, ...)
63{
Joe Perches106665d2010-11-09 17:14:01 -080064 struct va_format vaf;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 va_list args;
66 if (pc_debug > lvl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 va_start(args, fmt);
Joe Perches106665d2010-11-09 17:14:01 -080068
69 vaf.fmt = fmt;
70 vaf.va = &args;
71
72 printk(KERN_DEBUG "skt%u: %s: %pV", skt->nr, func, &vaf);
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 va_end(args);
75 }
76}
Marcelo Roberto Jimenezb9f515e2010-10-18 22:38:08 +010077EXPORT_SYMBOL(soc_pcmcia_debug);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79#endif
80
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +010081#define to_soc_pcmcia_socket(x) \
82 container_of(x, struct soc_pcmcia_socket, socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Russell Kingac61b602016-08-31 08:49:46 +010084int soc_pcmcia_regulator_set(struct soc_pcmcia_socket *skt,
85 struct soc_pcmcia_regulator *r, int v)
86{
87 bool on;
88 int ret;
89
90 if (!r->reg)
91 return 0;
92
93 on = v != 0;
94 if (r->on == on)
95 return 0;
96
97 if (on) {
98 ret = regulator_set_voltage(r->reg, v * 100000, v * 100000);
99 if (ret) {
100 int vout = regulator_get_voltage(r->reg) / 100000;
101
102 dev_warn(&skt->socket.dev,
103 "CS requested %s=%u.%uV, applying %u.%uV\n",
104 r == &skt->vcc ? "Vcc" : "Vpp",
105 v / 10, v % 10, vout / 10, vout % 10);
106 }
107
108 ret = regulator_enable(r->reg);
109 } else {
Arnd Bergmann75ed2682016-11-10 17:44:53 +0100110 ret = regulator_disable(r->reg);
Russell Kingac61b602016-08-31 08:49:46 +0100111 }
112 if (ret == 0)
113 r->on = on;
114
115 return ret;
116}
117EXPORT_SYMBOL_GPL(soc_pcmcia_regulator_set);
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static unsigned short
120calc_speed(unsigned short *spds, int num, unsigned short dflt)
121{
122 unsigned short speed = 0;
123 int i;
124
125 for (i = 0; i < num; i++)
126 if (speed < spds[i])
127 speed = spds[i];
128 if (speed == 0)
129 speed = dflt;
130
131 return speed;
132}
133
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100134void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt,
135 struct soc_pcmcia_timing *timing)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100137 timing->io =
138 calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
139 timing->mem =
140 calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
141 timing->attr =
142 calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143}
144EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
145
Russell Kingd9dc8782011-12-19 22:00:22 +0000146static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
147 unsigned int nr)
148{
149 unsigned int i;
150
Russell King59ecfef2016-09-04 21:50:47 +0100151 for (i = 0; i < nr; i++)
Russell Kingd9dc8782011-12-19 22:00:22 +0000152 if (skt->stat[i].irq)
153 free_irq(skt->stat[i].irq, skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000154
155 if (skt->ops->hw_shutdown)
156 skt->ops->hw_shutdown(skt);
Dmitry Eremin-Solenikov0821c3b2014-12-03 18:37:10 +0100157
158 clk_disable_unprepare(skt->clk);
Russell Kingd9dc8782011-12-19 22:00:22 +0000159}
160
161static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
162{
163 __soc_pcmcia_hw_shutdown(skt, ARRAY_SIZE(skt->stat));
164}
165
Russell King45ca7532016-08-31 08:49:45 +0100166int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
167{
168 struct device *dev = skt->socket.dev.parent;
169 struct gpio_desc *desc;
170 int i;
171
172 for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
173 if (!skt->stat[i].name)
174 continue;
175
176 desc = devm_gpiod_get(dev, skt->stat[i].name, GPIOD_IN);
177 if (IS_ERR(desc)) {
178 dev_err(dev, "Failed to get GPIO for %s: %ld\n",
179 skt->stat[i].name, PTR_ERR(desc));
180 return PTR_ERR(desc);
181 }
182
183 skt->stat[i].desc = desc;
184 }
185
186 return 0;
187}
188EXPORT_SYMBOL_GPL(soc_pcmcia_request_gpiods);
189
Russell Kingd9dc8782011-12-19 22:00:22 +0000190static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
191{
192 int ret = 0, i;
193
Arvind Yadavd3fdd702017-06-01 16:17:10 +0530194 ret = clk_prepare_enable(skt->clk);
195 if (ret)
196 return ret;
Dmitry Eremin-Solenikov0821c3b2014-12-03 18:37:10 +0100197
Russell Kingd9dc8782011-12-19 22:00:22 +0000198 if (skt->ops->hw_init) {
199 ret = skt->ops->hw_init(skt);
Arvind Yadavd3fdd702017-06-01 16:17:10 +0530200 if (ret) {
201 clk_disable_unprepare(skt->clk);
Russell Kingd9dc8782011-12-19 22:00:22 +0000202 return ret;
Arvind Yadavd3fdd702017-06-01 16:17:10 +0530203 }
Russell Kingd9dc8782011-12-19 22:00:22 +0000204 }
205
206 for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
207 if (gpio_is_valid(skt->stat[i].gpio)) {
Russell King7bfe4972016-08-31 08:49:45 +0100208 unsigned long flags = GPIOF_IN;
209
210 /* CD is active low by default */
211 if (i == SOC_STAT_CD)
212 flags |= GPIOF_ACTIVE_LOW;
213
Russell King59ecfef2016-09-04 21:50:47 +0100214 ret = devm_gpio_request_one(skt->socket.dev.parent,
Russell King7bfe4972016-08-31 08:49:45 +0100215 skt->stat[i].gpio, flags,
Russell King59ecfef2016-09-04 21:50:47 +0100216 skt->stat[i].name);
Russell Kingd9dc8782011-12-19 22:00:22 +0000217 if (ret) {
218 __soc_pcmcia_hw_shutdown(skt, i);
219 return ret;
220 }
221
Russell King45ca7532016-08-31 08:49:45 +0100222 skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio);
223 }
224
Russell King58052712016-08-31 11:28:19 +0100225 if (i < SOC_STAT_VS1 && skt->stat[i].desc) {
Russell King45ca7532016-08-31 08:49:45 +0100226 int irq = gpiod_to_irq(skt->stat[i].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000227
Russell Kinga49411912016-08-31 11:17:50 +0100228 if (irq > 0) {
229 if (i == SOC_STAT_RDY)
230 skt->socket.pci_irq = irq;
231 else
232 skt->stat[i].irq = irq;
233 }
Russell Kingd9dc8782011-12-19 22:00:22 +0000234 }
235
236 if (skt->stat[i].irq) {
237 ret = request_irq(skt->stat[i].irq,
238 soc_common_pcmcia_interrupt,
239 IRQF_TRIGGER_NONE,
240 skt->stat[i].name, skt);
241 if (ret) {
Russell Kingd9dc8782011-12-19 22:00:22 +0000242 __soc_pcmcia_hw_shutdown(skt, i);
243 return ret;
244 }
245 }
246 }
247
248 return ret;
249}
250
251static void soc_pcmcia_hw_enable(struct soc_pcmcia_socket *skt)
252{
253 int i;
254
255 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
256 if (skt->stat[i].irq) {
257 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_RISING);
258 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_EDGE_BOTH);
259 }
260}
261
262static void soc_pcmcia_hw_disable(struct soc_pcmcia_socket *skt)
263{
264 int i;
265
266 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
267 if (skt->stat[i].irq)
268 irq_set_irq_type(skt->stat[i].irq, IRQ_TYPE_NONE);
269}
270
Russell Kinga1d05002016-08-31 08:49:46 +0100271/*
272 * The CF 3.0 specification says that cards tie VS1 to ground and leave
273 * VS2 open. Many implementations do not wire up the VS signals, so we
274 * provide hard-coded values as per the CF 3.0 spec.
275 */
276void soc_common_cf_socket_state(struct soc_pcmcia_socket *skt,
277 struct pcmcia_state *state)
278{
279 state->vs_3v = 1;
280}
281EXPORT_SYMBOL_GPL(soc_common_cf_socket_state);
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
284{
285 struct pcmcia_state state;
286 unsigned int stat;
287
288 memset(&state, 0, sizeof(struct pcmcia_state));
289
Russell Kingd9dc8782011-12-19 22:00:22 +0000290 /* Make battery voltage state report 'good' */
291 state.bvd1 = 1;
292 state.bvd2 = 1;
293
Russell King45ca7532016-08-31 08:49:45 +0100294 if (skt->stat[SOC_STAT_CD].desc)
Russell King7bfe4972016-08-31 08:49:45 +0100295 state.detect = !!gpiod_get_value(skt->stat[SOC_STAT_CD].desc);
Russell King45ca7532016-08-31 08:49:45 +0100296 if (skt->stat[SOC_STAT_RDY].desc)
297 state.ready = !!gpiod_get_value(skt->stat[SOC_STAT_RDY].desc);
298 if (skt->stat[SOC_STAT_BVD1].desc)
299 state.bvd1 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD1].desc);
300 if (skt->stat[SOC_STAT_BVD2].desc)
301 state.bvd2 = !!gpiod_get_value(skt->stat[SOC_STAT_BVD2].desc);
Russell King58052712016-08-31 11:28:19 +0100302 if (skt->stat[SOC_STAT_VS1].desc)
303 state.vs_3v = !!gpiod_get_value(skt->stat[SOC_STAT_VS1].desc);
304 if (skt->stat[SOC_STAT_VS2].desc)
305 state.vs_Xv = !!gpiod_get_value(skt->stat[SOC_STAT_VS2].desc);
Russell Kingd9dc8782011-12-19 22:00:22 +0000306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 skt->ops->socket_state(skt, &state);
308
309 stat = state.detect ? SS_DETECT : 0;
310 stat |= state.ready ? SS_READY : 0;
311 stat |= state.wrprot ? SS_WRPROT : 0;
312 stat |= state.vs_3v ? SS_3VCARD : 0;
313 stat |= state.vs_Xv ? SS_XVCARD : 0;
314
315 /* The power status of individual sockets is not available
316 * explicitly from the hardware, so we just remember the state
317 * and regurgitate it upon request:
318 */
319 stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
320
321 if (skt->cs_state.flags & SS_IOCARD)
Russell Kinga466ebd2016-08-31 08:49:43 +0100322 stat |= state.bvd1 ? 0 : SS_STSCHG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 else {
324 if (state.bvd1 == 0)
325 stat |= SS_BATDEAD;
326 else if (state.bvd2 == 0)
327 stat |= SS_BATWARN;
328 }
329 return stat;
330}
331
332/*
333 * soc_common_pcmcia_config_skt
334 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
335 *
336 * Convert PCMCIA socket state to our socket configure structure.
337 */
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100338static int soc_common_pcmcia_config_skt(
339 struct soc_pcmcia_socket *skt, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
341 int ret;
342
343 ret = skt->ops->configure_socket(skt, state);
Russell King6ac95d82016-08-31 08:49:46 +0100344 if (ret < 0) {
345 pr_err("soc_common_pcmcia: unable to configure socket %d\n",
346 skt->nr);
347 /* restore the previous state */
348 WARN_ON(skt->ops->configure_socket(skt, &skt->cs_state));
349 return ret;
350 }
351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (ret == 0) {
Russell King535e0ab2016-08-31 08:49:45 +0100353 struct gpio_desc *descs[2];
Janusz Krzysztofikb9762be2018-09-05 23:50:05 +0200354 DECLARE_BITMAP(values, 2);
355 int n = 0;
Russell King535e0ab2016-08-31 08:49:45 +0100356
357 if (skt->gpio_reset) {
358 descs[n] = skt->gpio_reset;
Janusz Krzysztofikb9762be2018-09-05 23:50:05 +0200359 __assign_bit(n++, values, state->flags & SS_RESET);
Russell King535e0ab2016-08-31 08:49:45 +0100360 }
361 if (skt->gpio_bus_enable) {
362 descs[n] = skt->gpio_bus_enable;
Janusz Krzysztofikb9762be2018-09-05 23:50:05 +0200363 __assign_bit(n++, values, state->flags & SS_OUTPUT_ENA);
Russell King535e0ab2016-08-31 08:49:45 +0100364 }
365
366 if (n)
Janusz Krzysztofik77588c12018-09-05 23:50:07 +0200367 gpiod_set_array_value_cansleep(n, descs, NULL, values);
Russell King535e0ab2016-08-31 08:49:45 +0100368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 /*
370 * This really needs a better solution. The IRQ
371 * may or may not be claimed by the driver.
372 */
373 if (skt->irq_state != 1 && state->io_irq) {
374 skt->irq_state = 1;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200375 irq_set_irq_type(skt->socket.pci_irq,
376 IRQ_TYPE_EDGE_FALLING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 } else if (skt->irq_state == 1 && state->io_irq == 0) {
378 skt->irq_state = 0;
Thomas Gleixnerdced35a2011-03-28 17:49:12 +0200379 irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381
382 skt->cs_state = *state;
383 }
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return ret;
386}
387
388/* soc_common_pcmcia_sock_init()
389 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
390 *
391 * (Re-)Initialise the socket, turning on status interrupts
392 * and PCMCIA bus. This must wait for power to stabilise
393 * so that the card status signals report correctly.
394 *
395 * Returns: 0
396 */
397static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
398{
399 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
400
401 debug(skt, 2, "initializing socket\n");
Jonathan Camerona747ce82011-07-13 15:54:56 +0100402 if (skt->ops->socket_init)
403 skt->ops->socket_init(skt);
Russell Kingd9dc8782011-12-19 22:00:22 +0000404 soc_pcmcia_hw_enable(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return 0;
406}
407
408
409/*
410 * soc_common_pcmcia_suspend()
411 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
412 *
413 * Remove power on the socket, disable IRQs from the card.
414 * Turn off status interrupts, and disable the PCMCIA bus.
415 *
416 * Returns: 0
417 */
418static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
419{
420 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
421
422 debug(skt, 2, "suspending socket\n");
423
Russell Kingd9dc8782011-12-19 22:00:22 +0000424 soc_pcmcia_hw_disable(skt);
Jonathan Camerona747ce82011-07-13 15:54:56 +0100425 if (skt->ops->socket_suspend)
426 skt->ops->socket_suspend(skt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 return 0;
429}
430
431static DEFINE_SPINLOCK(status_lock);
432
433static void soc_common_check_status(struct soc_pcmcia_socket *skt)
434{
435 unsigned int events;
436
437 debug(skt, 4, "entering PCMCIA monitoring thread\n");
438
439 do {
440 unsigned int status;
441 unsigned long flags;
442
443 status = soc_common_pcmcia_skt_state(skt);
444
445 spin_lock_irqsave(&status_lock, flags);
446 events = (status ^ skt->status) & skt->cs_state.csc_mask;
447 skt->status = status;
448 spin_unlock_irqrestore(&status_lock, flags);
449
450 debug(skt, 4, "events: %s%s%s%s%s%s\n",
451 events == 0 ? "<NONE>" : "",
452 events & SS_DETECT ? "DETECT " : "",
453 events & SS_READY ? "READY " : "",
454 events & SS_BATDEAD ? "BATDEAD " : "",
455 events & SS_BATWARN ? "BATWARN " : "",
456 events & SS_STSCHG ? "STSCHG " : "");
457
458 if (events)
459 pcmcia_parse_events(&skt->socket, events);
460 } while (events);
461}
462
463/* Let's poll for events in addition to IRQs since IRQ only is unreliable... */
Kees Cook41760d02017-10-21 12:09:17 -0700464static void soc_common_pcmcia_poll_event(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Kees Cook41760d02017-10-21 12:09:17 -0700466 struct soc_pcmcia_socket *skt = from_timer(skt, t, poll_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 debug(skt, 4, "polling for events\n");
468
469 mod_timer(&skt->poll_timer, jiffies + SOC_PCMCIA_POLL_PERIOD);
470
471 soc_common_check_status(skt);
472}
473
474
475/*
476 * Service routine for socket driver interrupts (requested by the
477 * low-level PCMCIA init() operation via soc_common_pcmcia_thread()).
478 * The actual interrupt-servicing work is performed by
479 * soc_common_pcmcia_thread(), largely because the Card Services event-
480 * handling code performs scheduling operations which cannot be
481 * executed from within an interrupt context.
482 */
David Howells7d12e782006-10-05 14:55:46 +0100483static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct soc_pcmcia_socket *skt = dev;
486
487 debug(skt, 3, "servicing IRQ %d\n", irq);
488
489 soc_common_check_status(skt);
490
491 return IRQ_HANDLED;
492}
493
494
495/*
496 * Implements the get_status() operation for the in-kernel PCMCIA
497 * service (formerly SS_GetStatus in Card Services). Essentially just
498 * fills in bits in `status' according to internal driver state or
499 * the value of the voltage detect chipselect register.
500 *
501 * As a debugging note, during card startup, the PCMCIA core issues
502 * three set_socket() commands in a row the first with RESET deasserted,
503 * the second with RESET asserted, and the last with RESET deasserted
504 * again. Following the third set_socket(), a get_status() command will
505 * be issued. The kernel is looking for the SS_READY flag (see
506 * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
507 *
508 * Returns: 0
509 */
510static int
511soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
512{
513 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
514
515 skt->status = soc_common_pcmcia_skt_state(skt);
516 *status = skt->status;
517
518 return 0;
519}
520
521
522/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 * Implements the set_socket() operation for the in-kernel PCMCIA
524 * service (formerly SS_SetSocket in Card Services). We more or
525 * less punt all of this work and let the kernel handle the details
526 * of power configuration, reset, &c. We also record the value of
527 * `state' in order to regurgitate it to the PCMCIA core later.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 */
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100529static int soc_common_pcmcia_set_socket(
530 struct pcmcia_socket *sock, socket_state_t *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
532 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
533
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100534 debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n",
535 (state->csc_mask == 0) ? "<NONE> " : "",
536 (state->csc_mask & SS_DETECT) ? "DETECT " : "",
537 (state->csc_mask & SS_READY) ? "READY " : "",
538 (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "",
539 (state->csc_mask & SS_BATWARN) ? "BATWARN " : "",
540 (state->csc_mask & SS_STSCHG) ? "STSCHG " : "",
541 (state->flags == 0) ? "<NONE> " : "",
542 (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "",
543 (state->flags & SS_IOCARD) ? "IOCARD " : "",
544 (state->flags & SS_RESET) ? "RESET " : "",
545 (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "",
546 (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 state->Vcc, state->Vpp, state->io_irq);
548
549 return soc_common_pcmcia_config_skt(skt, state);
550}
551
552
553/*
554 * Implements the set_io_map() operation for the in-kernel PCMCIA
555 * service (formerly SS_SetIOMap in Card Services). We configure
556 * the map speed as requested, but override the address ranges
557 * supplied by Card Services.
558 *
559 * Returns: 0 on success, -1 on error
560 */
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100561static int soc_common_pcmcia_set_io_map(
562 struct pcmcia_socket *sock, struct pccard_io_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
565 unsigned short speed = map->speed;
566
Wolfram Sang5f784332009-10-19 11:42:13 +0200567 debug(skt, 2, "map %u speed %u start 0x%08llx stop 0x%08llx\n",
568 map->map, map->speed, (unsigned long long)map->start,
569 (unsigned long long)map->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100571 (map->flags == 0) ? "<NONE>" : "",
572 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
573 (map->flags & MAP_16BIT) ? "16BIT " : "",
574 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
575 (map->flags & MAP_0WS) ? "0WS " : "",
576 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
577 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
578 (map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 if (map->map >= MAX_IO_WIN) {
Harvey Harrison2e11cb42008-05-01 04:34:54 -0700581 printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 map->map);
583 return -1;
584 }
585
586 if (map->flags & MAP_ACTIVE) {
587 if (speed == 0)
588 speed = SOC_PCMCIA_IO_ACCESS;
589 } else {
590 speed = 0;
591 }
592
593 skt->spd_io[map->map] = speed;
594 skt->ops->set_timing(skt);
595
596 if (map->stop == 1)
597 map->stop = PAGE_SIZE-1;
598
599 map->stop -= map->start;
600 map->stop += skt->socket.io_offset;
601 map->start = skt->socket.io_offset;
602
603 return 0;
604}
605
606
607/*
608 * Implements the set_mem_map() operation for the in-kernel PCMCIA
609 * service (formerly SS_SetMemMap in Card Services). We configure
610 * the map speed as requested, but override the address ranges
611 * supplied by Card Services.
612 *
Pavel Machek4846d012005-10-14 15:59:02 -0700613 * Returns: 0 on success, -ERRNO on error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 */
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100615static int soc_common_pcmcia_set_mem_map(
616 struct pcmcia_socket *sock, struct pccard_mem_map *map)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
619 struct resource *res;
620 unsigned short speed = map->speed;
621
622 debug(skt, 2, "map %u speed %u card_start %08x\n",
623 map->map, map->speed, map->card_start);
624 debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n",
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100625 (map->flags == 0) ? "<NONE>" : "",
626 (map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
627 (map->flags & MAP_16BIT) ? "16BIT " : "",
628 (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
629 (map->flags & MAP_0WS) ? "0WS " : "",
630 (map->flags & MAP_WRPROT) ? "WRPROT " : "",
631 (map->flags & MAP_ATTRIB) ? "ATTRIB " : "",
632 (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 if (map->map >= MAX_WIN)
635 return -EINVAL;
636
637 if (map->flags & MAP_ACTIVE) {
638 if (speed == 0)
639 speed = 300;
640 } else {
641 speed = 0;
642 }
643
644 if (map->flags & MAP_ATTRIB) {
645 res = &skt->res_attr;
646 skt->spd_attr[map->map] = speed;
647 skt->spd_mem[map->map] = 0;
648 } else {
649 res = &skt->res_mem;
650 skt->spd_attr[map->map] = 0;
651 skt->spd_mem[map->map] = speed;
652 }
653
654 skt->ops->set_timing(skt);
655
656 map->static_start = res->start + map->card_start;
657
658 return 0;
659}
660
661struct bittbl {
662 unsigned int mask;
663 const char *name;
664};
665
666static struct bittbl status_bits[] = {
667 { SS_WRPROT, "SS_WRPROT" },
668 { SS_BATDEAD, "SS_BATDEAD" },
669 { SS_BATWARN, "SS_BATWARN" },
670 { SS_READY, "SS_READY" },
671 { SS_DETECT, "SS_DETECT" },
672 { SS_POWERON, "SS_POWERON" },
673 { SS_STSCHG, "SS_STSCHG" },
674 { SS_3VCARD, "SS_3VCARD" },
675 { SS_XVCARD, "SS_XVCARD" },
676};
677
678static struct bittbl conf_bits[] = {
679 { SS_PWR_AUTO, "SS_PWR_AUTO" },
680 { SS_IOCARD, "SS_IOCARD" },
681 { SS_RESET, "SS_RESET" },
682 { SS_DMA_MODE, "SS_DMA_MODE" },
683 { SS_SPKR_ENA, "SS_SPKR_ENA" },
684 { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" },
685};
686
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100687static void dump_bits(char **p, const char *prefix,
688 unsigned int val, struct bittbl *bits, int sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
690 char *b = *p;
691 int i;
692
693 b += sprintf(b, "%-9s:", prefix);
694 for (i = 0; i < sz; i++)
695 if (val & bits[i].mask)
696 b += sprintf(b, " %s", bits[i].name);
697 *b++ = '\n';
698 *p = b;
699}
700
701/*
702 * Implements the /sys/class/pcmcia_socket/??/status file.
703 *
704 * Returns: the number of characters added to the buffer
705 */
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100706static ssize_t show_status(
707 struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 struct soc_pcmcia_socket *skt =
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200710 container_of(dev, struct soc_pcmcia_socket, socket.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 char *p = buf;
712
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100713 p += sprintf(p, "slot : %d\n", skt->nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 dump_bits(&p, "status", skt->status,
716 status_bits, ARRAY_SIZE(status_bits));
717 dump_bits(&p, "csc_mask", skt->cs_state.csc_mask,
718 status_bits, ARRAY_SIZE(status_bits));
719 dump_bits(&p, "cs_flags", skt->cs_state.flags,
720 conf_bits, ARRAY_SIZE(conf_bits));
721
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100722 p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc);
723 p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp);
724 p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq,
Russell King - ARM Linux66024db2009-03-29 22:45:26 +0100725 skt->socket.pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (skt->ops->show_timing)
Marcelo Roberto Jimenez17b38ebb2010-10-18 22:39:05 +0100727 p += skt->ops->show_timing(skt, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 return p-buf;
730}
Alexey Dobriyane4a3c3f2007-02-13 22:39:27 -0800731static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733
734static struct pccard_operations soc_common_pcmcia_operations = {
735 .init = soc_common_pcmcia_sock_init,
736 .suspend = soc_common_pcmcia_suspend,
737 .get_status = soc_common_pcmcia_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 .set_socket = soc_common_pcmcia_set_socket,
739 .set_io_map = soc_common_pcmcia_set_io_map,
740 .set_mem_map = soc_common_pcmcia_set_mem_map,
741};
742
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744#ifdef CONFIG_CPU_FREQ
Russell Kingfb8c9952016-08-31 08:49:46 +0100745static int soc_common_pcmcia_cpufreq_nb(struct notifier_block *nb,
746 unsigned long val, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747{
Russell Kingfb8c9952016-08-31 08:49:46 +0100748 struct soc_pcmcia_socket *skt = container_of(nb, struct soc_pcmcia_socket, cpufreq_nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 struct cpufreq_freqs *freqs = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Russell Kingfb8c9952016-08-31 08:49:46 +0100751 return skt->ops->frequency_change(skt, val, freqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753#endif
754
Russell Kinge0d21172011-12-19 14:07:31 +0000755void soc_pcmcia_init_one(struct soc_pcmcia_socket *skt,
Russell Kingc8f9ce52016-08-31 08:49:46 +0100756 const struct pcmcia_low_level *ops, struct device *dev)
Russell Kinge0d21172011-12-19 14:07:31 +0000757{
Russell Kingd9dc8782011-12-19 22:00:22 +0000758 int i;
759
Russell Kinge0d21172011-12-19 14:07:31 +0000760 skt->ops = ops;
761 skt->socket.owner = ops->owner;
762 skt->socket.dev.parent = dev;
763 skt->socket.pci_irq = NO_IRQ;
Russell Kingd9dc8782011-12-19 22:00:22 +0000764
765 for (i = 0; i < ARRAY_SIZE(skt->stat); i++)
766 skt->stat[i].gpio = -EINVAL;
Russell Kinge0d21172011-12-19 14:07:31 +0000767}
768EXPORT_SYMBOL(soc_pcmcia_init_one);
769
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000770void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
771{
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000772 del_timer_sync(&skt->poll_timer);
773
774 pcmcia_unregister_socket(&skt->socket);
775
Russell Kingfb8c9952016-08-31 08:49:46 +0100776#ifdef CONFIG_CPU_FREQ
777 if (skt->ops->frequency_change)
778 cpufreq_unregister_notifier(&skt->cpufreq_nb,
779 CPUFREQ_TRANSITION_NOTIFIER);
780#endif
781
Russell Kingd9dc8782011-12-19 22:00:22 +0000782 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000783
Russell Kingd9dc8782011-12-19 22:00:22 +0000784 /* should not be required; violates some lowlevel drivers */
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000785 soc_common_pcmcia_config_skt(skt, &dead_socket);
786
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000787 iounmap(skt->virt_io);
788 skt->virt_io = NULL;
789 release_resource(&skt->res_attr);
790 release_resource(&skt->res_mem);
791 release_resource(&skt->res_io);
792 release_resource(&skt->res_skt);
793}
794EXPORT_SYMBOL(soc_pcmcia_remove_one);
795
796int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
797{
798 int ret;
799
Russell King6ac95d82016-08-31 08:49:46 +0100800 skt->cs_state = dead_socket;
801
Kees Cook41760d02017-10-21 12:09:17 -0700802 timer_setup(&skt->poll_timer, soc_common_pcmcia_poll_event, 0);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000803 skt->poll_timer.expires = jiffies + SOC_PCMCIA_POLL_PERIOD;
804
805 ret = request_resource(&iomem_resource, &skt->res_skt);
806 if (ret)
807 goto out_err_1;
808
809 ret = request_resource(&skt->res_skt, &skt->res_io);
810 if (ret)
811 goto out_err_2;
812
813 ret = request_resource(&skt->res_skt, &skt->res_mem);
814 if (ret)
815 goto out_err_3;
816
817 ret = request_resource(&skt->res_skt, &skt->res_attr);
818 if (ret)
819 goto out_err_4;
820
821 skt->virt_io = ioremap(skt->res_io.start, 0x10000);
822 if (skt->virt_io == NULL) {
823 ret = -ENOMEM;
824 goto out_err_5;
825 }
826
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000827 /*
828 * We initialize default socket timing here, because
829 * we are not guaranteed to see a SetIOMap operation at
830 * runtime.
831 */
832 skt->ops->set_timing(skt);
833
Russell Kingd9dc8782011-12-19 22:00:22 +0000834 ret = soc_pcmcia_hw_init(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000835 if (ret)
836 goto out_err_6;
837
838 skt->socket.ops = &soc_common_pcmcia_operations;
839 skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
840 skt->socket.resource_ops = &pccard_static_ops;
841 skt->socket.irq_mask = 0;
842 skt->socket.map_size = PAGE_SIZE;
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000843 skt->socket.io_offset = (unsigned long)skt->virt_io;
844
845 skt->status = soc_common_pcmcia_skt_state(skt);
846
Russell Kingfb8c9952016-08-31 08:49:46 +0100847#ifdef CONFIG_CPU_FREQ
848 if (skt->ops->frequency_change) {
849 skt->cpufreq_nb.notifier_call = soc_common_pcmcia_cpufreq_nb;
850
851 ret = cpufreq_register_notifier(&skt->cpufreq_nb,
852 CPUFREQ_TRANSITION_NOTIFIER);
853 if (ret < 0)
854 dev_err(skt->socket.dev.parent,
855 "unable to register CPU frequency change notifier for PCMCIA (%d)\n",
856 ret);
857 }
858#endif
859
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000860 ret = pcmcia_register_socket(&skt->socket);
861 if (ret)
862 goto out_err_7;
863
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000864 ret = device_create_file(&skt->socket.dev, &dev_attr_status);
865 if (ret)
866 goto out_err_8;
867
868 return ret;
869
870 out_err_8:
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000871 del_timer_sync(&skt->poll_timer);
872 pcmcia_unregister_socket(&skt->socket);
873
874 out_err_7:
Russell Kingd9dc8782011-12-19 22:00:22 +0000875 soc_pcmcia_hw_shutdown(skt);
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000876 out_err_6:
Russell King - ARM Linux097e2962009-03-26 21:45:05 +0000877 iounmap(skt->virt_io);
878 out_err_5:
879 release_resource(&skt->res_attr);
880 out_err_4:
881 release_resource(&skt->res_mem);
882 out_err_3:
883 release_resource(&skt->res_io);
884 out_err_2:
885 release_resource(&skt->res_skt);
886 out_err_1:
887
888 return ret;
889}
890EXPORT_SYMBOL(soc_pcmcia_add_one);
891
Russell King - ARM Linux0f767de2009-03-26 21:14:19 +0000892MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
893MODULE_DESCRIPTION("Linux PCMCIA Card Services: Common SoC support");
894MODULE_LICENSE("Dual MPL/GPL");