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