blob: 426ed9c520bd60462898c8f2e74c85d782a58b71 [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>
kevin.morfitt@fearnside-systems.co.ukac678042009-11-17 18:30:34 +090029#include <asm/arch/s3c24x0_cpu.h>
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +090030#include <asm/io.h>
Sergei Poselenov4265c352008-08-14 14:08:28 +020031#include <div64.h>
wdenk4f7cb082003-09-11 23:06:34 +000032#include "tsc2000.h"
33
wdenkf5300ab2003-09-12 15:35:15 +000034#include "Pt1000_temp_data.h"
35
wdenk151ab832005-02-24 22:44:16 +000036/* helper function */
37#define abs(value) (((value) < 0) ? ((value)*-1) : (value))
38
39/*
40 * Maximal allowed deviation between two immediate meassurments of an analog
41 * thermo channel. 1 DIGIT = 0.0276 °C. This is used to filter sporadic
42 * "jumps" in measurment.
43 */
44#define MAX_DEVIATION 18 /* unit: DIGITs of adc; 18 DIGIT = 0.5 °C */
45
Mike Frysingerf6e3a1f2009-08-13 00:32:14 -040046void tsc2000_spi_init(void)
wdenk4f7cb082003-09-11 23:06:34 +000047{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +090048 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
49 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +000050 int i;
51
52 /* Configure I/O ports. */
C Naumand9abba82010-10-26 23:04:31 +090053 gpio->pdcon = (gpio->pdcon & 0xF3FFFF) | 0x040000;
54 gpio->pgcon = (gpio->pgcon & 0x0F3FFF) | 0x008000;
55 gpio->pgcon = (gpio->pgcon & 0x0CFFFF) | 0x020000;
56 gpio->pgcon = (gpio->pgcon & 0x03FFFF) | 0x080000;
wdenk4f7cb082003-09-11 23:06:34 +000057
58 CLR_CS_TOUCH();
59
C Naumand9abba82010-10-26 23:04:31 +090060 spi->ch[0].sppre = 0x1F; /* Baud-rate ca. 514kHz */
61 spi->ch[0].sppin = 0x01; /* SPI-MOSI holds Level after last bit */
62 spi->ch[0].spcon = 0x1A; /* Polling, Prescaler, Master, CPOL=0,
wdenk42d1f032003-10-15 23:53:47 +000063 CPHA=1 */
wdenk4f7cb082003-09-11 23:06:34 +000064
65 /* Dummy byte ensures clock to be low. */
66 for (i = 0; i < 10; i++) {
C Naumand9abba82010-10-26 23:04:31 +090067 spi->ch[0].sptdat = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +000068 }
69 spi_wait_transmit_done();
70}
71
72
wdenkf5300ab2003-09-12 15:35:15 +000073void spi_wait_transmit_done(void)
wdenk4f7cb082003-09-11 23:06:34 +000074{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +090075 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +000076
C Naumand9abba82010-10-26 23:04:31 +090077 while (!(spi->ch[0].spsta & 0x01)) /* wait until transfer is done */
78 ;
wdenk4f7cb082003-09-11 23:06:34 +000079}
80
81
wdenkf5300ab2003-09-12 15:35:15 +000082void tsc2000_write(unsigned short reg, unsigned short data)
wdenk4f7cb082003-09-11 23:06:34 +000083{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +090084 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +000085 unsigned int command;
86
87 SET_CS_TOUCH();
88 command = reg;
C Naumand9abba82010-10-26 23:04:31 +090089 spi->ch[0].sptdat = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000090 spi_wait_transmit_done();
C Naumand9abba82010-10-26 23:04:31 +090091 spi->ch[0].sptdat = (command & 0x00FF);
wdenk4f7cb082003-09-11 23:06:34 +000092 spi_wait_transmit_done();
C Naumand9abba82010-10-26 23:04:31 +090093 spi->ch[0].sptdat = (data & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000094 spi_wait_transmit_done();
C Naumand9abba82010-10-26 23:04:31 +090095 spi->ch[0].sptdat = (data & 0x00FF);
wdenk4f7cb082003-09-11 23:06:34 +000096 spi_wait_transmit_done();
97
98 CLR_CS_TOUCH();
99}
100
101
wdenkf5300ab2003-09-12 15:35:15 +0000102unsigned short tsc2000_read (unsigned short reg)
wdenk4f7cb082003-09-11 23:06:34 +0000103{
104 unsigned short command, data;
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900105 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +0000106
107 SET_CS_TOUCH();
108 command = 0x8000 | reg;
109
C Naumand9abba82010-10-26 23:04:31 +0900110 spi->ch[0].sptdat = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +0000111 spi_wait_transmit_done();
C Naumand9abba82010-10-26 23:04:31 +0900112 spi->ch[0].sptdat = (command & 0x00FF);
wdenk4f7cb082003-09-11 23:06:34 +0000113 spi_wait_transmit_done();
114
C Naumand9abba82010-10-26 23:04:31 +0900115 spi->ch[0].sptdat = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +0000116 spi_wait_transmit_done();
C Naumand9abba82010-10-26 23:04:31 +0900117 data = spi->ch[0].sprdat;
118 spi->ch[0].sptdat = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +0000119 spi_wait_transmit_done();
120
121 CLR_CS_TOUCH();
C Naumand9abba82010-10-26 23:04:31 +0900122 return (spi->ch[0].sprdat & 0x0FF) | (data << 8);
wdenk4f7cb082003-09-11 23:06:34 +0000123}
124
125
wdenkf5300ab2003-09-12 15:35:15 +0000126void tsc2000_set_mux (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000127{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900128 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000129
130 CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
131 CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
132 switch (channel) {
133 case 0:
134 CLR_MUX0; CLR_MUX1;
135 SET_MUX1_ENABLE;
136 break;
137 case 1:
138 SET_MUX0; CLR_MUX1;
139 SET_MUX1_ENABLE;
140 break;
141 case 2:
142 CLR_MUX0; SET_MUX1;
143 SET_MUX1_ENABLE;
144 break;
145 case 3:
146 SET_MUX0; SET_MUX1;
147 SET_MUX1_ENABLE;
148 break;
149 case 4:
150 CLR_MUX0; CLR_MUX1;
151 SET_MUX2_ENABLE;
152 break;
153 case 5:
154 SET_MUX0; CLR_MUX1;
155 SET_MUX2_ENABLE;
156 break;
157 case 6:
158 CLR_MUX0; SET_MUX1;
159 SET_MUX2_ENABLE;
160 break;
161 case 7:
162 SET_MUX0; SET_MUX1;
163 SET_MUX2_ENABLE;
164 break;
165 case 8:
166 CLR_MUX0; CLR_MUX1;
167 SET_MUX3_ENABLE;
168 break;
169 case 9:
170 SET_MUX0; CLR_MUX1;
171 SET_MUX3_ENABLE;
172 break;
173 case 10:
174 CLR_MUX0; SET_MUX1;
175 SET_MUX3_ENABLE;
176 break;
177 case 11:
178 SET_MUX0; SET_MUX1;
179 SET_MUX3_ENABLE;
180 break;
181 case 12:
182 CLR_MUX0; CLR_MUX1;
183 SET_MUX4_ENABLE;
184 break;
185 case 13:
186 SET_MUX0; CLR_MUX1;
187 SET_MUX4_ENABLE;
188 break;
189 case 14:
190 CLR_MUX0; SET_MUX1;
191 SET_MUX4_ENABLE;
192 break;
193 case 15:
194 SET_MUX0; SET_MUX1;
195 SET_MUX4_ENABLE;
196 break;
197 default:
198 CLR_MUX0; CLR_MUX1;
199 }
200}
201
202
wdenkf5300ab2003-09-12 15:35:15 +0000203void tsc2000_set_range (unsigned int range)
wdenk4f7cb082003-09-11 23:06:34 +0000204{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900205 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000206
207 switch (range) {
208 case 1:
209 CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
210 CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
211 break;
212 case 2:
213 CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
214 CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
215 break;
216 case 3:
217 SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
218 SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
219 break;
220 }
221}
222
223
wdenkf5300ab2003-09-12 15:35:15 +0000224u16 tsc2000_read_channel (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000225{
226 u16 res;
227
228 tsc2000_set_mux(channel);
Wolfgang Denkcebd1fc2006-06-16 16:14:28 +0200229 udelay(20 * TSC2000_DELAY_BASE);
wdenk4f7cb082003-09-11 23:06:34 +0000230
231 tsc2000_write(TSC2000_REG_ADC, 0x2036);
wdenk42d1f032003-10-15 23:53:47 +0000232 adc_wait_conversion_done ();
233 res = tsc2000_read(TSC2000_REG_AUX1);
wdenk4f7cb082003-09-11 23:06:34 +0000234 return res;
235}
236
237
238s32 tsc2000_contact_temp (void)
239{
240 long adc_pt1000, offset;
wdenk42d1f032003-10-15 23:53:47 +0000241 long u_pt1000;
wdenk4f7cb082003-09-11 23:06:34 +0000242 long contact_temp;
wdenk151ab832005-02-24 22:44:16 +0000243 long temp1, temp2;
wdenk4f7cb082003-09-11 23:06:34 +0000244
wdenk42d1f032003-10-15 23:53:47 +0000245 tsc2000_reg_init ();
wdenk4f7cb082003-09-11 23:06:34 +0000246 tsc2000_set_range (3);
247
wdenk151ab832005-02-24 22:44:16 +0000248 /*
249 * Because of sporadic "jumps" in the measured adc values every
250 * channel is read two times. If there is a significant difference
251 * between the two measurements, then print an error and do a third
252 * measurement, because it is very unlikely that a successive third
253 * measurement goes also wrong.
254 */
255 temp1 = tsc2000_read_channel (14);
256 temp2 = tsc2000_read_channel (14);
257 if (abs(temp2 - temp1) < MAX_DEVIATION)
258 adc_pt1000 = temp2;
259 else {
260 printf ("%s: read adc value (channel 14) exceeded max allowed "
261 "deviation: %d * 0.0276 °C\n",
262 __FUNCTION__, MAX_DEVIATION);
263 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
264 temp1, temp2);
265 adc_pt1000 = tsc2000_read_channel (14);
266 printf ("use (third read) adc value: adc_pt1000 = "
267 "%ld DIGITs\n", adc_pt1000);
268 }
wdenk42d1f032003-10-15 23:53:47 +0000269 debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000270
wdenk151ab832005-02-24 22:44:16 +0000271 temp1 = tsc2000_read_channel (15);
272 temp2 = tsc2000_read_channel (15);
273 if (abs(temp2 - temp1) < MAX_DEVIATION)
274 offset = temp2;
275 else {
276 printf ("%s: read adc value (channel 15) exceeded max allowed "
277 "deviation: %d * 0.0276 °C\n",
278 __FUNCTION__, MAX_DEVIATION);
279 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
280 temp1, temp2);
281 offset = tsc2000_read_channel (15);
282 printf ("use (third read) adc value: offset = %ld DIGITs\n",
283 offset);
284 }
wdenk42d1f032003-10-15 23:53:47 +0000285 debug ("read channel 15 (offset): %ld\n", offset);
wdenk4f7cb082003-09-11 23:06:34 +0000286
wdenk42d1f032003-10-15 23:53:47 +0000287 /*
288 * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
289 * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
290 * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
291 * error correction Values err_vref and err_amp3 are assumed as 0 in
292 * u-boot, because this could cause only a very small error (< 1%).
293 */
294 u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
295 debug ("u_pt1000: %ld\n", u_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000296
wdenk42d1f032003-10-15 23:53:47 +0000297 if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
298 &contact_temp) == -1) {
299 printf ("%s: error interpolating PT1000 vlaue\n",
300 __FUNCTION__);
301 return (-1000);
302 }
303 debug ("contact_temp: %ld\n", contact_temp);
wdenk4f7cb082003-09-11 23:06:34 +0000304
305 return contact_temp;
306}
307
308
309void tsc2000_reg_init (void)
310{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900311 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000312
313 tsc2000_write(TSC2000_REG_ADC, 0x2036);
314 tsc2000_write(TSC2000_REG_REF, 0x0011);
315 tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
316
317 CON_MUX0;
318 CON_MUX1;
319
320 CON_MUX1_ENABLE;
321 CON_MUX2_ENABLE;
322 CON_MUX3_ENABLE;
323 CON_MUX4_ENABLE;
324
325 CON_SEL_TEMP_V_0;
326 CON_SEL_TEMP_V_1;
327 CON_SEL_TEMP_V_2;
328 CON_SEL_TEMP_V_3;
329
330 tsc2000_set_mux(0);
331 tsc2000_set_range(0);
332}
333
334
wdenkf5300ab2003-09-12 15:35:15 +0000335int tsc2000_interpolate(long value, long data[][2], long *result)
wdenk4f7cb082003-09-11 23:06:34 +0000336{
337 int i;
Sergei Poselenov4265c352008-08-14 14:08:28 +0200338 unsigned long long val;
wdenk4f7cb082003-09-11 23:06:34 +0000339
340 /* the data is sorted and the first element is upper
341 * limit so we can easily check for out-of-band values
342 */
343 if (data[0][0] < value || data[1][0] > value)
344 return -1;
345
346 i = 1;
347 while (data[i][0] < value)
348 i++;
349
350 /* To prevent overflow we have to store the intermediate
351 result in 'long long'.
352 */
353
Sergei Poselenov4265c352008-08-14 14:08:28 +0200354 val = ((unsigned long long)(data[i][1] - data[i-1][1])
355 * (unsigned long long)(value - data[i-1][0]));
356 do_div(val, (data[i][0] - data[i-1][0]));
357 *result = data[i-1][1] + val;
wdenk4f7cb082003-09-11 23:06:34 +0000358
359 return 0;
360}
361
362
wdenkf5300ab2003-09-12 15:35:15 +0000363void adc_wait_conversion_done(void)
wdenk4f7cb082003-09-11 23:06:34 +0000364{
wdenk42d1f032003-10-15 23:53:47 +0000365 while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
wdenk4f7cb082003-09-11 23:06:34 +0000366}