linux/drivers/pcmcia/pxa2xx_vpac270.c
<<
>>
Prefs
   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