<commit_before>/* Copyright 2018 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.
 */

/* Silergy SYV682x USB-C Power Path Controller */
#include "common.h"
#include "console.h"
#include "driver/ppc/syv682x.h"
#include "i2c.h"
#include "usb_charge.h"
#include "usb_pd_tcpm.h"
#include "usbc_ppc.h"
#include "util.h"

#define SYV682X_FLAGS_SOURCE_ENABLED (1 << 0)
/* 0 -> CC1, 1 -> CC2 */
#define SYV682X_FLAGS_CC_POLARITY (1 << 1)
#define SYV682X_FLAGS_VBUS_PRESENT (1 << 2)
static uint8_t flags[CONFIG_USB_PD_PORT_COUNT];

#define SYV682X_VBUS_DET_THRESH_MV 4000

static int read_reg(uint8_t port, int reg, int *regval)
{
	return i2c_read8(ppc_chips[port].i2c_port,
			 ppc_chips[port].i2c_addr,
			 reg,
			 regval);
}

static int write_reg(uint8_t port, int reg, int regval)
{
	return i2c_write8(ppc_chips[port].i2c_port,
			  ppc_chips[port].i2c_addr,
			  reg,
			  regval);
}

static int syv682x_is_sourcing_vbus(int port)
{
	return flags[port] & SYV682X_FLAGS_SOURCE_ENABLED;
}

static int syv682x_vbus_sink_enable(int port, int enable)
{
	int regval;
	int rv;

	/*
	 * For sink mode need to make sure high voltage power path is connected
	 * and sink mode is selected.
	 */
	rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
	if (rv)
		return rv;

	if (enable) {
		/* Select high voltage path */
		regval |= SYV682X_CONTROL_1_CH_SEL;
		/* Select Sink mode and turn on the channel */
		regval &= ~(SYV682X_CONTROL_1_HV_DR |
			    SYV682X_CONTROL_1_PWR_ENB);
	} else {
		/*
		 * No need to change the voltage path or channel direction. But,
		 * turn both paths off.
		 */
		regval |= SYV682X_CONTROL_1_PWR_ENB;
	}

	return write_reg(port, SYV682X_CONTROL_1_REG, regval);
}

#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
static int syv682x_is_vbus_present(int port)
{
	int val;
	int vbus = 0;

	/*
	 * TODO (b/112661747): This PPC doesn't fully support VBUS detection.
	 * It can detect both VSafe5V and VSafe0V. This function is intended
	 * here until detecting VBUS differently per channel is supported.
	 */
	if (read_reg(port, SYV682X_STATUS_REG, &val))
		return vbus;

	/*
	 * VBUS is considered present if VSafe5V is detected or neither VSafe5V
	 * or VSafe0V is detected, which implies VBUS > 5V.
	 */
	if ((val & SYV682X_STATUS_VSAFE_5V) ||
	    !(val & (SYV682X_STATUS_VSAFE_5V | SYV682X_STATUS_VSAFE_0V)))
		vbus = 1;
#ifdef CONFIG_USB_CHARGER
	if (!!(flags[port] & SYV682X_FLAGS_VBUS_PRESENT) != vbus)
		usb_charger_vbus_change(port, vbus);

	if (vbus)
		flags[port] |= SYV682X_FLAGS_VBUS_PRESENT;
	else
		flags[port] &= ~SYV682X_FLAGS_VBUS_PRESENT;
#endif

	return vbus;
}
#endif

static int syv682x_vbus_source_enable(int port, int enable)
{
	int regval;
	int rv;

	/*
	 * For source mode need to make sure 5V power path is connected
	 * and source mode is selected.
	 */
	rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
	if (rv)
		return rv;

	if (enable) {
		/* Select 5V path and turn on channel */
		regval &= ~(SYV682X_CONTROL_1_CH_SEL |
			    SYV682X_CONTROL_1_PWR_ENB);
		/* Disable HV Sink path */
		regval |= SYV682X_CONTROL_1_HV_DR;
	} else {
		/*
		 * No need to change the voltage path or channel direction. But,
		 * turn both paths off.
		 */
		regval |= SYV682X_CONTROL_1_PWR_ENB;
	}

	rv = write_reg(port, SYV682X_CONTROL_1_REG, regval);
	if (rv)
		return rv;

	if (enable)
		flags[port] |= SYV682X_FLAGS_SOURCE_ENABLED;
	else
		flags[port] &= ~SYV682X_FLAGS_SOURCE_ENABLED;

	return EC_SUCCESS;
}

static int syv682x_set_vbus_source_current_limit(int port,
						 enum tcpc_rp_value rp)<commit_msg>ppc: syv682x: Make source disable dependent on VBUS presence<commit_after>/* Copyright 2018 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.
 */

/* Silergy SYV682x USB-C Power Path Controller */
#include "common.h"
#include "console.h"
#include "driver/ppc/syv682x.h"
#include "i2c.h"
#include "usb_charge.h"
#include "usb_pd_tcpm.h"
#include "usbc_ppc.h"
#include "util.h"

#define SYV682X_FLAGS_SOURCE_ENABLED (1 << 0)
/* 0 -> CC1, 1 -> CC2 */
#define SYV682X_FLAGS_CC_POLARITY (1 << 1)
#define SYV682X_FLAGS_VBUS_PRESENT (1 << 2)
static uint8_t flags[CONFIG_USB_PD_PORT_COUNT];

#define SYV682X_VBUS_DET_THRESH_MV 4000

static int read_reg(uint8_t port, int reg, int *regval)
{
	return i2c_read8(ppc_chips[port].i2c_port,
			 ppc_chips[port].i2c_addr,
			 reg,
			 regval);
}

static int write_reg(uint8_t port, int reg, int regval)
{
	return i2c_write8(ppc_chips[port].i2c_port,
			  ppc_chips[port].i2c_addr,
			  reg,
			  regval);
}

static int syv682x_is_sourcing_vbus(int port)
{
	return flags[port] & SYV682X_FLAGS_SOURCE_ENABLED;
}

static int syv682x_vbus_sink_enable(int port, int enable)
{
	int regval;
	int rv;

	/*
	 * For sink mode need to make sure high voltage power path is connected
	 * and sink mode is selected.
	 */
	rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
	if (rv)
		return rv;

	if (enable) {
		/* Select high voltage path */
		regval |= SYV682X_CONTROL_1_CH_SEL;
		/* Select Sink mode and turn on the channel */
		regval &= ~(SYV682X_CONTROL_1_HV_DR |
			    SYV682X_CONTROL_1_PWR_ENB);
	} else {
		/*
		 * No need to change the voltage path or channel direction. But,
		 * turn both paths off.
		 */
		regval |= SYV682X_CONTROL_1_PWR_ENB;
	}

	return write_reg(port, SYV682X_CONTROL_1_REG, regval);
}

#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
static int syv682x_is_vbus_present(int port)
{
	int val;
	int vbus = 0;

	/*
	 * TODO (b/112661747): This PPC doesn't fully support VBUS detection.
	 * It can detect both VSafe5V and VSafe0V. This function is intended
	 * here until detecting VBUS differently per channel is supported.
	 */
	if (read_reg(port, SYV682X_STATUS_REG, &val))
		return vbus;

	/*
	 * VBUS is considered present if VSafe5V is detected or neither VSafe5V
	 * or VSafe0V is detected, which implies VBUS > 5V.
	 */
	if ((val & SYV682X_STATUS_VSAFE_5V) ||
	    !(val & (SYV682X_STATUS_VSAFE_5V | SYV682X_STATUS_VSAFE_0V)))
		vbus = 1;
#ifdef CONFIG_USB_CHARGER
	if (!!(flags[port] & SYV682X_FLAGS_VBUS_PRESENT) != vbus)
		usb_charger_vbus_change(port, vbus);

	if (vbus)
		flags[port] |= SYV682X_FLAGS_VBUS_PRESENT;
	else
		flags[port] &= ~SYV682X_FLAGS_VBUS_PRESENT;
#endif

	return vbus;
}
#endif

static int syv682x_vbus_source_enable(int port, int enable)
{
	int regval;
	int rv;

	/*
	 * For source mode need to make sure 5V power path is connected
	 * and source mode is selected.
	 */
	rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
	if (rv)
		return rv;

	if (enable) {
		/* Select 5V path and turn on channel */
		regval &= ~(SYV682X_CONTROL_1_CH_SEL |
			    SYV682X_CONTROL_1_PWR_ENB);
		/* Disable HV Sink path */
		regval |= SYV682X_CONTROL_1_HV_DR;
	} else if (flags[port] & SYV682X_FLAGS_SOURCE_ENABLED) {
		/*
		 * For the disable case, make sure that VBUS was being sourced
		 * proir to disabling the source path. Because the source/sink
		 * paths can't be independently disabled, and this function will
		 * get called as part of USB PD initialization, setting the
		 * PWR_ENB always can lead to broken dead battery behavior.
		 *
		 * No need to change the voltage path or channel direction. But,
		 * turn both paths off.
		 */
		regval |= SYV682X_CONTROL_1_PWR_ENB;
	}

	rv = write_reg(port, SYV682X_CONTROL_1_REG, regval);
	if (rv)
		return rv;

	if (enable)
		flags[port] |= SYV682X_FLAGS_SOURCE_ENABLED;
	else
		flags[port] &= ~SYV682X_FLAGS_SOURCE_ENABLED;

	return EC_SUCCESS;
}

static int syv682x_set_vbus_source_current_limit(int port,
						 enum tcpc_rp_value rp)
{'fraction_non_alphanumeric': 0.09720597790773229, 'fraction_numerical': 0.043144899285250164, 'mean_word_length': 4.0498687664042, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3907495', 'n_tokens_mistral': 3388, 'n_tokens_neox': 2999, 'n_words': 798}