blob: 4d960854c2069c27e9fbe164e3a8dfa5366d6d80 [file] [log] [blame]
wdenk4f7cb082003-09-11 23:06:34 +00001/*
2 * Functions to access the TSC2000 controller on TRAB board (used for scanning
3 * thermo sensors)
4 *
5 * Copyright (C) 2003 Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de
6 *
7 * Copyright (C) 2002 DENX Software Engineering, Wolfgang Denk, wd@denx.de
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28#include <common.h>
29#include <s3c2400.h>
30#include "tsc2000.h"
31
32void spi_init(void)
33{
34 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
35 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
36 int i;
37
38 /* Configure I/O ports. */
39 gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000;
40 gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000;
41 gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000;
42 gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000;
43
44 CLR_CS_TOUCH();
45
46 spi->ch[0].SPPRE = 0x1F; /* Baud-rate ca. 514kHz */
47 spi->ch[0].SPPIN = 0x01; /* SPI-MOSI holds Level after last bit */
48 spi->ch[0].SPCON = 0x1A; /* Polling, Prescaler, Master, CPOL=0,
49 CPHA=1 */
50
51 /* Dummy byte ensures clock to be low. */
52 for (i = 0; i < 10; i++) {
53 spi->ch[0].SPTDAT = 0xFF;
54 }
55 spi_wait_transmit_done();
56}
57
58
59static void spi_wait_transmit_done(void)
60{
61 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
62
63 while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
64}
65
66
67static void tsc2000_write(unsigned short reg, unsigned short data)
68{
69 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
70 unsigned int command;
71
72 SET_CS_TOUCH();
73 command = reg;
74 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
75 spi_wait_transmit_done();
76 spi->ch[0].SPTDAT = (command & 0x00FF);
77 spi_wait_transmit_done();
78 spi->ch[0].SPTDAT = (data & 0xFF00) >> 8;
79 spi_wait_transmit_done();
80 spi->ch[0].SPTDAT = (data & 0x00FF);
81 spi_wait_transmit_done();
82
83 CLR_CS_TOUCH();
84}
85
86
87static unsigned short tsc2000_read (unsigned short reg)
88{
89 unsigned short command, data;
90 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
91
92 SET_CS_TOUCH();
93 command = 0x8000 | reg;
94
95 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
96 spi_wait_transmit_done();
97 spi->ch[0].SPTDAT = (command & 0x00FF);
98 spi_wait_transmit_done();
99
100 spi->ch[0].SPTDAT = 0xFF;
101 spi_wait_transmit_done();
102 data = spi->ch[0].SPRDAT;
103 spi->ch[0].SPTDAT = 0xFF;
104 spi_wait_transmit_done();
105
106 CLR_CS_TOUCH();
107 return (spi->ch[0].SPRDAT & 0x0FF) | (data << 8);
108}
109
110
111static void tsc2000_set_mux (unsigned int channel)
112{
113 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
114
115 CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
116 CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
117 switch (channel) {
118 case 0:
119 CLR_MUX0; CLR_MUX1;
120 SET_MUX1_ENABLE;
121 break;
122 case 1:
123 SET_MUX0; CLR_MUX1;
124 SET_MUX1_ENABLE;
125 break;
126 case 2:
127 CLR_MUX0; SET_MUX1;
128 SET_MUX1_ENABLE;
129 break;
130 case 3:
131 SET_MUX0; SET_MUX1;
132 SET_MUX1_ENABLE;
133 break;
134 case 4:
135 CLR_MUX0; CLR_MUX1;
136 SET_MUX2_ENABLE;
137 break;
138 case 5:
139 SET_MUX0; CLR_MUX1;
140 SET_MUX2_ENABLE;
141 break;
142 case 6:
143 CLR_MUX0; SET_MUX1;
144 SET_MUX2_ENABLE;
145 break;
146 case 7:
147 SET_MUX0; SET_MUX1;
148 SET_MUX2_ENABLE;
149 break;
150 case 8:
151 CLR_MUX0; CLR_MUX1;
152 SET_MUX3_ENABLE;
153 break;
154 case 9:
155 SET_MUX0; CLR_MUX1;
156 SET_MUX3_ENABLE;
157 break;
158 case 10:
159 CLR_MUX0; SET_MUX1;
160 SET_MUX3_ENABLE;
161 break;
162 case 11:
163 SET_MUX0; SET_MUX1;
164 SET_MUX3_ENABLE;
165 break;
166 case 12:
167 CLR_MUX0; CLR_MUX1;
168 SET_MUX4_ENABLE;
169 break;
170 case 13:
171 SET_MUX0; CLR_MUX1;
172 SET_MUX4_ENABLE;
173 break;
174 case 14:
175 CLR_MUX0; SET_MUX1;
176 SET_MUX4_ENABLE;
177 break;
178 case 15:
179 SET_MUX0; SET_MUX1;
180 SET_MUX4_ENABLE;
181 break;
182 default:
183 CLR_MUX0; CLR_MUX1;
184 }
185}
186
187
188static void tsc2000_set_range (unsigned int range)
189{
190 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
191
192 switch (range) {
193 case 1:
194 CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
195 CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
196 break;
197 case 2:
198 CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
199 CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
200 break;
201 case 3:
202 SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
203 SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
204 break;
205 }
206}
207
208
209static u16 tsc2000_read_channel (unsigned int channel)
210{
211 u16 res;
212
213 tsc2000_set_mux(channel);
214 udelay(3 * TSC2000_DELAY_BASE);
215
216 tsc2000_write(TSC2000_REG_ADC, 0x2036);
217 adc_wait_conversion_done ();
218 res = tsc2000_read(TSC2000_REG_AUX1);
219 return res;
220}
221
222
223s32 tsc2000_contact_temp (void)
224{
225 long adc_pt1000, offset;
226 long u_pt1000;
227 long contact_temp;
228
229
230 tsc2000_reg_init ();
231 tsc2000_set_range (3);
232
233 adc_pt1000 = tsc2000_read_channel (14);
234 debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
235
236 offset = tsc2000_read_channel (15);
237 debug ("read channel 15 (offset): %ld\n", offset);
238
239 /*
240 * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
241 * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
242 * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
243 * error correction Values err_vref and err_amp3 are assumed as 0 in
244 * u-boot, because this could cause only a very small error (< 1%).
245 */
246 u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
247 debug ("u_pt1000: %ld\n", u_pt1000);
248
249 if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
250 &contact_temp) == -1) {
251 printf ("%s: error interpolating PT1000 vlaue\n",
252 __FUNCTION__);
253 return (-1000);
254 }
255 debug ("contact_temp: %ld\n", contact_temp);
256
257 return contact_temp;
258}
259
260
261void tsc2000_reg_init (void)
262{
263 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
264
265 tsc2000_write(TSC2000_REG_ADC, 0x2036);
266 tsc2000_write(TSC2000_REG_REF, 0x0011);
267 tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
268
269 CON_MUX0;
270 CON_MUX1;
271
272 CON_MUX1_ENABLE;
273 CON_MUX2_ENABLE;
274 CON_MUX3_ENABLE;
275 CON_MUX4_ENABLE;
276
277 CON_SEL_TEMP_V_0;
278 CON_SEL_TEMP_V_1;
279 CON_SEL_TEMP_V_2;
280 CON_SEL_TEMP_V_3;
281
282 tsc2000_set_mux(0);
283 tsc2000_set_range(0);
284}
285
286
287static int tsc2000_interpolate(long value, long data[][2], long *result)
288{
289 int i;
290
291 /* the data is sorted and the first element is upper
292 * limit so we can easily check for out-of-band values
293 */
294 if (data[0][0] < value || data[1][0] > value)
295 return -1;
296
297 i = 1;
298 while (data[i][0] < value)
299 i++;
300
301 /* To prevent overflow we have to store the intermediate
302 result in 'long long'.
303 */
304
305 *result = data[i-1][1] +
306 ((unsigned long long)(data[i][1] - data[i-1][1])
307 * (unsigned long long)(value - data[i-1][0]))
308 / (data[i][0] - data[i-1][0]);
309
310 return 0;
311}
312
313
314static void adc_wait_conversion_done(void)
315{
316 while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
317}