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