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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.15 196 lines 5.0 kB view raw
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 15enum dvfsrc_regulator_id { 16 DVFSRC_ID_VCORE, 17 DVFSRC_ID_VSCP, 18 DVFSRC_ID_MAX 19}; 20 21struct 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 38static inline struct device *to_dvfs_regulator_dev(struct regulator_dev *rdev) 39{ 40 return rdev_get_dev(rdev)->parent; 41} 42 43static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev) 44{ 45 return to_dvfs_regulator_dev(rdev)->parent; 46} 47 48static 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 64static 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 79static 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 97static 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 103static const unsigned int mt6873_voltages[] = { 104 575000, 105 600000, 106 650000, 107 725000, 108}; 109 110static 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 115static const struct dvfsrc_regulator_pdata mt6873_data = { 116 .descs = mt6873_regulators, 117 .size = ARRAY_SIZE(mt6873_regulators), 118}; 119 120static const unsigned int mt8183_voltages[] = { 121 725000, 122 800000, 123}; 124 125static const struct regulator_desc mt8183_regulators[] = { 126 MTK_DVFSRC_VREG("dvfsrc-vcore", VCORE, mt8183_voltages), 127}; 128 129static const struct dvfsrc_regulator_pdata mt8183_data = { 130 .descs = mt8183_regulators, 131 .size = ARRAY_SIZE(mt8183_regulators), 132}; 133 134static const unsigned int mt8195_voltages[] = { 135 550000, 136 600000, 137 650000, 138 750000, 139}; 140 141static 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 146static const struct dvfsrc_regulator_pdata mt8195_data = { 147 .descs = mt8195_regulators, 148 .size = ARRAY_SIZE(mt8195_regulators), 149}; 150 151static 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 174static 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}; 181MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match); 182 183static 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}; 191module_platform_driver(mtk_dvfsrc_regulator_driver); 192 193MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>"); 194MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>"); 195MODULE_DESCRIPTION("MediaTek DVFS Resource Collector Regulator driver"); 196MODULE_LICENSE("GPL");