Commit d920940be699a866c6853971d5589d6249bce6a4
Committed by
Jacob Stiffler
1 parent
053aa6ec56
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
drivers: power: Introduce TI coprocessor driver
All the coprocessors may not be used in all the system usecase scenarios, so we need a driver that can initialize the coprocessors based on the current system usecase. In a scenario where the user knows ahead what's the target OPP for a usecase and which doesnt change during runtime, using devfreq would be an overkill. Introduce a simple driver to configure the initial Operating frequency an dvoltage (OPP) for co processors in a SoC. TI co-processor driver makes use of voltage domain manager for handling the clock frequency changes and corresponding voltage handling thus it can still work seamlessly in a ganged rail scenario where the voltage rails of more than one coprocssor are ganged up. Change-Id: If8c4afba833cf972e080f81c9e02f3126703b96c Signed-off-by: Ravikumar Kattekola <rk@ti.com>
Showing 6 changed files with 275 additions and 0 deletions Side-by-side Diff
Documentation/devicetree/bindings/power/coproc/ti-coproc.txt
1 | +Texas Instruments co-processor driver | |
2 | + | |
3 | +A co-processor device is a non-cpu processor found on an SoC. | |
4 | + | |
5 | +This document describes the clock and voltage configuration | |
6 | +used by co-processors/devices typically found on Texas Instrument SoCs. | |
7 | + | |
8 | +Required properties | |
9 | +- compatible: should be | |
10 | + "ti,coproc" | |
11 | +- clocks: <functional clock>, <dpll clock> | |
12 | + dpll clock is optional | |
13 | +- clock-names: "fclk", "dpll" | |
14 | + if you change names here, go chnage the driver too | |
15 | +- clock-target-frequency: Mention your target frequency here | |
16 | +- operating-points: all OPPs applicable for this device/coprocessor | |
17 | +- coproc-voltdm: phandle of the Voltage domain associated with this device/coproc | |
18 | +- voltage-tolerance: Specify a voltage tolerance allowed for this voltage domain | |
19 | +as per datamanual limits | |
20 | + | |
21 | +Example: | |
22 | +iva_coproc { | |
23 | + compatible = "ti,coproc"; | |
24 | + clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>; | |
25 | + clock-names = "fclk", "dpll"; | |
26 | + clock-target-frequency = <532000000>; | |
27 | + operating-points = < | |
28 | + 388200 1055000 | |
29 | + 430000 1150000 | |
30 | + 532000 1250000 | |
31 | + >; | |
32 | + coproc-voltdm = <&voltdm_ivahd>; | |
33 | + voltage-tolerance = <1>; | |
34 | +}; |
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/coproc/Kconfig
drivers/power/coproc/Makefile
drivers/power/coproc/ti-coproc.c
1 | +/* | |
2 | + * OMAP SoC COPROC driver | |
3 | + * | |
4 | + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ | |
5 | + * Carlos Hernandez <ceh@ti.com> | |
6 | + * Nishanth Menon <nm@ti.com> | |
7 | + * Ravikumar Kattekola <rk@ti.com> | |
8 | + * This program is free software; you can redistribute it and/or modify | |
9 | + * it under the terms of the GNU General Public License version 2 as | |
10 | + * published by the Free Software Foundation. | |
11 | + * | |
12 | + * This program is distributed "as is" WITHOUT ANY WARRANTY of any | |
13 | + * kind, whether express or implied; without even the implied warranty | |
14 | + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + */ | |
17 | +#include <linux/io.h> | |
18 | +#include <linux/slab.h> | |
19 | +#include <linux/mutex.h> | |
20 | +#include <linux/suspend.h> | |
21 | +#include <linux/pm_opp.h> | |
22 | +#include <linux/of.h> | |
23 | +#include <linux/platform_device.h> | |
24 | +#include <linux/regulator/consumer.h> | |
25 | +#include <linux/module.h> | |
26 | +#include <linux/clk.h> | |
27 | +#include <linux/pm_voltage_domain.h> | |
28 | + | |
29 | +/** | |
30 | + * struct coproc_data - Co processor private data | |
31 | + * @profile: profile specific for this device | |
32 | + * @dev: device pointer | |
33 | + * @: for this device | |
34 | + * @stat: my current statistics | |
35 | + * @dev_clk: my device clk | |
36 | + * @dpll_clk: my dpll clk | |
37 | + * @nb: my notifier block | |
38 | + */ | |
39 | +struct coproc_data { | |
40 | + struct device *dev; | |
41 | + struct clk *dev_clk; | |
42 | + struct clk *dpll_clk; | |
43 | + struct notifier_block *clk_nb; | |
44 | +}; | |
45 | + | |
46 | +/** | |
47 | + * DOC: | |
48 | + * clock-names should be defined in dts file, e.g. | |
49 | + * coproc { | |
50 | + * | |
51 | + * compatible = "ti,coproc"; | |
52 | + * clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>; | |
53 | + * clock-names = "fclk", "dpll"; | |
54 | + * clock-target-frequency = <532000000>; | |
55 | + * operating-points = < | |
56 | + * 388200 1055000 | |
57 | + * 500000 1150000 | |
58 | + * 532000 1250000 | |
59 | + * >; | |
60 | + * coproc-voltdm = <&voltdm_ivahd>; | |
61 | + * voltage-tolerance = <1>; | |
62 | + * | |
63 | + * }; | |
64 | + */ | |
65 | +#define DEV_CLK_NAME "fclk" | |
66 | +#define DPLL_CLK_NAME "dpll" | |
67 | + | |
68 | +static int coproc_probe(struct platform_device *pdev) | |
69 | +{ | |
70 | + struct coproc_data *d; | |
71 | + unsigned int voltage_latency; | |
72 | + u32 target_freq = 0; | |
73 | + int err = 0; | |
74 | + struct device *dev = &pdev->dev; | |
75 | + struct device_node *np = of_node_get(dev->of_node); | |
76 | + bool noset_dpll_as_rate; | |
77 | + | |
78 | + dev_info(dev, "probe\n"); | |
79 | + | |
80 | + of_property_read_u32(np, "clock-target-frequency", &target_freq); | |
81 | + if (!target_freq) { | |
82 | + dev_err(dev, "%s: Invalid/no target frequency found in dt.\n", | |
83 | + __func__); | |
84 | + return -EINVAL; | |
85 | + } | |
86 | + | |
87 | + noset_dpll_as_rate = of_property_read_bool(np, "noset-dpll-rate"); | |
88 | + | |
89 | + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); | |
90 | + if (d == NULL) { | |
91 | + dev_err(dev, "%s: Cannot allocate memory.\n", __func__); | |
92 | + err = -ENOMEM; | |
93 | + goto out; | |
94 | + } | |
95 | + platform_set_drvdata(pdev, d); | |
96 | + | |
97 | + d->dpll_clk = devm_clk_get(dev, DPLL_CLK_NAME); | |
98 | + if (IS_ERR(d->dpll_clk)) { | |
99 | + err = PTR_ERR(d->dpll_clk); | |
100 | + dev_err(dev, "%s: Cannot get dpll clk(%d).\n", __func__, err); | |
101 | + d->dpll_clk = NULL; | |
102 | + } | |
103 | + | |
104 | + d->dev_clk = devm_clk_get(dev, DEV_CLK_NAME); | |
105 | + if (IS_ERR(d->dev_clk)) { | |
106 | + err = PTR_ERR(d->dpll_clk); | |
107 | + dev_err(dev, "%s: Cannot get func clk(%d).\n", __func__, err); | |
108 | + goto out; | |
109 | + } | |
110 | + | |
111 | + if (noset_dpll_as_rate) | |
112 | + d->dpll_clk = NULL; | |
113 | + | |
114 | + err = of_init_opp_table(dev); | |
115 | + if (err) { | |
116 | + dev_err(dev, "%s: Cannot initialize opp table(%d).\n", __func__, | |
117 | + err); | |
118 | + goto out; | |
119 | + } | |
120 | + d->dev = dev; | |
121 | + | |
122 | + /* Register voltage domain notifier */ | |
123 | + d->clk_nb = of_pm_voltdm_notifier_register(dev, np, d->dev_clk, | |
124 | + "coproc", | |
125 | + &voltage_latency); | |
126 | + if (IS_ERR(d->clk_nb)) { | |
127 | + err = PTR_ERR(d->clk_nb); | |
128 | + /* defer probe if regulator is not yet registered */ | |
129 | + if (err == -EPROBE_DEFER) { | |
130 | + dev_err(dev, | |
131 | + "coproc clock notifier not ready, retry\n"); | |
132 | + } else { | |
133 | + dev_err(dev, | |
134 | + "Failed to register coproc clk notifier: %d\n", | |
135 | + err); | |
136 | + } | |
137 | + goto out; | |
138 | + } | |
139 | + | |
140 | + if (target_freq) { | |
141 | + if (d->dpll_clk) { | |
142 | + err = clk_set_rate(d->dpll_clk, target_freq); | |
143 | + if (err) { | |
144 | + dev_err(dev, "%s: Cannot set dpll clock rate(%d).\n", | |
145 | + __func__, err); | |
146 | + goto out; | |
147 | + } | |
148 | + } | |
149 | + | |
150 | + err = clk_set_rate(d->dev_clk, target_freq); | |
151 | + if (err) { | |
152 | + dev_err(dev, "%s: Cannot set func clock rate(%d).\n", | |
153 | + __func__, err); | |
154 | + goto out; | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + /* All good.. */ | |
159 | + goto out; | |
160 | + | |
161 | +out: | |
162 | + dev_info(dev, "%s result=%d", __func__, err); | |
163 | + return err; | |
164 | +} | |
165 | + | |
166 | +static int coproc_remove(struct platform_device *pdev) | |
167 | +{ | |
168 | + struct coproc_data *d = platform_get_drvdata(pdev); | |
169 | + struct device *dev = &pdev->dev; | |
170 | + | |
171 | + dev_info(dev, "remove\n"); | |
172 | + | |
173 | + of_pm_voltdm_notifier_unregister(d->clk_nb); | |
174 | + | |
175 | + dev_info(dev, "%s Removed\n", __func__); | |
176 | + return 0; | |
177 | +} | |
178 | + | |
179 | +/** | |
180 | + * coproc_suspend() - dummy hook for suspend | |
181 | + * @dev: device pointer | |
182 | + * | |
183 | + * Return: 0 | |
184 | + */ | |
185 | +static int coproc_suspend(struct device *dev) | |
186 | +{ | |
187 | + dev_info(dev, "suspend\n"); | |
188 | + return 0; | |
189 | +} | |
190 | + | |
191 | +/** | |
192 | + * coproc_resume() - dummy hook for resume | |
193 | + * @dev: device pointer | |
194 | + * | |
195 | + * Return: 0 | |
196 | + */ | |
197 | +static int coproc_resume(struct device *dev) | |
198 | +{ | |
199 | + dev_info(dev, "resume\n"); | |
200 | + return 0; | |
201 | +} | |
202 | + | |
203 | +/* Device power management hooks */ | |
204 | +static SIMPLE_DEV_PM_OPS(coproc_pm, | |
205 | + coproc_suspend, | |
206 | + coproc_resume); | |
207 | + | |
208 | +static struct of_device_id of_coproc_match[] = { | |
209 | + {.compatible = "ti,coproc"}, | |
210 | + {}, | |
211 | +}; | |
212 | + | |
213 | +MODULE_DEVICE_TABLE(of, of_coproc_match); | |
214 | + | |
215 | +static struct platform_driver coproc_driver = { | |
216 | + .probe = coproc_probe, | |
217 | + .remove = coproc_remove, | |
218 | + .driver = { | |
219 | + .name = "coproc", | |
220 | + .owner = THIS_MODULE, | |
221 | + .of_match_table = of_match_ptr(of_coproc_match), | |
222 | + .pm = &coproc_pm, | |
223 | + }, | |
224 | +}; | |
225 | +module_platform_driver(coproc_driver); | |
226 | + | |
227 | +MODULE_LICENSE("GPL v2"); | |
228 | +MODULE_DESCRIPTION("OMAP Co-processor Driver"); | |
229 | +MODULE_AUTHOR("Texas Instruments Inc."); |