11bd4fe43Sopenharmony_ci/*
21bd4fe43Sopenharmony_ci * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
31bd4fe43Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
41bd4fe43Sopenharmony_ci * you may not use this file except in compliance with the License.
51bd4fe43Sopenharmony_ci * You may obtain a copy of the License at
61bd4fe43Sopenharmony_ci *
71bd4fe43Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
81bd4fe43Sopenharmony_ci *
91bd4fe43Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
101bd4fe43Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
111bd4fe43Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121bd4fe43Sopenharmony_ci * See the License for the specific language governing permissions and
131bd4fe43Sopenharmony_ci * limitations under the License.
141bd4fe43Sopenharmony_ci */
151bd4fe43Sopenharmony_ci
161bd4fe43Sopenharmony_ci#include "pwm_hi35xx.h"
171bd4fe43Sopenharmony_ci#include "device_resource_if.h"
181bd4fe43Sopenharmony_ci#include "hdf_log.h"
191bd4fe43Sopenharmony_ci#include "osal_io.h"
201bd4fe43Sopenharmony_ci#include "osal_mem.h"
211bd4fe43Sopenharmony_ci#include "platform_dumper.h"
221bd4fe43Sopenharmony_ci#include "pwm_core.h"
231bd4fe43Sopenharmony_ci
241bd4fe43Sopenharmony_ci#define HDF_LOG_TAG pwm_hi35xx
251bd4fe43Sopenharmony_ci
261bd4fe43Sopenharmony_cistruct HiPwm {
271bd4fe43Sopenharmony_ci    struct PwmDev dev;
281bd4fe43Sopenharmony_ci    volatile unsigned char *base;
291bd4fe43Sopenharmony_ci    struct HiPwmRegs *reg;
301bd4fe43Sopenharmony_ci    struct PlatformDumper *dumper;
311bd4fe43Sopenharmony_ci    char *dumperName;
321bd4fe43Sopenharmony_ci    bool supportPolarity;
331bd4fe43Sopenharmony_ci};
341bd4fe43Sopenharmony_ci
351bd4fe43Sopenharmony_cistatic int32_t PwmDumperCreate(struct HiPwm *hp)
361bd4fe43Sopenharmony_ci{
371bd4fe43Sopenharmony_ci    struct PlatformDumper *dumper = NULL;
381bd4fe43Sopenharmony_ci    char *name = (char *)OsalMemCalloc(PWM_DUMPER_NAME_LEN);
391bd4fe43Sopenharmony_ci
401bd4fe43Sopenharmony_ci    if (snprintf_s(name, PWM_DUMPER_NAME_LEN, PWM_DUMPER_NAME_LEN - 1, "%s%u",
411bd4fe43Sopenharmony_ci        PWM_DUMPER_NAME_PREFIX, hp->dev.num) < 0) {
421bd4fe43Sopenharmony_ci        HDF_LOGE("%s: snprintf_s name fail!", __func__);
431bd4fe43Sopenharmony_ci        OsalMemFree(name);
441bd4fe43Sopenharmony_ci        return HDF_ERR_IO;
451bd4fe43Sopenharmony_ci    }
461bd4fe43Sopenharmony_ci    dumper = PlatformDumperCreate(name);
471bd4fe43Sopenharmony_ci    if (dumper == NULL) {
481bd4fe43Sopenharmony_ci        HDF_LOGE("%s: get dumper for %s fail!", __func__, name);
491bd4fe43Sopenharmony_ci        OsalMemFree(name);
501bd4fe43Sopenharmony_ci        return HDF_ERR_IO;
511bd4fe43Sopenharmony_ci    }
521bd4fe43Sopenharmony_ci    hp->dumper = dumper;
531bd4fe43Sopenharmony_ci    hp->dumperName = name;
541bd4fe43Sopenharmony_ci
551bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
561bd4fe43Sopenharmony_ci}
571bd4fe43Sopenharmony_ci
581bd4fe43Sopenharmony_cistatic void PwmDumperDump(struct HiPwm *hp)
591bd4fe43Sopenharmony_ci{
601bd4fe43Sopenharmony_ci    int32_t ret;
611bd4fe43Sopenharmony_ci    struct PlatformDumperData datas[] = {
621bd4fe43Sopenharmony_ci        {"PWM_CFG0", PLATFORM_DUMPER_REGISTERL, (void *)hp->base},
631bd4fe43Sopenharmony_ci        {"PWM_CFG1", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base+ PWM_CFG1_SHIFT)},
641bd4fe43Sopenharmony_ci        {"PWM_CFG2", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_CFG2_SHIFT)},
651bd4fe43Sopenharmony_ci        {"PWM_CTRL", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_CTRL_SHIFT)},
661bd4fe43Sopenharmony_ci        {"PWM_STATE0", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE0_SHIFT)},
671bd4fe43Sopenharmony_ci        {"PWM_STATE1", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE1_SHIFT)},
681bd4fe43Sopenharmony_ci        {"PWM_STATE2", PLATFORM_DUMPER_REGISTERL, (void *)(hp->base + PWM_STATE2_SHIFT)},
691bd4fe43Sopenharmony_ci    };
701bd4fe43Sopenharmony_ci    if (hp->dumper == NULL) {
711bd4fe43Sopenharmony_ci        HDF_LOGE("%s: pwm dumper is NULL", __func__);
721bd4fe43Sopenharmony_ci        return;
731bd4fe43Sopenharmony_ci    }
741bd4fe43Sopenharmony_ci    ret = PlatformDumperAddDatas(hp->dumper, datas, sizeof(datas) / sizeof(struct PlatformDumperData));
751bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
761bd4fe43Sopenharmony_ci        return;
771bd4fe43Sopenharmony_ci    }
781bd4fe43Sopenharmony_ci    (void)PlatformDumperDump(hp->dumper);
791bd4fe43Sopenharmony_ci    (void)PlatformDumperClearDatas(hp->dumper);
801bd4fe43Sopenharmony_ci}
811bd4fe43Sopenharmony_ci
821bd4fe43Sopenharmony_cistatic inline void PwmDumperDestroy(struct HiPwm *hp)
831bd4fe43Sopenharmony_ci{
841bd4fe43Sopenharmony_ci    PlatformDumperDestroy(hp->dumper);
851bd4fe43Sopenharmony_ci    OsalMemFree(hp->dumperName);
861bd4fe43Sopenharmony_ci}
871bd4fe43Sopenharmony_ci
881bd4fe43Sopenharmony_ciint32_t HiPwmSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
891bd4fe43Sopenharmony_ci{
901bd4fe43Sopenharmony_ci    struct HiPwm *hp = (struct HiPwm *)pwm;
911bd4fe43Sopenharmony_ci    if (hp == NULL || hp->reg == NULL || config == NULL) {
921bd4fe43Sopenharmony_ci        HDF_LOGE("%s: hp reg or config is null", __func__);
931bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
941bd4fe43Sopenharmony_ci    }
951bd4fe43Sopenharmony_ci    if (config->polarity != PWM_NORMAL_POLARITY && config->polarity != PWM_INVERTED_POLARITY) {
961bd4fe43Sopenharmony_ci        HDF_LOGE("%s: polarity %hhu is invalid", __func__, config->polarity);
971bd4fe43Sopenharmony_ci        PwmDumperDump(hp);
981bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
991bd4fe43Sopenharmony_ci    }
1001bd4fe43Sopenharmony_ci    if (config->period < PWM_MIN_PERIOD) {
1011bd4fe43Sopenharmony_ci        HDF_LOGE("%s: period %u is not support, min period %d", __func__, config->period, PWM_MIN_PERIOD);
1021bd4fe43Sopenharmony_ci        PwmDumperDump(hp);
1031bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
1041bd4fe43Sopenharmony_ci    }
1051bd4fe43Sopenharmony_ci    if (config->duty < 1 || config->duty > config->period) {
1061bd4fe43Sopenharmony_ci        HDF_LOGE("%s: duty %u is not support, duty must in [1, period = %u].",
1071bd4fe43Sopenharmony_ci            __func__, config->duty, config->period);
1081bd4fe43Sopenharmony_ci        PwmDumperDump(hp);
1091bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
1101bd4fe43Sopenharmony_ci    }
1111bd4fe43Sopenharmony_ci    HiPwmDisable(hp->reg);
1121bd4fe43Sopenharmony_ci    if (pwm->cfg.polarity != config->polarity && hp->supportPolarity) {
1131bd4fe43Sopenharmony_ci        HiPwmSetPolarity(hp->reg, config->polarity);
1141bd4fe43Sopenharmony_ci        HDF_LOGI("%s: [HiPwmSetPolarity] done, polarity: %hhu -> %hhu.", __func__, pwm->cfg.polarity, config->polarity);
1151bd4fe43Sopenharmony_ci    }
1161bd4fe43Sopenharmony_ci    if (pwm->cfg.period != config->period) {
1171bd4fe43Sopenharmony_ci        HiPwmSetPeriod(hp->reg, config->period);
1181bd4fe43Sopenharmony_ci        HDF_LOGI("%s: [HiPwmSetPeriod] done, period: %u -> %u", __func__, pwm->cfg.period, config->period);
1191bd4fe43Sopenharmony_ci    }
1201bd4fe43Sopenharmony_ci    if (pwm->cfg.duty != config->duty) {
1211bd4fe43Sopenharmony_ci        HiPwmSetDuty(hp->reg, config->duty);
1221bd4fe43Sopenharmony_ci        HDF_LOGI("%s: [HiPwmSetDuty] done, duty: %u -> %u", __func__, pwm->cfg.duty, config->duty);
1231bd4fe43Sopenharmony_ci    }
1241bd4fe43Sopenharmony_ci    if (config->status == PWM_ENABLE_STATUS) {
1251bd4fe43Sopenharmony_ci        if (config->number == 0) {
1261bd4fe43Sopenharmony_ci            HiPwmAlwaysOutput(hp->reg);
1271bd4fe43Sopenharmony_ci            HDF_LOGI("%s: [HiPwmAlwaysOutput] done, then enable.", __func__);
1281bd4fe43Sopenharmony_ci        } else {
1291bd4fe43Sopenharmony_ci            HiPwmOutputNumberSquareWaves(hp->reg, config->number);
1301bd4fe43Sopenharmony_ci            HDF_LOGI("%s: [HiPwmOutputNumberSquareWaves] done, then enable.", __func__);
1311bd4fe43Sopenharmony_ci        }
1321bd4fe43Sopenharmony_ci    }
1331bd4fe43Sopenharmony_ci    HDF_LOGI("%s: set PwmConfig done: number %u, period %u, duty %u, polarity %hhu, enable %hhu.",
1341bd4fe43Sopenharmony_ci        __func__, config->number, config->period, config->duty, config->polarity, config->status);
1351bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
1361bd4fe43Sopenharmony_ci}
1371bd4fe43Sopenharmony_ci
1381bd4fe43Sopenharmony_cistruct PwmMethod g_pwmOps = {
1391bd4fe43Sopenharmony_ci    .setConfig = HiPwmSetConfig,
1401bd4fe43Sopenharmony_ci};
1411bd4fe43Sopenharmony_ci
1421bd4fe43Sopenharmony_cistatic void HiPwmRemove(struct HiPwm *hp)
1431bd4fe43Sopenharmony_ci{
1441bd4fe43Sopenharmony_ci    if (hp->base != NULL) {
1451bd4fe43Sopenharmony_ci        OsalIoUnmap((void *)hp->base);
1461bd4fe43Sopenharmony_ci    }
1471bd4fe43Sopenharmony_ci    OsalMemFree(hp);
1481bd4fe43Sopenharmony_ci}
1491bd4fe43Sopenharmony_ci
1501bd4fe43Sopenharmony_cistatic int32_t HiPwmProbe(struct HiPwm *hp, struct HdfDeviceObject *obj)
1511bd4fe43Sopenharmony_ci{
1521bd4fe43Sopenharmony_ci    uint32_t tmp;
1531bd4fe43Sopenharmony_ci    int32_t ret;
1541bd4fe43Sopenharmony_ci    struct DeviceResourceIface *iface = NULL;
1551bd4fe43Sopenharmony_ci
1561bd4fe43Sopenharmony_ci    iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
1571bd4fe43Sopenharmony_ci    if (iface == NULL || iface->GetUint32 == NULL) {
1581bd4fe43Sopenharmony_ci        HDF_LOGE("%s: face is invalid", __func__);
1591bd4fe43Sopenharmony_ci        return HDF_FAILURE;
1601bd4fe43Sopenharmony_ci    }
1611bd4fe43Sopenharmony_ci
1621bd4fe43Sopenharmony_ci    if (iface->GetUint32(obj->property, "num", &(hp->dev.num), 0) != HDF_SUCCESS) {
1631bd4fe43Sopenharmony_ci        HDF_LOGE("%s: read num fail", __func__);
1641bd4fe43Sopenharmony_ci        return HDF_FAILURE;
1651bd4fe43Sopenharmony_ci    }
1661bd4fe43Sopenharmony_ci
1671bd4fe43Sopenharmony_ci    if (iface->GetUint32(obj->property, "base", &tmp, 0) != HDF_SUCCESS) {
1681bd4fe43Sopenharmony_ci        HDF_LOGE("%s: read base fail", __func__);
1691bd4fe43Sopenharmony_ci        return HDF_FAILURE;
1701bd4fe43Sopenharmony_ci    }
1711bd4fe43Sopenharmony_ci
1721bd4fe43Sopenharmony_ci    hp->base = OsalIoRemap(tmp, sizeof(struct HiPwmRegs));
1731bd4fe43Sopenharmony_ci    if (hp->base == NULL) {
1741bd4fe43Sopenharmony_ci        HDF_LOGE("%s: OsalIoRemap fail", __func__);
1751bd4fe43Sopenharmony_ci        return HDF_FAILURE;
1761bd4fe43Sopenharmony_ci    }
1771bd4fe43Sopenharmony_ci
1781bd4fe43Sopenharmony_ci    hp->reg = (struct HiPwmRegs *)hp->base;
1791bd4fe43Sopenharmony_ci    hp->supportPolarity = true;
1801bd4fe43Sopenharmony_ci    hp->dev.method = &g_pwmOps;
1811bd4fe43Sopenharmony_ci    hp->dev.cfg.duty = PWM_DEFAULT_DUTY_CYCLE;
1821bd4fe43Sopenharmony_ci    hp->dev.cfg.period = PWM_DEFAULT_PERIOD;
1831bd4fe43Sopenharmony_ci    hp->dev.cfg.polarity = PWM_DEFAULT_POLARITY;
1841bd4fe43Sopenharmony_ci    hp->dev.cfg.status = PWM_DISABLE_STATUS;
1851bd4fe43Sopenharmony_ci    hp->dev.cfg.number = 0;
1861bd4fe43Sopenharmony_ci    hp->dev.busy = false;
1871bd4fe43Sopenharmony_ci    if (PwmDeviceAdd(obj, &(hp->dev)) != HDF_SUCCESS) {
1881bd4fe43Sopenharmony_ci        OsalIoUnmap((void *)hp->base);
1891bd4fe43Sopenharmony_ci        HDF_LOGE("%s: [PwmDeviceAdd] failed.", __func__);
1901bd4fe43Sopenharmony_ci        return HDF_FAILURE;
1911bd4fe43Sopenharmony_ci    }
1921bd4fe43Sopenharmony_ci    ret = PwmDumperCreate(hp);
1931bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
1941bd4fe43Sopenharmony_ci        HDF_LOGE("%s: create dumper failed:%d", __func__, ret);
1951bd4fe43Sopenharmony_ci        OsalIoUnmap((void *)hp->base);
1961bd4fe43Sopenharmony_ci        return ret;
1971bd4fe43Sopenharmony_ci    }
1981bd4fe43Sopenharmony_ci    HDF_LOGI("%s: set PwmConfig: number %u, period %u, duty %u, polarity %hhu, enable %hhu.", __func__,
1991bd4fe43Sopenharmony_ci        hp->dev.cfg.number, hp->dev.cfg.period, hp->dev.cfg.duty, hp->dev.cfg.polarity, hp->dev.cfg.status);
2001bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
2011bd4fe43Sopenharmony_ci}
2021bd4fe43Sopenharmony_ci
2031bd4fe43Sopenharmony_cistatic int32_t HdfPwmBind(struct HdfDeviceObject *obj)
2041bd4fe43Sopenharmony_ci{
2051bd4fe43Sopenharmony_ci    (void)obj;
2061bd4fe43Sopenharmony_ci    return HDF_SUCCESS;
2071bd4fe43Sopenharmony_ci}
2081bd4fe43Sopenharmony_ci
2091bd4fe43Sopenharmony_cistatic int32_t HdfPwmInit(struct HdfDeviceObject *obj)
2101bd4fe43Sopenharmony_ci{
2111bd4fe43Sopenharmony_ci    int ret;
2121bd4fe43Sopenharmony_ci    struct HiPwm *hp = NULL;
2131bd4fe43Sopenharmony_ci
2141bd4fe43Sopenharmony_ci    if (obj == NULL) {
2151bd4fe43Sopenharmony_ci        HDF_LOGE("%s: obj is null", __func__);
2161bd4fe43Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
2171bd4fe43Sopenharmony_ci    }
2181bd4fe43Sopenharmony_ci    hp = (struct HiPwm *)OsalMemCalloc(sizeof(*hp));
2191bd4fe43Sopenharmony_ci    if (hp == NULL) {
2201bd4fe43Sopenharmony_ci        HDF_LOGE("%s: OsalMemCalloc hp error", __func__);
2211bd4fe43Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
2221bd4fe43Sopenharmony_ci    }
2231bd4fe43Sopenharmony_ci
2241bd4fe43Sopenharmony_ci    ret = HiPwmProbe(hp, obj);
2251bd4fe43Sopenharmony_ci    if (ret != HDF_SUCCESS) {
2261bd4fe43Sopenharmony_ci        HDF_LOGE("%s: error probe, ret is %d", __func__, ret);
2271bd4fe43Sopenharmony_ci        OsalMemFree(hp);
2281bd4fe43Sopenharmony_ci    }
2291bd4fe43Sopenharmony_ci    PwmDumperDump(hp);
2301bd4fe43Sopenharmony_ci    HDF_LOGI("%s: pwm init success", __func__);
2311bd4fe43Sopenharmony_ci    return ret;
2321bd4fe43Sopenharmony_ci}
2331bd4fe43Sopenharmony_ci
2341bd4fe43Sopenharmony_cistatic void HdfPwmRelease(struct HdfDeviceObject *obj)
2351bd4fe43Sopenharmony_ci{
2361bd4fe43Sopenharmony_ci    struct HiPwm *hp = NULL;
2371bd4fe43Sopenharmony_ci
2381bd4fe43Sopenharmony_ci    HDF_LOGI("%s: entry", __func__);
2391bd4fe43Sopenharmony_ci    if (obj == NULL) {
2401bd4fe43Sopenharmony_ci        HDF_LOGE("%s: obj is null", __func__);
2411bd4fe43Sopenharmony_ci        return;
2421bd4fe43Sopenharmony_ci    }
2431bd4fe43Sopenharmony_ci    hp = (struct HiPwm *)obj->service;
2441bd4fe43Sopenharmony_ci    if (hp == NULL) {
2451bd4fe43Sopenharmony_ci        HDF_LOGE("%s: hp is null", __func__);
2461bd4fe43Sopenharmony_ci        return;
2471bd4fe43Sopenharmony_ci    }
2481bd4fe43Sopenharmony_ci    PwmDumperDestroy(hp);
2491bd4fe43Sopenharmony_ci    PwmDeviceRemove(obj, &(hp->dev));
2501bd4fe43Sopenharmony_ci    HiPwmRemove(hp);
2511bd4fe43Sopenharmony_ci}
2521bd4fe43Sopenharmony_ci
2531bd4fe43Sopenharmony_cistruct HdfDriverEntry g_hdfPwm = {
2541bd4fe43Sopenharmony_ci    .moduleVersion = 1,
2551bd4fe43Sopenharmony_ci    .moduleName = "HDF_PLATFORM_PWM",
2561bd4fe43Sopenharmony_ci    .Bind = HdfPwmBind,
2571bd4fe43Sopenharmony_ci    .Init = HdfPwmInit,
2581bd4fe43Sopenharmony_ci    .Release = HdfPwmRelease,
2591bd4fe43Sopenharmony_ci};
2601bd4fe43Sopenharmony_ci
2611bd4fe43Sopenharmony_ciHDF_INIT(g_hdfPwm);
262