Home | History | Annotate | Download | only in hikey960
      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