1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Voltage regulators coupler for MediaTek SoCs 4 * 5 * Copyright (C) 2022 Collabora, Ltd. 6 * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 7 */ 8 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 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 21 struct 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 and 28 * modify the vsram voltage only when changing voltage of vgpu. 29 * 30 * This function is limited to the GPU<->SRAM voltages relationships. 31 */ 32 static 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 directly 47 * 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 means 50 * that this is the first time we power up the SRAM regulator, which 51 * implies that the target device has yet to perform initialization 52 * 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, set 78 * the minimum allowed voltage on VSRAM, as in this case it is 79 * 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 100 static 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 and 108 * this means that this is surely not a GPU<->SRAM couple: in that 109 * case, we may want to use another coupler implementation, if any, 110 * or the generic one: the regulator core will keep walking through 111 * 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 127 static 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 138 static 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 146 static 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 } 155 arch_initcall(mediatek_regulator_coupler_init); 156 157 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); 158 MODULE_DESCRIPTION("MediaTek Regulator Coupler driver"); 159 MODULE_LICENSE("GPL"); 160