1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Qualcomm Wireless Connectivity Subsystem Iris driver |
4 | * |
5 | * Copyright (C) 2016 Linaro Ltd |
6 | * Copyright (C) 2014 Sony Mobile Communications AB |
7 | * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_device.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/regulator/consumer.h> |
17 | |
18 | #include "qcom_wcnss.h" |
19 | |
20 | struct qcom_iris { |
21 | struct device dev; |
22 | |
23 | struct clk *xo_clk; |
24 | |
25 | struct regulator_bulk_data *vregs; |
26 | size_t num_vregs; |
27 | }; |
28 | |
29 | struct iris_data { |
30 | const struct wcnss_vreg_info *vregs; |
31 | size_t num_vregs; |
32 | |
33 | bool use_48mhz_xo; |
34 | }; |
35 | |
36 | static const struct iris_data wcn3620_data = { |
37 | .vregs = (struct wcnss_vreg_info[]) { |
38 | { "vddxo" , 1800000, 1800000, 10000 }, |
39 | { "vddrfa" , 1300000, 1300000, 100000 }, |
40 | { "vddpa" , 3300000, 3300000, 515000 }, |
41 | { "vdddig" , 1800000, 1800000, 10000 }, |
42 | }, |
43 | .num_vregs = 4, |
44 | .use_48mhz_xo = false, |
45 | }; |
46 | |
47 | static const struct iris_data wcn3660_data = { |
48 | .vregs = (struct wcnss_vreg_info[]) { |
49 | { "vddxo" , 1800000, 1800000, 10000 }, |
50 | { "vddrfa" , 1300000, 1300000, 100000 }, |
51 | { "vddpa" , 2900000, 3000000, 515000 }, |
52 | { "vdddig" , 1200000, 1225000, 10000 }, |
53 | }, |
54 | .num_vregs = 4, |
55 | .use_48mhz_xo = true, |
56 | }; |
57 | |
58 | static const struct iris_data wcn3680_data = { |
59 | .vregs = (struct wcnss_vreg_info[]) { |
60 | { "vddxo" , 1800000, 1800000, 10000 }, |
61 | { "vddrfa" , 1300000, 1300000, 100000 }, |
62 | { "vddpa" , 3300000, 3300000, 515000 }, |
63 | { "vdddig" , 1800000, 1800000, 10000 }, |
64 | }, |
65 | .num_vregs = 4, |
66 | .use_48mhz_xo = true, |
67 | }; |
68 | |
69 | int qcom_iris_enable(struct qcom_iris *iris) |
70 | { |
71 | int ret; |
72 | |
73 | ret = regulator_bulk_enable(num_consumers: iris->num_vregs, consumers: iris->vregs); |
74 | if (ret) |
75 | return ret; |
76 | |
77 | ret = clk_prepare_enable(clk: iris->xo_clk); |
78 | if (ret) { |
79 | dev_err(&iris->dev, "failed to enable xo clk\n" ); |
80 | goto disable_regulators; |
81 | } |
82 | |
83 | return 0; |
84 | |
85 | disable_regulators: |
86 | regulator_bulk_disable(num_consumers: iris->num_vregs, consumers: iris->vregs); |
87 | |
88 | return ret; |
89 | } |
90 | |
91 | void qcom_iris_disable(struct qcom_iris *iris) |
92 | { |
93 | clk_disable_unprepare(clk: iris->xo_clk); |
94 | regulator_bulk_disable(num_consumers: iris->num_vregs, consumers: iris->vregs); |
95 | } |
96 | |
97 | static const struct of_device_id iris_of_match[] = { |
98 | { .compatible = "qcom,wcn3620" , .data = &wcn3620_data }, |
99 | { .compatible = "qcom,wcn3660" , .data = &wcn3660_data }, |
100 | { .compatible = "qcom,wcn3660b" , .data = &wcn3680_data }, |
101 | { .compatible = "qcom,wcn3680" , .data = &wcn3680_data }, |
102 | {} |
103 | }; |
104 | |
105 | static void qcom_iris_release(struct device *dev) |
106 | { |
107 | struct qcom_iris *iris = container_of(dev, struct qcom_iris, dev); |
108 | |
109 | of_node_put(node: iris->dev.of_node); |
110 | kfree(objp: iris); |
111 | } |
112 | |
113 | struct qcom_iris *qcom_iris_probe(struct device *parent, bool *use_48mhz_xo) |
114 | { |
115 | const struct of_device_id *match; |
116 | const struct iris_data *data; |
117 | struct device_node *of_node; |
118 | struct qcom_iris *iris; |
119 | int ret; |
120 | int i; |
121 | |
122 | of_node = of_get_child_by_name(node: parent->of_node, name: "iris" ); |
123 | if (!of_node) { |
124 | dev_err(parent, "No child node \"iris\" found\n" ); |
125 | return ERR_PTR(error: -EINVAL); |
126 | } |
127 | |
128 | iris = kzalloc(size: sizeof(*iris), GFP_KERNEL); |
129 | if (!iris) { |
130 | of_node_put(node: of_node); |
131 | return ERR_PTR(error: -ENOMEM); |
132 | } |
133 | |
134 | device_initialize(dev: &iris->dev); |
135 | iris->dev.parent = parent; |
136 | iris->dev.release = qcom_iris_release; |
137 | iris->dev.of_node = of_node; |
138 | |
139 | dev_set_name(dev: &iris->dev, name: "%s.iris" , dev_name(dev: parent)); |
140 | |
141 | ret = device_add(dev: &iris->dev); |
142 | if (ret) { |
143 | put_device(dev: &iris->dev); |
144 | return ERR_PTR(error: ret); |
145 | } |
146 | |
147 | match = of_match_device(matches: iris_of_match, dev: &iris->dev); |
148 | if (!match) { |
149 | dev_err(&iris->dev, "no matching compatible for iris\n" ); |
150 | ret = -EINVAL; |
151 | goto err_device_del; |
152 | } |
153 | |
154 | data = match->data; |
155 | |
156 | iris->xo_clk = devm_clk_get(dev: &iris->dev, id: "xo" ); |
157 | if (IS_ERR(ptr: iris->xo_clk)) { |
158 | ret = PTR_ERR(ptr: iris->xo_clk); |
159 | if (ret != -EPROBE_DEFER) |
160 | dev_err(&iris->dev, "failed to acquire xo clk\n" ); |
161 | goto err_device_del; |
162 | } |
163 | |
164 | iris->num_vregs = data->num_vregs; |
165 | iris->vregs = devm_kcalloc(dev: &iris->dev, |
166 | n: iris->num_vregs, |
167 | size: sizeof(struct regulator_bulk_data), |
168 | GFP_KERNEL); |
169 | if (!iris->vregs) { |
170 | ret = -ENOMEM; |
171 | goto err_device_del; |
172 | } |
173 | |
174 | for (i = 0; i < iris->num_vregs; i++) |
175 | iris->vregs[i].supply = data->vregs[i].name; |
176 | |
177 | ret = devm_regulator_bulk_get(dev: &iris->dev, num_consumers: iris->num_vregs, consumers: iris->vregs); |
178 | if (ret) { |
179 | dev_err(&iris->dev, "failed to get regulators\n" ); |
180 | goto err_device_del; |
181 | } |
182 | |
183 | for (i = 0; i < iris->num_vregs; i++) { |
184 | if (data->vregs[i].max_voltage) |
185 | regulator_set_voltage(regulator: iris->vregs[i].consumer, |
186 | min_uV: data->vregs[i].min_voltage, |
187 | max_uV: data->vregs[i].max_voltage); |
188 | |
189 | if (data->vregs[i].load_uA) |
190 | regulator_set_load(regulator: iris->vregs[i].consumer, |
191 | load_uA: data->vregs[i].load_uA); |
192 | } |
193 | |
194 | *use_48mhz_xo = data->use_48mhz_xo; |
195 | |
196 | return iris; |
197 | |
198 | err_device_del: |
199 | device_del(dev: &iris->dev); |
200 | |
201 | return ERR_PTR(error: ret); |
202 | } |
203 | |
204 | void qcom_iris_remove(struct qcom_iris *iris) |
205 | { |
206 | device_del(dev: &iris->dev); |
207 | } |
208 | |