162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Pinctrl driver for the Wondermedia SoC's
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/irq.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_irq.h>
1562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1662306a36Sopenharmony_ci#include <linux/pinctrl/machine.h>
1762306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
1862306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
1962306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
2062306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "pinctrl-wmt.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic inline void wmt_setbits(struct wmt_pinctrl_data *data, u32 reg,
2762306a36Sopenharmony_ci				 u32 mask)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	u32 val;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	val = readl_relaxed(data->base + reg);
3262306a36Sopenharmony_ci	val |= mask;
3362306a36Sopenharmony_ci	writel_relaxed(val, data->base + reg);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic inline void wmt_clearbits(struct wmt_pinctrl_data *data, u32 reg,
3762306a36Sopenharmony_ci				   u32 mask)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	u32 val;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	val = readl_relaxed(data->base + reg);
4262306a36Sopenharmony_ci	val &= ~mask;
4362306a36Sopenharmony_ci	writel_relaxed(val, data->base + reg);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cienum wmt_func_sel {
4762306a36Sopenharmony_ci	WMT_FSEL_GPIO_IN = 0,
4862306a36Sopenharmony_ci	WMT_FSEL_GPIO_OUT = 1,
4962306a36Sopenharmony_ci	WMT_FSEL_ALT = 2,
5062306a36Sopenharmony_ci	WMT_FSEL_COUNT = 3,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const char * const wmt_functions[WMT_FSEL_COUNT] = {
5462306a36Sopenharmony_ci	[WMT_FSEL_GPIO_IN] = "gpio_in",
5562306a36Sopenharmony_ci	[WMT_FSEL_GPIO_OUT] = "gpio_out",
5662306a36Sopenharmony_ci	[WMT_FSEL_ALT] = "alt",
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int wmt_pmx_get_functions_count(struct pinctrl_dev *pctldev)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	return WMT_FSEL_COUNT;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const char *wmt_pmx_get_function_name(struct pinctrl_dev *pctldev,
6562306a36Sopenharmony_ci					     unsigned selector)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	return wmt_functions[selector];
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int wmt_pmx_get_function_groups(struct pinctrl_dev *pctldev,
7162306a36Sopenharmony_ci				       unsigned selector,
7262306a36Sopenharmony_ci				       const char * const **groups,
7362306a36Sopenharmony_ci				       unsigned * const num_groups)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* every pin does every function */
7862306a36Sopenharmony_ci	*groups = data->groups;
7962306a36Sopenharmony_ci	*num_groups = data->ngroups;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func,
8562306a36Sopenharmony_ci			  unsigned pin)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	u32 bank = WMT_BANK_FROM_PIN(pin);
8862306a36Sopenharmony_ci	u32 bit = WMT_BIT_FROM_PIN(pin);
8962306a36Sopenharmony_ci	u32 reg_en = data->banks[bank].reg_en;
9062306a36Sopenharmony_ci	u32 reg_dir = data->banks[bank].reg_dir;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (reg_dir == NO_REG) {
9362306a36Sopenharmony_ci		dev_err(data->dev, "pin:%d no direction register defined\n",
9462306a36Sopenharmony_ci			pin);
9562306a36Sopenharmony_ci		return -EINVAL;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/*
9962306a36Sopenharmony_ci	 * If reg_en == NO_REG, we assume it is a dedicated GPIO and cannot be
10062306a36Sopenharmony_ci	 * disabled (as on VT8500) and that no alternate function is available.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	switch (func) {
10362306a36Sopenharmony_ci	case WMT_FSEL_GPIO_IN:
10462306a36Sopenharmony_ci		if (reg_en != NO_REG)
10562306a36Sopenharmony_ci			wmt_setbits(data, reg_en, BIT(bit));
10662306a36Sopenharmony_ci		wmt_clearbits(data, reg_dir, BIT(bit));
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case WMT_FSEL_GPIO_OUT:
10962306a36Sopenharmony_ci		if (reg_en != NO_REG)
11062306a36Sopenharmony_ci			wmt_setbits(data, reg_en, BIT(bit));
11162306a36Sopenharmony_ci		wmt_setbits(data, reg_dir, BIT(bit));
11262306a36Sopenharmony_ci		break;
11362306a36Sopenharmony_ci	case WMT_FSEL_ALT:
11462306a36Sopenharmony_ci		if (reg_en == NO_REG) {
11562306a36Sopenharmony_ci			dev_err(data->dev, "pin:%d no alt function available\n",
11662306a36Sopenharmony_ci				pin);
11762306a36Sopenharmony_ci			return -EINVAL;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci		wmt_clearbits(data, reg_en, BIT(bit));
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int wmt_pmx_set_mux(struct pinctrl_dev *pctldev,
12662306a36Sopenharmony_ci			   unsigned func_selector,
12762306a36Sopenharmony_ci			   unsigned group_selector)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
13062306a36Sopenharmony_ci	u32 pinnum = data->pins[group_selector].number;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return wmt_set_pinmux(data, func_selector, pinnum);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void wmt_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
13662306a36Sopenharmony_ci				      struct pinctrl_gpio_range *range,
13762306a36Sopenharmony_ci				      unsigned offset)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* disable by setting GPIO_IN */
14262306a36Sopenharmony_ci	wmt_set_pinmux(data, WMT_FSEL_GPIO_IN, offset);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int wmt_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
14662306a36Sopenharmony_ci				      struct pinctrl_gpio_range *range,
14762306a36Sopenharmony_ci				      unsigned offset,
14862306a36Sopenharmony_ci				      bool input)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	wmt_set_pinmux(data, (input ? WMT_FSEL_GPIO_IN : WMT_FSEL_GPIO_OUT),
15362306a36Sopenharmony_ci		       offset);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return 0;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const struct pinmux_ops wmt_pinmux_ops = {
15962306a36Sopenharmony_ci	.get_functions_count = wmt_pmx_get_functions_count,
16062306a36Sopenharmony_ci	.get_function_name = wmt_pmx_get_function_name,
16162306a36Sopenharmony_ci	.get_function_groups = wmt_pmx_get_function_groups,
16262306a36Sopenharmony_ci	.set_mux = wmt_pmx_set_mux,
16362306a36Sopenharmony_ci	.gpio_disable_free = wmt_pmx_gpio_disable_free,
16462306a36Sopenharmony_ci	.gpio_set_direction = wmt_pmx_gpio_set_direction,
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic int wmt_get_groups_count(struct pinctrl_dev *pctldev)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return data->ngroups;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic const char *wmt_get_group_name(struct pinctrl_dev *pctldev,
17562306a36Sopenharmony_ci				      unsigned selector)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return data->groups[selector];
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic int wmt_get_group_pins(struct pinctrl_dev *pctldev,
18362306a36Sopenharmony_ci			      unsigned selector,
18462306a36Sopenharmony_ci			      const unsigned **pins,
18562306a36Sopenharmony_ci			      unsigned *num_pins)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	*pins = &data->pins[selector].number;
19062306a36Sopenharmony_ci	*num_pins = 1;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int wmt_pctl_find_group_by_pin(struct wmt_pinctrl_data *data, u32 pin)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	int i;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	for (i = 0; i < data->npins; i++) {
20062306a36Sopenharmony_ci		if (data->pins[i].number == pin)
20162306a36Sopenharmony_ci			return i;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return -EINVAL;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map_func(struct wmt_pinctrl_data *data,
20862306a36Sopenharmony_ci					struct device_node *np,
20962306a36Sopenharmony_ci					u32 pin, u32 fnum,
21062306a36Sopenharmony_ci					struct pinctrl_map **maps)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	int group;
21362306a36Sopenharmony_ci	struct pinctrl_map *map = *maps;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (fnum >= ARRAY_SIZE(wmt_functions)) {
21662306a36Sopenharmony_ci		dev_err(data->dev, "invalid wm,function %d\n", fnum);
21762306a36Sopenharmony_ci		return -EINVAL;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	group = wmt_pctl_find_group_by_pin(data, pin);
22162306a36Sopenharmony_ci	if (group < 0) {
22262306a36Sopenharmony_ci		dev_err(data->dev, "unable to match pin %d to group\n", pin);
22362306a36Sopenharmony_ci		return group;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	map->type = PIN_MAP_TYPE_MUX_GROUP;
22762306a36Sopenharmony_ci	map->data.mux.group = data->groups[group];
22862306a36Sopenharmony_ci	map->data.mux.function = wmt_functions[fnum];
22962306a36Sopenharmony_ci	(*maps)++;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map_pull(struct wmt_pinctrl_data *data,
23562306a36Sopenharmony_ci					struct device_node *np,
23662306a36Sopenharmony_ci					u32 pin, u32 pull,
23762306a36Sopenharmony_ci					struct pinctrl_map **maps)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	int group;
24062306a36Sopenharmony_ci	unsigned long *configs;
24162306a36Sopenharmony_ci	struct pinctrl_map *map = *maps;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (pull > 2) {
24462306a36Sopenharmony_ci		dev_err(data->dev, "invalid wm,pull %d\n", pull);
24562306a36Sopenharmony_ci		return -EINVAL;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	group = wmt_pctl_find_group_by_pin(data, pin);
24962306a36Sopenharmony_ci	if (group < 0) {
25062306a36Sopenharmony_ci		dev_err(data->dev, "unable to match pin %d to group\n", pin);
25162306a36Sopenharmony_ci		return group;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	configs = kzalloc(sizeof(*configs), GFP_KERNEL);
25562306a36Sopenharmony_ci	if (!configs)
25662306a36Sopenharmony_ci		return -ENOMEM;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	switch (pull) {
25962306a36Sopenharmony_ci	case 0:
26062306a36Sopenharmony_ci		configs[0] = PIN_CONFIG_BIAS_DISABLE;
26162306a36Sopenharmony_ci		break;
26262306a36Sopenharmony_ci	case 1:
26362306a36Sopenharmony_ci		configs[0] = PIN_CONFIG_BIAS_PULL_DOWN;
26462306a36Sopenharmony_ci		break;
26562306a36Sopenharmony_ci	case 2:
26662306a36Sopenharmony_ci		configs[0] = PIN_CONFIG_BIAS_PULL_UP;
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	default:
26962306a36Sopenharmony_ci		configs[0] = PIN_CONFIG_BIAS_DISABLE;
27062306a36Sopenharmony_ci		dev_err(data->dev, "invalid pull state %d - disabling\n", pull);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	map->type = PIN_MAP_TYPE_CONFIGS_PIN;
27462306a36Sopenharmony_ci	map->data.configs.group_or_pin = data->groups[group];
27562306a36Sopenharmony_ci	map->data.configs.configs = configs;
27662306a36Sopenharmony_ci	map->data.configs.num_configs = 1;
27762306a36Sopenharmony_ci	(*maps)++;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic void wmt_pctl_dt_free_map(struct pinctrl_dev *pctldev,
28362306a36Sopenharmony_ci				 struct pinctrl_map *maps,
28462306a36Sopenharmony_ci				 unsigned num_maps)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	int i;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < num_maps; i++)
28962306a36Sopenharmony_ci		if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
29062306a36Sopenharmony_ci			kfree(maps[i].data.configs.configs);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	kfree(maps);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
29662306a36Sopenharmony_ci				   struct device_node *np,
29762306a36Sopenharmony_ci				   struct pinctrl_map **map,
29862306a36Sopenharmony_ci				   unsigned *num_maps)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct pinctrl_map *maps, *cur_map;
30162306a36Sopenharmony_ci	struct property *pins, *funcs, *pulls;
30262306a36Sopenharmony_ci	u32 pin, func, pull;
30362306a36Sopenharmony_ci	int num_pins, num_funcs, num_pulls, maps_per_pin;
30462306a36Sopenharmony_ci	int i, err;
30562306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	pins = of_find_property(np, "wm,pins", NULL);
30862306a36Sopenharmony_ci	if (!pins) {
30962306a36Sopenharmony_ci		dev_err(data->dev, "missing wmt,pins property\n");
31062306a36Sopenharmony_ci		return -EINVAL;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	funcs = of_find_property(np, "wm,function", NULL);
31462306a36Sopenharmony_ci	pulls = of_find_property(np, "wm,pull", NULL);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!funcs && !pulls) {
31762306a36Sopenharmony_ci		dev_err(data->dev, "neither wm,function nor wm,pull specified\n");
31862306a36Sopenharmony_ci		return -EINVAL;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/*
32262306a36Sopenharmony_ci	 * The following lines calculate how many values are defined for each
32362306a36Sopenharmony_ci	 * of the properties.
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci	num_pins = pins->length / sizeof(u32);
32662306a36Sopenharmony_ci	num_funcs = funcs ? (funcs->length / sizeof(u32)) : 0;
32762306a36Sopenharmony_ci	num_pulls = pulls ? (pulls->length / sizeof(u32)) : 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (num_funcs > 1 && num_funcs != num_pins) {
33062306a36Sopenharmony_ci		dev_err(data->dev, "wm,function must have 1 or %d entries\n",
33162306a36Sopenharmony_ci			num_pins);
33262306a36Sopenharmony_ci		return -EINVAL;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (num_pulls > 1 && num_pulls != num_pins) {
33662306a36Sopenharmony_ci		dev_err(data->dev, "wm,pull must have 1 or %d entries\n",
33762306a36Sopenharmony_ci			num_pins);
33862306a36Sopenharmony_ci		return -EINVAL;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	maps_per_pin = 0;
34262306a36Sopenharmony_ci	if (num_funcs)
34362306a36Sopenharmony_ci		maps_per_pin++;
34462306a36Sopenharmony_ci	if (num_pulls)
34562306a36Sopenharmony_ci		maps_per_pin++;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps),
34862306a36Sopenharmony_ci				 GFP_KERNEL);
34962306a36Sopenharmony_ci	if (!maps)
35062306a36Sopenharmony_ci		return -ENOMEM;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = 0; i < num_pins; i++) {
35362306a36Sopenharmony_ci		err = of_property_read_u32_index(np, "wm,pins", i, &pin);
35462306a36Sopenharmony_ci		if (err)
35562306a36Sopenharmony_ci			goto fail;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		if (pin >= (data->nbanks * 32)) {
35862306a36Sopenharmony_ci			dev_err(data->dev, "invalid wm,pins value\n");
35962306a36Sopenharmony_ci			err = -EINVAL;
36062306a36Sopenharmony_ci			goto fail;
36162306a36Sopenharmony_ci		}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		if (num_funcs) {
36462306a36Sopenharmony_ci			err = of_property_read_u32_index(np, "wm,function",
36562306a36Sopenharmony_ci						(num_funcs > 1 ? i : 0), &func);
36662306a36Sopenharmony_ci			if (err)
36762306a36Sopenharmony_ci				goto fail;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci			err = wmt_pctl_dt_node_to_map_func(data, np, pin, func,
37062306a36Sopenharmony_ci							   &cur_map);
37162306a36Sopenharmony_ci			if (err)
37262306a36Sopenharmony_ci				goto fail;
37362306a36Sopenharmony_ci		}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		if (num_pulls) {
37662306a36Sopenharmony_ci			err = of_property_read_u32_index(np, "wm,pull",
37762306a36Sopenharmony_ci						(num_pulls > 1 ? i : 0), &pull);
37862306a36Sopenharmony_ci			if (err)
37962306a36Sopenharmony_ci				goto fail;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci			err = wmt_pctl_dt_node_to_map_pull(data, np, pin, pull,
38262306a36Sopenharmony_ci							   &cur_map);
38362306a36Sopenharmony_ci			if (err)
38462306a36Sopenharmony_ci				goto fail;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	*map = maps;
38862306a36Sopenharmony_ci	*num_maps = num_pins * maps_per_pin;
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci * The fail path removes any maps that have been allocated. The fail path is
39362306a36Sopenharmony_ci * only called from code after maps has been kzalloc'd. It is also safe to
39462306a36Sopenharmony_ci * pass 'num_pins * maps_per_pin' as the map count even though we probably
39562306a36Sopenharmony_ci * failed before all the mappings were read as all maps are allocated at once,
39662306a36Sopenharmony_ci * and configs are only allocated for .type = PIN_MAP_TYPE_CONFIGS_PIN - there
39762306a36Sopenharmony_ci * is no failpath where a config can be allocated without .type being set.
39862306a36Sopenharmony_ci */
39962306a36Sopenharmony_cifail:
40062306a36Sopenharmony_ci	wmt_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
40162306a36Sopenharmony_ci	return err;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic const struct pinctrl_ops wmt_pctl_ops = {
40562306a36Sopenharmony_ci	.get_groups_count = wmt_get_groups_count,
40662306a36Sopenharmony_ci	.get_group_name	= wmt_get_group_name,
40762306a36Sopenharmony_ci	.get_group_pins	= wmt_get_group_pins,
40862306a36Sopenharmony_ci	.dt_node_to_map = wmt_pctl_dt_node_to_map,
40962306a36Sopenharmony_ci	.dt_free_map = wmt_pctl_dt_free_map,
41062306a36Sopenharmony_ci};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
41362306a36Sopenharmony_ci			   unsigned long *config)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	return -ENOTSUPP;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
41962306a36Sopenharmony_ci			   unsigned long *configs, unsigned num_configs)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
42262306a36Sopenharmony_ci	enum pin_config_param param;
42362306a36Sopenharmony_ci	u32 arg;
42462306a36Sopenharmony_ci	u32 bank = WMT_BANK_FROM_PIN(pin);
42562306a36Sopenharmony_ci	u32 bit = WMT_BIT_FROM_PIN(pin);
42662306a36Sopenharmony_ci	u32 reg_pull_en = data->banks[bank].reg_pull_en;
42762306a36Sopenharmony_ci	u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg;
42862306a36Sopenharmony_ci	int i;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) {
43162306a36Sopenharmony_ci		dev_err(data->dev, "bias functions not supported on pin %d\n",
43262306a36Sopenharmony_ci			pin);
43362306a36Sopenharmony_ci		return -EINVAL;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
43762306a36Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
43862306a36Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		if ((param == PIN_CONFIG_BIAS_PULL_DOWN) ||
44162306a36Sopenharmony_ci		    (param == PIN_CONFIG_BIAS_PULL_UP)) {
44262306a36Sopenharmony_ci			if (arg == 0)
44362306a36Sopenharmony_ci				param = PIN_CONFIG_BIAS_DISABLE;
44462306a36Sopenharmony_ci		}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		switch (param) {
44762306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_DISABLE:
44862306a36Sopenharmony_ci			wmt_clearbits(data, reg_pull_en, BIT(bit));
44962306a36Sopenharmony_ci			break;
45062306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_DOWN:
45162306a36Sopenharmony_ci			wmt_clearbits(data, reg_pull_cfg, BIT(bit));
45262306a36Sopenharmony_ci			wmt_setbits(data, reg_pull_en, BIT(bit));
45362306a36Sopenharmony_ci			break;
45462306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_UP:
45562306a36Sopenharmony_ci			wmt_setbits(data, reg_pull_cfg, BIT(bit));
45662306a36Sopenharmony_ci			wmt_setbits(data, reg_pull_en, BIT(bit));
45762306a36Sopenharmony_ci			break;
45862306a36Sopenharmony_ci		default:
45962306a36Sopenharmony_ci			dev_err(data->dev, "unknown pinconf param\n");
46062306a36Sopenharmony_ci			return -EINVAL;
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci	} /* for each config */
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	return 0;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic const struct pinconf_ops wmt_pinconf_ops = {
46862306a36Sopenharmony_ci	.pin_config_get = wmt_pinconf_get,
46962306a36Sopenharmony_ci	.pin_config_set = wmt_pinconf_set,
47062306a36Sopenharmony_ci};
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic struct pinctrl_desc wmt_desc = {
47362306a36Sopenharmony_ci	.owner = THIS_MODULE,
47462306a36Sopenharmony_ci	.name = "pinctrl-wmt",
47562306a36Sopenharmony_ci	.pctlops = &wmt_pctl_ops,
47662306a36Sopenharmony_ci	.pmxops = &wmt_pinmux_ops,
47762306a36Sopenharmony_ci	.confops = &wmt_pinconf_ops,
47862306a36Sopenharmony_ci};
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
48362306a36Sopenharmony_ci	u32 bank = WMT_BANK_FROM_PIN(offset);
48462306a36Sopenharmony_ci	u32 bit = WMT_BIT_FROM_PIN(offset);
48562306a36Sopenharmony_ci	u32 reg_dir = data->banks[bank].reg_dir;
48662306a36Sopenharmony_ci	u32 val;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	val = readl_relaxed(data->base + reg_dir);
48962306a36Sopenharmony_ci	if (val & BIT(bit))
49062306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_OUT;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return GPIO_LINE_DIRECTION_IN;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
49862306a36Sopenharmony_ci	u32 bank = WMT_BANK_FROM_PIN(offset);
49962306a36Sopenharmony_ci	u32 bit = WMT_BIT_FROM_PIN(offset);
50062306a36Sopenharmony_ci	u32 reg_data_in = data->banks[bank].reg_data_in;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (reg_data_in == NO_REG) {
50362306a36Sopenharmony_ci		dev_err(data->dev, "no data in register defined\n");
50462306a36Sopenharmony_ci		return -EINVAL;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit));
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
51162306a36Sopenharmony_ci			       int val)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
51462306a36Sopenharmony_ci	u32 bank = WMT_BANK_FROM_PIN(offset);
51562306a36Sopenharmony_ci	u32 bit = WMT_BIT_FROM_PIN(offset);
51662306a36Sopenharmony_ci	u32 reg_data_out = data->banks[bank].reg_data_out;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (reg_data_out == NO_REG) {
51962306a36Sopenharmony_ci		dev_err(data->dev, "no data out register defined\n");
52062306a36Sopenharmony_ci		return;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (val)
52462306a36Sopenharmony_ci		wmt_setbits(data, reg_data_out, BIT(bit));
52562306a36Sopenharmony_ci	else
52662306a36Sopenharmony_ci		wmt_clearbits(data, reg_data_out, BIT(bit));
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int wmt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	return pinctrl_gpio_direction_input(chip->base + offset);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
53562306a36Sopenharmony_ci				     int value)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	wmt_gpio_set_value(chip, offset, value);
53862306a36Sopenharmony_ci	return pinctrl_gpio_direction_output(chip->base + offset);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic const struct gpio_chip wmt_gpio_chip = {
54262306a36Sopenharmony_ci	.label = "gpio-wmt",
54362306a36Sopenharmony_ci	.owner = THIS_MODULE,
54462306a36Sopenharmony_ci	.request = gpiochip_generic_request,
54562306a36Sopenharmony_ci	.free = gpiochip_generic_free,
54662306a36Sopenharmony_ci	.get_direction = wmt_gpio_get_direction,
54762306a36Sopenharmony_ci	.direction_input = wmt_gpio_direction_input,
54862306a36Sopenharmony_ci	.direction_output = wmt_gpio_direction_output,
54962306a36Sopenharmony_ci	.get = wmt_gpio_get_value,
55062306a36Sopenharmony_ci	.set = wmt_gpio_set_value,
55162306a36Sopenharmony_ci	.can_sleep = false,
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ciint wmt_pinctrl_probe(struct platform_device *pdev,
55562306a36Sopenharmony_ci		      struct wmt_pinctrl_data *data)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	int err;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	data->base = devm_platform_ioremap_resource(pdev, 0);
56062306a36Sopenharmony_ci	if (IS_ERR(data->base))
56162306a36Sopenharmony_ci		return PTR_ERR(data->base);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	wmt_desc.pins = data->pins;
56462306a36Sopenharmony_ci	wmt_desc.npins = data->npins;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	data->gpio_chip = wmt_gpio_chip;
56762306a36Sopenharmony_ci	data->gpio_chip.parent = &pdev->dev;
56862306a36Sopenharmony_ci	data->gpio_chip.ngpio = data->nbanks * 32;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	platform_set_drvdata(pdev, data);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	data->dev = &pdev->dev;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	data->pctl_dev = devm_pinctrl_register(&pdev->dev, &wmt_desc, data);
57562306a36Sopenharmony_ci	if (IS_ERR(data->pctl_dev)) {
57662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register pinctrl\n");
57762306a36Sopenharmony_ci		return PTR_ERR(data->pctl_dev);
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	err = gpiochip_add_data(&data->gpio_chip, data);
58162306a36Sopenharmony_ci	if (err) {
58262306a36Sopenharmony_ci		dev_err(&pdev->dev, "could not add GPIO chip\n");
58362306a36Sopenharmony_ci		return err;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	err = gpiochip_add_pin_range(&data->gpio_chip, dev_name(data->dev),
58762306a36Sopenharmony_ci				     0, 0, data->nbanks * 32);
58862306a36Sopenharmony_ci	if (err)
58962306a36Sopenharmony_ci		goto fail_range;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	dev_info(&pdev->dev, "Pin controller initialized\n");
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cifail_range:
59662306a36Sopenharmony_ci	gpiochip_remove(&data->gpio_chip);
59762306a36Sopenharmony_ci	return err;
59862306a36Sopenharmony_ci}
599