Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Qualcomm Wireless Connectivity Subsystem Iris driver
  3 *
  4 * Copyright (C) 2016 Linaro Ltd
  5 * Copyright (C) 2014 Sony Mobile Communications AB
  6 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * version 2 as published by the Free Software Foundation.
 11 *
 12 * This program is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 * GNU General Public License for more details.
 16 */
 17
 18#include <linux/clk.h>
 19#include <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/of_device.h>
 22#include <linux/platform_device.h>
 23#include <linux/regulator/consumer.h>
 24
 25#include "qcom_wcnss.h"
 26
 27struct qcom_iris {
 28	struct device *dev;
 29
 30	struct clk *xo_clk;
 31
 32	struct regulator_bulk_data *vregs;
 33	size_t num_vregs;
 34};
 35
 36struct iris_data {
 37	const struct wcnss_vreg_info *vregs;
 38	size_t num_vregs;
 39
 40	bool use_48mhz_xo;
 41};
 42
 43static const struct iris_data wcn3620_data = {
 44	.vregs = (struct wcnss_vreg_info[]) {
 45		{ "vddxo",  1800000, 1800000, 10000 },
 46		{ "vddrfa", 1300000, 1300000, 100000 },
 47		{ "vddpa",  3300000, 3300000, 515000 },
 48		{ "vdddig", 1800000, 1800000, 10000 },
 49	},
 50	.num_vregs = 4,
 51	.use_48mhz_xo = false,
 52};
 53
 54static const struct iris_data wcn3660_data = {
 55	.vregs = (struct wcnss_vreg_info[]) {
 56		{ "vddxo",  1800000, 1800000, 10000 },
 57		{ "vddrfa", 1300000, 1300000, 100000 },
 58		{ "vddpa",  2900000, 3000000, 515000 },
 59		{ "vdddig", 1200000, 1225000, 10000 },
 60	},
 61	.num_vregs = 4,
 62	.use_48mhz_xo = true,
 63};
 64
 65static const struct iris_data wcn3680_data = {
 66	.vregs = (struct wcnss_vreg_info[]) {
 67		{ "vddxo",  1800000, 1800000, 10000 },
 68		{ "vddrfa", 1300000, 1300000, 100000 },
 69		{ "vddpa",  3300000, 3300000, 515000 },
 70		{ "vdddig", 1800000, 1800000, 10000 },
 71	},
 72	.num_vregs = 4,
 73	.use_48mhz_xo = true,
 74};
 75
 76int qcom_iris_enable(struct qcom_iris *iris)
 77{
 78	int ret;
 79
 80	ret = regulator_bulk_enable(iris->num_vregs, iris->vregs);
 81	if (ret)
 82		return ret;
 83
 84	ret = clk_prepare_enable(iris->xo_clk);
 85	if (ret) {
 86		dev_err(iris->dev, "failed to enable xo clk\n");
 87		goto disable_regulators;
 88	}
 89
 90	return 0;
 91
 92disable_regulators:
 93	regulator_bulk_disable(iris->num_vregs, iris->vregs);
 94
 95	return ret;
 96}
 97
 98void qcom_iris_disable(struct qcom_iris *iris)
 99{
100	clk_disable_unprepare(iris->xo_clk);
101	regulator_bulk_disable(iris->num_vregs, iris->vregs);
102}
103
104static int qcom_iris_probe(struct platform_device *pdev)
105{
106	const struct iris_data *data;
107	struct qcom_wcnss *wcnss;
108	struct qcom_iris *iris;
109	int ret;
110	int i;
111
112	iris = devm_kzalloc(&pdev->dev, sizeof(struct qcom_iris), GFP_KERNEL);
113	if (!iris)
114		return -ENOMEM;
115
116	data = of_device_get_match_data(&pdev->dev);
117	wcnss = dev_get_drvdata(pdev->dev.parent);
118
119	iris->xo_clk = devm_clk_get(&pdev->dev, "xo");
120	if (IS_ERR(iris->xo_clk)) {
121		if (PTR_ERR(iris->xo_clk) != -EPROBE_DEFER)
122			dev_err(&pdev->dev, "failed to acquire xo clk\n");
123		return PTR_ERR(iris->xo_clk);
124	}
125
126	iris->num_vregs = data->num_vregs;
127	iris->vregs = devm_kcalloc(&pdev->dev,
128				   iris->num_vregs,
129				   sizeof(struct regulator_bulk_data),
130				   GFP_KERNEL);
131	if (!iris->vregs)
132		return -ENOMEM;
133
134	for (i = 0; i < iris->num_vregs; i++)
135		iris->vregs[i].supply = data->vregs[i].name;
136
137	ret = devm_regulator_bulk_get(&pdev->dev, iris->num_vregs, iris->vregs);
138	if (ret) {
139		dev_err(&pdev->dev, "failed to get regulators\n");
140		return ret;
141	}
142
143	for (i = 0; i < iris->num_vregs; i++) {
144		if (data->vregs[i].max_voltage)
145			regulator_set_voltage(iris->vregs[i].consumer,
146					      data->vregs[i].min_voltage,
147					      data->vregs[i].max_voltage);
148
149		if (data->vregs[i].load_uA)
150			regulator_set_load(iris->vregs[i].consumer,
151					   data->vregs[i].load_uA);
152	}
153
154	qcom_wcnss_assign_iris(wcnss, iris, data->use_48mhz_xo);
155
156	return 0;
157}
158
159static int qcom_iris_remove(struct platform_device *pdev)
160{
161	struct qcom_wcnss *wcnss = dev_get_drvdata(pdev->dev.parent);
162
163	qcom_wcnss_assign_iris(wcnss, NULL, false);
164
165	return 0;
166}
167
168static const struct of_device_id iris_of_match[] = {
169	{ .compatible = "qcom,wcn3620", .data = &wcn3620_data },
170	{ .compatible = "qcom,wcn3660", .data = &wcn3660_data },
171	{ .compatible = "qcom,wcn3680", .data = &wcn3680_data },
172	{}
173};
174MODULE_DEVICE_TABLE(of, iris_of_match);
175
176struct platform_driver qcom_iris_driver = {
177	.probe = qcom_iris_probe,
178	.remove = qcom_iris_remove,
179	.driver = {
180		.name = "qcom-iris",
181		.of_match_table = iris_of_match,
182	},
183};