blob: 3db22103f285aae1943f18024bf755f5612a9462 [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/*
Karthikeyan Mani39b70f52019-02-20 17:24:10 -08003 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/gpio.h>
7#include <linux/io.h>
8#include <linux/module.h>
9#include <linux/of.h>
10#include <linux/pinctrl/pinconf-generic.h>
11#include <linux/pinctrl/pinconf.h>
12#include <linux/pinctrl/pinmux.h>
13#include <linux/platform_device.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053014#include <linux/slab.h>
15#include <linux/types.h>
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +053016#include <linux/clk.h>
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080017#include <linux/bitops.h>
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +053018#include <soc/snd_event.h>
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +053019#include <linux/pm_runtime.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053020#include <dsp/audio_notifier.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053021
Laxminath Kasam605b42f2017-08-01 22:02:15 +053022#include "core.h"
23#include "pinctrl-utils.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053024
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080025#define LPI_AUTO_SUSPEND_DELAY 100 /* delay in msec */
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +053026
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080027#define LPI_ADDRESS_SIZE 0x20000
28#define LPI_SLEW_ADDRESS_SIZE 0x1000
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053029
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080030#define LPI_GPIO_REG_VAL_CTL 0x00
31#define LPI_GPIO_REG_DIR_CTL 0x04
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053032
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080033#define LPI_SLEW_REG_VAL_CTL 0x00
34#define LPI_SLEW_RATE_MAX 0x03
35#define LPI_SLEW_BITS_SIZE 0x02
36#define LPI_SLEW_OFFSET_INVALID 0xFFFFFFFF
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053037
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080038#define LPI_GPIO_REG_PULL_SHIFT 0x0
39#define LPI_GPIO_REG_PULL_MASK 0x3
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053040
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080041#define LPI_GPIO_REG_FUNCTION_SHIFT 0x2
42#define LPI_GPIO_REG_FUNCTION_MASK 0x3C
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053043
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080044#define LPI_GPIO_REG_OUT_STRENGTH_SHIFT 0x6
45#define LPI_GPIO_REG_OUT_STRENGTH_MASK 0x1C0
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053046
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080047#define LPI_GPIO_REG_OE_SHIFT 0x9
48#define LPI_GPIO_REG_OE_MASK 0x200
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053049
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080050#define LPI_GPIO_REG_DIR_SHIFT 0x1
51#define LPI_GPIO_REG_DIR_MASK 0x2
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053052
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080053#define LPI_GPIO_BIAS_DISABLE 0x0
54#define LPI_GPIO_PULL_DOWN 0x1
55#define LPI_GPIO_KEEPER 0x2
56#define LPI_GPIO_PULL_UP 0x3
57
58#define LPI_GPIO_FUNC_GPIO "gpio"
59#define LPI_GPIO_FUNC_FUNC1 "func1"
60#define LPI_GPIO_FUNC_FUNC2 "func2"
61#define LPI_GPIO_FUNC_FUNC3 "func3"
62#define LPI_GPIO_FUNC_FUNC4 "func4"
63#define LPI_GPIO_FUNC_FUNC5 "func5"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053064
65static bool lpi_dev_up;
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +053066static struct device *lpi_dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053067
68/* The index of each function in lpi_gpio_functions[] array */
69enum lpi_gpio_func_index {
70 LPI_GPIO_FUNC_INDEX_GPIO = 0x00,
71 LPI_GPIO_FUNC_INDEX_FUNC1 = 0x01,
72 LPI_GPIO_FUNC_INDEX_FUNC2 = 0x02,
73 LPI_GPIO_FUNC_INDEX_FUNC3 = 0x03,
74 LPI_GPIO_FUNC_INDEX_FUNC4 = 0x04,
75 LPI_GPIO_FUNC_INDEX_FUNC5 = 0x05,
76};
77
78/**
79 * struct lpi_gpio_pad - keep current GPIO settings
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080080 * @offset: stores one of gpio_offset or slew_offset at a given time.
81 * @gpio_offset: Nth GPIO in supported GPIOs.
82 * @slew_offset: Nth GPIO's position in slew register in supported GPIOs.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053083 * @output_enabled: Set to true if GPIO output logic is enabled.
84 * @value: value of a pin
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080085 * @base: stores one of gpio_base or slew_base at a given time.
86 * @gpio_base: Address base of LPI GPIO PAD.
87 * @slew_base: Address base of LPI SLEW PAD.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053088 * @pullup: Constant current which flow through GPIO output buffer.
89 * @strength: No, Low, Medium, High
90 * @function: See lpi_gpio_functions[]
91 */
92struct lpi_gpio_pad {
Karthikeyan Mani39b70f52019-02-20 17:24:10 -080093 u32 offset;
94 u32 gpio_offset;
95 u32 slew_offset;
96 bool output_enabled;
97 bool value;
98 char __iomem *base;
99 char __iomem *gpio_base;
100 char __iomem *slew_base;
101 unsigned int pullup;
102 unsigned int strength;
103 unsigned int function;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530104};
105
106struct lpi_gpio_state {
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800107 struct device *dev;
108 struct pinctrl_dev *ctrl;
109 struct gpio_chip chip;
110 char __iomem *base;
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530111 struct clk *lpass_core_hw_vote;
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800112 struct mutex slew_access_lock;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530113};
114
115static const char *const lpi_gpio_groups[] = {
116 "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
117 "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
118 "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
119 "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
120 "gpio29", "gpio30", "gpio31",
121};
122
Aditya Bavanarid7ec18c2018-06-13 20:34:10 +0530123#define LPI_TLMM_MAX_PINS 100
124static u32 lpi_offset[LPI_TLMM_MAX_PINS];
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800125static u32 lpi_slew_offset[LPI_TLMM_MAX_PINS];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530126
127static const char *const lpi_gpio_functions[] = {
128 [LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO,
129 [LPI_GPIO_FUNC_INDEX_FUNC1] = LPI_GPIO_FUNC_FUNC1,
130 [LPI_GPIO_FUNC_INDEX_FUNC2] = LPI_GPIO_FUNC_FUNC2,
131 [LPI_GPIO_FUNC_INDEX_FUNC3] = LPI_GPIO_FUNC_FUNC3,
132 [LPI_GPIO_FUNC_INDEX_FUNC4] = LPI_GPIO_FUNC_FUNC4,
133 [LPI_GPIO_FUNC_INDEX_FUNC5] = LPI_GPIO_FUNC_FUNC5,
134};
135
136static int lpi_gpio_read(struct lpi_gpio_pad *pad, unsigned int addr)
137{
138 int ret;
139
140 if (!lpi_dev_up) {
141 pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
142 __func__);
143 return 0;
144 }
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530145 pm_runtime_get_sync(lpi_dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530146
147 ret = ioread32(pad->base + pad->offset + addr);
148 if (ret < 0)
149 pr_err("%s: read 0x%x failed\n", __func__, addr);
150
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530151 pm_runtime_mark_last_busy(lpi_dev);
152 pm_runtime_put_autosuspend(lpi_dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530153 return ret;
154}
155
156static int lpi_gpio_write(struct lpi_gpio_pad *pad, unsigned int addr,
157 unsigned int val)
158{
159 if (!lpi_dev_up) {
160 pr_err_ratelimited("%s: ADSP is down due to SSR, return\n",
161 __func__);
162 return 0;
163 }
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530164 pm_runtime_get_sync(lpi_dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530165
166 iowrite32(val, pad->base + pad->offset + addr);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530167
168 pm_runtime_mark_last_busy(lpi_dev);
169 pm_runtime_put_autosuspend(lpi_dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530170 return 0;
171}
172
173static int lpi_gpio_get_groups_count(struct pinctrl_dev *pctldev)
174{
175 /* Every PIN is a group */
176 return pctldev->desc->npins;
177}
178
179static const char *lpi_gpio_get_group_name(struct pinctrl_dev *pctldev,
180 unsigned int pin)
181{
182 return pctldev->desc->pins[pin].name;
183}
184
185static int lpi_gpio_get_group_pins(struct pinctrl_dev *pctldev,
186 unsigned int pin,
187 const unsigned int **pins,
188 unsigned int *num_pins)
189{
190 *pins = &pctldev->desc->pins[pin].number;
191 *num_pins = 1;
192 return 0;
193}
194
195static const struct pinctrl_ops lpi_gpio_pinctrl_ops = {
196 .get_groups_count = lpi_gpio_get_groups_count,
197 .get_group_name = lpi_gpio_get_group_name,
198 .get_group_pins = lpi_gpio_get_group_pins,
199 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
200 .dt_free_map = pinctrl_utils_free_map,
201};
202
203static int lpi_gpio_get_functions_count(struct pinctrl_dev *pctldev)
204{
205 return ARRAY_SIZE(lpi_gpio_functions);
206}
207
208static const char *lpi_gpio_get_function_name(struct pinctrl_dev *pctldev,
209 unsigned int function)
210{
211 return lpi_gpio_functions[function];
212}
213
214static int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev,
215 unsigned int function,
216 const char *const **groups,
217 unsigned *const num_qgroups)
218{
219 *groups = lpi_gpio_groups;
220 *num_qgroups = pctldev->desc->npins;
221 return 0;
222}
223
224static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
225 unsigned int pin)
226{
227 struct lpi_gpio_pad *pad;
228 unsigned int val;
229
230 pad = pctldev->desc->pins[pin].drv_data;
231
232 pad->function = function;
233
234 val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
235 val &= ~(LPI_GPIO_REG_FUNCTION_MASK);
236 val |= pad->function << LPI_GPIO_REG_FUNCTION_SHIFT;
237 lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
238 return 0;
239}
240
241static const struct pinmux_ops lpi_gpio_pinmux_ops = {
242 .get_functions_count = lpi_gpio_get_functions_count,
243 .get_function_name = lpi_gpio_get_function_name,
244 .get_function_groups = lpi_gpio_get_function_groups,
245 .set_mux = lpi_gpio_set_mux,
246};
247
248static int lpi_config_get(struct pinctrl_dev *pctldev,
249 unsigned int pin, unsigned long *config)
250{
251 unsigned int param = pinconf_to_config_param(*config);
252 struct lpi_gpio_pad *pad;
253 unsigned int arg;
254
255 pad = pctldev->desc->pins[pin].drv_data;
256
257 switch (param) {
258 case PIN_CONFIG_BIAS_DISABLE:
259 arg = pad->pullup = LPI_GPIO_BIAS_DISABLE;
260 break;
261 case PIN_CONFIG_BIAS_PULL_DOWN:
262 arg = pad->pullup == LPI_GPIO_PULL_DOWN;
263 break;
264 case PIN_CONFIG_BIAS_BUS_HOLD:
265 arg = pad->pullup = LPI_GPIO_KEEPER;
266 break;
267 case PIN_CONFIG_BIAS_PULL_UP:
268 arg = pad->pullup == LPI_GPIO_PULL_UP;
269 break;
270 case PIN_CONFIG_INPUT_ENABLE:
271 case PIN_CONFIG_OUTPUT:
272 arg = pad->output_enabled;
273 break;
274 default:
275 return -EINVAL;
276 }
277
278 *config = pinconf_to_config_packed(param, arg);
279 return 0;
280}
281
282static unsigned int lpi_drive_to_regval(u32 arg)
283{
284 return (arg/2 - 1);
285}
286
287static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
288 unsigned long *configs, unsigned int nconfs)
289{
290 struct lpi_gpio_pad *pad;
291 unsigned int param, arg;
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800292 int i, ret = 0;
293 volatile unsigned long val;
294 struct lpi_gpio_state *state = dev_get_drvdata(pctldev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530295
296 pad = pctldev->desc->pins[pin].drv_data;
297
298 for (i = 0; i < nconfs; i++) {
299 param = pinconf_to_config_param(configs[i]);
300 arg = pinconf_to_config_argument(configs[i]);
301
302 dev_dbg(pctldev->dev, "%s: param: %d arg: %d pin: %d\n",
303 __func__, param, arg, pin);
304
305 switch (param) {
306 case PIN_CONFIG_BIAS_DISABLE:
307 pad->pullup = LPI_GPIO_BIAS_DISABLE;
308 break;
309 case PIN_CONFIG_BIAS_PULL_DOWN:
310 pad->pullup = LPI_GPIO_PULL_DOWN;
311 break;
312 case PIN_CONFIG_BIAS_BUS_HOLD:
313 pad->pullup = LPI_GPIO_KEEPER;
314 break;
315 case PIN_CONFIG_BIAS_PULL_UP:
316 pad->pullup = LPI_GPIO_PULL_UP;
317 break;
318 case PIN_CONFIG_INPUT_ENABLE:
319 pad->output_enabled = false;
320 break;
321 case PIN_CONFIG_OUTPUT:
322 pad->output_enabled = true;
323 pad->value = arg;
324 break;
325 case PIN_CONFIG_DRIVE_STRENGTH:
326 pad->strength = arg;
327 break;
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800328 case PIN_CONFIG_SLEW_RATE:
329 if (pad->slew_base == NULL ||
330 pad->slew_offset == LPI_SLEW_OFFSET_INVALID) {
331 dev_dbg(pctldev->dev, "%s: invalid slew settings for pin: %d\n",
332 __func__, pin);
333 goto set_gpio;
334 }
335 if (arg > LPI_SLEW_RATE_MAX) {
336 dev_err(pctldev->dev, "%s: invalid slew rate %u for pin: %d\n",
337 __func__, arg, pin);
338 goto set_gpio;
339 }
340 pad->base = pad->slew_base;
341 pad->offset = 0;
342 mutex_lock(&state->slew_access_lock);
343 val = lpi_gpio_read(pad, LPI_SLEW_REG_VAL_CTL);
344 pad->offset = pad->slew_offset;
345 for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) {
346 if (arg & 0x01)
347 set_bit(pad->offset, &val);
348 else
349 clear_bit(pad->offset, &val);
350 pad->offset++;
351 arg = arg >> 1;
352 }
353 pad->offset = 0;
354 lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, val);
355 mutex_unlock(&state->slew_access_lock);
356 break;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530357 default:
358 ret = -EINVAL;
359 goto done;
360 }
361 }
362
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800363set_gpio:
364 pad->base = pad->gpio_base;
365 pad->offset = pad->gpio_offset;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530366 val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
367 val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK |
368 LPI_GPIO_REG_OE_MASK);
369 val |= pad->pullup << LPI_GPIO_REG_PULL_SHIFT;
370 val |= lpi_drive_to_regval(pad->strength) <<
371 LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
372 if (pad->output_enabled)
373 val |= pad->value << LPI_GPIO_REG_OE_SHIFT;
374
375 lpi_gpio_write(pad, LPI_GPIO_REG_VAL_CTL, val);
376 lpi_gpio_write(pad, LPI_GPIO_REG_DIR_CTL,
377 pad->output_enabled << LPI_GPIO_REG_DIR_SHIFT);
378done:
379 return ret;
380}
381
382static const struct pinconf_ops lpi_gpio_pinconf_ops = {
383 .is_generic = true,
384 .pin_config_group_get = lpi_config_get,
385 .pin_config_group_set = lpi_config_set,
386};
387
388static int lpi_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
389{
390 struct lpi_gpio_state *state = gpiochip_get_data(chip);
391 unsigned long config;
392
393 config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
394
395 return lpi_config_set(state->ctrl, pin, &config, 1);
396}
397
398static int lpi_gpio_direction_output(struct gpio_chip *chip,
399 unsigned int pin, int val)
400{
401 struct lpi_gpio_state *state = gpiochip_get_data(chip);
402 unsigned long config;
403
404 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
405
406 return lpi_config_set(state->ctrl, pin, &config, 1);
407}
408
409static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin)
410{
411 struct lpi_gpio_state *state = gpiochip_get_data(chip);
412 struct lpi_gpio_pad *pad;
413 int value;
414
415 pad = state->ctrl->desc->pins[pin].drv_data;
416
417 value = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
418 return value;
419}
420
421static void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
422{
423 struct lpi_gpio_state *state = gpiochip_get_data(chip);
424 unsigned long config;
425
426 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
427
428 lpi_config_set(state->ctrl, pin, &config, 1);
429}
430
431static int lpi_notifier_service_cb(struct notifier_block *this,
432 unsigned long opcode, void *ptr)
433{
434 static bool initial_boot = true;
435
436 pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
437
438 switch (opcode) {
439 case AUDIO_NOTIFIER_SERVICE_DOWN:
440 if (initial_boot) {
441 initial_boot = false;
442 break;
443 }
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530444 snd_event_notify(lpi_dev, SND_EVENT_DOWN);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530445 lpi_dev_up = false;
446 break;
447 case AUDIO_NOTIFIER_SERVICE_UP:
448 if (initial_boot)
449 initial_boot = false;
450 lpi_dev_up = true;
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530451 snd_event_notify(lpi_dev, SND_EVENT_UP);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530452 break;
453 default:
454 break;
455 }
456 return NOTIFY_OK;
457}
458
459static struct notifier_block service_nb = {
460 .notifier_call = lpi_notifier_service_cb,
461 .priority = -INT_MAX,
462};
463
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530464static void lpi_pinctrl_ssr_disable(struct device *dev, void *data)
465{
466 lpi_dev_up = false;
467}
468
469static const struct snd_event_ops lpi_pinctrl_ssr_ops = {
470 .disable = lpi_pinctrl_ssr_disable,
471};
472
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530473#ifdef CONFIG_DEBUG_FS
474#include <linux/seq_file.h>
475
476static unsigned int lpi_regval_to_drive(u32 val)
477{
478 return (val + 1) * 2;
479}
480
481static void lpi_gpio_dbg_show_one(struct seq_file *s,
482 struct pinctrl_dev *pctldev,
483 struct gpio_chip *chip,
484 unsigned int offset,
485 unsigned int gpio)
486{
Asish Bhattacharya84f7f732017-07-25 16:29:27 +0530487 struct lpi_gpio_state *state = gpiochip_get_data(chip);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530488 struct pinctrl_pin_desc pindesc;
489 struct lpi_gpio_pad *pad;
490 unsigned int func;
491 int is_out;
492 int drive;
493 int pull;
494 u32 ctl_reg;
495
496 static const char * const pulls[] = {
497 "no pull",
498 "pull down",
499 "keeper",
500 "pull up"
501 };
502
Asish Bhattacharya84f7f732017-07-25 16:29:27 +0530503 pctldev = pctldev ? : state->ctrl;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530504 pindesc = pctldev->desc->pins[offset];
505 pad = pctldev->desc->pins[offset].drv_data;
506 ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL);
507 is_out = (ctl_reg & LPI_GPIO_REG_DIR_MASK) >> LPI_GPIO_REG_DIR_SHIFT;
508 ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL);
509
510 func = (ctl_reg & LPI_GPIO_REG_FUNCTION_MASK) >>
511 LPI_GPIO_REG_FUNCTION_SHIFT;
512 drive = (ctl_reg & LPI_GPIO_REG_OUT_STRENGTH_MASK) >>
513 LPI_GPIO_REG_OUT_STRENGTH_SHIFT;
514 pull = (ctl_reg & LPI_GPIO_REG_PULL_MASK) >> LPI_GPIO_REG_PULL_SHIFT;
515
516 seq_printf(s, " %-8s: %-3s %d",
517 pindesc.name, is_out ? "out" : "in", func);
518 seq_printf(s, " %dmA", lpi_regval_to_drive(drive));
519 seq_printf(s, " %s", pulls[pull]);
520}
521
522static void lpi_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
523{
524 unsigned int gpio = chip->base;
525 unsigned int i;
526
527 for (i = 0; i < chip->ngpio; i++, gpio++) {
528 lpi_gpio_dbg_show_one(s, NULL, chip, i, gpio);
529 seq_puts(s, "\n");
530 }
531}
532
533#else
534#define lpi_gpio_dbg_show NULL
535#endif
536
537static const struct gpio_chip lpi_gpio_template = {
538 .direction_input = lpi_gpio_direction_input,
539 .direction_output = lpi_gpio_direction_output,
540 .get = lpi_gpio_get,
541 .set = lpi_gpio_set,
542 .request = gpiochip_generic_request,
543 .free = gpiochip_generic_free,
544 .dbg_show = lpi_gpio_dbg_show,
545};
546
547static int lpi_pinctrl_probe(struct platform_device *pdev)
548{
549 struct device *dev = &pdev->dev;
550 struct pinctrl_pin_desc *pindesc;
551 struct pinctrl_desc *pctrldesc;
552 struct lpi_gpio_pad *pad, *pads;
553 struct lpi_gpio_state *state;
554 int ret, npins, i;
555 char __iomem *lpi_base;
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800556 char __iomem *slew_base;
557 u32 reg, slew_reg;
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530558 struct clk *lpass_core_hw_vote = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530559
560 ret = of_property_read_u32(dev->of_node, "reg", &reg);
561 if (ret < 0) {
562 dev_err(dev, "missing base address\n");
563 return ret;
564 }
565
566 ret = of_property_read_u32(dev->of_node, "qcom,num-gpios", &npins);
567 if (ret < 0)
568 return ret;
569
570 WARN_ON(npins > ARRAY_SIZE(lpi_gpio_groups));
571
Aditya Bavanarid7ec18c2018-06-13 20:34:10 +0530572 ret = of_property_read_u32_array(dev->of_node, "qcom,lpi-offset-tbl",
573 lpi_offset, npins);
574 if (ret < 0) {
575 dev_err(dev, "error in reading lpi offset table: %d\n", ret);
576 return ret;
577 }
578
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800579 ret = of_property_read_u32_array(dev->of_node,
580 "qcom,lpi-slew-offset-tbl",
581 lpi_slew_offset, npins);
582 if (ret < 0) {
583 for (i = 0; i < npins; i++)
584 lpi_slew_offset[i] = LPI_SLEW_OFFSET_INVALID;
585 dev_dbg(dev, "%s: error in reading lpi slew offset table: %d\n",
586 __func__, ret);
587 }
588
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530589 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
590 if (!state)
591 return -ENOMEM;
592
593 platform_set_drvdata(pdev, state);
594
595 state->dev = &pdev->dev;
596
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800597 slew_reg = 0;
598 ret = of_property_read_u32(dev->of_node, "qcom,slew-reg", &slew_reg);
599 if (!ret) {
600 slew_base = devm_ioremap(dev, slew_reg, LPI_SLEW_ADDRESS_SIZE);
601 if (slew_base == NULL) {
602 dev_err(dev,
603 "%s devm_ioremap failed for slew rate reg\n",
604 __func__);
605 ret = -ENOMEM;
606 goto err_io;
607 }
608 } else {
609 slew_base = NULL;
610 dev_dbg(dev, "error in reading lpi slew register: %d\n",
611 __func__, ret);
612 }
613
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530614 pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
615 if (!pindesc)
616 return -ENOMEM;
617
618 pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
619 if (!pads)
620 return -ENOMEM;
621
622 pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
623 if (!pctrldesc)
624 return -ENOMEM;
625
626 pctrldesc->pctlops = &lpi_gpio_pinctrl_ops;
627 pctrldesc->pmxops = &lpi_gpio_pinmux_ops;
628 pctrldesc->confops = &lpi_gpio_pinconf_ops;
629 pctrldesc->owner = THIS_MODULE;
630 pctrldesc->name = dev_name(dev);
631 pctrldesc->pins = pindesc;
632 pctrldesc->npins = npins;
633
634 lpi_base = devm_ioremap(dev, reg, LPI_ADDRESS_SIZE);
635 if (lpi_base == NULL) {
636 dev_err(dev, "%s devm_ioremap failed\n", __func__);
637 return -ENOMEM;
638 }
639
640 state->base = lpi_base;
641
642 for (i = 0; i < npins; i++, pindesc++) {
643 pad = &pads[i];
644 pindesc->drv_data = pad;
645 pindesc->number = i;
646 pindesc->name = lpi_gpio_groups[i];
647
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800648 pad->gpio_base = lpi_base;
649 pad->slew_base = slew_base;
650 pad->base = pad->gpio_base;
651
652 pad->gpio_offset = lpi_offset[i];
653 pad->slew_offset = lpi_slew_offset[i];
654 pad->offset = pad->gpio_offset;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530655 }
656
657 state->chip = lpi_gpio_template;
658 state->chip.parent = dev;
659 state->chip.base = -1;
660 state->chip.ngpio = npins;
661 state->chip.label = dev_name(dev);
662 state->chip.of_gpio_n_cells = 2;
663 state->chip.can_sleep = false;
664
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800665 mutex_init(&state->slew_access_lock);
666
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530667 state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
668 if (IS_ERR(state->ctrl))
669 return PTR_ERR(state->ctrl);
670
671 ret = gpiochip_add_data(&state->chip, state);
672 if (ret) {
673 dev_err(state->dev, "can't add gpio chip\n");
674 goto err_chip;
675 }
676
677 ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
678 if (ret) {
679 dev_err(dev, "failed to add pin range\n");
680 goto err_range;
681 }
682
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530683 lpi_dev = &pdev->dev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530684 lpi_dev_up = true;
685 ret = audio_notifier_register("lpi_tlmm", AUDIO_NOTIFIER_ADSP_DOMAIN,
686 &service_nb);
687 if (ret < 0) {
688 pr_err("%s: Audio notifier register failed ret = %d\n",
689 __func__, ret);
690 goto err_range;
691 }
692
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530693 ret = snd_event_client_register(dev, &lpi_pinctrl_ssr_ops, NULL);
694 if (!ret) {
695 snd_event_notify(dev, SND_EVENT_UP);
696 } else {
697 dev_err(dev, "%s: snd_event registration failed, ret [%d]\n",
698 __func__, ret);
699 goto err_snd_evt;
700 }
701
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530702 /* Register LPASS core hw vote */
703 lpass_core_hw_vote = devm_clk_get(&pdev->dev, "lpass_core_hw_vote");
704 if (IS_ERR(lpass_core_hw_vote)) {
705 ret = PTR_ERR(lpass_core_hw_vote);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530706 dev_dbg(&pdev->dev, "%s: clk get %s failed %d\n",
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530707 __func__, "lpass_core_hw_vote", ret);
708 lpass_core_hw_vote = NULL;
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530709 ret = 0;
710 }
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530711 state->lpass_core_hw_vote = lpass_core_hw_vote;
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530712
713 pm_runtime_set_autosuspend_delay(&pdev->dev, LPI_AUTO_SUSPEND_DELAY);
714 pm_runtime_use_autosuspend(&pdev->dev);
715 pm_runtime_set_suspended(&pdev->dev);
716 pm_runtime_enable(&pdev->dev);
717
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530718 return 0;
719
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530720err_snd_evt:
721 audio_notifier_deregister("lpi_tlmm");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530722err_range:
723 gpiochip_remove(&state->chip);
724err_chip:
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800725 mutex_destroy(&state->slew_access_lock);
726err_io:
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530727 return ret;
728}
729
730static int lpi_pinctrl_remove(struct platform_device *pdev)
731{
732 struct lpi_gpio_state *state = platform_get_drvdata(pdev);
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800733
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530734 pm_runtime_disable(&pdev->dev);
735 pm_runtime_set_suspended(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530736
Laxminath Kasam27b1bbc2018-09-22 01:39:56 +0530737 snd_event_client_deregister(&pdev->dev);
Meng Wang921b95f2017-09-27 15:29:03 +0800738 audio_notifier_deregister("lpi_tlmm");
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530739 gpiochip_remove(&state->chip);
Karthikeyan Mani39b70f52019-02-20 17:24:10 -0800740 mutex_destroy(&state->slew_access_lock);
741
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530742 return 0;
743}
744
745static const struct of_device_id lpi_pinctrl_of_match[] = {
746 { .compatible = "qcom,lpi-pinctrl" }, /* Generic */
747 { },
748};
749
750MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
751
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530752int lpi_pinctrl_runtime_resume(struct device *dev)
753{
754 struct lpi_gpio_state *state = dev_get_drvdata(dev);
755 int ret = 0;
756
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530757 if (state->lpass_core_hw_vote == NULL) {
758 dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530759 return 0;
760 }
761
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530762 ret = clk_prepare_enable(state->lpass_core_hw_vote);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530763 if (ret < 0) {
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530764 dev_err(dev, "%s:lpass core hw island enable failed\n",
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530765 __func__);
766 }
767 pm_runtime_set_autosuspend_delay(dev, LPI_AUTO_SUSPEND_DELAY);
768 return 0;
769}
770
771int lpi_pinctrl_runtime_suspend(struct device *dev)
772{
773 struct lpi_gpio_state *state = dev_get_drvdata(dev);
774
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530775 if (state->lpass_core_hw_vote == NULL) {
776 dev_dbg(dev, "%s: Invalid core hw node\n", __func__);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530777 return 0;
778 }
Mangesh Kunchamwarcdd68db2019-01-10 16:21:00 +0530779 clk_disable_unprepare(state->lpass_core_hw_vote);
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530780 return 0;
781}
782
783static const struct dev_pm_ops lpi_pinctrl_dev_pm_ops = {
784 SET_RUNTIME_PM_OPS(
785 lpi_pinctrl_runtime_suspend,
786 lpi_pinctrl_runtime_resume,
787 NULL
788 )
789};
790
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530791static struct platform_driver lpi_pinctrl_driver = {
792 .driver = {
793 .name = "qcom-lpi-pinctrl",
Mangesh Kunchamwar8ab099a2018-11-13 16:20:16 +0530794 .pm = &lpi_pinctrl_dev_pm_ops,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530795 .of_match_table = lpi_pinctrl_of_match,
796 },
797 .probe = lpi_pinctrl_probe,
798 .remove = lpi_pinctrl_remove,
799};
800
801module_platform_driver(lpi_pinctrl_driver);
802
803MODULE_DESCRIPTION("QTI LPI GPIO pin control driver");
804MODULE_LICENSE("GPL v2");