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