uboot/board/trab/tsc2000.c
<<
>>
Prefs
   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/s3c24x0_cpu.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
  46void 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
  73void 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
  82void tsc2000_write(unsigned short reg, unsigned short data)
  83{
  84        struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
  85        unsigned int command;
  86
  87        SET_CS_TOUCH();
  88        command = reg;
  89        spi->ch[0].sptdat = (command & 0xFF00) >> 8;
  90        spi_wait_transmit_done();
  91        spi->ch[0].sptdat = (command & 0x00FF);
  92        spi_wait_transmit_done();
  93        spi->ch[0].sptdat = (data & 0xFF00) >> 8;
  94        spi_wait_transmit_done();
  95        spi->ch[0].sptdat = (data & 0x00FF);
  96        spi_wait_transmit_done();
  97
  98        CLR_CS_TOUCH();
  99}
 100
 101
 102unsigned short tsc2000_read (unsigned short reg)
 103{
 104        unsigned short command, data;
 105        struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
 106
 107        SET_CS_TOUCH();
 108        command = 0x8000 | reg;
 109
 110        spi->ch[0].sptdat = (command & 0xFF00) >> 8;
 111        spi_wait_transmit_done();
 112        spi->ch[0].sptdat = (command & 0x00FF);
 113        spi_wait_transmit_done();
 114
 115        spi->ch[0].sptdat = 0xFF;
 116        spi_wait_transmit_done();
 117        data = spi->ch[0].sprdat;
 118        spi->ch[0].sptdat = 0xFF;
 119        spi_wait_transmit_done();
 120
 121        CLR_CS_TOUCH();
 122        return (spi->ch[0].sprdat & 0x0FF) | (data << 8);
 123}
 124
 125
 126void tsc2000_set_mux (unsigned int channel)
 127{
 128        struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 129
 130        CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
 131        CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
 132        switch (channel) {
 133        case 0:
 134                CLR_MUX0; CLR_MUX1;
 135                SET_MUX1_ENABLE;
 136                break;
 137        case 1:
 138                SET_MUX0; CLR_MUX1;
 139                SET_MUX1_ENABLE;
 140                break;
 141        case 2:
 142                CLR_MUX0; SET_MUX1;
 143                SET_MUX1_ENABLE;
 144                break;
 145        case 3:
 146                SET_MUX0; SET_MUX1;
 147                SET_MUX1_ENABLE;
 148                break;
 149        case 4:
 150                CLR_MUX0; CLR_MUX1;
 151                SET_MUX2_ENABLE;
 152                break;
 153        case 5:
 154                SET_MUX0; CLR_MUX1;
 155                SET_MUX2_ENABLE;
 156                break;
 157        case 6:
 158                CLR_MUX0; SET_MUX1;
 159                SET_MUX2_ENABLE;
 160                break;
 161        case 7:
 162                SET_MUX0; SET_MUX1;
 163                SET_MUX2_ENABLE;
 164                break;
 165        case 8:
 166                CLR_MUX0; CLR_MUX1;
 167                SET_MUX3_ENABLE;
 168                break;
 169        case 9:
 170                SET_MUX0; CLR_MUX1;
 171                SET_MUX3_ENABLE;
 172                break;
 173        case 10:
 174                CLR_MUX0; SET_MUX1;
 175                SET_MUX3_ENABLE;
 176                break;
 177        case 11:
 178                SET_MUX0; SET_MUX1;
 179                SET_MUX3_ENABLE;
 180                break;
 181        case 12:
 182                CLR_MUX0; CLR_MUX1;
 183                SET_MUX4_ENABLE;
 184                break;
 185        case 13:
 186                SET_MUX0; CLR_MUX1;
 187                SET_MUX4_ENABLE;
 188                break;
 189        case 14:
 190                CLR_MUX0; SET_MUX1;
 191                SET_MUX4_ENABLE;
 192                break;
 193        case 15:
 194                SET_MUX0; SET_MUX1;
 195                SET_MUX4_ENABLE;
 196                break;
 197        default:
 198                CLR_MUX0; CLR_MUX1;
 199        }
 200}
 201
 202
 203void tsc2000_set_range (unsigned int range)
 204{
 205        struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 206
 207        switch (range) {
 208        case 1:
 209                CLR_SEL_TEMP_V_0; SET_SEL_TEMP_V_1;
 210                CLR_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
 211                break;
 212        case 2:
 213                CLR_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
 214                CLR_SEL_TEMP_V_2; SET_SEL_TEMP_V_3;
 215                break;
 216        case 3:
 217                SET_SEL_TEMP_V_0; CLR_SEL_TEMP_V_1;
 218                SET_SEL_TEMP_V_2; CLR_SEL_TEMP_V_3;
 219                break;
 220        }
 221}
 222
 223
 224u16 tsc2000_read_channel (unsigned int channel)
 225{
 226        u16 res;
 227
 228        tsc2000_set_mux(channel);
 229        udelay(20 * TSC2000_DELAY_BASE);
 230
 231        tsc2000_write(TSC2000_REG_ADC, 0x2036);
 232        adc_wait_conversion_done ();
 233        res = tsc2000_read(TSC2000_REG_AUX1);
 234        return res;
 235}
 236
 237
 238s32 tsc2000_contact_temp (void)
 239{
 240        long adc_pt1000, offset;
 241        long u_pt1000;
 242        long contact_temp;
 243        long temp1, temp2;
 244
 245        tsc2000_reg_init ();
 246        tsc2000_set_range (3);
 247
 248        /*
 249         * Because of sporadic "jumps" in the measured adc values every
 250         * channel is read two times. If there is a significant difference
 251         * between the two measurements, then print an error and do a third
 252         * measurement, because it is very unlikely that a successive third
 253         * measurement goes also wrong.
 254         */
 255        temp1 = tsc2000_read_channel (14);
 256        temp2 = tsc2000_read_channel (14);
 257        if (abs(temp2 - temp1) < MAX_DEVIATION)
 258                adc_pt1000 = temp2;
 259        else {
 260                printf ("%s: read adc value (channel 14) exceeded max allowed "
 261                        "deviation: %d * 0.0276 °C\n",
 262                        __FUNCTION__, MAX_DEVIATION);
 263                printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
 264                        temp1, temp2);
 265                adc_pt1000 = tsc2000_read_channel (14);
 266                printf ("use (third read) adc value: adc_pt1000 = "
 267                        "%ld DIGITs\n", adc_pt1000);
 268        }
 269        debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
 270
 271        temp1 = tsc2000_read_channel (15);
 272        temp2 = tsc2000_read_channel (15);
 273        if (abs(temp2 - temp1) < MAX_DEVIATION)
 274                offset = temp2;
 275        else {
 276                printf ("%s: read adc value (channel 15) exceeded max allowed "
 277                        "deviation: %d * 0.0276 °C\n",
 278                        __FUNCTION__, MAX_DEVIATION);
 279                printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
 280                        temp1, temp2);
 281                offset = tsc2000_read_channel (15);
 282                printf ("use (third read) adc value: offset = %ld DIGITs\n",
 283                        offset);
 284        }
 285        debug ("read channel 15 (offset): %ld\n", offset);
 286
 287        /*
 288         * Formula for calculating voltage drop on PT1000 resistor: u_pt1000 =
 289         * x_range3 * (adc_raw - offset) / 10. Formula to calculate x_range3:
 290         * x_range3 = (2500 * (1000000 + err_vref + err_amp3)) / (4095*6). The
 291         * error correction Values err_vref and err_amp3 are assumed as 0 in
 292         * u-boot, because this could cause only a very small error (< 1%).
 293         */
 294        u_pt1000 = (101750 * (adc_pt1000 - offset)) / 10;
 295        debug ("u_pt1000: %ld\n", u_pt1000);
 296
 297        if (tsc2000_interpolate(u_pt1000, Pt1000_temp_table,
 298                                &contact_temp) == -1) {
 299                printf ("%s: error interpolating PT1000 vlaue\n",
 300                         __FUNCTION__);
 301                return (-1000);
 302        }
 303        debug ("contact_temp: %ld\n", contact_temp);
 304
 305        return contact_temp;
 306}
 307
 308
 309void tsc2000_reg_init (void)
 310{
 311        struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 312
 313        tsc2000_write(TSC2000_REG_ADC, 0x2036);
 314        tsc2000_write(TSC2000_REG_REF, 0x0011);
 315        tsc2000_write(TSC2000_REG_DACCTL, 0x0000);
 316
 317        CON_MUX0;
 318        CON_MUX1;
 319
 320        CON_MUX1_ENABLE;
 321        CON_MUX2_ENABLE;
 322        CON_MUX3_ENABLE;
 323        CON_MUX4_ENABLE;
 324
 325        CON_SEL_TEMP_V_0;
 326        CON_SEL_TEMP_V_1;
 327        CON_SEL_TEMP_V_2;
 328        CON_SEL_TEMP_V_3;
 329
 330        tsc2000_set_mux(0);
 331        tsc2000_set_range(0);
 332}
 333
 334
 335int tsc2000_interpolate(long value, long data[][2], long *result)
 336{
 337        int i;
 338        unsigned long long val;
 339
 340        /* the data is sorted and the first element is upper
 341         * limit so we can easily check for out-of-band values
 342         */
 343        if (data[0][0] < value || data[1][0] > value)
 344                return -1;
 345
 346        i = 1;
 347        while (data[i][0] < value)
 348                i++;
 349
 350        /* To prevent overflow we have to store the intermediate
 351           result in 'long long'.
 352        */
 353
 354        val = ((unsigned long long)(data[i][1] - data[i-1][1])
 355                   * (unsigned long long)(value - data[i-1][0]));
 356        do_div(val, (data[i][0] - data[i-1][0]));
 357        *result = data[i-1][1] + val;
 358
 359        return 0;
 360}
 361
 362
 363void adc_wait_conversion_done(void)
 364{
 365        while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
 366}
 367