0001
0002
0003
0004
0005 #include <linux/err.h>
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/platform_device.h>
0009 #include <linux/of_device.h>
0010 #include <linux/of_platform.h>
0011 #include <linux/regulator/driver.h>
0012 #include <linux/regulator/of_regulator.h>
0013 #include <linux/soc/mediatek/mtk_dvfsrc.h>
0014
0015 #define DVFSRC_ID_VCORE 0
0016 #define DVFSRC_ID_VSCP 1
0017
0018 #define MT_DVFSRC_REGULAR(match, _name, _volt_table) \
0019 [DVFSRC_ID_##_name] = { \
0020 .desc = { \
0021 .name = match, \
0022 .of_match = of_match_ptr(match), \
0023 .ops = &dvfsrc_vcore_ops, \
0024 .type = REGULATOR_VOLTAGE, \
0025 .id = DVFSRC_ID_##_name, \
0026 .owner = THIS_MODULE, \
0027 .n_voltages = ARRAY_SIZE(_volt_table), \
0028 .volt_table = _volt_table, \
0029 }, \
0030 }
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 struct dvfsrc_regulator {
0041 struct regulator_desc desc;
0042 };
0043
0044
0045
0046
0047
0048
0049
0050 struct dvfsrc_regulator_init_data {
0051 u32 size;
0052 struct dvfsrc_regulator *regulator_info;
0053 };
0054
0055 static inline struct device *to_dvfsrc_dev(struct regulator_dev *rdev)
0056 {
0057 return rdev_get_dev(rdev)->parent;
0058 }
0059
0060 static int dvfsrc_set_voltage_sel(struct regulator_dev *rdev,
0061 unsigned int selector)
0062 {
0063 struct device *dvfsrc_dev = to_dvfsrc_dev(rdev);
0064 int id = rdev_get_id(rdev);
0065
0066 if (id == DVFSRC_ID_VCORE)
0067 mtk_dvfsrc_send_request(dvfsrc_dev,
0068 MTK_DVFSRC_CMD_VCORE_REQUEST,
0069 selector);
0070 else if (id == DVFSRC_ID_VSCP)
0071 mtk_dvfsrc_send_request(dvfsrc_dev,
0072 MTK_DVFSRC_CMD_VSCP_REQUEST,
0073 selector);
0074 else
0075 return -EINVAL;
0076
0077 return 0;
0078 }
0079
0080 static int dvfsrc_get_voltage_sel(struct regulator_dev *rdev)
0081 {
0082 struct device *dvfsrc_dev = to_dvfsrc_dev(rdev);
0083 int id = rdev_get_id(rdev);
0084 int val, ret;
0085
0086 if (id == DVFSRC_ID_VCORE)
0087 ret = mtk_dvfsrc_query_info(dvfsrc_dev,
0088 MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY,
0089 &val);
0090 else if (id == DVFSRC_ID_VSCP)
0091 ret = mtk_dvfsrc_query_info(dvfsrc_dev,
0092 MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY,
0093 &val);
0094 else
0095 return -EINVAL;
0096
0097 if (ret != 0)
0098 return ret;
0099
0100 return val;
0101 }
0102
0103 static const struct regulator_ops dvfsrc_vcore_ops = {
0104 .list_voltage = regulator_list_voltage_table,
0105 .get_voltage_sel = dvfsrc_get_voltage_sel,
0106 .set_voltage_sel = dvfsrc_set_voltage_sel,
0107 };
0108
0109 static const unsigned int mt8183_voltages[] = {
0110 725000,
0111 800000,
0112 };
0113
0114 static struct dvfsrc_regulator mt8183_regulators[] = {
0115 MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE,
0116 mt8183_voltages),
0117 };
0118
0119 static const struct dvfsrc_regulator_init_data regulator_mt8183_data = {
0120 .size = ARRAY_SIZE(mt8183_regulators),
0121 .regulator_info = &mt8183_regulators[0],
0122 };
0123
0124 static const unsigned int mt6873_voltages[] = {
0125 575000,
0126 600000,
0127 650000,
0128 725000,
0129 };
0130
0131 static struct dvfsrc_regulator mt6873_regulators[] = {
0132 MT_DVFSRC_REGULAR("dvfsrc-vcore", VCORE,
0133 mt6873_voltages),
0134 MT_DVFSRC_REGULAR("dvfsrc-vscp", VSCP,
0135 mt6873_voltages),
0136 };
0137
0138 static const struct dvfsrc_regulator_init_data regulator_mt6873_data = {
0139 .size = ARRAY_SIZE(mt6873_regulators),
0140 .regulator_info = &mt6873_regulators[0],
0141 };
0142
0143 static const struct of_device_id mtk_dvfsrc_regulator_match[] = {
0144 {
0145 .compatible = "mediatek,mt8183-dvfsrc",
0146 .data = ®ulator_mt8183_data,
0147 }, {
0148 .compatible = "mediatek,mt8192-dvfsrc",
0149 .data = ®ulator_mt6873_data,
0150 }, {
0151 .compatible = "mediatek,mt6873-dvfsrc",
0152 .data = ®ulator_mt6873_data,
0153 }, {
0154
0155 },
0156 };
0157 MODULE_DEVICE_TABLE(of, mtk_dvfsrc_regulator_match);
0158
0159 static int dvfsrc_vcore_regulator_probe(struct platform_device *pdev)
0160 {
0161 const struct of_device_id *match;
0162 struct device *dev = &pdev->dev;
0163 struct regulator_config config = { };
0164 struct regulator_dev *rdev;
0165 const struct dvfsrc_regulator_init_data *regulator_init_data;
0166 struct dvfsrc_regulator *mt_regulators;
0167 int i;
0168
0169 match = of_match_node(mtk_dvfsrc_regulator_match, dev->parent->of_node);
0170
0171 if (!match) {
0172 dev_err(dev, "invalid compatible string\n");
0173 return -ENODEV;
0174 }
0175
0176 regulator_init_data = match->data;
0177
0178 mt_regulators = regulator_init_data->regulator_info;
0179 for (i = 0; i < regulator_init_data->size; i++) {
0180 config.dev = dev->parent;
0181 config.driver_data = (mt_regulators + i);
0182 rdev = devm_regulator_register(dev, &(mt_regulators + i)->desc,
0183 &config);
0184 if (IS_ERR(rdev)) {
0185 dev_err(dev, "failed to register %s\n",
0186 (mt_regulators + i)->desc.name);
0187 return PTR_ERR(rdev);
0188 }
0189 }
0190
0191 return 0;
0192 }
0193
0194 static struct platform_driver mtk_dvfsrc_regulator_driver = {
0195 .driver = {
0196 .name = "mtk-dvfsrc-regulator",
0197 },
0198 .probe = dvfsrc_vcore_regulator_probe,
0199 };
0200
0201 static int __init mtk_dvfsrc_regulator_init(void)
0202 {
0203 return platform_driver_register(&mtk_dvfsrc_regulator_driver);
0204 }
0205 subsys_initcall(mtk_dvfsrc_regulator_init);
0206
0207 static void __exit mtk_dvfsrc_regulator_exit(void)
0208 {
0209 platform_driver_unregister(&mtk_dvfsrc_regulator_driver);
0210 }
0211 module_exit(mtk_dvfsrc_regulator_exit);
0212
0213 MODULE_AUTHOR("Arvin wang <arvin.wang@mediatek.com>");
0214 MODULE_LICENSE("GPL v2");