linux/drivers/pcmcia/sa1111_generic.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/pcmcia/sa1111_generic.c
   3 *
   4 * We implement the generic parts of a SA1111 PCMCIA driver.  This
   5 * basically means we handle everything except controlling the
   6 * power.  Power is machine specific...
   7 */
   8#include <linux/module.h>
   9#include <linux/kernel.h>
  10#include <linux/ioport.h>
  11#include <linux/device.h>
  12#include <linux/interrupt.h>
  13#include <linux/init.h>
  14#include <linux/io.h>
  15#include <linux/slab.h>
  16
  17#include <pcmcia/ss.h>
  18
  19#include <mach/hardware.h>
  20#include <asm/hardware/sa1111.h>
  21#include <asm/irq.h>
  22
  23#include "sa1111_generic.h"
  24
  25#define IDX_IRQ_S0_READY_NINT   (0)
  26#define IDX_IRQ_S0_CD_VALID     (1)
  27#define IDX_IRQ_S0_BVD1_STSCHG  (2)
  28#define IDX_IRQ_S1_READY_NINT   (3)
  29#define IDX_IRQ_S1_CD_VALID     (4)
  30#define IDX_IRQ_S1_BVD1_STSCHG  (5)
  31
  32static struct pcmcia_irqs irqs[] = {
  33        { 0, NO_IRQ, "SA1111 PCMCIA card detect" },
  34        { 0, NO_IRQ, "SA1111 PCMCIA BVD1"        },
  35        { 1, NO_IRQ, "SA1111 CF card detect"     },
  36        { 1, NO_IRQ, "SA1111 CF BVD1"            },
  37};
  38
  39static int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  40{
  41        return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
  42}
  43
  44static void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  45{
  46        soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
  47}
  48
  49void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
  50{
  51        struct sa1111_pcmcia_socket *s = to_skt(skt);
  52        unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR);
  53
  54        switch (skt->nr) {
  55        case 0:
  56                state->detect = status & PCSR_S0_DETECT ? 0 : 1;
  57                state->ready  = status & PCSR_S0_READY  ? 1 : 0;
  58                state->bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
  59                state->bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
  60                state->wrprot = status & PCSR_S0_WP     ? 1 : 0;
  61                state->vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
  62                state->vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
  63                break;
  64
  65        case 1:
  66                state->detect = status & PCSR_S1_DETECT ? 0 : 1;
  67                state->ready  = status & PCSR_S1_READY  ? 1 : 0;
  68                state->bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
  69                state->bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
  70                state->wrprot = status & PCSR_S1_WP     ? 1 : 0;
  71                state->vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
  72                state->vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
  73                break;
  74        }
  75}
  76
  77int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
  78{
  79        struct sa1111_pcmcia_socket *s = to_skt(skt);
  80        unsigned int pccr_skt_mask, pccr_set_mask, val;
  81        unsigned long flags;
  82
  83        switch (skt->nr) {
  84        case 0:
  85                pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE;
  86                break;
  87
  88        case 1:
  89                pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE;
  90                break;
  91
  92        default:
  93                return -1;
  94        }
  95
  96        pccr_set_mask = 0;
  97
  98        if (state->Vcc != 0)
  99                pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN;
 100        if (state->Vcc == 50)
 101                pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE;
 102        if (state->flags & SS_RESET)
 103                pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST;
 104        if (state->flags & SS_OUTPUT_ENA)
 105                pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
 106
 107        local_irq_save(flags);
 108        val = sa1111_readl(s->dev->mapbase + SA1111_PCCR);
 109        val &= ~pccr_skt_mask;
 110        val |= pccr_set_mask & pccr_skt_mask;
 111        sa1111_writel(val, s->dev->mapbase + SA1111_PCCR);
 112        local_irq_restore(flags);
 113
 114        return 0;
 115}
 116
 117void sa1111_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 118{
 119        soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 120}
 121
 122static void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 123{
 124        soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
 125}
 126
 127int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 128        int (*add)(struct soc_pcmcia_socket *))
 129{
 130        struct sa1111_pcmcia_socket *s;
 131        int i, ret = 0;
 132
 133        ops->hw_init = sa1111_pcmcia_hw_init;
 134        ops->hw_shutdown = sa1111_pcmcia_hw_shutdown;
 135        ops->socket_state = sa1111_pcmcia_socket_state;
 136        ops->socket_suspend = sa1111_pcmcia_socket_suspend;
 137
 138        for (i = 0; i < ops->nr; i++) {
 139                s = kzalloc(sizeof(*s), GFP_KERNEL);
 140                if (!s)
 141                        return -ENOMEM;
 142
 143                s->soc.nr = ops->first + i;
 144                s->soc.ops = ops;
 145                s->soc.socket.owner = ops->owner;
 146                s->soc.socket.dev.parent = &dev->dev;
 147                s->soc.socket.pci_irq = s->soc.nr ?
 148                                dev->irq[IDX_IRQ_S0_READY_NINT] :
 149                                dev->irq[IDX_IRQ_S1_READY_NINT];
 150                s->dev = dev;
 151
 152                ret = add(&s->soc);
 153                if (ret == 0) {
 154                        s->next = dev_get_drvdata(&dev->dev);
 155                        dev_set_drvdata(&dev->dev, s);
 156                } else
 157                        kfree(s);
 158        }
 159
 160        return ret;
 161}
 162
 163static int pcmcia_probe(struct sa1111_dev *dev)
 164{
 165        void __iomem *base;
 166
 167        dev_set_drvdata(&dev->dev, NULL);
 168
 169        if (!request_mem_region(dev->res.start, 512,
 170                                SA1111_DRIVER_NAME(dev)))
 171                return -EBUSY;
 172
 173        base = dev->mapbase;
 174
 175        /* Initialize PCMCIA IRQs */
 176        irqs[0].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
 177        irqs[1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
 178        irqs[2].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
 179        irqs[3].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
 180
 181        /*
 182         * Initialise the suspend state.
 183         */
 184        sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
 185        sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
 186
 187#ifdef CONFIG_SA1100_BADGE4
 188        pcmcia_badge4_init(&dev->dev);
 189#endif
 190#ifdef CONFIG_SA1100_JORNADA720
 191        pcmcia_jornada720_init(&dev->dev);
 192#endif
 193#ifdef CONFIG_ARCH_LUBBOCK
 194        pcmcia_lubbock_init(dev);
 195#endif
 196#ifdef CONFIG_ASSABET_NEPONSET
 197        pcmcia_neponset_init(dev);
 198#endif
 199        return 0;
 200}
 201
 202static int __devexit pcmcia_remove(struct sa1111_dev *dev)
 203{
 204        struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev);
 205
 206        dev_set_drvdata(&dev->dev, NULL);
 207
 208        for (; next = s->next, s; s = next) {
 209                soc_pcmcia_remove_one(&s->soc);
 210                kfree(s);
 211        }
 212
 213        release_mem_region(dev->res.start, 512);
 214        return 0;
 215}
 216
 217static struct sa1111_driver pcmcia_driver = {
 218        .drv = {
 219                .name   = "sa1111-pcmcia",
 220        },
 221        .devid          = SA1111_DEVID_PCMCIA,
 222        .probe          = pcmcia_probe,
 223        .remove         = __devexit_p(pcmcia_remove),
 224};
 225
 226static int __init sa1111_drv_pcmcia_init(void)
 227{
 228        return sa1111_driver_register(&pcmcia_driver);
 229}
 230
 231static void __exit sa1111_drv_pcmcia_exit(void)
 232{
 233        sa1111_driver_unregister(&pcmcia_driver);
 234}
 235
 236fs_initcall(sa1111_drv_pcmcia_init);
 237module_exit(sa1111_drv_pcmcia_exit);
 238
 239MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
 240MODULE_LICENSE("GPL");
 241