1 /*
2  * linux/drivers/pcmcia/sa1100_badge4.c
3  *
4  * BadgePAD 4 PCMCIA specific routines
5  *
6  *   Christopher Hoover <ch@hpl.hp.com>
7  *
8  * Copyright (C) 2002 Hewlett-Packard Company
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/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/init.h>
18 
19 #include <asm/hardware.h>
20 #include <asm/arch/badge4.h>
21 #include <asm/hardware/sa1111.h>
22 
23 #include "sa1100_generic.h"
24 #include "sa1111_generic.h"
25 
26 /*
27  * BadgePAD 4 Details
28  *
29  * PCM Vcc:
30  *
31  *  PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3
32  *  on JP6) or 5V (short pins 3 and 5 on JP6).  N.B., 5V supply rail
33  *  is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24).
34  *
35  * PCM Vpp:
36  *
37  *  PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4
38  *  on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6).  N.B., 12V
39  *  operation requires that the power supply actually supply 12V.
40  *
41  * CF Vcc:
42  *
43  *  CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1
44  *  and 2 on JP10) or 5V (short pins 2 and 3 on JP10).  The note above
45  *  about the 5V supply rail applies.
46  *
47  * There's no way programmatically to determine how a given board is
48  * jumpered.  This code assumes a default jumpering: 5V PCM Vcc (pins
49  * 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and
50  * no jumpering for CF Vcc.  If this isn't correct, Override these
51  * defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf
52  * vcc>.  E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp,
53  * and 5.0V CF Vcc.
54  *
55  */
56 
57 static int badge4_pcmvcc = 50;
58 static int badge4_pcmvpp = 50;
59 static int badge4_cfvcc = 0;
60 
badge4_pcmcia_init(struct pcmcia_init * init)61 static int badge4_pcmcia_init(struct pcmcia_init *init)
62 {
63 	printk(KERN_INFO __FUNCTION__
64 	       ": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
65 	       badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
66 
67 	return sa1111_pcmcia_init(init);
68 }
69 
badge4_pcmcia_shutdown(void)70 static int badge4_pcmcia_shutdown(void)
71 {
72 	int rc = sa1111_pcmcia_shutdown();
73 
74 	/* be sure to disable 5V use */
75 	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
76 	badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
77 
78 	return rc;
79 }
80 
complain_about_jumpering(const char * whom,const char * supply,int given,int wanted)81 static void complain_about_jumpering(const char *whom,
82 				     const char *supply,
83 				     int given, int wanted)
84 {
85 	printk(KERN_ERR
86 	 "%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
87 	 "; re-jumper the board and/or use pcmv=xx,xx,xx\n",
88 	       whom, supply,
89 	       wanted / 10, wanted % 10,
90 	       supply,
91 	       given / 10, given % 10);
92 }
93 
94 static unsigned badge4_need_5V_bitmap = 0;
95 
96 static int
badge4_pcmcia_configure_socket(const struct pcmcia_configure * conf)97 badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf)
98 {
99 	int ret;
100 
101 	switch (conf->sock) {
102 	case 0:
103 		if ((conf->vcc != 0) &&
104 		    (conf->vcc != badge4_pcmvcc)) {
105 			complain_about_jumpering(__FUNCTION__, "pcmvcc",
106 						 badge4_pcmvcc, conf->vcc);
107 			return -1;
108 		}
109 		if ((conf->vpp != 0) &&
110 		    (conf->vpp != badge4_pcmvpp)) {
111 			complain_about_jumpering(__FUNCTION__, "pcmvpp",
112 						 badge4_pcmvpp, conf->vpp);
113 			return -1;
114 		}
115 		break;
116 
117 	case 1:
118 		if ((conf->vcc != 0) &&
119 		    (conf->vcc != badge4_cfvcc)) {
120 			complain_about_jumpering(__FUNCTION__, "cfvcc",
121 						 badge4_cfvcc, conf->vcc);
122 			return -1;
123 		}
124 		break;
125 
126 	default:
127 		return -1;
128 	}
129 
130 	ret = sa1111_pcmcia_configure_socket(conf);
131 	if (ret == 0) {
132 		unsigned long flags;
133 		int need5V;
134 
135 		local_irq_save(flags);
136 
137 		need5V = ((conf->vcc == 50) || (conf->vpp == 50));
138 
139 		badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
140 
141 		local_irq_restore(flags);
142 	}
143 
144 	return 0;
145 }
146 
147 struct pcmcia_low_level badge4_pcmcia_ops = {
148 	init:			badge4_pcmcia_init,
149 	shutdown:		badge4_pcmcia_shutdown,
150 	socket_state:		sa1111_pcmcia_socket_state,
151 	get_irq_info:		sa1111_pcmcia_get_irq_info,
152 	configure_socket:	badge4_pcmcia_configure_socket,
153 
154 	socket_init:		sa1111_pcmcia_socket_init,
155 	socket_suspend:		sa1111_pcmcia_socket_suspend,
156 };
157 
158 
pcmv_setup(char * s)159 static int __init pcmv_setup(char *s)
160 {
161 	int v[4];
162 
163 	s = get_options(s, ARRAY_SIZE(v), v);
164 
165 	if (v[0] >= 1) badge4_pcmvcc = v[1];
166 	if (v[0] >= 2) badge4_pcmvpp = v[2];
167 	if (v[0] >= 3) badge4_cfvcc = v[3];
168 
169 	return 1;
170 }
171 
172 __setup("pcmv=", pcmv_setup);
173