Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.3 255 lines 6.2 kB view raw
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 struct pcmcia_irqs irqs[] = { 33 { .sock = 0, .str = "cs0_cd" } 34 /* on other baseboards we can have more inputs */ 35}; 36 37static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 38{ 39 int ret, i; 40 /* we dont have voltage/card/ready detection 41 * so we dont need interrupts for it 42 */ 43 switch (skt->nr) { 44 case 0: 45 if (gpio_request(GPIO_PRDY, "cf_irq") < 0) { 46 pr_err("%s: sock %d unable to request gpio %d\n", __func__, 47 skt->nr, GPIO_PRDY); 48 return -EBUSY; 49 } 50 if (gpio_direction_input(GPIO_PRDY) < 0) { 51 pr_err("%s: sock %d unable to set input gpio %d\n", __func__, 52 skt->nr, GPIO_PRDY); 53 gpio_free(GPIO_PRDY); 54 return -EINVAL; 55 } 56 skt->socket.pci_irq = gpio_to_irq(GPIO_PRDY); 57 irqs[0].irq = gpio_to_irq(GPIO_PCD); 58 break; 59 default: 60 break; 61 } 62 /* release the reset of this card */ 63 pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq); 64 65 /* supplementory irqs for the socket */ 66 for (i = 0; i < ARRAY_SIZE(irqs); i++) { 67 if (irqs[i].sock != skt->nr) 68 continue; 69 if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) { 70 pr_err("%s: sock %d unable to request gpio %d\n", 71 __func__, skt->nr, irq_to_gpio(irqs[i].irq)); 72 ret = -EBUSY; 73 goto error; 74 } 75 if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) { 76 pr_err("%s: sock %d unable to set input gpio %d\n", 77 __func__, skt->nr, irq_to_gpio(irqs[i].irq)); 78 ret = -EINVAL; 79 goto error; 80 } 81 } 82 return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); 83 84error: 85 for (; i >= 0; i--) { 86 gpio_free(irq_to_gpio(irqs[i].irq)); 87 } 88 return (ret); 89} 90 91static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 92{ 93 int i; 94 /* free allocated gpio's */ 95 gpio_free(GPIO_PRDY); 96 for (i = 0; i < ARRAY_SIZE(irqs); i++) 97 gpio_free(irq_to_gpio(irqs[i].irq)); 98} 99 100static unsigned long trizeps_pcmcia_status[2]; 101 102static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt, 103 struct pcmcia_state *state) 104{ 105 unsigned short status = 0, change; 106 status = CFSR_readw(); 107 change = (status ^ trizeps_pcmcia_status[skt->nr]) & 108 ConXS_CFSR_BVD_MASK; 109 if (change) { 110 trizeps_pcmcia_status[skt->nr] = status; 111 if (status & ConXS_CFSR_BVD1) { 112 /* enable_irq empty */ 113 } else { 114 /* disable_irq empty */ 115 } 116 } 117 118 switch (skt->nr) { 119 case 0: 120 /* just fill in fix states */ 121 state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1; 122 state->ready = gpio_get_value(GPIO_PRDY) ? 1 : 0; 123 state->bvd1 = (status & ConXS_CFSR_BVD1) ? 1 : 0; 124 state->bvd2 = (status & ConXS_CFSR_BVD2) ? 1 : 0; 125 state->vs_3v = (status & ConXS_CFSR_VS1) ? 0 : 1; 126 state->vs_Xv = (status & ConXS_CFSR_VS2) ? 0 : 1; 127 state->wrprot = 0; /* not available */ 128 break; 129 130#ifndef CONFIG_MACH_TRIZEPS_CONXS 131 /* on ConXS we only have one slot. Second is inactive */ 132 case 1: 133 state->detect = 0; 134 state->ready = 0; 135 state->bvd1 = 0; 136 state->bvd2 = 0; 137 state->vs_3v = 0; 138 state->vs_Xv = 0; 139 state->wrprot = 0; 140 break; 141 142#endif 143 } 144} 145 146static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, 147 const socket_state_t *state) 148{ 149 int ret = 0; 150 unsigned short power = 0; 151 152 /* we do nothing here just check a bit */ 153 switch (state->Vcc) { 154 case 0: power &= 0xfc; break; 155 case 33: power |= ConXS_BCR_S0_VCC_3V3; break; 156 case 50: 157 pr_err("%s(): Vcc 5V not supported in socket\n", __func__); 158 break; 159 default: 160 pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc); 161 ret = -1; 162 } 163 164 switch (state->Vpp) { 165 case 0: power &= 0xf3; break; 166 case 33: power |= ConXS_BCR_S0_VPP_3V3; break; 167 case 120: 168 pr_err("%s(): Vpp 12V not supported in socket\n", __func__); 169 break; 170 default: 171 if (state->Vpp != state->Vcc) { 172 pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp); 173 ret = -1; 174 } 175 } 176 177 switch (skt->nr) { 178 case 0: /* we only have 3.3V */ 179 board_pcmcia_power(power); 180 break; 181 182#ifndef CONFIG_MACH_TRIZEPS_CONXS 183 /* on ConXS we only have one slot. Second is inactive */ 184 case 1: 185#endif 186 default: 187 break; 188 } 189 190 return ret; 191} 192 193static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 194{ 195 /* default is on */ 196 board_pcmcia_power(0x9); 197} 198 199static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 200{ 201 board_pcmcia_power(0x0); 202} 203 204static struct pcmcia_low_level trizeps_pcmcia_ops = { 205 .owner = THIS_MODULE, 206 .hw_init = trizeps_pcmcia_hw_init, 207 .hw_shutdown = trizeps_pcmcia_hw_shutdown, 208 .socket_state = trizeps_pcmcia_socket_state, 209 .configure_socket = trizeps_pcmcia_configure_socket, 210 .socket_init = trizeps_pcmcia_socket_init, 211 .socket_suspend = trizeps_pcmcia_socket_suspend, 212#ifdef CONFIG_MACH_TRIZEPS_CONXS 213 .nr = 1, 214#else 215 .nr = 2, 216#endif 217 .first = 0, 218}; 219 220static struct platform_device *trizeps_pcmcia_device; 221 222static int __init trizeps_pcmcia_init(void) 223{ 224 int ret; 225 226 if (!machine_is_trizeps4() && !machine_is_trizeps4wl()) 227 return -ENODEV; 228 229 trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); 230 if (!trizeps_pcmcia_device) 231 return -ENOMEM; 232 233 ret = platform_device_add_data(trizeps_pcmcia_device, 234 &trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops)); 235 236 if (ret == 0) 237 ret = platform_device_add(trizeps_pcmcia_device); 238 239 if (ret) 240 platform_device_put(trizeps_pcmcia_device); 241 242 return ret; 243} 244 245static void __exit trizeps_pcmcia_exit(void) 246{ 247 platform_device_unregister(trizeps_pcmcia_device); 248} 249 250fs_initcall(trizeps_pcmcia_init); 251module_exit(trizeps_pcmcia_exit); 252 253MODULE_LICENSE("GPL"); 254MODULE_AUTHOR("Juergen Schindele"); 255MODULE_ALIAS("platform:pxa2xx-pcmcia");