11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2aed361adSBjorn Andersson /*
3aed361adSBjorn Andersson * Qualcomm Wireless Connectivity Subsystem Iris driver
4aed361adSBjorn Andersson *
5aed361adSBjorn Andersson * Copyright (C) 2016 Linaro Ltd
6aed361adSBjorn Andersson * Copyright (C) 2014 Sony Mobile Communications AB
7aed361adSBjorn Andersson * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
8aed361adSBjorn Andersson */
9aed361adSBjorn Andersson
10aed361adSBjorn Andersson #include <linux/clk.h>
11aed361adSBjorn Andersson #include <linux/kernel.h>
12aed361adSBjorn Andersson #include <linux/module.h>
13*3440d8daSRob Herring #include <linux/of.h>
14aed361adSBjorn Andersson #include <linux/of_device.h>
15aed361adSBjorn Andersson #include <linux/platform_device.h>
16aed361adSBjorn Andersson #include <linux/regulator/consumer.h>
17aed361adSBjorn Andersson
18aed361adSBjorn Andersson #include "qcom_wcnss.h"
19aed361adSBjorn Andersson
20aed361adSBjorn Andersson struct qcom_iris {
211fcef985SBjorn Andersson struct device dev;
22aed361adSBjorn Andersson
23aed361adSBjorn Andersson struct clk *xo_clk;
24aed361adSBjorn Andersson
25aed361adSBjorn Andersson struct regulator_bulk_data *vregs;
26aed361adSBjorn Andersson size_t num_vregs;
27aed361adSBjorn Andersson };
28aed361adSBjorn Andersson
29aed361adSBjorn Andersson struct iris_data {
30aed361adSBjorn Andersson const struct wcnss_vreg_info *vregs;
31aed361adSBjorn Andersson size_t num_vregs;
32aed361adSBjorn Andersson
33aed361adSBjorn Andersson bool use_48mhz_xo;
34aed361adSBjorn Andersson };
35aed361adSBjorn Andersson
36aed361adSBjorn Andersson static const struct iris_data wcn3620_data = {
37aed361adSBjorn Andersson .vregs = (struct wcnss_vreg_info[]) {
38aed361adSBjorn Andersson { "vddxo", 1800000, 1800000, 10000 },
39aed361adSBjorn Andersson { "vddrfa", 1300000, 1300000, 100000 },
40aed361adSBjorn Andersson { "vddpa", 3300000, 3300000, 515000 },
41aed361adSBjorn Andersson { "vdddig", 1800000, 1800000, 10000 },
42aed361adSBjorn Andersson },
43aed361adSBjorn Andersson .num_vregs = 4,
44aed361adSBjorn Andersson .use_48mhz_xo = false,
45aed361adSBjorn Andersson };
46aed361adSBjorn Andersson
47aed361adSBjorn Andersson static const struct iris_data wcn3660_data = {
48aed361adSBjorn Andersson .vregs = (struct wcnss_vreg_info[]) {
49aed361adSBjorn Andersson { "vddxo", 1800000, 1800000, 10000 },
50aed361adSBjorn Andersson { "vddrfa", 1300000, 1300000, 100000 },
51aed361adSBjorn Andersson { "vddpa", 2900000, 3000000, 515000 },
52aed361adSBjorn Andersson { "vdddig", 1200000, 1225000, 10000 },
53aed361adSBjorn Andersson },
54aed361adSBjorn Andersson .num_vregs = 4,
55aed361adSBjorn Andersson .use_48mhz_xo = true,
56aed361adSBjorn Andersson };
57aed361adSBjorn Andersson
58aed361adSBjorn Andersson static const struct iris_data wcn3680_data = {
59aed361adSBjorn Andersson .vregs = (struct wcnss_vreg_info[]) {
60aed361adSBjorn Andersson { "vddxo", 1800000, 1800000, 10000 },
61aed361adSBjorn Andersson { "vddrfa", 1300000, 1300000, 100000 },
62aed361adSBjorn Andersson { "vddpa", 3300000, 3300000, 515000 },
63aed361adSBjorn Andersson { "vdddig", 1800000, 1800000, 10000 },
64aed361adSBjorn Andersson },
65aed361adSBjorn Andersson .num_vregs = 4,
66aed361adSBjorn Andersson .use_48mhz_xo = true,
67aed361adSBjorn Andersson };
68aed361adSBjorn Andersson
qcom_iris_enable(struct qcom_iris * iris)69aed361adSBjorn Andersson int qcom_iris_enable(struct qcom_iris *iris)
70aed361adSBjorn Andersson {
71aed361adSBjorn Andersson int ret;
72aed361adSBjorn Andersson
73aed361adSBjorn Andersson ret = regulator_bulk_enable(iris->num_vregs, iris->vregs);
74aed361adSBjorn Andersson if (ret)
75aed361adSBjorn Andersson return ret;
76aed361adSBjorn Andersson
77aed361adSBjorn Andersson ret = clk_prepare_enable(iris->xo_clk);
78aed361adSBjorn Andersson if (ret) {
791fcef985SBjorn Andersson dev_err(&iris->dev, "failed to enable xo clk\n");
80aed361adSBjorn Andersson goto disable_regulators;
81aed361adSBjorn Andersson }
82aed361adSBjorn Andersson
83aed361adSBjorn Andersson return 0;
84aed361adSBjorn Andersson
85aed361adSBjorn Andersson disable_regulators:
86aed361adSBjorn Andersson regulator_bulk_disable(iris->num_vregs, iris->vregs);
87aed361adSBjorn Andersson
88aed361adSBjorn Andersson return ret;
89aed361adSBjorn Andersson }
90aed361adSBjorn Andersson
qcom_iris_disable(struct qcom_iris * iris)91aed361adSBjorn Andersson void qcom_iris_disable(struct qcom_iris *iris)
92aed361adSBjorn Andersson {
93aed361adSBjorn Andersson clk_disable_unprepare(iris->xo_clk);
94aed361adSBjorn Andersson regulator_bulk_disable(iris->num_vregs, iris->vregs);
95aed361adSBjorn Andersson }
96aed361adSBjorn Andersson
971fcef985SBjorn Andersson static const struct of_device_id iris_of_match[] = {
981fcef985SBjorn Andersson { .compatible = "qcom,wcn3620", .data = &wcn3620_data },
991fcef985SBjorn Andersson { .compatible = "qcom,wcn3660", .data = &wcn3660_data },
1001fcef985SBjorn Andersson { .compatible = "qcom,wcn3660b", .data = &wcn3680_data },
1011fcef985SBjorn Andersson { .compatible = "qcom,wcn3680", .data = &wcn3680_data },
1021fcef985SBjorn Andersson {}
1031fcef985SBjorn Andersson };
1041fcef985SBjorn Andersson
qcom_iris_release(struct device * dev)1051fcef985SBjorn Andersson static void qcom_iris_release(struct device *dev)
106aed361adSBjorn Andersson {
1071fcef985SBjorn Andersson struct qcom_iris *iris = container_of(dev, struct qcom_iris, dev);
1081fcef985SBjorn Andersson
1091fcef985SBjorn Andersson of_node_put(iris->dev.of_node);
1101fcef985SBjorn Andersson kfree(iris);
1111fcef985SBjorn Andersson }
1121fcef985SBjorn Andersson
qcom_iris_probe(struct device * parent,bool * use_48mhz_xo)1131fcef985SBjorn Andersson struct qcom_iris *qcom_iris_probe(struct device *parent, bool *use_48mhz_xo)
1141fcef985SBjorn Andersson {
1151fcef985SBjorn Andersson const struct of_device_id *match;
116aed361adSBjorn Andersson const struct iris_data *data;
1171fcef985SBjorn Andersson struct device_node *of_node;
118aed361adSBjorn Andersson struct qcom_iris *iris;
119aed361adSBjorn Andersson int ret;
120aed361adSBjorn Andersson int i;
121aed361adSBjorn Andersson
1221fcef985SBjorn Andersson of_node = of_get_child_by_name(parent->of_node, "iris");
1231fcef985SBjorn Andersson if (!of_node) {
1241fcef985SBjorn Andersson dev_err(parent, "No child node \"iris\" found\n");
1251fcef985SBjorn Andersson return ERR_PTR(-EINVAL);
1261fcef985SBjorn Andersson }
127aed361adSBjorn Andersson
1281fcef985SBjorn Andersson iris = kzalloc(sizeof(*iris), GFP_KERNEL);
1291fcef985SBjorn Andersson if (!iris) {
1301fcef985SBjorn Andersson of_node_put(of_node);
1311fcef985SBjorn Andersson return ERR_PTR(-ENOMEM);
1321fcef985SBjorn Andersson }
133aed361adSBjorn Andersson
1341fcef985SBjorn Andersson device_initialize(&iris->dev);
1351fcef985SBjorn Andersson iris->dev.parent = parent;
1361fcef985SBjorn Andersson iris->dev.release = qcom_iris_release;
1371fcef985SBjorn Andersson iris->dev.of_node = of_node;
1381fcef985SBjorn Andersson
1391fcef985SBjorn Andersson dev_set_name(&iris->dev, "%s.iris", dev_name(parent));
1401fcef985SBjorn Andersson
1411fcef985SBjorn Andersson ret = device_add(&iris->dev);
1421fcef985SBjorn Andersson if (ret) {
1431fcef985SBjorn Andersson put_device(&iris->dev);
1441fcef985SBjorn Andersson return ERR_PTR(ret);
1451fcef985SBjorn Andersson }
1461fcef985SBjorn Andersson
1471fcef985SBjorn Andersson match = of_match_device(iris_of_match, &iris->dev);
1481fcef985SBjorn Andersson if (!match) {
1491fcef985SBjorn Andersson dev_err(&iris->dev, "no matching compatible for iris\n");
1501fcef985SBjorn Andersson ret = -EINVAL;
1511fcef985SBjorn Andersson goto err_device_del;
1521fcef985SBjorn Andersson }
1531fcef985SBjorn Andersson
1541fcef985SBjorn Andersson data = match->data;
1551fcef985SBjorn Andersson
1561fcef985SBjorn Andersson iris->xo_clk = devm_clk_get(&iris->dev, "xo");
157aed361adSBjorn Andersson if (IS_ERR(iris->xo_clk)) {
1581fcef985SBjorn Andersson ret = PTR_ERR(iris->xo_clk);
1591fcef985SBjorn Andersson if (ret != -EPROBE_DEFER)
1601fcef985SBjorn Andersson dev_err(&iris->dev, "failed to acquire xo clk\n");
1611fcef985SBjorn Andersson goto err_device_del;
162aed361adSBjorn Andersson }
163aed361adSBjorn Andersson
164aed361adSBjorn Andersson iris->num_vregs = data->num_vregs;
1651fcef985SBjorn Andersson iris->vregs = devm_kcalloc(&iris->dev,
166aed361adSBjorn Andersson iris->num_vregs,
167aed361adSBjorn Andersson sizeof(struct regulator_bulk_data),
168aed361adSBjorn Andersson GFP_KERNEL);
1691fcef985SBjorn Andersson if (!iris->vregs) {
1701fcef985SBjorn Andersson ret = -ENOMEM;
1711fcef985SBjorn Andersson goto err_device_del;
1721fcef985SBjorn Andersson }
173aed361adSBjorn Andersson
174aed361adSBjorn Andersson for (i = 0; i < iris->num_vregs; i++)
175aed361adSBjorn Andersson iris->vregs[i].supply = data->vregs[i].name;
176aed361adSBjorn Andersson
1771fcef985SBjorn Andersson ret = devm_regulator_bulk_get(&iris->dev, iris->num_vregs, iris->vregs);
178aed361adSBjorn Andersson if (ret) {
1791fcef985SBjorn Andersson dev_err(&iris->dev, "failed to get regulators\n");
1801fcef985SBjorn Andersson goto err_device_del;
181aed361adSBjorn Andersson }
182aed361adSBjorn Andersson
183aed361adSBjorn Andersson for (i = 0; i < iris->num_vregs; i++) {
184aed361adSBjorn Andersson if (data->vregs[i].max_voltage)
185aed361adSBjorn Andersson regulator_set_voltage(iris->vregs[i].consumer,
186aed361adSBjorn Andersson data->vregs[i].min_voltage,
187aed361adSBjorn Andersson data->vregs[i].max_voltage);
188aed361adSBjorn Andersson
189aed361adSBjorn Andersson if (data->vregs[i].load_uA)
190aed361adSBjorn Andersson regulator_set_load(iris->vregs[i].consumer,
191aed361adSBjorn Andersson data->vregs[i].load_uA);
192aed361adSBjorn Andersson }
193aed361adSBjorn Andersson
1941fcef985SBjorn Andersson *use_48mhz_xo = data->use_48mhz_xo;
195aed361adSBjorn Andersson
1961fcef985SBjorn Andersson return iris;
1971fcef985SBjorn Andersson
1981fcef985SBjorn Andersson err_device_del:
1991fcef985SBjorn Andersson device_del(&iris->dev);
2001fcef985SBjorn Andersson
2011fcef985SBjorn Andersson return ERR_PTR(ret);
202aed361adSBjorn Andersson }
203aed361adSBjorn Andersson
qcom_iris_remove(struct qcom_iris * iris)2041fcef985SBjorn Andersson void qcom_iris_remove(struct qcom_iris *iris)
205aed361adSBjorn Andersson {
2061fcef985SBjorn Andersson device_del(&iris->dev);
207aed361adSBjorn Andersson }
208