1/* 2 * linux/drivers/pcmcia/pxa2xx_vpac270.c 3 * 4 * Driver for Voipac PXA270 PCMCIA and CF sockets 5 * 6 * Copyright (C) 2010 7 * Marek Vasut <marek.vasut@gmail.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 */ 14 15#include <linux/module.h> 16#include <linux/platform_device.h> 17 18#include <asm/mach-types.h> 19 20#include <mach/gpio.h> 21#include <mach/vpac270.h> 22 23#include "soc_common.h" 24 25static struct pcmcia_irqs cd_irqs[] = { 26 { 27 .sock = 0, 28 .irq = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD), 29 .str = "PCMCIA CD" 30 }, 31 { 32 .sock = 1, 33 .irq = IRQ_GPIO(GPIO17_VPAC270_CF_CD), 34 .str = "CF CD" 35 }, 36}; 37 38static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 39{ 40 int ret; 41 42 if (skt->nr == 0) { 43 ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD"); 44 if (ret) 45 goto err1; 46 ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD); 47 if (ret) 48 goto err2; 49 50 ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY"); 51 if (ret) 52 goto err2; 53 ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY); 54 if (ret) 55 goto err3; 56 57 ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN"); 58 if (ret) 59 goto err3; 60 ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0); 61 if (ret) 62 goto err4; 63 64 ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET"); 65 if (ret) 66 goto err4; 67 ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0); 68 if (ret) 69 goto err5; 70 71 skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY); 72 73 return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1); 74 75err5: 76 gpio_free(GPIO11_VPAC270_PCMCIA_RESET); 77err4: 78 gpio_free(GPIO107_VPAC270_PCMCIA_PPEN); 79err3: 80 gpio_free(GPIO35_VPAC270_PCMCIA_RDY); 81err2: 82 gpio_free(GPIO84_VPAC270_PCMCIA_CD); 83err1: 84 return ret; 85 86 } else { 87 ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD"); 88 if (ret) 89 goto err6; 90 ret = gpio_direction_input(GPIO17_VPAC270_CF_CD); 91 if (ret) 92 goto err7; 93 94 ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY"); 95 if (ret) 96 goto err7; 97 ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY); 98 if (ret) 99 goto err8; 100 101 ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET"); 102 if (ret) 103 goto err8; 104 ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0); 105 if (ret) 106 goto err9; 107 108 skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY); 109 110 return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1); 111 112err9: 113 gpio_free(GPIO16_VPAC270_CF_RESET); 114err8: 115 gpio_free(GPIO12_VPAC270_CF_RDY); 116err7: 117 gpio_free(GPIO17_VPAC270_CF_CD); 118err6: 119 return ret; 120 121 } 122} 123 124static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 125{ 126 gpio_free(GPIO11_VPAC270_PCMCIA_RESET); 127 gpio_free(GPIO107_VPAC270_PCMCIA_PPEN); 128 gpio_free(GPIO35_VPAC270_PCMCIA_RDY); 129 gpio_free(GPIO84_VPAC270_PCMCIA_CD); 130 gpio_free(GPIO16_VPAC270_CF_RESET); 131 gpio_free(GPIO12_VPAC270_CF_RDY); 132 gpio_free(GPIO17_VPAC270_CF_CD); 133} 134 135static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt, 136 struct pcmcia_state *state) 137{ 138 if (skt->nr == 0) { 139 state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD); 140 state->ready = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY); 141 } else { 142 state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD); 143 state->ready = !!gpio_get_value(GPIO12_VPAC270_CF_RDY); 144 } 145 state->bvd1 = 1; 146 state->bvd2 = 1; 147 state->wrprot = 0; 148 state->vs_3v = 1; 149 state->vs_Xv = 0; 150} 151 152static int 153vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, 154 const socket_state_t *state) 155{ 156 if (skt->nr == 0) { 157 gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET, 158 (state->flags & SS_RESET)); 159 gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN, 160 !(state->Vcc == 33 || state->Vcc == 50)); 161 } else { 162 gpio_set_value(GPIO16_VPAC270_CF_RESET, 163 (state->flags & SS_RESET)); 164 } 165 166 return 0; 167} 168 169static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 170{ 171} 172 173static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 174{ 175} 176 177static struct pcmcia_low_level vpac270_pcmcia_ops = { 178 .owner = THIS_MODULE, 179 180 .first = 0, 181 .nr = 2, 182 183 .hw_init = vpac270_pcmcia_hw_init, 184 .hw_shutdown = vpac270_pcmcia_hw_shutdown, 185 186 .socket_state = vpac270_pcmcia_socket_state, 187 .configure_socket = vpac270_pcmcia_configure_socket, 188 189 .socket_init = vpac270_pcmcia_socket_init, 190 .socket_suspend = vpac270_pcmcia_socket_suspend, 191}; 192 193static struct platform_device *vpac270_pcmcia_device; 194 195static int __init vpac270_pcmcia_init(void) 196{ 197 int ret; 198 199 if (!machine_is_vpac270()) 200 return -ENODEV; 201 202 vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); 203 if (!vpac270_pcmcia_device) 204 return -ENOMEM; 205 206 ret = platform_device_add_data(vpac270_pcmcia_device, 207 &vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops)); 208 209 if (!ret) 210 ret = platform_device_add(vpac270_pcmcia_device); 211 212 if (ret) 213 platform_device_put(vpac270_pcmcia_device); 214 215 return ret; 216} 217 218static void __exit vpac270_pcmcia_exit(void) 219{ 220 platform_device_unregister(vpac270_pcmcia_device); 221} 222 223module_init(vpac270_pcmcia_init); 224module_exit(vpac270_pcmcia_exit); 225 226MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 227MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270"); 228MODULE_ALIAS("platform:pxa2xx-pcmcia"); 229MODULE_LICENSE("GPL"); 230