blob: ca6868212eadb9a4ea45c3513602029b61ac1daa [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
wdenkf5300ab2003-09-12 15:35:15 +000032#include "Pt1000_temp_data.h"
33
wdenk151ab832005-02-24 22:44:16 +000034/* helper function */
35#define abs(value) (((value) < 0) ? ((value)*-1) : (value))
36
37/*
38 * Maximal allowed deviation between two immediate meassurments of an analog
39 * thermo channel. 1 DIGIT = 0.0276 °C. This is used to filter sporadic
40 * "jumps" in measurment.
41 */
42#define MAX_DEVIATION 18 /* unit: DIGITs of adc; 18 DIGIT = 0.5 °C */
43
wdenk4f7cb082003-09-11 23:06:34 +000044void spi_init(void)
45{
46 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
47 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
48 int i;
49
50 /* Configure I/O ports. */
wdenk42d1f032003-10-15 23:53:47 +000051 gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000;
wdenk4f7cb082003-09-11 23:06:34 +000052 gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000;
53 gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000;
54 gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000;
55
56 CLR_CS_TOUCH();
57
58 spi->ch[0].SPPRE = 0x1F; /* Baud-rate ca. 514kHz */
59 spi->ch[0].SPPIN = 0x01; /* SPI-MOSI holds Level after last bit */
60 spi->ch[0].SPCON = 0x1A; /* Polling, Prescaler, Master, CPOL=0,
wdenk42d1f032003-10-15 23:53:47 +000061 CPHA=1 */
wdenk4f7cb082003-09-11 23:06:34 +000062
63 /* Dummy byte ensures clock to be low. */
64 for (i = 0; i < 10; i++) {
65 spi->ch[0].SPTDAT = 0xFF;
66 }
67 spi_wait_transmit_done();
68}
69
70
wdenkf5300ab2003-09-12 15:35:15 +000071void spi_wait_transmit_done(void)
wdenk4f7cb082003-09-11 23:06:34 +000072{
73 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
74
75 while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
76}
77
78
wdenkf5300ab2003-09-12 15:35:15 +000079void tsc2000_write(unsigned short reg, unsigned short data)
wdenk4f7cb082003-09-11 23:06:34 +000080{
81 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
82 unsigned int command;
83
84 SET_CS_TOUCH();
85 command = reg;
wdenk42d1f032003-10-15 23:53:47 +000086 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000087 spi_wait_transmit_done();
88 spi->ch[0].SPTDAT = (command & 0x00FF);
89 spi_wait_transmit_done();
90 spi->ch[0].SPTDAT = (data & 0xFF00) >> 8;
91 spi_wait_transmit_done();
92 spi->ch[0].SPTDAT = (data & 0x00FF);
93 spi_wait_transmit_done();
94
95 CLR_CS_TOUCH();
96}
97
98
wdenkf5300ab2003-09-12 15:35:15 +000099unsigned short tsc2000_read (unsigned short reg)
wdenk4f7cb082003-09-11 23:06:34 +0000100{
101 unsigned short command, data;
102 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
103
104 SET_CS_TOUCH();
105 command = 0x8000 | reg;
106
wdenk42d1f032003-10-15 23:53:47 +0000107 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +0000108 spi_wait_transmit_done();
109 spi->ch[0].SPTDAT = (command & 0x00FF);
110 spi_wait_transmit_done();
111
wdenk42d1f032003-10-15 23:53:47 +0000112 spi->ch[0].SPTDAT = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +0000113 spi_wait_transmit_done();
114 data = spi->ch[0].SPRDAT;
115 spi->ch[0].SPTDAT = 0xFF;
116 spi_wait_transmit_done();
117
118 CLR_CS_TOUCH();
119 return (spi->ch[0].SPRDAT & 0x0FF) | (data << 8);
120}
121
122
wdenkf5300ab2003-09-12 15:35:15 +0000123void tsc2000_set_mux (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000124{
wdenk42d1f032003-10-15 23:53:47 +0000125 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000126
127 CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
128 CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
129 switch (channel) {
130 case 0:
131 CLR_MUX0; CLR_MUX1;
132 SET_MUX1_ENABLE;
133 break;
134 case 1:
135 SET_MUX0; CLR_MUX1;
136 SET_MUX1_ENABLE;
137 break;
138 case 2:
139 CLR_MUX0; SET_MUX1;
140 SET_MUX1_ENABLE;
141 break;
142 case 3:
143 SET_MUX0; SET_MUX1;
144 SET_MUX1_ENABLE;
145 break;
146 case 4:
147 CLR_MUX0; CLR_MUX1;
148 SET_MUX2_ENABLE;
149 break;
150 case 5:
151 SET_MUX0; CLR_MUX1;
152 SET_MUX2_ENABLE;
153 break;
154 case 6:
155 CLR_MUX0; SET_MUX1;
156 SET_MUX2_ENABLE;
157 break;
158 case 7:
159 SET_MUX0; SET_MUX1;
160 SET_MUX2_ENABLE;
161 break;
162 case 8:
163 CLR_MUX0; CLR_MUX1;
164 SET_MUX3_ENABLE;
165 break;
166 case 9:
167 SET_MUX0; CLR_MUX1;
168 SET_MUX3_ENABLE;
169 break;
170 case 10:
171 CLR_MUX0; SET_MUX1;
172 SET_MUX3_ENABLE;
173 break;
174 case 11:
175 SET_MUX0; SET_MUX1;
176 SET_MUX3_ENABLE;
177 break;
178 case 12:
179 CLR_MUX0; CLR_MUX1;
180 SET_MUX4_ENABLE;
181 break;
182 case 13:
183 SET_MUX0; CLR_MUX1;
184 SET_MUX4_ENABLE;
185 break;
186 case 14:
187 CLR_MUX0; SET_MUX1;
188 SET_MUX4_ENABLE;
189 break;
190 case 15:
191 SET_MUX0; SET_MUX1;
192 SET_MUX4_ENABLE;
193 break;
194 default:
195 CLR_MUX0; CLR_MUX1;
196 }
197}
198
199
wdenkf5300ab2003-09-12 15:35:15 +0000200void tsc2000_set_range (unsigned int range)
wdenk4f7cb082003-09-11 23:06:34 +0000201{
wdenk42d1f032003-10-15 23:53:47 +0000202 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000203
204 switch (range) {
205 case 1:
206 CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
207 CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
208 break;
209 case 2:
210 CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
211 CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
212 break;
213 case 3:
214 SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
215 SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
216 break;
217 }
218}
219
220
wdenkf5300ab2003-09-12 15:35:15 +0000221u16 tsc2000_read_channel (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000222{
223 u16 res;
224
225 tsc2000_set_mux(channel);
226 udelay(3 * TSC2000_DELAY_BASE);
227
228 tsc2000_write(TSC2000_REG_ADC, 0x2036);
wdenk42d1f032003-10-15 23:53:47 +0000229 adc_wait_conversion_done ();
230 res = tsc2000_read(TSC2000_REG_AUX1);
wdenk4f7cb082003-09-11 23:06:34 +0000231 return res;
232}
233
234
235s32 tsc2000_contact_temp (void)
236{
237 long adc_pt1000, offset;
wdenk42d1f032003-10-15 23:53:47 +0000238 long u_pt1000;
wdenk4f7cb082003-09-11 23:06:34 +0000239 long contact_temp;
wdenk151ab832005-02-24 22:44:16 +0000240 long temp1, temp2;
wdenk4f7cb082003-09-11 23:06:34 +0000241
wdenk42d1f032003-10-15 23:53:47 +0000242 tsc2000_reg_init ();
wdenk4f7cb082003-09-11 23:06:34 +0000243 tsc2000_set_range (3);
244
wdenk151ab832005-02-24 22:44:16 +0000245 /*
246 * Because of sporadic "jumps" in the measured adc values every
247 * channel is read two times. If there is a significant difference
248 * between the two measurements, then print an error and do a third
249 * measurement, because it is very unlikely that a successive third
250 * measurement goes also wrong.
251 */
252 temp1 = tsc2000_read_channel (14);
253 temp2 = tsc2000_read_channel (14);
254 if (abs(temp2 - temp1) < MAX_DEVIATION)
255 adc_pt1000 = temp2;
256 else {
257 printf ("%s: read adc value (channel 14) exceeded max allowed "
258 "deviation: %d * 0.0276 °C\n",
259 __FUNCTION__, MAX_DEVIATION);
260 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
261 temp1, temp2);
262 adc_pt1000 = tsc2000_read_channel (14);
263 printf ("use (third read) adc value: adc_pt1000 = "
264 "%ld DIGITs\n", adc_pt1000);
265 }
wdenk42d1f032003-10-15 23:53:47 +0000266 debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000267
wdenk151ab832005-02-24 22:44:16 +0000268 temp1 = tsc2000_read_channel (15);
269 temp2 = tsc2000_read_channel (15);
270 if (abs(temp2 - temp1) < MAX_DEVIATION)
271 offset = temp2;
272 else {
273 printf ("%s: read adc value (channel 15) exceeded max allowed "
274 "deviation: %d * 0.0276 °C\n",
275 __FUNCTION__, MAX_DEVIATION);
276 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
277 temp1, temp2);
278 offset = tsc2000_read_channel (15);
279 printf ("use (third read) adc value: offset = %ld DIGITs\n",
280 offset);
281 }
wdenk42d1f032003-10-15 23:53:47 +0000282 debug ("read channel 15 (offset): %ld\n", offset);
wdenk4f7cb082003-09-11 23:06:34 +0000283
wdenk42d1f032003-10-15 23:53:47 +0000284 /*
285 * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
286 * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
287 * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
288 * error correction Values err_vref and err_amp3 are assumed as 0 in
289 * u-boot, because this could cause only a very small error (< 1%).
290 */
291 u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
292 debug ("u_pt1000: %ld\n", u_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000293
wdenk42d1f032003-10-15 23:53:47 +0000294 if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
295 &contact_temp) == -1) {
296 printf ("%s: error interpolating PT1000 vlaue\n",
297 __FUNCTION__);
298 return (-1000);
299 }
300 debug ("contact_temp: %ld\n", contact_temp);
wdenk4f7cb082003-09-11 23:06:34 +0000301
302 return contact_temp;
303}
304
305
306void tsc2000_reg_init (void)
307{
wdenk42d1f032003-10-15 23:53:47 +0000308 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000309
310 tsc2000_write(TSC2000_REG_ADC, 0x2036);
311 tsc2000_write(TSC2000_REG_REF, 0x0011);
312 tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
313
314 CON_MUX0;
315 CON_MUX1;
316
317 CON_MUX1_ENABLE;
318 CON_MUX2_ENABLE;
319 CON_MUX3_ENABLE;
320 CON_MUX4_ENABLE;
321
322 CON_SEL_TEMP_V_0;
323 CON_SEL_TEMP_V_1;
324 CON_SEL_TEMP_V_2;
325 CON_SEL_TEMP_V_3;
326
327 tsc2000_set_mux(0);
328 tsc2000_set_range(0);
329}
330
331
wdenkf5300ab2003-09-12 15:35:15 +0000332int tsc2000_interpolate(long value, long data[][2], long *result)
wdenk4f7cb082003-09-11 23:06:34 +0000333{
334 int i;
335
336 /* the data is sorted and the first element is upper
337 * limit so we can easily check for out-of-band values
338 */
339 if (data[0][0] < value || data[1][0] > value)
340 return -1;
341
342 i = 1;
343 while (data[i][0] < value)
344 i++;
345
346 /* To prevent overflow we have to store the intermediate
347 result in 'long long'.
348 */
349
350 *result = data[i-1][1] +
351 ((unsigned long long)(data[i][1] - data[i-1][1])
352 * (unsigned long long)(value - data[i-1][0]))
353 / (data[i][0] - data[i-1][0]);
354
355 return 0;
356}
357
358
wdenkf5300ab2003-09-12 15:35:15 +0000359void adc_wait_conversion_done(void)
wdenk4f7cb082003-09-11 23:06:34 +0000360{
wdenk42d1f032003-10-15 23:53:47 +0000361 while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
wdenk4f7cb082003-09-11 23:06:34 +0000362}