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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <hi3660.h>
#include "hikey960_private.h"
#define ADC_ADCIN0 0
#define ADC_ADCIN1 1
#define ADC_ADCIN2 2
#define HKADC_DATA_GRADE0 0
#define HKADC_DATA_GRADE1 100
#define HKADC_DATA_GRADE2 300
#define HKADC_DATA_GRADE3 500
#define HKADC_DATA_GRADE4 700
#define HKADC_DATA_GRADE5 900
#define HKADC_DATA_GRADE6 1100
#define HKADC_DATA_GRADE7 1300
#define HKADC_DATA_GRADE8 1500
#define HKADC_DATA_GRADE9 1700
#define HKADC_DATA_GRADE10 1800
#define BOARDID_VALUE0 0
#define BOARDID_VALUE1 1
#define BOARDID_VALUE2 2
#define BOARDID_VALUE3 3
#define BOARDID_VALUE4 4
#define BOARDID_VALUE5 5
#define BOARDID_VALUE6 6
#define BOARDID_VALUE7 7
#define BOARDID_VALUE8 8
#define BOARDID_VALUE9 9
#define BOARDID_UNKNOWN 0xF
#define BOARDID3_BASE 5
static void init_adc(void)
{
/* reset hkadc */
mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
/* wait a few clock cycles */
udelay(2);
mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
udelay(2);
/* enable hkadc clock */
mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
udelay(2);
mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
udelay(2);
}
static int get_adc(unsigned int channel, unsigned int *value)
{
unsigned int data, value1, value0;
if (channel > HKADC_CHANNEL_MAX) {
WARN("invalid channel:%d\n", channel);
return -EFAULT;
}
/* configure the read/write operation for external HKADC */
mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
/* configure the number of accessing registers */
mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
/* configure delay of accessing registers */
mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
/* start HKADC */
mmio_write_32(HKADC_DSP_START_REG, 1);
do {
data = mmio_read_32(HKADC_DSP_START_REG);
} while (data & 1);
/* convert AD result */
value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
data = ((value1 << 4) & HKADC_VALUE_HIGH) |
((value0 >> 4) & HKADC_VALUE_LOW);
*value = data;
return 0;
}
static int get_value(unsigned int channel, unsigned int *value)
{
int ret;
ret = get_adc(channel, value);
if (ret)
return ret;
/* convert ADC value to micro-volt */
ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
*value = ret;
return 0;
}
static int adcin_data_remap(unsigned int adcin_value)
{
int ret;
if (adcin_value < HKADC_DATA_GRADE1)
ret = BOARDID_VALUE0;
else if (adcin_value < HKADC_DATA_GRADE2)
ret = BOARDID_VALUE1;
else if (adcin_value < HKADC_DATA_GRADE3)
ret = BOARDID_VALUE2;
else if (adcin_value < HKADC_DATA_GRADE4)
ret = BOARDID_VALUE3;
else if (adcin_value < HKADC_DATA_GRADE5)
ret = BOARDID_VALUE4;
else if (adcin_value < HKADC_DATA_GRADE6)
ret = BOARDID_VALUE5;
else if (adcin_value < HKADC_DATA_GRADE7)
ret = BOARDID_VALUE6;
else if (adcin_value < HKADC_DATA_GRADE8)
ret = BOARDID_VALUE7;
else if (adcin_value < HKADC_DATA_GRADE9)
ret = BOARDID_VALUE8;
else if (adcin_value < HKADC_DATA_GRADE10)
ret = BOARDID_VALUE9;
else
ret = BOARDID_UNKNOWN;
return ret;
}
int hikey960_read_boardid(unsigned int *id)
{
unsigned int adcin0, adcin1, adcin2;
unsigned int adcin0_remap, adcin1_remap, adcin2_remap;
assert(id != NULL);
init_adc();
/* read ADC channel0 data */
get_value(ADC_ADCIN0, &adcin0);
adcin0_remap = adcin_data_remap(adcin0);
if (adcin0_remap == BOARDID_UNKNOWN)
return -EINVAL;
/* read ADC channel1 data */
get_value(ADC_ADCIN1, &adcin1);
adcin1_remap = adcin_data_remap(adcin1);
if (adcin1_remap == BOARDID_UNKNOWN)
return -EINVAL;
/* read ADC channel2 data */
get_value(ADC_ADCIN2, &adcin2);
adcin2_remap = adcin_data_remap(adcin2);
if (adcin2_remap == BOARDID_UNKNOWN)
return -EINVAL;
*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
(adcin1_remap * 10) + adcin0_remap;
return 0;
}
|