1 /*
2  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <errno.h>
9 
10 #include <common/debug.h>
11 #include <drivers/delay_timer.h>
12 #include <lib/mmio.h>
13 
14 #include <hi3660.h>
15 #include "hikey960_private.h"
16 
17 #define ADC_ADCIN0				0
18 #define ADC_ADCIN1				1
19 #define ADC_ADCIN2				2
20 
21 #define HKADC_DATA_GRADE0			0
22 #define HKADC_DATA_GRADE1			100
23 #define HKADC_DATA_GRADE2			300
24 #define HKADC_DATA_GRADE3			500
25 #define HKADC_DATA_GRADE4			700
26 #define HKADC_DATA_GRADE5			900
27 #define HKADC_DATA_GRADE6			1100
28 #define HKADC_DATA_GRADE7			1300
29 #define HKADC_DATA_GRADE8			1500
30 #define HKADC_DATA_GRADE9			1700
31 #define HKADC_DATA_GRADE10			1800
32 
33 #define BOARDID_VALUE0				0
34 #define BOARDID_VALUE1				1
35 #define BOARDID_VALUE2				2
36 #define BOARDID_VALUE3				3
37 #define BOARDID_VALUE4				4
38 #define BOARDID_VALUE5				5
39 #define BOARDID_VALUE6				6
40 #define BOARDID_VALUE7				7
41 #define BOARDID_VALUE8				8
42 #define BOARDID_VALUE9				9
43 #define BOARDID_UNKNOWN				0xF
44 
45 #define BOARDID3_BASE				5
46 
47 
init_adc(void)48 static void init_adc(void)
49 {
50 	/* reset hkadc */
51 	mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
52 	/* wait a few clock cycles */
53 	udelay(2);
54 	mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
55 	udelay(2);
56 	/* enable hkadc clock */
57 	mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
58 	udelay(2);
59 	mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
60 	udelay(2);
61 }
62 
get_adc(unsigned int channel,unsigned int * value)63 static int get_adc(unsigned int channel, unsigned int *value)
64 {
65 	unsigned int	data, value1, value0;
66 
67 	if (channel > HKADC_CHANNEL_MAX) {
68 		WARN("invalid channel:%d\n", channel);
69 		return -EFAULT;
70 	}
71 	/* configure the read/write operation for external HKADC */
72 	mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
73 	mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
74 	mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
75 	/* configure the number of accessing registers */
76 	mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
77 	/* configure delay of accessing registers */
78 	mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
79 	mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
80 
81 	/* start HKADC */
82 	mmio_write_32(HKADC_DSP_START_REG, 1);
83 	do {
84 		data = mmio_read_32(HKADC_DSP_START_REG);
85 	} while (data & 1);
86 
87 	/* convert AD result */
88 	value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
89 	value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
90 
91 	data = ((value1 << 4) & HKADC_VALUE_HIGH) |
92 	       ((value0 >> 4) & HKADC_VALUE_LOW);
93 	*value = data;
94 	return 0;
95 }
96 
get_value(unsigned int channel,unsigned int * value)97 static int get_value(unsigned int channel, unsigned int *value)
98 {
99 	int ret;
100 
101 	ret = get_adc(channel, value);
102 	if (ret)
103 		return ret;
104 
105 	/* convert ADC value to micro-volt */
106 	ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
107 	*value = ret;
108 	return 0;
109 }
110 
adcin_data_remap(unsigned int adcin_value)111 static int adcin_data_remap(unsigned int adcin_value)
112 {
113 	int	ret;
114 
115 	if (adcin_value < HKADC_DATA_GRADE1)
116 		ret = BOARDID_VALUE0;
117 	else if (adcin_value < HKADC_DATA_GRADE2)
118 		ret = BOARDID_VALUE1;
119 	else if (adcin_value < HKADC_DATA_GRADE3)
120 		ret = BOARDID_VALUE2;
121 	else if (adcin_value < HKADC_DATA_GRADE4)
122 		ret = BOARDID_VALUE3;
123 	else if (adcin_value < HKADC_DATA_GRADE5)
124 		ret = BOARDID_VALUE4;
125 	else if (adcin_value < HKADC_DATA_GRADE6)
126 		ret = BOARDID_VALUE5;
127 	else if (adcin_value < HKADC_DATA_GRADE7)
128 		ret = BOARDID_VALUE6;
129 	else if (adcin_value < HKADC_DATA_GRADE8)
130 		ret = BOARDID_VALUE7;
131 	else if (adcin_value < HKADC_DATA_GRADE9)
132 		ret = BOARDID_VALUE8;
133 	else if (adcin_value < HKADC_DATA_GRADE10)
134 		ret = BOARDID_VALUE9;
135 	else
136 		ret = BOARDID_UNKNOWN;
137 	return ret;
138 }
139 
hikey960_read_boardid(unsigned int * id)140 int hikey960_read_boardid(unsigned int *id)
141 {
142 	unsigned int	adcin0, adcin1, adcin2;
143 	unsigned int	adcin0_remap, adcin1_remap, adcin2_remap;
144 
145 	assert(id != NULL);
146 
147 	init_adc();
148 
149 	/* read ADC channel0 data */
150 	get_value(ADC_ADCIN0, &adcin0);
151 	adcin0_remap = adcin_data_remap(adcin0);
152 	if (adcin0_remap == BOARDID_UNKNOWN)
153 		return -EINVAL;
154 	/* read ADC channel1 data */
155 	get_value(ADC_ADCIN1, &adcin1);
156 	adcin1_remap = adcin_data_remap(adcin1);
157 	if (adcin1_remap == BOARDID_UNKNOWN)
158 		return -EINVAL;
159 	/* read ADC channel2 data */
160 	get_value(ADC_ADCIN2, &adcin2);
161 	adcin2_remap = adcin_data_remap(adcin2);
162 	if (adcin2_remap == BOARDID_UNKNOWN)
163 		return -EINVAL;
164 	*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
165 		(adcin1_remap * 10) + adcin0_remap;
166 	return 0;
167 }
168