blob: 5890624f0f02c272fd049bd6258cd8e72fa6ef0d [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. */
wdenk42d1f032003-10-15 23:53:47 +000053 gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000;
wdenk4f7cb082003-09-11 23:06:34 +000054 gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000;
55 gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000;
56 gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000;
57
58 CLR_CS_TOUCH();
59
60 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++) {
67 spi->ch[0].SPTDAT = 0xFF;
68 }
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
77 while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
78}
79
80
wdenkf5300ab2003-09-12 15:35:15 +000081void tsc2000_write(unsigned short reg, unsigned short data)
wdenk4f7cb082003-09-11 23:06:34 +000082{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +090083 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +000084 unsigned int command;
85
86 SET_CS_TOUCH();
87 command = reg;
wdenk42d1f032003-10-15 23:53:47 +000088 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000089 spi_wait_transmit_done();
90 spi->ch[0].SPTDAT = (command & 0x00FF);
91 spi_wait_transmit_done();
92 spi->ch[0].SPTDAT = (data & 0xFF00) >> 8;
93 spi_wait_transmit_done();
94 spi->ch[0].SPTDAT = (data & 0x00FF);
95 spi_wait_transmit_done();
96
97 CLR_CS_TOUCH();
98}
99
100
wdenkf5300ab2003-09-12 15:35:15 +0000101unsigned short tsc2000_read (unsigned short reg)
wdenk4f7cb082003-09-11 23:06:34 +0000102{
103 unsigned short command, data;
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900104 struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
wdenk4f7cb082003-09-11 23:06:34 +0000105
106 SET_CS_TOUCH();
107 command = 0x8000 | reg;
108
wdenk42d1f032003-10-15 23:53:47 +0000109 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +0000110 spi_wait_transmit_done();
111 spi->ch[0].SPTDAT = (command & 0x00FF);
112 spi_wait_transmit_done();
113
wdenk42d1f032003-10-15 23:53:47 +0000114 spi->ch[0].SPTDAT = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +0000115 spi_wait_transmit_done();
116 data = spi->ch[0].SPRDAT;
117 spi->ch[0].SPTDAT = 0xFF;
118 spi_wait_transmit_done();
119
120 CLR_CS_TOUCH();
121 return (spi->ch[0].SPRDAT & 0x0FF) | (data << 8);
122}
123
124
wdenkf5300ab2003-09-12 15:35:15 +0000125void tsc2000_set_mux (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000126{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900127 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000128
129 CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
130 CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
131 switch (channel) {
132 case 0:
133 CLR_MUX0; CLR_MUX1;
134 SET_MUX1_ENABLE;
135 break;
136 case 1:
137 SET_MUX0; CLR_MUX1;
138 SET_MUX1_ENABLE;
139 break;
140 case 2:
141 CLR_MUX0; SET_MUX1;
142 SET_MUX1_ENABLE;
143 break;
144 case 3:
145 SET_MUX0; SET_MUX1;
146 SET_MUX1_ENABLE;
147 break;
148 case 4:
149 CLR_MUX0; CLR_MUX1;
150 SET_MUX2_ENABLE;
151 break;
152 case 5:
153 SET_MUX0; CLR_MUX1;
154 SET_MUX2_ENABLE;
155 break;
156 case 6:
157 CLR_MUX0; SET_MUX1;
158 SET_MUX2_ENABLE;
159 break;
160 case 7:
161 SET_MUX0; SET_MUX1;
162 SET_MUX2_ENABLE;
163 break;
164 case 8:
165 CLR_MUX0; CLR_MUX1;
166 SET_MUX3_ENABLE;
167 break;
168 case 9:
169 SET_MUX0; CLR_MUX1;
170 SET_MUX3_ENABLE;
171 break;
172 case 10:
173 CLR_MUX0; SET_MUX1;
174 SET_MUX3_ENABLE;
175 break;
176 case 11:
177 SET_MUX0; SET_MUX1;
178 SET_MUX3_ENABLE;
179 break;
180 case 12:
181 CLR_MUX0; CLR_MUX1;
182 SET_MUX4_ENABLE;
183 break;
184 case 13:
185 SET_MUX0; CLR_MUX1;
186 SET_MUX4_ENABLE;
187 break;
188 case 14:
189 CLR_MUX0; SET_MUX1;
190 SET_MUX4_ENABLE;
191 break;
192 case 15:
193 SET_MUX0; SET_MUX1;
194 SET_MUX4_ENABLE;
195 break;
196 default:
197 CLR_MUX0; CLR_MUX1;
198 }
199}
200
201
wdenkf5300ab2003-09-12 15:35:15 +0000202void tsc2000_set_range (unsigned int range)
wdenk4f7cb082003-09-11 23:06:34 +0000203{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900204 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000205
206 switch (range) {
207 case 1:
208 CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
209 CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
210 break;
211 case 2:
212 CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
213 CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
214 break;
215 case 3:
216 SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
217 SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
218 break;
219 }
220}
221
222
wdenkf5300ab2003-09-12 15:35:15 +0000223u16 tsc2000_read_channel (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000224{
225 u16 res;
226
227 tsc2000_set_mux(channel);
Wolfgang Denkcebd1fc2006-06-16 16:14:28 +0200228 udelay(20 * TSC2000_DELAY_BASE);
wdenk4f7cb082003-09-11 23:06:34 +0000229
230 tsc2000_write(TSC2000_REG_ADC, 0x2036);
wdenk42d1f032003-10-15 23:53:47 +0000231 adc_wait_conversion_done ();
232 res = tsc2000_read(TSC2000_REG_AUX1);
wdenk4f7cb082003-09-11 23:06:34 +0000233 return res;
234}
235
236
237s32 tsc2000_contact_temp (void)
238{
239 long adc_pt1000, offset;
wdenk42d1f032003-10-15 23:53:47 +0000240 long u_pt1000;
wdenk4f7cb082003-09-11 23:06:34 +0000241 long contact_temp;
wdenk151ab832005-02-24 22:44:16 +0000242 long temp1, temp2;
wdenk4f7cb082003-09-11 23:06:34 +0000243
wdenk42d1f032003-10-15 23:53:47 +0000244 tsc2000_reg_init ();
wdenk4f7cb082003-09-11 23:06:34 +0000245 tsc2000_set_range (3);
246
wdenk151ab832005-02-24 22:44:16 +0000247 /*
248 * Because of sporadic "jumps" in the measured adc values every
249 * channel is read two times. If there is a significant difference
250 * between the two measurements, then print an error and do a third
251 * measurement, because it is very unlikely that a successive third
252 * measurement goes also wrong.
253 */
254 temp1 = tsc2000_read_channel (14);
255 temp2 = tsc2000_read_channel (14);
256 if (abs(temp2 - temp1) < MAX_DEVIATION)
257 adc_pt1000 = temp2;
258 else {
259 printf ("%s: read adc value (channel 14) exceeded max allowed "
260 "deviation: %d * 0.0276 °C\n",
261 __FUNCTION__, MAX_DEVIATION);
262 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
263 temp1, temp2);
264 adc_pt1000 = tsc2000_read_channel (14);
265 printf ("use (third read) adc value: adc_pt1000 = "
266 "%ld DIGITs\n", adc_pt1000);
267 }
wdenk42d1f032003-10-15 23:53:47 +0000268 debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000269
wdenk151ab832005-02-24 22:44:16 +0000270 temp1 = tsc2000_read_channel (15);
271 temp2 = tsc2000_read_channel (15);
272 if (abs(temp2 - temp1) < MAX_DEVIATION)
273 offset = temp2;
274 else {
275 printf ("%s: read adc value (channel 15) exceeded max allowed "
276 "deviation: %d * 0.0276 °C\n",
277 __FUNCTION__, MAX_DEVIATION);
278 printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
279 temp1, temp2);
280 offset = tsc2000_read_channel (15);
281 printf ("use (third read) adc value: offset = %ld DIGITs\n",
282 offset);
283 }
wdenk42d1f032003-10-15 23:53:47 +0000284 debug ("read channel 15 (offset): %ld\n", offset);
wdenk4f7cb082003-09-11 23:06:34 +0000285
wdenk42d1f032003-10-15 23:53:47 +0000286 /*
287 * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
288 * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
289 * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
290 * error correction Values err_vref and err_amp3 are assumed as 0 in
291 * u-boot, because this could cause only a very small error (< 1%).
292 */
293 u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
294 debug ("u_pt1000: %ld\n", u_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000295
wdenk42d1f032003-10-15 23:53:47 +0000296 if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
297 &contact_temp) == -1) {
298 printf ("%s: error interpolating PT1000 vlaue\n",
299 __FUNCTION__);
300 return (-1000);
301 }
302 debug ("contact_temp: %ld\n", contact_temp);
wdenk4f7cb082003-09-11 23:06:34 +0000303
304 return contact_temp;
305}
306
307
308void tsc2000_reg_init (void)
309{
kevin.morfitt@fearnside-systems.co.ukeb0ae7f2009-10-10 13:33:11 +0900310 struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
wdenk4f7cb082003-09-11 23:06:34 +0000311
312 tsc2000_write(TSC2000_REG_ADC, 0x2036);
313 tsc2000_write(TSC2000_REG_REF, 0x0011);
314 tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
315
316 CON_MUX0;
317 CON_MUX1;
318
319 CON_MUX1_ENABLE;
320 CON_MUX2_ENABLE;
321 CON_MUX3_ENABLE;
322 CON_MUX4_ENABLE;
323
324 CON_SEL_TEMP_V_0;
325 CON_SEL_TEMP_V_1;
326 CON_SEL_TEMP_V_2;
327 CON_SEL_TEMP_V_3;
328
329 tsc2000_set_mux(0);
330 tsc2000_set_range(0);
331}
332
333
wdenkf5300ab2003-09-12 15:35:15 +0000334int tsc2000_interpolate(long value, long data[][2], long *result)
wdenk4f7cb082003-09-11 23:06:34 +0000335{
336 int i;
Sergei Poselenov4265c352008-08-14 14:08:28 +0200337 unsigned long long val;
wdenk4f7cb082003-09-11 23:06:34 +0000338
339 /* the data is sorted and the first element is upper
340 * limit so we can easily check for out-of-band values
341 */
342 if (data[0][0] < value || data[1][0] > value)
343 return -1;
344
345 i = 1;
346 while (data[i][0] < value)
347 i++;
348
349 /* To prevent overflow we have to store the intermediate
350 result in 'long long'.
351 */
352
Sergei Poselenov4265c352008-08-14 14:08:28 +0200353 val = ((unsigned long long)(data[i][1] - data[i-1][1])
354 * (unsigned long long)(value - data[i-1][0]));
355 do_div(val, (data[i][0] - data[i-1][0]));
356 *result = data[i-1][1] + val;
wdenk4f7cb082003-09-11 23:06:34 +0000357
358 return 0;
359}
360
361
wdenkf5300ab2003-09-12 15:35:15 +0000362void adc_wait_conversion_done(void)
wdenk4f7cb082003-09-11 23:06:34 +0000363{
wdenk42d1f032003-10-15 23:53:47 +0000364 while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
wdenk4f7cb082003-09-11 23:06:34 +0000365}