soc: renesas: ARCH_R9A07G043 depends on !RISCV_ISA_ZICBOM
[platform/kernel/linux-starfive.git] / drivers / soc / mediatek / mtk-regulator-coupler.c
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");