blob: 437563f0a8a096ea03452135130a353c5a93ebbc [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
Xiaojun Sang53cd13a2018-06-29 15:14:37 +08003 * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/gpio.h>
7#include <linux/module.h>
8#include <linux/of.h>
9#include <linux/pinctrl/pinconf-generic.h>
10#include <linux/pinctrl/pinconf.h>
11#include <linux/pinctrl/pinmux.h>
12#include <linux/platform_device.h>
13#include <linux/regmap.h>
14#include <linux/slab.h>
15#include <linux/types.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053016#include <asoc/wcd934x_registers.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053017
Laxminath Kasam605b42f2017-08-01 22:02:15 +053018#include "core.h"
19#include "pinctrl-utils.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020
21#define WCD_REG_DIR_CTL WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE
22#define WCD_REG_VAL_CTL WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA
23#define WCD_GPIO_PULL_UP 1
24#define WCD_GPIO_PULL_DOWN 2
25#define WCD_GPIO_BIAS_DISABLE 3
26#define WCD_GPIO_STRING_LEN 20
27
28/**
29 * struct wcd_gpio_pad - keep current GPIO settings
30 * @offset: offset of gpio.
31 * @is_valid: Set to false, when GPIO in high Z state.
32 * @value: value of a pin
33 * @output_enabled: Set to true if GPIO is output and false if it is input
34 * @pullup: Constant current which flow through GPIO output buffer.
35 * @strength: Drive strength of a pin
36 */
37struct wcd_gpio_pad {
38 u16 offset;
39 bool is_valid;
40 bool value;
41 bool output_enabled;
42 unsigned int pullup;
43 unsigned int strength;
44};
45
46struct wcd_gpio_priv {
47 struct device *dev;
48 struct regmap *map;
49 struct pinctrl_dev *ctrl;
50 struct gpio_chip chip;
51};
52
53static int wcd_gpio_read(struct wcd_gpio_priv *priv_data,
54 struct wcd_gpio_pad *pad, unsigned int addr)
55{
56 unsigned int val;
57 int ret;
58
59 ret = regmap_read(priv_data->map, addr, &val);
60 if (ret < 0)
61 dev_err(priv_data->dev, "%s: read 0x%x failed\n",
62 __func__, addr);
63 else
64 ret = (val >> pad->offset);
65
66 return ret;
67}
68
69static int wcd_gpio_write(struct wcd_gpio_priv *priv_data,
70 struct wcd_gpio_pad *pad, unsigned int addr,
71 unsigned int val)
72{
73 int ret;
74
75 ret = regmap_update_bits(priv_data->map, addr, (1 << pad->offset),
76 val << pad->offset);
77 if (ret < 0)
78 dev_err(priv_data->dev, "write 0x%x failed\n", addr);
79
80 return ret;
81}
82
83static int wcd_get_groups_count(struct pinctrl_dev *pctldev)
84{
85 return pctldev->desc->npins;
86}
87
88static const char *wcd_get_group_name(struct pinctrl_dev *pctldev,
89 unsigned int pin)
90{
91 return pctldev->desc->pins[pin].name;
92}
93
94static int wcd_get_group_pins(struct pinctrl_dev *pctldev, unsigned int pin,
95 const unsigned int **pins, unsigned int *num_pins)
96{
97 *pins = &pctldev->desc->pins[pin].number;
98 *num_pins = 1;
99 return 0;
100}
101
102static const struct pinctrl_ops wcd_pinctrl_ops = {
103 .get_groups_count = wcd_get_groups_count,
104 .get_group_name = wcd_get_group_name,
105 .get_group_pins = wcd_get_group_pins,
106 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
107 .dt_free_map = pinctrl_utils_free_map,
108};
109
110static int wcd_config_get(struct pinctrl_dev *pctldev,
111 unsigned int pin, unsigned long *config)
112{
113 unsigned int param = pinconf_to_config_param(*config);
114 struct wcd_gpio_pad *pad;
115 unsigned int arg;
116
117 pad = pctldev->desc->pins[pin].drv_data;
118
119 switch (param) {
120 case PIN_CONFIG_BIAS_PULL_DOWN:
121 arg = pad->pullup == WCD_GPIO_PULL_DOWN;
122 break;
123 case PIN_CONFIG_BIAS_DISABLE:
124 arg = pad->pullup = WCD_GPIO_BIAS_DISABLE;
125 break;
126 case PIN_CONFIG_BIAS_PULL_UP:
127 arg = pad->pullup == WCD_GPIO_PULL_UP;
128 break;
129 case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
130 arg = !pad->is_valid;
131 break;
132 case PIN_CONFIG_INPUT_ENABLE:
133 arg = pad->output_enabled;
134 break;
135 case PIN_CONFIG_OUTPUT:
136 arg = pad->value;
137 break;
138 default:
139 return -EINVAL;
140 }
141
142 *config = pinconf_to_config_packed(param, arg);
143 return 0;
144}
145
146static int wcd_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
147 unsigned long *configs, unsigned int nconfs)
148{
149 struct wcd_gpio_priv *priv_data = pinctrl_dev_get_drvdata(pctldev);
150 struct wcd_gpio_pad *pad;
151 unsigned int param, arg;
152 int i, ret;
153
154 pad = pctldev->desc->pins[pin].drv_data;
155
156 for (i = 0; i < nconfs; i++) {
157 param = pinconf_to_config_param(configs[i]);
158 arg = pinconf_to_config_argument(configs[i]);
159
160 dev_dbg(priv_data->dev, "%s: param: %d arg: %d",
161 __func__, param, arg);
162
163 switch (param) {
164 case PIN_CONFIG_BIAS_DISABLE:
165 pad->pullup = WCD_GPIO_BIAS_DISABLE;
166 break;
167 case PIN_CONFIG_BIAS_PULL_UP:
168 pad->pullup = WCD_GPIO_PULL_UP;
169 break;
170 case PIN_CONFIG_BIAS_PULL_DOWN:
171 pad->pullup = WCD_GPIO_PULL_DOWN;
172 break;
173 case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
174 pad->is_valid = false;
175 break;
176 case PIN_CONFIG_INPUT_ENABLE:
177 pad->output_enabled = false;
178 break;
179 case PIN_CONFIG_OUTPUT:
180 pad->output_enabled = true;
181 pad->value = arg;
182 break;
183 case PIN_CONFIG_DRIVE_STRENGTH:
184 pad->strength = arg;
185 break;
186 default:
187 ret = -EINVAL;
188 goto done;
189 }
190 }
191
192 if (pad->output_enabled) {
193 ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL,
194 pad->output_enabled);
195 if (ret < 0)
196 goto done;
197 ret = wcd_gpio_write(priv_data, pad, WCD_REG_VAL_CTL,
198 pad->value);
199 } else
200 ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL,
201 pad->output_enabled);
202done:
203 return ret;
204}
205
206static const struct pinconf_ops wcd_pinconf_ops = {
207 .is_generic = true,
208 .pin_config_group_get = wcd_config_get,
209 .pin_config_group_set = wcd_config_set,
210};
211
212static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
213{
214 struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
215 unsigned long config;
216
217 config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
218
219 return wcd_config_set(priv_data->ctrl, pin, &config, 1);
220}
221
222static int wcd_gpio_direction_output(struct gpio_chip *chip,
223 unsigned int pin, int val)
224{
225 struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
226 unsigned long config;
227
228 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
229
230 return wcd_config_set(priv_data->ctrl, pin, &config, 1);
231}
232
233static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
234{
235 struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
236 struct wcd_gpio_pad *pad;
237 int value;
238
239 pad = priv_data->ctrl->desc->pins[pin].drv_data;
240
241 if (!pad->is_valid)
242 return -EINVAL;
243
244 value = wcd_gpio_read(priv_data, pad, WCD_REG_VAL_CTL);
245 return value;
246}
247
248static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
249{
250 struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
251 unsigned long config;
252
253 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
254
255 wcd_config_set(priv_data->ctrl, pin, &config, 1);
256}
257
258static const struct gpio_chip wcd_gpio_chip = {
259 .direction_input = wcd_gpio_direction_input,
260 .direction_output = wcd_gpio_direction_output,
261 .get = wcd_gpio_get,
262 .set = wcd_gpio_set,
263};
264
265static int wcd_pinctrl_probe(struct platform_device *pdev)
266{
267 struct device *dev = &pdev->dev;
268 struct pinctrl_pin_desc *pindesc;
269 struct pinctrl_desc *pctrldesc;
270 struct wcd_gpio_pad *pad, *pads;
271 struct wcd_gpio_priv *priv_data;
272 int ret, i, j;
273 u32 npins;
274 char **name;
275
276 ret = of_property_read_u32(dev->of_node, "qcom,num-gpios", &npins);
277 if (ret) {
278 dev_err(dev, "%s: Looking up %s property in node %s failed\n",
279 __func__, "qcom,num-gpios", dev->of_node->full_name);
280 ret = -EINVAL;
281 goto err_priv_alloc;
282 }
283 if (!npins) {
284 dev_err(dev, "%s: no.of pins are 0\n", __func__);
285 ret = -EINVAL;
286 goto err_priv_alloc;
287 }
288
289 priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
290 if (!priv_data) {
291 ret = -ENOMEM;
292 goto err_priv_alloc;
293 }
294
295 priv_data->dev = dev;
296 priv_data->map = dev_get_regmap(dev->parent, NULL);
297 if (!priv_data->map) {
298 dev_err(dev, "%s: failed to get regmap\n", __func__);
299 ret = -EINVAL;
300 goto err_regmap;
301 }
302
303 pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
304 if (!pindesc) {
305 ret = -ENOMEM;
306 goto err_pinsec_alloc;
307 }
308
309 pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
310 if (!pads) {
311 ret = -ENOMEM;
312 goto err_pads_alloc;
313 }
314
315 pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
316 if (!pctrldesc) {
317 ret = -ENOMEM;
318 goto err_pinctrl_alloc;
319 }
320
321 pctrldesc->pctlops = &wcd_pinctrl_ops;
322 pctrldesc->confops = &wcd_pinconf_ops;
323 pctrldesc->owner = THIS_MODULE;
324 pctrldesc->name = dev_name(dev);
325 pctrldesc->pins = pindesc;
326 pctrldesc->npins = npins;
327
328 name = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL);
329 if (!name) {
330 ret = -ENOMEM;
331 goto err_name_alloc;
332 }
333 for (i = 0; i < npins; i++, pindesc++) {
334 name[i] = devm_kzalloc(dev, sizeof(char) * WCD_GPIO_STRING_LEN,
335 GFP_KERNEL);
336 if (!name[i]) {
337 ret = -ENOMEM;
338 goto err_pin;
339 }
340 pad = &pads[i];
341 pindesc->drv_data = pad;
342 pindesc->number = i;
343 snprintf(name[i], (WCD_GPIO_STRING_LEN - 1), "gpio%d", (i+1));
344 pindesc->name = name[i];
345 pad->offset = i;
346 pad->is_valid = true;
347 }
348
349 priv_data->chip = wcd_gpio_chip;
350 priv_data->chip.parent = dev;
351 priv_data->chip.base = -1;
352 priv_data->chip.ngpio = npins;
353 priv_data->chip.label = dev_name(dev);
354 priv_data->chip.of_gpio_n_cells = 2;
355 priv_data->chip.can_sleep = false;
356
357 priv_data->ctrl = devm_pinctrl_register(dev, pctrldesc, priv_data);
358 if (IS_ERR(priv_data->ctrl)) {
359 dev_err(dev, "%s: failed to register to pinctrl\n", __func__);
360 ret = PTR_ERR(priv_data->ctrl);
361 goto err_pin;
362 }
363
364 ret = gpiochip_add_data(&priv_data->chip, priv_data);
365 if (ret) {
366 dev_err(dev, "%s: can't add gpio chip\n", __func__);
367 goto err_pin;
368 }
369
370 ret = gpiochip_add_pin_range(&priv_data->chip, dev_name(dev), 0, 0,
371 npins);
372 if (ret) {
373 dev_err(dev, "%s: failed to add pin range\n", __func__);
374 goto err_range;
375 }
376 platform_set_drvdata(pdev, priv_data);
377
378 return 0;
379
380err_range:
381 gpiochip_remove(&priv_data->chip);
382err_pin:
383 for (j = 0; j < i; j++)
384 devm_kfree(dev, name[j]);
385 devm_kfree(dev, name);
386err_name_alloc:
387 devm_kfree(dev, pctrldesc);
388err_pinctrl_alloc:
389 devm_kfree(dev, pads);
390err_pads_alloc:
391 devm_kfree(dev, pindesc);
392err_pinsec_alloc:
393err_regmap:
394 devm_kfree(dev, priv_data);
395err_priv_alloc:
396 return ret;
397}
398
399static int wcd_pinctrl_remove(struct platform_device *pdev)
400{
401 struct wcd_gpio_priv *priv_data = platform_get_drvdata(pdev);
402
403 gpiochip_remove(&priv_data->chip);
404
405 return 0;
406}
407
408static const struct of_device_id wcd_pinctrl_of_match[] = {
409 { .compatible = "qcom,wcd-pinctrl" },
410 { },
411};
412
413MODULE_DEVICE_TABLE(of, wcd_pinctrl_of_match);
414
415static struct platform_driver wcd_pinctrl_driver = {
416 .driver = {
417 .name = "qcom-wcd-pinctrl",
418 .of_match_table = wcd_pinctrl_of_match,
Xiaojun Sang53cd13a2018-06-29 15:14:37 +0800419 .suppress_bind_attrs = true,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530420 },
421 .probe = wcd_pinctrl_probe,
422 .remove = wcd_pinctrl_remove,
423};
424
425module_platform_driver(wcd_pinctrl_driver);
426
427MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO pin control driver");
428MODULE_LICENSE("GPL v2");