]>
Commit | Line | Data |
---|---|---|
4d9057e8 PM |
1 | /* |
2 | * Copyright (C) 2014-2015 Samsung Electronics | |
3 | * Przemyslaw Marczak <p.marczak@samsung.com> | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <fdtdec.h> | |
10 | #include <errno.h> | |
11 | #include <dm.h> | |
e15bb3e6 | 12 | #include <vsprintf.h> |
4d9057e8 PM |
13 | #include <dm/lists.h> |
14 | #include <dm/device-internal.h> | |
15 | #include <dm/uclass-internal.h> | |
16 | #include <power/pmic.h> | |
17 | #include <linux/ctype.h> | |
18 | ||
19 | DECLARE_GLOBAL_DATA_PTR; | |
20 | ||
1f2b4b06 | 21 | #if CONFIG_IS_ENABLED(PMIC_CHILDREN) |
7a869e6c | 22 | int pmic_bind_children(struct udevice *pmic, ofnode parent, |
f415a3ec | 23 | const struct pmic_child_info *child_info) |
4d9057e8 PM |
24 | { |
25 | const struct pmic_child_info *info; | |
4d9057e8 PM |
26 | struct driver *drv; |
27 | struct udevice *child; | |
28 | const char *node_name; | |
bf802f5d | 29 | const char *reg_name; |
4d9057e8 | 30 | int bind_count = 0; |
7a869e6c | 31 | ofnode node; |
4d9057e8 PM |
32 | int prefix_len; |
33 | int ret; | |
34 | ||
35 | debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, | |
e160f7d4 | 36 | dev_of_offset(pmic)); |
4d9057e8 | 37 | |
3991f42e | 38 | ofnode_for_each_subnode(node, parent) { |
7a869e6c | 39 | node_name = ofnode_get_name(node); |
4d9057e8 | 40 | |
7a869e6c | 41 | debug("* Found child node: '%s'\n", node_name); |
4d9057e8 PM |
42 | |
43 | child = NULL; | |
f415a3ec | 44 | for (info = child_info; info->prefix && info->driver; info++) { |
e15bb3e6 SG |
45 | debug(" - compatible prefix: '%s'\n", info->prefix); |
46 | ||
4d9057e8 | 47 | prefix_len = strlen(info->prefix); |
bf802f5d FB |
48 | if (strncmp(info->prefix, node_name, prefix_len)) { |
49 | reg_name = ofnode_read_string(node, | |
50 | "regulator-name"); | |
51 | if (!reg_name) | |
52 | continue; | |
53 | if (strncmp(info->prefix, reg_name, prefix_len)) | |
54 | continue; | |
55 | } | |
4d9057e8 | 56 | |
4d9057e8 PM |
57 | drv = lists_driver_lookup_name(info->driver); |
58 | if (!drv) { | |
59 | debug(" - driver: '%s' not found!\n", | |
60 | info->driver); | |
61 | continue; | |
62 | } | |
63 | ||
64 | debug(" - found child driver: '%s'\n", drv->name); | |
65 | ||
7a869e6c SG |
66 | ret = device_bind_with_driver_data(pmic, drv, node_name, |
67 | 0, node, &child); | |
4d9057e8 PM |
68 | if (ret) { |
69 | debug(" - child binding error: %d\n", ret); | |
70 | continue; | |
71 | } | |
72 | ||
73 | debug(" - bound child device: '%s'\n", child->name); | |
74 | ||
e15bb3e6 | 75 | child->driver_data = trailing_strtol(node_name); |
4d9057e8 PM |
76 | |
77 | debug(" - set 'child->driver_data': %lu\n", | |
78 | child->driver_data); | |
79 | break; | |
80 | } | |
81 | ||
82 | if (child) | |
83 | bind_count++; | |
84 | else | |
85 | debug(" - compatible prefix not found\n"); | |
86 | } | |
87 | ||
7a869e6c | 88 | debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); |
4d9057e8 PM |
89 | return bind_count; |
90 | } | |
1f2b4b06 | 91 | #endif |
4d9057e8 PM |
92 | |
93 | int pmic_get(const char *name, struct udevice **devp) | |
94 | { | |
95 | return uclass_get_device_by_name(UCLASS_PMIC, name, devp); | |
96 | } | |
97 | ||
98 | int pmic_reg_count(struct udevice *dev) | |
99 | { | |
100 | const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); | |
f415a3ec PM |
101 | |
102 | if (!ops || !ops->reg_count) | |
4d9057e8 PM |
103 | return -ENOSYS; |
104 | ||
f415a3ec | 105 | return ops->reg_count(dev); |
4d9057e8 PM |
106 | } |
107 | ||
108 | int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) | |
109 | { | |
110 | const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); | |
4d9057e8 PM |
111 | |
112 | if (!buffer) | |
113 | return -EFAULT; | |
114 | ||
115 | if (!ops || !ops->read) | |
116 | return -ENOSYS; | |
117 | ||
f415a3ec | 118 | return ops->read(dev, reg, buffer, len); |
4d9057e8 PM |
119 | } |
120 | ||
121 | int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) | |
122 | { | |
123 | const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); | |
4d9057e8 PM |
124 | |
125 | if (!buffer) | |
126 | return -EFAULT; | |
127 | ||
128 | if (!ops || !ops->write) | |
129 | return -ENOSYS; | |
130 | ||
f415a3ec | 131 | return ops->write(dev, reg, buffer, len); |
4d9057e8 PM |
132 | } |
133 | ||
6c69c7fb SG |
134 | int pmic_reg_read(struct udevice *dev, uint reg) |
135 | { | |
136 | u8 byte; | |
137 | int ret; | |
138 | ||
7d577999 | 139 | debug("%s: reg=%x", __func__, reg); |
6c69c7fb | 140 | ret = pmic_read(dev, reg, &byte, 1); |
7d577999 | 141 | debug(", value=%x, ret=%d\n", byte, ret); |
6c69c7fb SG |
142 | |
143 | return ret ? ret : byte; | |
144 | } | |
145 | ||
146 | int pmic_reg_write(struct udevice *dev, uint reg, uint value) | |
147 | { | |
148 | u8 byte = value; | |
7d577999 SG |
149 | int ret; |
150 | ||
151 | debug("%s: reg=%x, value=%x", __func__, reg, value); | |
152 | ret = pmic_write(dev, reg, &byte, 1); | |
153 | debug(", ret=%d\n", ret); | |
6c69c7fb | 154 | |
7d577999 | 155 | return ret; |
6c69c7fb SG |
156 | } |
157 | ||
158 | int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) | |
159 | { | |
160 | u8 byte; | |
161 | int ret; | |
162 | ||
163 | ret = pmic_reg_read(dev, reg); | |
164 | if (ret < 0) | |
165 | return ret; | |
166 | byte = (ret & ~clr) | set; | |
167 | ||
168 | return pmic_reg_write(dev, reg, byte); | |
169 | } | |
170 | ||
4d9057e8 PM |
171 | UCLASS_DRIVER(pmic) = { |
172 | .id = UCLASS_PMIC, | |
173 | .name = "pmic", | |
174 | }; |