162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ams AS3722 pin control and GPIO driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013, NVIDIA Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Laxman Dewangan <ldewangan@nvidia.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/mfd/as3722.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/pm.h>
1862306a36Sopenharmony_ci#include <linux/property.h>
1962306a36Sopenharmony_ci#include <linux/slab.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2262306a36Sopenharmony_ci#include <linux/pinctrl/machine.h>
2362306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
2462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
2562306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
2662306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include "core.h"
2962306a36Sopenharmony_ci#include "pinconf.h"
3062306a36Sopenharmony_ci#include "pinctrl-utils.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define AS3722_PIN_GPIO0		0
3362306a36Sopenharmony_ci#define AS3722_PIN_GPIO1		1
3462306a36Sopenharmony_ci#define AS3722_PIN_GPIO2		2
3562306a36Sopenharmony_ci#define AS3722_PIN_GPIO3		3
3662306a36Sopenharmony_ci#define AS3722_PIN_GPIO4		4
3762306a36Sopenharmony_ci#define AS3722_PIN_GPIO5		5
3862306a36Sopenharmony_ci#define AS3722_PIN_GPIO6		6
3962306a36Sopenharmony_ci#define AS3722_PIN_GPIO7		7
4062306a36Sopenharmony_ci#define AS3722_PIN_NUM			(AS3722_PIN_GPIO7 + 1)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define AS3722_GPIO_MODE_PULL_UP           BIT(PIN_CONFIG_BIAS_PULL_UP)
4362306a36Sopenharmony_ci#define AS3722_GPIO_MODE_PULL_DOWN         BIT(PIN_CONFIG_BIAS_PULL_DOWN)
4462306a36Sopenharmony_ci#define AS3722_GPIO_MODE_HIGH_IMPED        BIT(PIN_CONFIG_BIAS_HIGH_IMPEDANCE)
4562306a36Sopenharmony_ci#define AS3722_GPIO_MODE_OPEN_DRAIN        BIT(PIN_CONFIG_DRIVE_OPEN_DRAIN)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct as3722_pin_function {
4862306a36Sopenharmony_ci	const char *name;
4962306a36Sopenharmony_ci	const char * const *groups;
5062306a36Sopenharmony_ci	unsigned ngroups;
5162306a36Sopenharmony_ci	int mux_option;
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct as3722_gpio_pin_control {
5562306a36Sopenharmony_ci	unsigned mode_prop;
5662306a36Sopenharmony_ci	int io_function;
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct as3722_pingroup {
6062306a36Sopenharmony_ci	const char *name;
6162306a36Sopenharmony_ci	const unsigned pins[1];
6262306a36Sopenharmony_ci	unsigned npins;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct as3722_pctrl_info {
6662306a36Sopenharmony_ci	struct device *dev;
6762306a36Sopenharmony_ci	struct pinctrl_dev *pctl;
6862306a36Sopenharmony_ci	struct as3722 *as3722;
6962306a36Sopenharmony_ci	struct gpio_chip gpio_chip;
7062306a36Sopenharmony_ci	int pins_current_opt[AS3722_PIN_NUM];
7162306a36Sopenharmony_ci	const struct as3722_pin_function *functions;
7262306a36Sopenharmony_ci	unsigned num_functions;
7362306a36Sopenharmony_ci	const struct as3722_pingroup *pin_groups;
7462306a36Sopenharmony_ci	int num_pin_groups;
7562306a36Sopenharmony_ci	const struct pinctrl_pin_desc *pins;
7662306a36Sopenharmony_ci	unsigned num_pins;
7762306a36Sopenharmony_ci	struct as3722_gpio_pin_control gpio_control[AS3722_PIN_NUM];
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic const struct pinctrl_pin_desc as3722_pins_desc[] = {
8162306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO0, "gpio0"),
8262306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO1, "gpio1"),
8362306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO2, "gpio2"),
8462306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO3, "gpio3"),
8562306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO4, "gpio4"),
8662306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO5, "gpio5"),
8762306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO6, "gpio6"),
8862306a36Sopenharmony_ci	PINCTRL_PIN(AS3722_PIN_GPIO7, "gpio7"),
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const char * const gpio_groups[] = {
9262306a36Sopenharmony_ci	"gpio0",
9362306a36Sopenharmony_ci	"gpio1",
9462306a36Sopenharmony_ci	"gpio2",
9562306a36Sopenharmony_ci	"gpio3",
9662306a36Sopenharmony_ci	"gpio4",
9762306a36Sopenharmony_ci	"gpio5",
9862306a36Sopenharmony_ci	"gpio6",
9962306a36Sopenharmony_ci	"gpio7",
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cienum as3722_pinmux_option {
10362306a36Sopenharmony_ci	AS3722_PINMUX_GPIO			= 0,
10462306a36Sopenharmony_ci	AS3722_PINMUX_INTERRUPT_OUT		= 1,
10562306a36Sopenharmony_ci	AS3722_PINMUX_VSUB_VBAT_UNDEB_LOW_OUT	= 2,
10662306a36Sopenharmony_ci	AS3722_PINMUX_GPIO_INTERRUPT		= 3,
10762306a36Sopenharmony_ci	AS3722_PINMUX_PWM_INPUT			= 4,
10862306a36Sopenharmony_ci	AS3722_PINMUX_VOLTAGE_IN_STBY		= 5,
10962306a36Sopenharmony_ci	AS3722_PINMUX_OC_PG_SD0			= 6,
11062306a36Sopenharmony_ci	AS3722_PINMUX_PG_OUT			= 7,
11162306a36Sopenharmony_ci	AS3722_PINMUX_CLK32K_OUT		= 8,
11262306a36Sopenharmony_ci	AS3722_PINMUX_WATCHDOG_INPUT		= 9,
11362306a36Sopenharmony_ci	AS3722_PINMUX_SOFT_RESET_IN		= 11,
11462306a36Sopenharmony_ci	AS3722_PINMUX_PWM_OUTPUT		= 12,
11562306a36Sopenharmony_ci	AS3722_PINMUX_VSUB_VBAT_LOW_DEB_OUT	= 13,
11662306a36Sopenharmony_ci	AS3722_PINMUX_OC_PG_SD6			= 14,
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define FUNCTION_GROUP(fname, mux)			\
12062306a36Sopenharmony_ci	{						\
12162306a36Sopenharmony_ci		.name = #fname,				\
12262306a36Sopenharmony_ci		.groups = gpio_groups,			\
12362306a36Sopenharmony_ci		.ngroups = ARRAY_SIZE(gpio_groups),	\
12462306a36Sopenharmony_ci		.mux_option = AS3722_PINMUX_##mux,	\
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct as3722_pin_function as3722_pin_function[] = {
12862306a36Sopenharmony_ci	FUNCTION_GROUP(gpio, GPIO),
12962306a36Sopenharmony_ci	FUNCTION_GROUP(interrupt-out, INTERRUPT_OUT),
13062306a36Sopenharmony_ci	FUNCTION_GROUP(gpio-in-interrupt, GPIO_INTERRUPT),
13162306a36Sopenharmony_ci	FUNCTION_GROUP(vsup-vbat-low-undebounce-out, VSUB_VBAT_UNDEB_LOW_OUT),
13262306a36Sopenharmony_ci	FUNCTION_GROUP(vsup-vbat-low-debounce-out, VSUB_VBAT_LOW_DEB_OUT),
13362306a36Sopenharmony_ci	FUNCTION_GROUP(voltage-in-standby, VOLTAGE_IN_STBY),
13462306a36Sopenharmony_ci	FUNCTION_GROUP(oc-pg-sd0, OC_PG_SD0),
13562306a36Sopenharmony_ci	FUNCTION_GROUP(oc-pg-sd6, OC_PG_SD6),
13662306a36Sopenharmony_ci	FUNCTION_GROUP(powergood-out, PG_OUT),
13762306a36Sopenharmony_ci	FUNCTION_GROUP(pwm-in, PWM_INPUT),
13862306a36Sopenharmony_ci	FUNCTION_GROUP(pwm-out, PWM_OUTPUT),
13962306a36Sopenharmony_ci	FUNCTION_GROUP(clk32k-out, CLK32K_OUT),
14062306a36Sopenharmony_ci	FUNCTION_GROUP(watchdog-in, WATCHDOG_INPUT),
14162306a36Sopenharmony_ci	FUNCTION_GROUP(soft-reset-in, SOFT_RESET_IN),
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define AS3722_PINGROUP(pg_name, pin_id) \
14562306a36Sopenharmony_ci	{								\
14662306a36Sopenharmony_ci		.name = #pg_name,					\
14762306a36Sopenharmony_ci		.pins = {AS3722_PIN_##pin_id},				\
14862306a36Sopenharmony_ci		.npins = 1,						\
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic const struct as3722_pingroup as3722_pingroups[] = {
15262306a36Sopenharmony_ci	AS3722_PINGROUP(gpio0,	GPIO0),
15362306a36Sopenharmony_ci	AS3722_PINGROUP(gpio1,	GPIO1),
15462306a36Sopenharmony_ci	AS3722_PINGROUP(gpio2,	GPIO2),
15562306a36Sopenharmony_ci	AS3722_PINGROUP(gpio3,	GPIO3),
15662306a36Sopenharmony_ci	AS3722_PINGROUP(gpio4,	GPIO4),
15762306a36Sopenharmony_ci	AS3722_PINGROUP(gpio5,	GPIO5),
15862306a36Sopenharmony_ci	AS3722_PINGROUP(gpio6,	GPIO6),
15962306a36Sopenharmony_ci	AS3722_PINGROUP(gpio7,	GPIO7),
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int as3722_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return as_pci->num_pin_groups;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic const char *as3722_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
17062306a36Sopenharmony_ci		unsigned group)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return as_pci->pin_groups[group].name;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int as3722_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
17862306a36Sopenharmony_ci		unsigned group, const unsigned **pins, unsigned *num_pins)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	*pins = as_pci->pin_groups[group].pins;
18362306a36Sopenharmony_ci	*num_pins = as_pci->pin_groups[group].npins;
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic const struct pinctrl_ops as3722_pinctrl_ops = {
18862306a36Sopenharmony_ci	.get_groups_count = as3722_pinctrl_get_groups_count,
18962306a36Sopenharmony_ci	.get_group_name = as3722_pinctrl_get_group_name,
19062306a36Sopenharmony_ci	.get_group_pins = as3722_pinctrl_get_group_pins,
19162306a36Sopenharmony_ci	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
19262306a36Sopenharmony_ci	.dt_free_map = pinctrl_utils_free_map,
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int as3722_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return as_pci->num_functions;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic const char *as3722_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
20362306a36Sopenharmony_ci			unsigned function)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return as_pci->functions[function].name;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int as3722_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
21162306a36Sopenharmony_ci		unsigned function, const char * const **groups,
21262306a36Sopenharmony_ci		unsigned * const num_groups)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	*groups = as_pci->functions[function].groups;
21762306a36Sopenharmony_ci	*num_groups = as_pci->functions[function].ngroups;
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int as3722_pinctrl_set(struct pinctrl_dev *pctldev, unsigned function,
22262306a36Sopenharmony_ci		unsigned group)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
22562306a36Sopenharmony_ci	int gpio_cntr_reg = AS3722_GPIOn_CONTROL_REG(group);
22662306a36Sopenharmony_ci	u8 val = AS3722_GPIO_IOSF_VAL(as_pci->functions[function].mux_option);
22762306a36Sopenharmony_ci	int ret;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	dev_dbg(as_pci->dev, "%s(): GPIO %u pin to function %u and val %u\n",
23062306a36Sopenharmony_ci		__func__, group, function, val);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ret = as3722_update_bits(as_pci->as3722, gpio_cntr_reg,
23362306a36Sopenharmony_ci			AS3722_GPIO_IOSF_MASK, val);
23462306a36Sopenharmony_ci	if (ret < 0) {
23562306a36Sopenharmony_ci		dev_err(as_pci->dev, "GPIO%d_CTRL_REG update failed %d\n",
23662306a36Sopenharmony_ci			group, ret);
23762306a36Sopenharmony_ci		return ret;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	as_pci->gpio_control[group].io_function = function;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	switch (val) {
24262306a36Sopenharmony_ci	case AS3722_GPIO_IOSF_SD0_OUT:
24362306a36Sopenharmony_ci	case AS3722_GPIO_IOSF_PWR_GOOD_OUT:
24462306a36Sopenharmony_ci	case AS3722_GPIO_IOSF_Q32K_OUT:
24562306a36Sopenharmony_ci	case AS3722_GPIO_IOSF_PWM_OUT:
24662306a36Sopenharmony_ci	case AS3722_GPIO_IOSF_SD6_LOW_VOLT_LOW:
24762306a36Sopenharmony_ci		ret = as3722_update_bits(as_pci->as3722, gpio_cntr_reg,
24862306a36Sopenharmony_ci			AS3722_GPIO_MODE_MASK, AS3722_GPIO_MODE_OUTPUT_VDDH);
24962306a36Sopenharmony_ci		if (ret < 0) {
25062306a36Sopenharmony_ci			dev_err(as_pci->dev, "GPIO%d_CTRL update failed %d\n",
25162306a36Sopenharmony_ci				group, ret);
25262306a36Sopenharmony_ci			return ret;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		as_pci->gpio_control[group].mode_prop =
25562306a36Sopenharmony_ci				AS3722_GPIO_MODE_OUTPUT_VDDH;
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	default:
25862306a36Sopenharmony_ci		break;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci	return ret;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int as3722_pinctrl_gpio_get_mode(unsigned gpio_mode_prop, bool input)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	if (gpio_mode_prop & AS3722_GPIO_MODE_HIGH_IMPED)
26662306a36Sopenharmony_ci		return -EINVAL;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (gpio_mode_prop & AS3722_GPIO_MODE_OPEN_DRAIN) {
26962306a36Sopenharmony_ci		if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP)
27062306a36Sopenharmony_ci			return AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP;
27162306a36Sopenharmony_ci		return AS3722_GPIO_MODE_IO_OPEN_DRAIN;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	if (input) {
27462306a36Sopenharmony_ci		if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP)
27562306a36Sopenharmony_ci			return AS3722_GPIO_MODE_INPUT_PULL_UP;
27662306a36Sopenharmony_ci		else if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN)
27762306a36Sopenharmony_ci			return AS3722_GPIO_MODE_INPUT_PULL_DOWN;
27862306a36Sopenharmony_ci		return AS3722_GPIO_MODE_INPUT;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN)
28162306a36Sopenharmony_ci		return AS3722_GPIO_MODE_OUTPUT_VDDL;
28262306a36Sopenharmony_ci	return AS3722_GPIO_MODE_OUTPUT_VDDH;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int as3722_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
28662306a36Sopenharmony_ci		struct pinctrl_gpio_range *range, unsigned offset)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (as_pci->gpio_control[offset].io_function)
29162306a36Sopenharmony_ci		return -EBUSY;
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic int as3722_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,
29662306a36Sopenharmony_ci		struct pinctrl_gpio_range *range, unsigned offset, bool input)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
29962306a36Sopenharmony_ci	struct as3722 *as3722 = as_pci->as3722;
30062306a36Sopenharmony_ci	int mode;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	mode = as3722_pinctrl_gpio_get_mode(
30362306a36Sopenharmony_ci			as_pci->gpio_control[offset].mode_prop, input);
30462306a36Sopenharmony_ci	if (mode < 0) {
30562306a36Sopenharmony_ci		dev_err(as_pci->dev, "%s direction for GPIO %d not supported\n",
30662306a36Sopenharmony_ci			(input) ? "Input" : "Output", offset);
30762306a36Sopenharmony_ci		return mode;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return as3722_update_bits(as3722, AS3722_GPIOn_CONTROL_REG(offset),
31162306a36Sopenharmony_ci				AS3722_GPIO_MODE_MASK, mode);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic const struct pinmux_ops as3722_pinmux_ops = {
31562306a36Sopenharmony_ci	.get_functions_count	= as3722_pinctrl_get_funcs_count,
31662306a36Sopenharmony_ci	.get_function_name	= as3722_pinctrl_get_func_name,
31762306a36Sopenharmony_ci	.get_function_groups	= as3722_pinctrl_get_func_groups,
31862306a36Sopenharmony_ci	.set_mux		= as3722_pinctrl_set,
31962306a36Sopenharmony_ci	.gpio_request_enable	= as3722_pinctrl_gpio_request_enable,
32062306a36Sopenharmony_ci	.gpio_set_direction	= as3722_pinctrl_gpio_set_direction,
32162306a36Sopenharmony_ci};
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int as3722_pinconf_get(struct pinctrl_dev *pctldev,
32462306a36Sopenharmony_ci			unsigned pin, unsigned long *config)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
32762306a36Sopenharmony_ci	enum pin_config_param param = pinconf_to_config_param(*config);
32862306a36Sopenharmony_ci	int arg = 0;
32962306a36Sopenharmony_ci	u16 prop;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	switch (param) {
33262306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
33362306a36Sopenharmony_ci		prop = AS3722_GPIO_MODE_PULL_UP |
33462306a36Sopenharmony_ci				AS3722_GPIO_MODE_PULL_DOWN;
33562306a36Sopenharmony_ci		if (!(as_pci->gpio_control[pin].mode_prop & prop))
33662306a36Sopenharmony_ci			arg = 1;
33762306a36Sopenharmony_ci		prop = 0;
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
34162306a36Sopenharmony_ci		prop = AS3722_GPIO_MODE_PULL_UP;
34262306a36Sopenharmony_ci		break;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
34562306a36Sopenharmony_ci		prop = AS3722_GPIO_MODE_PULL_DOWN;
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
34962306a36Sopenharmony_ci		prop = AS3722_GPIO_MODE_OPEN_DRAIN;
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
35362306a36Sopenharmony_ci		prop = AS3722_GPIO_MODE_HIGH_IMPED;
35462306a36Sopenharmony_ci		break;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	default:
35762306a36Sopenharmony_ci		dev_err(as_pci->dev, "Properties not supported\n");
35862306a36Sopenharmony_ci		return -ENOTSUPP;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (as_pci->gpio_control[pin].mode_prop & prop)
36262306a36Sopenharmony_ci		arg = 1;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	*config = pinconf_to_config_packed(param, (u16)arg);
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int as3722_pinconf_set(struct pinctrl_dev *pctldev,
36962306a36Sopenharmony_ci			unsigned pin, unsigned long *configs,
37062306a36Sopenharmony_ci			unsigned num_configs)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);
37362306a36Sopenharmony_ci	enum pin_config_param param;
37462306a36Sopenharmony_ci	int mode_prop;
37562306a36Sopenharmony_ci	int i;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
37862306a36Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
37962306a36Sopenharmony_ci		mode_prop = as_pci->gpio_control[pin].mode_prop;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		switch (param) {
38262306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
38362306a36Sopenharmony_ci			break;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_DISABLE:
38662306a36Sopenharmony_ci			mode_prop &= ~(AS3722_GPIO_MODE_PULL_UP |
38762306a36Sopenharmony_ci					AS3722_GPIO_MODE_PULL_DOWN);
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_UP:
39062306a36Sopenharmony_ci			mode_prop |= AS3722_GPIO_MODE_PULL_UP;
39162306a36Sopenharmony_ci			break;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_DOWN:
39462306a36Sopenharmony_ci			mode_prop |= AS3722_GPIO_MODE_PULL_DOWN;
39562306a36Sopenharmony_ci			break;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
39862306a36Sopenharmony_ci			mode_prop |= AS3722_GPIO_MODE_HIGH_IMPED;
39962306a36Sopenharmony_ci			break;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
40262306a36Sopenharmony_ci			mode_prop |= AS3722_GPIO_MODE_OPEN_DRAIN;
40362306a36Sopenharmony_ci			break;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		default:
40662306a36Sopenharmony_ci			dev_err(as_pci->dev, "Properties not supported\n");
40762306a36Sopenharmony_ci			return -ENOTSUPP;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		as_pci->gpio_control[pin].mode_prop = mode_prop;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic const struct pinconf_ops as3722_pinconf_ops = {
41662306a36Sopenharmony_ci	.pin_config_get = as3722_pinconf_get,
41762306a36Sopenharmony_ci	.pin_config_set = as3722_pinconf_set,
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic struct pinctrl_desc as3722_pinctrl_desc = {
42162306a36Sopenharmony_ci	.pctlops = &as3722_pinctrl_ops,
42262306a36Sopenharmony_ci	.pmxops = &as3722_pinmux_ops,
42362306a36Sopenharmony_ci	.confops = &as3722_pinconf_ops,
42462306a36Sopenharmony_ci	.owner = THIS_MODULE,
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
43062306a36Sopenharmony_ci	struct as3722 *as3722 = as_pci->as3722;
43162306a36Sopenharmony_ci	int ret;
43262306a36Sopenharmony_ci	u32 reg;
43362306a36Sopenharmony_ci	u32 control;
43462306a36Sopenharmony_ci	u32 val;
43562306a36Sopenharmony_ci	int mode;
43662306a36Sopenharmony_ci	int invert_enable;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &control);
43962306a36Sopenharmony_ci	if (ret < 0) {
44062306a36Sopenharmony_ci		dev_err(as_pci->dev,
44162306a36Sopenharmony_ci			"GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);
44262306a36Sopenharmony_ci		return ret;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	invert_enable = !!(control & AS3722_GPIO_INV);
44662306a36Sopenharmony_ci	mode = control & AS3722_GPIO_MODE_MASK;
44762306a36Sopenharmony_ci	switch (mode) {
44862306a36Sopenharmony_ci	case AS3722_GPIO_MODE_INPUT:
44962306a36Sopenharmony_ci	case AS3722_GPIO_MODE_INPUT_PULL_UP:
45062306a36Sopenharmony_ci	case AS3722_GPIO_MODE_INPUT_PULL_DOWN:
45162306a36Sopenharmony_ci	case AS3722_GPIO_MODE_IO_OPEN_DRAIN:
45262306a36Sopenharmony_ci	case AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP:
45362306a36Sopenharmony_ci		reg = AS3722_GPIO_SIGNAL_IN_REG;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci	case AS3722_GPIO_MODE_OUTPUT_VDDH:
45662306a36Sopenharmony_ci	case AS3722_GPIO_MODE_OUTPUT_VDDL:
45762306a36Sopenharmony_ci		reg = AS3722_GPIO_SIGNAL_OUT_REG;
45862306a36Sopenharmony_ci		break;
45962306a36Sopenharmony_ci	default:
46062306a36Sopenharmony_ci		return -EINVAL;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	ret = as3722_read(as3722, reg, &val);
46462306a36Sopenharmony_ci	if (ret < 0) {
46562306a36Sopenharmony_ci		dev_err(as_pci->dev,
46662306a36Sopenharmony_ci			"GPIO_SIGNAL_IN_REG read failed: %d\n", ret);
46762306a36Sopenharmony_ci		return ret;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	val = !!(val & AS3722_GPIOn_SIGNAL(offset));
47162306a36Sopenharmony_ci	return (invert_enable) ? !val : val;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
47562306a36Sopenharmony_ci		int value)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
47862306a36Sopenharmony_ci	struct as3722 *as3722 = as_pci->as3722;
47962306a36Sopenharmony_ci	int en_invert;
48062306a36Sopenharmony_ci	u32 val;
48162306a36Sopenharmony_ci	int ret;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &val);
48462306a36Sopenharmony_ci	if (ret < 0) {
48562306a36Sopenharmony_ci		dev_err(as_pci->dev,
48662306a36Sopenharmony_ci			"GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);
48762306a36Sopenharmony_ci		return;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci	en_invert = !!(val & AS3722_GPIO_INV);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (value)
49262306a36Sopenharmony_ci		val = (en_invert) ? 0 : AS3722_GPIOn_SIGNAL(offset);
49362306a36Sopenharmony_ci	else
49462306a36Sopenharmony_ci		val = (en_invert) ? AS3722_GPIOn_SIGNAL(offset) : 0;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	ret = as3722_update_bits(as3722, AS3722_GPIO_SIGNAL_OUT_REG,
49762306a36Sopenharmony_ci			AS3722_GPIOn_SIGNAL(offset), val);
49862306a36Sopenharmony_ci	if (ret < 0)
49962306a36Sopenharmony_ci		dev_err(as_pci->dev,
50062306a36Sopenharmony_ci			"GPIO_SIGNAL_OUT_REG update failed: %d\n", ret);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int as3722_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	return pinctrl_gpio_direction_input(chip->base + offset);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int as3722_gpio_direction_output(struct gpio_chip *chip,
50962306a36Sopenharmony_ci		unsigned offset, int value)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	as3722_gpio_set(chip, offset, value);
51262306a36Sopenharmony_ci	return pinctrl_gpio_direction_output(chip->base + offset);
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return as3722_irq_get_virq(as_pci->as3722, offset);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic const struct gpio_chip as3722_gpio_chip = {
52362306a36Sopenharmony_ci	.label			= "as3722-gpio",
52462306a36Sopenharmony_ci	.owner			= THIS_MODULE,
52562306a36Sopenharmony_ci	.request		= gpiochip_generic_request,
52662306a36Sopenharmony_ci	.free			= gpiochip_generic_free,
52762306a36Sopenharmony_ci	.get			= as3722_gpio_get,
52862306a36Sopenharmony_ci	.set			= as3722_gpio_set,
52962306a36Sopenharmony_ci	.direction_input	= as3722_gpio_direction_input,
53062306a36Sopenharmony_ci	.direction_output	= as3722_gpio_direction_output,
53162306a36Sopenharmony_ci	.to_irq			= as3722_gpio_to_irq,
53262306a36Sopenharmony_ci	.can_sleep		= true,
53362306a36Sopenharmony_ci	.ngpio			= AS3722_PIN_NUM,
53462306a36Sopenharmony_ci	.base			= -1,
53562306a36Sopenharmony_ci};
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic int as3722_pinctrl_probe(struct platform_device *pdev)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci;
54062306a36Sopenharmony_ci	int ret;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent));
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	as_pci = devm_kzalloc(&pdev->dev, sizeof(*as_pci), GFP_KERNEL);
54562306a36Sopenharmony_ci	if (!as_pci)
54662306a36Sopenharmony_ci		return -ENOMEM;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	as_pci->dev = &pdev->dev;
54962306a36Sopenharmony_ci	as_pci->as3722 = dev_get_drvdata(pdev->dev.parent);
55062306a36Sopenharmony_ci	platform_set_drvdata(pdev, as_pci);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	as_pci->pins = as3722_pins_desc;
55362306a36Sopenharmony_ci	as_pci->num_pins = ARRAY_SIZE(as3722_pins_desc);
55462306a36Sopenharmony_ci	as_pci->functions = as3722_pin_function;
55562306a36Sopenharmony_ci	as_pci->num_functions = ARRAY_SIZE(as3722_pin_function);
55662306a36Sopenharmony_ci	as_pci->pin_groups = as3722_pingroups;
55762306a36Sopenharmony_ci	as_pci->num_pin_groups = ARRAY_SIZE(as3722_pingroups);
55862306a36Sopenharmony_ci	as3722_pinctrl_desc.name = dev_name(&pdev->dev);
55962306a36Sopenharmony_ci	as3722_pinctrl_desc.pins = as3722_pins_desc;
56062306a36Sopenharmony_ci	as3722_pinctrl_desc.npins = ARRAY_SIZE(as3722_pins_desc);
56162306a36Sopenharmony_ci	as_pci->pctl = devm_pinctrl_register(&pdev->dev, &as3722_pinctrl_desc,
56262306a36Sopenharmony_ci					     as_pci);
56362306a36Sopenharmony_ci	if (IS_ERR(as_pci->pctl)) {
56462306a36Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
56562306a36Sopenharmony_ci		return PTR_ERR(as_pci->pctl);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	as_pci->gpio_chip = as3722_gpio_chip;
56962306a36Sopenharmony_ci	as_pci->gpio_chip.parent = &pdev->dev;
57062306a36Sopenharmony_ci	ret = gpiochip_add_data(&as_pci->gpio_chip, as_pci);
57162306a36Sopenharmony_ci	if (ret < 0) {
57262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret);
57362306a36Sopenharmony_ci		return ret;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ret = gpiochip_add_pin_range(&as_pci->gpio_chip, dev_name(&pdev->dev),
57762306a36Sopenharmony_ci				0, 0, AS3722_PIN_NUM);
57862306a36Sopenharmony_ci	if (ret < 0) {
57962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't add pin range, %d\n", ret);
58062306a36Sopenharmony_ci		goto fail_range_add;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cifail_range_add:
58662306a36Sopenharmony_ci	gpiochip_remove(&as_pci->gpio_chip);
58762306a36Sopenharmony_ci	return ret;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic int as3722_pinctrl_remove(struct platform_device *pdev)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct as3722_pctrl_info *as_pci = platform_get_drvdata(pdev);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	gpiochip_remove(&as_pci->gpio_chip);
59562306a36Sopenharmony_ci	return 0;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic const struct of_device_id as3722_pinctrl_of_match[] = {
59962306a36Sopenharmony_ci	{ .compatible = "ams,as3722-pinctrl", },
60062306a36Sopenharmony_ci	{ },
60162306a36Sopenharmony_ci};
60262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, as3722_pinctrl_of_match);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic struct platform_driver as3722_pinctrl_driver = {
60562306a36Sopenharmony_ci	.driver = {
60662306a36Sopenharmony_ci		.name = "as3722-pinctrl",
60762306a36Sopenharmony_ci		.of_match_table = as3722_pinctrl_of_match,
60862306a36Sopenharmony_ci	},
60962306a36Sopenharmony_ci	.probe = as3722_pinctrl_probe,
61062306a36Sopenharmony_ci	.remove = as3722_pinctrl_remove,
61162306a36Sopenharmony_ci};
61262306a36Sopenharmony_cimodule_platform_driver(as3722_pinctrl_driver);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ciMODULE_ALIAS("platform:as3722-pinctrl");
61562306a36Sopenharmony_ciMODULE_DESCRIPTION("AS3722 pin control and GPIO driver");
61662306a36Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
61762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
618