162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2020 Linaro Ltd.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/bitfield.h>
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/seq_file.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
1662306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
1762306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "../pinctrl-utils.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "pinctrl-lpass-lpi.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define MAX_NR_GPIO		23
2462306a36Sopenharmony_ci#define GPIO_FUNC		0
2562306a36Sopenharmony_ci#define MAX_LPI_NUM_CLKS	2
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct lpi_pinctrl {
2862306a36Sopenharmony_ci	struct device *dev;
2962306a36Sopenharmony_ci	struct pinctrl_dev *ctrl;
3062306a36Sopenharmony_ci	struct gpio_chip chip;
3162306a36Sopenharmony_ci	struct pinctrl_desc desc;
3262306a36Sopenharmony_ci	char __iomem *tlmm_base;
3362306a36Sopenharmony_ci	char __iomem *slew_base;
3462306a36Sopenharmony_ci	struct clk_bulk_data clks[MAX_LPI_NUM_CLKS];
3562306a36Sopenharmony_ci	/* Protects from concurrent register updates */
3662306a36Sopenharmony_ci	struct mutex lock;
3762306a36Sopenharmony_ci	DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO);
3862306a36Sopenharmony_ci	const struct lpi_pinctrl_variant_data *data;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin,
4262306a36Sopenharmony_ci			 unsigned int addr)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	return ioread32(state->tlmm_base + LPI_TLMM_REG_OFFSET * pin + addr);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin,
4862306a36Sopenharmony_ci			  unsigned int addr, unsigned int val)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	iowrite32(val, state->tlmm_base + LPI_TLMM_REG_OFFSET * pin + addr);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic const struct pinctrl_ops lpi_gpio_pinctrl_ops = {
5662306a36Sopenharmony_ci	.get_groups_count	= pinctrl_generic_get_group_count,
5762306a36Sopenharmony_ci	.get_group_name		= pinctrl_generic_get_group_name,
5862306a36Sopenharmony_ci	.get_group_pins		= pinctrl_generic_get_group_pins,
5962306a36Sopenharmony_ci	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
6062306a36Sopenharmony_ci	.dt_free_map		= pinctrl_utils_free_map,
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int lpi_gpio_get_functions_count(struct pinctrl_dev *pctldev)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return pctrl->data->nfunctions;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic const char *lpi_gpio_get_function_name(struct pinctrl_dev *pctldev,
7162306a36Sopenharmony_ci					      unsigned int function)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return pctrl->data->functions[function].name;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev,
7962306a36Sopenharmony_ci					unsigned int function,
8062306a36Sopenharmony_ci					const char *const **groups,
8162306a36Sopenharmony_ci					unsigned *const num_qgroups)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	*groups = pctrl->data->functions[function].groups;
8662306a36Sopenharmony_ci	*num_qgroups = pctrl->data->functions[function].ngroups;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
9262306a36Sopenharmony_ci			    unsigned int group)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
9562306a36Sopenharmony_ci	const struct lpi_pingroup *g = &pctrl->data->groups[group];
9662306a36Sopenharmony_ci	u32 val;
9762306a36Sopenharmony_ci	int i, pin = g->pin;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	for (i = 0; i < g->nfuncs; i++) {
10062306a36Sopenharmony_ci		if (g->funcs[i] == function)
10162306a36Sopenharmony_ci			break;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (WARN_ON(i == g->nfuncs))
10562306a36Sopenharmony_ci		return -EINVAL;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	mutex_lock(&pctrl->lock);
10862306a36Sopenharmony_ci	val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/*
11162306a36Sopenharmony_ci	 * If this is the first time muxing to GPIO and the direction is
11262306a36Sopenharmony_ci	 * output, make sure that we're not going to be glitching the pin
11362306a36Sopenharmony_ci	 * by reading the current state of the pin and setting it as the
11462306a36Sopenharmony_ci	 * output.
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	if (i == GPIO_FUNC && (val & LPI_GPIO_OE_MASK) &&
11762306a36Sopenharmony_ci	    !test_and_set_bit(group, pctrl->ever_gpio)) {
11862306a36Sopenharmony_ci		u32 io_val = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		if (io_val & LPI_GPIO_VALUE_IN_MASK) {
12162306a36Sopenharmony_ci			if (!(io_val & LPI_GPIO_VALUE_OUT_MASK))
12262306a36Sopenharmony_ci				lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG,
12362306a36Sopenharmony_ci					       io_val | LPI_GPIO_VALUE_OUT_MASK);
12462306a36Sopenharmony_ci		} else {
12562306a36Sopenharmony_ci			if (io_val & LPI_GPIO_VALUE_OUT_MASK)
12662306a36Sopenharmony_ci				lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG,
12762306a36Sopenharmony_ci					       io_val & ~LPI_GPIO_VALUE_OUT_MASK);
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
13262306a36Sopenharmony_ci	lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
13362306a36Sopenharmony_ci	mutex_unlock(&pctrl->lock);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic const struct pinmux_ops lpi_gpio_pinmux_ops = {
13962306a36Sopenharmony_ci	.get_functions_count	= lpi_gpio_get_functions_count,
14062306a36Sopenharmony_ci	.get_function_name	= lpi_gpio_get_function_name,
14162306a36Sopenharmony_ci	.get_function_groups	= lpi_gpio_get_function_groups,
14262306a36Sopenharmony_ci	.set_mux		= lpi_gpio_set_mux,
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int lpi_config_get(struct pinctrl_dev *pctldev,
14662306a36Sopenharmony_ci			  unsigned int pin, unsigned long *config)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	unsigned int param = pinconf_to_config_param(*config);
14962306a36Sopenharmony_ci	struct lpi_pinctrl *state = dev_get_drvdata(pctldev->dev);
15062306a36Sopenharmony_ci	unsigned int arg = 0;
15162306a36Sopenharmony_ci	int is_out;
15262306a36Sopenharmony_ci	int pull;
15362306a36Sopenharmony_ci	u32 ctl_reg;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ctl_reg = lpi_gpio_read(state, pin, LPI_GPIO_CFG_REG);
15662306a36Sopenharmony_ci	is_out = ctl_reg & LPI_GPIO_OE_MASK;
15762306a36Sopenharmony_ci	pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	switch (param) {
16062306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
16162306a36Sopenharmony_ci		if (pull == LPI_GPIO_BIAS_DISABLE)
16262306a36Sopenharmony_ci			arg = 1;
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
16562306a36Sopenharmony_ci		if (pull == LPI_GPIO_PULL_DOWN)
16662306a36Sopenharmony_ci			arg = 1;
16762306a36Sopenharmony_ci		break;
16862306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_BUS_HOLD:
16962306a36Sopenharmony_ci		if (pull == LPI_GPIO_KEEPER)
17062306a36Sopenharmony_ci			arg = 1;
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
17362306a36Sopenharmony_ci		if (pull == LPI_GPIO_PULL_UP)
17462306a36Sopenharmony_ci			arg = 1;
17562306a36Sopenharmony_ci		break;
17662306a36Sopenharmony_ci	case PIN_CONFIG_INPUT_ENABLE:
17762306a36Sopenharmony_ci	case PIN_CONFIG_OUTPUT:
17862306a36Sopenharmony_ci		if (is_out)
17962306a36Sopenharmony_ci			arg = 1;
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	default:
18262306a36Sopenharmony_ci		return -EINVAL;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
19062306a36Sopenharmony_ci			  unsigned long *configs, unsigned int nconfs)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = dev_get_drvdata(pctldev->dev);
19362306a36Sopenharmony_ci	unsigned int param, arg, pullup = LPI_GPIO_BIAS_DISABLE, strength = 2;
19462306a36Sopenharmony_ci	bool value, output_enabled = false;
19562306a36Sopenharmony_ci	const struct lpi_pingroup *g;
19662306a36Sopenharmony_ci	unsigned long sval;
19762306a36Sopenharmony_ci	int i, slew_offset;
19862306a36Sopenharmony_ci	u32 val;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	g = &pctrl->data->groups[group];
20162306a36Sopenharmony_ci	for (i = 0; i < nconfs; i++) {
20262306a36Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
20362306a36Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		switch (param) {
20662306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_DISABLE:
20762306a36Sopenharmony_ci			pullup = LPI_GPIO_BIAS_DISABLE;
20862306a36Sopenharmony_ci			break;
20962306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_DOWN:
21062306a36Sopenharmony_ci			pullup = LPI_GPIO_PULL_DOWN;
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_BUS_HOLD:
21362306a36Sopenharmony_ci			pullup = LPI_GPIO_KEEPER;
21462306a36Sopenharmony_ci			break;
21562306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_UP:
21662306a36Sopenharmony_ci			pullup = LPI_GPIO_PULL_UP;
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		case PIN_CONFIG_INPUT_ENABLE:
21962306a36Sopenharmony_ci			output_enabled = false;
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		case PIN_CONFIG_OUTPUT:
22262306a36Sopenharmony_ci			output_enabled = true;
22362306a36Sopenharmony_ci			value = arg;
22462306a36Sopenharmony_ci			break;
22562306a36Sopenharmony_ci		case PIN_CONFIG_DRIVE_STRENGTH:
22662306a36Sopenharmony_ci			strength = arg;
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci		case PIN_CONFIG_SLEW_RATE:
22962306a36Sopenharmony_ci			if (arg > LPI_SLEW_RATE_MAX) {
23062306a36Sopenharmony_ci				dev_err(pctldev->dev, "invalid slew rate %u for pin: %d\n",
23162306a36Sopenharmony_ci					arg, group);
23262306a36Sopenharmony_ci				return -EINVAL;
23362306a36Sopenharmony_ci			}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci			slew_offset = g->slew_offset;
23662306a36Sopenharmony_ci			if (slew_offset == LPI_NO_SLEW)
23762306a36Sopenharmony_ci				break;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci			mutex_lock(&pctrl->lock);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci			sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
24262306a36Sopenharmony_ci			sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
24362306a36Sopenharmony_ci			sval |= arg << slew_offset;
24462306a36Sopenharmony_ci			iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			mutex_unlock(&pctrl->lock);
24762306a36Sopenharmony_ci			break;
24862306a36Sopenharmony_ci		default:
24962306a36Sopenharmony_ci			return -EINVAL;
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/*
25462306a36Sopenharmony_ci	 * As per Hardware Programming Guide, when configuring pin as output,
25562306a36Sopenharmony_ci	 * set the pin value before setting output-enable (OE).
25662306a36Sopenharmony_ci	 */
25762306a36Sopenharmony_ci	if (output_enabled) {
25862306a36Sopenharmony_ci		val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK);
25962306a36Sopenharmony_ci		lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	mutex_lock(&pctrl->lock);
26362306a36Sopenharmony_ci	val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK);
26662306a36Sopenharmony_ci	u32p_replace_bits(&val, LPI_GPIO_DS_TO_VAL(strength),
26762306a36Sopenharmony_ci			  LPI_GPIO_OUT_STRENGTH_MASK);
26862306a36Sopenharmony_ci	u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
27162306a36Sopenharmony_ci	mutex_unlock(&pctrl->lock);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const struct pinconf_ops lpi_gpio_pinconf_ops = {
27762306a36Sopenharmony_ci	.is_generic			= true,
27862306a36Sopenharmony_ci	.pin_config_group_get		= lpi_config_get,
27962306a36Sopenharmony_ci	.pin_config_group_set		= lpi_config_set,
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int lpi_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct lpi_pinctrl *state = gpiochip_get_data(chip);
28562306a36Sopenharmony_ci	unsigned long config;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	return lpi_config_set(state->ctrl, pin, &config, 1);
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic int lpi_gpio_direction_output(struct gpio_chip *chip,
29362306a36Sopenharmony_ci				     unsigned int pin, int val)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct lpi_pinctrl *state = gpiochip_get_data(chip);
29662306a36Sopenharmony_ci	unsigned long config;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return lpi_config_set(state->ctrl, pin, &config, 1);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct lpi_pinctrl *state = gpiochip_get_data(chip);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return lpi_gpio_read(state, pin, LPI_GPIO_VALUE_REG) &
30862306a36Sopenharmony_ci		LPI_GPIO_VALUE_IN_MASK;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct lpi_pinctrl *state = gpiochip_get_data(chip);
31462306a36Sopenharmony_ci	unsigned long config;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	lpi_config_set(state->ctrl, pin, &config, 1);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
32262306a36Sopenharmony_ci#include <linux/seq_file.h>
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic unsigned int lpi_regval_to_drive(u32 val)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	return (val + 1) * 2;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void lpi_gpio_dbg_show_one(struct seq_file *s,
33062306a36Sopenharmony_ci				  struct pinctrl_dev *pctldev,
33162306a36Sopenharmony_ci				  struct gpio_chip *chip,
33262306a36Sopenharmony_ci				  unsigned int offset,
33362306a36Sopenharmony_ci				  unsigned int gpio)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct lpi_pinctrl *state = gpiochip_get_data(chip);
33662306a36Sopenharmony_ci	struct pinctrl_pin_desc pindesc;
33762306a36Sopenharmony_ci	unsigned int func;
33862306a36Sopenharmony_ci	int is_out;
33962306a36Sopenharmony_ci	int drive;
34062306a36Sopenharmony_ci	int pull;
34162306a36Sopenharmony_ci	u32 ctl_reg;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	static const char * const pulls[] = {
34462306a36Sopenharmony_ci		"no pull",
34562306a36Sopenharmony_ci		"pull down",
34662306a36Sopenharmony_ci		"keeper",
34762306a36Sopenharmony_ci		"pull up"
34862306a36Sopenharmony_ci	};
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	pctldev = pctldev ? : state->ctrl;
35162306a36Sopenharmony_ci	pindesc = pctldev->desc->pins[offset];
35262306a36Sopenharmony_ci	ctl_reg = lpi_gpio_read(state, offset, LPI_GPIO_CFG_REG);
35362306a36Sopenharmony_ci	is_out = ctl_reg & LPI_GPIO_OE_MASK;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	func = FIELD_GET(LPI_GPIO_FUNCTION_MASK, ctl_reg);
35662306a36Sopenharmony_ci	drive = FIELD_GET(LPI_GPIO_OUT_STRENGTH_MASK, ctl_reg);
35762306a36Sopenharmony_ci	pull = FIELD_GET(LPI_GPIO_PULL_MASK, ctl_reg);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	seq_printf(s, " %-8s: %-3s %d", pindesc.name, is_out ? "out" : "in", func);
36062306a36Sopenharmony_ci	seq_printf(s, " %dmA", lpi_regval_to_drive(drive));
36162306a36Sopenharmony_ci	seq_printf(s, " %s", pulls[pull]);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void lpi_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	unsigned int gpio = chip->base;
36762306a36Sopenharmony_ci	unsigned int i;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < chip->ngpio; i++, gpio++) {
37062306a36Sopenharmony_ci		lpi_gpio_dbg_show_one(s, NULL, chip, i, gpio);
37162306a36Sopenharmony_ci		seq_puts(s, "\n");
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci#else
37662306a36Sopenharmony_ci#define lpi_gpio_dbg_show NULL
37762306a36Sopenharmony_ci#endif
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic const struct gpio_chip lpi_gpio_template = {
38062306a36Sopenharmony_ci	.direction_input	= lpi_gpio_direction_input,
38162306a36Sopenharmony_ci	.direction_output	= lpi_gpio_direction_output,
38262306a36Sopenharmony_ci	.get			= lpi_gpio_get,
38362306a36Sopenharmony_ci	.set			= lpi_gpio_set,
38462306a36Sopenharmony_ci	.request		= gpiochip_generic_request,
38562306a36Sopenharmony_ci	.free			= gpiochip_generic_free,
38662306a36Sopenharmony_ci	.dbg_show		= lpi_gpio_dbg_show,
38762306a36Sopenharmony_ci};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int lpi_build_pin_desc_groups(struct lpi_pinctrl *pctrl)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	int i, ret;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	for (i = 0; i < pctrl->data->npins; i++) {
39462306a36Sopenharmony_ci		const struct pinctrl_pin_desc *pin_info = pctrl->desc.pins + i;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		ret = pinctrl_generic_add_group(pctrl->ctrl, pin_info->name,
39762306a36Sopenharmony_ci						  (int *)&pin_info->number, 1, NULL);
39862306a36Sopenharmony_ci		if (ret < 0)
39962306a36Sopenharmony_ci			goto err_pinctrl;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cierr_pinctrl:
40562306a36Sopenharmony_ci	for (; i > 0; i--)
40662306a36Sopenharmony_ci		pinctrl_generic_remove_group(pctrl->ctrl, i - 1);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return ret;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ciint lpi_pinctrl_probe(struct platform_device *pdev)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	const struct lpi_pinctrl_variant_data *data;
41462306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
41562306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl;
41662306a36Sopenharmony_ci	int ret;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
41962306a36Sopenharmony_ci	if (!pctrl)
42062306a36Sopenharmony_ci		return -ENOMEM;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	platform_set_drvdata(pdev, pctrl);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	data = of_device_get_match_data(dev);
42562306a36Sopenharmony_ci	if (!data)
42662306a36Sopenharmony_ci		return -EINVAL;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	if (WARN_ON(data->npins > MAX_NR_GPIO))
42962306a36Sopenharmony_ci		return -EINVAL;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	pctrl->data = data;
43262306a36Sopenharmony_ci	pctrl->dev = &pdev->dev;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	pctrl->clks[0].id = "core";
43562306a36Sopenharmony_ci	pctrl->clks[1].id = "audio";
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	pctrl->tlmm_base = devm_platform_ioremap_resource(pdev, 0);
43862306a36Sopenharmony_ci	if (IS_ERR(pctrl->tlmm_base))
43962306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pctrl->tlmm_base),
44062306a36Sopenharmony_ci				     "TLMM resource not provided\n");
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	pctrl->slew_base = devm_platform_ioremap_resource(pdev, 1);
44362306a36Sopenharmony_ci	if (IS_ERR(pctrl->slew_base))
44462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pctrl->slew_base),
44562306a36Sopenharmony_ci				     "Slew resource not provided\n");
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
44862306a36Sopenharmony_ci	if (ret)
44962306a36Sopenharmony_ci		return ret;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(MAX_LPI_NUM_CLKS, pctrl->clks);
45262306a36Sopenharmony_ci	if (ret)
45362306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "Can't enable clocks\n");
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	pctrl->desc.pctlops = &lpi_gpio_pinctrl_ops;
45662306a36Sopenharmony_ci	pctrl->desc.pmxops = &lpi_gpio_pinmux_ops;
45762306a36Sopenharmony_ci	pctrl->desc.confops = &lpi_gpio_pinconf_ops;
45862306a36Sopenharmony_ci	pctrl->desc.owner = THIS_MODULE;
45962306a36Sopenharmony_ci	pctrl->desc.name = dev_name(dev);
46062306a36Sopenharmony_ci	pctrl->desc.pins = data->pins;
46162306a36Sopenharmony_ci	pctrl->desc.npins = data->npins;
46262306a36Sopenharmony_ci	pctrl->chip = lpi_gpio_template;
46362306a36Sopenharmony_ci	pctrl->chip.parent = dev;
46462306a36Sopenharmony_ci	pctrl->chip.base = -1;
46562306a36Sopenharmony_ci	pctrl->chip.ngpio = data->npins;
46662306a36Sopenharmony_ci	pctrl->chip.label = dev_name(dev);
46762306a36Sopenharmony_ci	pctrl->chip.can_sleep = false;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	mutex_init(&pctrl->lock);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl);
47262306a36Sopenharmony_ci	if (IS_ERR(pctrl->ctrl)) {
47362306a36Sopenharmony_ci		ret = PTR_ERR(pctrl->ctrl);
47462306a36Sopenharmony_ci		dev_err(dev, "failed to add pin controller\n");
47562306a36Sopenharmony_ci		goto err_pinctrl;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	ret = lpi_build_pin_desc_groups(pctrl);
47962306a36Sopenharmony_ci	if (ret)
48062306a36Sopenharmony_ci		goto err_pinctrl;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(dev, &pctrl->chip, pctrl);
48362306a36Sopenharmony_ci	if (ret) {
48462306a36Sopenharmony_ci		dev_err(pctrl->dev, "can't add gpio chip\n");
48562306a36Sopenharmony_ci		goto err_pinctrl;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cierr_pinctrl:
49162306a36Sopenharmony_ci	mutex_destroy(&pctrl->lock);
49262306a36Sopenharmony_ci	clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	return ret;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lpi_pinctrl_probe);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciint lpi_pinctrl_remove(struct platform_device *pdev)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev);
50162306a36Sopenharmony_ci	int i;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	mutex_destroy(&pctrl->lock);
50462306a36Sopenharmony_ci	clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	for (i = 0; i < pctrl->data->npins; i++)
50762306a36Sopenharmony_ci		pinctrl_generic_remove_group(pctrl->ctrl, i);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lpi_pinctrl_remove);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ciMODULE_DESCRIPTION("QTI LPI GPIO pin control driver");
51462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
515