summaryrefslogtreecommitdiff
path: root/board/servo_v4p1/dacs.c
blob: 087a33487320d094971dfc299fe895d54109d28b (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
134
135
136
137
138
139
140
/* Copyright 2020 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "dacs.h"
#include "i2c.h"
#include "ioexpanders.h"
#include "util.h"

#define MAX_MV 5000

#define CC1_DAC_ADDR 0x48
#define CC2_DAC_ADDR 0x49

#define REG_NOOP    0
#define REG_DEVID   1
#define REG_SYNC    2
#define REG_CONFIG  3
#define REG_GAIN    4
#define REG_TRIGGER 5
#define REG_STATUS  7
#define REG_DAC     8

#define DAC1	BIT(0)
#define DAC2	BIT(1)

static uint8_t dac_enabled;

void init_dacs(void)
{
	/* Disable both DACS by default */
	enable_dac(CC1_DAC, 0);
	enable_dac(CC2_DAC, 0);
	dac_enabled = 0;
}

void enable_dac(enum dac_t dac, uint8_t en)
{
	switch (dac) {
	case CC1_DAC:
		if (en) {
			fault_clear_cc(1);
			fault_clear_cc(0);
			en_vout_buf_cc1(1);
			/* Power ON DAC */
			i2c_write8(1, CC1_DAC_ADDR, REG_CONFIG, 0);
			dac_enabled |= DAC1;
		} else {
			en_vout_buf_cc1(0);
			/* Power OFF DAC */
			i2c_write8(1, CC1_DAC_ADDR, REG_CONFIG, 1);
			dac_enabled &= ~DAC1;
		}
		break;
	case CC2_DAC:
		if (en) {
			fault_clear_cc(1);
			fault_clear_cc(0);
			en_vout_buf_cc2(1);
			i2c_write8(1, CC2_DAC_ADDR, REG_CONFIG, 0);
			dac_enabled |= DAC2;
		} else {
			en_vout_buf_cc2(0);
			/* Power down DAC */
			i2c_write8(1, CC2_DAC_ADDR, REG_CONFIG, 1);
			dac_enabled &= ~DAC2;
		}
		break;
	}
}

int write_dac(enum dac_t dac, uint16_t value)
{
	uint16_t tmp;

	/*
	 * Data are MSB aligned in straight binary format, and
	 * use the following format: DATA[13:0], 0, 0
	 */
	tmp = (value << 8) & 0xff00;
	tmp |= (value >> 8) & 0xff;
	tmp <<= 2;

	switch (dac) {
	case CC1_DAC:
		if (!(dac_enabled & DAC1)) {
			ccprintf("CC1_DAC is disabled\n");
			return EC_ERROR_ACCESS_DENIED;
		}
		i2c_write16(1, CC1_DAC_ADDR, REG_DAC, tmp);
		break;
	case CC2_DAC:
		if (!(dac_enabled & DAC2)) {
			ccprintf("CC2_DAC is disabled\n");
			return EC_ERROR_ACCESS_DENIED;
		}
		i2c_write16(1, CC2_DAC_ADDR, REG_DAC, tmp);
		break;
	}
	return EC_SUCCESS;
}

#ifdef SECTION_IS_RO
static int cmd_cc_dac(int argc, char *argv[])
{
	uint8_t dac;
	uint64_t mv;
	uint64_t round_up;
	char *e;

	if (argc < 3)
		return EC_ERROR_PARAM_COUNT;

	dac = strtoi(argv[1], &e, 10);
	if (*e || (dac != CC1_DAC && dac != CC2_DAC))
		return EC_ERROR_PARAM2;

	if (!strcasecmp(argv[2], "on")) {
		enable_dac(dac, 1);
	} else if (!strcasecmp(argv[2], "off")) {
		enable_dac(dac, 0);
	} else {
		/* get value in mV */
		mv = strtoi(argv[2], &e, 10);
		/* 5000 mV max */
		if (*e || mv > MAX_MV)
			return EC_ERROR_PARAM3;
		/* 305176 = (5V / 2^14) * 1000000 */
		/* 152588 = 305176 / 2 : used for round up after division */
		round_up = (((mv * 1000000) + 152588) / 305176);
		if (!write_dac(dac, (uint16_t)round_up))
			ccprintf("Setting DAC to %lld counts\n", round_up);
	}
	return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(cc_dac, cmd_cc_dac,
			"dac <\"on\"|\"off\"|mv>",
			"Set Servo v4.1 CC dacs");
#endif