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