12f2abcf4SHaojian Zhuang /* 2*17cf8ab1SHaojian Zhuang * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 32f2abcf4SHaojian Zhuang * 42f2abcf4SHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 52f2abcf4SHaojian Zhuang */ 62f2abcf4SHaojian Zhuang 72f2abcf4SHaojian Zhuang #include <assert.h> 82f2abcf4SHaojian Zhuang #include <debug.h> 92f2abcf4SHaojian Zhuang #include <delay_timer.h> 102f2abcf4SHaojian Zhuang #include <errno.h> 112f2abcf4SHaojian Zhuang #include <hi3660.h> 122f2abcf4SHaojian Zhuang #include <mmio.h> 132f2abcf4SHaojian Zhuang 142f2abcf4SHaojian Zhuang #include "hikey960_private.h" 152f2abcf4SHaojian Zhuang 162f2abcf4SHaojian Zhuang #define ADC_ADCIN0 0 172f2abcf4SHaojian Zhuang #define ADC_ADCIN1 1 182f2abcf4SHaojian Zhuang #define ADC_ADCIN2 2 192f2abcf4SHaojian Zhuang 202f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE0 0 212f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE1 100 222f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE2 300 232f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE3 500 242f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE4 700 252f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE5 900 262f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE6 1100 272f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE7 1300 282f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE8 1500 292f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE9 1700 302f2abcf4SHaojian Zhuang #define HKADC_DATA_GRADE10 1800 312f2abcf4SHaojian Zhuang 322f2abcf4SHaojian Zhuang #define BOARDID_VALUE0 0 332f2abcf4SHaojian Zhuang #define BOARDID_VALUE1 1 342f2abcf4SHaojian Zhuang #define BOARDID_VALUE2 2 352f2abcf4SHaojian Zhuang #define BOARDID_VALUE3 3 362f2abcf4SHaojian Zhuang #define BOARDID_VALUE4 4 372f2abcf4SHaojian Zhuang #define BOARDID_VALUE5 5 382f2abcf4SHaojian Zhuang #define BOARDID_VALUE6 6 392f2abcf4SHaojian Zhuang #define BOARDID_VALUE7 7 402f2abcf4SHaojian Zhuang #define BOARDID_VALUE8 8 412f2abcf4SHaojian Zhuang #define BOARDID_VALUE9 9 422f2abcf4SHaojian Zhuang #define BOARDID_UNKNOWN 0xF 432f2abcf4SHaojian Zhuang 442f2abcf4SHaojian Zhuang #define BOARDID3_BASE 5 452f2abcf4SHaojian Zhuang 462f2abcf4SHaojian Zhuang 472f2abcf4SHaojian Zhuang static void init_adc(void) 482f2abcf4SHaojian Zhuang { 492f2abcf4SHaojian Zhuang /* reset hkadc */ 502f2abcf4SHaojian Zhuang mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI); 512f2abcf4SHaojian Zhuang /* wait a few clock cycles */ 522f2abcf4SHaojian Zhuang udelay(2); 532f2abcf4SHaojian Zhuang mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI); 542f2abcf4SHaojian Zhuang udelay(2); 552f2abcf4SHaojian Zhuang /* enable hkadc clock */ 562f2abcf4SHaojian Zhuang mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI); 572f2abcf4SHaojian Zhuang udelay(2); 582f2abcf4SHaojian Zhuang mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI); 592f2abcf4SHaojian Zhuang udelay(2); 602f2abcf4SHaojian Zhuang } 612f2abcf4SHaojian Zhuang 622f2abcf4SHaojian Zhuang static int get_adc(unsigned int channel, unsigned int *value) 632f2abcf4SHaojian Zhuang { 642f2abcf4SHaojian Zhuang unsigned int data, value1, value0; 652f2abcf4SHaojian Zhuang 662f2abcf4SHaojian Zhuang if (channel > HKADC_CHANNEL_MAX) { 672f2abcf4SHaojian Zhuang WARN("invalid channel:%d\n", channel); 682f2abcf4SHaojian Zhuang return -EFAULT; 692f2abcf4SHaojian Zhuang } 702f2abcf4SHaojian Zhuang /* configure the read/write operation for external HKADC */ 712f2abcf4SHaojian Zhuang mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel); 722f2abcf4SHaojian Zhuang mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE); 732f2abcf4SHaojian Zhuang mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE); 742f2abcf4SHaojian Zhuang /* configure the number of accessing registers */ 752f2abcf4SHaojian Zhuang mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE); 762f2abcf4SHaojian Zhuang /* configure delay of accessing registers */ 772f2abcf4SHaojian Zhuang mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE); 782f2abcf4SHaojian Zhuang mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE); 792f2abcf4SHaojian Zhuang 802f2abcf4SHaojian Zhuang /* start HKADC */ 812f2abcf4SHaojian Zhuang mmio_write_32(HKADC_DSP_START_REG, 1); 822f2abcf4SHaojian Zhuang do { 832f2abcf4SHaojian Zhuang data = mmio_read_32(HKADC_DSP_START_REG); 842f2abcf4SHaojian Zhuang } while (data & 1); 852f2abcf4SHaojian Zhuang 862f2abcf4SHaojian Zhuang /* convert AD result */ 872f2abcf4SHaojian Zhuang value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff; 882f2abcf4SHaojian Zhuang value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff; 892f2abcf4SHaojian Zhuang 902f2abcf4SHaojian Zhuang data = ((value1 << 4) & HKADC_VALUE_HIGH) | 912f2abcf4SHaojian Zhuang ((value0 >> 4) & HKADC_VALUE_LOW); 922f2abcf4SHaojian Zhuang *value = data; 932f2abcf4SHaojian Zhuang return 0; 942f2abcf4SHaojian Zhuang } 952f2abcf4SHaojian Zhuang 962f2abcf4SHaojian Zhuang static int get_value(unsigned int channel, unsigned int *value) 972f2abcf4SHaojian Zhuang { 982f2abcf4SHaojian Zhuang int ret; 992f2abcf4SHaojian Zhuang 1002f2abcf4SHaojian Zhuang ret = get_adc(channel, value); 1012f2abcf4SHaojian Zhuang if (ret) 1022f2abcf4SHaojian Zhuang return ret; 1032f2abcf4SHaojian Zhuang 1042f2abcf4SHaojian Zhuang /* convert ADC value to micro-volt */ 1052f2abcf4SHaojian Zhuang ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY; 1062f2abcf4SHaojian Zhuang *value = ret; 1072f2abcf4SHaojian Zhuang return 0; 1082f2abcf4SHaojian Zhuang } 1092f2abcf4SHaojian Zhuang 1102f2abcf4SHaojian Zhuang static int adcin_data_remap(unsigned int adcin_value) 1112f2abcf4SHaojian Zhuang { 1122f2abcf4SHaojian Zhuang int ret; 1132f2abcf4SHaojian Zhuang 1148aa928acSHaojian Zhuang if (adcin_value < HKADC_DATA_GRADE1) 1152f2abcf4SHaojian Zhuang ret = BOARDID_VALUE0; 1162f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE2) 1172f2abcf4SHaojian Zhuang ret = BOARDID_VALUE1; 1182f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE3) 1192f2abcf4SHaojian Zhuang ret = BOARDID_VALUE2; 1202f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE4) 1212f2abcf4SHaojian Zhuang ret = BOARDID_VALUE3; 1222f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE5) 1232f2abcf4SHaojian Zhuang ret = BOARDID_VALUE4; 1242f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE6) 1252f2abcf4SHaojian Zhuang ret = BOARDID_VALUE5; 1262f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE7) 1272f2abcf4SHaojian Zhuang ret = BOARDID_VALUE6; 1282f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE8) 1292f2abcf4SHaojian Zhuang ret = BOARDID_VALUE7; 1302f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE9) 1312f2abcf4SHaojian Zhuang ret = BOARDID_VALUE8; 1322f2abcf4SHaojian Zhuang else if (adcin_value < HKADC_DATA_GRADE10) 1332f2abcf4SHaojian Zhuang ret = BOARDID_VALUE9; 1342f2abcf4SHaojian Zhuang else 1352f2abcf4SHaojian Zhuang ret = BOARDID_UNKNOWN; 1362f2abcf4SHaojian Zhuang return ret; 1372f2abcf4SHaojian Zhuang } 1382f2abcf4SHaojian Zhuang 1392f2abcf4SHaojian Zhuang int hikey960_read_boardid(unsigned int *id) 1402f2abcf4SHaojian Zhuang { 1412f2abcf4SHaojian Zhuang unsigned int adcin0, adcin1, adcin2; 1422f2abcf4SHaojian Zhuang unsigned int adcin0_remap, adcin1_remap, adcin2_remap; 1432f2abcf4SHaojian Zhuang 1442f2abcf4SHaojian Zhuang assert(id != NULL); 1452f2abcf4SHaojian Zhuang 1462f2abcf4SHaojian Zhuang init_adc(); 1472f2abcf4SHaojian Zhuang 1482f2abcf4SHaojian Zhuang /* read ADC channel0 data */ 1492f2abcf4SHaojian Zhuang get_value(ADC_ADCIN0, &adcin0); 1502f2abcf4SHaojian Zhuang adcin0_remap = adcin_data_remap(adcin0); 1512f2abcf4SHaojian Zhuang if (adcin0_remap == BOARDID_UNKNOWN) 1522f2abcf4SHaojian Zhuang return -EINVAL; 1532f2abcf4SHaojian Zhuang /* read ADC channel1 data */ 1542f2abcf4SHaojian Zhuang get_value(ADC_ADCIN1, &adcin1); 1552f2abcf4SHaojian Zhuang adcin1_remap = adcin_data_remap(adcin1); 1562f2abcf4SHaojian Zhuang if (adcin1_remap == BOARDID_UNKNOWN) 1572f2abcf4SHaojian Zhuang return -EINVAL; 1582f2abcf4SHaojian Zhuang /* read ADC channel2 data */ 1592f2abcf4SHaojian Zhuang get_value(ADC_ADCIN2, &adcin2); 1602f2abcf4SHaojian Zhuang adcin2_remap = adcin_data_remap(adcin2); 1612f2abcf4SHaojian Zhuang if (adcin2_remap == BOARDID_UNKNOWN) 1622f2abcf4SHaojian Zhuang return -EINVAL; 1632f2abcf4SHaojian Zhuang *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) + 1642f2abcf4SHaojian Zhuang (adcin1_remap * 10) + adcin0_remap; 1652f2abcf4SHaojian Zhuang return 0; 1662f2abcf4SHaojian Zhuang } 167