/*
 * Copyright (c) 2023 The ChromiumOS Authors
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/adc/voltage_divider.h>
#include <zephyr/drivers/adc/current_sense_amplifier.h>

/* The devicetree node identifier for the adc aliases. */
#define VBUS_V_MEAS_NODE DT_ALIAS(vbus)
#define VBUS_C_MEAS_NODE DT_ALIAS(cbus)

static const struct voltage_divider_dt_spec adc_vbus_v =
	VOLTAGE_DIVIDER_DT_SPEC_GET(VBUS_V_MEAS_NODE);
static const struct current_sense_amplifier_dt_spec adc_vbus_c =
	CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(VBUS_C_MEAS_NODE);

int meas_vbus_v(int32_t *v)
{
	int ret;
	int32_t sample_buffer = 0;

	/* Structure defining an ADC sampling sequence */
	struct adc_sequence sequence = {
		.buffer = &sample_buffer,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(sample_buffer),
		.calibrate = true,
	};
	adc_sequence_init_dt(&adc_vbus_v.port, &sequence);

	ret = adc_read(adc_vbus_v.port.dev, &sequence);
	if (ret != 0) {
		return ret;
	}

	*v = sample_buffer;
	ret = adc_raw_to_millivolts_dt(&adc_vbus_v.port, v);
	if (ret != 0) {
		return ret;
	}

	ret = voltage_divider_scale_dt(&adc_vbus_v, v);
	if (ret != 0) {
		return ret;
	}

	return 0;
}

int meas_vbus_c(int32_t *c)
{
	int ret;
	int32_t sample_buffer = 0;

	/* Structure defining an ADC sampling sequence */
	struct adc_sequence sequence = {
		.buffer = &sample_buffer,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(sample_buffer),
		.calibrate = true,
	};
	adc_sequence_init_dt(&adc_vbus_c.port, &sequence);

	ret = adc_read(adc_vbus_c.port.dev, &sequence);
	if (ret != 0) {
		return ret;
	}

	*c = sample_buffer;
	ret = adc_raw_to_millivolts_dt(&adc_vbus_c.port, c);
	if (ret != 0) {
		return ret;
	}

	/* prescaling the voltage offset */
	*c -= adc_vbus_c.port.vref_mv / 2;
	current_sense_amplifier_scale_dt(&adc_vbus_c, c);

	return 0;
}

int meas_init(void)
{
	int ret;

	ret = adc_channel_setup_dt(&adc_vbus_v.port);
	if (ret != 0) {
		return ret;
	}

	ret = adc_channel_setup_dt(&adc_vbus_c.port);
	if (ret != 0) {
		return ret;
	}

	return 0;
}
