1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <linux/stddef.h>
7 #include <adc.h>
8 #include <asm/io.h>
9 #include <dm.h>
10 #include <env.h>
11 #include <stdlib.h>
12 
13 #define DTB_DIR			"rockchip/"
14 
15 struct oga_model {
16 	const u16 adc_value;
17 	const char *board;
18 	const char *board_name;
19 	const char *fdtfile;
20 };
21 
22 enum oga_device_id {
23 	OGA,
24 	OGA_V11,
25 	OGS,
26 };
27 
28 /*
29  * All ADC values from schematic of Odroid Go Advance Black Edition.
30  * Value for OGS is inferred based on schematic and observed values.
31  */
32 static const struct oga_model oga_model_details[] = {
33 	[OGA] = {
34 		856,
35 		"rk3326-odroid-go2",
36 		"ODROID-GO Advance",
37 		DTB_DIR "rk3326-odroid-go2.dtb",
38 	},
39 	[OGA_V11] = {
40 		677,
41 		"rk3326-odroid-go2-v11",
42 		"ODROID-GO Advance Black Edition",
43 		DTB_DIR "rk3326-odroid-go2-v11.dtb",
44 	},
45 	[OGS] = {
46 		85,
47 		"rk3326-odroid-go3",
48 		"ODROID-GO Super",
49 		DTB_DIR "rk3326-odroid-go3.dtb",
50 	},
51 };
52 
53 /* Detect which Odroid Go Advance device we are using so as to load the
54  * correct devicetree for Linux. Set an environment variable once
55  * found. The detection depends on the value of ADC channel 0.
56  */
oga_detect_device(void)57 int oga_detect_device(void)
58 {
59 	u32 adc_info;
60 	int ret, i;
61 	int board_id = -ENXIO;
62 
63 	ret = adc_channel_single_shot("saradc@ff288000", 0, &adc_info);
64 	if (ret) {
65 		printf("Read SARADC failed with error %d\n", ret);
66 		return ret;
67 	}
68 
69 	/*
70 	 * Get the correct device from the table. The ADC value is
71 	 * determined by a resistor on ADC channel 0. The manufacturer
72 	 * accounted for this with a 5% tolerance, so assume a +- value
73 	 * of 50 should be enough.
74 	 */
75 	for (i = 0; i < ARRAY_SIZE(oga_model_details); i++) {
76 		u32 adc_min = oga_model_details[i].adc_value - 50;
77 		u32 adc_max = oga_model_details[i].adc_value + 50;
78 
79 		if (adc_min < adc_info && adc_max > adc_info) {
80 			board_id = i;
81 			break;
82 		}
83 	}
84 
85 	if (board_id < 0)
86 		return board_id;
87 
88 	env_set("board", oga_model_details[board_id].board);
89 	env_set("board_name",
90 		oga_model_details[board_id].board_name);
91 	env_set("fdtfile", oga_model_details[board_id].fdtfile);
92 
93 	return 0;
94 }
95 
rk_board_late_init(void)96 int rk_board_late_init(void)
97 {
98 	int ret;
99 
100 	ret = oga_detect_device();
101 	if (ret) {
102 		printf("Unable to detect device type: %d\n", ret);
103 		return ret;
104 	}
105 
106 	return 0;
107 }
108