blob: 938ffd5f2f48deaefade46ec4aeb7b33b043c5b1 [file] [log] [blame]
Karthikeyan Manieea18362017-06-27 18:09:46 -07001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Banajit Goswamide8271c2017-01-18 00:28:59 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/of_device.h>
19#include <linux/platform_device.h>
20#include <linux/gpio.h>
21#include <linux/of_gpio.h>
22#include <linux/mfd/msm-cdc-pinctrl.h>
23
24struct msm_cdc_pinctrl_info {
25 struct pinctrl *pinctrl;
26 struct pinctrl_state *pinctrl_active;
27 struct pinctrl_state *pinctrl_sleep;
28 int gpio;
29 bool state;
30};
31
32static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
33 struct device_node *np)
34{
35 struct platform_device *pdev;
36 struct msm_cdc_pinctrl_info *gpio_data;
37
38 if (!np) {
39 pr_err("%s: device node is null\n", __func__);
40 return NULL;
41 }
42
43 pdev = of_find_device_by_node(np);
44 if (!pdev) {
45 pr_err("%s: platform device not found!\n", __func__);
46 return NULL;
47 }
48
49 gpio_data = dev_get_drvdata(&pdev->dev);
50 if (!gpio_data)
51 dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
52 __func__);
53
54 return gpio_data;
55}
56
57/*
58 * msm_cdc_get_gpio_state: select pinctrl sleep state
59 * @np: pointer to struct device_node
60 *
61 * Returns error code for failure and GPIO value on success
62 */
63int msm_cdc_get_gpio_state(struct device_node *np)
64{
65 struct msm_cdc_pinctrl_info *gpio_data;
66 int value = -EINVAL;
67
68 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
69 if (!gpio_data)
70 return value;
71
72 if (gpio_is_valid(gpio_data->gpio))
73 value = gpio_get_value_cansleep(gpio_data->gpio);
74
75 return value;
76}
77EXPORT_SYMBOL(msm_cdc_get_gpio_state);
78
79/*
80 * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state
81 * @np: pointer to struct device_node
82 *
83 * Returns error code for failure
84 */
85int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
86{
87 struct msm_cdc_pinctrl_info *gpio_data;
88
89 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
90 if (!gpio_data)
91 return -EINVAL;
92
93 if (!gpio_data->pinctrl_sleep) {
94 pr_err("%s: pinctrl sleep state is null\n", __func__);
95 return -EINVAL;
96 }
97 gpio_data->state = false;
98
99 return pinctrl_select_state(gpio_data->pinctrl,
100 gpio_data->pinctrl_sleep);
101}
102EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
103
104/*
105 * msm_cdc_pinctrl_select_active_state: select pinctrl active state
106 * @np: pointer to struct device_node
107 *
108 * Returns error code for failure
109 */
110int msm_cdc_pinctrl_select_active_state(struct device_node *np)
111{
112 struct msm_cdc_pinctrl_info *gpio_data;
113
114 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
115 if (!gpio_data)
116 return -EINVAL;
117
118 if (!gpio_data->pinctrl_active) {
119 pr_err("%s: pinctrl active state is null\n", __func__);
120 return -EINVAL;
121 }
122 gpio_data->state = true;
123
124 return pinctrl_select_state(gpio_data->pinctrl,
125 gpio_data->pinctrl_active);
126}
127EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state);
128
129/*
130 * msm_cdc_pinctrl_get_state: get curren pinctrl state
131 * @np: pointer to struct device_node
132 *
133 * Returns 0 for sleep state, 1 for active state
134 */
135bool msm_cdc_pinctrl_get_state(struct device_node *np)
136{
137 struct msm_cdc_pinctrl_info *gpio_data;
138
139 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
140 if (!gpio_data)
141 return -EINVAL;
142
143 return gpio_data->state;
144}
145EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
146
147static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
148{
149 int ret = 0;
150 struct msm_cdc_pinctrl_info *gpio_data;
151
152 gpio_data = devm_kzalloc(&pdev->dev,
153 sizeof(struct msm_cdc_pinctrl_info),
154 GFP_KERNEL);
155 if (!gpio_data)
156 return -ENOMEM;
157
158 gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
159 if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
160 dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
161 __func__, PTR_ERR(gpio_data->pinctrl));
162 ret = PTR_ERR(gpio_data->pinctrl);
163 goto err_pctrl_get;
164 }
165
166 gpio_data->pinctrl_active = pinctrl_lookup_state(
167 gpio_data->pinctrl, "aud_active");
168 if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
169 dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
170 __func__, PTR_ERR(gpio_data->pinctrl_active));
171 ret = PTR_ERR(gpio_data->pinctrl_active);
172 goto err_lookup_state;
173 }
174
175 gpio_data->pinctrl_sleep = pinctrl_lookup_state(
176 gpio_data->pinctrl, "aud_sleep");
177 if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
178 dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
179 __func__, PTR_ERR(gpio_data->pinctrl_sleep));
180 ret = PTR_ERR(gpio_data->pinctrl_sleep);
181 goto err_lookup_state;
182 }
Laxminath Kasamad0f6962016-12-14 20:00:35 +0530183 /* skip setting to sleep state for LPI_TLMM GPIOs */
184 if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
185 /* Set pinctrl state to aud_sleep by default */
186 ret = pinctrl_select_state(gpio_data->pinctrl,
187 gpio_data->pinctrl_sleep);
188 if (ret)
189 dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
190 __func__, ret);
191 }
Banajit Goswamide8271c2017-01-18 00:28:59 -0800192
193 gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
194 "qcom,cdc-rst-n-gpio", 0);
195 if (gpio_is_valid(gpio_data->gpio)) {
196 ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
197 if (ret) {
198 dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
199 __func__, gpio_data->gpio);
200 goto err_lookup_state;
201 }
202 }
203
204 dev_set_drvdata(&pdev->dev, gpio_data);
205 return 0;
206
207err_lookup_state:
208 devm_pinctrl_put(gpio_data->pinctrl);
209err_pctrl_get:
210 devm_kfree(&pdev->dev, gpio_data);
211 return ret;
212}
213
214static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
215{
216 struct msm_cdc_pinctrl_info *gpio_data;
217
218 gpio_data = dev_get_drvdata(&pdev->dev);
219
Karthikeyan Manic8da5ca2017-07-26 23:42:44 -0700220 /* to free the requested gpio before exiting */
221 if (gpio_data) {
222 if (gpio_is_valid(gpio_data->gpio))
223 gpio_free(gpio_data->gpio);
224
225 if (gpio_data->pinctrl)
226 devm_pinctrl_put(gpio_data->pinctrl);
227 }
Banajit Goswamide8271c2017-01-18 00:28:59 -0800228
229 devm_kfree(&pdev->dev, gpio_data);
230
231 return 0;
232}
233
234static const struct of_device_id msm_cdc_pinctrl_match[] = {
235 {.compatible = "qcom,msm-cdc-pinctrl"},
236 {}
237};
238
239static struct platform_driver msm_cdc_pinctrl_driver = {
240 .driver = {
241 .name = "msm-cdc-pinctrl",
242 .owner = THIS_MODULE,
243 .of_match_table = msm_cdc_pinctrl_match,
244 },
245 .probe = msm_cdc_pinctrl_probe,
246 .remove = msm_cdc_pinctrl_remove,
247};
Banajit Goswamide8271c2017-01-18 00:28:59 -0800248
Karthikeyan Manieea18362017-06-27 18:09:46 -0700249int msm_cdc_pinctrl_drv_init(void)
250{
251 return platform_driver_register(&msm_cdc_pinctrl_driver);
252}
253
254void msm_cdc_pinctrl_drv_exit(void)
255{
256 platform_driver_unregister(&msm_cdc_pinctrl_driver);
257}
Banajit Goswamide8271c2017-01-18 00:28:59 -0800258MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
259MODULE_LICENSE("GPL v2");