Thomas Gleixner | d2912cb | 2019-06-04 10:11:33 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | /* |
| 3 | * linux/drivers/pcmcia/pxa2xx_mainstone.c |
| 4 | * |
| 5 | * Mainstone PCMCIA specific routines. |
| 6 | * |
| 7 | * Created: May 12, 2004 |
| 8 | * Author: Nicolas Pitre |
| 9 | * Copyright: MontaVista Software Inc. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | */ |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 11 | #include <linux/gpio/consumer.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | #include <linux/module.h> |
| 13 | #include <linux/init.h> |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 14 | #include <linux/interrupt.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/errno.h> |
Russell King | d052d1b | 2005-10-29 19:07:23 +0100 | [diff] [blame] | 17 | #include <linux/platform_device.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | |
| 19 | #include <pcmcia/ss.h> |
| 20 | |
Russell King | 04ba0f6 | 2008-04-24 15:23:25 +0100 | [diff] [blame] | 21 | #include <asm/mach-types.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | |
| 23 | #include "soc_common.h" |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 24 | #include "max1600.h" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
| 27 | { |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 28 | struct device *dev = skt->socket.dev.parent; |
| 29 | struct max1600 *m; |
| 30 | int ret; |
| 31 | |
| 32 | skt->stat[SOC_STAT_CD].name = skt->nr ? "bdetect" : "adetect"; |
| 33 | skt->stat[SOC_STAT_BVD1].name = skt->nr ? "bbvd1" : "abvd1"; |
| 34 | skt->stat[SOC_STAT_BVD2].name = skt->nr ? "bbvd2" : "abvd2"; |
| 35 | skt->stat[SOC_STAT_RDY].name = skt->nr ? "bready" : "aready"; |
| 36 | skt->stat[SOC_STAT_VS1].name = skt->nr ? "bvs1" : "avs1"; |
| 37 | skt->stat[SOC_STAT_VS2].name = skt->nr ? "bvs2" : "avs2"; |
| 38 | |
| 39 | skt->gpio_reset = devm_gpiod_get(dev, skt->nr ? "breset" : "areset", |
| 40 | GPIOD_OUT_HIGH); |
| 41 | if (IS_ERR(skt->gpio_reset)) |
| 42 | return PTR_ERR(skt->gpio_reset); |
| 43 | |
| 44 | ret = max1600_init(dev, &m, skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A, |
| 45 | MAX1600_CODE_HIGH); |
| 46 | if (ret) |
| 47 | return ret; |
| 48 | |
| 49 | skt->driver_data = m; |
| 50 | |
| 51 | return soc_pcmcia_request_gpiods(skt); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | } |
| 53 | |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 54 | static unsigned int mst_pcmcia_bvd1_status[2]; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 55 | |
| 56 | static void mst_pcmcia_socket_state(struct soc_pcmcia_socket *skt, |
| 57 | struct pcmcia_state *state) |
| 58 | { |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 59 | unsigned int flip = mst_pcmcia_bvd1_status[skt->nr] ^ state->bvd1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | |
| 61 | /* |
| 62 | * Workaround for STSCHG which can't be deasserted: |
| 63 | * We therefore disable/enable corresponding IRQs |
| 64 | * as needed to avoid IRQ locks. |
| 65 | */ |
| 66 | if (flip) { |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 67 | mst_pcmcia_bvd1_status[skt->nr] = state->bvd1; |
| 68 | if (state->bvd1) |
| 69 | enable_irq(skt->stat[SOC_STAT_BVD1].irq); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | else |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 71 | disable_irq(skt->stat[SOC_STAT_BVD2].irq); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
| 76 | const socket_state_t *state) |
| 77 | { |
Russell King | 34fdbe6 | 2018-11-28 13:57:23 +0000 | [diff] [blame] | 78 | return max1600_configure(skt->driver_data, state->Vcc, state->Vpp); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 | } |
| 80 | |
Russell King | 4e5e8de | 2008-04-24 15:28:11 +0100 | [diff] [blame] | 81 | static struct pcmcia_low_level mst_pcmcia_ops __initdata = { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | .owner = THIS_MODULE, |
| 83 | .hw_init = mst_pcmcia_hw_init, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | .socket_state = mst_pcmcia_socket_state, |
| 85 | .configure_socket = mst_pcmcia_configure_socket, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | .nr = 2, |
| 87 | }; |
| 88 | |
| 89 | static struct platform_device *mst_pcmcia_device; |
| 90 | |
| 91 | static int __init mst_pcmcia_init(void) |
| 92 | { |
| 93 | int ret; |
| 94 | |
Russell King | 04ba0f6 | 2008-04-24 15:23:25 +0100 | [diff] [blame] | 95 | if (!machine_is_mainstone()) |
| 96 | return -ENODEV; |
| 97 | |
Richard Purdie | b016450 | 2006-01-10 17:16:12 +0000 | [diff] [blame] | 98 | mst_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 99 | if (!mst_pcmcia_device) |
| 100 | return -ENOMEM; |
Richard Purdie | b016450 | 2006-01-10 17:16:12 +0000 | [diff] [blame] | 101 | |
Russell King | 4e5e8de | 2008-04-24 15:28:11 +0100 | [diff] [blame] | 102 | ret = platform_device_add_data(mst_pcmcia_device, &mst_pcmcia_ops, |
| 103 | sizeof(mst_pcmcia_ops)); |
| 104 | if (ret == 0) |
| 105 | ret = platform_device_add(mst_pcmcia_device); |
Richard Purdie | b016450 | 2006-01-10 17:16:12 +0000 | [diff] [blame] | 106 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | if (ret) |
Richard Purdie | b016450 | 2006-01-10 17:16:12 +0000 | [diff] [blame] | 108 | platform_device_put(mst_pcmcia_device); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | |
| 110 | return ret; |
| 111 | } |
| 112 | |
| 113 | static void __exit mst_pcmcia_exit(void) |
| 114 | { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | platform_device_unregister(mst_pcmcia_device); |
| 116 | } |
| 117 | |
Richard Purdie | f36598ae | 2005-09-03 19:39:25 +0100 | [diff] [blame] | 118 | fs_initcall(mst_pcmcia_init); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | module_exit(mst_pcmcia_exit); |
| 120 | |
| 121 | MODULE_LICENSE("GPL"); |
Kay Sievers | 43cc71e | 2007-08-18 04:40:39 +0200 | [diff] [blame] | 122 | MODULE_ALIAS("platform:pxa2xx-pcmcia"); |