]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/trab/tsc2000.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / board / trab / tsc2000.c
1 /*
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 <asm/arch/s3c2400.h>
30 #include <asm/io.h>
31 #include <div64.h>
32 #include "tsc2000.h"
33
34 #include "Pt1000_temp_data.h"
35
36 /* 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
46 void tsc2000_spi_init(void)
47 {
48         struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
49         struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
50         int i;
51
52         /* Configure I/O ports. */
53         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;
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,
63                                     CPHA=1 */
64
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
73 void spi_wait_transmit_done(void)
74 {
75         struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
76
77         while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
78 }
79
80
81 void tsc2000_write(unsigned short reg, unsigned short data)
82 {
83         struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
84         unsigned int command;
85
86         SET_CS_TOUCH();
87         command = reg;
88         spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
89         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
101 unsigned short tsc2000_read (unsigned short reg)
102 {
103         unsigned short command, data;
104         struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
105
106         SET_CS_TOUCH();
107         command = 0x8000 | reg;
108
109         spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
110         spi_wait_transmit_done();
111         spi->ch[0].SPTDAT = (command & 0x00FF);
112         spi_wait_transmit_done();
113
114         spi->ch[0].SPTDAT = 0xFF;
115         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
125 void tsc2000_set_mux (unsigned int channel)
126 {
127         struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
128
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
202 void tsc2000_set_range (unsigned int range)
203 {
204         struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
205
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
223 u16 tsc2000_read_channel (unsigned int channel)
224 {
225         u16 res;
226
227         tsc2000_set_mux(channel);
228         udelay(20 * TSC2000_DELAY_BASE);
229
230         tsc2000_write(TSC2000_REG_ADC, 0x2036);
231         adc_wait_conversion_done ();
232         res = tsc2000_read(TSC2000_REG_AUX1);
233         return res;
234 }
235
236
237 s32 tsc2000_contact_temp (void)
238 {
239         long adc_pt1000, offset;
240         long u_pt1000;
241         long contact_temp;
242         long temp1, temp2;
243
244         tsc2000_reg_init ();
245         tsc2000_set_range (3);
246
247         /*
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         }
268         debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
269
270         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         }
284         debug ("read channel 15 (offset): %ld\n", offset);
285
286         /*
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);
295
296         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);
303
304         return contact_temp;
305 }
306
307
308 void tsc2000_reg_init (void)
309 {
310         struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
311
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
334 int tsc2000_interpolate(long value, long data[][2], long *result)
335 {
336         int i;
337         unsigned long long val;
338
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
353         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;
357
358         return 0;
359 }
360
361
362 void adc_wait_conversion_done(void)
363 {
364         while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
365 }