1 // SPDX-License-Identifier: GPL-2.0+
3 * Texas Instruments System Control Interface (TI SCI) power domain driver
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6 * Andreas Dannenberg <dannenberg@ti.com>
8 * Loosely based on Linux kernel ti_sci_pm_domains.c...
16 #include <power-domain-uclass.h>
17 #include <dm/device_compat.h>
18 #include <linux/err.h>
19 #include <linux/soc/ti/ti_sci_protocol.h>
20 #include <dt-bindings/soc/ti,sci_pm_domain.h>
23 * struct ti_sci_power_domain_data - pm domain controller information structure
24 * @sci: TI SCI handle used for communication with system controller
26 struct ti_sci_power_domain_data
{
27 const struct ti_sci_handle
*sci
;
30 static int ti_sci_power_domain_probe(struct udevice
*dev
)
32 struct ti_sci_power_domain_data
*data
= dev_get_priv(dev
);
34 debug("%s(dev=%p)\n", __func__
, dev
);
39 /* Store handle for communication with the system controller */
40 data
->sci
= ti_sci_get_handle(dev
);
41 if (IS_ERR(data
->sci
))
42 return PTR_ERR(data
->sci
);
47 static int ti_sci_power_domain_request(struct power_domain
*pd
)
49 debug("%s(pd=%p)\n", __func__
, pd
);
53 static int ti_sci_power_domain_free(struct power_domain
*pd
)
55 debug("%s(pd=%p)\n", __func__
, pd
);
59 static int ti_sci_power_domain_on(struct power_domain
*pd
)
61 struct ti_sci_power_domain_data
*data
= dev_get_priv(pd
->dev
);
62 const struct ti_sci_handle
*sci
= data
->sci
;
63 const struct ti_sci_dev_ops
*dops
= &sci
->ops
.dev_ops
;
64 u8 flags
= (uintptr_t)pd
->priv
;
67 debug("%s(pd=%p)\n", __func__
, pd
);
69 if (flags
& TI_SCI_PD_EXCLUSIVE
)
70 ret
= dops
->get_device_exclusive(sci
, pd
->id
);
72 ret
= dops
->get_device(sci
, pd
->id
);
75 dev_err(pd
->dev
, "%s: get_device(%lu) failed (%d)\n",
76 __func__
, pd
->id
, ret
);
81 static int ti_sci_power_domain_off(struct power_domain
*pd
)
83 struct ti_sci_power_domain_data
*data
= dev_get_priv(pd
->dev
);
84 const struct ti_sci_handle
*sci
= data
->sci
;
85 const struct ti_sci_dev_ops
*dops
= &sci
->ops
.dev_ops
;
88 debug("%s(pd=%p)\n", __func__
, pd
);
90 ret
= dops
->put_device(sci
, pd
->id
);
92 dev_err(pd
->dev
, "%s: put_device(%lu) failed (%d)\n",
93 __func__
, pd
->id
, ret
);
98 static int ti_sci_power_domain_of_xlate(struct power_domain
*pd
,
99 struct ofnode_phandle_args
*args
)
103 debug("%s(power_domain=%p)\n", __func__
, pd
);
105 if (args
->args_count
< 1) {
106 debug("Invalid args_count: %d\n", args
->args_count
);
110 pd
->id
= args
->args
[0];
111 /* By default request for device exclusive */
112 flags
= TI_SCI_PD_EXCLUSIVE
;
113 if (args
->args_count
== 2)
114 flags
= args
->args
[1] & TI_SCI_PD_EXCLUSIVE
;
115 pd
->priv
= (void *)(uintptr_t)flags
;
120 static const struct udevice_id ti_sci_power_domain_of_match
[] = {
121 { .compatible
= "ti,sci-pm-domain" },
125 static struct power_domain_ops ti_sci_power_domain_ops
= {
126 .request
= ti_sci_power_domain_request
,
127 .rfree
= ti_sci_power_domain_free
,
128 .on
= ti_sci_power_domain_on
,
129 .off
= ti_sci_power_domain_off
,
130 .of_xlate
= ti_sci_power_domain_of_xlate
,
133 U_BOOT_DRIVER(ti_sci_pm_domains
) = {
134 .name
= "ti-sci-pm-domains",
135 .id
= UCLASS_POWER_DOMAIN
,
136 .of_match
= ti_sci_power_domain_of_match
,
137 .probe
= ti_sci_power_domain_probe
,
138 .priv_auto_alloc_size
= sizeof(struct ti_sci_power_domain_data
),
139 .ops
= &ti_sci_power_domain_ops
,