blob: 8ed0c8ebf50d84f391cb883bad79a1a843b12188 [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 *
125 * Returns 0 for sleep state, 1 for active state
126 */
127bool msm_cdc_pinctrl_get_state(struct device_node *np)
128{
129 struct msm_cdc_pinctrl_info *gpio_data;
130
131 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
132 if (!gpio_data)
133 return -EINVAL;
134
135 return gpio_data->state;
136}
137EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
138
139static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
140{
141 int ret = 0;
142 struct msm_cdc_pinctrl_info *gpio_data;
143
144 gpio_data = devm_kzalloc(&pdev->dev,
145 sizeof(struct msm_cdc_pinctrl_info),
146 GFP_KERNEL);
147 if (!gpio_data)
148 return -ENOMEM;
149
150 gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
151 if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
152 dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
153 __func__, PTR_ERR(gpio_data->pinctrl));
154 ret = PTR_ERR(gpio_data->pinctrl);
155 goto err_pctrl_get;
156 }
157
158 gpio_data->pinctrl_active = pinctrl_lookup_state(
159 gpio_data->pinctrl, "aud_active");
160 if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
161 dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
162 __func__, PTR_ERR(gpio_data->pinctrl_active));
163 ret = PTR_ERR(gpio_data->pinctrl_active);
164 goto err_lookup_state;
165 }
166
167 gpio_data->pinctrl_sleep = pinctrl_lookup_state(
168 gpio_data->pinctrl, "aud_sleep");
169 if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
170 dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
171 __func__, PTR_ERR(gpio_data->pinctrl_sleep));
172 ret = PTR_ERR(gpio_data->pinctrl_sleep);
173 goto err_lookup_state;
174 }
175 /* skip setting to sleep state for LPI_TLMM GPIOs */
176 if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
177 /* Set pinctrl state to aud_sleep by default */
178 ret = pinctrl_select_state(gpio_data->pinctrl,
179 gpio_data->pinctrl_sleep);
180 if (ret)
181 dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
182 __func__, ret);
183 }
184
185 gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
186 "qcom,cdc-rst-n-gpio", 0);
187 if (gpio_is_valid(gpio_data->gpio)) {
188 ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
189 if (ret) {
190 dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
191 __func__, gpio_data->gpio);
192 goto err_lookup_state;
193 }
194 }
195
196 dev_set_drvdata(&pdev->dev, gpio_data);
197 return 0;
198
199err_lookup_state:
200 devm_pinctrl_put(gpio_data->pinctrl);
201err_pctrl_get:
202 devm_kfree(&pdev->dev, gpio_data);
203 return ret;
204}
205
206static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
207{
208 struct msm_cdc_pinctrl_info *gpio_data;
209
210 gpio_data = dev_get_drvdata(&pdev->dev);
211
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +0530212 /* to free the requested gpio before exiting */
213 if (gpio_data) {
214 if (gpio_is_valid(gpio_data->gpio))
215 gpio_free(gpio_data->gpio);
216
217 if (gpio_data->pinctrl)
218 devm_pinctrl_put(gpio_data->pinctrl);
219 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530220
221 devm_kfree(&pdev->dev, gpio_data);
222
223 return 0;
224}
225
226static const struct of_device_id msm_cdc_pinctrl_match[] = {
227 {.compatible = "qcom,msm-cdc-pinctrl"},
228 {}
229};
230
231static struct platform_driver msm_cdc_pinctrl_driver = {
232 .driver = {
233 .name = "msm-cdc-pinctrl",
234 .owner = THIS_MODULE,
235 .of_match_table = msm_cdc_pinctrl_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800236 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530237 },
238 .probe = msm_cdc_pinctrl_probe,
239 .remove = msm_cdc_pinctrl_remove,
240};
241
242int msm_cdc_pinctrl_drv_init(void)
243{
244 return platform_driver_register(&msm_cdc_pinctrl_driver);
245}
246
247void msm_cdc_pinctrl_drv_exit(void)
248{
249 platform_driver_unregister(&msm_cdc_pinctrl_driver);
250}
251MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
252MODULE_LICENSE("GPL v2");