/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #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_GRADE0) ret = BOARDID_UNKNOWN; else 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); INFO("[BDID]adcin0:%d adcin0_remap:%d\n", adcin0, adcin0_remap); if (adcin0_remap == BOARDID_UNKNOWN) return -EINVAL; /* read ADC channel1 data */ get_value(ADC_ADCIN1, &adcin1); adcin1_remap = adcin_data_remap(adcin1); INFO("[BDID]adcin1:%d adcin1_remap:%d\n", adcin1, adcin1_remap); if (adcin1_remap == BOARDID_UNKNOWN) return -EINVAL; /* read ADC channel2 data */ get_value(ADC_ADCIN2, &adcin2); adcin2_remap = adcin_data_remap(adcin2); INFO("[BDID]adcin2:%d adcin2_remap:%d\n", adcin2, adcin2_remap); if (adcin2_remap == BOARDID_UNKNOWN) return -EINVAL; *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) + (adcin1_remap * 10) + adcin0_remap; INFO("[BDID]boardid: %d\n", *id); return 0; }