1*d4e6f98dSHope Wang /*
2*d4e6f98dSHope Wang * Copyright (c) 2025, Mediatek Inc. All rights reserved.
3*d4e6f98dSHope Wang *
4*d4e6f98dSHope Wang * SPDX-License-Identifier: BSD-3-Clause
5*d4e6f98dSHope Wang */
6*d4e6f98dSHope Wang
7*d4e6f98dSHope Wang #include <errno.h>
8*d4e6f98dSHope Wang
9*d4e6f98dSHope Wang #include <common/debug.h>
10*d4e6f98dSHope Wang #include <drivers/pmic/pmic_psc.h>
11*d4e6f98dSHope Wang #ifdef CONFIG_MTK_PMIC_SHUTDOWN_CFG
12*d4e6f98dSHope Wang #include <drivers/pmic/pmic_shutdown_cfg.h>
13*d4e6f98dSHope Wang #endif
14*d4e6f98dSHope Wang
15*d4e6f98dSHope Wang #define ERR_INVALID_ARGS -EINVAL
16*d4e6f98dSHope Wang #define ERR_NOT_CONFIGURED -ENODEV
17*d4e6f98dSHope Wang
18*d4e6f98dSHope Wang static const struct pmic_psc_config *pmic_psc;
19*d4e6f98dSHope Wang
read_pmic_psc_reg(enum pmic_psc_reg_name reg_name)20*d4e6f98dSHope Wang static uint32_t read_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
21*d4e6f98dSHope Wang {
22*d4e6f98dSHope Wang uint32_t val = 0;
23*d4e6f98dSHope Wang const struct pmic_psc_reg *reg;
24*d4e6f98dSHope Wang
25*d4e6f98dSHope Wang if (reg_name >= pmic_psc->reg_size)
26*d4e6f98dSHope Wang return 0;
27*d4e6f98dSHope Wang
28*d4e6f98dSHope Wang reg = &pmic_psc->regs[reg_name];
29*d4e6f98dSHope Wang pmic_psc->read_field(reg->reg_addr, &val, reg->reg_mask, reg->reg_shift);
30*d4e6f98dSHope Wang return val;
31*d4e6f98dSHope Wang }
32*d4e6f98dSHope Wang
set_pmic_psc_reg(enum pmic_psc_reg_name reg_name)33*d4e6f98dSHope Wang static int set_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
34*d4e6f98dSHope Wang {
35*d4e6f98dSHope Wang const struct pmic_psc_reg *reg;
36*d4e6f98dSHope Wang
37*d4e6f98dSHope Wang if (reg_name >= pmic_psc->reg_size)
38*d4e6f98dSHope Wang return ERR_INVALID_ARGS;
39*d4e6f98dSHope Wang
40*d4e6f98dSHope Wang reg = &pmic_psc->regs[reg_name];
41*d4e6f98dSHope Wang pmic_psc->write_field(reg->reg_addr, 1, reg->reg_mask, reg->reg_shift);
42*d4e6f98dSHope Wang return 0;
43*d4e6f98dSHope Wang }
44*d4e6f98dSHope Wang
clr_pmic_psc_reg(enum pmic_psc_reg_name reg_name)45*d4e6f98dSHope Wang static int clr_pmic_psc_reg(enum pmic_psc_reg_name reg_name)
46*d4e6f98dSHope Wang {
47*d4e6f98dSHope Wang const struct pmic_psc_reg *reg;
48*d4e6f98dSHope Wang
49*d4e6f98dSHope Wang if (reg_name >= pmic_psc->reg_size)
50*d4e6f98dSHope Wang return ERR_INVALID_ARGS;
51*d4e6f98dSHope Wang
52*d4e6f98dSHope Wang reg = &pmic_psc->regs[reg_name];
53*d4e6f98dSHope Wang pmic_psc->write_field(reg->reg_addr, 0, reg->reg_mask, reg->reg_shift);
54*d4e6f98dSHope Wang return 0;
55*d4e6f98dSHope Wang }
56*d4e6f98dSHope Wang
enable_pmic_smart_reset(bool enable)57*d4e6f98dSHope Wang int enable_pmic_smart_reset(bool enable)
58*d4e6f98dSHope Wang {
59*d4e6f98dSHope Wang if (!pmic_psc)
60*d4e6f98dSHope Wang return ERR_NOT_CONFIGURED;
61*d4e6f98dSHope Wang if (enable)
62*d4e6f98dSHope Wang set_pmic_psc_reg(RG_SMART_RST_MODE);
63*d4e6f98dSHope Wang else
64*d4e6f98dSHope Wang clr_pmic_psc_reg(RG_SMART_RST_MODE);
65*d4e6f98dSHope Wang return 0;
66*d4e6f98dSHope Wang }
67*d4e6f98dSHope Wang
enable_pmic_smart_reset_shutdown(bool enable)68*d4e6f98dSHope Wang int enable_pmic_smart_reset_shutdown(bool enable)
69*d4e6f98dSHope Wang {
70*d4e6f98dSHope Wang if (!pmic_psc)
71*d4e6f98dSHope Wang return ERR_NOT_CONFIGURED;
72*d4e6f98dSHope Wang if (enable)
73*d4e6f98dSHope Wang set_pmic_psc_reg(RG_SMART_RST_SDN_EN);
74*d4e6f98dSHope Wang else
75*d4e6f98dSHope Wang clr_pmic_psc_reg(RG_SMART_RST_SDN_EN);
76*d4e6f98dSHope Wang return 0;
77*d4e6f98dSHope Wang }
78*d4e6f98dSHope Wang
platform_cold_reset(void)79*d4e6f98dSHope Wang int platform_cold_reset(void)
80*d4e6f98dSHope Wang {
81*d4e6f98dSHope Wang if (!pmic_psc)
82*d4e6f98dSHope Wang return ERR_NOT_CONFIGURED;
83*d4e6f98dSHope Wang /* Some PMICs may not support cold reset */
84*d4e6f98dSHope Wang if (!pmic_psc->regs[RG_CRST].reg_addr)
85*d4e6f98dSHope Wang return ERR_NOT_CONFIGURED;
86*d4e6f98dSHope Wang set_pmic_psc_reg(RG_CRST);
87*d4e6f98dSHope Wang return 0;
88*d4e6f98dSHope Wang }
89*d4e6f98dSHope Wang
platform_power_hold(bool hold)90*d4e6f98dSHope Wang int platform_power_hold(bool hold)
91*d4e6f98dSHope Wang {
92*d4e6f98dSHope Wang int use_spmi_cmd_sdn = 0;
93*d4e6f98dSHope Wang
94*d4e6f98dSHope Wang if (!pmic_psc)
95*d4e6f98dSHope Wang return ERR_NOT_CONFIGURED;
96*d4e6f98dSHope Wang if (hold)
97*d4e6f98dSHope Wang set_pmic_psc_reg(RG_PWRHOLD);
98*d4e6f98dSHope Wang else {
99*d4e6f98dSHope Wang #ifdef CONFIG_MTK_PMIC_SHUTDOWN_CFG
100*d4e6f98dSHope Wang use_spmi_cmd_sdn = pmic_shutdown_cfg();
101*d4e6f98dSHope Wang #endif
102*d4e6f98dSHope Wang if (use_spmi_cmd_sdn == 1)
103*d4e6f98dSHope Wang spmi_shutdown();
104*d4e6f98dSHope Wang else
105*d4e6f98dSHope Wang clr_pmic_psc_reg(RG_PWRHOLD);
106*d4e6f98dSHope Wang }
107*d4e6f98dSHope Wang return 0;
108*d4e6f98dSHope Wang }
109*d4e6f98dSHope Wang
pmic_psc_register(const struct pmic_psc_config * psc)110*d4e6f98dSHope Wang int pmic_psc_register(const struct pmic_psc_config *psc)
111*d4e6f98dSHope Wang {
112*d4e6f98dSHope Wang if (!psc || !psc->regs || !psc->read_field || !psc->write_field)
113*d4e6f98dSHope Wang return ERR_INVALID_ARGS;
114*d4e6f98dSHope Wang pmic_psc = psc;
115*d4e6f98dSHope Wang INFO("POWER_HOLD=0x%x\n", read_pmic_psc_reg(RG_PWRHOLD));
116*d4e6f98dSHope Wang return 0;
117*d4e6f98dSHope Wang }
118