1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include <linux/err.h>
10 #include <linux/kernel.h>
11 #include <linux/device.h>
12 #include <linux/delay.h>
13 #include <linux/platform_device.h>
14 #include <linux/regulator/driver.h>
15 #include <linux/regulator/machine.h>
16 #include <linux/regmap.h>
17 #include <linux/sysfs.h>
18 #include "hdf_log.h"
19 #include "hdf_base.h"
20 
21 #define HDF_LOG_TAG regulator_virtual_current
22 
23 #define MINIMUN_CURRENT            1000
24 #define MAXIMUN_CURRENT            50000
25 
26 struct VirtualCurrentRegulatorDev {
27     struct regmap *regmap;
28     struct regulator_dev *dev;
29 };
30 
31 // note:linux kernel constraints:len(devName) + len(supplyName) < REG_STR_SIZE(64)
32 static struct regulator_consumer_supply g_virtualCurrentRegulatorSupplies[] = {
33     REGULATOR_SUPPLY("vir-current-reg-hdf-adp", "regulator_adapter_consumer01"),
34 };
35 
36 // virtual regulator init info
37 static struct regulator_init_data g_virtualCurrentRegulatorInitData = {
38     .constraints = {
39         .name = "virtual_current_regulator",
40         .min_uA = MINIMUN_CURRENT,
41         .max_uA = MAXIMUN_CURRENT,
42         .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS,
43     },
44     .num_consumer_supplies = ARRAY_SIZE(g_virtualCurrentRegulatorSupplies),
45     .consumer_supplies = g_virtualCurrentRegulatorSupplies,
46 };
47 
VirtualCurrentRegulatorDevRelease(struct device * dev)48 static void VirtualCurrentRegulatorDevRelease(struct device *dev)
49 {
50     (void)dev;
51 }
52 
53 static struct platform_device g_virtualCurrentRegulatorPlatformDevice = {
54     .name = "virtual_current_regulator_dev",
55     .id = -1,
56     .dev = {
57         .release = VirtualCurrentRegulatorDevRelease,
58     }
59 };
60 
61 enum RegulatorStatus {
62     VIR_REGULATOR_STATUS_OFF,
63     VIR_REGULATOR_STATUS_ON,
64 };
65 
66 static int g_virStatus = VIR_REGULATOR_STATUS_OFF;
VirtualCurrentRegulatorEnable(struct regulator_dev * rdev)67 static int VirtualCurrentRegulatorEnable(struct regulator_dev *rdev)
68 {
69     if (rdev == NULL) {
70         HDF_LOGE("VirtualCurrentRegulatorEnable: rdev is null!");
71         return HDF_FAILURE;
72     }
73 
74     g_virStatus = VIR_REGULATOR_STATUS_ON;
75     return HDF_SUCCESS;
76 }
77 
VirtualCurrentRegulatorDisable(struct regulator_dev * rdev)78 static int VirtualCurrentRegulatorDisable(struct regulator_dev *rdev)
79 {
80     if (rdev == NULL) {
81         HDF_LOGE("VirtualCurrentRegulatorDisable: rdev is null!");
82         return HDF_FAILURE;
83     }
84 
85     g_virStatus = VIR_REGULATOR_STATUS_OFF;
86     return HDF_SUCCESS;
87 }
88 
VirtualCurrentRegulatorIsEnabled(struct regulator_dev * rdev)89 static int VirtualCurrentRegulatorIsEnabled(struct regulator_dev *rdev)
90 {
91     if (rdev == NULL) {
92         HDF_LOGE("VirtualCurrentRegulatorIsEnabled: rdev is null!");
93         return HDF_FAILURE;
94     }
95 
96     return g_virStatus;
97 }
98 
VirtualCurrentRegulatorSetCurrent(struct regulator_dev * rdev,int minUa,int maxUa)99 static int VirtualCurrentRegulatorSetCurrent(struct regulator_dev *rdev, int minUa,
100     int maxUa)
101 {
102     if ((rdev == NULL) || (rdev->constraints == NULL)) {
103         HDF_LOGE("VirtualCurrentRegulatorSetCurrent: rdev or constraints is null!");
104         return HDF_FAILURE;
105     }
106 
107     struct regulation_constraints *regu_constraints = rdev->constraints;
108     if (regu_constraints->min_uA == minUa &&
109         regu_constraints->max_uA == maxUa) {
110         return HDF_SUCCESS;
111     }
112 
113     return HDF_SUCCESS;
114 }
115 
116 #define VIRTUAL_CURRENT_VAL_500 500
VirtualCurrentRegulatorGetCurrent(struct regulator_dev * rdev)117 static int VirtualCurrentRegulatorGetCurrent(struct regulator_dev *rdev)
118 {
119     if (rdev == NULL) {
120         HDF_LOGE("VirtualCurrentRegulatorGetCurrent: rdev is null!");
121         return HDF_FAILURE;
122     }
123 
124     return VIRTUAL_CURRENT_VAL_500;
125 }
126 
127 static struct regulator_ops g_virtualCurrentRegulatorOps = {
128     .enable = VirtualCurrentRegulatorEnable,
129     .disable = VirtualCurrentRegulatorDisable,
130     .is_enabled = VirtualCurrentRegulatorIsEnabled,
131     .set_current_limit = VirtualCurrentRegulatorSetCurrent,
132     .get_current_limit = VirtualCurrentRegulatorGetCurrent,
133 };
134 
135 static struct regulator_desc g_virtualCurrentRegulatorDesc = {
136     .name = "regulator_virtual_current",
137     .type = REGULATOR_CURRENT,
138     .ops = &g_virtualCurrentRegulatorOps,
139     .owner = THIS_MODULE,
140 };
141 
VirtualCurrentRegulatorPlatformProbe(struct platform_device * platformDev)142 static int VirtualCurrentRegulatorPlatformProbe(struct platform_device *platformDev)
143 {
144     if (platformDev == NULL) {
145         HDF_LOGE("VirtualCurrentRegulatorPlatformProbe: platformDev is null!");
146         return HDF_FAILURE;
147     }
148     struct VirtualCurrentRegulatorDev *data;
149     struct regulator_config config = {0};
150 
151     data = devm_kzalloc(&platformDev->dev, sizeof(*data), GFP_KERNEL);
152     if (!data) {
153         HDF_LOGE("VirtualCurrentRegulatorPlatformProbe: devm_kzalloc error!");
154         return -ENOMEM;
155     }
156     config.dev = &platformDev->dev;
157     config.init_data = &g_virtualCurrentRegulatorInitData;
158     config.driver_data = data;
159 
160     data->dev = regulator_register(&g_virtualCurrentRegulatorDesc, &config);
161     if (IS_ERR(data->dev)) {
162         HDF_LOGE("VirtualCurrentRegulatorPlatformProbe: fail to register regulator %s\n",
163             g_virtualCurrentRegulatorDesc.name);
164         return PTR_ERR(data->dev);
165     }
166 
167     platform_set_drvdata(platformDev, data);
168     HDF_LOGI("VirtualCurrentRegulatorPlatformProbe: success!");
169     return 0;
170 }
171 
VirtualCurrentRegulatorPlatformRemove(struct platform_device * platformDev)172 static int VirtualCurrentRegulatorPlatformRemove(struct platform_device *platformDev)
173 {
174     struct VirtualCurrentRegulatorDev *rdev = platform_get_drvdata(platformDev);
175 
176     regulator_unregister(rdev->dev);
177 
178     platform_set_drvdata(platformDev, NULL);
179     HDF_LOGI("VirtualCurrentRegulatorPlatformRemove: success!");
180     return 0;
181 }
182 
183 static struct platform_driver g_virtualCurrentRegulatorPlatformDriver = {
184     .driver = {
185         .name = "virtual_current_regulator_dev",
186         .owner = THIS_MODULE,
187     },
188     .probe = VirtualCurrentRegulatorPlatformProbe,
189     .remove = VirtualCurrentRegulatorPlatformRemove,
190 };
191 
VirtualCurrentRegulatorAdapterInit(void)192 int VirtualCurrentRegulatorAdapterInit(void)
193 {
194     int ret = platform_device_register(&g_virtualCurrentRegulatorPlatformDevice);
195     if (ret == 0) {
196         ret = platform_driver_register(&g_virtualCurrentRegulatorPlatformDriver);
197     } else {
198         HDF_LOGE("VirtualCurrentRegulatorAdapterInit:device register fail, ret: %d!", ret);
199     }
200     return ret;
201 }
202 
VirtualCurrentRegulatorInit(void)203 static int __init VirtualCurrentRegulatorInit(void)
204 {
205     int ret = platform_device_register(&g_virtualCurrentRegulatorPlatformDevice);
206     if (ret == 0) {
207         ret = platform_driver_register(&g_virtualCurrentRegulatorPlatformDriver);
208     }
209     return ret;
210 }
211 
VirtualCurrentRegulatorExit(void)212 static void __exit VirtualCurrentRegulatorExit(void)
213 {
214     platform_device_unregister(&g_virtualCurrentRegulatorPlatformDevice);
215     platform_driver_unregister(&g_virtualCurrentRegulatorPlatformDriver);
216 }
217 
218 MODULE_DESCRIPTION("Virtual current Regulator Controller Platform Device Drivers");
219 MODULE_LICENSE("GPL");
220