* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "hdf_power.h"
#include "gpio_if.h"
#include "hdf_base.h"
#include "hdf_chip.h"
#include "hdf_chip_config.h"
#define MAX_POWER_COUNT 4
struct NoManagablePower {
struct HdfPower base;
uint8_t powerSeqDelay;
};
struct GpioBasedPower {
struct HdfPower base;
uint8_t powerSeqDelay;
uint16_t gpioId;
uint8_t activeLevel;
};
struct MutiPowers {
struct HdfPower base;
uint8_t innerPowerCount;
struct HdfPower *powers[0];
};
static int32_t NotManagablePowerOn(struct HdfPower *power) {
(void)power;
return HDF_SUCCESS;
}
static int32_t NotManagablePowerOff(struct HdfPower *power) {
(void)power;
return HDF_FAILURE;
}
static void ReleasePower(struct HdfPower *power) {
if (power == NULL) {
return;
}
OsalMemFree(power);
}
static struct NoManagablePower *CreateNoManagablePower(const struct HdfPowerConfig *power) {
struct NoManagablePower *result = NULL;
static const struct HdfPowerOps notManagablePowerOps = {.On = NotManagablePowerOn,
.Off = NotManagablePowerOff,
.Release = ReleasePower};
result = (struct NoManagablePower *)OsalMemCalloc(sizeof(struct NoManagablePower));
if (result == NULL) {
return NULL;
}
result->base.ops = ¬ManagablePowerOps;
result->powerSeqDelay = power->powerSeqDelay;
return result;
}
static int32_t GpioPowerOn(struct HdfPower *power) {
int32_t ret;
struct GpioBasedPower *gpioPower = (struct GpioBasedPower *)power;
if (power == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return HDF_FAILURE;
}
ret = GpioSetDir(gpioPower->gpioId, 1);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s:set dir fail! ret=%d\n", __func__, ret);
return HDF_FAILURE;
}
ret = GpioWrite(gpioPower->gpioId, gpioPower->activeLevel);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s:set power on fail! ret=%d\n", __func__, ret);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t GpioPowerOff(struct HdfPower *power) {
int32_t ret;
struct GpioBasedPower *gpioPower = (struct GpioBasedPower *)power;
if (power == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return HDF_FAILURE;
}
ret = GpioSetDir(gpioPower->gpioId, 1);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s:set dir fail! ret=%d\n", __func__, ret);
return HDF_FAILURE;
}
ret = GpioWrite(gpioPower->gpioId, !gpioPower->activeLevel);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s:set power on fail! ret=%d\n", __func__, ret);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static struct GpioBasedPower *CreateGpioBasedPower(const struct HdfPowerConfig *power) {
struct GpioBasedPower *result = NULL;
result = (struct GpioBasedPower *)OsalMemCalloc(sizeof(struct GpioBasedPower));
if (result == NULL) {
return NULL;
}
static const struct HdfPowerOps notManagablePowerOps = {.On = GpioPowerOn,
.Off = GpioPowerOff,
.Release = ReleasePower};
result->base.ops = ¬ManagablePowerOps;
result->powerSeqDelay = power->powerSeqDelay;
result->gpioId = power->gpio.gpioId;
result->activeLevel = power->gpio.activeLevel;
return result;
}
static struct HdfPower *CreatePower(const struct HdfPowerConfig *power) {
if (power == NULL) {
return NULL;
}
if (power->type == POWER_TYPE_ALWAYS_ON) {
return (struct HdfPower *)CreateNoManagablePower(power);
} else if (power->type == POWER_TYPE_GPIO) {
return (struct HdfPower *)CreateGpioBasedPower(power);
} else {
HDF_LOGE("%s:not supported power type %d", __func__, power->type);
return NULL;
}
}
static int32_t ActiveMutiPower(struct HdfPower *power) {
struct MutiPowers *mutiPower = (struct MutiPowers *)power;
int ret;
if (power == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return HDF_FAILURE;
}
for (uint8_t i = 0; i < mutiPower->innerPowerCount; i++) {
if (mutiPower->powers[i] == NULL || mutiPower->powers[i]->ops == NULL ||
mutiPower->powers[i]->ops->On == NULL) {
HDF_LOGW("%s:bad power!index=%d", __func__, i);
ret = HDF_FAILURE;
break;
}
if (i > 0) {
struct NoManagablePower *innerPower = (struct NoManagablePower *)mutiPower->powers[i];
OsalMSleep(innerPower->powerSeqDelay);
}
ret = mutiPower->powers[i]->ops->On(mutiPower->powers[i]);
if (ret != HDF_SUCCESS) {
break;
}
}
return ret;
}
static int32_t DeactiveMutiPower(struct HdfPower *power) {
struct MutiPowers *mutiPower = (struct MutiPowers *)power;
int ret;
if (power == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return HDF_FAILURE;
}
for (uint8_t i = 0; i < mutiPower->innerPowerCount; i++) {
if (mutiPower->powers[i] == NULL || mutiPower->powers[i]->ops == NULL ||
mutiPower->powers[i]->ops->Off == NULL) {
HDF_LOGW("%s:bad power!index=%d", __func__, i);
ret = HDF_FAILURE;
break;
}
ret = mutiPower->powers[i]->ops->Off(mutiPower->powers[i]);
if (ret != HDF_SUCCESS) {
break;
}
}
return ret;
}
static void ReleaseMutiPower(struct HdfPower *power) {
struct MutiPowers *mutiPower = (struct MutiPowers *)power;
if (power == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return;
}
for (uint8_t i = 0; i < mutiPower->innerPowerCount; i++) {
if (mutiPower->powers[i] == NULL || mutiPower->powers[i]->ops == NULL ||
mutiPower->powers[i]->ops->Release == NULL) {
HDF_LOGW("%s:bad power!index=%d", __func__, i);
} else {
mutiPower->powers[i]->ops->Release(mutiPower->powers[i]);
}
mutiPower->powers[i] = NULL;
}
OsalMemFree(power);
}
static struct MutiPowers *CreateMutiPower(const struct HdfPowersConfig *powersConfig) {
int ret = HDF_SUCCESS;
struct MutiPowers *mutiPower =
OsalMemCalloc(sizeof(struct MutiPowers) + sizeof(struct HdfPower *) * powersConfig->powerCount);
static const struct HdfPowerOps mutiPowerOps = {.On = ActiveMutiPower,
.Off = DeactiveMutiPower,
.Release = ReleaseMutiPower};
for (uint8_t i = 0; i < powersConfig->powerCount; i++) {
mutiPower->powers[i] = CreatePower(powersConfig->power + i);
if (mutiPower->powers[i] == NULL) {
OsalMemFree(mutiPower);
ret = HDF_FAILURE;
break;
}
}
mutiPower->innerPowerCount = powersConfig->powerCount;
if (ret != HDF_SUCCESS) {
ReleaseMutiPower((struct HdfPower *)mutiPower);
return NULL;
}
mutiPower->base.ops = &mutiPowerOps;
return mutiPower;
}
struct HdfPower *CreateVirtualPower(const struct HdfPowersConfig *powers) {
if (powers == NULL) {
HDF_LOGE("%s:nullptr", __func__);
return NULL;
}
if (powers->powerCount > MAX_POWER_COUNT) {
HDF_LOGE("%s:too many power in config!count=%d", __func__, powers->powerCount);
return NULL;
}
if (powers->powerCount == 1) {
return CreatePower(&powers->power[0]);
} else if (powers->powerCount > 1) {
return (struct HdfPower *)CreateMutiPower(powers);
} else {
return NULL;
}
}