ppc4xx: Add missing APC405 to MAKEALL
[oweals/u-boot.git] / board / trab / tsc2000.c
index df2d87f5c23e6ecf581461a7db2664f71cec6575..5890624f0f02c272fd049bd6258cd8e72fa6ef0d 100644 (file)
  */
 
 #include <common.h>
-#include <s3c2400.h>
+#include <asm/arch/s3c24x0_cpu.h>
+#include <asm/io.h>
+#include <div64.h>
 #include "tsc2000.h"
 
 #include "Pt1000_temp_data.h"
 
-void spi_init(void)
+/* helper function */
+#define abs(value) (((value) < 0) ? ((value)*-1) : (value))
+
+/*
+ * Maximal allowed deviation between two immediate meassurments of an analog
+ * thermo channel. 1 DIGIT = 0.0276 °C. This is used to filter sporadic
+ * "jumps" in measurment.
+ */
+#define MAX_DEVIATION  18      /* unit: DIGITs of adc; 18 DIGIT = 0.5 °C */
+
+void tsc2000_spi_init(void)
 {
-       S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
-       S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
+       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
+       struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
        int i;
 
        /* Configure I/O ports. */
@@ -60,7 +72,7 @@ void spi_init(void)
 
 void spi_wait_transmit_done(void)
 {
-       S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
+       struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
 
        while (!(spi->ch[0].SPSTA & 0x01)); /* wait until transfer is done */
 }
@@ -68,7 +80,7 @@ void spi_wait_transmit_done(void)
 
 void tsc2000_write(unsigned short reg, unsigned short data)
 {
-       S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
+       struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
        unsigned int command;
 
        SET_CS_TOUCH();
@@ -89,7 +101,7 @@ void tsc2000_write(unsigned short reg, unsigned short data)
 unsigned short tsc2000_read (unsigned short reg)
 {
        unsigned short command, data;
-       S3C24X0_SPI * const spi = S3C24X0_GetBase_SPI();
+       struct s3c24x0_spi * const spi = s3c24x0_get_base_spi();
 
        SET_CS_TOUCH();
        command = 0x8000 | reg;
@@ -112,7 +124,7 @@ unsigned short tsc2000_read (unsigned short reg)
 
 void tsc2000_set_mux (unsigned int channel)
 {
-       S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 
        CLR_MUX1_ENABLE; CLR_MUX2_ENABLE;
        CLR_MUX3_ENABLE; CLR_MUX4_ENABLE;
@@ -189,7 +201,7 @@ void tsc2000_set_mux (unsigned int channel)
 
 void tsc2000_set_range (unsigned int range)
 {
-       S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 
        switch (range) {
        case 1:
@@ -213,7 +225,7 @@ u16 tsc2000_read_channel (unsigned int channel)
        u16 res;
 
        tsc2000_set_mux(channel);
-       udelay(3 * TSC2000_DELAY_BASE);
+       udelay(20 * TSC2000_DELAY_BASE);
 
        tsc2000_write(TSC2000_REG_ADC, 0x2036);
        adc_wait_conversion_done ();
@@ -227,15 +239,48 @@ s32 tsc2000_contact_temp (void)
        long adc_pt1000, offset;
        long u_pt1000;
        long contact_temp;
-
+       long temp1, temp2;
 
        tsc2000_reg_init ();
        tsc2000_set_range (3);
 
-       adc_pt1000 = tsc2000_read_channel (14);
+       /*
+        * Because of sporadic "jumps" in the measured adc values every
+        * channel is read two times. If there is a significant difference
+        * between the two measurements, then print an error and do a third
+        * measurement, because it is very unlikely that a successive third
+        * measurement goes also wrong.
+        */
+       temp1 = tsc2000_read_channel (14);
+       temp2 = tsc2000_read_channel (14);
+       if (abs(temp2 - temp1) < MAX_DEVIATION)
+               adc_pt1000 = temp2;
+       else {
+               printf ("%s: read adc value (channel 14) exceeded max allowed "
+                       "deviation: %d * 0.0276 °C\n",
+                       __FUNCTION__, MAX_DEVIATION);
+               printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
+                       temp1, temp2);
+               adc_pt1000 = tsc2000_read_channel (14);
+               printf ("use (third read) adc value: adc_pt1000 = "
+                       "%ld DIGITs\n", adc_pt1000);
+       }
        debug ("read channel 14 (pt1000 adc value): %ld\n", adc_pt1000);
 
-       offset = tsc2000_read_channel (15);
+       temp1 = tsc2000_read_channel (15);
+       temp2 = tsc2000_read_channel (15);
+       if (abs(temp2 - temp1) < MAX_DEVIATION)
+               offset = temp2;
+       else {
+               printf ("%s: read adc value (channel 15) exceeded max allowed "
+                       "deviation: %d * 0.0276 °C\n",
+                       __FUNCTION__, MAX_DEVIATION);
+               printf ("adc value 1: %ld DIGITs\nadc value 2: %ld DIGITs\n",
+                       temp1, temp2);
+               offset = tsc2000_read_channel (15);
+               printf ("use (third read) adc value: offset = %ld DIGITs\n",
+                       offset);
+       }
        debug ("read channel 15 (offset): %ld\n", offset);
 
        /*
@@ -262,7 +307,7 @@ s32 tsc2000_contact_temp (void)
 
 void tsc2000_reg_init (void)
 {
-       S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+       struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();
 
        tsc2000_write(TSC2000_REG_ADC, 0x2036);
        tsc2000_write(TSC2000_REG_REF, 0x0011);
@@ -289,6 +334,7 @@ void tsc2000_reg_init (void)
 int tsc2000_interpolate(long value, long data[][2], long *result)
 {
        int i;
+       unsigned long long val;
 
        /* the data is sorted and the first element is upper
         * limit so we can easily check for out-of-band values
@@ -304,10 +350,10 @@ int tsc2000_interpolate(long value, long data[][2], long *result)
           result in 'long long'.
        */
 
-       *result = data[i-1][1] +
-               ((unsigned long long)(data[i][1] - data[i-1][1])
-                * (unsigned long long)(value - data[i-1][0]))
-               / (data[i][0] - data[i-1][0]);
+       val = ((unsigned long long)(data[i][1] - data[i-1][1])
+                  * (unsigned long long)(value - data[i-1][0]));
+       do_div(val, (data[i][0] - data[i-1][0]));
+       *result = data[i-1][1] + val;
 
        return 0;
 }