linux/drivers/pcmcia/pxa2xx_trizeps4.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/drivers/pcmcia/pxa2xx_trizeps4.c
   4 *
   5 * TRIZEPS PCMCIA specific routines.
   6 *
   7 * Author:      Jürgen Schindele
   8 * Created:     20 02, 2006
   9 * Copyright:   Jürgen Schindele
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/kernel.h>
  15#include <linux/gpio.h>
  16#include <linux/interrupt.h>
  17#include <linux/platform_device.h>
  18
  19#include <asm/mach-types.h>
  20#include <asm/irq.h>
  21
  22#include <mach/pxa2xx-regs.h>
  23#include <mach/trizeps4.h>
  24
  25#include "soc_common.h"
  26
  27extern void board_pcmcia_power(int power);
  28
  29static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  30{
  31        /* we dont have voltage/card/ready detection
  32         * so we dont need interrupts for it
  33         */
  34        switch (skt->nr) {
  35        case 0:
  36                skt->stat[SOC_STAT_CD].gpio = GPIO_PCD;
  37                skt->stat[SOC_STAT_CD].name = "cs0_cd";
  38                skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY;
  39                skt->stat[SOC_STAT_RDY].name = "cs0_rdy";
  40                break;
  41        default:
  42                break;
  43        }
  44        /* release the reset of this card */
  45        pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
  46
  47        return 0;
  48}
  49
  50static unsigned long trizeps_pcmcia_status[2];
  51
  52static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  53                                struct pcmcia_state *state)
  54{
  55        unsigned short status = 0, change;
  56        status = CFSR_readw();
  57        change = (status ^ trizeps_pcmcia_status[skt->nr]) &
  58                                ConXS_CFSR_BVD_MASK;
  59        if (change) {
  60                trizeps_pcmcia_status[skt->nr] = status;
  61                if (status & ConXS_CFSR_BVD1) {
  62                        /* enable_irq empty */
  63                } else {
  64                        /* disable_irq empty */
  65                }
  66        }
  67
  68        switch (skt->nr) {
  69        case 0:
  70                /* just fill in fix states */
  71                state->bvd1   = (status & ConXS_CFSR_BVD1) ? 1 : 0;
  72                state->bvd2   = (status & ConXS_CFSR_BVD2) ? 1 : 0;
  73                state->vs_3v  = (status & ConXS_CFSR_VS1) ? 0 : 1;
  74                state->vs_Xv  = (status & ConXS_CFSR_VS2) ? 0 : 1;
  75                break;
  76
  77#ifndef CONFIG_MACH_TRIZEPS_CONXS
  78        /* on ConXS we only have one slot. Second is inactive */
  79        case 1:
  80                state->detect = 0;
  81                state->ready  = 0;
  82                state->bvd1   = 0;
  83                state->bvd2   = 0;
  84                state->vs_3v  = 0;
  85                state->vs_Xv  = 0;
  86                break;
  87
  88#endif
  89        }
  90}
  91
  92static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  93                                const socket_state_t *state)
  94{
  95        int ret = 0;
  96        unsigned short power = 0;
  97
  98        /* we do nothing here just check a bit */
  99        switch (state->Vcc) {
 100        case 0:  power &= 0xfc; break;
 101        case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
 102        case 50:
 103                pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
 104                break;
 105        default:
 106                pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
 107                ret = -1;
 108        }
 109
 110        switch (state->Vpp) {
 111        case 0:  power &= 0xf3; break;
 112        case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
 113        case 120:
 114                pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
 115                break;
 116        default:
 117                if (state->Vpp != state->Vcc) {
 118                        pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
 119                        ret = -1;
 120                }
 121        }
 122
 123        switch (skt->nr) {
 124        case 0:                  /* we only have 3.3V */
 125                board_pcmcia_power(power);
 126                break;
 127
 128#ifndef CONFIG_MACH_TRIZEPS_CONXS
 129        /* on ConXS we only have one slot. Second is inactive */
 130        case 1:
 131#endif
 132        default:
 133                break;
 134        }
 135
 136        return ret;
 137}
 138
 139static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 140{
 141        /* default is on */
 142        board_pcmcia_power(0x9);
 143}
 144
 145static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 146{
 147        board_pcmcia_power(0x0);
 148}
 149
 150static struct pcmcia_low_level trizeps_pcmcia_ops = {
 151        .owner                  = THIS_MODULE,
 152        .hw_init                = trizeps_pcmcia_hw_init,
 153        .socket_state           = trizeps_pcmcia_socket_state,
 154        .configure_socket       = trizeps_pcmcia_configure_socket,
 155        .socket_init            = trizeps_pcmcia_socket_init,
 156        .socket_suspend         = trizeps_pcmcia_socket_suspend,
 157#ifdef CONFIG_MACH_TRIZEPS_CONXS
 158        .nr                     = 1,
 159#else
 160        .nr                     = 2,
 161#endif
 162        .first                  = 0,
 163};
 164
 165static struct platform_device *trizeps_pcmcia_device;
 166
 167static int __init trizeps_pcmcia_init(void)
 168{
 169        int ret;
 170
 171        if (!machine_is_trizeps4() && !machine_is_trizeps4wl())
 172                return -ENODEV;
 173
 174        trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
 175        if (!trizeps_pcmcia_device)
 176                return -ENOMEM;
 177
 178        ret = platform_device_add_data(trizeps_pcmcia_device,
 179                        &trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
 180
 181        if (ret == 0)
 182                ret = platform_device_add(trizeps_pcmcia_device);
 183
 184        if (ret)
 185                platform_device_put(trizeps_pcmcia_device);
 186
 187        return ret;
 188}
 189
 190static void __exit trizeps_pcmcia_exit(void)
 191{
 192        platform_device_unregister(trizeps_pcmcia_device);
 193}
 194
 195fs_initcall(trizeps_pcmcia_init);
 196module_exit(trizeps_pcmcia_exit);
 197
 198MODULE_LICENSE("GPL");
 199MODULE_AUTHOR("Juergen Schindele");
 200MODULE_ALIAS("platform:pxa2xx-pcmcia");
 201