1*1a88a04eSAndreas Dannenberg // SPDX-License-Identifier: GPL-2.0+
2*1a88a04eSAndreas Dannenberg /*
3*1a88a04eSAndreas Dannenberg  * Texas Instruments System Control Interface (TI SCI) power domain driver
4*1a88a04eSAndreas Dannenberg  *
5*1a88a04eSAndreas Dannenberg  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6*1a88a04eSAndreas Dannenberg  *	Andreas Dannenberg <dannenberg@ti.com>
7*1a88a04eSAndreas Dannenberg  *
8*1a88a04eSAndreas Dannenberg  * Loosely based on Linux kernel ti_sci_pm_domains.c...
9*1a88a04eSAndreas Dannenberg  */
10*1a88a04eSAndreas Dannenberg 
11*1a88a04eSAndreas Dannenberg #include <common.h>
12*1a88a04eSAndreas Dannenberg #include <dm.h>
13*1a88a04eSAndreas Dannenberg #include <errno.h>
14*1a88a04eSAndreas Dannenberg #include <power-domain-uclass.h>
15*1a88a04eSAndreas Dannenberg #include <linux/soc/ti/ti_sci_protocol.h>
16*1a88a04eSAndreas Dannenberg 
17*1a88a04eSAndreas Dannenberg /**
18*1a88a04eSAndreas Dannenberg  * struct ti_sci_power_domain_data - pm domain controller information structure
19*1a88a04eSAndreas Dannenberg  * @sci: TI SCI handle used for communication with system controller
20*1a88a04eSAndreas Dannenberg  */
21*1a88a04eSAndreas Dannenberg struct ti_sci_power_domain_data {
22*1a88a04eSAndreas Dannenberg 	const struct ti_sci_handle *sci;
23*1a88a04eSAndreas Dannenberg };
24*1a88a04eSAndreas Dannenberg 
ti_sci_power_domain_probe(struct udevice * dev)25*1a88a04eSAndreas Dannenberg static int ti_sci_power_domain_probe(struct udevice *dev)
26*1a88a04eSAndreas Dannenberg {
27*1a88a04eSAndreas Dannenberg 	struct ti_sci_power_domain_data *data = dev_get_priv(dev);
28*1a88a04eSAndreas Dannenberg 
29*1a88a04eSAndreas Dannenberg 	debug("%s(dev=%p)\n", __func__, dev);
30*1a88a04eSAndreas Dannenberg 
31*1a88a04eSAndreas Dannenberg 	if (!data)
32*1a88a04eSAndreas Dannenberg 		return -ENOMEM;
33*1a88a04eSAndreas Dannenberg 
34*1a88a04eSAndreas Dannenberg 	/* Store handle for communication with the system controller */
35*1a88a04eSAndreas Dannenberg 	data->sci = ti_sci_get_handle(dev);
36*1a88a04eSAndreas Dannenberg 	if (IS_ERR(data->sci))
37*1a88a04eSAndreas Dannenberg 		return PTR_ERR(data->sci);
38*1a88a04eSAndreas Dannenberg 
39*1a88a04eSAndreas Dannenberg 	return 0;
40*1a88a04eSAndreas Dannenberg }
41*1a88a04eSAndreas Dannenberg 
ti_sci_power_domain_request(struct power_domain * pd)42*1a88a04eSAndreas Dannenberg static int ti_sci_power_domain_request(struct power_domain *pd)
43*1a88a04eSAndreas Dannenberg {
44*1a88a04eSAndreas Dannenberg 	debug("%s(pd=%p)\n", __func__, pd);
45*1a88a04eSAndreas Dannenberg 	return 0;
46*1a88a04eSAndreas Dannenberg }
47*1a88a04eSAndreas Dannenberg 
ti_sci_power_domain_free(struct power_domain * pd)48*1a88a04eSAndreas Dannenberg static int ti_sci_power_domain_free(struct power_domain *pd)
49*1a88a04eSAndreas Dannenberg {
50*1a88a04eSAndreas Dannenberg 	debug("%s(pd=%p)\n", __func__, pd);
51*1a88a04eSAndreas Dannenberg 	return 0;
52*1a88a04eSAndreas Dannenberg }
53*1a88a04eSAndreas Dannenberg 
ti_sci_power_domain_on(struct power_domain * pd)54*1a88a04eSAndreas Dannenberg static int ti_sci_power_domain_on(struct power_domain *pd)
55*1a88a04eSAndreas Dannenberg {
56*1a88a04eSAndreas Dannenberg 	struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
57*1a88a04eSAndreas Dannenberg 	const struct ti_sci_handle *sci = data->sci;
58*1a88a04eSAndreas Dannenberg 	const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
59*1a88a04eSAndreas Dannenberg 	int ret;
60*1a88a04eSAndreas Dannenberg 
61*1a88a04eSAndreas Dannenberg 	debug("%s(pd=%p)\n", __func__, pd);
62*1a88a04eSAndreas Dannenberg 
63*1a88a04eSAndreas Dannenberg 	ret = dops->get_device(sci, pd->id);
64*1a88a04eSAndreas Dannenberg 	if (ret)
65*1a88a04eSAndreas Dannenberg 		dev_err(power_domain->dev, "%s: get_device failed (%d)\n",
66*1a88a04eSAndreas Dannenberg 			__func__, ret);
67*1a88a04eSAndreas Dannenberg 
68*1a88a04eSAndreas Dannenberg 	return ret;
69*1a88a04eSAndreas Dannenberg }
70*1a88a04eSAndreas Dannenberg 
ti_sci_power_domain_off(struct power_domain * pd)71*1a88a04eSAndreas Dannenberg static int ti_sci_power_domain_off(struct power_domain *pd)
72*1a88a04eSAndreas Dannenberg {
73*1a88a04eSAndreas Dannenberg 	struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
74*1a88a04eSAndreas Dannenberg 	const struct ti_sci_handle *sci = data->sci;
75*1a88a04eSAndreas Dannenberg 	const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
76*1a88a04eSAndreas Dannenberg 	int ret;
77*1a88a04eSAndreas Dannenberg 
78*1a88a04eSAndreas Dannenberg 	debug("%s(pd=%p)\n", __func__, pd);
79*1a88a04eSAndreas Dannenberg 
80*1a88a04eSAndreas Dannenberg 	ret = dops->put_device(sci, pd->id);
81*1a88a04eSAndreas Dannenberg 	if (ret)
82*1a88a04eSAndreas Dannenberg 		dev_err(power_domain->dev, "%s: put_device failed (%d)\n",
83*1a88a04eSAndreas Dannenberg 			__func__, ret);
84*1a88a04eSAndreas Dannenberg 
85*1a88a04eSAndreas Dannenberg 	return ret;
86*1a88a04eSAndreas Dannenberg }
87*1a88a04eSAndreas Dannenberg 
88*1a88a04eSAndreas Dannenberg static const struct udevice_id ti_sci_power_domain_of_match[] = {
89*1a88a04eSAndreas Dannenberg 	{ .compatible = "ti,sci-pm-domain" },
90*1a88a04eSAndreas Dannenberg 	{ /* sentinel */ }
91*1a88a04eSAndreas Dannenberg };
92*1a88a04eSAndreas Dannenberg 
93*1a88a04eSAndreas Dannenberg static struct power_domain_ops ti_sci_power_domain_ops = {
94*1a88a04eSAndreas Dannenberg 	.request = ti_sci_power_domain_request,
95*1a88a04eSAndreas Dannenberg 	.free = ti_sci_power_domain_free,
96*1a88a04eSAndreas Dannenberg 	.on = ti_sci_power_domain_on,
97*1a88a04eSAndreas Dannenberg 	.off = ti_sci_power_domain_off,
98*1a88a04eSAndreas Dannenberg };
99*1a88a04eSAndreas Dannenberg 
100*1a88a04eSAndreas Dannenberg U_BOOT_DRIVER(ti_sci_pm_domains) = {
101*1a88a04eSAndreas Dannenberg 	.name = "ti-sci-pm-domains",
102*1a88a04eSAndreas Dannenberg 	.id = UCLASS_POWER_DOMAIN,
103*1a88a04eSAndreas Dannenberg 	.of_match = ti_sci_power_domain_of_match,
104*1a88a04eSAndreas Dannenberg 	.probe = ti_sci_power_domain_probe,
105*1a88a04eSAndreas Dannenberg 	.priv_auto_alloc_size = sizeof(struct ti_sci_power_domain_data),
106*1a88a04eSAndreas Dannenberg 	.ops = &ti_sci_power_domain_ops,
107*1a88a04eSAndreas Dannenberg };
108