summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/adc-imx233.c
blob: a0bda9ab029648a9c2c5037027fb5c0456efa244 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2011 by Amaury Pouly
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "adc-target.h"
#include "power-imx233.h"

/* Virtual channels */
#define IMX233_ADC_BATTERY      -1 /* Battery voltage (mV) */
#define IMX233_ADC_DIE_TEMP     -2 /* Die temperature (°C) */
#define IMX233_ADC_VDDIO        -3 /* VddIO voltage (mV) */
#if IMX233_SUBTARGET >= 3700
#define IMX233_ADC_VDD5V        -4 /* Vdd5V voltage (mV) */
#endif
#ifdef IMX233_BATT_TEMP_SENSOR
#define IMX233_ADC_BATT_TEMP    -5 /* Battery temperature (°C) */
#endif

static const char *imx233_adc_channel_name[NUM_ADC_CHANNELS] =
{
    [ADC_BATTERY] = "Battery(raw)",
    [ADC_DIE_TEMP] = "Die temperature(°C)",
    [ADC_VDDIO] = "VddIO(mV)",
#if IMX233_SUBTARGET >= 3700
    [ADC_VDD5V] = "Vdd5V(mV)",
#endif
#ifdef IMX233_BATT_TEMP_SENSOR
    [ADC_BATT_TEMP] = "Battery temperature(raw)",
#endif
};

static int imx233_adc_mapping[NUM_ADC_CHANNELS] =
{
    [ADC_BATTERY] = IMX233_ADC_BATTERY,
    [ADC_DIE_TEMP] = IMX233_ADC_DIE_TEMP,
    [ADC_VDDIO] = IMX233_ADC_VDDIO,
#if IMX233_SUBTARGET >= 3700
    [ADC_VDD5V] = IMX233_ADC_VDD5V,
#endif
#ifdef IMX233_BATT_TEMP_SENSOR
    [ADC_BATT_TEMP] = IMX233_ADC_BATT_TEMP,
#endif
};

void adc_init(void)
{
}

static short adc_read_physical_ex(int virt)
{
    imx233_lradc_clear_channel(virt);
    imx233_lradc_kick_channel(virt);
    imx233_lradc_wait_channel(virt);
    return imx233_lradc_read_channel(virt);
}

static short adc_read_physical(int src, bool div2)
{
    int virt = imx233_lradc_acquire_channel(src, TIMEOUT_BLOCK);
    // divide by two for wider ranger
    imx233_lradc_setup_channel(virt, div2, false, 0, src);
    int val = adc_read_physical_ex(virt);
    imx233_lradc_release_channel(virt);
    return val;
}

static short adc_read_virtual(int c)
{
    switch(c)
    {
        case IMX233_ADC_BATTERY:
            return imx233_lradc_read_battery_voltage();
        case IMX233_ADC_VDDIO:
            /* VddIO pin has a builtin 2:1 divide */
            return adc_read_physical(LRADC_SRC_VDDIO, true) * 2;
#if IMX233_SUBTARGET >= 3700
        case IMX233_ADC_VDD5V:
            /* Vdd5V pin has a builtin 4:1 divide */
            return adc_read_physical(LRADC_SRC_5V, true) * 4;
#endif
        case IMX233_ADC_DIE_TEMP:
        {
#if IMX233_SUBTARGET >= 3700
            // don't block on second channel otherwise we might deadlock !
            int nmos_chan = imx233_lradc_acquire_channel(LRADC_SRC_NMOS_THIN, TIMEOUT_BLOCK);
            int pmos_chan = imx233_lradc_acquire_channel(LRADC_SRC_PMOS_THIN, TIMEOUT_NOBLOCK);
            int val = 0;
            if(pmos_chan >= 0)
            {
                val = imx233_lradc_sense_die_temperature(nmos_chan, pmos_chan) - 273;
                imx233_lradc_release_channel(pmos_chan);
            }
            imx233_lradc_release_channel(nmos_chan);
#else
            int min, max, val;
            if(imx233_power_sense_die_temperature(&min, &max) < 0)
                val = -1;
            else
                val = (max + min) / 2;
#endif
            return val;
        }
#ifdef IMX233_BATT_TEMP_SENSOR
        case IMX233_ADC_BATT_TEMP:
        {
            int virt = imx233_lradc_acquire_channel(IMX233_BATT_TEMP_SENSOR, TIMEOUT_BLOCK);
            int val = imx233_lradc_sense_ext_temperature(virt, IMX233_BATT_TEMP_SENSOR);
            imx233_lradc_release_channel(virt);
            return val;
        }
#endif
        default:
            return 0;
    }
}

unsigned short adc_read(int channel)
{
    int c = imx233_adc_mapping[channel];
    if(c < 0)
        return adc_read_virtual(c);
    else
        return adc_read_physical(c, true);
}

const char *adc_name(int channel)
{
    return imx233_adc_channel_name[channel];
}