linux/drivers/pcmcia/pxa2xx_balloon3.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/pcmcia/pxa2xx_balloon3.c
   3 *
   4 * Balloon3 PCMCIA specific routines.
   5 *
   6 *  Author:     Nick Bane
   7 *  Created:    June, 2006
   8 *  Copyright:  Toby Churchill Ltd
   9 *  Derived from pxa2xx_mainstone.c, by Nico Pitre
  10 *
  11 * Various modification by Marek Vasut <marek.vasut@gmail.com>
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License version 2 as
  15 * published by the Free Software Foundation.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/gpio.h>
  20#include <linux/errno.h>
  21#include <linux/interrupt.h>
  22#include <linux/platform_device.h>
  23#include <linux/irq.h>
  24#include <linux/io.h>
  25
  26#include <mach/balloon3.h>
  27
  28#include "soc_common.h"
  29
  30/*
  31 * These are a list of interrupt sources that provokes a polled
  32 * check of status
  33 */
  34static struct pcmcia_irqs irqs[] = {
  35        { 0, BALLOON3_S0_CD_IRQ, "PCMCIA0 CD" },
  36        { 0, BALLOON3_BP_NSTSCHG_IRQ, "PCMCIA0 STSCHG" },
  37};
  38
  39static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  40{
  41        uint16_t ver;
  42
  43        ver = __raw_readw(BALLOON3_FPGA_VER);
  44        if (ver < 0x4f08)
  45                pr_warn("The FPGA code, version 0x%04x, is too old. "
  46                        "PCMCIA/CF support might be broken in this version!",
  47                        ver);
  48
  49        skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ;
  50        return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
  51}
  52
  53static void balloon3_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  54{
  55        soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
  56}
  57
  58static unsigned long balloon3_pcmcia_status[2] = {
  59        BALLOON3_CF_nSTSCHG_BVD1,
  60        BALLOON3_CF_nSTSCHG_BVD1
  61};
  62
  63static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  64                                    struct pcmcia_state *state)
  65{
  66        uint16_t status;
  67        int flip;
  68
  69        /* This actually reads the STATUS register */
  70        status = __raw_readw(BALLOON3_CF_STATUS_REG);
  71        flip = (status ^ balloon3_pcmcia_status[skt->nr])
  72                & BALLOON3_CF_nSTSCHG_BVD1;
  73        /*
  74         * Workaround for STSCHG which can't be deasserted:
  75         * We therefore disable/enable corresponding IRQs
  76         * as needed to avoid IRQ locks.
  77         */
  78        if (flip) {
  79                balloon3_pcmcia_status[skt->nr] = status;
  80                if (status & BALLOON3_CF_nSTSCHG_BVD1)
  81                        enable_irq(BALLOON3_BP_NSTSCHG_IRQ);
  82                else
  83                        disable_irq(BALLOON3_BP_NSTSCHG_IRQ);
  84        }
  85
  86        state->detect   = !gpio_get_value(BALLOON3_GPIO_S0_CD);
  87        state->ready    = !!(status & BALLOON3_CF_nIRQ);
  88        state->bvd1     = !!(status & BALLOON3_CF_nSTSCHG_BVD1);
  89        state->bvd2     = 0;    /* not available */
  90        state->vs_3v    = 1;    /* Always true its a CF card */
  91        state->vs_Xv    = 0;    /* not available */
  92        state->wrprot   = 0;    /* not available */
  93}
  94
  95static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  96                                       const socket_state_t *state)
  97{
  98        __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG |
  99                        ((state->flags & SS_RESET) ?
 100                        BALLOON3_FPGA_SETnCLR : 0));
 101        return 0;
 102}
 103
 104static void balloon3_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 105{
 106}
 107
 108static void balloon3_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 109{
 110}
 111
 112static struct pcmcia_low_level balloon3_pcmcia_ops = {
 113        .owner                  = THIS_MODULE,
 114        .hw_init                = balloon3_pcmcia_hw_init,
 115        .hw_shutdown            = balloon3_pcmcia_hw_shutdown,
 116        .socket_state           = balloon3_pcmcia_socket_state,
 117        .configure_socket       = balloon3_pcmcia_configure_socket,
 118        .socket_init            = balloon3_pcmcia_socket_init,
 119        .socket_suspend         = balloon3_pcmcia_socket_suspend,
 120        .first                  = 0,
 121        .nr                     = 1,
 122};
 123
 124static struct platform_device *balloon3_pcmcia_device;
 125
 126static int __init balloon3_pcmcia_init(void)
 127{
 128        int ret;
 129
 130        balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 131        if (!balloon3_pcmcia_device)
 132                return -ENOMEM;
 133
 134        ret = platform_device_add_data(balloon3_pcmcia_device,
 135                        &balloon3_pcmcia_ops, sizeof(balloon3_pcmcia_ops));
 136
 137        if (!ret)
 138                ret = platform_device_add(balloon3_pcmcia_device);
 139
 140        if (ret)
 141                platform_device_put(balloon3_pcmcia_device);
 142
 143        return ret;
 144}
 145
 146static void __exit balloon3_pcmcia_exit(void)
 147{
 148        platform_device_unregister(balloon3_pcmcia_device);
 149}
 150
 151module_init(balloon3_pcmcia_init);
 152module_exit(balloon3_pcmcia_exit);
 153
 154MODULE_LICENSE("GPL");
 155MODULE_AUTHOR("Nick Bane <nick@cecomputing.co.uk>");
 156MODULE_ALIAS("platform:pxa2xx-pcmcia");
 157MODULE_DESCRIPTION("Balloon3 board CF/PCMCIA driver");
 158