summaryrefslogtreecommitdiff
path: root/drivers/power/pmic/pca9450.c
blob: e99ece8fb0838d1adecf174d5a1b2b3eae8f0eb9 (plain)
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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2019 NXP
 */

#include <common.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 <asm/global_data.h>
#include <asm-generic/gpio.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/pca9450.h>

DECLARE_GLOBAL_DATA_PTR;

static const struct pmic_child_info pmic_children_info[] = {
	/* buck */
	{ .prefix = "b", .driver = PCA9450_REGULATOR_DRIVER},
	{ .prefix = "B", .driver = PCA9450_REGULATOR_DRIVER},
	/* ldo */
	{ .prefix = "l", .driver = PCA9450_REGULATOR_DRIVER},
	{ .prefix = "L", .driver = PCA9450_REGULATOR_DRIVER},
	{ },
};

struct pca9450_priv {
	struct gpio_desc *sd_vsel_gpio;
};

static int pca9450_reg_count(struct udevice *dev)
{
	return PCA9450_REG_NUM;
}

static int pca9450_write(struct udevice *dev, uint reg, const uint8_t *buff,
			 int len)
{
	if (dm_i2c_write(dev, reg, buff, len)) {
		pr_err("write error to device: %p register: %#x!", dev, reg);
		return -EIO;
	}

	return 0;
}

static int pca9450_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!", dev, reg);
		return -EIO;
	}

	return 0;
}

static int pca9450_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 pca9450_probe(struct udevice *dev)
{
	struct pca9450_priv *priv = dev_get_priv(dev);
	unsigned int reset_ctrl;
	int ret = 0;

	if (CONFIG_IS_ENABLED(DM_GPIO) && CONFIG_IS_ENABLED(DM_REGULATOR_PCA9450)) {
		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 = PCA9450_PMIC_RESET_WDOG_B_CFG_WARM;
	else
		reset_ctrl = PCA9450_PMIC_RESET_WDOG_B_CFG_COLD_LDO12;

	return pmic_clrsetbits(dev, PCA9450_RESET_CTRL,
			       PCA9450_PMIC_RESET_WDOG_B_CFG_MASK, reset_ctrl);
}

static struct dm_pmic_ops pca9450_ops = {
	.reg_count = pca9450_reg_count,
	.read = pca9450_read,
	.write = pca9450_write,
};

static const struct udevice_id pca9450_ids[] = {
	{ .compatible = "nxp,pca9450a", .data = NXP_CHIP_TYPE_PCA9450A, },
	{ .compatible = "nxp,pca9450b", .data = NXP_CHIP_TYPE_PCA9450BC, },
	{ .compatible = "nxp,pca9450c", .data = NXP_CHIP_TYPE_PCA9450BC, },
	{ .compatible = "nxp,pca9451a", .data = NXP_CHIP_TYPE_PCA9451A, },
	{ }
};

U_BOOT_DRIVER(pmic_pca9450) = {
	.name = "pca9450 pmic",
	.id = UCLASS_PMIC,
	.of_match = pca9450_ids,
	.bind = pca9450_bind,
	.probe = pca9450_probe,
	.ops = &pca9450_ops,
	.priv_auto = sizeof(struct pca9450_priv),
};