Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
3
4#include <linux/cleanup.h>
5#include <linux/err.h>
6#include <linux/init.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/mutex.h>
10#include <linux/pm_domain.h>
11#include <linux/slab.h>
12#include <linux/of.h>
13#include <linux/platform_device.h>
14#include <linux/pm_opp.h>
15#include <soc/qcom/cmd-db.h>
16#include <soc/qcom/rpmh.h>
17#include <dt-bindings/power/qcom-rpmpd.h>
18#include <dt-bindings/power/qcom,rpmhpd.h>
19
20#define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd)
21
22#define RPMH_ARC_MAX_LEVELS 32
23
24/**
25 * struct rpmhpd - top level RPMh power domain resource data structure
26 * @dev: rpmh power domain controller device
27 * @pd: generic_pm_domain corresponding to the power domain
28 * @parent: generic_pm_domain corresponding to the parent's power domain
29 * @peer: A peer power domain in case Active only Voting is
30 * supported
31 * @active_only: True if it represents an Active only peer
32 * @corner: current corner
33 * @active_corner: current active corner
34 * @enable_corner: lowest non-zero corner
35 * @level: An array of level (vlvl) to corner (hlvl) mappings
36 * derived from cmd-db
37 * @level_count: Number of levels supported by the power domain. max
38 * being 16 (0 - 15)
39 * @enabled: true if the power domain is enabled
40 * @res_name: Resource name used for cmd-db lookup
41 * @addr: Resource address as looped up using resource name from
42 * cmd-db
43 * @state_synced: Indicator that sync_state has been invoked for the rpmhpd resource
44 * @skip_retention_level: Indicate that retention level should not be used for the power domain
45 */
46struct rpmhpd {
47 struct device *dev;
48 struct generic_pm_domain pd;
49 struct generic_pm_domain *parent;
50 struct rpmhpd *peer;
51 const bool active_only;
52 unsigned int corner;
53 unsigned int active_corner;
54 unsigned int enable_corner;
55 u32 level[RPMH_ARC_MAX_LEVELS];
56 size_t level_count;
57 bool enabled;
58 const char *res_name;
59 u32 addr;
60 bool state_synced;
61 bool skip_retention_level;
62};
63
64struct rpmhpd_desc {
65 struct rpmhpd **rpmhpds;
66 size_t num_pds;
67};
68
69static DEFINE_MUTEX(rpmhpd_lock);
70
71/* RPMH powerdomains */
72
73static struct rpmhpd cx_ao;
74static struct rpmhpd mx;
75static struct rpmhpd mx_ao;
76static struct rpmhpd cx = {
77 .pd = { .name = "cx", },
78 .peer = &cx_ao,
79 .res_name = "cx.lvl",
80};
81
82static struct rpmhpd cx_ao = {
83 .pd = { .name = "cx_ao", },
84 .active_only = true,
85 .peer = &cx,
86 .res_name = "cx.lvl",
87};
88
89static struct rpmhpd cx_ao_w_mx_parent;
90static struct rpmhpd cx_w_mx_parent = {
91 .pd = { .name = "cx", },
92 .peer = &cx_ao_w_mx_parent,
93 .parent = &mx.pd,
94 .res_name = "cx.lvl",
95};
96
97static struct rpmhpd cx_ao_w_mx_parent = {
98 .pd = { .name = "cx_ao", },
99 .active_only = true,
100 .peer = &cx_w_mx_parent,
101 .parent = &mx_ao.pd,
102 .res_name = "cx.lvl",
103};
104
105static struct rpmhpd dcx = {
106 .pd = { .name = "dcx", },
107 .res_name = "dcx.lvl",
108};
109
110static struct rpmhpd ebi = {
111 .pd = { .name = "ebi", },
112 .res_name = "ebi.lvl",
113};
114
115static struct rpmhpd gbx = {
116 .pd = { .name = "gbx", },
117 .res_name = "gbx.lvl",
118};
119
120static struct rpmhpd gfx = {
121 .pd = { .name = "gfx", },
122 .res_name = "gfx.lvl",
123};
124
125static struct rpmhpd lcx = {
126 .pd = { .name = "lcx", },
127 .res_name = "lcx.lvl",
128};
129
130static struct rpmhpd lmx = {
131 .pd = { .name = "lmx", },
132 .res_name = "lmx.lvl",
133};
134
135static struct rpmhpd mmcx_ao;
136static struct rpmhpd mmcx = {
137 .pd = { .name = "mmcx", },
138 .peer = &mmcx_ao,
139 .res_name = "mmcx.lvl",
140};
141
142static struct rpmhpd mmcx_ao = {
143 .pd = { .name = "mmcx_ao", },
144 .active_only = true,
145 .peer = &mmcx,
146 .res_name = "mmcx.lvl",
147};
148
149static struct rpmhpd mmcx_ao_w_cx_parent;
150static struct rpmhpd mmcx_w_cx_parent = {
151 .pd = { .name = "mmcx", },
152 .peer = &mmcx_ao_w_cx_parent,
153 .parent = &cx.pd,
154 .res_name = "mmcx.lvl",
155};
156
157static struct rpmhpd mmcx_ao_w_cx_parent = {
158 .pd = { .name = "mmcx_ao", },
159 .active_only = true,
160 .peer = &mmcx_w_cx_parent,
161 .parent = &cx_ao.pd,
162 .res_name = "mmcx.lvl",
163};
164
165static struct rpmhpd mss = {
166 .pd = { .name = "mss", },
167 .res_name = "mss.lvl",
168};
169
170static struct rpmhpd mx_ao;
171static struct rpmhpd mx = {
172 .pd = { .name = "mx", },
173 .peer = &mx_ao,
174 .res_name = "mx.lvl",
175};
176
177static struct rpmhpd mx_ao = {
178 .pd = { .name = "mx_ao", },
179 .active_only = true,
180 .peer = &mx,
181 .res_name = "mx.lvl",
182};
183
184static struct rpmhpd mxc_ao;
185static struct rpmhpd mxc = {
186 .pd = { .name = "mxc", },
187 .peer = &mxc_ao,
188 .res_name = "mxc.lvl",
189 .skip_retention_level = true,
190};
191
192static struct rpmhpd mxc_ao = {
193 .pd = { .name = "mxc_ao", },
194 .active_only = true,
195 .peer = &mxc,
196 .res_name = "mxc.lvl",
197 .skip_retention_level = true,
198};
199
200static struct rpmhpd nsp = {
201 .pd = { .name = "nsp", },
202 .res_name = "nsp.lvl",
203};
204
205static struct rpmhpd nsp0 = {
206 .pd = { .name = "nsp0", },
207 .res_name = "nsp0.lvl",
208};
209
210static struct rpmhpd nsp1 = {
211 .pd = { .name = "nsp1", },
212 .res_name = "nsp1.lvl",
213};
214
215static struct rpmhpd nsp2 = {
216 .pd = { .name = "nsp2", },
217 .res_name = "nsp2.lvl",
218};
219
220static struct rpmhpd qphy = {
221 .pd = { .name = "qphy", },
222 .res_name = "qphy.lvl",
223};
224
225static struct rpmhpd gmxc = {
226 .pd = { .name = "gmxc", },
227 .res_name = "gmxc.lvl",
228};
229
230/* Eliza RPMH powerdomains */
231static struct rpmhpd *eliza_rpmhpds[] = {
232 [RPMHPD_CX] = &cx,
233 [RPMHPD_CX_AO] = &cx_ao,
234 [RPMHPD_EBI] = &ebi,
235 [RPMHPD_GFX] = &gfx,
236 [RPMHPD_LCX] = &lcx,
237 [RPMHPD_LMX] = &lmx,
238 [RPMHPD_MSS] = &mss,
239 [RPMHPD_MX] = &mx,
240 [RPMHPD_MX_AO] = &mx_ao,
241 [RPMHPD_NSP] = &nsp,
242};
243
244static const struct rpmhpd_desc eliza_desc = {
245 .rpmhpds = eliza_rpmhpds,
246 .num_pds = ARRAY_SIZE(eliza_rpmhpds),
247};
248
249/* Milos RPMH powerdomains */
250static struct rpmhpd *milos_rpmhpds[] = {
251 [RPMHPD_CX] = &cx,
252 [RPMHPD_CX_AO] = &cx_ao,
253 [RPMHPD_EBI] = &ebi,
254 [RPMHPD_GFX] = &gfx,
255 [RPMHPD_LCX] = &lcx,
256 [RPMHPD_LMX] = &lmx,
257 [RPMHPD_MSS] = &mss,
258 [RPMHPD_MX] = &mx,
259 [RPMHPD_MX_AO] = &mx_ao,
260};
261
262static const struct rpmhpd_desc milos_desc = {
263 .rpmhpds = milos_rpmhpds,
264 .num_pds = ARRAY_SIZE(milos_rpmhpds),
265};
266
267/* SA8540P RPMH powerdomains */
268static struct rpmhpd *sa8540p_rpmhpds[] = {
269 [SC8280XP_CX] = &cx,
270 [SC8280XP_CX_AO] = &cx_ao,
271 [SC8280XP_EBI] = &ebi,
272 [SC8280XP_LCX] = &lcx,
273 [SC8280XP_LMX] = &lmx,
274 [SC8280XP_MMCX] = &mmcx,
275 [SC8280XP_MMCX_AO] = &mmcx_ao,
276 [SC8280XP_MX] = &mx,
277 [SC8280XP_MX_AO] = &mx_ao,
278 [SC8280XP_MXC] = &mxc,
279 [SC8280XP_MXC_AO] = &mxc_ao,
280 [SC8280XP_NSP] = &nsp,
281};
282
283static const struct rpmhpd_desc sa8540p_desc = {
284 .rpmhpds = sa8540p_rpmhpds,
285 .num_pds = ARRAY_SIZE(sa8540p_rpmhpds),
286};
287
288/* SA8775P RPMH power domains */
289static struct rpmhpd *sa8775p_rpmhpds[] = {
290 [SA8775P_CX] = &cx,
291 [SA8775P_CX_AO] = &cx_ao,
292 [SA8775P_EBI] = &ebi,
293 [SA8775P_GFX] = &gfx,
294 [SA8775P_LCX] = &lcx,
295 [SA8775P_LMX] = &lmx,
296 [SA8775P_MMCX] = &mmcx,
297 [SA8775P_MMCX_AO] = &mmcx_ao,
298 [SA8775P_MXC] = &mxc,
299 [SA8775P_MXC_AO] = &mxc_ao,
300 [SA8775P_MX] = &mx,
301 [SA8775P_MX_AO] = &mx_ao,
302 [SA8775P_NSP0] = &nsp0,
303 [SA8775P_NSP1] = &nsp1,
304};
305
306static const struct rpmhpd_desc sa8775p_desc = {
307 .rpmhpds = sa8775p_rpmhpds,
308 .num_pds = ARRAY_SIZE(sa8775p_rpmhpds),
309};
310
311/* SAR2130P RPMH powerdomains */
312static struct rpmhpd *sar2130p_rpmhpds[] = {
313 [RPMHPD_CX] = &cx,
314 [RPMHPD_CX_AO] = &cx_ao,
315 [RPMHPD_EBI] = &ebi,
316 [RPMHPD_GFX] = &gfx,
317 [RPMHPD_LCX] = &lcx,
318 [RPMHPD_LMX] = &lmx,
319 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
320 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
321 [RPMHPD_MSS] = &mss,
322 [RPMHPD_MX] = &mx,
323 [RPMHPD_MX_AO] = &mx_ao,
324 [RPMHPD_MXC] = &mxc,
325 [RPMHPD_MXC_AO] = &mxc_ao,
326 [RPMHPD_NSP] = &nsp,
327 [RPMHPD_QPHY] = &qphy,
328};
329
330static const struct rpmhpd_desc sar2130p_desc = {
331 .rpmhpds = sar2130p_rpmhpds,
332 .num_pds = ARRAY_SIZE(sar2130p_rpmhpds),
333};
334
335/* SDM670 RPMH powerdomains */
336static struct rpmhpd *sdm670_rpmhpds[] = {
337 [SDM670_CX] = &cx_w_mx_parent,
338 [SDM670_CX_AO] = &cx_ao_w_mx_parent,
339 [SDM670_GFX] = &gfx,
340 [SDM670_LCX] = &lcx,
341 [SDM670_LMX] = &lmx,
342 [SDM670_MSS] = &mss,
343 [SDM670_MX] = &mx,
344 [SDM670_MX_AO] = &mx_ao,
345};
346
347static const struct rpmhpd_desc sdm670_desc = {
348 .rpmhpds = sdm670_rpmhpds,
349 .num_pds = ARRAY_SIZE(sdm670_rpmhpds),
350};
351
352/* SDM845 RPMH powerdomains */
353static struct rpmhpd *sdm845_rpmhpds[] = {
354 [SDM845_CX] = &cx_w_mx_parent,
355 [SDM845_CX_AO] = &cx_ao_w_mx_parent,
356 [SDM845_EBI] = &ebi,
357 [SDM845_GFX] = &gfx,
358 [SDM845_LCX] = &lcx,
359 [SDM845_LMX] = &lmx,
360 [SDM845_MSS] = &mss,
361 [SDM845_MX] = &mx,
362 [SDM845_MX_AO] = &mx_ao,
363};
364
365static const struct rpmhpd_desc sdm845_desc = {
366 .rpmhpds = sdm845_rpmhpds,
367 .num_pds = ARRAY_SIZE(sdm845_rpmhpds),
368};
369
370/* SDX55 RPMH powerdomains */
371static struct rpmhpd *sdx55_rpmhpds[] = {
372 [SDX55_CX] = &cx_w_mx_parent,
373 [SDX55_MSS] = &mss,
374 [SDX55_MX] = &mx,
375};
376
377static const struct rpmhpd_desc sdx55_desc = {
378 .rpmhpds = sdx55_rpmhpds,
379 .num_pds = ARRAY_SIZE(sdx55_rpmhpds),
380};
381
382/* SDX65 RPMH powerdomains */
383static struct rpmhpd *sdx65_rpmhpds[] = {
384 [SDX65_CX] = &cx_w_mx_parent,
385 [SDX65_CX_AO] = &cx_ao_w_mx_parent,
386 [SDX65_MSS] = &mss,
387 [SDX65_MX] = &mx,
388 [SDX65_MX_AO] = &mx_ao,
389 [SDX65_MXC] = &mxc,
390};
391
392static const struct rpmhpd_desc sdx65_desc = {
393 .rpmhpds = sdx65_rpmhpds,
394 .num_pds = ARRAY_SIZE(sdx65_rpmhpds),
395};
396
397/* SDX75 RPMH powerdomains */
398static struct rpmhpd *sdx75_rpmhpds[] = {
399 [RPMHPD_CX] = &cx,
400 [RPMHPD_CX_AO] = &cx_ao,
401 [RPMHPD_MSS] = &mss,
402 [RPMHPD_MX] = &mx,
403 [RPMHPD_MX_AO] = &mx_ao,
404 [RPMHPD_MXC] = &mxc,
405};
406
407static const struct rpmhpd_desc sdx75_desc = {
408 .rpmhpds = sdx75_rpmhpds,
409 .num_pds = ARRAY_SIZE(sdx75_rpmhpds),
410};
411
412/* SM4450 RPMH powerdomains */
413static struct rpmhpd *sm4450_rpmhpds[] = {
414 [RPMHPD_CX] = &cx,
415 [RPMHPD_CX_AO] = &cx_ao,
416 [RPMHPD_EBI] = &ebi,
417 [RPMHPD_LMX] = &lmx,
418 [RPMHPD_MSS] = &mss,
419 [RPMHPD_MX] = &mx,
420};
421
422static const struct rpmhpd_desc sm4450_desc = {
423 .rpmhpds = sm4450_rpmhpds,
424 .num_pds = ARRAY_SIZE(sm4450_rpmhpds),
425};
426
427/* SM6350 RPMH powerdomains */
428static struct rpmhpd *sm6350_rpmhpds[] = {
429 [SM6350_CX] = &cx_w_mx_parent,
430 [SM6350_GFX] = &gfx,
431 [SM6350_LCX] = &lcx,
432 [SM6350_LMX] = &lmx,
433 [SM6350_MSS] = &mss,
434 [SM6350_MX] = &mx,
435};
436
437static const struct rpmhpd_desc sm6350_desc = {
438 .rpmhpds = sm6350_rpmhpds,
439 .num_pds = ARRAY_SIZE(sm6350_rpmhpds),
440};
441
442/* SM7150 RPMH powerdomains */
443static struct rpmhpd *sm7150_rpmhpds[] = {
444 [RPMHPD_CX] = &cx_w_mx_parent,
445 [RPMHPD_CX_AO] = &cx_ao_w_mx_parent,
446 [RPMHPD_GFX] = &gfx,
447 [RPMHPD_LCX] = &lcx,
448 [RPMHPD_LMX] = &lmx,
449 [RPMHPD_MX] = &mx,
450 [RPMHPD_MX_AO] = &mx_ao,
451 [RPMHPD_MSS] = &mss,
452};
453
454static const struct rpmhpd_desc sm7150_desc = {
455 .rpmhpds = sm7150_rpmhpds,
456 .num_pds = ARRAY_SIZE(sm7150_rpmhpds),
457};
458
459/* SM8150 RPMH powerdomains */
460static struct rpmhpd *sm8150_rpmhpds[] = {
461 [SM8150_CX] = &cx_w_mx_parent,
462 [SM8150_CX_AO] = &cx_ao_w_mx_parent,
463 [SM8150_EBI] = &ebi,
464 [SM8150_GFX] = &gfx,
465 [SM8150_LCX] = &lcx,
466 [SM8150_LMX] = &lmx,
467 [SM8150_MMCX] = &mmcx,
468 [SM8150_MMCX_AO] = &mmcx_ao,
469 [SM8150_MSS] = &mss,
470 [SM8150_MX] = &mx,
471 [SM8150_MX_AO] = &mx_ao,
472};
473
474static const struct rpmhpd_desc sm8150_desc = {
475 .rpmhpds = sm8150_rpmhpds,
476 .num_pds = ARRAY_SIZE(sm8150_rpmhpds),
477};
478
479static struct rpmhpd *sa8155p_rpmhpds[] = {
480 [SA8155P_CX] = &cx_w_mx_parent,
481 [SA8155P_CX_AO] = &cx_ao_w_mx_parent,
482 [SA8155P_EBI] = &ebi,
483 [SA8155P_GFX] = &gfx,
484 [SA8155P_MSS] = &mss,
485 [SA8155P_MX] = &mx,
486 [SA8155P_MX_AO] = &mx_ao,
487};
488
489static const struct rpmhpd_desc sa8155p_desc = {
490 .rpmhpds = sa8155p_rpmhpds,
491 .num_pds = ARRAY_SIZE(sa8155p_rpmhpds),
492};
493
494/* SM8250 RPMH powerdomains */
495static struct rpmhpd *sm8250_rpmhpds[] = {
496 [RPMHPD_CX] = &cx_w_mx_parent,
497 [RPMHPD_CX_AO] = &cx_ao_w_mx_parent,
498 [RPMHPD_EBI] = &ebi,
499 [RPMHPD_GFX] = &gfx,
500 [RPMHPD_LCX] = &lcx,
501 [RPMHPD_LMX] = &lmx,
502 [RPMHPD_MMCX] = &mmcx,
503 [RPMHPD_MMCX_AO] = &mmcx_ao,
504 [RPMHPD_MX] = &mx,
505 [RPMHPD_MX_AO] = &mx_ao,
506};
507
508static const struct rpmhpd_desc sm8250_desc = {
509 .rpmhpds = sm8250_rpmhpds,
510 .num_pds = ARRAY_SIZE(sm8250_rpmhpds),
511};
512
513/* SM8350 Power domains */
514static struct rpmhpd *sm8350_rpmhpds[] = {
515 [RPMHPD_CX] = &cx_w_mx_parent,
516 [RPMHPD_CX_AO] = &cx_ao_w_mx_parent,
517 [RPMHPD_EBI] = &ebi,
518 [RPMHPD_GFX] = &gfx,
519 [RPMHPD_LCX] = &lcx,
520 [RPMHPD_LMX] = &lmx,
521 [RPMHPD_MMCX] = &mmcx,
522 [RPMHPD_MMCX_AO] = &mmcx_ao,
523 [RPMHPD_MSS] = &mss,
524 [RPMHPD_MX] = &mx,
525 [RPMHPD_MX_AO] = &mx_ao,
526 [RPMHPD_MXC] = &mxc,
527 [RPMHPD_MXC_AO] = &mxc_ao,
528};
529
530static const struct rpmhpd_desc sm8350_desc = {
531 .rpmhpds = sm8350_rpmhpds,
532 .num_pds = ARRAY_SIZE(sm8350_rpmhpds),
533};
534
535/* SM8450 RPMH powerdomains */
536static struct rpmhpd *sm8450_rpmhpds[] = {
537 [RPMHPD_CX] = &cx,
538 [RPMHPD_CX_AO] = &cx_ao,
539 [RPMHPD_EBI] = &ebi,
540 [RPMHPD_GFX] = &gfx,
541 [RPMHPD_LCX] = &lcx,
542 [RPMHPD_LMX] = &lmx,
543 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
544 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
545 [RPMHPD_MSS] = &mss,
546 [RPMHPD_MX] = &mx,
547 [RPMHPD_MX_AO] = &mx_ao,
548 [RPMHPD_MXC] = &mxc,
549 [RPMHPD_MXC_AO] = &mxc_ao,
550};
551
552static const struct rpmhpd_desc sm8450_desc = {
553 .rpmhpds = sm8450_rpmhpds,
554 .num_pds = ARRAY_SIZE(sm8450_rpmhpds),
555};
556
557/* SM8550 RPMH powerdomains */
558static struct rpmhpd *sm8550_rpmhpds[] = {
559 [RPMHPD_CX] = &cx,
560 [RPMHPD_CX_AO] = &cx_ao,
561 [RPMHPD_EBI] = &ebi,
562 [RPMHPD_GFX] = &gfx,
563 [RPMHPD_LCX] = &lcx,
564 [RPMHPD_LMX] = &lmx,
565 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
566 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
567 [RPMHPD_MSS] = &mss,
568 [RPMHPD_MX] = &mx,
569 [RPMHPD_MX_AO] = &mx_ao,
570 [RPMHPD_MXC] = &mxc,
571 [RPMHPD_MXC_AO] = &mxc_ao,
572 [RPMHPD_NSP] = &nsp,
573};
574
575static const struct rpmhpd_desc sm8550_desc = {
576 .rpmhpds = sm8550_rpmhpds,
577 .num_pds = ARRAY_SIZE(sm8550_rpmhpds),
578};
579
580/* SM8650 RPMH powerdomains */
581static struct rpmhpd *sm8650_rpmhpds[] = {
582 [RPMHPD_CX] = &cx,
583 [RPMHPD_CX_AO] = &cx_ao,
584 [RPMHPD_EBI] = &ebi,
585 [RPMHPD_GFX] = &gfx,
586 [RPMHPD_LCX] = &lcx,
587 [RPMHPD_LMX] = &lmx,
588 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
589 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
590 [RPMHPD_MSS] = &mss,
591 [RPMHPD_MX] = &mx,
592 [RPMHPD_MX_AO] = &mx_ao,
593 [RPMHPD_MXC] = &mxc,
594 [RPMHPD_MXC_AO] = &mxc_ao,
595 [RPMHPD_NSP] = &nsp,
596 [RPMHPD_NSP2] = &nsp2,
597};
598
599static const struct rpmhpd_desc sm8650_desc = {
600 .rpmhpds = sm8650_rpmhpds,
601 .num_pds = ARRAY_SIZE(sm8650_rpmhpds),
602};
603
604/* SM8750 RPMH powerdomains */
605static struct rpmhpd *sm8750_rpmhpds[] = {
606 [RPMHPD_CX] = &cx,
607 [RPMHPD_CX_AO] = &cx_ao,
608 [RPMHPD_EBI] = &ebi,
609 [RPMHPD_GFX] = &gfx,
610 [RPMHPD_GMXC] = &gmxc,
611 [RPMHPD_LCX] = &lcx,
612 [RPMHPD_LMX] = &lmx,
613 [RPMHPD_MX] = &mx,
614 [RPMHPD_MX_AO] = &mx_ao,
615 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
616 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
617 [RPMHPD_MSS] = &mss,
618 [RPMHPD_MXC] = &mxc,
619 [RPMHPD_MXC_AO] = &mxc_ao,
620 [RPMHPD_NSP] = &nsp,
621 [RPMHPD_NSP2] = &nsp2,
622};
623
624static const struct rpmhpd_desc sm8750_desc = {
625 .rpmhpds = sm8750_rpmhpds,
626 .num_pds = ARRAY_SIZE(sm8750_rpmhpds),
627};
628
629/* KAANAPALI RPMH powerdomains */
630static struct rpmhpd *kaanapali_rpmhpds[] = {
631 [RPMHPD_CX] = &cx,
632 [RPMHPD_CX_AO] = &cx_ao,
633 [RPMHPD_EBI] = &ebi,
634 [RPMHPD_GFX] = &gfx,
635 [RPMHPD_GMXC] = &gmxc,
636 [RPMHPD_LCX] = &lcx,
637 [RPMHPD_LMX] = &lmx,
638 [RPMHPD_MX] = &mx,
639 [RPMHPD_MX_AO] = &mx_ao,
640 [RPMHPD_MMCX] = &mmcx,
641 [RPMHPD_MMCX_AO] = &mmcx_ao,
642 [RPMHPD_MSS] = &mss,
643 [RPMHPD_MXC] = &mxc,
644 [RPMHPD_MXC_AO] = &mxc_ao,
645 [RPMHPD_NSP] = &nsp,
646 [RPMHPD_NSP2] = &nsp2,
647};
648
649static const struct rpmhpd_desc kaanapali_desc = {
650 .rpmhpds = kaanapali_rpmhpds,
651 .num_pds = ARRAY_SIZE(kaanapali_rpmhpds),
652};
653
654/* Hawi RPMH powerdomains */
655static struct rpmhpd *hawi_rpmhpds[] = {
656 [RPMHPD_CX] = &cx,
657 [RPMHPD_CX_AO] = &cx_ao,
658 [RPMHPD_DCX] = &dcx,
659 [RPMHPD_EBI] = &ebi,
660 [RPMHPD_GBX] = &gbx,
661 [RPMHPD_GFX] = &gfx,
662 [RPMHPD_GMXC] = &gmxc,
663 [RPMHPD_LCX] = &lcx,
664 [RPMHPD_LMX] = &lmx,
665 [RPMHPD_MMCX] = &mmcx,
666 [RPMHPD_MMCX_AO] = &mmcx_ao,
667 [RPMHPD_MX] = &mx,
668 [RPMHPD_MX_AO] = &mx_ao,
669 [RPMHPD_MXC] = &mxc,
670 [RPMHPD_MXC_AO] = &mxc_ao,
671 [RPMHPD_MSS] = &mss,
672 [RPMHPD_NSP] = &nsp,
673 [RPMHPD_NSP2] = &nsp2,
674};
675
676static const struct rpmhpd_desc hawi_desc = {
677 .rpmhpds = hawi_rpmhpds,
678 .num_pds = ARRAY_SIZE(hawi_rpmhpds),
679};
680
681/* QDU1000/QRU1000 RPMH powerdomains */
682static struct rpmhpd *qdu1000_rpmhpds[] = {
683 [QDU1000_CX] = &cx,
684 [QDU1000_EBI] = &ebi,
685 [QDU1000_MSS] = &mss,
686 [QDU1000_MX] = &mx,
687};
688
689static const struct rpmhpd_desc qdu1000_desc = {
690 .rpmhpds = qdu1000_rpmhpds,
691 .num_pds = ARRAY_SIZE(qdu1000_rpmhpds),
692};
693
694/* SC7180 RPMH powerdomains */
695static struct rpmhpd *sc7180_rpmhpds[] = {
696 [SC7180_CX] = &cx_w_mx_parent,
697 [SC7180_CX_AO] = &cx_ao_w_mx_parent,
698 [SC7180_GFX] = &gfx,
699 [SC7180_LCX] = &lcx,
700 [SC7180_LMX] = &lmx,
701 [SC7180_MSS] = &mss,
702 [SC7180_MX] = &mx,
703 [SC7180_MX_AO] = &mx_ao,
704};
705
706static const struct rpmhpd_desc sc7180_desc = {
707 .rpmhpds = sc7180_rpmhpds,
708 .num_pds = ARRAY_SIZE(sc7180_rpmhpds),
709};
710
711/* SC7280 RPMH powerdomains */
712static struct rpmhpd *sc7280_rpmhpds[] = {
713 [SC7280_CX] = &cx,
714 [SC7280_CX_AO] = &cx_ao,
715 [SC7280_EBI] = &ebi,
716 [SC7280_GFX] = &gfx,
717 [SC7280_LCX] = &lcx,
718 [SC7280_LMX] = &lmx,
719 [SC7280_MSS] = &mss,
720 [SC7280_MX] = &mx,
721 [SC7280_MX_AO] = &mx_ao,
722};
723
724static const struct rpmhpd_desc sc7280_desc = {
725 .rpmhpds = sc7280_rpmhpds,
726 .num_pds = ARRAY_SIZE(sc7280_rpmhpds),
727};
728
729/* SC8180x RPMH powerdomains */
730static struct rpmhpd *sc8180x_rpmhpds[] = {
731 [SC8180X_CX] = &cx_w_mx_parent,
732 [SC8180X_CX_AO] = &cx_ao_w_mx_parent,
733 [SC8180X_EBI] = &ebi,
734 [SC8180X_GFX] = &gfx,
735 [SC8180X_LCX] = &lcx,
736 [SC8180X_LMX] = &lmx,
737 [SC8180X_MMCX] = &mmcx,
738 [SC8180X_MMCX_AO] = &mmcx_ao,
739 [SC8180X_MSS] = &mss,
740 [SC8180X_MX] = &mx,
741 [SC8180X_MX_AO] = &mx_ao,
742};
743
744static const struct rpmhpd_desc sc8180x_desc = {
745 .rpmhpds = sc8180x_rpmhpds,
746 .num_pds = ARRAY_SIZE(sc8180x_rpmhpds),
747};
748
749/* SC8280xp RPMH powerdomains */
750static struct rpmhpd *sc8280xp_rpmhpds[] = {
751 [SC8280XP_CX] = &cx,
752 [SC8280XP_CX_AO] = &cx_ao,
753 [SC8280XP_EBI] = &ebi,
754 [SC8280XP_GFX] = &gfx,
755 [SC8280XP_LCX] = &lcx,
756 [SC8280XP_LMX] = &lmx,
757 [SC8280XP_MMCX] = &mmcx,
758 [SC8280XP_MMCX_AO] = &mmcx_ao,
759 [SC8280XP_MX] = &mx,
760 [SC8280XP_MX_AO] = &mx_ao,
761 [SC8280XP_MXC] = &mxc,
762 [SC8280XP_MXC_AO] = &mxc_ao,
763 [SC8280XP_NSP] = &nsp,
764 [SC8280XP_QPHY] = &qphy,
765};
766
767static const struct rpmhpd_desc sc8280xp_desc = {
768 .rpmhpds = sc8280xp_rpmhpds,
769 .num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
770};
771
772/* Glymur RPMH powerdomains */
773static struct rpmhpd *glymur_rpmhpds[] = {
774 [RPMHPD_CX] = &cx,
775 [RPMHPD_CX_AO] = &cx_ao,
776 [RPMHPD_EBI] = &ebi,
777 [RPMHPD_GFX] = &gfx,
778 [RPMHPD_LCX] = &lcx,
779 [RPMHPD_LMX] = &lmx,
780 [RPMHPD_MMCX] = &mmcx,
781 [RPMHPD_MMCX_AO] = &mmcx_ao,
782 [RPMHPD_MX] = &mx,
783 [RPMHPD_MX_AO] = &mx_ao,
784 [RPMHPD_MXC] = &mxc,
785 [RPMHPD_MXC_AO] = &mxc_ao,
786 [RPMHPD_MSS] = &mss,
787 [RPMHPD_NSP] = &nsp,
788 [RPMHPD_NSP2] = &nsp2,
789 [RPMHPD_GMXC] = &gmxc,
790};
791
792static const struct rpmhpd_desc glymur_desc = {
793 .rpmhpds = glymur_rpmhpds,
794 .num_pds = ARRAY_SIZE(glymur_rpmhpds),
795};
796
797/* X1E80100 RPMH powerdomains */
798static struct rpmhpd *x1e80100_rpmhpds[] = {
799 [RPMHPD_CX] = &cx,
800 [RPMHPD_CX_AO] = &cx_ao,
801 [RPMHPD_EBI] = &ebi,
802 [RPMHPD_GFX] = &gfx,
803 [RPMHPD_LCX] = &lcx,
804 [RPMHPD_LMX] = &lmx,
805 [RPMHPD_MMCX] = &mmcx,
806 [RPMHPD_MMCX_AO] = &mmcx_ao,
807 [RPMHPD_MX] = &mx,
808 [RPMHPD_MX_AO] = &mx_ao,
809 [RPMHPD_NSP] = &nsp,
810 [RPMHPD_MXC] = &mxc,
811 [RPMHPD_GMXC] = &gmxc,
812};
813
814static const struct rpmhpd_desc x1e80100_desc = {
815 .rpmhpds = x1e80100_rpmhpds,
816 .num_pds = ARRAY_SIZE(x1e80100_rpmhpds),
817};
818
819/* QCS8300 RPMH power domains */
820static struct rpmhpd *qcs8300_rpmhpds[] = {
821 [RPMHPD_CX] = &cx,
822 [RPMHPD_CX_AO] = &cx_ao,
823 [RPMHPD_EBI] = &ebi,
824 [RPMHPD_GFX] = &gfx,
825 [RPMHPD_LCX] = &lcx,
826 [RPMHPD_LMX] = &lmx,
827 [RPMHPD_MMCX] = &mmcx_w_cx_parent,
828 [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent,
829 [RPMHPD_MXC] = &mxc,
830 [RPMHPD_MXC_AO] = &mxc_ao,
831 [RPMHPD_MX] = &mx,
832 [RPMHPD_MX_AO] = &mx_ao,
833 [RPMHPD_NSP0] = &nsp0,
834 [RPMHPD_NSP1] = &nsp1,
835};
836
837static const struct rpmhpd_desc qcs8300_desc = {
838 .rpmhpds = qcs8300_rpmhpds,
839 .num_pds = ARRAY_SIZE(qcs8300_rpmhpds),
840};
841
842/* QCS615 RPMH powerdomains */
843static struct rpmhpd *qcs615_rpmhpds[] = {
844 [RPMHPD_CX] = &cx,
845 [RPMHPD_CX_AO] = &cx_ao,
846};
847
848static const struct rpmhpd_desc qcs615_desc = {
849 .rpmhpds = qcs615_rpmhpds,
850 .num_pds = ARRAY_SIZE(qcs615_rpmhpds),
851};
852
853static const struct of_device_id rpmhpd_match_table[] = {
854 { .compatible = "qcom,eliza-rpmhpd", .data = &eliza_desc },
855 { .compatible = "qcom,glymur-rpmhpd", .data = &glymur_desc },
856 { .compatible = "qcom,hawi-rpmhpd", .data = &hawi_desc },
857 { .compatible = "qcom,kaanapali-rpmhpd", .data = &kaanapali_desc },
858 { .compatible = "qcom,milos-rpmhpd", .data = &milos_desc },
859 { .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc },
860 { .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc },
861 { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
862 { .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc },
863 { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
864 { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc },
865 { .compatible = "qcom,sar2130p-rpmhpd", .data = &sar2130p_desc},
866 { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
867 { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
868 { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
869 { .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
870 { .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
871 { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
872 { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
873 { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc},
874 { .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc},
875 { .compatible = "qcom,sm4450-rpmhpd", .data = &sm4450_desc },
876 { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc },
877 { .compatible = "qcom,sm7150-rpmhpd", .data = &sm7150_desc },
878 { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
879 { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
880 { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc },
881 { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
882 { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
883 { .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc },
884 { .compatible = "qcom,sm8750-rpmhpd", .data = &sm8750_desc },
885 { .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc },
886 { }
887};
888MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
889
890static int rpmhpd_send_corner(struct rpmhpd *pd, int state,
891 unsigned int corner, bool sync)
892{
893 struct tcs_cmd cmd = {
894 .addr = pd->addr,
895 .data = corner,
896 };
897
898 /*
899 * Wait for an ack only when we are increasing the
900 * perf state of the power domain
901 */
902 if (sync)
903 return rpmh_write(pd->dev, state, &cmd, 1);
904 else
905 return rpmh_write_async(pd->dev, state, &cmd, 1);
906}
907
908static void to_active_sleep(struct rpmhpd *pd, unsigned int corner,
909 unsigned int *active, unsigned int *sleep)
910{
911 *active = corner;
912
913 if (pd->active_only)
914 *sleep = 0;
915 else
916 *sleep = *active;
917}
918
919/*
920 * This function is used to aggregate the votes across the active only
921 * resources and its peers. The aggregated votes are sent to RPMh as
922 * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes
923 * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh
924 * on system sleep).
925 * We send ACTIVE_ONLY votes for resources without any peers. For others,
926 * which have an active only peer, all 3 votes are sent.
927 */
928static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
929{
930 int ret;
931 struct rpmhpd *peer = pd->peer;
932 unsigned int active_corner, sleep_corner;
933 unsigned int this_active_corner = 0, this_sleep_corner = 0;
934 unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
935 unsigned int peer_enabled_corner;
936
937 if (pd->state_synced) {
938 to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
939 } else {
940 /* Clamp to highest corner if sync_state hasn't happened */
941 this_active_corner = pd->level_count - 1;
942 this_sleep_corner = pd->level_count - 1;
943 }
944
945 if (peer && peer->enabled) {
946 peer_enabled_corner = max(peer->corner, peer->enable_corner);
947 to_active_sleep(peer, peer_enabled_corner, &peer_active_corner,
948 &peer_sleep_corner);
949 }
950
951 active_corner = max(this_active_corner, peer_active_corner);
952
953 ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner,
954 active_corner > pd->active_corner);
955 if (ret)
956 return ret;
957
958 pd->active_corner = active_corner;
959
960 if (peer) {
961 peer->active_corner = active_corner;
962
963 ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE,
964 active_corner, false);
965 if (ret)
966 return ret;
967
968 sleep_corner = max(this_sleep_corner, peer_sleep_corner);
969
970 return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner,
971 false);
972 }
973
974 return ret;
975}
976
977static int rpmhpd_power_on(struct generic_pm_domain *domain)
978{
979 struct rpmhpd *pd = domain_to_rpmhpd(domain);
980 unsigned int corner;
981 int ret;
982
983 mutex_lock(&rpmhpd_lock);
984
985 corner = max(pd->corner, pd->enable_corner);
986 ret = rpmhpd_aggregate_corner(pd, corner);
987 if (!ret)
988 pd->enabled = true;
989
990 mutex_unlock(&rpmhpd_lock);
991
992 return ret;
993}
994
995static int rpmhpd_power_off(struct generic_pm_domain *domain)
996{
997 struct rpmhpd *pd = domain_to_rpmhpd(domain);
998 int ret;
999
1000 mutex_lock(&rpmhpd_lock);
1001
1002 ret = rpmhpd_aggregate_corner(pd, 0);
1003 if (!ret)
1004 pd->enabled = false;
1005
1006 mutex_unlock(&rpmhpd_lock);
1007
1008 return ret;
1009}
1010
1011static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
1012 unsigned int level)
1013{
1014 struct rpmhpd *pd = domain_to_rpmhpd(domain);
1015 int ret, i;
1016
1017 guard(mutex)(&rpmhpd_lock);
1018
1019 for (i = 0; i < pd->level_count; i++)
1020 if (level <= pd->level[i])
1021 break;
1022
1023 /*
1024 * If the level requested is more than that supported by the
1025 * max corner, just set it to max anyway.
1026 */
1027 if (i == pd->level_count)
1028 i--;
1029
1030 if (pd->enabled) {
1031 /* Ensure that the domain isn't turn off */
1032 if (i < pd->enable_corner)
1033 i = pd->enable_corner;
1034
1035 ret = rpmhpd_aggregate_corner(pd, i);
1036 if (ret)
1037 return ret;
1038 }
1039
1040 pd->corner = i;
1041
1042 return 0;
1043}
1044
1045static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
1046{
1047 int i;
1048 const u16 *buf;
1049
1050 buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count);
1051 if (IS_ERR(buf))
1052 return PTR_ERR(buf);
1053
1054 /* 2 bytes used for each command DB aux data entry */
1055 rpmhpd->level_count >>= 1;
1056
1057 if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS)
1058 return -EINVAL;
1059
1060 for (i = 0; i < rpmhpd->level_count; i++) {
1061 if (rpmhpd->skip_retention_level && buf[i] == RPMH_REGULATOR_LEVEL_RETENTION)
1062 continue;
1063
1064 rpmhpd->level[i] = buf[i];
1065
1066 /* Remember the first corner with non-zero level */
1067 if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
1068 rpmhpd->enable_corner = i;
1069
1070 /*
1071 * The AUX data may be zero padded. These 0 valued entries at
1072 * the end of the map must be ignored.
1073 */
1074 if (i > 0 && rpmhpd->level[i] == 0) {
1075 rpmhpd->level_count = i;
1076 break;
1077 }
1078 pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
1079 rpmhpd->level[i]);
1080 }
1081
1082 return 0;
1083}
1084
1085static int rpmhpd_probe(struct platform_device *pdev)
1086{
1087 int i, ret;
1088 size_t num_pds;
1089 struct device *dev = &pdev->dev;
1090 struct genpd_onecell_data *data;
1091 struct rpmhpd **rpmhpds;
1092 const struct rpmhpd_desc *desc;
1093
1094 desc = of_device_get_match_data(dev);
1095 if (!desc)
1096 return -EINVAL;
1097
1098 rpmhpds = desc->rpmhpds;
1099 num_pds = desc->num_pds;
1100
1101 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
1102 if (!data)
1103 return -ENOMEM;
1104
1105 data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains),
1106 GFP_KERNEL);
1107 if (!data->domains)
1108 return -ENOMEM;
1109
1110 data->num_domains = num_pds;
1111
1112 for (i = 0; i < num_pds; i++) {
1113 if (!rpmhpds[i])
1114 continue;
1115
1116 rpmhpds[i]->dev = dev;
1117 rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name);
1118 if (!rpmhpds[i]->addr) {
1119 dev_err(dev, "Could not find RPMh address for resource %s\n",
1120 rpmhpds[i]->res_name);
1121 return -ENODEV;
1122 }
1123
1124 ret = cmd_db_read_slave_id(rpmhpds[i]->res_name);
1125 if (ret != CMD_DB_HW_ARC) {
1126 dev_err(dev, "RPMh slave ID mismatch\n");
1127 return -EINVAL;
1128 }
1129
1130 ret = rpmhpd_update_level_mapping(rpmhpds[i]);
1131 if (ret)
1132 return ret;
1133
1134 rpmhpds[i]->pd.power_off = rpmhpd_power_off;
1135 rpmhpds[i]->pd.power_on = rpmhpd_power_on;
1136 rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state;
1137 pm_genpd_init(&rpmhpds[i]->pd, NULL, true);
1138
1139 data->domains[i] = &rpmhpds[i]->pd;
1140 }
1141
1142 /* Add subdomains */
1143 for (i = 0; i < num_pds; i++) {
1144 if (!rpmhpds[i])
1145 continue;
1146 if (rpmhpds[i]->parent)
1147 pm_genpd_add_subdomain(rpmhpds[i]->parent,
1148 &rpmhpds[i]->pd);
1149 }
1150
1151 return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
1152}
1153
1154static void rpmhpd_sync_state(struct device *dev)
1155{
1156 const struct rpmhpd_desc *desc = of_device_get_match_data(dev);
1157 struct rpmhpd **rpmhpds = desc->rpmhpds;
1158 unsigned int corner;
1159 struct rpmhpd *pd;
1160 unsigned int i;
1161 int ret;
1162
1163 of_genpd_sync_state(dev->of_node);
1164
1165 mutex_lock(&rpmhpd_lock);
1166 for (i = 0; i < desc->num_pds; i++) {
1167 pd = rpmhpds[i];
1168 if (!pd)
1169 continue;
1170
1171 pd->state_synced = true;
1172 if (pd->enabled)
1173 corner = max(pd->corner, pd->enable_corner);
1174 else
1175 corner = 0;
1176
1177 ret = rpmhpd_aggregate_corner(pd, corner);
1178 if (ret)
1179 dev_err(dev, "failed to sync %s\n", pd->res_name);
1180 }
1181 mutex_unlock(&rpmhpd_lock);
1182}
1183
1184static struct platform_driver rpmhpd_driver = {
1185 .driver = {
1186 .name = "qcom-rpmhpd",
1187 .of_match_table = rpmhpd_match_table,
1188 .suppress_bind_attrs = true,
1189 .sync_state = rpmhpd_sync_state,
1190 },
1191 .probe = rpmhpd_probe,
1192};
1193
1194static int __init rpmhpd_init(void)
1195{
1196 return platform_driver_register(&rpmhpd_driver);
1197}
1198core_initcall(rpmhpd_init);
1199
1200MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver");
1201MODULE_LICENSE("GPL v2");