brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · ad2ed42 Raw
160 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Voltage regulators coupler for MediaTek SoCs4 *5 * Copyright (C) 2022 Collabora, Ltd.6 * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>7 */8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt10 11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/of.h>14#include <linux/regulator/coupler.h>15#include <linux/regulator/driver.h>16#include <linux/regulator/machine.h>17#include <linux/suspend.h>18 19#define to_mediatek_coupler(x)	container_of(x, struct mediatek_regulator_coupler, coupler)20 21struct mediatek_regulator_coupler {22	struct regulator_coupler coupler;23	struct regulator_dev *vsram_rdev;24};25 26/*27 * We currently support only couples of not more than two vregs and28 * modify the vsram voltage only when changing voltage of vgpu.29 *30 * This function is limited to the GPU<->SRAM voltages relationships.31 */32static int mediatek_regulator_balance_voltage(struct regulator_coupler *coupler,33					      struct regulator_dev *rdev,34					      suspend_state_t state)35{36	struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);37	int max_spread = rdev->constraints->max_spread[0];38	int vsram_min_uV = mrc->vsram_rdev->constraints->min_uV;39	int vsram_max_uV = mrc->vsram_rdev->constraints->max_uV;40	int vsram_target_min_uV, vsram_target_max_uV;41	int min_uV = 0;42	int max_uV = INT_MAX;43	int ret;44 45	/*46	 * If the target device is on, setting the SRAM voltage directly47	 * is not supported as it scales through its coupled supply voltage.48	 *49	 * An exception is made in case the use_count is zero: this means50	 * that this is the first time we power up the SRAM regulator, which51	 * implies that the target device has yet to perform initialization52	 * and setting a voltage at that time is harmless.53	 */54	if (rdev == mrc->vsram_rdev) {55		if (rdev->use_count == 0)56			return regulator_do_balance_voltage(rdev, state, true);57 58		return -EPERM;59	}60 61	ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);62	if (ret < 0)63		return ret;64 65	if (min_uV == 0) {66		ret = regulator_get_voltage_rdev(rdev);67		if (ret < 0)68			return ret;69		min_uV = ret;70	}71 72	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);73	if (ret < 0)74		return ret;75 76	/*77	 * If we're asked to set a voltage less than VSRAM min_uV, set78	 * the minimum allowed voltage on VSRAM, as in this case it is79	 * safe to ignore the max_spread parameter.80	 */81	vsram_target_min_uV = max(vsram_min_uV, min_uV + max_spread);82	vsram_target_max_uV = min(vsram_max_uV, vsram_target_min_uV + max_spread);83 84	/* Make sure we're not out of range */85	vsram_target_min_uV = min(vsram_target_min_uV, vsram_max_uV);86 87	pr_debug("Setting voltage %d-%duV on %s (minuV %d)\n",88		 vsram_target_min_uV, vsram_target_max_uV,89		 rdev_get_name(mrc->vsram_rdev), min_uV);90 91	ret = regulator_set_voltage_rdev(mrc->vsram_rdev, vsram_target_min_uV,92					 vsram_target_max_uV, state);93	if (ret)94		return ret;95 96	/* The sram voltage is now balanced: update the target vreg voltage */97	return regulator_do_balance_voltage(rdev, state, true);98}99 100static int mediatek_regulator_attach(struct regulator_coupler *coupler,101				     struct regulator_dev *rdev)102{103	struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);104	const char *rdev_name = rdev_get_name(rdev);105 106	/*107	 * If we're getting a coupling of more than two regulators here and108	 * this means that this is surely not a GPU<->SRAM couple: in that109	 * case, we may want to use another coupler implementation, if any,110	 * or the generic one: the regulator core will keep walking through111	 * the list of couplers when any .attach_regulator() cb returns 1.112	 */113	if (rdev->coupling_desc.n_coupled > 2)114		return 1;115 116	if (strstr(rdev_name, "sram")) {117		if (mrc->vsram_rdev)118			return -EINVAL;119		mrc->vsram_rdev = rdev;120	} else if (!strstr(rdev_name, "vgpu") && !strstr(rdev_name, "Vgpu")) {121		return 1;122	}123 124	return 0;125}126 127static int mediatek_regulator_detach(struct regulator_coupler *coupler,128				     struct regulator_dev *rdev)129{130	struct mediatek_regulator_coupler *mrc = to_mediatek_coupler(coupler);131 132	if (rdev == mrc->vsram_rdev)133		mrc->vsram_rdev = NULL;134 135	return 0;136}137 138static struct mediatek_regulator_coupler mediatek_coupler = {139	.coupler = {140		.attach_regulator = mediatek_regulator_attach,141		.detach_regulator = mediatek_regulator_detach,142		.balance_voltage = mediatek_regulator_balance_voltage,143	},144};145 146static int mediatek_regulator_coupler_init(void)147{148	if (!of_machine_is_compatible("mediatek,mt8183") &&149	    !of_machine_is_compatible("mediatek,mt8186") &&150	    !of_machine_is_compatible("mediatek,mt8192"))151		return 0;152 153	return regulator_coupler_register(&mediatek_coupler.coupler);154}155arch_initcall(mediatek_regulator_coupler_init);156 157MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");158MODULE_DESCRIPTION("MediaTek Regulator Coupler driver");159MODULE_LICENSE("GPL");160