162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2013 John Crispin <blogic@openwrt.org>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/device.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
1362306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
1462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
1562306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
1662306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1762306a36Sopenharmony_ci#include <linux/pinctrl/machine.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/mach-ralink/ralink_regs.h>
2062306a36Sopenharmony_ci#include <asm/mach-ralink/mt7620.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "pinctrl-mtmips.h"
2362306a36Sopenharmony_ci#include "../core.h"
2462306a36Sopenharmony_ci#include "../pinctrl-utils.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define SYSC_REG_GPIO_MODE	0x60
2762306a36Sopenharmony_ci#define SYSC_REG_GPIO_MODE2	0x64
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct mtmips_priv {
3062306a36Sopenharmony_ci	struct device *dev;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	struct pinctrl_pin_desc *pads;
3362306a36Sopenharmony_ci	struct pinctrl_desc *desc;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	struct mtmips_pmx_func **func;
3662306a36Sopenharmony_ci	int func_count;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	struct mtmips_pmx_group *groups;
3962306a36Sopenharmony_ci	const char **group_names;
4062306a36Sopenharmony_ci	int group_count;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	u8 *gpio;
4362306a36Sopenharmony_ci	int max_pins;
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int mtmips_get_group_count(struct pinctrl_dev *pctrldev)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	return p->group_count;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const char *mtmips_get_group_name(struct pinctrl_dev *pctrldev,
5462306a36Sopenharmony_ci					 unsigned int group)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return (group >= p->group_count) ? NULL : p->group_names[group];
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int mtmips_get_group_pins(struct pinctrl_dev *pctrldev,
6262306a36Sopenharmony_ci				 unsigned int group,
6362306a36Sopenharmony_ci				 const unsigned int **pins,
6462306a36Sopenharmony_ci				 unsigned int *num_pins)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (group >= p->group_count)
6962306a36Sopenharmony_ci		return -EINVAL;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	*pins = p->groups[group].func[0].pins;
7262306a36Sopenharmony_ci	*num_pins = p->groups[group].func[0].pin_count;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return 0;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic const struct pinctrl_ops mtmips_pctrl_ops = {
7862306a36Sopenharmony_ci	.get_groups_count	= mtmips_get_group_count,
7962306a36Sopenharmony_ci	.get_group_name		= mtmips_get_group_name,
8062306a36Sopenharmony_ci	.get_group_pins		= mtmips_get_group_pins,
8162306a36Sopenharmony_ci	.dt_node_to_map		= pinconf_generic_dt_node_to_map_all,
8262306a36Sopenharmony_ci	.dt_free_map		= pinconf_generic_dt_free_map,
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic int mtmips_pmx_func_count(struct pinctrl_dev *pctrldev)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return p->func_count;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const char *mtmips_pmx_func_name(struct pinctrl_dev *pctrldev,
9362306a36Sopenharmony_ci					unsigned int func)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return p->func[func]->name;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int mtmips_pmx_group_get_groups(struct pinctrl_dev *pctrldev,
10162306a36Sopenharmony_ci				       unsigned int func,
10262306a36Sopenharmony_ci				       const char * const **groups,
10362306a36Sopenharmony_ci				       unsigned int * const num_groups)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (p->func[func]->group_count == 1)
10862306a36Sopenharmony_ci		*groups = &p->group_names[p->func[func]->groups[0]];
10962306a36Sopenharmony_ci	else
11062306a36Sopenharmony_ci		*groups = p->group_names;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	*num_groups = p->func[func]->group_count;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int mtmips_pmx_group_enable(struct pinctrl_dev *pctrldev,
11862306a36Sopenharmony_ci				   unsigned int func, unsigned int group)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
12162306a36Sopenharmony_ci	u32 mode = 0;
12262306a36Sopenharmony_ci	u32 reg = SYSC_REG_GPIO_MODE;
12362306a36Sopenharmony_ci	int i;
12462306a36Sopenharmony_ci	int shift;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* dont allow double use */
12762306a36Sopenharmony_ci	if (p->groups[group].enabled) {
12862306a36Sopenharmony_ci		dev_err(p->dev, "%s is already enabled\n",
12962306a36Sopenharmony_ci			p->groups[group].name);
13062306a36Sopenharmony_ci		return 0;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	p->groups[group].enabled = 1;
13462306a36Sopenharmony_ci	p->func[func]->enabled = 1;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	shift = p->groups[group].shift;
13762306a36Sopenharmony_ci	if (shift >= 32) {
13862306a36Sopenharmony_ci		shift -= 32;
13962306a36Sopenharmony_ci		reg = SYSC_REG_GPIO_MODE2;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	mode = rt_sysc_r32(reg);
14262306a36Sopenharmony_ci	mode &= ~(p->groups[group].mask << shift);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* mark the pins as gpio */
14562306a36Sopenharmony_ci	for (i = 0; i < p->groups[group].func[0].pin_count; i++)
14662306a36Sopenharmony_ci		p->gpio[p->groups[group].func[0].pins[i]] = 1;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* function 0 is gpio and needs special handling */
14962306a36Sopenharmony_ci	if (func == 0) {
15062306a36Sopenharmony_ci		mode |= p->groups[group].gpio << shift;
15162306a36Sopenharmony_ci	} else {
15262306a36Sopenharmony_ci		for (i = 0; i < p->func[func]->pin_count; i++)
15362306a36Sopenharmony_ci			p->gpio[p->func[func]->pins[i]] = 0;
15462306a36Sopenharmony_ci		mode |= p->func[func]->value << shift;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	rt_sysc_w32(mode, reg);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int mtmips_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev,
16262306a36Sopenharmony_ci						struct pinctrl_gpio_range *range,
16362306a36Sopenharmony_ci						unsigned int pin)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (!p->gpio[pin]) {
16862306a36Sopenharmony_ci		dev_err(p->dev, "pin %d is not set to gpio mux\n", pin);
16962306a36Sopenharmony_ci		return -EINVAL;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	return 0;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic const struct pinmux_ops mtmips_pmx_group_ops = {
17662306a36Sopenharmony_ci	.get_functions_count	= mtmips_pmx_func_count,
17762306a36Sopenharmony_ci	.get_function_name	= mtmips_pmx_func_name,
17862306a36Sopenharmony_ci	.get_function_groups	= mtmips_pmx_group_get_groups,
17962306a36Sopenharmony_ci	.set_mux		= mtmips_pmx_group_enable,
18062306a36Sopenharmony_ci	.gpio_request_enable	= mtmips_pmx_group_gpio_request_enable,
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct pinctrl_desc mtmips_pctrl_desc = {
18462306a36Sopenharmony_ci	.owner		= THIS_MODULE,
18562306a36Sopenharmony_ci	.name		= "mtmips-pinctrl",
18662306a36Sopenharmony_ci	.pctlops	= &mtmips_pctrl_ops,
18762306a36Sopenharmony_ci	.pmxops		= &mtmips_pmx_group_ops,
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct mtmips_pmx_func gpio_func = {
19162306a36Sopenharmony_ci	.name = "gpio",
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int mtmips_pinctrl_index(struct mtmips_priv *p)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct mtmips_pmx_group *mux = p->groups;
19762306a36Sopenharmony_ci	int i, j, c = 0;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* count the mux functions */
20062306a36Sopenharmony_ci	while (mux->name) {
20162306a36Sopenharmony_ci		p->group_count++;
20262306a36Sopenharmony_ci		mux++;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* allocate the group names array needed by the gpio function */
20662306a36Sopenharmony_ci	p->group_names = devm_kcalloc(p->dev, p->group_count,
20762306a36Sopenharmony_ci				      sizeof(char *), GFP_KERNEL);
20862306a36Sopenharmony_ci	if (!p->group_names)
20962306a36Sopenharmony_ci		return -ENOMEM;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < p->group_count; i++) {
21262306a36Sopenharmony_ci		p->group_names[i] = p->groups[i].name;
21362306a36Sopenharmony_ci		p->func_count += p->groups[i].func_count;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/* we have a dummy function[0] for gpio */
21762306a36Sopenharmony_ci	p->func_count++;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* allocate our function and group mapping index buffers */
22062306a36Sopenharmony_ci	p->func = devm_kcalloc(p->dev, p->func_count,
22162306a36Sopenharmony_ci			       sizeof(*p->func), GFP_KERNEL);
22262306a36Sopenharmony_ci	gpio_func.groups = devm_kcalloc(p->dev, p->group_count, sizeof(int),
22362306a36Sopenharmony_ci					GFP_KERNEL);
22462306a36Sopenharmony_ci	if (!p->func || !gpio_func.groups)
22562306a36Sopenharmony_ci		return -ENOMEM;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* add a backpointer to the function so it knows its group */
22862306a36Sopenharmony_ci	gpio_func.group_count = p->group_count;
22962306a36Sopenharmony_ci	for (i = 0; i < gpio_func.group_count; i++)
23062306a36Sopenharmony_ci		gpio_func.groups[i] = i;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	p->func[c] = &gpio_func;
23362306a36Sopenharmony_ci	c++;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* add remaining functions */
23662306a36Sopenharmony_ci	for (i = 0; i < p->group_count; i++) {
23762306a36Sopenharmony_ci		for (j = 0; j < p->groups[i].func_count; j++) {
23862306a36Sopenharmony_ci			p->func[c] = &p->groups[i].func[j];
23962306a36Sopenharmony_ci			p->func[c]->groups = devm_kzalloc(p->dev, sizeof(int),
24062306a36Sopenharmony_ci						    GFP_KERNEL);
24162306a36Sopenharmony_ci			if (!p->func[c]->groups)
24262306a36Sopenharmony_ci				return -ENOMEM;
24362306a36Sopenharmony_ci			p->func[c]->groups[0] = i;
24462306a36Sopenharmony_ci			p->func[c]->group_count = 1;
24562306a36Sopenharmony_ci			c++;
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int mtmips_pinctrl_pins(struct mtmips_priv *p)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	int i, j;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/*
25662306a36Sopenharmony_ci	 * loop over the functions and initialize the pins array.
25762306a36Sopenharmony_ci	 * also work out the highest pin used.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	for (i = 0; i < p->func_count; i++) {
26062306a36Sopenharmony_ci		int pin;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		if (!p->func[i]->pin_count)
26362306a36Sopenharmony_ci			continue;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		p->func[i]->pins = devm_kcalloc(p->dev,
26662306a36Sopenharmony_ci						p->func[i]->pin_count,
26762306a36Sopenharmony_ci						sizeof(int),
26862306a36Sopenharmony_ci						GFP_KERNEL);
26962306a36Sopenharmony_ci		if (!p->func[i]->pins)
27062306a36Sopenharmony_ci			return -ENOMEM;
27162306a36Sopenharmony_ci		for (j = 0; j < p->func[i]->pin_count; j++)
27262306a36Sopenharmony_ci			p->func[i]->pins[j] = p->func[i]->pin_first + j;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		pin = p->func[i]->pin_first + p->func[i]->pin_count;
27562306a36Sopenharmony_ci		if (pin > p->max_pins)
27662306a36Sopenharmony_ci			p->max_pins = pin;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* the buffer that tells us which pins are gpio */
28062306a36Sopenharmony_ci	p->gpio = devm_kcalloc(p->dev, p->max_pins, sizeof(u8), GFP_KERNEL);
28162306a36Sopenharmony_ci	/* the pads needed to tell pinctrl about our pins */
28262306a36Sopenharmony_ci	p->pads = devm_kcalloc(p->dev, p->max_pins,
28362306a36Sopenharmony_ci			       sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
28462306a36Sopenharmony_ci	if (!p->pads || !p->gpio)
28562306a36Sopenharmony_ci		return -ENOMEM;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	memset(p->gpio, 1, sizeof(u8) * p->max_pins);
28862306a36Sopenharmony_ci	for (i = 0; i < p->func_count; i++) {
28962306a36Sopenharmony_ci		if (!p->func[i]->pin_count)
29062306a36Sopenharmony_ci			continue;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		for (j = 0; j < p->func[i]->pin_count; j++)
29362306a36Sopenharmony_ci			p->gpio[p->func[i]->pins[j]] = 0;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* pin 0 is always a gpio */
29762306a36Sopenharmony_ci	p->gpio[0] = 1;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* set the pads */
30062306a36Sopenharmony_ci	for (i = 0; i < p->max_pins; i++) {
30162306a36Sopenharmony_ci		/* strlen("ioXY") + 1 = 5 */
30262306a36Sopenharmony_ci		char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		if (!name)
30562306a36Sopenharmony_ci			return -ENOMEM;
30662306a36Sopenharmony_ci		snprintf(name, 5, "io%d", i);
30762306a36Sopenharmony_ci		p->pads[i].number = i;
30862306a36Sopenharmony_ci		p->pads[i].name = name;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci	p->desc->pins = p->pads;
31162306a36Sopenharmony_ci	p->desc->npins = p->max_pins;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ciint mtmips_pinctrl_init(struct platform_device *pdev,
31762306a36Sopenharmony_ci			struct mtmips_pmx_group *data)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct mtmips_priv *p;
32062306a36Sopenharmony_ci	struct pinctrl_dev *dev;
32162306a36Sopenharmony_ci	int err;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (!data)
32462306a36Sopenharmony_ci		return -ENOTSUPP;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* setup the private data */
32762306a36Sopenharmony_ci	p = devm_kzalloc(&pdev->dev, sizeof(struct mtmips_priv), GFP_KERNEL);
32862306a36Sopenharmony_ci	if (!p)
32962306a36Sopenharmony_ci		return -ENOMEM;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	p->dev = &pdev->dev;
33262306a36Sopenharmony_ci	p->desc = &mtmips_pctrl_desc;
33362306a36Sopenharmony_ci	p->groups = data;
33462306a36Sopenharmony_ci	platform_set_drvdata(pdev, p);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/* init the device */
33762306a36Sopenharmony_ci	err = mtmips_pinctrl_index(p);
33862306a36Sopenharmony_ci	if (err) {
33962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to load index\n");
34062306a36Sopenharmony_ci		return err;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	err = mtmips_pinctrl_pins(p);
34462306a36Sopenharmony_ci	if (err) {
34562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to load pins\n");
34662306a36Sopenharmony_ci		return err;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci	dev = pinctrl_register(p->desc, &pdev->dev, p);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(dev);
35162306a36Sopenharmony_ci}
352