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