| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/drivers/pcmcia/pxa2xx_lubbock.c | 
 | 3 |  * | 
 | 4 |  * Author:	George Davis | 
 | 5 |  * Created:	Jan 10, 2002 | 
 | 6 |  * Copyright:	MontaVista Software Inc. | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or modify | 
 | 9 |  * it under the terms of the GNU General Public License version 2 as | 
 | 10 |  * published by the Free Software Foundation. | 
 | 11 |  * | 
 | 12 |  * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c | 
 | 13 |  * | 
 | 14 |  * Lubbock PCMCIA specific routines. | 
 | 15 |  * | 
 | 16 |  */ | 
 | 17 | #include <linux/module.h> | 
 | 18 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include <linux/device.h> | 
 | 20 | #include <linux/errno.h> | 
 | 21 | #include <linux/init.h> | 
 | 22 | #include <linux/delay.h> | 
 | 23 |  | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 24 | #include <mach/hardware.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | #include <asm/hardware/sa1111.h> | 
 | 26 | #include <asm/mach-types.h> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 27 | #include <mach/lubbock.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 |  | 
 | 29 | #include "sa1111_generic.h" | 
 | 30 |  | 
 | 31 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 32 | lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | 
 | 33 | 				const socket_state_t *state) | 
 | 34 | { | 
| Russell King - ARM Linux | 701a5dc | 2009-03-29 19:42:44 +0100 | [diff] [blame] | 35 | 	struct sa1111_pcmcia_socket *s = to_skt(skt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | 	unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; | 
 | 37 | 	int ret = 0; | 
 | 38 |  | 
 | 39 | 	pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0; | 
 | 40 |  | 
 | 41 | 	/* Lubbock uses the Maxim MAX1602, with the following connections: | 
 | 42 | 	 * | 
 | 43 | 	 * Socket 0 (PCMCIA): | 
 | 44 | 	 *	MAX1602	Lubbock		Register | 
 | 45 | 	 *	Pin	Signal | 
 | 46 | 	 *	-----	-------		---------------------- | 
 | 47 | 	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0> | 
 | 48 | 	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1> | 
 | 49 | 	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2> | 
 | 50 | 	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3> | 
 | 51 | 	 *	VX	VCC | 
 | 52 | 	 *	VY	+3.3V | 
 | 53 | 	 *	12IN	+12V | 
 | 54 | 	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY) | 
 | 55 | 	 * | 
 | 56 | 	 * Socket 1 (CF): | 
 | 57 | 	 *	MAX1602	Lubbock		Register | 
 | 58 | 	 *	Pin	Signal | 
 | 59 | 	 *	-----	-------		---------------------- | 
 | 60 | 	 *	A0VPP	GND		VPP is not connected | 
 | 61 | 	 *	A1VPP	GND		VPP is not connected | 
 | 62 | 	 *	A0VCC	S1_PWR0		MISC_WR<14> | 
 | 63 | 	 *	A1VCC	S1_PWR1		MISC_WR<15> | 
 | 64 | 	 *	VX	VCC | 
 | 65 | 	 *	VY	+3.3V | 
 | 66 | 	 *	12IN	GND		VPP is not connected | 
 | 67 | 	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY) | 
 | 68 | 	 * | 
 | 69 | 	 */ | 
 | 70 |  | 
 | 71 |  again: | 
 | 72 | 	switch (skt->nr) { | 
 | 73 | 	case 0: | 
 | 74 | 		pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; | 
 | 75 |  | 
 | 76 | 		switch (state->Vcc) { | 
 | 77 | 		case 0: /* Hi-Z */ | 
 | 78 | 			break; | 
 | 79 |  | 
 | 80 | 		case 33: /* VY */ | 
 | 81 | 			pa_dwr_set |= GPIO_A3; | 
 | 82 | 			break; | 
 | 83 |  | 
 | 84 | 		case 50: /* VX */ | 
 | 85 | 			pa_dwr_set |= GPIO_A2; | 
 | 86 | 			break; | 
 | 87 |  | 
 | 88 | 		default: | 
 | 89 | 			printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | 
| Harvey Harrison | 2e11cb4 | 2008-05-01 04:34:54 -0700 | [diff] [blame] | 90 | 			       __func__, state->Vcc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | 			ret = -1; | 
 | 92 | 		} | 
 | 93 |  | 
 | 94 | 		switch (state->Vpp) { | 
 | 95 | 		case 0: /* Hi-Z */ | 
 | 96 | 			break; | 
 | 97 |  | 
 | 98 | 		case 120: /* 12IN */ | 
 | 99 | 			pa_dwr_set |= GPIO_A1; | 
 | 100 | 			break; | 
 | 101 |  | 
 | 102 | 		default: /* VCC */ | 
 | 103 | 			if (state->Vpp == state->Vcc) | 
 | 104 | 				pa_dwr_set |= GPIO_A0; | 
 | 105 | 			else { | 
 | 106 | 				printk(KERN_ERR "%s(): unrecognized Vpp %u\n", | 
| Harvey Harrison | 2e11cb4 | 2008-05-01 04:34:54 -0700 | [diff] [blame] | 107 | 				       __func__, state->Vpp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | 				ret = -1; | 
 | 109 | 				break; | 
 | 110 | 			} | 
 | 111 | 		} | 
 | 112 | 		break; | 
 | 113 |  | 
 | 114 | 	case 1: | 
 | 115 | 		misc_mask = (1 << 15) | (1 << 14); | 
 | 116 |  | 
 | 117 | 		switch (state->Vcc) { | 
 | 118 | 		case 0: /* Hi-Z */ | 
 | 119 | 			break; | 
 | 120 |  | 
 | 121 | 		case 33: /* VY */ | 
 | 122 | 			misc_set |= 1 << 15; | 
 | 123 | 			break; | 
 | 124 |  | 
 | 125 | 		case 50: /* VX */ | 
 | 126 | 			misc_set |= 1 << 14; | 
 | 127 | 			break; | 
 | 128 |  | 
 | 129 | 		default: | 
 | 130 | 			printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | 
| Harvey Harrison | 2e11cb4 | 2008-05-01 04:34:54 -0700 | [diff] [blame] | 131 | 			       __func__, state->Vcc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | 			ret = -1; | 
 | 133 | 			break; | 
 | 134 | 		} | 
 | 135 |  | 
 | 136 | 		if (state->Vpp != state->Vcc && state->Vpp != 0) { | 
 | 137 | 			printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", | 
| Harvey Harrison | 2e11cb4 | 2008-05-01 04:34:54 -0700 | [diff] [blame] | 138 | 			       __func__, state->Vpp); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 139 | 			ret = -1; | 
 | 140 | 			break; | 
 | 141 | 		} | 
 | 142 | 		break; | 
 | 143 |  | 
 | 144 | 	default: | 
 | 145 | 		ret = -1; | 
 | 146 | 	} | 
 | 147 |  | 
 | 148 | 	if (ret == 0) | 
 | 149 | 		ret = sa1111_pcmcia_configure_socket(skt, state); | 
 | 150 |  | 
 | 151 | 	if (ret == 0) { | 
 | 152 | 		lubbock_set_misc_wr(misc_mask, misc_set); | 
| Russell King - ARM Linux | 701a5dc | 2009-03-29 19:42:44 +0100 | [diff] [blame] | 153 | 		sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 154 | 	} | 
 | 155 |  | 
 | 156 | #if 1 | 
 | 157 | 	if (ret == 0 && state->Vcc == 33) { | 
 | 158 | 		struct pcmcia_state new_state; | 
 | 159 |  | 
 | 160 | 		/* | 
 | 161 | 		 * HACK ALERT: | 
 | 162 | 		 * We can't sense the voltage properly on Lubbock before | 
 | 163 | 		 * actually applying some power to the socket (catch 22). | 
 | 164 | 		 * Resense the socket Voltage Sense pins after applying | 
 | 165 | 		 * socket power. | 
 | 166 | 		 * | 
 | 167 | 		 * Note: It takes about 2.5ms for the MAX1602 VCC output | 
 | 168 | 		 * to rise. | 
 | 169 | 		 */ | 
 | 170 | 		mdelay(3); | 
 | 171 |  | 
 | 172 | 		sa1111_pcmcia_socket_state(skt, &new_state); | 
 | 173 |  | 
 | 174 | 		if (!new_state.vs_3v && !new_state.vs_Xv) { | 
 | 175 | 			/* | 
 | 176 | 			 * Switch to 5V,  Configure socket with 5V voltage | 
 | 177 | 			 */ | 
 | 178 | 			lubbock_set_misc_wr(misc_mask, 0); | 
| Russell King - ARM Linux | 701a5dc | 2009-03-29 19:42:44 +0100 | [diff] [blame] | 179 | 			sa1111_set_io(s->dev, pa_dwr_mask, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 |  | 
 | 181 | 			/* | 
 | 182 | 			 * It takes about 100ms to turn off Vcc. | 
 | 183 | 			 */ | 
 | 184 | 			mdelay(100); | 
 | 185 |  | 
 | 186 | 			/* | 
 | 187 | 			 * We need to hack around the const qualifier as | 
 | 188 | 			 * well to keep this ugly workaround localized and | 
 | 189 | 			 * not force it to the rest of the code. Barf bags | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 190 | 			 * available in the seat pocket in front of you! | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | 			 */ | 
 | 192 | 			((socket_state_t *)state)->Vcc = 50; | 
 | 193 | 			((socket_state_t *)state)->Vpp = 50; | 
 | 194 | 			goto again; | 
 | 195 | 		} | 
 | 196 | 	} | 
 | 197 | #endif | 
 | 198 |  | 
 | 199 | 	return ret; | 
 | 200 | } | 
 | 201 |  | 
 | 202 | static struct pcmcia_low_level lubbock_pcmcia_ops = { | 
 | 203 | 	.owner			= THIS_MODULE, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 204 | 	.configure_socket	= lubbock_pcmcia_configure_socket, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 205 | 	.first			= 0, | 
 | 206 | 	.nr			= 2, | 
 | 207 | }; | 
 | 208 |  | 
 | 209 | #include "pxa2xx_base.h" | 
 | 210 |  | 
| David Brownell | 7bbaac1 | 2007-12-22 14:03:29 -0800 | [diff] [blame] | 211 | int pcmcia_lubbock_init(struct sa1111_dev *sadev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 212 | { | 
 | 213 | 	int ret = -ENODEV; | 
 | 214 |  | 
 | 215 | 	if (machine_is_lubbock()) { | 
 | 216 | 		/* | 
 | 217 | 		 * Set GPIO_A<3:0> to be outputs for the MAX1600, | 
 | 218 | 		 * and switch to standby mode. | 
 | 219 | 		 */ | 
 | 220 | 		sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | 
 | 221 | 		sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | 
 | 222 | 		sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | 
 | 223 |  | 
 | 224 | 		/* Set CF Socket 1 power to standby mode. */ | 
 | 225 | 		lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); | 
 | 226 |  | 
| Russell King - ARM Linux | 701a5dc | 2009-03-29 19:42:44 +0100 | [diff] [blame] | 227 | 		pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); | 
| Pavel Machek | 5b70368 | 2011-02-04 09:03:43 +0100 | [diff] [blame] | 228 | 		pxa2xx_configure_sockets(&sadev->dev); | 
| Russell King - ARM Linux | 701a5dc | 2009-03-29 19:42:44 +0100 | [diff] [blame] | 229 | 		ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, | 
 | 230 | 				pxa2xx_drv_pcmcia_add_one); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | 	} | 
 | 232 |  | 
 | 233 | 	return ret; | 
 | 234 | } | 
 | 235 |  | 
 | 236 | MODULE_LICENSE("GPL"); |