drivers/soc/mediatek/mtk-regulator-coupler.c

Source file repositories/reference/linux-study-clean/drivers/soc/mediatek/mtk-regulator-coupler.c

File Facts

System
Linux kernel
Corpus path
drivers/soc/mediatek/mtk-regulator-coupler.c
Extension
.c
Size
4944 bytes
Lines
161
Domain
Driver Families
Bucket
drivers/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mediatek_regulator_coupler {
	struct regulator_coupler coupler;
	struct regulator_dev *vsram_rdev;
};

/*
 * We currently support only couples of not more than two vregs and
 * modify the vsram voltage only when changing voltage of vgpu.
 *
 * This function is limited to the GPU<->SRAM voltages relationships.
 */
static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,
					      struct regulator_dev *rdev,
					      suspend_state_t state)
{
	struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
	int max_spread = rdev->constraints->max_spread[0];
	int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;
	int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;
	int vsram_target_min_uV, vsram_target_max_uV;
	int min_uV = 0;
	int max_uV = INT_MAX;
	int ret;

	/*
	 * If the target device is on, setting the SRAM voltage directly
	 * is not supported as it scales through its coupled supply voltage.
	 *
	 * An exception is made in case the use_count is zero: this means
	 * that this is the first time we power up the SRAM regulator, which
	 * implies that the target device has yet to perform initialization
	 * and setting a voltage at that time is harmless.
	 */
	if (rdev == mrc->vsram_rdev) {
		if (rdev->use_count == 0)
			return regulator_do_balance_voltage(rdev, state, true);

		return -EPERM;
	}

	ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
	if (ret < 0)
		return ret;

	if (min_uV == 0) {
		ret = regulator_get_voltage_rdev(rdev);
		if (ret < 0)
			return ret;
		min_uV = ret;
	}

	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
	if (ret < 0)
		return ret;

	/*
	 * If we're asked to set a voltage less than VSRAM min_uV, set
	 * the minimum allowed voltage on VSRAM, as in this case it is
	 * safe to ignore the max_spread parameter.
	 */
	vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);
	vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);

	/* Make sure we're not out of range */
	vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);

	pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",
		 vsram_target_min_uV, vsram_target_max_uV,
		 rdev_get_name(mrc->vsram_rdev), min_uV);

	ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,
					 vsram_target_max_uV, state);
	if (ret)
		return ret;

	/* The sram voltage is now balanced: update the target vreg voltage */
	return regulator_do_balance_voltage(rdev, state, true);
}

static int mediatek_regulator_attach(struct regulator_coupler *coupler,
				     struct regulator_dev *rdev)
{
	struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);
	const char *rdev_name = rdev_get_name(rdev);

	/*
	 * If we're getting a coupling of more than two regulators here and
	 * this means that this is surely not a GPU<->SRAM couple: in that
	 * case, we may want to use another coupler implementation, if any,
	 * or the generic one: the regulator core will keep walking through

Annotation

Implementation Notes