Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: Regulator driver for the Mediatek DVFSRC

Driver for regulators exposed by the DVFSRC (dynamic voltage and
frequency scaling resource collector) found in devices based on
mt8183 and newer platforms.

Signed-off-by: Henry Chen <henryc.chen@mediatek.com>
Link: https://lore.kernel.org/r/1608790134-27425-12-git-send-email-henryc.chen@mediatek.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

henryc.chen and committed by
Mark Brown
a0db6b0a c4208849

+226
+10
drivers/regulator/Kconfig
··· 785 785 This driver supports the control of different power rails of device 786 786 through regulator interface. 787 787 788 + config REGULATOR_MTK_DVFSRC 789 + tristate "MediaTek DVFSRC regulator driver" 790 + depends on MTK_DVFSRC 791 + help 792 + Say y here to control regulator by DVFSRC (dynamic voltage 793 + and frequency scaling resource collector). 794 + This driver supports to control regulators via the DVFSRC 795 + of Mediatek. It allows for voting on regulator state 796 + between multiple users. 797 + 788 798 config REGULATOR_PALMAS 789 799 tristate "TI Palmas PMIC Regulators" 790 800 depends on MFD_PALMAS
+1
drivers/regulator/Makefile
··· 95 95 obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o 96 96 obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o 97 97 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o 98 + obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o 98 99 obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o 99 100 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o 100 101 obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+215
drivers/regulator/mtk-dvfsrc-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Copyright (c) 2020 MediaTek Inc. 4 + 5 + #include <linux/err.h> 6 + #include <linux/init.h> 7 + #include <linux/module.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/of_device.h> 10 + #include <linux/of_platform.h> 11 + #include <linux/regulator/driver.h> 12 + #include <linux/regulator/of_regulator.h> 13 + #include <linux/soc/mediatek/mtk_dvfsrc.h> 14 + 15 + #define DVFSRC_ID_VCORE 0 16 + #define DVFSRC_ID_VSCP 1 17 + 18 + #define MT_DVFSRC_REGULAR(match, _name, _volt_table) \ 19 + [DVFSRC_ID_##_name] = { \ 20 + .desc = { \ 21 + .name = match, \ 22 + .of_match = of_match_ptr(match), \ 23 + .ops = &dvfsrc_vcore_ops, \ 24 + .type = REGULATOR_VOLTAGE, \ 25 + .id = DVFSRC_ID_##_name, \ 26 + .owner = THIS_MODULE, \ 27 + .n_voltages = ARRAY_SIZE(_volt_table), \ 28 + .volt_table = _volt_table, \ 29 + }, \ 30 + } 31 + 32 + /* 33 + * DVFSRC regulators' information 34 + * 35 + * @desc: standard fields of regulator description. 36 + * @voltage_selector: Selector used for get_voltage_sel() and 37 + * set_voltage_sel() callbacks 38 + */ 39 + 40 + struct dvfsrc_regulator { 41 + struct regulator_desc desc; 42 + }; 43 + 44 + /* 45 + * MTK DVFSRC regulators' init data 46 + * 47 + * @size: num of regulators 48 + * @regulator_info: regulator info. 49 + */ 50 + struct dvfsrc_regulator_init_data { 51 + u32 size; 52 + struct dvfsrc_regulator *regulator_info; 53 + }; 54 + 55 + static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev) 56 + { 57 + return rdev_get_dev(rdev)->parent; 58 + } 59 + 60 + static int dvfsrc_set_voltage_sel(struct regulator_dev *rdev, 61 + unsigned int selector) 62 + { 63 + struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); 64 + int id = rdev_get_id(rdev); 65 + 66 + if (id == DVFSRC_ID_VCORE) 67 + mtk_dvfsrc_send_request(dvfsrc_dev, 68 + MTK_DVFSRC_CMD_VCORE_REQUEST, 69 + selector); 70 + else if (id == DVFSRC_ID_VSCP) 71 + mtk_dvfsrc_send_request(dvfsrc_dev, 72 + MTK_DVFSRC_CMD_VSCP_REQUEST, 73 + selector); 74 + else 75 + return -EINVAL; 76 + 77 + return 0; 78 + } 79 + 80 + static int dvfsrc_get_voltage_sel(struct regulator_dev *rdev) 81 + { 82 + struct device *dvfsrc_dev = to_dvfsrc_dev(rdev); 83 + int id = rdev_get_id(rdev); 84 + int val, ret; 85 + 86 + if (id == DVFSRC_ID_VCORE) 87 + ret = mtk_dvfsrc_query_info(dvfsrc_dev, 88 + MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY, 89 + &val); 90 + else if (id == DVFSRC_ID_VSCP) 91 + ret = mtk_dvfsrc_query_info(dvfsrc_dev, 92 + MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY, 93 + &val); 94 + else 95 + return -EINVAL; 96 + 97 + if (ret != 0) 98 + return ret; 99 + 100 + return val; 101 + } 102 + 103 + static const struct regulator_ops dvfsrc_vcore_ops = { 104 + .list_voltage = regulator_list_voltage_table, 105 + .get_voltage_sel = dvfsrc_get_voltage_sel, 106 + .set_voltage_sel = dvfsrc_set_voltage_sel, 107 + }; 108 + 109 + static const unsigned int mt8183_voltages[] = { 110 + 725000, 111 + 800000, 112 + }; 113 + 114 + static struct dvfsrc_regulator mt8183_regulators[] = { 115 + MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE, 116 + mt8183_voltages), 117 + }; 118 + 119 + static const struct dvfsrc_regulator_init_data regulator_mt8183_data = { 120 + .size = ARRAY_SIZE(mt8183_regulators), 121 + .regulator_info = &mt8183_regulators[0], 122 + }; 123 + 124 + static const unsigned int mt6873_voltages[] = { 125 + 575000, 126 + 600000, 127 + 650000, 128 + 725000, 129 + }; 130 + 131 + static struct dvfsrc_regulator mt6873_regulators[] = { 132 + MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE, 133 + mt6873_voltages), 134 + MT_DVFSRC_REGULAR("dvfsrc-vscp", VSCP, 135 + mt6873_voltages), 136 + }; 137 + 138 + static const struct dvfsrc_regulator_init_data regulator_mt6873_data = { 139 + .size = ARRAY_SIZE(mt6873_regulators), 140 + .regulator_info = &mt6873_regulators[0], 141 + }; 142 + 143 + static const struct of_device_id mtk_dvfsrc_regulator_match[] = { 144 + { 145 + .compatible = "mediatek,mt8183-dvfsrc", 146 + .data = &regulator_mt8183_data, 147 + }, { 148 + .compatible = "mediatek,mt8192-dvfsrc", 149 + .data = &regulator_mt6873_data, 150 + }, { 151 + .compatible = "mediatek,mt6873-dvfsrc", 152 + .data = &regulator_mt6873_data, 153 + }, { 154 + /* sentinel */ 155 + }, 156 + }; 157 + MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); 158 + 159 + static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev) 160 + { 161 + const struct of_device_id *match; 162 + struct device *dev = &pdev->dev; 163 + struct regulator_config config = { }; 164 + struct regulator_dev *rdev; 165 + const struct dvfsrc_regulator_init_data *regulator_init_data; 166 + struct dvfsrc_regulator *mt_regulators; 167 + int i; 168 + 169 + match = of_match_node(mtk_dvfsrc_regulator_match, dev->parent->of_node); 170 + 171 + if (!match) { 172 + dev_err(dev, "invalid compatible string\n"); 173 + return -ENODEV; 174 + } 175 + 176 + regulator_init_data = match->data; 177 + 178 + mt_regulators = regulator_init_data->regulator_info; 179 + for (i = 0; i < regulator_init_data->size; i++) { 180 + config.dev = dev->parent; 181 + config.driver_data = (mt_regulators + i); 182 + rdev = devm_regulator_register(dev->parent, 183 + &(mt_regulators + i)->desc, 184 + &config); 185 + if (IS_ERR(rdev)) { 186 + dev_err(dev, "failed to register %s\n", 187 + (mt_regulators + i)->desc.name); 188 + return PTR_ERR(rdev); 189 + } 190 + } 191 + 192 + return 0; 193 + } 194 + 195 + static struct platform_driver mtk_dvfsrc_regulator_driver = { 196 + .driver = { 197 + .name = "mtk-dvfsrc-regulator", 198 + }, 199 + .probe = dvfsrc_vcore_regulator_probe, 200 + }; 201 + 202 + static int __init mtk_dvfsrc_regulator_init(void) 203 + { 204 + return platform_driver_register(&mtk_dvfsrc_regulator_driver); 205 + } 206 + subsys_initcall(mtk_dvfsrc_regulator_init); 207 + 208 + static void __exit mtk_dvfsrc_regulator_exit(void) 209 + { 210 + platform_driver_unregister(&mtk_dvfsrc_regulator_driver); 211 + } 212 + module_exit(mtk_dvfsrc_regulator_exit); 213 + 214 + MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>"); 215 + MODULE_LICENSE("GPL v2");