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