1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 MediaTek Inc. 4 * Copyright (c) 2024 Collabora Ltd. 5 * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> 6 */ 7 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/of.h> 11 #include <linux/regulator/driver.h> 12 #include <linux/regulator/of_regulator.h> 13 #include <linux/soc/mediatek/dvfsrc.h> 14 15 enum dvfsrc_regulator_id { 16 DVFSRC_ID_VCORE, 17 DVFSRC_ID_VSCP, 18 DVFSRC_ID_MAX 19 }; 20 21 struct dvfsrc_regulator_pdata { 22 const struct regulator_desc *descs; 23 u32 size; 24 }; 25 26 #define MTK_DVFSRC_VREG(match, _name, _volt_table) \ 27 { \ 28 .name = match, \ 29 .of_match = match, \ 30 .ops = &dvfsrc_vcore_ops, \ 31 .type = REGULATOR_VOLTAGE, \ 32 .id = DVFSRC_ID_##_name, \ 33 .owner = THIS_MODULE, \ 34 .n_voltages = ARRAY_SIZE(_volt_table), \ 35 .volt_table = _volt_table, \ 36 } 37 38 static inline struct device *to_dvfs_regulator_dev(struct regulator_dev *rdev) 39 { 40 return rdev_get_dev(rdev)->parent; 41 } 42 43 static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev) 44 { 45 return to_dvfs_regulator_dev(rdev)->parent; 46 } 47 48 static int dvfsrc_get_cmd(int rdev_id, enum mtk_dvfsrc_cmd *cmd) 49 { 50 switch (rdev_id) { 51 case DVFSRC_ID_VCORE: 52 *cmd = MTK_DVFSRC_CMD_VCORE_LEVEL; 53 break; 54 case DVFSRC_ID_VSCP: 55 *cmd = MTK_DVFSRC_CMD_VSCP_LEVEL; 56 break; 57 default: 58 return -EINVAL; 59 } 60 61 return 0; 62 } 63 64 static int dvfsrc_set_voltage_sel(struct regulator_dev *rdev, 65 unsigned int selector) 66 { 67 struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); 68 enum mtk_dvfsrc_cmd req_cmd; 69 int id = rdev_get_id(rdev); 70 int ret; 71 72 ret = dvfsrc_get_cmd(id, &req_cmd); 73 if (ret) 74 return ret; 75 76 return mtk_dvfsrc_send_request(dvfsrc_dev, req_cmd, selector); 77 } 78 79 static int dvfsrc_get_voltage_sel(struct regulator_dev *rdev) 80 { 81 struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); 82 enum mtk_dvfsrc_cmd query_cmd; 83 int id = rdev_get_id(rdev); 84 int val, ret; 85 86 ret = dvfsrc_get_cmd(id, &query_cmd); 87 if (ret) 88 return ret; 89 90 ret = mtk_dvfsrc_query_info(dvfsrc_dev, query_cmd, &val); 91 if (ret) 92 return ret; 93 94 return val; 95 } 96 97 static const struct regulator_ops dvfsrc_vcore_ops = { 98 .list_voltage = regulator_list_voltage_table, 99 .get_voltage_sel = dvfsrc_get_voltage_sel, 100 .set_voltage_sel = dvfsrc_set_voltage_sel, 101 }; 102 103 static const unsigned int mt6873_voltages[] = { 104 575000, 105 600000, 106 650000, 107 725000, 108 }; 109 110 static const struct regulator_desc mt6873_regulators[] = { 111 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt6873_voltages), 112 MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt6873_voltages), 113 }; 114 115 static const struct dvfsrc_regulator_pdata mt6873_data = { 116 .descs = mt6873_regulators, 117 .size = ARRAY_SIZE(mt6873_regulators), 118 }; 119 120 static const unsigned int mt6893_voltages[] = { 121 575000, 122 600000, 123 650000, 124 725000, 125 750000, 126 }; 127 128 static const struct regulator_desc mt6893_regulators[] = { 129 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt6893_voltages), 130 MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt6893_voltages), 131 }; 132 133 static const struct dvfsrc_regulator_pdata mt6893_data = { 134 .descs = mt6893_regulators, 135 .size = ARRAY_SIZE(mt6893_regulators), 136 }; 137 138 static const unsigned int mt8183_voltages[] = { 139 725000, 140 800000, 141 }; 142 143 static const struct regulator_desc mt8183_regulators[] = { 144 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8183_voltages), 145 }; 146 147 static const struct dvfsrc_regulator_pdata mt8183_data = { 148 .descs = mt8183_regulators, 149 .size = ARRAY_SIZE(mt8183_regulators), 150 }; 151 152 static const unsigned int mt8195_voltages[] = { 153 550000, 154 600000, 155 650000, 156 750000, 157 }; 158 159 static const struct regulator_desc mt8195_regulators[] = { 160 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8195_voltages), 161 MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt8195_voltages), 162 }; 163 164 static const struct dvfsrc_regulator_pdata mt8195_data = { 165 .descs = mt8195_regulators, 166 .size = ARRAY_SIZE(mt8195_regulators), 167 }; 168 169 static const unsigned int mt8196_voltages[] = { 170 575000, 171 600000, 172 650000, 173 725000, 174 825000, 175 875000, 176 }; 177 178 static const struct regulator_desc mt8196_regulators[] = { 179 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8196_voltages), 180 }; 181 182 static const struct dvfsrc_regulator_pdata mt8196_data = { 183 .descs = mt8196_regulators, 184 .size = ARRAY_SIZE(mt8196_regulators), 185 }; 186 187 static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev) 188 { 189 struct regulator_config config = { .dev = &pdev->dev }; 190 const struct dvfsrc_regulator_pdata *pdata; 191 int i; 192 193 pdata = device_get_match_data(&pdev->dev); 194 if (!pdata) 195 return -EINVAL; 196 197 for (i = 0; i < pdata->size; i++) { 198 const struct regulator_desc *vrdesc = &pdata->descs[i]; 199 struct regulator_dev *rdev; 200 201 rdev = devm_regulator_register(&pdev->dev, vrdesc, &config); 202 if (IS_ERR(rdev)) 203 return dev_err_probe(&pdev->dev, PTR_ERR(rdev), 204 "failed to register %s\n", vrdesc->name); 205 } 206 207 return 0; 208 } 209 210 static const struct of_device_id mtk_dvfsrc_regulator_match[] = { 211 { .compatible = "mediatek,mt6873-dvfsrc-regulator", .data = &mt6873_data }, 212 { .compatible = "mediatek,mt6893-dvfsrc-regulator", .data = &mt6893_data }, 213 { .compatible = "mediatek,mt8183-dvfsrc-regulator", .data = &mt8183_data }, 214 { .compatible = "mediatek,mt8192-dvfsrc-regulator", .data = &mt6873_data }, 215 { .compatible = "mediatek,mt8195-dvfsrc-regulator", .data = &mt8195_data }, 216 { .compatible = "mediatek,mt8196-dvfsrc-regulator", .data = &mt8196_data }, 217 { /* sentinel */ } 218 }; 219 MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); 220 221 static struct platform_driver mtk_dvfsrc_regulator_driver = { 222 .driver = { 223 .name = "mtk-dvfsrc-regulator", 224 .of_match_table = mtk_dvfsrc_regulator_match, 225 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 226 }, 227 .probe = dvfsrc_vcore_regulator_probe, 228 }; 229 module_platform_driver(mtk_dvfsrc_regulator_driver); 230 231 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); 232 MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>"); 233 MODULE_DESCRIPTION("MediaTek DVFS Resource Collector Regulator driver"); 234 MODULE_LICENSE("GPL"); 235