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