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 mt8183_voltages[] = { 121 725000, 122 800000, 123 }; 124 125 static const struct regulator_desc mt8183_regulators[] = { 126 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8183_voltages), 127 }; 128 129 static const struct dvfsrc_regulator_pdata mt8183_data = { 130 .descs = mt8183_regulators, 131 .size = ARRAY_SIZE(mt8183_regulators), 132 }; 133 134 static const unsigned int mt8195_voltages[] = { 135 550000, 136 600000, 137 650000, 138 750000, 139 }; 140 141 static const struct regulator_desc mt8195_regulators[] = { 142 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8195_voltages), 143 MTK_DVFSRC_VREG("dvfsrc-vscp", VSCP, mt8195_voltages), 144 }; 145 146 static const struct dvfsrc_regulator_pdata mt8195_data = { 147 .descs = mt8195_regulators, 148 .size = ARRAY_SIZE(mt8195_regulators), 149 }; 150 151 static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev) 152 { 153 struct regulator_config config = { .dev = &pdev->dev }; 154 const struct dvfsrc_regulator_pdata *pdata; 155 int i; 156 157 pdata = device_get_match_data(&pdev->dev); 158 if (!pdata) 159 return -EINVAL; 160 161 for (i = 0; i < pdata->size; i++) { 162 const struct regulator_desc *vrdesc = &pdata->descs[i]; 163 struct regulator_dev *rdev; 164 165 rdev = devm_regulator_register(&pdev->dev, vrdesc, &config); 166 if (IS_ERR(rdev)) 167 return dev_err_probe(&pdev->dev, PTR_ERR(rdev), 168 "failed to register %s\n", vrdesc->name); 169 } 170 171 return 0; 172 } 173 174 static const struct of_device_id mtk_dvfsrc_regulator_match[] = { 175 { .compatible = "mediatek,mt6873-dvfsrc-regulator", .data = &mt6873_data }, 176 { .compatible = "mediatek,mt8183-dvfsrc-regulator", .data = &mt8183_data }, 177 { .compatible = "mediatek,mt8192-dvfsrc-regulator", .data = &mt6873_data }, 178 { .compatible = "mediatek,mt8195-dvfsrc-regulator", .data = &mt8195_data }, 179 { /* sentinel */ } 180 }; 181 MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); 182 183 static struct platform_driver mtk_dvfsrc_regulator_driver = { 184 .driver = { 185 .name = "mtk-dvfsrc-regulator", 186 .of_match_table = mtk_dvfsrc_regulator_match, 187 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 188 }, 189 .probe = dvfsrc_vcore_regulator_probe, 190 }; 191 module_platform_driver(mtk_dvfsrc_regulator_driver); 192 193 MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); 194 MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>"); 195 MODULE_DESCRIPTION("MediaTek DVFS Resource Collector Regulator driver"); 196 MODULE_LICENSE("GPL"); 197