blob: 1e1126fb1a903bf1c2225c6a4a3963416c88cfda [file] [log] [blame]
Haojian Zhuang602362d2017-06-01 12:15:14 +08001/*
Haojian Zhuangac340722018-01-27 19:29:36 +08002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Haojian Zhuang602362d2017-06-01 12:15:14 +08003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Haojian Zhuang602362d2017-06-01 12:15:14 +08008#include <errno.h>
Haojian Zhuang602362d2017-06-01 12:15:14 +08009
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010#include <common/debug.h>
11#include <drivers/delay_timer.h>
12#include <lib/mmio.h>
13
14#include <hi3660.h>
Haojian Zhuang602362d2017-06-01 12:15:14 +080015#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
48static 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
63static 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
97static 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
111static int adcin_data_remap(unsigned int adcin_value)
112{
113 int ret;
114
Haojian Zhuangb7ee0922017-06-12 22:20:38 +0800115 if (adcin_value < HKADC_DATA_GRADE1)
Haojian Zhuang602362d2017-06-01 12:15:14 +0800116 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
140int 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);
Haojian Zhuang602362d2017-06-01 12:15:14 +0800152 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);
Haojian Zhuang602362d2017-06-01 12:15:14 +0800157 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);
Haojian Zhuang602362d2017-06-01 12:15:14 +0800162 if (adcin2_remap == BOARDID_UNKNOWN)
163 return -EINVAL;
164 *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
165 (adcin1_remap * 10) + adcin0_remap;
Haojian Zhuang602362d2017-06-01 12:15:14 +0800166 return 0;
167}