1/* 2 * drivers/pcmcia/sa1100_h3600.c 3 * 4 * PCMCIA implementation routines for H3600 5 * 6 */ 7#include <linux/module.h> 8#include <linux/kernel.h> 9#include <linux/device.h> 10#include <linux/interrupt.h> 11#include <linux/init.h> 12#include <linux/delay.h> 13#include <linux/gpio.h> 14 15#include <mach/hardware.h> 16#include <asm/irq.h> 17#include <asm/mach-types.h> 18#include <mach/h3xxx.h> 19 20#include "sa1100_generic.h" 21 22static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 23{ 24 int err; 25 26 switch (skt->nr) { 27 case 0: 28 skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD0; 29 skt->stat[SOC_STAT_CD].name = "PCMCIA CD0"; 30 skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ0; 31 skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ0"; 32 33 err = gpio_request(H3XXX_EGPIO_OPT_NVRAM_ON, "OPT NVRAM ON"); 34 if (err) 35 goto err01; 36 err = gpio_direction_output(H3XXX_EGPIO_OPT_NVRAM_ON, 0); 37 if (err) 38 goto err03; 39 err = gpio_request(H3XXX_EGPIO_OPT_ON, "OPT ON"); 40 if (err) 41 goto err03; 42 err = gpio_direction_output(H3XXX_EGPIO_OPT_ON, 0); 43 if (err) 44 goto err04; 45 err = gpio_request(H3XXX_EGPIO_OPT_RESET, "OPT RESET"); 46 if (err) 47 goto err04; 48 err = gpio_direction_output(H3XXX_EGPIO_OPT_RESET, 0); 49 if (err) 50 goto err05; 51 err = gpio_request(H3XXX_EGPIO_CARD_RESET, "PCMCIA CARD RESET"); 52 if (err) 53 goto err05; 54 err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0); 55 if (err) 56 goto err06; 57 break; 58 case 1: 59 skt->stat[SOC_STAT_CD].gpio = H3XXX_GPIO_PCMCIA_CD1; 60 skt->stat[SOC_STAT_CD].name = "PCMCIA CD1"; 61 skt->stat[SOC_STAT_RDY].gpio = H3XXX_GPIO_PCMCIA_IRQ1; 62 skt->stat[SOC_STAT_RDY].name = "PCMCIA IRQ1"; 63 break; 64 } 65 return 0; 66 67err06: gpio_free(H3XXX_EGPIO_CARD_RESET); 68err05: gpio_free(H3XXX_EGPIO_OPT_RESET); 69err04: gpio_free(H3XXX_EGPIO_OPT_ON); 70err03: gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON); 71err01: gpio_free(H3XXX_GPIO_PCMCIA_IRQ0); 72 return err; 73} 74 75static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) 76{ 77 switch (skt->nr) { 78 case 0: 79 /* Disable CF bus: */ 80 gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0); 81 gpio_set_value(H3XXX_EGPIO_OPT_ON, 0); 82 gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1); 83 84 gpio_free(H3XXX_EGPIO_CARD_RESET); 85 gpio_free(H3XXX_EGPIO_OPT_RESET); 86 gpio_free(H3XXX_EGPIO_OPT_ON); 87 gpio_free(H3XXX_EGPIO_OPT_NVRAM_ON); 88 break; 89 case 1: 90 break; 91 } 92} 93 94static void 95h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) 96{ 97 state->bvd1 = 0; 98 state->bvd2 = 0; 99 state->vs_3v = 0; 100 state->vs_Xv = 0; 101} 102 103static int 104h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) 105{ 106 if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) { 107 printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", 108 state->Vcc / 10, state->Vcc % 10); 109 return -1; 110 } 111 112 gpio_set_value(H3XXX_EGPIO_CARD_RESET, !!(state->flags & SS_RESET)); 113 114 /* Silently ignore Vpp, output enable, speaker enable. */ 115 116 return 0; 117} 118 119static void h3600_pcmcia_socket_init(struct soc_pcmcia_socket *skt) 120{ 121 /* Enable CF bus: */ 122 gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 1); 123 gpio_set_value(H3XXX_EGPIO_OPT_ON, 1); 124 gpio_set_value(H3XXX_EGPIO_OPT_RESET, 0); 125 126 msleep(10); 127} 128 129static void h3600_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) 130{ 131 /* 132 * FIXME: This doesn't fit well. We don't have the mechanism in 133 * the generic PCMCIA layer to deal with the idea of two sockets 134 * on one bus. We rely on the cs.c behaviour shutting down 135 * socket 0 then socket 1. 136 */ 137 if (skt->nr == 1) { 138 gpio_set_value(H3XXX_EGPIO_OPT_ON, 0); 139 gpio_set_value(H3XXX_EGPIO_OPT_NVRAM_ON, 0); 140 /* hmm, does this suck power? */ 141 gpio_set_value(H3XXX_EGPIO_OPT_RESET, 1); 142 } 143} 144 145struct pcmcia_low_level h3600_pcmcia_ops = { 146 .owner = THIS_MODULE, 147 .hw_init = h3600_pcmcia_hw_init, 148 .hw_shutdown = h3600_pcmcia_hw_shutdown, 149 .socket_state = h3600_pcmcia_socket_state, 150 .configure_socket = h3600_pcmcia_configure_socket, 151 152 .socket_init = h3600_pcmcia_socket_init, 153 .socket_suspend = h3600_pcmcia_socket_suspend, 154}; 155 156int pcmcia_h3600_init(struct device *dev) 157{ 158 int ret = -ENODEV; 159 160 if (machine_is_h3600() || machine_is_h3100()) 161 ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); 162 163 return ret; 164} 165