blob: df2d87f5c23e6ecf581461a7db2664f71cec6575 [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>
30#include "tsc2000.h"
31
wdenkf5300ab2003-09-12 15:35:15 +000032#include "Pt1000_temp_data.h"
33
wdenk4f7cb082003-09-11 23:06:34 +000034void spi_init(void)
35{
36 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
37 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
38 int i;
39
40 /* Configure I/O ports. */
wdenk42d1f032003-10-15 23:53:47 +000041 gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000;
wdenk4f7cb082003-09-11 23:06:34 +000042 gpio->PGCON = (gpio->PGCON & 0x0F3FFF) | 0x008000;
43 gpio->PGCON = (gpio->PGCON & 0x0CFFFF) | 0x020000;
44 gpio->PGCON = (gpio->PGCON & 0x03FFFF) | 0x080000;
45
46 CLR_CS_TOUCH();
47
48 spi->ch[0].SPPRE = 0x1F; /* Baud-rate ca. 514kHz */
49 spi->ch[0].SPPIN = 0x01; /* SPI-MOSI holds Level after last bit */
50 spi->ch[0].SPCON = 0x1A; /* Polling, Prescaler, Master, CPOL=0,
wdenk42d1f032003-10-15 23:53:47 +000051 CPHA=1 */
wdenk4f7cb082003-09-11 23:06:34 +000052
53 /* Dummy byte ensures clock to be low. */
54 for (i = 0; i < 10; i++) {
55 spi->ch[0].SPTDAT = 0xFF;
56 }
57 spi_wait_transmit_done();
58}
59
60
wdenkf5300ab2003-09-12 15:35:15 +000061void spi_wait_transmit_done(void)
wdenk4f7cb082003-09-11 23:06:34 +000062{
63 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
64
65 while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
66}
67
68
wdenkf5300ab2003-09-12 15:35:15 +000069void tsc2000_write(unsigned short reg, unsigned short data)
wdenk4f7cb082003-09-11 23:06:34 +000070{
71 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
72 unsigned int command;
73
74 SET_CS_TOUCH();
75 command = reg;
wdenk42d1f032003-10-15 23:53:47 +000076 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000077 spi_wait_transmit_done();
78 spi->ch[0].SPTDAT = (command & 0x00FF);
79 spi_wait_transmit_done();
80 spi->ch[0].SPTDAT = (data & 0xFF00) >> 8;
81 spi_wait_transmit_done();
82 spi->ch[0].SPTDAT = (data & 0x00FF);
83 spi_wait_transmit_done();
84
85 CLR_CS_TOUCH();
86}
87
88
wdenkf5300ab2003-09-12 15:35:15 +000089unsigned short tsc2000_read (unsigned short reg)
wdenk4f7cb082003-09-11 23:06:34 +000090{
91 unsigned short command, data;
92 S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
93
94 SET_CS_TOUCH();
95 command = 0x8000 | reg;
96
wdenk42d1f032003-10-15 23:53:47 +000097 spi->ch[0].SPTDAT = (command & 0xFF00) >> 8;
wdenk4f7cb082003-09-11 23:06:34 +000098 spi_wait_transmit_done();
99 spi->ch[0].SPTDAT = (command & 0x00FF);
100 spi_wait_transmit_done();
101
wdenk42d1f032003-10-15 23:53:47 +0000102 spi->ch[0].SPTDAT = 0xFF;
wdenk4f7cb082003-09-11 23:06:34 +0000103 spi_wait_transmit_done();
104 data = spi->ch[0].SPRDAT;
105 spi->ch[0].SPTDAT = 0xFF;
106 spi_wait_transmit_done();
107
108 CLR_CS_TOUCH();
109 return (spi->ch[0].SPRDAT & 0x0FF) | (data << 8);
110}
111
112
wdenkf5300ab2003-09-12 15:35:15 +0000113void tsc2000_set_mux (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000114{
wdenk42d1f032003-10-15 23:53:47 +0000115 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000116
117 CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
118 CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
119 switch (channel) {
120 case 0:
121 CLR_MUX0; CLR_MUX1;
122 SET_MUX1_ENABLE;
123 break;
124 case 1:
125 SET_MUX0; CLR_MUX1;
126 SET_MUX1_ENABLE;
127 break;
128 case 2:
129 CLR_MUX0; SET_MUX1;
130 SET_MUX1_ENABLE;
131 break;
132 case 3:
133 SET_MUX0; SET_MUX1;
134 SET_MUX1_ENABLE;
135 break;
136 case 4:
137 CLR_MUX0; CLR_MUX1;
138 SET_MUX2_ENABLE;
139 break;
140 case 5:
141 SET_MUX0; CLR_MUX1;
142 SET_MUX2_ENABLE;
143 break;
144 case 6:
145 CLR_MUX0; SET_MUX1;
146 SET_MUX2_ENABLE;
147 break;
148 case 7:
149 SET_MUX0; SET_MUX1;
150 SET_MUX2_ENABLE;
151 break;
152 case 8:
153 CLR_MUX0; CLR_MUX1;
154 SET_MUX3_ENABLE;
155 break;
156 case 9:
157 SET_MUX0; CLR_MUX1;
158 SET_MUX3_ENABLE;
159 break;
160 case 10:
161 CLR_MUX0; SET_MUX1;
162 SET_MUX3_ENABLE;
163 break;
164 case 11:
165 SET_MUX0; SET_MUX1;
166 SET_MUX3_ENABLE;
167 break;
168 case 12:
169 CLR_MUX0; CLR_MUX1;
170 SET_MUX4_ENABLE;
171 break;
172 case 13:
173 SET_MUX0; CLR_MUX1;
174 SET_MUX4_ENABLE;
175 break;
176 case 14:
177 CLR_MUX0; SET_MUX1;
178 SET_MUX4_ENABLE;
179 break;
180 case 15:
181 SET_MUX0; SET_MUX1;
182 SET_MUX4_ENABLE;
183 break;
184 default:
185 CLR_MUX0; CLR_MUX1;
186 }
187}
188
189
wdenkf5300ab2003-09-12 15:35:15 +0000190void tsc2000_set_range (unsigned int range)
wdenk4f7cb082003-09-11 23:06:34 +0000191{
wdenk42d1f032003-10-15 23:53:47 +0000192 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000193
194 switch (range) {
195 case 1:
196 CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
197 CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
198 break;
199 case 2:
200 CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
201 CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
202 break;
203 case 3:
204 SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
205 SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
206 break;
207 }
208}
209
210
wdenkf5300ab2003-09-12 15:35:15 +0000211u16 tsc2000_read_channel (unsigned int channel)
wdenk4f7cb082003-09-11 23:06:34 +0000212{
213 u16 res;
214
215 tsc2000_set_mux(channel);
216 udelay(3 * TSC2000_DELAY_BASE);
217
218 tsc2000_write(TSC2000_REG_ADC, 0x2036);
wdenk42d1f032003-10-15 23:53:47 +0000219 adc_wait_conversion_done ();
220 res = tsc2000_read(TSC2000_REG_AUX1);
wdenk4f7cb082003-09-11 23:06:34 +0000221 return res;
222}
223
224
225s32 tsc2000_contact_temp (void)
226{
227 long adc_pt1000, offset;
wdenk42d1f032003-10-15 23:53:47 +0000228 long u_pt1000;
wdenk4f7cb082003-09-11 23:06:34 +0000229 long contact_temp;
230
231
wdenk42d1f032003-10-15 23:53:47 +0000232 tsc2000_reg_init ();
wdenk4f7cb082003-09-11 23:06:34 +0000233 tsc2000_set_range (3);
234
wdenk42d1f032003-10-15 23:53:47 +0000235 adc_pt1000 = tsc2000_read_channel (14);
236 debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000237
wdenk42d1f032003-10-15 23:53:47 +0000238 offset = tsc2000_read_channel (15);
239 debug ("read channel 15 (offset): %ld\n", offset);
wdenk4f7cb082003-09-11 23:06:34 +0000240
wdenk42d1f032003-10-15 23:53:47 +0000241 /*
242 * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
243 * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
244 * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
245 * error correction Values err_vref and err_amp3 are assumed as 0 in
246 * u-boot, because this could cause only a very small error (< 1%).
247 */
248 u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
249 debug ("u_pt1000: %ld\n", u_pt1000);
wdenk4f7cb082003-09-11 23:06:34 +0000250
wdenk42d1f032003-10-15 23:53:47 +0000251 if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
252 &contact_temp) == -1) {
253 printf ("%s: error interpolating PT1000 vlaue\n",
254 __FUNCTION__);
255 return (-1000);
256 }
257 debug ("contact_temp: %ld\n", contact_temp);
wdenk4f7cb082003-09-11 23:06:34 +0000258
259 return contact_temp;
260}
261
262
263void tsc2000_reg_init (void)
264{
wdenk42d1f032003-10-15 23:53:47 +0000265 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
wdenk4f7cb082003-09-11 23:06:34 +0000266
267 tsc2000_write(TSC2000_REG_ADC, 0x2036);
268 tsc2000_write(TSC2000_REG_REF, 0x0011);
269 tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
270
271 CON_MUX0;
272 CON_MUX1;
273
274 CON_MUX1_ENABLE;
275 CON_MUX2_ENABLE;
276 CON_MUX3_ENABLE;
277 CON_MUX4_ENABLE;
278
279 CON_SEL_TEMP_V_0;
280 CON_SEL_TEMP_V_1;
281 CON_SEL_TEMP_V_2;
282 CON_SEL_TEMP_V_3;
283
284 tsc2000_set_mux(0);
285 tsc2000_set_range(0);
286}
287
288
wdenkf5300ab2003-09-12 15:35:15 +0000289int tsc2000_interpolate(long value, long data[][2], long *result)
wdenk4f7cb082003-09-11 23:06:34 +0000290{
291 int i;
292
293 /* the data is sorted and the first element is upper
294 * limit so we can easily check for out-of-band values
295 */
296 if (data[0][0] < value || data[1][0] > value)
297 return -1;
298
299 i = 1;
300 while (data[i][0] < value)
301 i++;
302
303 /* To prevent overflow we have to store the intermediate
304 result in 'long long'.
305 */
306
307 *result = data[i-1][1] +
308 ((unsigned long long)(data[i][1] - data[i-1][1])
309 * (unsigned long long)(value - data[i-1][0]))
310 / (data[i][0] - data[i-1][0]);
311
312 return 0;
313}
314
315
wdenkf5300ab2003-09-12 15:35:15 +0000316void adc_wait_conversion_done(void)
wdenk4f7cb082003-09-11 23:06:34 +0000317{
wdenk42d1f032003-10-15 23:53:47 +0000318 while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
wdenk4f7cb082003-09-11 23:06:34 +0000319}