blob: ca3d1fe25ad18e0a0cb04bc3e084cbce01012f3c [file] [log] [blame]
Harald Welte67322482017-02-04 14:43:41 +01001#include "board.h"
2#include "boardver_adc.h"
3
4/* FIXME: share this with mode_cardemu.c */
5#define UV_PER_LSB ((3300 * 1000) / 4096)
6static uint32_t adc2uv(uint16_t adc)
7{
8 uint32_t uv = (uint32_t) adc * UV_PER_LSB;
9 return uv;
10}
11
12/***********************************************************************
13 * ADC for board version detection
14 ***********************************************************************/
15
16#ifdef PIN_VERSION_DET
17
18static int adc_sam3s_reva_errata = 0;
19
20static const Pin pin_version_det = PIN_VERSION_DET;
21
22/* Warning: Don't call this while other code (like the SIM VCC voltage
23 * reading) is running. The idea is you call this once during board
24 * startup and cache the result in a (global) variable if you need it
25 * later throughout the code */
26int get_board_version_adc(void)
27{
28 uint32_t chip_arch = CHIPID->CHIPID_CIDR & CHIPID_CIDR_ARCH_Msk;
29 uint32_t chip_ver = CHIPID->CHIPID_CIDR & CHIPID_CIDR_VERSION_Msk;
30 uint16_t sample;
31 uint32_t uv;
32
33 PIO_Configure(&pin_version_det, 1);
34
35 PMC_EnablePeripheral(ID_ADC);
36
37 ADC->ADC_CR |= ADC_CR_SWRST;
38 if (chip_ver == 0 &&
39 (chip_arch == CHIPID_CIDR_ARCH_SAM3SxA ||
40 chip_arch == CHIPID_CIDR_ARCH_SAM3SxB ||
41 chip_arch == CHIPID_CIDR_ARCH_SAM3SxC)) {
42 TRACE_INFO("Enabling Rev.A ADC Errata work-around\r\n");
43 adc_sam3s_reva_errata = 1;
44 }
45
46 if (adc_sam3s_reva_errata) {
47 /* Errata Work-Around to clear EOCx flags */
48 volatile uint32_t foo;
49 int i;
50 for (i = 0; i < 16; i++)
51 foo = ADC->ADC_CDR[i];
52 }
53
54 /* Initialize ADC for AD2, fADC=48/24=2MHz */
55 ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
56 ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
57 ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
58 ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
59 ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
60 ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
61 /* enable AD2 channel only */
62 ADC->ADC_CHER = ADC_CHER_CH2;
63
64 /* Make sure we don't use interrupts as that's what the SIM card
65 * VCC ADC code is using */
66 ADC->ADC_IER = 0;
67 NVIC_DisableIRQ(ADC_IRQn);
68
69 ADC->ADC_CR |= ADC_CR_START;
70
71 /* busy-wait, actually read the value */
72 do { } while (!(ADC->ADC_ISR & ADC_ISR_EOC2));
73 /* convert to voltage */
74 sample = ADC->ADC_CDR[2];
75 uv = adc2uv(sample);
76 TRACE_INFO("VERSION_DET ADC=%u => %u uV\r\n", sample, uv);
77
78 /* FIXME: convert to board version based on thresholds */
79
80 return 0;
81}
82
83#endif /* PIN_VERSION_DET */