]>
Commit | Line | Data |
---|---|---|
4f7cb08e WD |
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 "tsc2000.h" | |
31 | ||
f5300ab2 WD |
32 | #include "Pt1000_temp_data.h" |
33 | ||
4f7cb08e WD |
34 | void 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. */ | |
42d1f039 | 41 | gpio->PDCON = (gpio->PDCON & 0xF3FFFF) | 0x040000; |
4f7cb08e WD |
42 | 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, | |
42d1f039 | 51 | CPHA=1 */ |
4f7cb08e WD |
52 | |
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 | ||
f5300ab2 | 61 | void spi_wait_transmit_done(void) |
4f7cb08e WD |
62 | { |
63 | S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); | |
64 | ||
65 | while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */ | |
66 | } | |
67 | ||
68 | ||
f5300ab2 | 69 | void tsc2000_write(unsigned short reg, unsigned short data) |
4f7cb08e WD |
70 | { |
71 | S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); | |
72 | unsigned int command; | |
73 | ||
74 | SET_CS_TOUCH(); | |
75 | command = reg; | |
42d1f039 | 76 | spi->ch[0].SPTDAT = (command & 0xFF00) >> 8; |
4f7cb08e WD |
77 | 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 | ||
f5300ab2 | 89 | unsigned short tsc2000_read (unsigned short reg) |
4f7cb08e WD |
90 | { |
91 | unsigned short command, data; | |
92 | S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI(); | |
93 | ||
94 | SET_CS_TOUCH(); | |
95 | command = 0x8000 | reg; | |
96 | ||
42d1f039 | 97 | spi->ch[0].SPTDAT = (command & 0xFF00) >> 8; |
4f7cb08e WD |
98 | spi_wait_transmit_done(); |
99 | spi->ch[0].SPTDAT = (command & 0x00FF); | |
100 | spi_wait_transmit_done(); | |
101 | ||
42d1f039 | 102 | spi->ch[0].SPTDAT = 0xFF; |
4f7cb08e WD |
103 | 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 | ||
f5300ab2 | 113 | void tsc2000_set_mux (unsigned int channel) |
4f7cb08e | 114 | { |
42d1f039 | 115 | S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); |
4f7cb08e WD |
116 | |
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 | ||
f5300ab2 | 190 | void tsc2000_set_range (unsigned int range) |
4f7cb08e | 191 | { |
42d1f039 | 192 | S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); |
4f7cb08e WD |
193 | |
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 | ||
f5300ab2 | 211 | u16 tsc2000_read_channel (unsigned int channel) |
4f7cb08e WD |
212 | { |
213 | u16 res; | |
214 | ||
215 | tsc2000_set_mux(channel); | |
216 | udelay(3 * TSC2000_DELAY_BASE); | |
217 | ||
218 | tsc2000_write(TSC2000_REG_ADC, 0x2036); | |
42d1f039 WD |
219 | adc_wait_conversion_done (); |
220 | res = tsc2000_read(TSC2000_REG_AUX1); | |
4f7cb08e WD |
221 | return res; |
222 | } | |
223 | ||
224 | ||
225 | s32 tsc2000_contact_temp (void) | |
226 | { | |
227 | long adc_pt1000, offset; | |
42d1f039 | 228 | long u_pt1000; |
4f7cb08e WD |
229 | long contact_temp; |
230 | ||
231 | ||
42d1f039 | 232 | tsc2000_reg_init (); |
4f7cb08e WD |
233 | tsc2000_set_range (3); |
234 | ||
42d1f039 WD |
235 | adc_pt1000 = tsc2000_read_channel (14); |
236 | debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000); | |
237 | ||
238 | offset = tsc2000_read_channel (15); | |
239 | debug ("read channel 15 (offset): %ld\n", offset); | |
240 | ||
241 | /* | |
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); | |
250 | ||
251 | 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); | |
4f7cb08e WD |
258 | |
259 | return contact_temp; | |
260 | } | |
261 | ||
262 | ||
263 | void tsc2000_reg_init (void) | |
264 | { | |
42d1f039 | 265 | S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); |
4f7cb08e WD |
266 | |
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 | ||
f5300ab2 | 289 | int tsc2000_interpolate(long value, long data[][2], long *result) |
4f7cb08e WD |
290 | { |
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 | ||
f5300ab2 | 316 | void adc_wait_conversion_done(void) |
4f7cb08e | 317 | { |
42d1f039 | 318 | while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14))); |
4f7cb08e | 319 | } |