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
  81void 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
 101unsigned 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
 125void 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
 202void 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
 223u16 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
 237s32 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
 308void 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
 334int 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
 362void adc_wait_conversion_done(void)
 363{
 364        while (!(tsc2000_read(TSC2000_REG_ADC) & (1 << 14)));
 365}
 366