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