168 lines
4.3 KiB
C
168 lines
4.3 KiB
C
/*
|
|
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
|
|
#include <common/debug.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#include <hi3660.h>
|
|
#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_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);
|
|
if (adcin0_remap == BOARDID_UNKNOWN)
|
|
return -EINVAL;
|
|
/* read ADC channel1 data */
|
|
get_value(ADC_ADCIN1, &adcin1);
|
|
adcin1_remap = adcin_data_remap(adcin1);
|
|
if (adcin1_remap == BOARDID_UNKNOWN)
|
|
return -EINVAL;
|
|
/* read ADC channel2 data */
|
|
get_value(ADC_ADCIN2, &adcin2);
|
|
adcin2_remap = adcin_data_remap(adcin2);
|
|
if (adcin2_remap == BOARDID_UNKNOWN)
|
|
return -EINVAL;
|
|
*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
|
|
(adcin1_remap * 10) + adcin0_remap;
|
|
return 0;
|
|
}
|