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/*
  26 * These are offsets from the above base.
  27 */
  28#define PCCR    0x0000
  29#define PCSSR   0x0004
  30#define PCSR    0x0008
  31
  32#define PCSR_S0_READY   (1<<0)
  33#define PCSR_S1_READY   (1<<1)
  34#define PCSR_S0_DETECT  (1<<2)
  35#define PCSR_S1_DETECT  (1<<3)
  36#define PCSR_S0_VS1     (1<<4)
  37#define PCSR_S0_VS2     (1<<5)
  38#define PCSR_S1_VS1     (1<<6)
  39#define PCSR_S1_VS2     (1<<7)
  40#define PCSR_S0_WP      (1<<8)
  41#define PCSR_S1_WP      (1<<9)
  42#define PCSR_S0_BVD1    (1<<10)
  43#define PCSR_S0_BVD2    (1<<11)
  44#define PCSR_S1_BVD1    (1<<12)
  45#define PCSR_S1_BVD2    (1<<13)
  46
  47#define PCCR_S0_RST     (1<<0)
  48#define PCCR_S1_RST     (1<<1)
  49#define PCCR_S0_FLT     (1<<2)
  50#define PCCR_S1_FLT     (1<<3)
  51#define PCCR_S0_PWAITEN (1<<4)
  52#define PCCR_S1_PWAITEN (1<<5)
  53#define PCCR_S0_PSE     (1<<6)
  54#define PCCR_S1_PSE     (1<<7)
  55
  56#define PCSSR_S0_SLEEP  (1<<0)
  57#define PCSSR_S1_SLEEP  (1<<1)
  58
  59#define IDX_IRQ_S0_READY_NINT   (0)
  60#define IDX_IRQ_S0_CD_VALID     (1)
  61#define IDX_IRQ_S0_BVD1_STSCHG  (2)
  62#define IDX_IRQ_S1_READY_NINT   (3)
  63#define IDX_IRQ_S1_CD_VALID     (4)
  64#define IDX_IRQ_S1_BVD1_STSCHG  (5)
  65
  66void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
  67{
  68        struct sa1111_pcmcia_socket *s = to_skt(skt);
  69        unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
  70
  71        switch (skt->nr) {
  72        case 0:
  73                state->detect = status & PCSR_S0_DETECT ? 0 : 1;
  74                state->ready  = status & PCSR_S0_READY  ? 1 : 0;
  75                state->bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
  76                state->bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
  77                state->wrprot = status & PCSR_S0_WP     ? 1 : 0;
  78                state->vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
  79                state->vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
  80                break;
  81
  82        case 1:
  83                state->detect = status & PCSR_S1_DETECT ? 0 : 1;
  84                state->ready  = status & PCSR_S1_READY  ? 1 : 0;
  85                state->bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
  86                state->bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
  87                state->wrprot = status & PCSR_S1_WP     ? 1 : 0;
  88                state->vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
  89                state->vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
  90                break;
  91        }
  92}
  93
  94int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
  95{
  96        struct sa1111_pcmcia_socket *s = to_skt(skt);
  97        unsigned int pccr_skt_mask, pccr_set_mask, val;
  98        unsigned long flags;
  99
 100        switch (skt->nr) {
 101        case 0:
 102                pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE;
 103                break;
 104
 105        case 1:
 106                pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE;
 107                break;
 108
 109        default:
 110                return -1;
 111        }
 112
 113        pccr_set_mask = 0;
 114
 115        if (state->Vcc != 0)
 116                pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN;
 117        if (state->Vcc == 50)
 118                pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE;
 119        if (state->flags & SS_RESET)
 120                pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST;
 121        if (state->flags & SS_OUTPUT_ENA)
 122                pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
 123
 124        local_irq_save(flags);
 125        val = sa1111_readl(s->dev->mapbase + PCCR);
 126        val &= ~pccr_skt_mask;
 127        val |= pccr_set_mask & pccr_skt_mask;
 128        sa1111_writel(val, s->dev->mapbase + PCCR);
 129        local_irq_restore(flags);
 130
 131        return 0;
 132}
 133
 134int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 135        int (*add)(struct soc_pcmcia_socket *))
 136{
 137        struct sa1111_pcmcia_socket *s;
 138        int i, ret = 0;
 139
 140        ops->socket_state = sa1111_pcmcia_socket_state;
 141
 142        for (i = 0; i < ops->nr; i++) {
 143                s = kzalloc(sizeof(*s), GFP_KERNEL);
 144                if (!s)
 145                        return -ENOMEM;
 146
 147                s->soc.nr = ops->first + i;
 148                soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
 149                s->dev = dev;
 150                if (s->soc.nr) {
 151                        s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S1_READY_NINT];
 152                        s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
 153                        s->soc.stat[SOC_STAT_CD].name = "SA1111 CF card detect";
 154                        s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
 155                        s->soc.stat[SOC_STAT_BVD1].name = "SA1111 CF BVD1";
 156                } else {
 157                        s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S0_READY_NINT];
 158                        s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
 159                        s->soc.stat[SOC_STAT_CD].name = "SA1111 PCMCIA card detect";
 160                        s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
 161                        s->soc.stat[SOC_STAT_BVD1].name = "SA1111 PCMCIA BVD1";
 162                }
 163
 164                ret = add(&s->soc);
 165                if (ret == 0) {
 166                        s->next = dev_get_drvdata(&dev->dev);
 167                        dev_set_drvdata(&dev->dev, s);
 168                } else
 169                        kfree(s);
 170        }
 171
 172        return ret;
 173}
 174
 175static int pcmcia_probe(struct sa1111_dev *dev)
 176{
 177        void __iomem *base;
 178        int ret;
 179
 180        ret = sa1111_enable_device(dev);
 181        if (ret)
 182                return ret;
 183
 184        dev_set_drvdata(&dev->dev, NULL);
 185
 186        if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
 187                sa1111_disable_device(dev);
 188                return -EBUSY;
 189        }
 190
 191        base = dev->mapbase;
 192
 193        /*
 194         * Initialise the suspend state.
 195         */
 196        sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
 197        sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
 198
 199#ifdef CONFIG_SA1100_BADGE4
 200        pcmcia_badge4_init(&dev->dev);
 201#endif
 202#ifdef CONFIG_SA1100_JORNADA720
 203        pcmcia_jornada720_init(&dev->dev);
 204#endif
 205#ifdef CONFIG_ARCH_LUBBOCK
 206        pcmcia_lubbock_init(dev);
 207#endif
 208#ifdef CONFIG_ASSABET_NEPONSET
 209        pcmcia_neponset_init(dev);
 210#endif
 211        return 0;
 212}
 213
 214static int __devexit pcmcia_remove(struct sa1111_dev *dev)
 215{
 216        struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev);
 217
 218        dev_set_drvdata(&dev->dev, NULL);
 219
 220        for (; s; s = next) {
 221                next = s->next;
 222                soc_pcmcia_remove_one(&s->soc);
 223                kfree(s);
 224        }
 225
 226        release_mem_region(dev->res.start, 512);
 227        sa1111_disable_device(dev);
 228        return 0;
 229}
 230
 231static struct sa1111_driver pcmcia_driver = {
 232        .drv = {
 233                .name   = "sa1111-pcmcia",
 234        },
 235        .devid          = SA1111_DEVID_PCMCIA,
 236        .probe          = pcmcia_probe,
 237        .remove         = __devexit_p(pcmcia_remove),
 238};
 239
 240static int __init sa1111_drv_pcmcia_init(void)
 241{
 242        return sa1111_driver_register(&pcmcia_driver);
 243}
 244
 245static void __exit sa1111_drv_pcmcia_exit(void)
 246{
 247        sa1111_driver_unregister(&pcmcia_driver);
 248}
 249
 250fs_initcall(sa1111_drv_pcmcia_init);
 251module_exit(sa1111_drv_pcmcia_exit);
 252
 253MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
 254MODULE_LICENSE("GPL");
 255
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.