1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pwm_hi35xx.h"
17 #include "device_resource_if.h"
18 #include "hdf_log.h"
19 #include "osal_io.h"
20 #include "osal_mem.h"
21 #include "platform_dumper.h"
22 #include "pwm_core.h"
23
24 #define HDF_LOG_TAG pwm_hi35xx
25
26 struct HiPwm {
27 struct PwmDev dev;
28 volatile unsigned char *base;
29 struct HiPwmRegs *reg;
30 struct PlatformDumper *dumper;
31 char *dumperName;
32 bool supportPolarity;
33 };
34
PwmDumperCreate(struct HiPwm * hp)35 static int32_t PwmDumperCreate(struct HiPwm *hp)
36 {
37 struct PlatformDumper *dumper = NULL;
38 char *name = (char *)OsalMemCalloc(PWM_DUMPER_NAME_LEN);
39
40 if (snprintf_s(name, PWM_DUMPER_NAME_LEN, PWM_DUMPER_NAME_LEN - 1, "%s%u",
41 PWM_DUMPER_NAME_PREFIX, hp->dev.num) < 0) {
42 HDF_LOGE("%s: snprintf_s name fail!", __func__);
43 OsalMemFree(name);
44 return HDF_ERR_IO;
45 }
46 dumper = PlatformDumperCreate(name);
47 if (dumper == NULL) {
48 HDF_LOGE("%s: get dumper for %s fail!", __func__, name);
49 OsalMemFree(name);
50 return HDF_ERR_IO;
51 }
52 hp->dumper = dumper;
53 hp->dumperName = name;
54
55 return HDF_SUCCESS;
56 }
57
PwmDumperDump(struct HiPwm * hp)58 static void PwmDumperDump(struct HiPwm *hp)
59 {
60 int32_t ret;
61 struct PlatformDumperData datas[] = {
62 {"PWM_CFG0", PLATFORM_DUMPER_REGISTERL, (void *)hp->base},
63 {"PWM_CFG1", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base+ PWM_CFG1_SHIFT)},
64 {"PWM_CFG2", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_CFG2_SHIFT)},
65 {"PWM_CTRL", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_CTRL_SHIFT)},
66 {"PWM_STATE0", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE0_SHIFT)},
67 {"PWM_STATE1", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE1_SHIFT)},
68 {"PWM_STATE2", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE2_SHIFT)},
69 };
70 if (hp->dumper == NULL) {
71 HDF_LOGE("%s: pwm dumper is NULL", __func__);
72 return;
73 }
74 ret = PlatformDumperAddDatas(hp->dumper, datas, sizeof(datas) / sizeof(struct PlatformDumperData));
75 if (ret != HDF_SUCCESS) {
76 return;
77 }
78 (void)PlatformDumperDump(hp->dumper);
79 (void)PlatformDumperClearDatas(hp->dumper);
80 }
81
PwmDumperDestroy(struct HiPwm * hp)82 static inline void PwmDumperDestroy(struct HiPwm *hp)
83 {
84 PlatformDumperDestroy(hp->dumper);
85 OsalMemFree(hp->dumperName);
86 }
87
HiPwmSetConfig(struct PwmDev * pwm,struct PwmConfig * config)88 int32_t HiPwmSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
89 {
90 struct HiPwm *hp = (struct HiPwm *)pwm;
91 if (hp == NULL || hp->reg == NULL || config == NULL) {
92 HDF_LOGE("%s: hp reg or config is null", __func__);
93 return HDF_ERR_INVALID_PARAM;
94 }
95 if (config->polarity != PWM_NORMAL_POLARITY && config->polarity != PWM_INVERTED_POLARITY) {
96 HDF_LOGE("%s: polarity %hhu is invalid", __func__, config->polarity);
97 PwmDumperDump(hp);
98 return HDF_ERR_INVALID_PARAM;
99 }
100 if (config->period < PWM_MIN_PERIOD) {
101 HDF_LOGE("%s: period %u is not support, min period %d", __func__, config->period, PWM_MIN_PERIOD);
102 PwmDumperDump(hp);
103 return HDF_ERR_INVALID_PARAM;
104 }
105 if (config->duty < 1 || config->duty > config->period) {
106 HDF_LOGE("%s: duty %u is not support, duty must in [1, period = %u].",
107 __func__, config->duty, config->period);
108 PwmDumperDump(hp);
109 return HDF_ERR_INVALID_PARAM;
110 }
111 HiPwmDisable(hp->reg);
112 if (pwm->cfg.polarity != config->polarity && hp->supportPolarity) {
113 HiPwmSetPolarity(hp->reg, config->polarity);
114 HDF_LOGI("%s: [HiPwmSetPolarity] done, polarity: %hhu -> %hhu.", __func__, pwm->cfg.polarity, config->polarity);
115 }
116 if (pwm->cfg.period != config->period) {
117 HiPwmSetPeriod(hp->reg, config->period);
118 HDF_LOGI("%s: [HiPwmSetPeriod] done, period: %u -> %u", __func__, pwm->cfg.period, config->period);
119 }
120 if (pwm->cfg.duty != config->duty) {
121 HiPwmSetDuty(hp->reg, config->duty);
122 HDF_LOGI("%s: [HiPwmSetDuty] done, duty: %u -> %u", __func__, pwm->cfg.duty, config->duty);
123 }
124 if (config->status == PWM_ENABLE_STATUS) {
125 if (config->number == 0) {
126 HiPwmAlwaysOutput(hp->reg);
127 HDF_LOGI("%s: [HiPwmAlwaysOutput] done, then enable.", __func__);
128 } else {
129 HiPwmOutputNumberSquareWaves(hp->reg, config->number);
130 HDF_LOGI("%s: [HiPwmOutputNumberSquareWaves] done, then enable.", __func__);
131 }
132 }
133 HDF_LOGI("%s: set PwmConfig done: number %u, period %u, duty %u, polarity %hhu, enable %hhu.",
134 __func__, config->number, config->period, config->duty, config->polarity, config->status);
135 return HDF_SUCCESS;
136 }
137
138 struct PwmMethod g_pwmOps = {
139 .setConfig = HiPwmSetConfig,
140 };
141
HiPwmRemove(struct HiPwm * hp)142 static void HiPwmRemove(struct HiPwm *hp)
143 {
144 if (hp->base != NULL) {
145 OsalIoUnmap((void *)hp->base);
146 }
147 OsalMemFree(hp);
148 }
149
HiPwmProbe(struct HiPwm * hp,struct HdfDeviceObject * obj)150 static int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
151 {
152 uint32_t tmp;
153 int32_t ret;
154 struct DeviceResourceIface *iface = NULL;
155
156 iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
157 if (iface == NULL || iface->GetUint32 == NULL) {
158 HDF_LOGE("%s: face is invalid", __func__);
159 return HDF_FAILURE;
160 }
161
162 if (iface->GetUint32(obj->property, "num", &(hp->dev.num), 0) != HDF_SUCCESS) {
163 HDF_LOGE("%s: read num fail", __func__);
164 return HDF_FAILURE;
165 }
166
167 if (iface->GetUint32(obj->property, "base", &tmp, 0) != HDF_SUCCESS) {
168 HDF_LOGE("%s: read base fail", __func__);
169 return HDF_FAILURE;
170 }
171
172 hp->base = OsalIoRemap(tmp, sizeof(struct HiPwmRegs));
173 if (hp->base == NULL) {
174 HDF_LOGE("%s: OsalIoRemap fail", __func__);
175 return HDF_FAILURE;
176 }
177
178 hp->reg = (struct HiPwmRegs *)hp->base;
179 hp->supportPolarity = true;
180 hp->dev.method = &g_pwmOps;
181 hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE;
182 hp->dev.cfg.period = PWM_DEFAULT_PERIOD;
183 hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY;
184 hp->dev.cfg.status = PWM_DISABLE_STATUS;
185 hp->dev.cfg.number = 0;
186 hp->dev.busy = false;
187 if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {
188 OsalIoUnmap((void *)hp->base);
189 HDF_LOGE("%s: [PwmDeviceAdd] failed.", __func__);
190 return HDF_FAILURE;
191 }
192 ret = PwmDumperCreate(hp);
193 if (ret != HDF_SUCCESS) {
194 HDF_LOGE("%s: create dumper failed:%d", __func__, ret);
195 OsalIoUnmap((void *)hp->base);
196 return ret;
197 }
198 HDF_LOGI("%s: set PwmConfig: number %u, period %u, duty %u, polarity %hhu, enable %hhu.", __func__,
199 hp->dev.cfg.number, hp->dev.cfg.period, hp->dev.cfg.duty, hp->dev.cfg.polarity, hp->dev.cfg.status);
200 return HDF_SUCCESS;
201 }
202
HdfPwmBind(struct HdfDeviceObject * obj)203 static int32_t HdfPwmBind(struct HdfDeviceObject *obj)
204 {
205 (void)obj;
206 return HDF_SUCCESS;
207 }
208
HdfPwmInit(struct HdfDeviceObject * obj)209 static int32_t HdfPwmInit(struct HdfDeviceObject *obj)
210 {
211 int ret;
212 struct HiPwm *hp = NULL;
213
214 if (obj == NULL) {
215 HDF_LOGE("%s: obj is null", __func__);
216 return HDF_ERR_INVALID_OBJECT;
217 }
218 hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));
219 if (hp == NULL) {
220 HDF_LOGE("%s: OsalMemCalloc hp error", __func__);
221 return HDF_ERR_MALLOC_FAIL;
222 }
223
224 ret = HiPwmProbe(hp, obj);
225 if (ret != HDF_SUCCESS) {
226 HDF_LOGE("%s: error probe, ret is %d", __func__, ret);
227 OsalMemFree(hp);
228 }
229 PwmDumperDump(hp);
230 HDF_LOGI("%s: pwm init success", __func__);
231 return ret;
232 }
233
HdfPwmRelease(struct HdfDeviceObject * obj)234 static void HdfPwmRelease(struct HdfDeviceObject *obj)
235 {
236 struct HiPwm *hp = NULL;
237
238 HDF_LOGI("%s: entry", __func__);
239 if (obj == NULL) {
240 HDF_LOGE("%s: obj is null", __func__);
241 return;
242 }
243 hp = (struct HiPwm *)obj->service;
244 if (hp == NULL) {
245 HDF_LOGE("%s: hp is null", __func__);
246 return;
247 }
248 PwmDumperDestroy(hp);
249 PwmDeviceRemove(obj, &(hp->dev));
250 HiPwmRemove(hp);
251 }
252
253 struct HdfDriverEntry g_hdfPwm = {
254 .moduleVersion = 1,
255 .moduleName = "HDF_PLATFORM_PWM",
256 .Bind = HdfPwmBind,
257 .Init = HdfPwmInit,
258 .Release = HdfPwmRelease,
259 };
260
261 HDF_INIT(g_hdfPwm);
262