]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/trab/tsc2000.c
imported Freescale specific U-Boot additions for i.MX28,... release L2.6.31_10.08.01
[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 <s3c2400.h>
30 #include <div64.h>
31 #include "tsc2000.h"
32
33 #include "Pt1000_temp_data.h"
34
35 /* 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
45 void tsc2000_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. */
52         gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000;
53         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,
62                                     CPHA=1 */
63
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
72 void spi_wait_transmit_done(void)
73 {
74         S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
75
76         while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
77 }
78
79
80 void tsc2000_write(unsigned short reg, unsigned short data)
81 {
82         S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
83         unsigned int command;
84
85         SET_CS_TOUCH();
86         command = reg;
87         spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
88         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
100 unsigned short tsc2000_read (unsigned short reg)
101 {
102         unsigned short command, data;
103         S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
104
105         SET_CS_TOUCH();
106         command = 0x8000 | reg;
107
108         spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
109         spi_wait_transmit_done();
110         spi->ch[0].SPTDAT = (command & 0x00FF);
111         spi_wait_transmit_done();
112
113         spi->ch[0].SPTDAT = 0xFF;
114         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
124 void tsc2000_set_mux (unsigned int channel)
125 {
126         S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
127
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
201 void tsc2000_set_range (unsigned int range)
202 {
203         S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
204
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
222 u16 tsc2000_read_channel (unsigned int channel)
223 {
224         u16 res;
225
226         tsc2000_set_mux(channel);
227         udelay(20 * TSC2000_DELAY_BASE);
228
229         tsc2000_write(TSC2000_REG_ADC, 0x2036);
230         adc_wait_conversion_done ();
231         res = tsc2000_read(TSC2000_REG_AUX1);
232         return res;
233 }
234
235
236 s32 tsc2000_contact_temp (void)
237 {
238         long adc_pt1000, offset;
239         long u_pt1000;
240         long contact_temp;
241         long temp1, temp2;
242
243         tsc2000_reg_init ();
244         tsc2000_set_range (3);
245
246         /*
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         }
267         debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
268
269         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         }
283         debug ("read channel 15 (offset): %ld\n", offset);
284
285         /*
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);
294
295         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);
302
303         return contact_temp;
304 }
305
306
307 void tsc2000_reg_init (void)
308 {
309         S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
310
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
333 int tsc2000_interpolate(long value, long data[][2], long *result)
334 {
335         int i;
336         unsigned long long val;
337
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
352         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;
356
357         return 0;
358 }
359
360
361 void adc_wait_conversion_done(void)
362 {
363         while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
364 }