linux/drivers/pcmcia/pxa2xx_colibri.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/pcmcia/pxa2xx_colibri.c
   3 *
   4 * Driver for Toradex Colibri PXA270 CF socket
   5 *
   6 * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/platform_device.h>
  16#include <linux/delay.h>
  17#include <linux/gpio.h>
  18
  19#include <asm/mach-types.h>
  20
  21#include "soc_common.h"
  22
  23#define COLIBRI270_RESET_GPIO   53
  24#define COLIBRI270_PPEN_GPIO    107
  25#define COLIBRI270_BVD1_GPIO    83
  26#define COLIBRI270_BVD2_GPIO    82
  27#define COLIBRI270_DETECT_GPIO  84
  28#define COLIBRI270_READY_GPIO   1
  29
  30#define COLIBRI320_RESET_GPIO   77
  31#define COLIBRI320_PPEN_GPIO    57
  32#define COLIBRI320_BVD1_GPIO    53
  33#define COLIBRI320_BVD2_GPIO    79
  34#define COLIBRI320_DETECT_GPIO  81
  35#define COLIBRI320_READY_GPIO   29
  36
  37enum {
  38        DETECT = 0,
  39        READY = 1,
  40        BVD1 = 2,
  41        BVD2 = 3,
  42        PPEN = 4,
  43        RESET = 5,
  44};
  45
  46/* Contents of this array are configured on-the-fly in init function */
  47static struct gpio colibri_pcmcia_gpios[] = {
  48        { 0,    GPIOF_IN,       "PCMCIA Detect" },
  49        { 0,    GPIOF_IN,       "PCMCIA Ready" },
  50        { 0,    GPIOF_IN,       "PCMCIA BVD1" },
  51        { 0,    GPIOF_IN,       "PCMCIA BVD2" },
  52        { 0,    GPIOF_INIT_LOW, "PCMCIA PPEN" },
  53        { 0,    GPIOF_INIT_HIGH,"PCMCIA Reset" },
  54};
  55
  56static struct pcmcia_irqs colibri_irqs[] = {
  57        {
  58                .sock = 0,
  59                .str  = "PCMCIA CD"
  60        },
  61};
  62
  63static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  64{
  65        int ret;
  66
  67        ret = gpio_request_array(colibri_pcmcia_gpios,
  68                                ARRAY_SIZE(colibri_pcmcia_gpios));
  69        if (ret)
  70                goto err1;
  71
  72        colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio);
  73        skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio);
  74
  75        ret = soc_pcmcia_request_irqs(skt, colibri_irqs,
  76                                        ARRAY_SIZE(colibri_irqs));
  77        if (ret)
  78                goto err2;
  79
  80        return ret;
  81
  82err2:
  83        gpio_free_array(colibri_pcmcia_gpios,
  84                        ARRAY_SIZE(colibri_pcmcia_gpios));
  85err1:
  86        return ret;
  87}
  88
  89static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  90{
  91        gpio_free_array(colibri_pcmcia_gpios,
  92                        ARRAY_SIZE(colibri_pcmcia_gpios));
  93}
  94
  95static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  96                                        struct pcmcia_state *state)
  97{
  98
  99        state->detect = !!gpio_get_value(colibri_pcmcia_gpios[DETECT].gpio);
 100        state->ready  = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio);
 101        state->bvd1   = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio);
 102        state->bvd2   = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio);
 103        state->wrprot = 0;
 104        state->vs_3v  = 1;
 105        state->vs_Xv  = 0;
 106}
 107
 108static int
 109colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 110                                const socket_state_t *state)
 111{
 112        gpio_set_value(colibri_pcmcia_gpios[PPEN].gpio,
 113                        !(state->Vcc == 33 && state->Vpp < 50));
 114        gpio_set_value(colibri_pcmcia_gpios[RESET].gpio,
 115                        state->flags & SS_RESET);
 116        return 0;
 117}
 118
 119static struct pcmcia_low_level colibri_pcmcia_ops = {
 120        .owner                  = THIS_MODULE,
 121
 122        .first                  = 0,
 123        .nr                     = 1,
 124
 125        .hw_init                = colibri_pcmcia_hw_init,
 126        .hw_shutdown            = colibri_pcmcia_hw_shutdown,
 127
 128        .socket_state           = colibri_pcmcia_socket_state,
 129        .configure_socket       = colibri_pcmcia_configure_socket,
 130};
 131
 132static struct platform_device *colibri_pcmcia_device;
 133
 134static int __init colibri_pcmcia_init(void)
 135{
 136        int ret;
 137
 138        if (!machine_is_colibri() && !machine_is_colibri320())
 139                return -ENODEV;
 140
 141        colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 142        if (!colibri_pcmcia_device)
 143                return -ENOMEM;
 144
 145        /* Colibri PXA270 */
 146        if (machine_is_colibri()) {
 147                colibri_pcmcia_gpios[RESET].gpio        = COLIBRI270_RESET_GPIO;
 148                colibri_pcmcia_gpios[PPEN].gpio         = COLIBRI270_PPEN_GPIO;
 149                colibri_pcmcia_gpios[BVD1].gpio         = COLIBRI270_BVD1_GPIO;
 150                colibri_pcmcia_gpios[BVD2].gpio         = COLIBRI270_BVD2_GPIO;
 151                colibri_pcmcia_gpios[DETECT].gpio       = COLIBRI270_DETECT_GPIO;
 152                colibri_pcmcia_gpios[READY].gpio        = COLIBRI270_READY_GPIO;
 153        /* Colibri PXA320 */
 154        } else if (machine_is_colibri320()) {
 155                colibri_pcmcia_gpios[RESET].gpio        = COLIBRI320_RESET_GPIO;
 156                colibri_pcmcia_gpios[PPEN].gpio         = COLIBRI320_PPEN_GPIO;
 157                colibri_pcmcia_gpios[BVD1].gpio         = COLIBRI320_BVD1_GPIO;
 158                colibri_pcmcia_gpios[BVD2].gpio         = COLIBRI320_BVD2_GPIO;
 159                colibri_pcmcia_gpios[DETECT].gpio       = COLIBRI320_DETECT_GPIO;
 160                colibri_pcmcia_gpios[READY].gpio        = COLIBRI320_READY_GPIO;
 161        }
 162
 163        ret = platform_device_add_data(colibri_pcmcia_device,
 164                &colibri_pcmcia_ops, sizeof(colibri_pcmcia_ops));
 165
 166        if (!ret)
 167                ret = platform_device_add(colibri_pcmcia_device);
 168
 169        if (ret)
 170                platform_device_put(colibri_pcmcia_device);
 171
 172        return ret;
 173}
 174
 175static void __exit colibri_pcmcia_exit(void)
 176{
 177        platform_device_unregister(colibri_pcmcia_device);
 178}
 179
 180module_init(colibri_pcmcia_init);
 181module_exit(colibri_pcmcia_exit);
 182
 183MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
 184MODULE_DESCRIPTION("PCMCIA support for Toradex Colibri PXA270/PXA320");
 185MODULE_ALIAS("platform:pxa2xx-pcmcia");
 186MODULE_LICENSE("GPL");
 187