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