1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 NXP
*/
#include <asm/global_data.h>
#include <asm-generic/gpio.h>
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <i2c.h>
#include <linux/err.h>
#include <log.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/pf9453.h>
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
/* buck */
{ .prefix = "b", .driver = PF9453_REGULATOR_DRIVER},
{ .prefix = "B", .driver = PF9453_REGULATOR_DRIVER},
/* ldo */
{ .prefix = "l", .driver = PF9453_REGULATOR_DRIVER},
{ .prefix = "L", .driver = PF9453_REGULATOR_DRIVER},
{ },
};
struct pf9453_priv {
struct gpio_desc *sd_vsel_gpio;
};
static int pf9453_reg_count(struct udevice *dev)
{
return PF9453_REG_NUM;
}
static bool is_reg_protect(uint reg)
{
switch (reg) {
case PF9453_BUCK1OUT:
case PF9453_BUCK2OUT:
case PF9453_BUCK3OUT:
case PF9453_BUCK4OUT:
case PF9453_LDO1OUT_L:
case PF9453_LDO1OUT_H:
case PF9453_LDO2OUT:
case PF9453_LDOSNVS_CFG1:
case PF9453_BUCK2OUT_MAX_LIMIT:
case PF9453_BUCK2OUT_MIN_LIMIT:
return true;
default:
return false;
}
}
static int pf9453_write(struct udevice *dev, uint reg, const uint8_t *buff, int len)
{
bool is_pro;
u32 val = PF9453_UNLOCK_KEY;
is_pro = is_reg_protect(reg);
if (is_pro) {
if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
pr_err("write error to device: %p register: %#x!\n", dev, reg);
return -EIO;
}
if (dm_i2c_write(dev, reg, buff, len)) {
pr_err("write error to device: %p register: %#x!\n", dev, reg);
return -EIO;
}
val = PF9453_LOCK_KEY;
if (dm_i2c_write(dev, PF9453_REG_LOCK, (uint8_t *)&val, 1)) {
pr_err("write error to device: %p register: %#x!\n", dev, reg);
return -EIO;
}
} else {
if (dm_i2c_write(dev, reg, buff, len)) {
pr_err("write error to device: %p register: %#x!\n", dev, reg);
return -EIO;
}
}
return 0;
}
static int pf9453_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
if (dm_i2c_read(dev, reg, buff, len)) {
pr_err("read error from device: %p register: %#x!\n", dev, reg);
return -EIO;
}
return 0;
}
static int pf9453_bind(struct udevice *dev)
{
int children;
ofnode regulators_node;
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
debug("%s: %s regulators subnode not found!", __func__,
dev->name);
return -ENXIO;
}
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
children = pmic_bind_children(dev, regulators_node,
pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
/* Always return success for this device */
return 0;
}
static int pf9453_probe(struct udevice *dev)
{
struct pf9453_priv *priv = dev_get_priv(dev);
unsigned int reset_ctrl;
int ret = 0;
if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PF9453)) {
priv->sd_vsel_gpio = devm_gpiod_get_optional(dev, "sd-vsel",
GPIOD_IS_OUT |
GPIOD_IS_OUT_ACTIVE);
if (IS_ERR(priv->sd_vsel_gpio)) {
ret = PTR_ERR(priv->sd_vsel_gpio);
dev_err(dev, "Failed to request SD_VSEL GPIO: %d\n", ret);
if (ret)
return ret;
}
}
if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset"))
reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_WARM;
else
reset_ctrl = PF9453_PMIC_RESET_WDOG_B_CFG_COLD;
return pmic_clrsetbits(dev, PF9453_RESET_CTRL,
PF9453_PMIC_RESET_WDOG_B_CFG_MASK, reset_ctrl);
}
static struct dm_pmic_ops pf9453_ops = {
.reg_count = pf9453_reg_count,
.read = pf9453_read,
.write = pf9453_write,
};
static const struct udevice_id pf9453_ids[] = {
{ .compatible = "nxp,pf9453", .data = NXP_CHIP_TYPE_PF9453, },
{ }
};
U_BOOT_DRIVER(pmic_pf9453) = {
.name = "pf9453 pmic",
.id = UCLASS_PMIC,
.of_match = pf9453_ids,
.bind = pf9453_bind,
.probe = pf9453_probe,
.ops = &pf9453_ops,
.priv_auto = sizeof(struct pf9453_priv),
};
|