blob: f2076afff4354321ee0c0f302214b5bf8fce4543 [file] [log] [blame]
Svyatoslav Ryhelcf77d732025-02-01 16:02:45 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <dm.h>
7#include <dm/lists.h>
8#include <log.h>
9#include <power/pmic.h>
10#include <power/cpcap.h>
11#include <spi.h>
12#include <linux/delay.h>
13#include <linux/err.h>
14
Svyatoslav Ryhel2f98a672025-03-17 20:49:22 +020015static const struct pmic_child_info pmic_children_info[] = {
16 { .prefix = "sw", .driver = CPCAP_SW_DRIVER },
17 { .prefix = "v", .driver = CPCAP_LDO_DRIVER },
18 { },
19};
20
Svyatoslav Ryhelcf77d732025-02-01 16:02:45 +020021static int cpcap_write(struct udevice *dev, uint reg, const uint8_t *buff, int len)
22{
23 u8 buf[4];
24 u16 data = *(u16 *)buff;
25 int ret;
26
27 buf[0] = ((reg >> 8) & 0xff) | 0x80;
28 buf[1] = reg & 0xff;
29 buf[2] = data >> 8 & 0xff;
30 buf[3] = data & 0xff;
31
32 ret = dm_spi_xfer(dev, 32, buf, NULL, SPI_XFER_ONCE);
33
34 log_debug("%s: reg 0x%x, data 0x%04x, ret %d\n", __func__, reg, data, ret);
35
36 return ret;
37}
38
39static int cpcap_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
40{
41 u8 buf[4];
42 int ret;
43
44 buf[0] = (reg >> 8) & 0xff;
45 buf[1] = reg & 0xff;
46 buf[2] = 0;
47 buf[3] = 0;
48
49 ret = dm_spi_xfer(dev, 32, buf, buf, SPI_XFER_ONCE);
50 *buff = (buf[2] << 8) | buf[3];
51
52 log_debug("%s: reg 0x%x, data 0x%04x, ret %d\n", __func__, reg, *buff, ret);
53 return ret;
54}
55
Svyatoslav Ryhel2f98a672025-03-17 20:49:22 +020056static int cpcap_bind(struct udevice *dev)
57{
58 ofnode regulators_node;
59 int children;
60
61 /* Regulator device node of PMIC */
62 regulators_node = dev_read_subnode(dev, "regulator");
63 if (!ofnode_valid(regulators_node)) {
64 log_err("%s regulator subnode not found!\n", dev->name);
65 return -ENXIO;
66 }
67
68 /* Actual regulators container */
69 regulators_node = ofnode_find_subnode(regulators_node, "regulators");
70 if (!ofnode_valid(regulators_node)) {
71 log_err("%s regulators subnode not found!\n", dev->name);
72 return -ENXIO;
73 }
74
75 debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
76
77 children = pmic_bind_children(dev, regulators_node, pmic_children_info);
78 if (!children)
79 log_err("%s - no child found\n", dev->name);
80
81 return dm_scan_fdt_dev(dev);
82}
83
Svyatoslav Ryhelcf77d732025-02-01 16:02:45 +020084static int cpcap_probe(struct udevice *dev)
85{
86 struct spi_slave *slave = dev_get_parent_priv(dev);
87 int ret;
88
89 ret = spi_claim_bus(slave);
90 if (ret) {
91 log_err("SPI bus allocation failed (%d)\n", ret);
92 return ret;
93 }
94
95 u16 id = pmic_reg_read(dev, CPCAP_REG_VERSC1);
96
97 u16 ven = (id >> 6) & 0x7;
98 u16 rev = ((id >> 3) & 0x7) | ((id << 3) & 0x38);
99
100 log_debug("%s: vendor %s rev: %i.%i (%x)\n", __func__,
101 ven == CPCAP_VENDOR_ST ? "ST" : "TI",
102 CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
103 rev);
104 return 0;
105}
106
107static struct dm_pmic_ops cpcap_ops = {
108 .read = cpcap_read,
109 .write = cpcap_write,
110};
111
112static const struct udevice_id cpcap_ids[] = {
113 { .compatible = "motorola,cpcap" },
114 { .compatible = "st,6556002" },
115 { }
116};
117
118U_BOOT_DRIVER(pmic_cpcap) = {
119 .name = "cpcap_pmic",
120 .id = UCLASS_PMIC,
121 .of_match = cpcap_ids,
Svyatoslav Ryhel2f98a672025-03-17 20:49:22 +0200122 .bind = cpcap_bind,
Svyatoslav Ryhelcf77d732025-02-01 16:02:45 +0200123 .probe = cpcap_probe,
124 .ops = &cpcap_ops,
125};