linux/drivers/pcmcia/pxa2xx_sharpsl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Sharp SL-C7xx Series PCMCIA routines
   4 *
   5 * Copyright (c) 2004-2005 Richard Purdie
   6 *
   7 * Based on Sharp's 2.4 kernel patches and pxa2xx_mainstone.c
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/init.h>
  12#include <linux/kernel.h>
  13#include <linux/errno.h>
  14#include <linux/interrupt.h>
  15#include <linux/platform_device.h>
  16
  17#include <asm/mach-types.h>
  18#include <mach/hardware.h>
  19#include <asm/irq.h>
  20#include <asm/hardware/scoop.h>
  21
  22#include "soc_common.h"
  23
  24#define NO_KEEP_VS 0x0001
  25#define SCOOP_DEV platform_scoop_config->devs
  26
  27static void sharpsl_pcmcia_init_reset(struct soc_pcmcia_socket *skt)
  28{
  29        struct scoop_pcmcia_dev *scoopdev = &SCOOP_DEV[skt->nr];
  30
  31        reset_scoop(scoopdev->dev);
  32
  33        /* Shared power controls need to be handled carefully */
  34        if (platform_scoop_config->power_ctrl)
  35                platform_scoop_config->power_ctrl(scoopdev->dev, 0x0000, skt->nr);
  36        else
  37                write_scoop_reg(scoopdev->dev, SCOOP_CPR, 0x0000);
  38
  39        scoopdev->keep_vs = NO_KEEP_VS;
  40        scoopdev->keep_rd = 0;
  41}
  42
  43static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  44{
  45        if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
  46                skt->stat[SOC_STAT_CD].irq = SCOOP_DEV[skt->nr].cd_irq;
  47                skt->stat[SOC_STAT_CD].name = SCOOP_DEV[skt->nr].cd_irq_str;
  48        }
  49
  50        skt->socket.pci_irq = SCOOP_DEV[skt->nr].irq;
  51
  52        return 0;
  53}
  54
  55static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  56                                    struct pcmcia_state *state)
  57{
  58        unsigned short cpr, csr;
  59        struct device *scoop = SCOOP_DEV[skt->nr].dev;
  60
  61        cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR);
  62
  63        write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
  64        write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
  65        write_scoop_reg(scoop, SCOOP_IRM, 0x0000);
  66        csr = read_scoop_reg(scoop, SCOOP_CSR);
  67        if (csr & 0x0004) {
  68                /* card eject */
  69                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
  70                SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
  71        }
  72        else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) {
  73                /* keep vs1,vs2 */
  74                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
  75                csr |= SCOOP_DEV[skt->nr].keep_vs;
  76        }
  77        else if (cpr & 0x0003) {
  78                /* power on */
  79                write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
  80                SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0);
  81        }
  82        else {
  83                /* card detect */
  84                if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) {
  85                        write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
  86                } else {
  87                        write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
  88                }
  89        }
  90
  91        state->detect = (csr & 0x0004) ? 0 : 1;
  92        state->ready  = (csr & 0x0002) ? 1 : 0;
  93        state->bvd1   = (csr & 0x0010) ? 1 : 0;
  94        state->bvd2   = (csr & 0x0020) ? 1 : 0;
  95        state->wrprot = (csr & 0x0008) ? 1 : 0;
  96        state->vs_3v  = (csr & 0x0040) ? 0 : 1;
  97        state->vs_Xv  = (csr & 0x0080) ? 0 : 1;
  98
  99        if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) {
 100                printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr);
 101        }
 102}
 103
 104
 105static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 106                                       const socket_state_t *state)
 107{
 108        unsigned long flags;
 109        struct device *scoop = SCOOP_DEV[skt->nr].dev;
 110
 111        unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
 112
 113        switch (state->Vcc) {
 114        case    0:      break;
 115        case    33:     break;
 116        case    50:     break;
 117        default:
 118                 printk(KERN_ERR "sharpsl_pcmcia_configure_socket(): bad Vcc %u\n", state->Vcc);
 119                 return -1;
 120        }
 121
 122        if ((state->Vpp!=state->Vcc) && (state->Vpp!=0)) {
 123                printk(KERN_ERR "CF slot cannot support Vpp %u\n", state->Vpp);
 124                return -1;
 125        }
 126
 127        local_irq_save(flags);
 128
 129        nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010;
 130        ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083;
 131        nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
 132        nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
 133
 134        if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) {
 135                ncpr |= (state->Vcc == 33) ? 0x0002 :
 136                        (state->Vcc == 50) ? 0x0002 : 0;
 137        } else {
 138                ncpr |= (state->Vcc == 33) ? 0x0001 :
 139                        (state->Vcc == 50) ? 0x0002 : 0;
 140        }
 141        nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0;
 142        ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0;
 143        nccr |= (state->flags&SS_RESET)? 0x0080: 0;
 144        nimr |= ((skt->status&SS_DETECT) ? 0x0004 : 0)|
 145                        ((skt->status&SS_READY)  ? 0x0002 : 0)|
 146                        ((skt->status&SS_BATDEAD)? 0x0010 : 0)|
 147                        ((skt->status&SS_BATWARN)? 0x0020 : 0)|
 148                        ((skt->status&SS_STSCHG) ? 0x0010 : 0)|
 149                        ((skt->status&SS_WRPROT) ? 0x0008 : 0);
 150
 151        if (!(ncpr & 0x0003)) {
 152                SCOOP_DEV[skt->nr].keep_rd = 0;
 153        } else if (!SCOOP_DEV[skt->nr].keep_rd) {
 154                if (nccr & 0x0080)
 155                        SCOOP_DEV[skt->nr].keep_rd = 1;
 156                else
 157                        nccr |= 0x0080;
 158        }
 159
 160        if (mcr != nmcr)
 161                write_scoop_reg(scoop, SCOOP_MCR, nmcr);
 162        if (cpr != ncpr) {
 163                if (platform_scoop_config->power_ctrl)
 164                        platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr);
 165                else
 166                        write_scoop_reg(scoop, SCOOP_CPR, ncpr);
 167        }
 168        if (ccr != nccr)
 169                write_scoop_reg(scoop, SCOOP_CCR, nccr);
 170        if (imr != nimr)
 171                write_scoop_reg(scoop, SCOOP_IMR, nimr);
 172
 173        local_irq_restore(flags);
 174
 175        return 0;
 176}
 177
 178static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 179{
 180        sharpsl_pcmcia_init_reset(skt);
 181
 182        /* Enable interrupt */
 183        write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
 184        write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
 185        SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
 186}
 187
 188static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 189{
 190        sharpsl_pcmcia_init_reset(skt);
 191}
 192
 193static struct pcmcia_low_level sharpsl_pcmcia_ops = {
 194        .owner                  = THIS_MODULE,
 195        .hw_init                = sharpsl_pcmcia_hw_init,
 196        .socket_state           = sharpsl_pcmcia_socket_state,
 197        .configure_socket       = sharpsl_pcmcia_configure_socket,
 198        .socket_init            = sharpsl_pcmcia_socket_init,
 199        .socket_suspend         = sharpsl_pcmcia_socket_suspend,
 200        .first                  = 0,
 201        .nr                     = 0,
 202};
 203
 204#ifdef CONFIG_SA1100_COLLIE
 205#include "sa11xx_base.h"
 206
 207int pcmcia_collie_init(struct device *dev)
 208{
 209       int ret = -ENODEV;
 210
 211       if (machine_is_collie())
 212               ret = sa11xx_drv_pcmcia_probe(dev, &sharpsl_pcmcia_ops, 0, 1);
 213
 214       return ret;
 215}
 216
 217#else
 218
 219static struct platform_device *sharpsl_pcmcia_device;
 220
 221static int __init sharpsl_pcmcia_init(void)
 222{
 223        int ret;
 224
 225        if (!platform_scoop_config)
 226                return -ENODEV;
 227
 228        sharpsl_pcmcia_ops.nr = platform_scoop_config->num_devs;
 229        sharpsl_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 230
 231        if (!sharpsl_pcmcia_device)
 232                return -ENOMEM;
 233
 234        ret = platform_device_add_data(sharpsl_pcmcia_device,
 235                        &sharpsl_pcmcia_ops, sizeof(sharpsl_pcmcia_ops));
 236        if (ret == 0) {
 237                sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
 238                ret = platform_device_add(sharpsl_pcmcia_device);
 239        }
 240
 241        if (ret)
 242                platform_device_put(sharpsl_pcmcia_device);
 243
 244        return ret;
 245}
 246
 247static void __exit sharpsl_pcmcia_exit(void)
 248{
 249        platform_device_unregister(sharpsl_pcmcia_device);
 250}
 251
 252fs_initcall(sharpsl_pcmcia_init);
 253module_exit(sharpsl_pcmcia_exit);
 254#endif
 255
 256MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
 257MODULE_LICENSE("GPL");
 258MODULE_ALIAS("platform:pxa2xx-pcmcia");
 259