123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- /*
- * Copyright (c) 2021 Actions Semiconductor Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief Actions LARK family PMUVDD and PMUSVCC Implementation
- */
- #include <kernel.h>
- #include <device.h>
- #include <string.h>
- #include <errno.h>
- #include <soc.h>
- #include <board_cfg.h>
- #include <soc_pmu.h>
- #include <logging/log.h>
- LOG_MODULE_REGISTER(pmu0, CONFIG_LOG_DEFAULT_LEVEL);
- #define PMU_INTMASK_COUNTER8HZ_INTEN BIT(14)
- #define PMU_INTMASK_REMOTE_INTEN BIT(12)
- #define PMU_INTMASK_BATLV_INTEN BIT(11)
- #define PMU_INTMASK_DC5VLV_INTEN BIT(10)
- #define PMU_INTMASK_WIO1LV_INTEN BIT(7)
- #define PMU_INTMASK_WIO0LV_INTEN BIT(6)
- #define PMU_INTMASK_ALARM8HZ_INTEN BIT(4)
- #define PMU_INTMASK_DC5VOUT_INTEN BIT(3)
- #define PMU_INTMASK_DC5VIN_INTEN BIT(2)
- #define PMU_INTMASK_ONOFF_S_INTEN BIT(1)
- #define PMU_INTMASK_ONOFF_L_INTEN BIT(0)
- #define WAKE_CTL_SVCC_BATLV_VOL_SHIFT (27) /* Battery voltage level wakeup threshold */
- #define WAKE_CTL_SVCC_BATLV_VOL_MASK (0x7 << WAKE_CTL_SVCC_BATLV_VOL_SHIFT)
- #define WAKE_CTL_SVCC_DC5VLV_VOL_SHIFT (24) /* DC5V voltage level wakeup threshold */
- #define WAKE_CTL_SVCC_DC5VLV_VOL_MASK (0x7 << WAKE_CTL_SVCC_DC5VLV_VOL_SHIFT)
- #define WAKE_CTL_SVCC_WIO1LV_VOL_SHIFT (22)
- #define WAKE_CTL_SVCC_WIO1LV_VOL_MASK (0x3 << WAKE_CTL_SVCC_WIO1LV_VOL_SHIFT)
- #define WAKE_CTL_SVCC_WIO0LV_VOL_SHIFT (20)
- #define WAKE_CTL_SVCC_WIO0LV_VOL_MASK (0x3 << WAKE_CTL_SVCC_WIO0LV_VOL_SHIFT)
- #define WAKE_CTL_SVCC_REMOTE_WKEN BIT(12)
- #define WAKE_CTL_SVCC_BATLV_WKEN BIT(11)
- #define WAKE_CTL_SVCC_DC5VLV_WKEN BIT(10)
- #define WAKE_CTL_SVCC_WIO1LV_DETEN BIT(9)
- #define WAKE_CTL_SVCC_WIO0LV_DETEN BIT(8)
- #define WAKE_CTL_SVCC_WIO1LV_WKEN BIT(7)
- #define WAKE_CTL_SVCC_WIO0LV_WKEN BIT(6)
- #define WAKE_CTL_SVCC_WIO_WKEN BIT(5)
- #define WAKE_CTL_SVCC_ALARM8HZ_WKEN BIT(4)
- #define WAKE_CTL_SVCC_DC5VOUT_WKEN BIT(3)
- #define WAKE_CTL_SVCC_DC5VIN_WKEN BIT(2)
- #define WAKE_CTL_SVCC_SHORT_WKEN BIT(1)
- #define WAKE_CTL_SVCC_LONG_WKEN BIT(0)
- #define WAKE_PD_SVCC_REG_SVCC_SHIFT (24)
- #define WAKE_PD_SVCC_REG_SVCC_MASK (0xFF << WAKE_PD_SVCC_REG_SVCC_SHIFT)
- #define WAKE_PD_SVCC_SYSRESET_PD BIT(20)
- #define WAKE_PD_SVCC_POWEROK_PD BIT(19)
- #define WAKE_PD_SVCC_LB_PD BIT(18)
- #define WAKE_PD_SVCC_OC_PD BIT(17)
- #define WAKE_PD_SVCC_LVPRO_PD BIT(16)
- #define WAKE_PD_SVCC_BATWK_PD BIT(13)
- #define WAKE_PD_SVCC_REMOTE_PD BIT(12)
- #define WAKE_PD_SVCC_BATLV_PD BIT(11)
- #define WAKE_PD_SVCC_DC5VLV_PD BIT(10)
- #define WAKE_PD_SVCC_WIO1LV_PD BIT(7)
- #define WAKE_PD_SVCC_WIO0LV_PD BIT(6)
- #define WAKE_PD_SVCC_WIO_PD BIT(5)
- #define WAKE_PD_SVCC_ALARM8HZ_PD BIT(4)
- #define WAKE_PD_SVCC_DC5VOUT_PD BIT(3)
- #define WAKE_PD_SVCC_DC5VIN_PD BIT(2)
- #define WAKE_PD_SVCC_ONOFF_S_PD BIT(1)
- #define WAKE_PD_SVCC_ONOFF_L_PD BIT(0)
- #define SYSTEM_SET_SVCC_ONOFF_SEL_SHIFT (25)
- #define SYSTEM_SET_SVCC_ONOFF_SEL_MASK (0x3 << SYSTEM_SET_SVCC_ONOFF_SEL_SHIFT)
- #define SYSTEM_SET_SVCC_SIM_A_EN BIT(24)
- #define SYSTEM_SET_SVCC_ONOFF_PRESS_TIME_SHIFT (21)
- #define SYSTEM_SET_SVCC_ONOFF_PRESS_TIME_MASK (0x7 << SYSTEM_SET_SVCC_ONOFF_PRESS_TIME_SHIFT)
- #define SYSTEM_SET_SVCC_ONOFF_PRESS_TIME(x) ((x) << SYSTEM_SET_SVCC_ONOFF_PRESS_TIME_SHIFT)
- #define SYSTEM_SET_SVCC_ONOFF_RST_EN_SHIFT (19)
- #define SYSTEM_SET_SVCC_ONOFF_RST_EN_MASK (0x3 << SYSTEM_SET_SVCC_ONOFF_RST_EN_SHIFT)
- #define SYSTEM_SET_SVCC_ONOFF_RST_EN(x) ((x) << SYSTEM_SET_SVCC_ONOFF_RST_EN_SHIFT)
- #define SYSTEM_SET_SVCC_ONOFF_RST_TIME BIT(18)
- #define SYSTEM_SET_SVCC_ONOFF_PRES BIT(17)
- #define CHG_CTL_SVCC_CV_3V3 BIT(19)
- #define CHG_CTL_SVCC_CV_OFFSET_SHIFT (5)
- #define CHG_CTL_SVCC_CV_OFFSET_MASK (0x1F << CHG_CTL_SVCC_CV_OFFSET_SHIFT)
- #define CHG_CTL_SVCC_CV_OFFSET(x) ((x) << CHG_CTL_SVCC_CV_OFFSET_SHIFT)
- #define PMU_DET_COUNTR8HZ_PD BIT(12)
- #define PMU_DET_DC5VIN_DET BIT(0)
- #define PMU_COUNTER8HZ_SVCC_CLK_SEL_SHIFT (27)
- #define PMU_COUNTER8HZ_SVCC_CLK_SEL_MASK (1 << PMU_COUNTER8HZ_SVCC_CLK_SEL_SHIFT)
- #define PMU_COUNTER8HZ_SVCC_CLK_SEL_LOSC BIT(27)
- #define PMU_COUNTER8HZ_SVCC_COUNTER_EN BIT(26)
- #define PMU_COUNTER8HZ_SVCC_COUNTER_VAL (0x3FFFFFF)
- #define PMU_ALARM8HZ_SVCC_PD BIT(26)
- #define PMU_ALARM8HZ_SVCC_ALARM_VAL_MASK (0x3FFFFFF)
- #define PMU_MONITOR_DEV_INVALID(x) (((x) != PMU_DETECT_DEV_DC5V) \
- && ((x) != PMU_DETECT_DEV_REMOTE) \
- && ((x) != PMU_DETECT_DEV_ONOFF) \
- && ((x) != PMU_DETECT_DEV_COUNTER8HZ) \
- && ((x) != PMU_DETECT_DEV_ALARM8HZ))
- /*
- * @struct acts_pmuvdd
- * @brief Actions PMUVDD controller hardware register
- */
- struct acts_pmuvdd {
- volatile uint32_t vout_ctl0;
- volatile uint32_t vout_ctl1_s1;
- volatile uint32_t vout_ctl1_s2;
- volatile uint32_t vout_ctl1_s3;
- volatile uint32_t pmu_det;
- volatile uint32_t reserved0[3];
- volatile uint32_t dcdc_vc18_ctl;
- volatile uint32_t dcdc_vd12_ctl;
- volatile uint32_t dcdc_vdd_ctl;
- volatile uint32_t reserved1;
- volatile uint32_t pwrgate_dig;
- volatile uint32_t pwrgate_dig_ack;
- volatile uint32_t pwrgate_ram;
- volatile uint32_t pwrgate_ram_ack;
- volatile uint32_t pmu_intmask;
- };
- /*
- * @struct acts_pmusvcc
- * @brief Actions PMUSVCC controller hardware register
- */
- struct acts_pmusvcc {
- volatile uint32_t chg_ctl_svcc;
- volatile uint32_t bdg_ctl_svcc;
- volatile uint32_t system_set_svcc;
- volatile uint32_t power_ctl_svcc;
- volatile uint32_t wake_ctl_svcc;
- volatile uint32_t wake_pd_svcc;
- volatile uint32_t counter8hz_svcc;
- volatile uint32_t alarm8hz_svcc;
- };
- /**
- * struct pmu_drv_data
- * @brief The meta data which related to Actions PMU module.
- */
- struct pmu_context_t {
- struct detect_param_t detect_devs[PMU_DETECT_MAX_DEV]; /* PMU monitor peripheral devices */
- uint32_t pmuvdd_base; /* PMUVDD register base address */
- uint32_t pmusvcc_base; /* PMUSVCC register base address */
- uint8_t onoff_short_detect : 1; /* if 1 to enable onoff key short press detection */
- uint8_t onoff_remote_same_wio : 1; /* if 1 to indicate that onoff key and remote key use the same WIO source */
- };
- /* @brief get the PMU management context handler */
- static inline struct pmu_context_t *get_pmu_context(void)
- {
- static struct pmu_context_t pmu_context = {0};
- static struct pmu_context_t *p_pmu_context = NULL;
- if (!p_pmu_context) {
- pmu_context.pmuvdd_base = PMUVDD_BASE;
- pmu_context.pmusvcc_base = CHG_CTL_SVCC;
- pmu_context.onoff_short_detect = CONFIG_PMU_ONOFF_SHORT_DETECT;
- pmu_context.onoff_remote_same_wio = CONFIG_PMU_ONOFF_REMOTE_SAME_WIO;
- p_pmu_context = &pmu_context;
- }
- return p_pmu_context;
- }
- /* @brief get the base address of PMUVDD register */
- static inline struct acts_pmuvdd *get_pmuvdd_reg_base(struct pmu_context_t *ctx)
- {
- return (struct acts_pmuvdd *)ctx->pmuvdd_base;
- }
- /* @brief get the base address of PMUSVCC register */
- static inline struct acts_pmusvcc *get_pmusvcc_reg_base(struct pmu_context_t *ctx)
- {
- return (struct acts_pmusvcc *)ctx->pmusvcc_base;
- }
- #if 0
- /* @brief find the monitor device parameters by given detect_dev */
- static struct detect_param_t *soc_pmu_find_detect_dev(struct pmu_context_t *ctx, uint8_t detect_dev)
- {
- uint8_t i;
- for (i = 0; i < PMU_DETECT_MAX_DEV; i++) {
- if (ctx->detect_devs[i].detect_dev == detect_dev) {
- return &ctx->detect_devs[i];
- }
- LOG_DBG("dev slot[%d]:%d", i, ctx->detect_devs[i].detect_dev);
- }
- return NULL;
- }
- #endif
- /* @brief register the function will be called when the state of monitor device change */
- int soc_pmu_register_notify(struct detect_param_t *param)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- uint8_t i;
- if (!param)
- return -EINVAL;
- if (PMU_MONITOR_DEV_INVALID(param->detect_dev)) {
- LOG_ERR("Invalid monitor dev:%d", param->detect_dev);
- return -EINVAL;
- }
- for (i = 0; i < PMU_DETECT_MAX_DEV; i++) {
- /* new or update a monitor device into PMU context */
- if ((!(ctx->detect_devs[i].detect_dev))
- || (ctx->detect_devs[i].detect_dev == param->detect_dev)) {
- ctx->detect_devs[i].detect_dev = param->detect_dev;
- ctx->detect_devs[i].cb_data = param->cb_data;
- ctx->detect_devs[i].notify = param->notify;
- break;
- } else {
- LOG_DBG("Busy slot[%d]:%d", i, ctx->detect_devs[i].detect_dev);
- }
- }
- if (i == PMU_DETECT_MAX_DEV) {
- LOG_ERR("no space for dev:0x%x", param->detect_dev);
- return -ENOMEM;
- }
- /* enable detect device interrupt and DC5V is already enabled at the stage of initialization */
- if (PMU_DETECT_DEV_ONOFF == param->detect_dev) {
- if (ctx->onoff_short_detect) {
- pmusvcc_reg->wake_ctl_svcc |= (WAKE_CTL_SVCC_SHORT_WKEN | WAKE_CTL_SVCC_LONG_WKEN);
- pmuvdd_reg->pmu_intmask |= (PMU_INTMASK_ONOFF_S_INTEN | PMU_INTMASK_ONOFF_L_INTEN);
- } else {
- pmusvcc_reg->wake_ctl_svcc |= WAKE_CTL_SVCC_LONG_WKEN;
- pmuvdd_reg->pmu_intmask |= PMU_INTMASK_ONOFF_L_INTEN;
- }
- } else if (PMU_DETECT_DEV_REMOTE == param->detect_dev) {
- pmusvcc_reg->wake_ctl_svcc |= WAKE_CTL_SVCC_REMOTE_WKEN;
- pmuvdd_reg->pmu_intmask |= PMU_INTMASK_REMOTE_INTEN;
- } else if (PMU_DETECT_DEV_COUNTER8HZ == param->detect_dev) {
- pmuvdd_reg->pmu_intmask |= PMU_INTMASK_COUNTER8HZ_INTEN;
- }
- LOG_DBG("pmu register dev:%d", param->detect_dev);
- return 0;
- }
- /* @brief unregister the notify function for specified monitor device */
- void soc_pmu_unregister_notify(uint8_t detect_dev)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- uint8_t i;
- uint32_t key;
- for (i = 0; i < PMU_DETECT_MAX_DEV; i++) {
- if (ctx->detect_devs[i].detect_dev == detect_dev) {
- key = irq_lock();
- ctx->detect_devs[i].detect_dev = 0;
- ctx->detect_devs[i].notify = 0;
- ctx->detect_devs[i].cb_data = NULL;
- irq_unlock(key);
- }
- }
- }
- /* @brief get the current DC5V status of plug in or out */
- bool soc_pmu_get_dc5v_status(void)
- {
- bool status;
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- /* DC5VIN indicator, 0: DC5V < BAT +33mV; 1: DC5V > BAT + 80mV */
- if (pmuvdd_reg->pmu_det & PMU_DET_DC5VIN_DET)
- status = true;
- else
- status = false;
- return status;
- }
- /* @brief return the wakeup pending by system startup */
- uint32_t soc_pmu_get_wakeup_source(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- static uint32_t pmu_wakeup_pending;
- if (!pmu_wakeup_pending) {
- pmu_wakeup_pending = pmusvcc_reg->wake_pd_svcc;
- LOG_INF("pmu wakeup pending:0x%x", pmu_wakeup_pending);
- }
- return pmu_wakeup_pending;
- }
- /* @brief return the wakeup setting by system startup */
- uint32_t soc_pmu_get_wakeup_setting(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- static uint32_t pmu_wakeup_ctl;
- if (!pmu_wakeup_ctl) {
- pmu_wakeup_ctl = pmusvcc_reg->wake_ctl_svcc;
- LOG_INF("pmu wakeup setting:0x%x", pmu_wakeup_ctl);
- }
- return pmu_wakeup_ctl;
- }
- /* @brief check if system wakeup by RTC alarm */
- bool soc_pmu_is_alarm_wakeup(void)
- {
- uint32_t wk_pd;
- wk_pd = soc_pmu_get_wakeup_source();
- if (wk_pd & WAKE_CTL_SVCC_ALARM8HZ_WKEN)
- return true;
- return false;
- }
- /* @brief set the max constant current */
- void soc_pmu_set_max_current(uint16_t cur_ma)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- uint8_t level;
- if (cur_ma <= 100) {
- level = (cur_ma + 9) / 10 - 1;
- } else if (cur_ma < 240) {
- level = (cur_ma + 19) / 20 + 4;
- } else {
- level = 15;
- }
- pmusvcc_reg->chg_ctl_svcc = (pmusvcc_reg->chg_ctl_svcc & ~0xF) | level;
- }
- /* @brief get the max constant current */
- uint16_t soc_pmu_get_max_current(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- uint8_t level, cur_ma;
- level = pmusvcc_reg->chg_ctl_svcc & 0xF;
- if (level >= 10) {
- cur_ma = (level - 4) * 20;
- } else {
- cur_ma = (level + 1) * 10;
- }
- return cur_ma;
- }
- /* @brief lock(stop) DC5V charging for reading battery voltage */
- void soc_pmu_read_bat_lock(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- pmusvcc_reg->chg_ctl_svcc |= CHG_CTL_SVCC_CV_3V3;
- k_busy_wait(300);
- }
- /* @brief unlock(resume) and restart DC5V charging */
- void soc_pmu_read_bat_unlock(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- pmusvcc_reg->chg_ctl_svcc &= ~CHG_CTL_SVCC_CV_3V3;
- k_busy_wait(300);
- }
- /* @brief set const voltage value */
- void soc_pmu_set_const_voltage(uint8_t cv)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- if (cv <= 0x1F) {
- pmusvcc_reg->chg_ctl_svcc = \
- (pmusvcc_reg->chg_ctl_svcc & ~CHG_CTL_SVCC_CV_OFFSET_MASK) | CHG_CTL_SVCC_CV_OFFSET(cv);
- k_busy_wait(300);
- }
- }
- /* @brief configure the long press on-off key time */
- void soc_pmu_config_onoffkey_time(uint8_t val)
- {
- unsigned int val_reg;
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- if (val > 7)
- return ;
- val_reg = pmusvcc_reg->system_set_svcc & (~SYSTEM_SET_SVCC_ONOFF_PRESS_TIME_MASK);
- pmusvcc_reg->system_set_svcc = val_reg | SYSTEM_SET_SVCC_ONOFF_PRESS_TIME(val);
- k_busy_wait(300);
- }
- /* @brief configure the long press on-off key time */
- void soc_pmu_config_onoffkey_function(uint8_t val)
- {
- unsigned int val_reg;
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- /**
- * ONOFF long pressed function
- * 0: no function
- * 1: reset
- * 2: restart (S1 => S4 => S1)
- */
- if (val > 2)
- return ;
- val_reg = pmusvcc_reg->system_set_svcc &(~SYSTEM_SET_SVCC_ONOFF_RST_EN_MASK);
- pmusvcc_reg->system_set_svcc = val_reg | SYSTEM_SET_SVCC_ONOFF_RST_EN(val);
- k_busy_wait(300);
- }
- /* @brief check if the onoff key has been pressed or not */
- bool soc_pmu_is_onoff_key_pressed(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- /* if 1 indicates that onoff key has been pressed */
- if (pmusvcc_reg->system_set_svcc & SYSTEM_SET_SVCC_ONOFF_PRES)
- return true;
- return false;
- }
- /* @brief configure the long press on-off key reset/restart time */
- void soc_pmu_config_onoffkey_reset_time(uint8_t val)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- if (val) {
- pmusvcc_reg->system_set_svcc |= SYSTEM_SET_SVCC_ONOFF_RST_TIME; /* 12s */
- } else {
- pmusvcc_reg->system_set_svcc &= ~SYSTEM_SET_SVCC_ONOFF_RST_TIME; /* 8s */
- }
- k_busy_wait(300);
- }
- #ifdef CONFIG_PMU_COUNTER8HZ_SYNC_TIMEOUT_US
- /* @brief counter 8hz clock enable */
- void soc_pmu_counter8hz_enable(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- LOG_DBG("counter8hz_svcc:0x%x", pmusvcc_reg->counter8hz_svcc);
- /* clock source select LOSC */
- if (!(pmusvcc_reg->counter8hz_svcc & PMU_COUNTER8HZ_SVCC_COUNTER_EN)) {
- #if (CONFIG_RTC_CLK_SOURCE == 1)
- pmusvcc_reg->counter8hz_svcc |= \
- (PMU_COUNTER8HZ_SVCC_CLK_SEL_LOSC | PMU_COUNTER8HZ_SVCC_COUNTER_EN);
- #else
- pmusvcc_reg->counter8hz_svcc |= PMU_COUNTER8HZ_SVCC_COUNTER_EN;
- #endif
- k_busy_wait(300);
- }
- }
- /* @brief get counter8hz and the retval is by cycles */
- int soc_pmu_get_counter8hz_cycles(bool is_sync)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- if (!(pmusvcc_reg->counter8hz_svcc
- & PMU_COUNTER8HZ_SVCC_COUNTER_EN)) {
- LOG_ERR("counter8hz does not enable yet");
- return -EACCES;
- }
- if (is_sync) {
- /* clear counter8hz pending */
- pmuvdd_reg->pmu_det |= PMU_DET_COUNTR8HZ_PD;
- /* wait a new counter8hz pending */
- uint32_t cur_time = k_cycle_get_32();
- while (!(pmuvdd_reg->pmu_det & PMU_DET_COUNTR8HZ_PD)) {
- if (k_cyc_to_us_floor32(k_cycle_get_32() - cur_time) >=
- CONFIG_PMU_COUNTER8HZ_SYNC_TIMEOUT_US) {
- LOG_ERR("wait counter8hz pending timeout");
- return -ETIMEDOUT;
- }
- k_sleep(K_MSEC(1));
- }
- }
- return (pmusvcc_reg->counter8hz_svcc & PMU_COUNTER8HZ_SVCC_COUNTER_VAL);
- }
- /* @brief enable PMU alarm 8hz */
- int soc_pmu_alarm8hz_enable(uint32_t alarm_msec)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- uint32_t alarm8hz_cycles, new_alarm8hz_cycles, reg;
- int ret;
- /* clear alarm 8Hz pending */
- if (pmusvcc_reg->wake_pd_svcc & WAKE_PD_SVCC_ALARM8HZ_PD) {
- pmusvcc_reg->wake_pd_svcc |= WAKE_PD_SVCC_ALARM8HZ_PD;
- k_busy_wait(300);
- }
- alarm8hz_cycles = (alarm_msec + 124) / 125;
- #if (CONFIG_RTC_CLK_SOURCE == 2) // rc32k inaccurate, need calibration
- uint32_t rc32k_freq;
- rc32k_freq = acts_clock_rc32k_set_cal_cyc(100);
- printk("rc32k_freq=%d set 8hz=%d,", rc32k_freq, alarm8hz_cycles);
- alarm8hz_cycles = (uint64_t)alarm8hz_cycles*rc32k_freq/32768;
- printk("cal alarm8hz=%d cur_8hz=%d\n", alarm8hz_cycles, soc_pmu_get_counter8hz_cycles(false));
- #endif
- if (alarm8hz_cycles < 3) {
- LOG_ERR("invalid alarm8hz msec:%d", alarm_msec);
- return -EINVAL;
- }
- ret = soc_pmu_get_counter8hz_cycles(false);
- if (ret < 0) {
- LOG_ERR("failed to get counter8hz");
- return ret;
- }
- new_alarm8hz_cycles = ret + alarm8hz_cycles;
- /* 8Hz counter overflow */
- if (new_alarm8hz_cycles > 0x3FFFFFF)
- new_alarm8hz_cycles = new_alarm8hz_cycles - 0x3FFFFFF;
- reg = pmusvcc_reg->alarm8hz_svcc;
- reg &= ~PMU_ALARM8HZ_SVCC_ALARM_VAL_MASK;
- reg |= (new_alarm8hz_cycles & PMU_ALARM8HZ_SVCC_ALARM_VAL_MASK);
- pmusvcc_reg->alarm8hz_svcc = reg;
- pmusvcc_reg->wake_ctl_svcc |= WAKE_CTL_SVCC_ALARM8HZ_WKEN;
- pmuvdd_reg->pmu_intmask |= PMU_INTMASK_ALARM8HZ_INTEN;
- k_busy_wait(300);
- return 0;
- }
- /* @brief disable PMU alarm8hz */
- void soc_pmu_alarm8hz_disable(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- /* clear alarm 8Hz pending */
- if (pmusvcc_reg->wake_pd_svcc & WAKE_PD_SVCC_ALARM8HZ_PD) {
- pmusvcc_reg->wake_pd_svcc |= WAKE_PD_SVCC_ALARM8HZ_PD;
- k_busy_wait(300);
- }
- pmuvdd_reg->pmu_intmask &= ~PMU_INTMASK_ALARM8HZ_INTEN;
- pmusvcc_reg->wake_ctl_svcc &= ~WAKE_CTL_SVCC_ALARM8HZ_WKEN;
- pmusvcc_reg->alarm8hz_svcc &= ~PMU_ALARM8HZ_SVCC_ALARM_VAL_MASK;
- k_busy_wait(300);
- }
- /* @brief get alarm8hz cycles */
- int soc_pmu_get_alarm8hz(void)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- return pmusvcc_reg->alarm8hz_svcc & PMU_ALARM8HZ_SVCC_ALARM_VAL_MASK;
- }
- /*return rc32k freq*/
- uint32_t acts_clock_rc32k_set_cal_cyc(uint32_t cal_cyc)
- {
- uint32_t cnt;
- uint64_t tmp = 32000000;
- sys_write32(0, RC32K_CAL);
- soc_udelay(300);
- sys_write32((cal_cyc << 8)|1, RC32K_CAL);
- soc_udelay(300);
- /* wait calibration done */
- while (!(sys_read32(RC32K_CAL) & (1 << 4))){}
- cnt = sys_read32(RC32K_COUNT);
- if(cnt){
- cnt = tmp*cal_cyc/cnt;
- }
- LOG_INF("cal freq=%d\n", cnt);
- return cnt;
- }
- void soc_pmu_set_vdd_voltage(uint32_t volt_mv)
- {
- unsigned int sel;
- if (volt_mv < 550 || volt_mv > 1300)
- return ;
- sel = (volt_mv - 550) / 50;
- sel = (sel << 4) | sel; // set vdd s1 adn s1ml
- sys_write32((sys_read32(VOUT_CTL1_S1M) & ~(0xff)) | (sel), VOUT_CTL1_S1M);
- soc_udelay(33);
- }
- #endif
- #if 0
- static void soc_pmu_isr(void *arg)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- struct detect_param_t *detect_param = NULL;
- ARG_UNUSED(arg);
- uint32_t pending = pmusvcc_reg->wake_pd_svcc;
- LOG_DBG("pmu pending:0x%x", pending);
- if (pending & WAKE_PD_SVCC_REMOTE_PD) {
- /* Both REMOTE and ONOFF key are connected with WIO0.
- * Once the ONOFF key are pressed, the REMOTE key pending will also trigger.
- */
- if (pending & WAKE_PD_SVCC_WIO0LV_PD) {
- if (ctx->onoff_short_detect) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_ONOFF);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_PRESSED);
- }
- /* If ONOFF and REMOTE key use the same WIO pin, ignore the REMOTE key pending when WIO low voltage. */
- if (ctx->onoff_remote_same_wio)
- goto out;
- }
- /* disable remote interrupt and the remote device will enable interrupt through register interface again */
- pmuvdd_reg->pmu_intmask &= ~PMU_INTMASK_REMOTE_INTEN;
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_REMOTE);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_PRESSED);
- } else if (pending & WAKE_PD_SVCC_ONOFF_L_PD) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_ONOFF);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_LONG_PRESSED);
- } else if (pending & WAKE_PD_SVCC_ONOFF_S_PD) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_ONOFF);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_PRESSED);
- } else if (pending & WAKE_PD_SVCC_WIO0LV_PD) {
- if (ctx->onoff_short_detect) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_ONOFF);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_PRESSED);
- }
- }
- if (pending & WAKE_PD_SVCC_DC5VOUT_PD) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_DC5V);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_OUT);
- }
- if (pending & WAKE_PD_SVCC_DC5VIN_PD) {
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_DC5V);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_IN);
- }
- /* check whether counter8hz pending */
- if (pmuvdd_reg->pmu_det & PMU_DET_COUNTR8HZ_PD) {
- /* clear counter8hz pending */
- pmuvdd_reg->pmu_det |= PMU_DET_COUNTR8HZ_PD;
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_COUNTER8HZ);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_TIME_ON);
- }
- /* check whether alarm8hz pending */
- if (pmusvcc_reg->alarm8hz_svcc & PMU_ALARM8HZ_SVCC_PD) {
- /* clear alarm8hz pending */
- pmusvcc_reg->wake_pd_svcc |= WAKE_PD_SVCC_ALARM8HZ_PD;
- detect_param = soc_pmu_find_detect_dev(ctx, PMU_DETECT_DEV_ALARM8HZ);
- if (detect_param)
- detect_param->notify(detect_param->cb_data, PMU_NOTIFY_STATE_TIME_ON);
- }
- out:
- /* counter8Hz irq pending is shared with WAKE_PD_SVCC */
- if (pending)
- pmusvcc_reg->wake_pd_svcc = pending;
- }
- static void soc_pmu_irq_config(void)
- {
- IRQ_CONNECT(IRQ_ID_PMU, CONFIG_PMU_IRQ_PRI,
- soc_pmu_isr,
- NULL, 0);
- irq_enable(IRQ_ID_PMU);
- }
- /* @brief PMUVDD and PMUSVCC initialization */
- static int soc_pmu_init(const struct device *dev)
- {
- struct pmu_context_t *ctx = get_pmu_context();
- struct acts_pmusvcc *pmusvcc_reg = get_pmusvcc_reg_base(ctx);
- struct acts_pmuvdd *pmuvdd_reg = get_pmuvdd_reg_base(ctx);
- ARG_UNUSED(dev);
- soc_pmu_get_wakeup_source();
- /* by default to enable DC5V plug in/out detection */
- pmusvcc_reg->wake_ctl_svcc |= (WAKE_CTL_SVCC_DC5VOUT_WKEN | WAKE_CTL_SVCC_DC5VIN_WKEN);
- pmuvdd_reg->pmu_intmask |= (PMU_INTMASK_DC5VIN_INTEN | PMU_INTMASK_DC5VOUT_INTEN);
- if (ctx->onoff_short_detect) {
- pmusvcc_reg->wake_ctl_svcc |= WAKE_CTL_SVCC_WIO0LV_WKEN;
- pmuvdd_reg->pmu_intmask |= PMU_INTMASK_WIO0LV_INTEN;
- }
- pmusvcc_reg->wake_pd_svcc = pmusvcc_reg->wake_pd_svcc;
- if (!ctx->onoff_remote_same_wio)
- sys_write32(0, WIO0_CTL);
- soc_pmu_irq_config();
- return 0;
- }
- /*bootloader not init pmu*/
- //SYS_INIT(soc_pmu_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
- #endif
|