summaryrefslogtreecommitdiff
path: root/board/servo_v4p1/dacs.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/servo_v4p1/dacs.c')
-rw-r--r--board/servo_v4p1/dacs.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/board/servo_v4p1/dacs.c b/board/servo_v4p1/dacs.c
new file mode 100644
index 0000000000..b5c62bb438
--- /dev/null
+++ b/board/servo_v4p1/dacs.c
@@ -0,0 +1,138 @@
+/* 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;
+}
+
+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");