blob: a10a6817336207d41cafc0b458f366978204e953 [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>
Sudheer Papothi124ec092019-08-01 10:21:08 +053014#include <linux/pinctrl/qcom-pinctrl.h>
Meng Wang11a25cf2018-10-31 14:11:26 +080015#include <asoc/msm-cdc-pinctrl.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053016
Laxminath Kasamc39ed802019-09-16 13:05:53 +053017#define MAX_GPIOS 16
18
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053019struct msm_cdc_pinctrl_info {
20 struct pinctrl *pinctrl;
21 struct pinctrl_state *pinctrl_active;
22 struct pinctrl_state *pinctrl_sleep;
23 int gpio;
24 bool state;
Laxminath Kasamc39ed802019-09-16 13:05:53 +053025 u32 tlmm_gpio[MAX_GPIOS];
26 u32 count;
Sudheer Papothi124ec092019-08-01 10:21:08 +053027 bool wakeup_capable;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053028};
29
30static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
31 struct device_node *np)
32{
33 struct platform_device *pdev;
34 struct msm_cdc_pinctrl_info *gpio_data;
35
36 if (!np) {
37 pr_err("%s: device node is null\n", __func__);
38 return NULL;
39 }
40
41 pdev = of_find_device_by_node(np);
42 if (!pdev) {
43 pr_err("%s: platform device not found!\n", __func__);
44 return NULL;
45 }
46
47 gpio_data = dev_get_drvdata(&pdev->dev);
48 if (!gpio_data)
49 dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
50 __func__);
51
52 return gpio_data;
53}
54
55/*
56 * msm_cdc_get_gpio_state: select pinctrl sleep state
57 * @np: pointer to struct device_node
58 *
59 * Returns error code for failure and GPIO value on success
60 */
61int msm_cdc_get_gpio_state(struct device_node *np)
62{
63 struct msm_cdc_pinctrl_info *gpio_data;
64 int value = -EINVAL;
65
66 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
67 if (!gpio_data)
68 return value;
69
70 if (gpio_is_valid(gpio_data->gpio))
71 value = gpio_get_value_cansleep(gpio_data->gpio);
72
73 return value;
74}
75EXPORT_SYMBOL(msm_cdc_get_gpio_state);
76
77/*
78 * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state
79 * @np: pointer to struct device_node
80 *
81 * Returns error code for failure
82 */
83int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
84{
85 struct msm_cdc_pinctrl_info *gpio_data;
86
87 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
88 if (!gpio_data)
89 return -EINVAL;
90
91 if (!gpio_data->pinctrl_sleep) {
92 pr_err("%s: pinctrl sleep state is null\n", __func__);
93 return -EINVAL;
94 }
95 gpio_data->state = false;
96
97 return pinctrl_select_state(gpio_data->pinctrl,
98 gpio_data->pinctrl_sleep);
99}
100EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
101
102/*
103 * msm_cdc_pinctrl_select_active_state: select pinctrl active state
104 * @np: pointer to struct device_node
105 *
106 * Returns error code for failure
107 */
108int msm_cdc_pinctrl_select_active_state(struct device_node *np)
109{
110 struct msm_cdc_pinctrl_info *gpio_data;
111
112 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
113 if (!gpio_data)
114 return -EINVAL;
115
116 if (!gpio_data->pinctrl_active) {
117 pr_err("%s: pinctrl active state is null\n", __func__);
118 return -EINVAL;
119 }
120 gpio_data->state = true;
121
122 return pinctrl_select_state(gpio_data->pinctrl,
123 gpio_data->pinctrl_active);
124}
125EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state);
126
127/*
128 * msm_cdc_pinctrl_get_state: get curren pinctrl state
129 * @np: pointer to struct device_node
130 *
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700131 * Returns 0 for sleep state, 1 for active state,
132 * error code for failure
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530133 */
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700134int msm_cdc_pinctrl_get_state(struct device_node *np)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530135{
136 struct msm_cdc_pinctrl_info *gpio_data;
137
138 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
139 if (!gpio_data)
140 return -EINVAL;
141
142 return gpio_data->state;
143}
144EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
145
Sudheer Papothi124ec092019-08-01 10:21:08 +0530146/*
147 * msm_cdc_pinctrl_set_wakeup_capable: Set a pinctrl to wakeup capable
148 * @np: pointer to struct device_node
149 * @enable: wakeup capable when set to true
150 *
151 * Returns 0 for success and error code for failure
152 */
153int msm_cdc_pinctrl_set_wakeup_capable(struct device_node *np, bool enable)
154{
155 struct msm_cdc_pinctrl_info *gpio_data;
156 int ret = 0;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530157 u32 i = 0;
Sudheer Papothi124ec092019-08-01 10:21:08 +0530158
159 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
160 if (!gpio_data)
161 return -EINVAL;
162
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530163 if (gpio_data->wakeup_capable) {
164 for (i = 0; i < gpio_data->count; i++) {
165 ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i],
166 enable);
167 if (ret < 0)
168 goto exit;
169 }
170 }
171exit:
Sudheer Papothi124ec092019-08-01 10:21:08 +0530172 return ret;
173}
174EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable);
175
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530176static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
177{
178 int ret = 0;
179 struct msm_cdc_pinctrl_info *gpio_data;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530180 u32 tlmm_gpio[MAX_GPIOS] = {0};
181 u32 i = 0;
182 int count = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530183
184 gpio_data = devm_kzalloc(&pdev->dev,
185 sizeof(struct msm_cdc_pinctrl_info),
186 GFP_KERNEL);
187 if (!gpio_data)
188 return -ENOMEM;
189
190 gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
191 if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
192 dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
193 __func__, PTR_ERR(gpio_data->pinctrl));
194 ret = PTR_ERR(gpio_data->pinctrl);
195 goto err_pctrl_get;
196 }
197
198 gpio_data->pinctrl_active = pinctrl_lookup_state(
199 gpio_data->pinctrl, "aud_active");
200 if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
201 dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
202 __func__, PTR_ERR(gpio_data->pinctrl_active));
203 ret = PTR_ERR(gpio_data->pinctrl_active);
204 goto err_lookup_state;
205 }
206
207 gpio_data->pinctrl_sleep = pinctrl_lookup_state(
208 gpio_data->pinctrl, "aud_sleep");
209 if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
210 dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
211 __func__, PTR_ERR(gpio_data->pinctrl_sleep));
212 ret = PTR_ERR(gpio_data->pinctrl_sleep);
213 goto err_lookup_state;
214 }
215 /* skip setting to sleep state for LPI_TLMM GPIOs */
216 if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
217 /* Set pinctrl state to aud_sleep by default */
218 ret = pinctrl_select_state(gpio_data->pinctrl,
219 gpio_data->pinctrl_sleep);
220 if (ret)
221 dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
222 __func__, ret);
223 }
224
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530225
226 count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
227 if (count <= 0)
228 goto cdc_rst;
229 if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-gpio",
230 tlmm_gpio, count)) {
Sudheer Papothi124ec092019-08-01 10:21:08 +0530231 gpio_data->wakeup_capable = true;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530232 for (i = 0; i < count; i++)
233 gpio_data->tlmm_gpio[i] = tlmm_gpio[i];
234 gpio_data->count = count;
Sudheer Papothi124ec092019-08-01 10:21:08 +0530235 }
236
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530237cdc_rst:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530238 gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
239 "qcom,cdc-rst-n-gpio", 0);
240 if (gpio_is_valid(gpio_data->gpio)) {
241 ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
242 if (ret) {
243 dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
244 __func__, gpio_data->gpio);
245 goto err_lookup_state;
246 }
247 }
248
249 dev_set_drvdata(&pdev->dev, gpio_data);
250 return 0;
251
252err_lookup_state:
253 devm_pinctrl_put(gpio_data->pinctrl);
254err_pctrl_get:
255 devm_kfree(&pdev->dev, gpio_data);
256 return ret;
257}
258
259static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
260{
261 struct msm_cdc_pinctrl_info *gpio_data;
262
263 gpio_data = dev_get_drvdata(&pdev->dev);
264
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +0530265 /* to free the requested gpio before exiting */
266 if (gpio_data) {
267 if (gpio_is_valid(gpio_data->gpio))
268 gpio_free(gpio_data->gpio);
269
270 if (gpio_data->pinctrl)
271 devm_pinctrl_put(gpio_data->pinctrl);
272 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530273
274 devm_kfree(&pdev->dev, gpio_data);
275
276 return 0;
277}
278
279static const struct of_device_id msm_cdc_pinctrl_match[] = {
280 {.compatible = "qcom,msm-cdc-pinctrl"},
281 {}
282};
283
284static struct platform_driver msm_cdc_pinctrl_driver = {
285 .driver = {
286 .name = "msm-cdc-pinctrl",
287 .owner = THIS_MODULE,
288 .of_match_table = msm_cdc_pinctrl_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800289 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530290 },
291 .probe = msm_cdc_pinctrl_probe,
292 .remove = msm_cdc_pinctrl_remove,
293};
294
295int msm_cdc_pinctrl_drv_init(void)
296{
297 return platform_driver_register(&msm_cdc_pinctrl_driver);
298}
299
300void msm_cdc_pinctrl_drv_exit(void)
301{
302 platform_driver_unregister(&msm_cdc_pinctrl_driver);
303}
304MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
305MODULE_LICENSE("GPL v2");