blob: 5c6ca495faedcd09e609648066a7c10b81dd2e07 [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>
Laxminath Kasam3d89d532019-10-09 23:18:03 +05307#include <linux/io.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05308#include <linux/err.h>
9#include <linux/module.h>
10#include <linux/of.h>
11#include <linux/of_device.h>
12#include <linux/platform_device.h>
13#include <linux/gpio.h>
14#include <linux/of_gpio.h>
Sudheer Papothi124ec092019-08-01 10:21:08 +053015#include <linux/pinctrl/qcom-pinctrl.h>
Meng Wang11a25cf2018-10-31 14:11:26 +080016#include <asoc/msm-cdc-pinctrl.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053017
Laxminath Kasamc39ed802019-09-16 13:05:53 +053018#define MAX_GPIOS 16
19
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020struct msm_cdc_pinctrl_info {
21 struct pinctrl *pinctrl;
22 struct pinctrl_state *pinctrl_active;
23 struct pinctrl_state *pinctrl_sleep;
24 int gpio;
25 bool state;
Laxminath Kasamc39ed802019-09-16 13:05:53 +053026 u32 tlmm_gpio[MAX_GPIOS];
Laxminath Kasam3d89d532019-10-09 23:18:03 +053027 char __iomem *chip_wakeup_register[MAX_GPIOS];
28 u32 chip_wakeup_maskbit[MAX_GPIOS];
Laxminath Kasamc39ed802019-09-16 13:05:53 +053029 u32 count;
Laxminath Kasam3d89d532019-10-09 23:18:03 +053030 u32 wakeup_reg_count;
Sudheer Papothi124ec092019-08-01 10:21:08 +053031 bool wakeup_capable;
Laxminath Kasam3d89d532019-10-09 23:18:03 +053032 bool chip_wakeup_reg;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053033};
34
35static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata(
36 struct device_node *np)
37{
38 struct platform_device *pdev;
39 struct msm_cdc_pinctrl_info *gpio_data;
40
41 if (!np) {
42 pr_err("%s: device node is null\n", __func__);
43 return NULL;
44 }
45
46 pdev = of_find_device_by_node(np);
47 if (!pdev) {
48 pr_err("%s: platform device not found!\n", __func__);
49 return NULL;
50 }
51
52 gpio_data = dev_get_drvdata(&pdev->dev);
53 if (!gpio_data)
54 dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
55 __func__);
56
57 return gpio_data;
58}
59
60/*
61 * msm_cdc_get_gpio_state: select pinctrl sleep state
62 * @np: pointer to struct device_node
63 *
64 * Returns error code for failure and GPIO value on success
65 */
66int msm_cdc_get_gpio_state(struct device_node *np)
67{
68 struct msm_cdc_pinctrl_info *gpio_data;
69 int value = -EINVAL;
70
71 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
72 if (!gpio_data)
73 return value;
74
75 if (gpio_is_valid(gpio_data->gpio))
76 value = gpio_get_value_cansleep(gpio_data->gpio);
77
78 return value;
79}
80EXPORT_SYMBOL(msm_cdc_get_gpio_state);
81
82/*
83 * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state
84 * @np: pointer to struct device_node
85 *
86 * Returns error code for failure
87 */
88int msm_cdc_pinctrl_select_sleep_state(struct device_node *np)
89{
90 struct msm_cdc_pinctrl_info *gpio_data;
91
92 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
93 if (!gpio_data)
94 return -EINVAL;
95
96 if (!gpio_data->pinctrl_sleep) {
97 pr_err("%s: pinctrl sleep state is null\n", __func__);
98 return -EINVAL;
99 }
100 gpio_data->state = false;
101
102 return pinctrl_select_state(gpio_data->pinctrl,
103 gpio_data->pinctrl_sleep);
104}
105EXPORT_SYMBOL(msm_cdc_pinctrl_select_sleep_state);
106
107/*
108 * msm_cdc_pinctrl_select_active_state: select pinctrl active state
109 * @np: pointer to struct device_node
110 *
111 * Returns error code for failure
112 */
113int msm_cdc_pinctrl_select_active_state(struct device_node *np)
114{
115 struct msm_cdc_pinctrl_info *gpio_data;
116
117 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
118 if (!gpio_data)
119 return -EINVAL;
120
121 if (!gpio_data->pinctrl_active) {
122 pr_err("%s: pinctrl active state is null\n", __func__);
123 return -EINVAL;
124 }
125 gpio_data->state = true;
126
127 return pinctrl_select_state(gpio_data->pinctrl,
128 gpio_data->pinctrl_active);
129}
130EXPORT_SYMBOL(msm_cdc_pinctrl_select_active_state);
131
132/*
133 * msm_cdc_pinctrl_get_state: get curren pinctrl state
134 * @np: pointer to struct device_node
135 *
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700136 * Returns 0 for sleep state, 1 for active state,
137 * error code for failure
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530138 */
Karthikeyan Mani326536d2019-06-03 13:29:43 -0700139int msm_cdc_pinctrl_get_state(struct device_node *np)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530140{
141 struct msm_cdc_pinctrl_info *gpio_data;
142
143 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
144 if (!gpio_data)
145 return -EINVAL;
146
147 return gpio_data->state;
148}
149EXPORT_SYMBOL(msm_cdc_pinctrl_get_state);
150
Sudheer Papothi124ec092019-08-01 10:21:08 +0530151/*
152 * msm_cdc_pinctrl_set_wakeup_capable: Set a pinctrl to wakeup capable
153 * @np: pointer to struct device_node
154 * @enable: wakeup capable when set to true
155 *
156 * Returns 0 for success and error code for failure
157 */
158int msm_cdc_pinctrl_set_wakeup_capable(struct device_node *np, bool enable)
159{
160 struct msm_cdc_pinctrl_info *gpio_data;
161 int ret = 0;
Laxminath Kasam3d89d532019-10-09 23:18:03 +0530162 u32 i = 0, temp = 0;
Sudheer Papothi124ec092019-08-01 10:21:08 +0530163
164 gpio_data = msm_cdc_pinctrl_get_gpiodata(np);
165 if (!gpio_data)
166 return -EINVAL;
167
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530168 if (gpio_data->wakeup_capable) {
169 for (i = 0; i < gpio_data->count; i++) {
170 ret = msm_gpio_mpm_wake_set(gpio_data->tlmm_gpio[i],
171 enable);
172 if (ret < 0)
173 goto exit;
174 }
175 }
Laxminath Kasam3d89d532019-10-09 23:18:03 +0530176 if (gpio_data->chip_wakeup_reg) {
177 for (i = 0; i < gpio_data->wakeup_reg_count; i++) {
178 temp = ioread32(gpio_data->chip_wakeup_register[i]);
179 if (enable)
180 temp |= (1 <<
181 gpio_data->chip_wakeup_maskbit[i]);
182 else
183 temp &= ~(1 <<
184 gpio_data->chip_wakeup_maskbit[i]);
185 iowrite32(temp, gpio_data->chip_wakeup_register[i]);
186 }
187 }
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530188exit:
Sudheer Papothi124ec092019-08-01 10:21:08 +0530189 return ret;
190}
191EXPORT_SYMBOL(msm_cdc_pinctrl_set_wakeup_capable);
192
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530193static int msm_cdc_pinctrl_probe(struct platform_device *pdev)
194{
195 int ret = 0;
196 struct msm_cdc_pinctrl_info *gpio_data;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530197 u32 tlmm_gpio[MAX_GPIOS] = {0};
Laxminath Kasam3d89d532019-10-09 23:18:03 +0530198 u32 chip_wakeup_reg[MAX_GPIOS] = {0};
Laxminath Kasam0f738192019-11-06 13:00:46 +0530199 u32 chip_wakeup_default_val[MAX_GPIOS] = {0};
200 u32 i = 0, temp = 0;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530201 int count = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530202
203 gpio_data = devm_kzalloc(&pdev->dev,
204 sizeof(struct msm_cdc_pinctrl_info),
205 GFP_KERNEL);
206 if (!gpio_data)
207 return -ENOMEM;
208
209 gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
210 if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
211 dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
212 __func__, PTR_ERR(gpio_data->pinctrl));
213 ret = PTR_ERR(gpio_data->pinctrl);
214 goto err_pctrl_get;
215 }
216
217 gpio_data->pinctrl_active = pinctrl_lookup_state(
218 gpio_data->pinctrl, "aud_active");
219 if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
220 dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
221 __func__, PTR_ERR(gpio_data->pinctrl_active));
222 ret = PTR_ERR(gpio_data->pinctrl_active);
223 goto err_lookup_state;
224 }
225
226 gpio_data->pinctrl_sleep = pinctrl_lookup_state(
227 gpio_data->pinctrl, "aud_sleep");
228 if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
229 dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
230 __func__, PTR_ERR(gpio_data->pinctrl_sleep));
231 ret = PTR_ERR(gpio_data->pinctrl_sleep);
232 goto err_lookup_state;
233 }
234 /* skip setting to sleep state for LPI_TLMM GPIOs */
235 if (!of_property_read_bool(pdev->dev.of_node, "qcom,lpi-gpios")) {
236 /* Set pinctrl state to aud_sleep by default */
237 ret = pinctrl_select_state(gpio_data->pinctrl,
238 gpio_data->pinctrl_sleep);
239 if (ret)
240 dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
241 __func__, ret);
242 }
243
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530244
Laxminath Kasam3d89d532019-10-09 23:18:03 +0530245 count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,chip-wakeup-reg");
246 if (count <= 0)
247 goto cdc_tlmm_gpio;
248 if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,chip-wakeup-reg",
249 chip_wakeup_reg, count)) {
250 if (of_property_read_u32_array(pdev->dev.of_node,
251 "qcom,chip-wakeup-maskbit",
252 gpio_data->chip_wakeup_maskbit, count)) {
253 dev_err(&pdev->dev,
254 "chip-wakeup-maskbit needed if chip-wakeup-reg is defined!\n");
255 goto cdc_tlmm_gpio;
256 }
257 gpio_data->chip_wakeup_reg = true;
258 for (i = 0; i < count; i++) {
259 gpio_data->chip_wakeup_register[i] =
260 devm_ioremap(&pdev->dev, chip_wakeup_reg[i], 0x4);
261 }
Laxminath Kasam0f738192019-11-06 13:00:46 +0530262 if (of_property_read_u32_array(pdev->dev.of_node,
263 "qcom,chip-wakeup-default-val",
264 chip_wakeup_default_val, count)) {
265 for (i = 0; i < count; i++) {
266 temp = ioread32(gpio_data->chip_wakeup_register[i]);
267 if (chip_wakeup_default_val[i])
268 temp |= (1 <<
269 gpio_data->chip_wakeup_maskbit[i]);
270 else
271 temp &= ~(1 <<
272 gpio_data->chip_wakeup_maskbit[i]);
273 iowrite32(temp, gpio_data->chip_wakeup_register[i]);
274 }
275 }
Laxminath Kasam3d89d532019-10-09 23:18:03 +0530276 gpio_data->wakeup_reg_count = count;
277 }
278
279cdc_tlmm_gpio:
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530280 count = of_property_count_u32_elems(pdev->dev.of_node, "qcom,tlmm-gpio");
281 if (count <= 0)
282 goto cdc_rst;
283 if (!of_property_read_u32_array(pdev->dev.of_node, "qcom,tlmm-gpio",
284 tlmm_gpio, count)) {
Sudheer Papothi124ec092019-08-01 10:21:08 +0530285 gpio_data->wakeup_capable = true;
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530286 for (i = 0; i < count; i++)
287 gpio_data->tlmm_gpio[i] = tlmm_gpio[i];
288 gpio_data->count = count;
Sudheer Papothi124ec092019-08-01 10:21:08 +0530289 }
290
Laxminath Kasamc39ed802019-09-16 13:05:53 +0530291cdc_rst:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530292 gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node,
293 "qcom,cdc-rst-n-gpio", 0);
294 if (gpio_is_valid(gpio_data->gpio)) {
295 ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET");
296 if (ret) {
297 dev_err(&pdev->dev, "%s: Failed to request gpio %d\n",
298 __func__, gpio_data->gpio);
299 goto err_lookup_state;
300 }
301 }
302
303 dev_set_drvdata(&pdev->dev, gpio_data);
304 return 0;
305
306err_lookup_state:
307 devm_pinctrl_put(gpio_data->pinctrl);
308err_pctrl_get:
309 devm_kfree(&pdev->dev, gpio_data);
310 return ret;
311}
312
313static int msm_cdc_pinctrl_remove(struct platform_device *pdev)
314{
315 struct msm_cdc_pinctrl_info *gpio_data;
316
317 gpio_data = dev_get_drvdata(&pdev->dev);
318
Laxminath Kasam8f7ccc22017-08-28 17:35:04 +0530319 /* to free the requested gpio before exiting */
320 if (gpio_data) {
321 if (gpio_is_valid(gpio_data->gpio))
322 gpio_free(gpio_data->gpio);
323
324 if (gpio_data->pinctrl)
325 devm_pinctrl_put(gpio_data->pinctrl);
326 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530327
328 devm_kfree(&pdev->dev, gpio_data);
329
330 return 0;
331}
332
333static const struct of_device_id msm_cdc_pinctrl_match[] = {
334 {.compatible = "qcom,msm-cdc-pinctrl"},
335 {}
336};
337
338static struct platform_driver msm_cdc_pinctrl_driver = {
339 .driver = {
340 .name = "msm-cdc-pinctrl",
341 .owner = THIS_MODULE,
342 .of_match_table = msm_cdc_pinctrl_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800343 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530344 },
345 .probe = msm_cdc_pinctrl_probe,
346 .remove = msm_cdc_pinctrl_remove,
347};
348
349int msm_cdc_pinctrl_drv_init(void)
350{
351 return platform_driver_register(&msm_cdc_pinctrl_driver);
352}
353
354void msm_cdc_pinctrl_drv_exit(void)
355{
356 platform_driver_unregister(&msm_cdc_pinctrl_driver);
357}
358MODULE_DESCRIPTION("MSM CODEC pin control platform driver");
359MODULE_LICENSE("GPL v2");