summaryrefslogtreecommitdiff
path: root/board/gateworks/gw_ventana/gsc.c
blob: a34a9a84c8f211f39bd9d776d83e6b390eaf7d83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2013 Gateworks Corporation
 *
 * Author: Tim Harvey <tharvey@gateworks.com>
 *
 * SPDX-License-Identifier: GPL-2.0+
 */

#include <asm/errno.h>
#include <common.h>
#include <i2c.h>
#include <linux/ctype.h>

#include "gsc.h"

#define MINMAX(n, percent)	((n)*(100-percent)/100), ((n)*(100+percent)/100)

/*
 * The Gateworks System Controller will fail to ACK a master transaction if
 * it is busy, which can occur during its 1HZ timer tick while reading ADC's.
 * When this does occur, it will never be busy long enough to fail more than
 * 2 back-to-back transfers.  Thus we wrap i2c_read and i2c_write with
 * 3 retries.
 */
int gsc_i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
{
	int retry = 3;
	int n = 0;
	int ret;

	while (n++ < retry) {
		ret = i2c_read(chip, addr, alen, buf, len);
		if (!ret)
			break;
		debug("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
		      n, ret);
		if (ret != -ENODEV)
			break;
		mdelay(10);
	}
	return ret;
}

int gsc_i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
{
	int retry = 3;
	int n = 0;
	int ret;

	while (n++ < retry) {
		ret = i2c_write(chip, addr, alen, buf, len);
		if (!ret)
			break;
		debug("%s: 0x%02x 0x%02x retry%d: %d\n", __func__, chip, addr,
		      n, ret);
		if (ret != -ENODEV)
			break;
		mdelay(10);
	}
	mdelay(100);
	return ret;
}

#ifdef CONFIG_CMD_GSC
static void read_hwmon(const char *name, uint reg, uint size, uint low,
		       uint high)
{
	unsigned char buf[3];
	uint ui;

	printf("%-8s:", name);
	memset(buf, 0, sizeof(buf));
	if (gsc_i2c_read(GSC_HWMON_ADDR, reg, 1, buf, size)) {
		puts("fRD\n");
	} else {
		ui = buf[0] | (buf[1]<<8) | (buf[2]<<16);
		if (ui == 0xffffff)
			printf("invalid");
		else if (ui < low)
			printf("%d Failed - Low", ui);
		else if (ui > high)
			printf("%d Failed - High", ui);
		else
			printf("%d", ui);
	}
	puts("\n");
}

int do_gsc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	const char *model = getenv("model");

	i2c_set_bus_num(0);
	read_hwmon("Temp",     GSC_HWMON_TEMP, 2, 0, 9000);
	read_hwmon("VIN",      GSC_HWMON_VIN, 3, 8000, 60000);
	read_hwmon("VBATT",    GSC_HWMON_VBATT, 3, 1800, 3500);
	read_hwmon("VDD_3P3",  GSC_HWMON_VDD_3P3, 3, MINMAX(3300, 10));
	read_hwmon("VDD_HIGH", GSC_HWMON_VDD_HIGH, 3, MINMAX(3000, 10));
	read_hwmon("VDD_DDR",  GSC_HWMON_VDD_DDR, 3, MINMAX(1500, 10));
	read_hwmon("VDD_5P0",  GSC_HWMON_VDD_5P0, 3, MINMAX(5000, 10));
	read_hwmon("VDD_2P5",  GSC_HWMON_VDD_2P5, 3, MINMAX(2500, 10));
	read_hwmon("VDD_1P8",  GSC_HWMON_VDD_1P8, 3, MINMAX(1800, 10));

	switch (model[3]) {
	case '1': /* GW51xx */
		read_hwmon("VDD_CORE", GSC_HWMON_VDD_CORE, 3, MINMAX(1175, 10));
		read_hwmon("VDD_SOC",  GSC_HWMON_VDD_SOC, 3, MINMAX(1175, 10));
		break;
	case '2': /* GW52xx */
	case '3': /* GW53xx */
		read_hwmon("VDD_CORE", GSC_HWMON_VDD_CORE, 3, MINMAX(1175, 10));
		read_hwmon("VDD_SOC",  GSC_HWMON_VDD_SOC, 3, MINMAX(1175, 10));
		read_hwmon("VDD_1P0",  GSC_HWMON_VDD_1P0, 3, MINMAX(1000, 10));
		break;
	case '4': /* GW54xx */
		read_hwmon("VDD_CORE", GSC_HWMON_VDD_CORE, 3, MINMAX(1375, 10));
		read_hwmon("VDD_SOC",  GSC_HWMON_VDD_SOC, 3, MINMAX(1375, 10));
		read_hwmon("VDD_1P0",  GSC_HWMON_VDD_1P0, 3, MINMAX(1000, 10));
		break;
	case '5': /* GW55xx */
		read_hwmon("VDD_CORE", GSC_HWMON_VDD_CORE, 3, MINMAX(1175, 10));
		read_hwmon("VDD_SOC",  GSC_HWMON_VDD_SOC, 3, MINMAX(1175, 10));
		break;
	}
	return 0;
}

U_BOOT_CMD(gsc, 1, 1, do_gsc,
	   "GSC test",
	   ""
);

#endif /* CONFIG_CMD_GSC */