trizeps4-pcmcia.c (4524B)
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 "pxa2xx-regs.h" 23#include "trizeps4.h" 24 25#include <pcmcia/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");