blob: 0dadb7489aa55e9cc0e43e753df3874a72b2937d [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08002/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 */
4
5#include <linux/kernel.h>
6#include <linux/init.h>
7#include <linux/err.h>
8#include <linux/module.h>
9#include <linux/of.h>
10#include <linux/of_device.h>
11#include <linux/platform_device.h>
12#include <linux/gpio.h>
13#include <linux/of_gpio.h>
Meng Wang11a25cf2018-10-31 14:11:26 +080014#include <asoc/msm-cdc-pinctrl.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015
16struct msm_cdc_pinctrl_info {
17 struct pinctrl *pinctrl;
18 struct pinctrl_state *pinctrl_active;
19 struct pinctrl_state *pinctrl_sleep;
20 int gpio;
21 bool state;
22};
23
24static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
25 struct device_node *np)
26{
27 struct platform_device *pdev;
28 struct msm_cdc_pinctrl_info *gpio_data;
29
30 if (!np) {
31 pr_err("%s: device node is null\n", __func__);
32 return NULL;
33 }
34
35 pdev = of_find_device_by_node(np);
36 if (!pdev) {
37 pr_err("%s: platform device not found!\n", __func__);
38 return NULL;
39 }
40
41 gpio_data = dev_get_drvdata(&pdev->dev);
42 if (!gpio_data)
43 dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
44 __func__);
45
46 return gpio_data;
47}
48
49/*
50 * msm_cdc_get_gpio_state: select pinctrl sleep state
51 * @np: pointer to struct device_node
52 *
53 * Returns error code for failure and GPIO value on success
54 */
55int msm_cdc_get_gpio_state(struct device_node *np)
56{
57 struct msm_cdc_pinctrl_info *gpio_data;
58 int value = -EINVAL;
59
60 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
61 if (!gpio_data)
62 return value;
63
64 if (gpio_is_valid(gpio_data->gpio))
65 value = gpio_get_value_cansleep(gpio_data->gpio);
66
67 return value;
68}
69EXPORT_SYMBOL(msm_cdc_get_gpio_state);
70
71/*
72 * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state
73 * @np: pointer to struct device_node
74 *
75 * Returns error code for failure
76 */
77int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
78{
79 struct msm_cdc_pinctrl_info *gpio_data;
80
81 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
82 if (!gpio_data)
83 return -EINVAL;
84
85 if (!gpio_data->pinctrl_sleep) {
86 pr_err("%s: pinctrl sleep state is null\n", __func__);
87 return -EINVAL;
88 }
89 gpio_data->state = false;
90
91 return pinctrl_select_state(gpio_data->pinctrl,
92 gpio_data->pinctrl_sleep);
93}
94EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
95
96/*
97 * msm_cdc_pinctrl_select_active_state: select pinctrl active state
98 * @np: pointer to struct device_node
99 *
100 * Returns error code for failure
101 */
102int msm_cdc_pinctrl_select_active_state(struct device_node *np)
103{
104 struct msm_cdc_pinctrl_info *gpio_data;
105
106 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
107 if (!gpio_data)
108 return -EINVAL;
109
110 if (!gpio_data->pinctrl_active) {
111 pr_err("%s: pinctrl active state is null\n", __func__);
112 return -EINVAL;
113 }
114 gpio_data->state = true;
115
116 return pinctrl_select_state(gpio_data->pinctrl,
117 gpio_data->pinctrl_active);
118}
119EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state);
120
121/*
122 * msm_cdc_pinctrl_get_state: get curren pinctrl state
123 * @np: pointer to struct device_node
124 *
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700125 * Returns 0 for sleep state, 1 for active state,
126 * error code for failure
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530127 */
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700128int msm_cdc_pinctrl_get_state(struct device_node *np)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530129{
130 struct msm_cdc_pinctrl_info *gpio_data;
131
132 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
133 if (!gpio_data)
134 return -EINVAL;
135
136 return gpio_data->state;
137}
138EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
139
140static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
141{
142 int ret = 0;
143 struct msm_cdc_pinctrl_info *gpio_data;
144
145 gpio_data = devm_kzalloc(&pdev->dev,
146 sizeof(struct msm_cdc_pinctrl_info),
147 GFP_KERNEL);
148 if (!gpio_data)
149 return -ENOMEM;
150
151 gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
152 if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
153 dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
154 __func__, PTR_ERR(gpio_data->pinctrl));
155 ret = PTR_ERR(gpio_data->pinctrl);
156 goto err_pctrl_get;
157 }
158
159 gpio_data->pinctrl_active = pinctrl_lookup_state(
160 gpio_data->pinctrl, "aud_active");
161 if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
162 dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
163 __func__, PTR_ERR(gpio_data->pinctrl_active));
164 ret = PTR_ERR(gpio_data->pinctrl_active);
165 goto err_lookup_state;
166 }
167
168 gpio_data->pinctrl_sleep = pinctrl_lookup_state(
169 gpio_data->pinctrl, "aud_sleep");
170 if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
171 dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
172 __func__, PTR_ERR(gpio_data->pinctrl_sleep));
173 ret = PTR_ERR(gpio_data->pinctrl_sleep);
174 goto err_lookup_state;
175 }
176 /* skip setting to sleep state for LPI_TLMM GPIOs */
177 if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
178 /* Set pinctrl state to aud_sleep by default */
179 ret = pinctrl_select_state(gpio_data->pinctrl,
180 gpio_data->pinctrl_sleep);
181 if (ret)
182 dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
183 __func__, ret);
184 }
185
186 gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
187 "qcom,cdc-rst-n-gpio", 0);
188 if (gpio_is_valid(gpio_data->gpio)) {
189 ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
190 if (ret) {
191 dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
192 __func__, gpio_data->gpio);
193 goto err_lookup_state;
194 }
195 }
196
197 dev_set_drvdata(&pdev->dev, gpio_data);
198 return 0;
199
200err_lookup_state:
201 devm_pinctrl_put(gpio_data->pinctrl);
202err_pctrl_get:
203 devm_kfree(&pdev->dev, gpio_data);
204 return ret;
205}
206
207static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
208{
209 struct msm_cdc_pinctrl_info *gpio_data;
210
211 gpio_data = dev_get_drvdata(&pdev->dev);
212
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +0530213 /* to free the requested gpio before exiting */
214 if (gpio_data) {
215 if (gpio_is_valid(gpio_data->gpio))
216 gpio_free(gpio_data->gpio);
217
218 if (gpio_data->pinctrl)
219 devm_pinctrl_put(gpio_data->pinctrl);
220 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530221
222 devm_kfree(&pdev->dev, gpio_data);
223
224 return 0;
225}
226
227static const struct of_device_id msm_cdc_pinctrl_match[] = {
228 {.compatible = "qcom,msm-cdc-pinctrl"},
229 {}
230};
231
232static struct platform_driver msm_cdc_pinctrl_driver = {
233 .driver = {
234 .name = "msm-cdc-pinctrl",
235 .owner = THIS_MODULE,
236 .of_match_table = msm_cdc_pinctrl_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800237 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530238 },
239 .probe = msm_cdc_pinctrl_probe,
240 .remove = msm_cdc_pinctrl_remove,
241};
242
243int msm_cdc_pinctrl_drv_init(void)
244{
245 return platform_driver_register(&msm_cdc_pinctrl_driver);
246}
247
248void msm_cdc_pinctrl_drv_exit(void)
249{
250 platform_driver_unregister(&msm_cdc_pinctrl_driver);
251}
252MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
253MODULE_LICENSE("GPL v2");