xref: /linux/drivers/pinctrl/meson/pinctrl-amlogic-a4.c (revision eafd95ea74846eda3e3eac6b2bb7f34619d8a6f8)
16e9be3abSXianwei Zhao // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
26e9be3abSXianwei Zhao /*
36e9be3abSXianwei Zhao  * Copyright (c) 2024 Amlogic, Inc. All rights reserved.
46e9be3abSXianwei Zhao  * Author: Xianwei Zhao <xianwei.zhao@amlogic.com>
56e9be3abSXianwei Zhao  */
66e9be3abSXianwei Zhao 
76e9be3abSXianwei Zhao #include <linux/err.h>
86e9be3abSXianwei Zhao #include <linux/gpio/driver.h>
96e9be3abSXianwei Zhao #include <linux/init.h>
106e9be3abSXianwei Zhao #include <linux/io.h>
116e9be3abSXianwei Zhao #include <linux/module.h>
126e9be3abSXianwei Zhao #include <linux/of.h>
136e9be3abSXianwei Zhao #include <linux/of_address.h>
146e9be3abSXianwei Zhao #include <linux/platform_device.h>
156e9be3abSXianwei Zhao #include <linux/regmap.h>
166e9be3abSXianwei Zhao #include <linux/seq_file.h>
176e9be3abSXianwei Zhao #include <linux/slab.h>
186e9be3abSXianwei Zhao #include <linux/string_helpers.h>
196e9be3abSXianwei Zhao 
206e9be3abSXianwei Zhao #include <linux/pinctrl/consumer.h>
216e9be3abSXianwei Zhao #include <linux/pinctrl/pinconf.h>
226e9be3abSXianwei Zhao #include <linux/pinctrl/pinctrl.h>
236e9be3abSXianwei Zhao #include <linux/pinctrl/pinmux.h>
246e9be3abSXianwei Zhao #include <dt-bindings/pinctrl/amlogic,pinctrl.h>
256e9be3abSXianwei Zhao 
266e9be3abSXianwei Zhao #include "../core.h"
276e9be3abSXianwei Zhao #include "../pinconf.h"
286e9be3abSXianwei Zhao 
296e9be3abSXianwei Zhao #define gpio_chip_to_bank(chip) \
306e9be3abSXianwei Zhao 		container_of(chip, struct aml_gpio_bank, gpio_chip)
316e9be3abSXianwei Zhao 
326e9be3abSXianwei Zhao #define AML_REG_PULLEN		0
336e9be3abSXianwei Zhao #define AML_REG_PULL		1
346e9be3abSXianwei Zhao #define AML_REG_DIR		2
356e9be3abSXianwei Zhao #define AML_REG_OUT		3
366e9be3abSXianwei Zhao #define AML_REG_IN		4
376e9be3abSXianwei Zhao #define AML_REG_DS		5
386e9be3abSXianwei Zhao #define AML_NUM_REG		6
396e9be3abSXianwei Zhao 
406e9be3abSXianwei Zhao enum aml_pinconf_drv {
416e9be3abSXianwei Zhao 	PINCONF_DRV_500UA,
426e9be3abSXianwei Zhao 	PINCONF_DRV_2500UA,
436e9be3abSXianwei Zhao 	PINCONF_DRV_3000UA,
446e9be3abSXianwei Zhao 	PINCONF_DRV_4000UA,
456e9be3abSXianwei Zhao };
466e9be3abSXianwei Zhao 
476e9be3abSXianwei Zhao struct aml_pio_control {
486e9be3abSXianwei Zhao 	u32 gpio_offset;
496e9be3abSXianwei Zhao 	u32 reg_offset[AML_NUM_REG];
506e9be3abSXianwei Zhao 	u32 bit_offset[AML_NUM_REG];
516e9be3abSXianwei Zhao };
526e9be3abSXianwei Zhao 
536e9be3abSXianwei Zhao struct aml_reg_bit {
546e9be3abSXianwei Zhao 	u32 bank_id;
556e9be3abSXianwei Zhao 	u32 reg_offs[AML_NUM_REG];
566e9be3abSXianwei Zhao 	u32 bit_offs[AML_NUM_REG];
576e9be3abSXianwei Zhao };
586e9be3abSXianwei Zhao 
596e9be3abSXianwei Zhao struct aml_pctl_data {
606e9be3abSXianwei Zhao 	unsigned int number;
616e9be3abSXianwei Zhao 	struct aml_reg_bit rb_offs[];
626e9be3abSXianwei Zhao };
636e9be3abSXianwei Zhao 
646e9be3abSXianwei Zhao struct aml_pmx_func {
656e9be3abSXianwei Zhao 	const char	*name;
666e9be3abSXianwei Zhao 	const char	**groups;
676e9be3abSXianwei Zhao 	unsigned int	ngroups;
686e9be3abSXianwei Zhao };
696e9be3abSXianwei Zhao 
706e9be3abSXianwei Zhao struct aml_pctl_group {
716e9be3abSXianwei Zhao 	const char		*name;
726e9be3abSXianwei Zhao 	unsigned int		npins;
736e9be3abSXianwei Zhao 	unsigned int		*pins;
746e9be3abSXianwei Zhao 	unsigned int		*func;
756e9be3abSXianwei Zhao };
766e9be3abSXianwei Zhao 
776e9be3abSXianwei Zhao struct aml_gpio_bank {
786e9be3abSXianwei Zhao 	struct gpio_chip		gpio_chip;
796e9be3abSXianwei Zhao 	struct aml_pio_control		pc;
806e9be3abSXianwei Zhao 	u32				bank_id;
816e9be3abSXianwei Zhao 	unsigned int			pin_base;
826e9be3abSXianwei Zhao 	struct regmap			*reg_mux;
836e9be3abSXianwei Zhao 	struct regmap			*reg_gpio;
846e9be3abSXianwei Zhao 	struct regmap			*reg_ds;
856e9be3abSXianwei Zhao };
866e9be3abSXianwei Zhao 
876e9be3abSXianwei Zhao struct aml_pinctrl {
886e9be3abSXianwei Zhao 	struct device			*dev;
896e9be3abSXianwei Zhao 	struct pinctrl_dev		*pctl;
906e9be3abSXianwei Zhao 	struct aml_gpio_bank		*banks;
916e9be3abSXianwei Zhao 	int				nbanks;
926e9be3abSXianwei Zhao 	struct aml_pmx_func		*functions;
936e9be3abSXianwei Zhao 	int				nfunctions;
946e9be3abSXianwei Zhao 	struct aml_pctl_group		*groups;
956e9be3abSXianwei Zhao 	int				ngroups;
966e9be3abSXianwei Zhao 
976e9be3abSXianwei Zhao 	const struct aml_pctl_data	*data;
986e9be3abSXianwei Zhao };
996e9be3abSXianwei Zhao 
1006e9be3abSXianwei Zhao static const unsigned int aml_bit_strides[AML_NUM_REG] = {
1016e9be3abSXianwei Zhao 	1, 1, 1, 1, 1, 2
1026e9be3abSXianwei Zhao };
1036e9be3abSXianwei Zhao 
1046e9be3abSXianwei Zhao static const unsigned int aml_def_regoffs[AML_NUM_REG] = {
1056e9be3abSXianwei Zhao 	3, 4, 2, 1, 0, 7
1066e9be3abSXianwei Zhao };
1076e9be3abSXianwei Zhao 
1086e9be3abSXianwei Zhao static const char *aml_bank_name[31] = {
1096e9be3abSXianwei Zhao "GPIOA", "GPIOB", "GPIOC", "GPIOD", "GPIOE", "GPIOF", "GPIOG",
1106e9be3abSXianwei Zhao "GPIOH", "GPIOI", "GPIOJ", "GPIOK", "GPIOL", "GPIOM", "GPION",
1116e9be3abSXianwei Zhao "GPIOO", "GPIOP", "GPIOQ", "GPIOR", "GPIOS", "GPIOT", "GPIOU",
1126e9be3abSXianwei Zhao "GPIOV", "GPIOW", "GPIOX", "GPIOY", "GPIOZ", "GPIODV", "GPIOAO",
1136e9be3abSXianwei Zhao "GPIOCC", "TEST_N", "ANALOG"
1146e9be3abSXianwei Zhao };
1156e9be3abSXianwei Zhao 
aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range * range,unsigned int pin,unsigned int * reg,unsigned int * offset)1166e9be3abSXianwei Zhao static int aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range *range,
1176e9be3abSXianwei Zhao 				       unsigned int pin, unsigned int *reg,
1186e9be3abSXianwei Zhao 				       unsigned int *offset)
1196e9be3abSXianwei Zhao {
1206e9be3abSXianwei Zhao 	unsigned int shift;
1216e9be3abSXianwei Zhao 
1226e9be3abSXianwei Zhao 	shift = (pin - range->pin_base) << 2;
1236e9be3abSXianwei Zhao 	*reg = (shift / 32) * 4;
1246e9be3abSXianwei Zhao 	*offset = shift % 32;
1256e9be3abSXianwei Zhao 
1266e9be3abSXianwei Zhao 	return 0;
1276e9be3abSXianwei Zhao }
1286e9be3abSXianwei Zhao 
aml_pctl_set_function(struct aml_pinctrl * info,struct pinctrl_gpio_range * range,int pin_id,int func)1296e9be3abSXianwei Zhao static int aml_pctl_set_function(struct aml_pinctrl *info,
1306e9be3abSXianwei Zhao 				 struct pinctrl_gpio_range *range,
1316e9be3abSXianwei Zhao 				 int pin_id, int func)
1326e9be3abSXianwei Zhao {
1336e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
1346e9be3abSXianwei Zhao 	int reg;
1356e9be3abSXianwei Zhao 	int offset;
1366e9be3abSXianwei Zhao 
1376e9be3abSXianwei Zhao 	if (!bank->reg_mux)
1386e9be3abSXianwei Zhao 		return 0;
1396e9be3abSXianwei Zhao 
1406e9be3abSXianwei Zhao 	aml_pmx_calc_reg_and_offset(range, pin_id, &reg, &offset);
1416e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_mux, reg,
1426e9be3abSXianwei Zhao 			0xf << offset, (func & 0xf) << offset);
1436e9be3abSXianwei Zhao }
1446e9be3abSXianwei Zhao 
aml_pmx_get_funcs_count(struct pinctrl_dev * pctldev)1456e9be3abSXianwei Zhao static int aml_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
1466e9be3abSXianwei Zhao {
1476e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1486e9be3abSXianwei Zhao 
1496e9be3abSXianwei Zhao 	return info->nfunctions;
1506e9be3abSXianwei Zhao }
1516e9be3abSXianwei Zhao 
aml_pmx_get_fname(struct pinctrl_dev * pctldev,unsigned int selector)1526e9be3abSXianwei Zhao static const char *aml_pmx_get_fname(struct pinctrl_dev *pctldev,
1536e9be3abSXianwei Zhao 				     unsigned int selector)
1546e9be3abSXianwei Zhao {
1556e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1566e9be3abSXianwei Zhao 
1576e9be3abSXianwei Zhao 	return info->functions[selector].name;
1586e9be3abSXianwei Zhao }
1596e9be3abSXianwei Zhao 
aml_pmx_get_groups(struct pinctrl_dev * pctldev,unsigned int selector,const char * const ** grps,unsigned * const ngrps)1606e9be3abSXianwei Zhao static int aml_pmx_get_groups(struct pinctrl_dev *pctldev,
1616e9be3abSXianwei Zhao 			      unsigned int selector,
1626e9be3abSXianwei Zhao 			      const char * const **grps,
1636e9be3abSXianwei Zhao 			      unsigned * const ngrps)
1646e9be3abSXianwei Zhao {
1656e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1666e9be3abSXianwei Zhao 
1676e9be3abSXianwei Zhao 	*grps = info->functions[selector].groups;
1686e9be3abSXianwei Zhao 	*ngrps = info->functions[selector].ngroups;
1696e9be3abSXianwei Zhao 
1706e9be3abSXianwei Zhao 	return 0;
1716e9be3abSXianwei Zhao }
1726e9be3abSXianwei Zhao 
aml_pmx_set_mux(struct pinctrl_dev * pctldev,unsigned int fselector,unsigned int group_id)1736e9be3abSXianwei Zhao static int aml_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int fselector,
1746e9be3abSXianwei Zhao 			   unsigned int group_id)
1756e9be3abSXianwei Zhao {
1766e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1776e9be3abSXianwei Zhao 	struct aml_pctl_group *group = &info->groups[group_id];
1786e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range;
1796e9be3abSXianwei Zhao 	int i;
1806e9be3abSXianwei Zhao 
1816e9be3abSXianwei Zhao 	for (i = 0; i < group->npins; i++) {
1826e9be3abSXianwei Zhao 		range =  pinctrl_find_gpio_range_from_pin(pctldev, group->pins[i]);
1836e9be3abSXianwei Zhao 		aml_pctl_set_function(info, range, group->pins[i], group->func[i]);
1846e9be3abSXianwei Zhao 	}
1856e9be3abSXianwei Zhao 
1866e9be3abSXianwei Zhao 	return 0;
1876e9be3abSXianwei Zhao }
1886e9be3abSXianwei Zhao 
aml_pmx_request_gpio(struct pinctrl_dev * pctldev,struct pinctrl_gpio_range * range,unsigned int pin)1896e9be3abSXianwei Zhao static int aml_pmx_request_gpio(struct pinctrl_dev *pctldev,
1906e9be3abSXianwei Zhao 				struct pinctrl_gpio_range *range,
1916e9be3abSXianwei Zhao 				unsigned int pin)
1926e9be3abSXianwei Zhao {
1936e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1946e9be3abSXianwei Zhao 
1956e9be3abSXianwei Zhao 	return aml_pctl_set_function(info, range, pin, 0);
1966e9be3abSXianwei Zhao }
1976e9be3abSXianwei Zhao 
1986e9be3abSXianwei Zhao static const struct pinmux_ops aml_pmx_ops = {
1996e9be3abSXianwei Zhao 	.set_mux		= aml_pmx_set_mux,
2006e9be3abSXianwei Zhao 	.get_functions_count	= aml_pmx_get_funcs_count,
2016e9be3abSXianwei Zhao 	.get_function_name	= aml_pmx_get_fname,
2026e9be3abSXianwei Zhao 	.get_function_groups	= aml_pmx_get_groups,
2036e9be3abSXianwei Zhao 	.gpio_request_enable	= aml_pmx_request_gpio,
2046e9be3abSXianwei Zhao };
2056e9be3abSXianwei Zhao 
aml_calc_reg_and_bit(struct pinctrl_gpio_range * range,unsigned int pin,unsigned int reg_type,unsigned int * reg,unsigned int * bit)2066e9be3abSXianwei Zhao static int aml_calc_reg_and_bit(struct pinctrl_gpio_range *range,
2076e9be3abSXianwei Zhao 				unsigned int pin,
2086e9be3abSXianwei Zhao 				unsigned int reg_type,
2096e9be3abSXianwei Zhao 				unsigned int *reg, unsigned int *bit)
2106e9be3abSXianwei Zhao {
2116e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
2126e9be3abSXianwei Zhao 
2136e9be3abSXianwei Zhao 	*bit = (pin - range->pin_base) * aml_bit_strides[reg_type]
2146e9be3abSXianwei Zhao 		+ bank->pc.bit_offset[reg_type];
2156e9be3abSXianwei Zhao 	*reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4;
2166e9be3abSXianwei Zhao 	*bit &= 0x1f;
2176e9be3abSXianwei Zhao 
2186e9be3abSXianwei Zhao 	return 0;
2196e9be3abSXianwei Zhao }
2206e9be3abSXianwei Zhao 
aml_pinconf_get_pull(struct aml_pinctrl * info,unsigned int pin)2216e9be3abSXianwei Zhao static int aml_pinconf_get_pull(struct aml_pinctrl *info, unsigned int pin)
2226e9be3abSXianwei Zhao {
2236e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
2246e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
2256e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
2266e9be3abSXianwei Zhao 	unsigned int reg, bit, val;
2276e9be3abSXianwei Zhao 	int ret, conf;
2286e9be3abSXianwei Zhao 
2296e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, &reg, &bit);
2306e9be3abSXianwei Zhao 
2316e9be3abSXianwei Zhao 	ret = regmap_read(bank->reg_gpio, reg, &val);
2326e9be3abSXianwei Zhao 	if (ret)
2336e9be3abSXianwei Zhao 		return ret;
2346e9be3abSXianwei Zhao 
2356e9be3abSXianwei Zhao 	if (!(val & BIT(bit))) {
2366e9be3abSXianwei Zhao 		conf = PIN_CONFIG_BIAS_DISABLE;
2376e9be3abSXianwei Zhao 	} else {
2386e9be3abSXianwei Zhao 		aml_calc_reg_and_bit(range, pin, AML_REG_PULL, &reg, &bit);
2396e9be3abSXianwei Zhao 
2406e9be3abSXianwei Zhao 		ret = regmap_read(bank->reg_gpio, reg, &val);
2416e9be3abSXianwei Zhao 		if (ret)
2426e9be3abSXianwei Zhao 			return ret;
2436e9be3abSXianwei Zhao 
2446e9be3abSXianwei Zhao 		if (val & BIT(bit))
2456e9be3abSXianwei Zhao 			conf = PIN_CONFIG_BIAS_PULL_UP;
2466e9be3abSXianwei Zhao 		else
2476e9be3abSXianwei Zhao 			conf = PIN_CONFIG_BIAS_PULL_DOWN;
2486e9be3abSXianwei Zhao 	}
2496e9be3abSXianwei Zhao 
2506e9be3abSXianwei Zhao 	return conf;
2516e9be3abSXianwei Zhao }
2526e9be3abSXianwei Zhao 
aml_pinconf_get_drive_strength(struct aml_pinctrl * info,unsigned int pin,u16 * drive_strength_ua)2536e9be3abSXianwei Zhao static int aml_pinconf_get_drive_strength(struct aml_pinctrl *info,
2546e9be3abSXianwei Zhao 					  unsigned int pin,
2556e9be3abSXianwei Zhao 					  u16 *drive_strength_ua)
2566e9be3abSXianwei Zhao {
2576e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
2586e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
2596e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
2606e9be3abSXianwei Zhao 	unsigned int reg, bit;
2616e9be3abSXianwei Zhao 	unsigned int val;
2626e9be3abSXianwei Zhao 	int ret;
2636e9be3abSXianwei Zhao 
2646e9be3abSXianwei Zhao 	if (!bank->reg_ds)
2656e9be3abSXianwei Zhao 		return -EOPNOTSUPP;
2666e9be3abSXianwei Zhao 
2676e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_DS, &reg, &bit);
2686e9be3abSXianwei Zhao 	ret = regmap_read(bank->reg_ds, reg, &val);
2696e9be3abSXianwei Zhao 	if (ret)
2706e9be3abSXianwei Zhao 		return ret;
2716e9be3abSXianwei Zhao 
2726e9be3abSXianwei Zhao 	switch ((val >> bit) & 0x3) {
2736e9be3abSXianwei Zhao 	case PINCONF_DRV_500UA:
2746e9be3abSXianwei Zhao 		*drive_strength_ua = 500;
2756e9be3abSXianwei Zhao 		break;
2766e9be3abSXianwei Zhao 	case PINCONF_DRV_2500UA:
2776e9be3abSXianwei Zhao 		*drive_strength_ua = 2500;
2786e9be3abSXianwei Zhao 		break;
2796e9be3abSXianwei Zhao 	case PINCONF_DRV_3000UA:
2806e9be3abSXianwei Zhao 		*drive_strength_ua = 3000;
2816e9be3abSXianwei Zhao 		break;
2826e9be3abSXianwei Zhao 	case PINCONF_DRV_4000UA:
2836e9be3abSXianwei Zhao 		*drive_strength_ua = 4000;
2846e9be3abSXianwei Zhao 		break;
2856e9be3abSXianwei Zhao 	default:
2866e9be3abSXianwei Zhao 		return -EINVAL;
2876e9be3abSXianwei Zhao 	}
2886e9be3abSXianwei Zhao 
2896e9be3abSXianwei Zhao 	return 0;
2906e9be3abSXianwei Zhao }
2916e9be3abSXianwei Zhao 
aml_pinconf_get_gpio_bit(struct aml_pinctrl * info,unsigned int pin,unsigned int reg_type)2926e9be3abSXianwei Zhao static int aml_pinconf_get_gpio_bit(struct aml_pinctrl *info,
2936e9be3abSXianwei Zhao 				    unsigned int pin,
2946e9be3abSXianwei Zhao 				    unsigned int reg_type)
2956e9be3abSXianwei Zhao {
2966e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
2976e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
2986e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
2996e9be3abSXianwei Zhao 	unsigned int reg, bit, val;
3006e9be3abSXianwei Zhao 	int ret;
3016e9be3abSXianwei Zhao 
3026e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, reg_type, &reg, &bit);
3036e9be3abSXianwei Zhao 	ret = regmap_read(bank->reg_gpio, reg, &val);
3046e9be3abSXianwei Zhao 	if (ret)
3056e9be3abSXianwei Zhao 		return ret;
3066e9be3abSXianwei Zhao 
3076e9be3abSXianwei Zhao 	return BIT(bit) & val ? 1 : 0;
3086e9be3abSXianwei Zhao }
3096e9be3abSXianwei Zhao 
aml_pinconf_get_output(struct aml_pinctrl * info,unsigned int pin)3106e9be3abSXianwei Zhao static int aml_pinconf_get_output(struct aml_pinctrl *info,
3116e9be3abSXianwei Zhao 				  unsigned int pin)
3126e9be3abSXianwei Zhao {
3136e9be3abSXianwei Zhao 	int ret = aml_pinconf_get_gpio_bit(info, pin, AML_REG_DIR);
3146e9be3abSXianwei Zhao 
3156e9be3abSXianwei Zhao 	if (ret < 0)
3166e9be3abSXianwei Zhao 		return ret;
3176e9be3abSXianwei Zhao 
3186e9be3abSXianwei Zhao 	return !ret;
3196e9be3abSXianwei Zhao }
3206e9be3abSXianwei Zhao 
aml_pinconf_get_drive(struct aml_pinctrl * info,unsigned int pin)3216e9be3abSXianwei Zhao static int aml_pinconf_get_drive(struct aml_pinctrl *info,
3226e9be3abSXianwei Zhao 				 unsigned int pin)
3236e9be3abSXianwei Zhao {
3246e9be3abSXianwei Zhao 	return aml_pinconf_get_gpio_bit(info, pin, AML_REG_OUT);
3256e9be3abSXianwei Zhao }
3266e9be3abSXianwei Zhao 
aml_pinconf_get(struct pinctrl_dev * pcdev,unsigned int pin,unsigned long * config)3276e9be3abSXianwei Zhao static int aml_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
3286e9be3abSXianwei Zhao 			   unsigned long *config)
3296e9be3abSXianwei Zhao {
3306e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev);
3316e9be3abSXianwei Zhao 	enum pin_config_param param = pinconf_to_config_param(*config);
3326e9be3abSXianwei Zhao 	u16 arg;
3336e9be3abSXianwei Zhao 	int ret;
3346e9be3abSXianwei Zhao 
3356e9be3abSXianwei Zhao 	switch (param) {
3366e9be3abSXianwei Zhao 	case PIN_CONFIG_BIAS_DISABLE:
3376e9be3abSXianwei Zhao 	case PIN_CONFIG_BIAS_PULL_DOWN:
3386e9be3abSXianwei Zhao 	case PIN_CONFIG_BIAS_PULL_UP:
3396e9be3abSXianwei Zhao 		if (aml_pinconf_get_pull(info, pin) == param)
3406e9be3abSXianwei Zhao 			arg = 1;
3416e9be3abSXianwei Zhao 		else
3426e9be3abSXianwei Zhao 			return -EINVAL;
3436e9be3abSXianwei Zhao 		break;
3446e9be3abSXianwei Zhao 	case PIN_CONFIG_DRIVE_STRENGTH_UA:
3456e9be3abSXianwei Zhao 		ret = aml_pinconf_get_drive_strength(info, pin, &arg);
3466e9be3abSXianwei Zhao 		if (ret)
3476e9be3abSXianwei Zhao 			return ret;
3486e9be3abSXianwei Zhao 		break;
3496e9be3abSXianwei Zhao 	case PIN_CONFIG_OUTPUT_ENABLE:
3506e9be3abSXianwei Zhao 		ret = aml_pinconf_get_output(info, pin);
3516e9be3abSXianwei Zhao 		if (ret <= 0)
3526e9be3abSXianwei Zhao 			return -EINVAL;
3536e9be3abSXianwei Zhao 		arg = 1;
3546e9be3abSXianwei Zhao 		break;
3556e9be3abSXianwei Zhao 	case PIN_CONFIG_OUTPUT:
3566e9be3abSXianwei Zhao 		ret = aml_pinconf_get_output(info, pin);
3576e9be3abSXianwei Zhao 		if (ret <= 0)
3586e9be3abSXianwei Zhao 			return -EINVAL;
3596e9be3abSXianwei Zhao 
3606e9be3abSXianwei Zhao 		ret = aml_pinconf_get_drive(info, pin);
3616e9be3abSXianwei Zhao 		if (ret < 0)
3626e9be3abSXianwei Zhao 			return -EINVAL;
3636e9be3abSXianwei Zhao 
3646e9be3abSXianwei Zhao 		arg = ret;
3656e9be3abSXianwei Zhao 		break;
3666e9be3abSXianwei Zhao 
3676e9be3abSXianwei Zhao 	default:
3686e9be3abSXianwei Zhao 		return -ENOTSUPP;
3696e9be3abSXianwei Zhao 	}
3706e9be3abSXianwei Zhao 
3716e9be3abSXianwei Zhao 	*config = pinconf_to_config_packed(param, arg);
3726e9be3abSXianwei Zhao 	dev_dbg(info->dev, "pinconf for pin %u is %lu\n", pin, *config);
3736e9be3abSXianwei Zhao 
3746e9be3abSXianwei Zhao 	return 0;
3756e9be3abSXianwei Zhao }
3766e9be3abSXianwei Zhao 
aml_pinconf_disable_bias(struct aml_pinctrl * info,unsigned int pin)3776e9be3abSXianwei Zhao static int aml_pinconf_disable_bias(struct aml_pinctrl *info,
3786e9be3abSXianwei Zhao 				    unsigned int pin)
3796e9be3abSXianwei Zhao {
3806e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
3816e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
3826e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
3836e9be3abSXianwei Zhao 	unsigned int reg, bit = 0;
3846e9be3abSXianwei Zhao 
3856e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, &reg, &bit);
3866e9be3abSXianwei Zhao 
3876e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0);
3886e9be3abSXianwei Zhao }
3896e9be3abSXianwei Zhao 
aml_pinconf_enable_bias(struct aml_pinctrl * info,unsigned int pin,bool pull_up)3906e9be3abSXianwei Zhao static int aml_pinconf_enable_bias(struct aml_pinctrl *info, unsigned int pin,
3916e9be3abSXianwei Zhao 				   bool pull_up)
3926e9be3abSXianwei Zhao {
3936e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
3946e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
3956e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
3966e9be3abSXianwei Zhao 	unsigned int reg, bit, val = 0;
3976e9be3abSXianwei Zhao 	int ret;
3986e9be3abSXianwei Zhao 
3996e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_PULL, &reg, &bit);
4006e9be3abSXianwei Zhao 	if (pull_up)
4016e9be3abSXianwei Zhao 		val = BIT(bit);
4026e9be3abSXianwei Zhao 
4036e9be3abSXianwei Zhao 	ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), val);
4046e9be3abSXianwei Zhao 	if (ret)
4056e9be3abSXianwei Zhao 		return ret;
4066e9be3abSXianwei Zhao 
4076e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_PULLEN, &reg, &bit);
4086e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit));
4096e9be3abSXianwei Zhao }
4106e9be3abSXianwei Zhao 
aml_pinconf_set_drive_strength(struct aml_pinctrl * info,unsigned int pin,u16 drive_strength_ua)4116e9be3abSXianwei Zhao static int aml_pinconf_set_drive_strength(struct aml_pinctrl *info,
4126e9be3abSXianwei Zhao 					  unsigned int pin,
4136e9be3abSXianwei Zhao 					  u16 drive_strength_ua)
4146e9be3abSXianwei Zhao {
4156e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
4166e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
4176e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
4186e9be3abSXianwei Zhao 	unsigned int reg, bit, ds_val;
4196e9be3abSXianwei Zhao 
4206e9be3abSXianwei Zhao 	if (!bank->reg_ds) {
4216e9be3abSXianwei Zhao 		dev_err(info->dev, "drive-strength not supported\n");
4226e9be3abSXianwei Zhao 		return -EOPNOTSUPP;
4236e9be3abSXianwei Zhao 	}
4246e9be3abSXianwei Zhao 
4256e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, AML_REG_DS, &reg, &bit);
4266e9be3abSXianwei Zhao 
4276e9be3abSXianwei Zhao 	if (drive_strength_ua <= 500) {
4286e9be3abSXianwei Zhao 		ds_val = PINCONF_DRV_500UA;
4296e9be3abSXianwei Zhao 	} else if (drive_strength_ua <= 2500) {
4306e9be3abSXianwei Zhao 		ds_val = PINCONF_DRV_2500UA;
4316e9be3abSXianwei Zhao 	} else if (drive_strength_ua <= 3000) {
4326e9be3abSXianwei Zhao 		ds_val = PINCONF_DRV_3000UA;
4336e9be3abSXianwei Zhao 	} else if (drive_strength_ua <= 4000) {
4346e9be3abSXianwei Zhao 		ds_val = PINCONF_DRV_4000UA;
4356e9be3abSXianwei Zhao 	} else {
4366e9be3abSXianwei Zhao 		dev_warn_once(info->dev,
4376e9be3abSXianwei Zhao 			      "pin %u: invalid drive-strength : %d , default to 4mA\n",
4386e9be3abSXianwei Zhao 			      pin, drive_strength_ua);
4396e9be3abSXianwei Zhao 		ds_val = PINCONF_DRV_4000UA;
4406e9be3abSXianwei Zhao 	}
4416e9be3abSXianwei Zhao 
4426e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_ds, reg, 0x3 << bit, ds_val << bit);
4436e9be3abSXianwei Zhao }
4446e9be3abSXianwei Zhao 
aml_pinconf_set_gpio_bit(struct aml_pinctrl * info,unsigned int pin,unsigned int reg_type,bool arg)4456e9be3abSXianwei Zhao static int aml_pinconf_set_gpio_bit(struct aml_pinctrl *info,
4466e9be3abSXianwei Zhao 				    unsigned int pin,
4476e9be3abSXianwei Zhao 				    unsigned int reg_type,
4486e9be3abSXianwei Zhao 				    bool arg)
4496e9be3abSXianwei Zhao {
4506e9be3abSXianwei Zhao 	struct pinctrl_gpio_range *range =
4516e9be3abSXianwei Zhao 			 pinctrl_find_gpio_range_from_pin(info->pctl, pin);
4526e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
4536e9be3abSXianwei Zhao 	unsigned int reg, bit;
4546e9be3abSXianwei Zhao 
4556e9be3abSXianwei Zhao 	aml_calc_reg_and_bit(range, pin, reg_type, &reg, &bit);
4566e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit),
4576e9be3abSXianwei Zhao 				  arg ? BIT(bit) : 0);
4586e9be3abSXianwei Zhao }
4596e9be3abSXianwei Zhao 
aml_pinconf_set_output(struct aml_pinctrl * info,unsigned int pin,bool out)4606e9be3abSXianwei Zhao static int aml_pinconf_set_output(struct aml_pinctrl *info,
4616e9be3abSXianwei Zhao 				  unsigned int pin,
4626e9be3abSXianwei Zhao 				  bool out)
4636e9be3abSXianwei Zhao {
4646e9be3abSXianwei Zhao 	return aml_pinconf_set_gpio_bit(info, pin, AML_REG_DIR, !out);
4656e9be3abSXianwei Zhao }
4666e9be3abSXianwei Zhao 
aml_pinconf_set_drive(struct aml_pinctrl * info,unsigned int pin,bool high)4676e9be3abSXianwei Zhao static int aml_pinconf_set_drive(struct aml_pinctrl *info,
4686e9be3abSXianwei Zhao 				 unsigned int pin,
4696e9be3abSXianwei Zhao 				 bool high)
4706e9be3abSXianwei Zhao {
4716e9be3abSXianwei Zhao 	return aml_pinconf_set_gpio_bit(info, pin, AML_REG_OUT, high);
4726e9be3abSXianwei Zhao }
4736e9be3abSXianwei Zhao 
aml_pinconf_set_output_drive(struct aml_pinctrl * info,unsigned int pin,bool high)4746e9be3abSXianwei Zhao static int aml_pinconf_set_output_drive(struct aml_pinctrl *info,
4756e9be3abSXianwei Zhao 					unsigned int pin,
4766e9be3abSXianwei Zhao 					bool high)
4776e9be3abSXianwei Zhao {
4786e9be3abSXianwei Zhao 	int ret;
4796e9be3abSXianwei Zhao 
4806e9be3abSXianwei Zhao 	ret = aml_pinconf_set_output(info, pin, true);
4816e9be3abSXianwei Zhao 	if (ret)
4826e9be3abSXianwei Zhao 		return ret;
4836e9be3abSXianwei Zhao 
4846e9be3abSXianwei Zhao 	return aml_pinconf_set_drive(info, pin, high);
4856e9be3abSXianwei Zhao }
4866e9be3abSXianwei Zhao 
aml_pinconf_set(struct pinctrl_dev * pcdev,unsigned int pin,unsigned long * configs,unsigned int num_configs)4876e9be3abSXianwei Zhao static int aml_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
4886e9be3abSXianwei Zhao 			   unsigned long *configs, unsigned int num_configs)
4896e9be3abSXianwei Zhao {
4906e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev);
4916e9be3abSXianwei Zhao 	enum pin_config_param param;
4926e9be3abSXianwei Zhao 	unsigned int arg = 0;
4936e9be3abSXianwei Zhao 	int i, ret;
4946e9be3abSXianwei Zhao 
4956e9be3abSXianwei Zhao 	for (i = 0; i < num_configs; i++) {
4966e9be3abSXianwei Zhao 		param = pinconf_to_config_param(configs[i]);
4976e9be3abSXianwei Zhao 
4986e9be3abSXianwei Zhao 		switch (param) {
4996e9be3abSXianwei Zhao 		case PIN_CONFIG_DRIVE_STRENGTH_UA:
5006e9be3abSXianwei Zhao 		case PIN_CONFIG_OUTPUT_ENABLE:
5016e9be3abSXianwei Zhao 		case PIN_CONFIG_OUTPUT:
5026e9be3abSXianwei Zhao 			arg = pinconf_to_config_argument(configs[i]);
5036e9be3abSXianwei Zhao 			break;
5046e9be3abSXianwei Zhao 
5056e9be3abSXianwei Zhao 		default:
5066e9be3abSXianwei Zhao 			break;
5076e9be3abSXianwei Zhao 		}
5086e9be3abSXianwei Zhao 
5096e9be3abSXianwei Zhao 		switch (param) {
5106e9be3abSXianwei Zhao 		case PIN_CONFIG_BIAS_DISABLE:
5116e9be3abSXianwei Zhao 			ret = aml_pinconf_disable_bias(info, pin);
5126e9be3abSXianwei Zhao 			break;
5136e9be3abSXianwei Zhao 		case PIN_CONFIG_BIAS_PULL_UP:
5146e9be3abSXianwei Zhao 			ret = aml_pinconf_enable_bias(info, pin, true);
5156e9be3abSXianwei Zhao 			break;
5166e9be3abSXianwei Zhao 		case PIN_CONFIG_BIAS_PULL_DOWN:
5176e9be3abSXianwei Zhao 			ret = aml_pinconf_enable_bias(info, pin, false);
5186e9be3abSXianwei Zhao 			break;
5196e9be3abSXianwei Zhao 		case PIN_CONFIG_DRIVE_STRENGTH_UA:
5206e9be3abSXianwei Zhao 			ret = aml_pinconf_set_drive_strength(info, pin, arg);
5216e9be3abSXianwei Zhao 			break;
5226e9be3abSXianwei Zhao 		case PIN_CONFIG_OUTPUT_ENABLE:
5236e9be3abSXianwei Zhao 			ret = aml_pinconf_set_output(info, pin, arg);
5246e9be3abSXianwei Zhao 			break;
5256e9be3abSXianwei Zhao 		case PIN_CONFIG_OUTPUT:
5266e9be3abSXianwei Zhao 			ret = aml_pinconf_set_output_drive(info, pin, arg);
5276e9be3abSXianwei Zhao 			break;
5286e9be3abSXianwei Zhao 		default:
5296e9be3abSXianwei Zhao 			ret = -ENOTSUPP;
5306e9be3abSXianwei Zhao 		}
5316e9be3abSXianwei Zhao 
5326e9be3abSXianwei Zhao 		if (ret)
5336e9be3abSXianwei Zhao 			return ret;
5346e9be3abSXianwei Zhao 	}
5356e9be3abSXianwei Zhao 
5366e9be3abSXianwei Zhao 	return 0;
5376e9be3abSXianwei Zhao }
5386e9be3abSXianwei Zhao 
aml_pinconf_group_set(struct pinctrl_dev * pcdev,unsigned int num_group,unsigned long * configs,unsigned int num_configs)5396e9be3abSXianwei Zhao static int aml_pinconf_group_set(struct pinctrl_dev *pcdev,
5406e9be3abSXianwei Zhao 				 unsigned int num_group,
5416e9be3abSXianwei Zhao 				 unsigned long *configs,
5426e9be3abSXianwei Zhao 				 unsigned int num_configs)
5436e9be3abSXianwei Zhao {
5446e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pcdev);
5456e9be3abSXianwei Zhao 	int i;
5466e9be3abSXianwei Zhao 
5476e9be3abSXianwei Zhao 	for (i = 0; i < info->groups[num_group].npins; i++) {
5486e9be3abSXianwei Zhao 		aml_pinconf_set(pcdev, info->groups[num_group].pins[i], configs,
5496e9be3abSXianwei Zhao 				num_configs);
5506e9be3abSXianwei Zhao 	}
5516e9be3abSXianwei Zhao 
5526e9be3abSXianwei Zhao 	return 0;
5536e9be3abSXianwei Zhao }
5546e9be3abSXianwei Zhao 
aml_pinconf_group_get(struct pinctrl_dev * pcdev,unsigned int group,unsigned long * config)5556e9be3abSXianwei Zhao static int aml_pinconf_group_get(struct pinctrl_dev *pcdev,
5566e9be3abSXianwei Zhao 				 unsigned int group, unsigned long *config)
5576e9be3abSXianwei Zhao {
5586e9be3abSXianwei Zhao 	return -EOPNOTSUPP;
5596e9be3abSXianwei Zhao }
5606e9be3abSXianwei Zhao 
5616e9be3abSXianwei Zhao static const struct pinconf_ops aml_pinconf_ops = {
5626e9be3abSXianwei Zhao 	.pin_config_get		= aml_pinconf_get,
5636e9be3abSXianwei Zhao 	.pin_config_set		= aml_pinconf_set,
5646e9be3abSXianwei Zhao 	.pin_config_group_get	= aml_pinconf_group_get,
5656e9be3abSXianwei Zhao 	.pin_config_group_set	= aml_pinconf_group_set,
5666e9be3abSXianwei Zhao 	.is_generic		= true,
5676e9be3abSXianwei Zhao };
5686e9be3abSXianwei Zhao 
aml_get_groups_count(struct pinctrl_dev * pctldev)5696e9be3abSXianwei Zhao static int aml_get_groups_count(struct pinctrl_dev *pctldev)
5706e9be3abSXianwei Zhao {
5716e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
5726e9be3abSXianwei Zhao 
5736e9be3abSXianwei Zhao 	return info->ngroups;
5746e9be3abSXianwei Zhao }
5756e9be3abSXianwei Zhao 
aml_get_group_name(struct pinctrl_dev * pctldev,unsigned int selector)5766e9be3abSXianwei Zhao static const char *aml_get_group_name(struct pinctrl_dev *pctldev,
5776e9be3abSXianwei Zhao 				      unsigned int selector)
5786e9be3abSXianwei Zhao {
5796e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
5806e9be3abSXianwei Zhao 
5816e9be3abSXianwei Zhao 	return info->groups[selector].name;
5826e9be3abSXianwei Zhao }
5836e9be3abSXianwei Zhao 
aml_get_group_pins(struct pinctrl_dev * pctldev,unsigned int selector,const unsigned int ** pins,unsigned int * npins)5846e9be3abSXianwei Zhao static int aml_get_group_pins(struct pinctrl_dev *pctldev,
5856e9be3abSXianwei Zhao 			      unsigned int selector, const unsigned int **pins,
5866e9be3abSXianwei Zhao 			      unsigned int *npins)
5876e9be3abSXianwei Zhao {
5886e9be3abSXianwei Zhao 	struct aml_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
5896e9be3abSXianwei Zhao 
5906e9be3abSXianwei Zhao 	if (selector >= info->ngroups)
5916e9be3abSXianwei Zhao 		return -EINVAL;
5926e9be3abSXianwei Zhao 
5936e9be3abSXianwei Zhao 	*pins = info->groups[selector].pins;
5946e9be3abSXianwei Zhao 	*npins = info->groups[selector].npins;
5956e9be3abSXianwei Zhao 
5966e9be3abSXianwei Zhao 	return 0;
5976e9be3abSXianwei Zhao }
5986e9be3abSXianwei Zhao 
aml_pin_dbg_show(struct pinctrl_dev * pcdev,struct seq_file * s,unsigned int offset)5996e9be3abSXianwei Zhao static void aml_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s,
6006e9be3abSXianwei Zhao 			     unsigned int offset)
6016e9be3abSXianwei Zhao {
6026e9be3abSXianwei Zhao 	seq_printf(s, " %s", dev_name(pcdev->dev));
6036e9be3abSXianwei Zhao }
6046e9be3abSXianwei Zhao 
6056e9be3abSXianwei Zhao static const struct pinctrl_ops aml_pctrl_ops = {
6066e9be3abSXianwei Zhao 	.get_groups_count	= aml_get_groups_count,
6076e9be3abSXianwei Zhao 	.get_group_name		= aml_get_group_name,
6086e9be3abSXianwei Zhao 	.get_group_pins		= aml_get_group_pins,
6096e9be3abSXianwei Zhao 	.dt_node_to_map		= pinconf_generic_dt_node_to_map_pinmux,
6106e9be3abSXianwei Zhao 	.dt_free_map		= pinconf_generic_dt_free_map,
6116e9be3abSXianwei Zhao 	.pin_dbg_show		= aml_pin_dbg_show,
6126e9be3abSXianwei Zhao };
6136e9be3abSXianwei Zhao 
aml_pctl_parse_functions(struct device_node * np,struct aml_pinctrl * info,u32 index,int * grp_index)6146e9be3abSXianwei Zhao static int aml_pctl_parse_functions(struct device_node *np,
6156e9be3abSXianwei Zhao 				    struct aml_pinctrl *info, u32 index,
6166e9be3abSXianwei Zhao 				    int *grp_index)
6176e9be3abSXianwei Zhao {
6186e9be3abSXianwei Zhao 	struct device *dev = info->dev;
6196e9be3abSXianwei Zhao 	struct aml_pmx_func *func;
6206e9be3abSXianwei Zhao 	struct aml_pctl_group *grp;
6216e9be3abSXianwei Zhao 	int ret, i;
6226e9be3abSXianwei Zhao 
6236e9be3abSXianwei Zhao 	func = &info->functions[index];
6246e9be3abSXianwei Zhao 	func->name = np->name;
6256e9be3abSXianwei Zhao 	func->ngroups = of_get_child_count(np);
6266e9be3abSXianwei Zhao 	if (func->ngroups == 0)
6276e9be3abSXianwei Zhao 		return dev_err_probe(dev, -EINVAL, "No groups defined\n");
6286e9be3abSXianwei Zhao 
6296e9be3abSXianwei Zhao 	func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL);
6306e9be3abSXianwei Zhao 	if (!func->groups)
6316e9be3abSXianwei Zhao 		return -ENOMEM;
6326e9be3abSXianwei Zhao 
6336e9be3abSXianwei Zhao 	i = 0;
6346e9be3abSXianwei Zhao 	for_each_child_of_node_scoped(np, child) {
6356e9be3abSXianwei Zhao 		func->groups[i++] = child->name;
6366e9be3abSXianwei Zhao 		grp = &info->groups[*grp_index];
6376e9be3abSXianwei Zhao 		grp->name = child->name;
6386e9be3abSXianwei Zhao 		*grp_index += 1;
6396e9be3abSXianwei Zhao 		ret = pinconf_generic_parse_dt_pinmux(child, dev, &grp->pins,
6406e9be3abSXianwei Zhao 						      &grp->func, &grp->npins);
6416e9be3abSXianwei Zhao 		if (ret) {
6426e9be3abSXianwei Zhao 			dev_err(dev, "function :%s, groups:%s fail\n", func->name, child->name);
6436e9be3abSXianwei Zhao 			return ret;
6446e9be3abSXianwei Zhao 		}
6456e9be3abSXianwei Zhao 	}
6466e9be3abSXianwei Zhao 	dev_dbg(dev, "Function[%d\t name:%s,\tgroups:%d]\n", index, func->name, func->ngroups);
6476e9be3abSXianwei Zhao 
6486e9be3abSXianwei Zhao 	return 0;
6496e9be3abSXianwei Zhao }
6506e9be3abSXianwei Zhao 
aml_bank_pins(struct device_node * np)6516e9be3abSXianwei Zhao static u32 aml_bank_pins(struct device_node *np)
6526e9be3abSXianwei Zhao {
6536e9be3abSXianwei Zhao 	struct of_phandle_args of_args;
6546e9be3abSXianwei Zhao 
6556e9be3abSXianwei Zhao 	if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
6566e9be3abSXianwei Zhao 					     0, &of_args))
6576e9be3abSXianwei Zhao 		return 0;
6586e9be3abSXianwei Zhao 	else
6596e9be3abSXianwei Zhao 		return of_args.args[2];
6606e9be3abSXianwei Zhao }
6616e9be3abSXianwei Zhao 
aml_bank_number(struct device_node * np)6626e9be3abSXianwei Zhao static int aml_bank_number(struct device_node *np)
6636e9be3abSXianwei Zhao {
6646e9be3abSXianwei Zhao 	struct of_phandle_args of_args;
6656e9be3abSXianwei Zhao 
6666e9be3abSXianwei Zhao 	if (of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
6676e9be3abSXianwei Zhao 					     0, &of_args))
6686e9be3abSXianwei Zhao 		return -EINVAL;
6696e9be3abSXianwei Zhao 	else
6706e9be3abSXianwei Zhao 		return of_args.args[1] >> 8;
6716e9be3abSXianwei Zhao }
6726e9be3abSXianwei Zhao 
aml_count_pins(struct device_node * np)6736e9be3abSXianwei Zhao static unsigned int aml_count_pins(struct device_node *np)
6746e9be3abSXianwei Zhao {
6756e9be3abSXianwei Zhao 	struct device_node *child;
6766e9be3abSXianwei Zhao 	unsigned int pins = 0;
6776e9be3abSXianwei Zhao 
6786e9be3abSXianwei Zhao 	for_each_child_of_node(np, child) {
6796e9be3abSXianwei Zhao 		if (of_property_read_bool(child, "gpio-controller"))
6806e9be3abSXianwei Zhao 			pins += aml_bank_pins(child);
6816e9be3abSXianwei Zhao 	}
6826e9be3abSXianwei Zhao 
6836e9be3abSXianwei Zhao 	return pins;
6846e9be3abSXianwei Zhao }
6856e9be3abSXianwei Zhao 
6866e9be3abSXianwei Zhao /*
6876e9be3abSXianwei Zhao  * A pinctrl device contains two types of nodes. The one named GPIO
6886e9be3abSXianwei Zhao  * bank which includes gpio-controller property. The other one named
6896e9be3abSXianwei Zhao  * function which includes one or more pin groups. The pin group
6906e9be3abSXianwei Zhao  * include pinmux property(global index in pinctrl dev, and mux vlaue
6916e9be3abSXianwei Zhao  * in mux reg) and pin configuration properties.
6926e9be3abSXianwei Zhao  */
aml_pctl_dt_child_count(struct aml_pinctrl * info,struct device_node * np)6936e9be3abSXianwei Zhao static void aml_pctl_dt_child_count(struct aml_pinctrl *info,
6946e9be3abSXianwei Zhao 				    struct device_node *np)
6956e9be3abSXianwei Zhao {
6966e9be3abSXianwei Zhao 	struct device_node *child;
6976e9be3abSXianwei Zhao 
6986e9be3abSXianwei Zhao 	for_each_child_of_node(np, child) {
6996e9be3abSXianwei Zhao 		if (of_property_read_bool(child, "gpio-controller")) {
7006e9be3abSXianwei Zhao 			info->nbanks++;
7016e9be3abSXianwei Zhao 		} else {
7026e9be3abSXianwei Zhao 			info->nfunctions++;
7036e9be3abSXianwei Zhao 			info->ngroups += of_get_child_count(child);
7046e9be3abSXianwei Zhao 		}
7056e9be3abSXianwei Zhao 	}
7066e9be3abSXianwei Zhao }
7076e9be3abSXianwei Zhao 
aml_map_resource(struct device * dev,unsigned int id,struct device_node * node,char * name)7086e9be3abSXianwei Zhao static struct regmap *aml_map_resource(struct device *dev, unsigned int id,
7096e9be3abSXianwei Zhao 				       struct device_node *node, char *name)
7106e9be3abSXianwei Zhao {
7116e9be3abSXianwei Zhao 	struct resource res;
7126e9be3abSXianwei Zhao 	void __iomem *base;
7136e9be3abSXianwei Zhao 	int i;
7146e9be3abSXianwei Zhao 
7156e9be3abSXianwei Zhao 	struct regmap_config aml_regmap_config = {
7166e9be3abSXianwei Zhao 		.reg_bits = 32,
7176e9be3abSXianwei Zhao 		.val_bits = 32,
7186e9be3abSXianwei Zhao 		.reg_stride = 4,
7196e9be3abSXianwei Zhao 	};
7206e9be3abSXianwei Zhao 
7216e9be3abSXianwei Zhao 	i = of_property_match_string(node, "reg-names", name);
7226e9be3abSXianwei Zhao 	if (i < 0)
7236e9be3abSXianwei Zhao 		return NULL;
7246e9be3abSXianwei Zhao 	if (of_address_to_resource(node, i, &res))
7256e9be3abSXianwei Zhao 		return NULL;
7266e9be3abSXianwei Zhao 	base = devm_ioremap_resource(dev, &res);
7276e9be3abSXianwei Zhao 	if (IS_ERR(base))
7286e9be3abSXianwei Zhao 		return ERR_CAST(base);
7296e9be3abSXianwei Zhao 
7306e9be3abSXianwei Zhao 	aml_regmap_config.max_register = resource_size(&res) - 4;
7316e9be3abSXianwei Zhao 	aml_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL,
7326e9be3abSXianwei Zhao 						"%s-%s", aml_bank_name[id], name);
7336e9be3abSXianwei Zhao 	if (!aml_regmap_config.name)
7346e9be3abSXianwei Zhao 		return ERR_PTR(-ENOMEM);
7356e9be3abSXianwei Zhao 
7366e9be3abSXianwei Zhao 	return devm_regmap_init_mmio(dev, base, &aml_regmap_config);
7376e9be3abSXianwei Zhao }
7386e9be3abSXianwei Zhao 
aml_gpio_calc_reg_and_bit(struct aml_gpio_bank * bank,unsigned int reg_type,unsigned int gpio,unsigned int * reg,unsigned int * bit)7396e9be3abSXianwei Zhao static inline int aml_gpio_calc_reg_and_bit(struct aml_gpio_bank *bank,
7406e9be3abSXianwei Zhao 					    unsigned int reg_type,
7416e9be3abSXianwei Zhao 					    unsigned int gpio,
7426e9be3abSXianwei Zhao 					    unsigned int *reg,
7436e9be3abSXianwei Zhao 					    unsigned int *bit)
7446e9be3abSXianwei Zhao {
7456e9be3abSXianwei Zhao 	*bit = gpio * aml_bit_strides[reg_type] + bank->pc.bit_offset[reg_type];
7466e9be3abSXianwei Zhao 	*reg = (bank->pc.reg_offset[reg_type] + (*bit / 32)) * 4;
7476e9be3abSXianwei Zhao 	*bit &= 0x1f;
7486e9be3abSXianwei Zhao 
7496e9be3abSXianwei Zhao 	return 0;
7506e9be3abSXianwei Zhao }
7516e9be3abSXianwei Zhao 
aml_gpio_get_direction(struct gpio_chip * chip,unsigned int gpio)7526e9be3abSXianwei Zhao static int aml_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
7536e9be3abSXianwei Zhao {
7546e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpiochip_get_data(chip);
7556e9be3abSXianwei Zhao 	unsigned int bit, reg, val;
7566e9be3abSXianwei Zhao 	int ret;
7576e9be3abSXianwei Zhao 
7586e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, &reg, &bit);
7596e9be3abSXianwei Zhao 
7606e9be3abSXianwei Zhao 	ret = regmap_read(bank->reg_gpio, reg, &val);
7616e9be3abSXianwei Zhao 	if (ret)
7626e9be3abSXianwei Zhao 		return ret;
7636e9be3abSXianwei Zhao 
764c3a0b61eSXianwei Zhao 	return BIT(bit) & val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
7656e9be3abSXianwei Zhao }
7666e9be3abSXianwei Zhao 
aml_gpio_direction_input(struct gpio_chip * chip,unsigned int gpio)7676e9be3abSXianwei Zhao static int aml_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
7686e9be3abSXianwei Zhao {
7696e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpiochip_get_data(chip);
7706e9be3abSXianwei Zhao 	unsigned int bit, reg;
7716e9be3abSXianwei Zhao 
7726e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, &reg, &bit);
7736e9be3abSXianwei Zhao 
774c3a0b61eSXianwei Zhao 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit), BIT(bit));
7756e9be3abSXianwei Zhao }
7766e9be3abSXianwei Zhao 
aml_gpio_direction_output(struct gpio_chip * chip,unsigned int gpio,int value)7776e9be3abSXianwei Zhao static int aml_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
7786e9be3abSXianwei Zhao 				     int value)
7796e9be3abSXianwei Zhao {
7806e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpiochip_get_data(chip);
7816e9be3abSXianwei Zhao 	unsigned int bit, reg;
7826e9be3abSXianwei Zhao 	int ret;
7836e9be3abSXianwei Zhao 
7846e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_DIR, gpio, &reg, &bit);
785c3a0b61eSXianwei Zhao 	ret = regmap_update_bits(bank->reg_gpio, reg, BIT(bit), 0);
7866e9be3abSXianwei Zhao 	if (ret < 0)
7876e9be3abSXianwei Zhao 		return ret;
7886e9be3abSXianwei Zhao 
7896e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, &reg, &bit);
7906e9be3abSXianwei Zhao 
7916e9be3abSXianwei Zhao 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit),
7926e9be3abSXianwei Zhao 				  value ? BIT(bit) : 0);
7936e9be3abSXianwei Zhao }
7946e9be3abSXianwei Zhao 
aml_gpio_set(struct gpio_chip * chip,unsigned int gpio,int value)795*e1d2a8ecSBartosz Golaszewski static int aml_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
7966e9be3abSXianwei Zhao {
7976e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpiochip_get_data(chip);
7986e9be3abSXianwei Zhao 	unsigned int bit, reg;
7996e9be3abSXianwei Zhao 
8006e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_OUT, gpio, &reg, &bit);
8016e9be3abSXianwei Zhao 
802*e1d2a8ecSBartosz Golaszewski 	return regmap_update_bits(bank->reg_gpio, reg, BIT(bit),
8036e9be3abSXianwei Zhao 				  value ? BIT(bit) : 0);
8046e9be3abSXianwei Zhao }
8056e9be3abSXianwei Zhao 
aml_gpio_get(struct gpio_chip * chip,unsigned int gpio)8066e9be3abSXianwei Zhao static int aml_gpio_get(struct gpio_chip *chip, unsigned int gpio)
8076e9be3abSXianwei Zhao {
8086e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = gpiochip_get_data(chip);
8096e9be3abSXianwei Zhao 	unsigned int reg, bit, val;
8106e9be3abSXianwei Zhao 
8116e9be3abSXianwei Zhao 	aml_gpio_calc_reg_and_bit(bank, AML_REG_IN, gpio, &reg, &bit);
8126e9be3abSXianwei Zhao 	regmap_read(bank->reg_gpio, reg, &val);
8136e9be3abSXianwei Zhao 
8146e9be3abSXianwei Zhao 	return !!(val & BIT(bit));
8156e9be3abSXianwei Zhao }
8166e9be3abSXianwei Zhao 
8176e9be3abSXianwei Zhao static const struct gpio_chip aml_gpio_template = {
8186e9be3abSXianwei Zhao 	.request		= gpiochip_generic_request,
8196e9be3abSXianwei Zhao 	.free			= gpiochip_generic_free,
8206e9be3abSXianwei Zhao 	.set_config		= gpiochip_generic_config,
821*e1d2a8ecSBartosz Golaszewski 	.set_rv			= aml_gpio_set,
8226e9be3abSXianwei Zhao 	.get			= aml_gpio_get,
8236e9be3abSXianwei Zhao 	.direction_input	= aml_gpio_direction_input,
8246e9be3abSXianwei Zhao 	.direction_output	= aml_gpio_direction_output,
8256e9be3abSXianwei Zhao 	.get_direction		= aml_gpio_get_direction,
8266e9be3abSXianwei Zhao 	.can_sleep		= false,
8276e9be3abSXianwei Zhao };
8286e9be3abSXianwei Zhao 
init_bank_register_bit(struct aml_pinctrl * info,struct aml_gpio_bank * bank)8296e9be3abSXianwei Zhao static void init_bank_register_bit(struct aml_pinctrl *info,
8306e9be3abSXianwei Zhao 				   struct aml_gpio_bank *bank)
8316e9be3abSXianwei Zhao {
8326e9be3abSXianwei Zhao 	const struct aml_pctl_data *data = info->data;
8336e9be3abSXianwei Zhao 	const struct aml_reg_bit *aml_rb;
8346e9be3abSXianwei Zhao 	bool def_offs = true;
8356e9be3abSXianwei Zhao 	int i;
8366e9be3abSXianwei Zhao 
8376e9be3abSXianwei Zhao 	if (data) {
8386e9be3abSXianwei Zhao 		for (i = 0; i < data->number; i++) {
8396e9be3abSXianwei Zhao 			aml_rb = &data->rb_offs[i];
8406e9be3abSXianwei Zhao 			if (bank->bank_id == aml_rb->bank_id) {
8416e9be3abSXianwei Zhao 				def_offs = false;
8426e9be3abSXianwei Zhao 				break;
8436e9be3abSXianwei Zhao 			}
8446e9be3abSXianwei Zhao 		}
8455df0211aSLinus Walleij 	}
8466e9be3abSXianwei Zhao 
8476e9be3abSXianwei Zhao 	if (def_offs) {
8486e9be3abSXianwei Zhao 		for (i = 0; i < AML_NUM_REG; i++) {
8496e9be3abSXianwei Zhao 			bank->pc.reg_offset[i] = aml_def_regoffs[i];
8506e9be3abSXianwei Zhao 			bank->pc.bit_offset[i] = 0;
8516e9be3abSXianwei Zhao 		}
8526e9be3abSXianwei Zhao 	} else {
8536e9be3abSXianwei Zhao 		for (i = 0; i < AML_NUM_REG; i++) {
8546e9be3abSXianwei Zhao 			bank->pc.reg_offset[i] = aml_rb->reg_offs[i];
8556e9be3abSXianwei Zhao 			bank->pc.bit_offset[i] = aml_rb->bit_offs[i];
8566e9be3abSXianwei Zhao 		}
8576e9be3abSXianwei Zhao 	}
8586e9be3abSXianwei Zhao }
8596e9be3abSXianwei Zhao 
aml_gpiolib_register_bank(struct aml_pinctrl * info,int bank_nr,struct device_node * np)8606e9be3abSXianwei Zhao static int aml_gpiolib_register_bank(struct aml_pinctrl *info,
8616e9be3abSXianwei Zhao 				     int bank_nr, struct device_node *np)
8626e9be3abSXianwei Zhao {
8636e9be3abSXianwei Zhao 	struct aml_gpio_bank *bank = &info->banks[bank_nr];
8646e9be3abSXianwei Zhao 	struct device *dev = info->dev;
8656e9be3abSXianwei Zhao 	int ret = 0;
8666e9be3abSXianwei Zhao 
8676e9be3abSXianwei Zhao 	ret = aml_bank_number(np);
8686e9be3abSXianwei Zhao 	if (ret < 0) {
8696e9be3abSXianwei Zhao 		dev_err(dev, "get num=%d bank identity fail\n", bank_nr);
8706e9be3abSXianwei Zhao 		return -EINVAL;
8716e9be3abSXianwei Zhao 	}
8726e9be3abSXianwei Zhao 	bank->bank_id = ret;
8736e9be3abSXianwei Zhao 
8746e9be3abSXianwei Zhao 	bank->reg_mux = aml_map_resource(dev, bank->bank_id, np, "mux");
8756e9be3abSXianwei Zhao 	if (IS_ERR_OR_NULL(bank->reg_mux)) {
8766e9be3abSXianwei Zhao 		if (bank->bank_id == AMLOGIC_GPIO_TEST_N ||
8776e9be3abSXianwei Zhao 		    bank->bank_id == AMLOGIC_GPIO_ANALOG)
8786e9be3abSXianwei Zhao 			bank->reg_mux = NULL;
8796e9be3abSXianwei Zhao 		else
8806e9be3abSXianwei Zhao 			return dev_err_probe(dev, bank->reg_mux ? PTR_ERR(bank->reg_mux) : -ENOENT,
8816e9be3abSXianwei Zhao 					     "mux registers not found\n");
8826e9be3abSXianwei Zhao 	}
8836e9be3abSXianwei Zhao 
8846e9be3abSXianwei Zhao 	bank->reg_gpio = aml_map_resource(dev, bank->bank_id, np, "gpio");
8856e9be3abSXianwei Zhao 	if (IS_ERR_OR_NULL(bank->reg_gpio))
8866e9be3abSXianwei Zhao 		return dev_err_probe(dev, bank->reg_gpio ? PTR_ERR(bank->reg_gpio) : -ENOENT,
8876e9be3abSXianwei Zhao 				     "gpio registers not found\n");
8886e9be3abSXianwei Zhao 
8896e9be3abSXianwei Zhao 	bank->reg_ds = aml_map_resource(dev, bank->bank_id, np, "ds");
8906e9be3abSXianwei Zhao 	if (IS_ERR_OR_NULL(bank->reg_ds)) {
8916e9be3abSXianwei Zhao 		dev_dbg(info->dev, "ds registers not found - skipping\n");
8926e9be3abSXianwei Zhao 		bank->reg_ds = bank->reg_gpio;
8936e9be3abSXianwei Zhao 	}
8946e9be3abSXianwei Zhao 
8956e9be3abSXianwei Zhao 	bank->gpio_chip = aml_gpio_template;
8966e9be3abSXianwei Zhao 	bank->gpio_chip.base = -1;
8976e9be3abSXianwei Zhao 	bank->gpio_chip.ngpio = aml_bank_pins(np);
8986e9be3abSXianwei Zhao 	bank->gpio_chip.fwnode = of_fwnode_handle(np);
8996e9be3abSXianwei Zhao 	bank->gpio_chip.parent = dev;
9006e9be3abSXianwei Zhao 
9016e9be3abSXianwei Zhao 	init_bank_register_bit(info, bank);
9026e9be3abSXianwei Zhao 	bank->gpio_chip.label = aml_bank_name[bank->bank_id];
9036e9be3abSXianwei Zhao 
9046e9be3abSXianwei Zhao 	bank->pin_base = bank->bank_id << 8;
9056e9be3abSXianwei Zhao 
9066e9be3abSXianwei Zhao 	return 0;
9076e9be3abSXianwei Zhao }
9086e9be3abSXianwei Zhao 
aml_pctl_probe_dt(struct platform_device * pdev,struct pinctrl_desc * pctl_desc,struct aml_pinctrl * info)9096e9be3abSXianwei Zhao static int aml_pctl_probe_dt(struct platform_device *pdev,
9106e9be3abSXianwei Zhao 			     struct pinctrl_desc *pctl_desc,
9116e9be3abSXianwei Zhao 			     struct aml_pinctrl *info)
9126e9be3abSXianwei Zhao {
9136e9be3abSXianwei Zhao 	struct device *dev = &pdev->dev;
9146e9be3abSXianwei Zhao 	struct pinctrl_pin_desc *pdesc;
9156e9be3abSXianwei Zhao 	struct device_node *np = dev->of_node;
9166e9be3abSXianwei Zhao 	int grp_index = 0;
9176e9be3abSXianwei Zhao 	int i = 0, j = 0, k = 0, bank;
9186e9be3abSXianwei Zhao 	int ret = 0;
9196e9be3abSXianwei Zhao 
9206e9be3abSXianwei Zhao 	aml_pctl_dt_child_count(info, np);
9216e9be3abSXianwei Zhao 	if (!info->nbanks)
9226e9be3abSXianwei Zhao 		return dev_err_probe(dev, -EINVAL, "you need at least one gpio bank\n");
9236e9be3abSXianwei Zhao 
9246e9be3abSXianwei Zhao 	dev_dbg(dev, "nbanks = %d\n", info->nbanks);
9256e9be3abSXianwei Zhao 	dev_dbg(dev, "nfunctions = %d\n", info->nfunctions);
9266e9be3abSXianwei Zhao 	dev_dbg(dev, "ngroups = %d\n", info->ngroups);
9276e9be3abSXianwei Zhao 
9286e9be3abSXianwei Zhao 	info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL);
9296e9be3abSXianwei Zhao 
9306e9be3abSXianwei Zhao 	info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL);
9316e9be3abSXianwei Zhao 
9326e9be3abSXianwei Zhao 	info->banks = devm_kcalloc(dev, info->nbanks, sizeof(*info->banks), GFP_KERNEL);
9336e9be3abSXianwei Zhao 
9346e9be3abSXianwei Zhao 	if (!info->functions || !info->groups || !info->banks)
9356e9be3abSXianwei Zhao 		return -ENOMEM;
9366e9be3abSXianwei Zhao 
9376e9be3abSXianwei Zhao 	info->data = (struct aml_pctl_data *)of_device_get_match_data(dev);
9386e9be3abSXianwei Zhao 
9396e9be3abSXianwei Zhao 	pctl_desc->npins = aml_count_pins(np);
9406e9be3abSXianwei Zhao 
9416e9be3abSXianwei Zhao 	pdesc =	devm_kcalloc(dev, pctl_desc->npins, sizeof(*pdesc), GFP_KERNEL);
9426e9be3abSXianwei Zhao 	if (!pdesc)
9436e9be3abSXianwei Zhao 		return -ENOMEM;
9446e9be3abSXianwei Zhao 
9456e9be3abSXianwei Zhao 	pctl_desc->pins = pdesc;
9466e9be3abSXianwei Zhao 
9476e9be3abSXianwei Zhao 	bank = 0;
9486e9be3abSXianwei Zhao 	for_each_child_of_node_scoped(np, child) {
9496e9be3abSXianwei Zhao 		if (of_property_read_bool(child, "gpio-controller")) {
9506e9be3abSXianwei Zhao 			const char *bank_name = NULL;
9516e9be3abSXianwei Zhao 			char **pin_names;
9526e9be3abSXianwei Zhao 
9536e9be3abSXianwei Zhao 			ret = aml_gpiolib_register_bank(info, bank, child);
9546e9be3abSXianwei Zhao 			if (ret)
9556e9be3abSXianwei Zhao 				return ret;
9566e9be3abSXianwei Zhao 
9576e9be3abSXianwei Zhao 			k = info->banks[bank].pin_base;
9586e9be3abSXianwei Zhao 			bank_name = info->banks[bank].gpio_chip.label;
9596e9be3abSXianwei Zhao 
9606e9be3abSXianwei Zhao 			pin_names = devm_kasprintf_strarray(dev, bank_name,
9616e9be3abSXianwei Zhao 							    info->banks[bank].gpio_chip.ngpio);
9626e9be3abSXianwei Zhao 			if (IS_ERR(pin_names))
9636e9be3abSXianwei Zhao 				return PTR_ERR(pin_names);
9646e9be3abSXianwei Zhao 
9656e9be3abSXianwei Zhao 			for (j = 0; j < info->banks[bank].gpio_chip.ngpio; j++, k++) {
9666e9be3abSXianwei Zhao 				pdesc->number = k;
9676e9be3abSXianwei Zhao 				pdesc->name = pin_names[j];
9686e9be3abSXianwei Zhao 				pdesc++;
9696e9be3abSXianwei Zhao 			}
9706e9be3abSXianwei Zhao 			bank++;
9716e9be3abSXianwei Zhao 		} else {
9726e9be3abSXianwei Zhao 			ret = aml_pctl_parse_functions(child, info,
9736e9be3abSXianwei Zhao 						       i++, &grp_index);
9746e9be3abSXianwei Zhao 			if (ret)
9756e9be3abSXianwei Zhao 				return ret;
9766e9be3abSXianwei Zhao 		}
9776e9be3abSXianwei Zhao 	}
9786e9be3abSXianwei Zhao 
9796e9be3abSXianwei Zhao 	return 0;
9806e9be3abSXianwei Zhao }
9816e9be3abSXianwei Zhao 
aml_pctl_probe(struct platform_device * pdev)9826e9be3abSXianwei Zhao static int aml_pctl_probe(struct platform_device *pdev)
9836e9be3abSXianwei Zhao {
9846e9be3abSXianwei Zhao 	struct device *dev = &pdev->dev;
9856e9be3abSXianwei Zhao 	struct aml_pinctrl *info;
9866e9be3abSXianwei Zhao 	struct pinctrl_desc *pctl_desc;
9876e9be3abSXianwei Zhao 	int ret, i;
9886e9be3abSXianwei Zhao 
9896e9be3abSXianwei Zhao 	pctl_desc = devm_kzalloc(dev, sizeof(*pctl_desc), GFP_KERNEL);
9906e9be3abSXianwei Zhao 	if (!pctl_desc)
9916e9be3abSXianwei Zhao 		return -ENOMEM;
9926e9be3abSXianwei Zhao 
9936e9be3abSXianwei Zhao 	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
9946e9be3abSXianwei Zhao 	if (!info)
9956e9be3abSXianwei Zhao 		return -ENOMEM;
9966e9be3abSXianwei Zhao 
9976e9be3abSXianwei Zhao 	info->dev = dev;
9986e9be3abSXianwei Zhao 	platform_set_drvdata(pdev, info);
9996e9be3abSXianwei Zhao 	ret = aml_pctl_probe_dt(pdev, pctl_desc, info);
10006e9be3abSXianwei Zhao 	if (ret)
10016e9be3abSXianwei Zhao 		return ret;
10026e9be3abSXianwei Zhao 
10036e9be3abSXianwei Zhao 	pctl_desc->owner	= THIS_MODULE;
10046e9be3abSXianwei Zhao 	pctl_desc->pctlops	= &aml_pctrl_ops;
10056e9be3abSXianwei Zhao 	pctl_desc->pmxops	= &aml_pmx_ops;
10066e9be3abSXianwei Zhao 	pctl_desc->confops	= &aml_pinconf_ops;
10076e9be3abSXianwei Zhao 	pctl_desc->name		= dev_name(dev);
10086e9be3abSXianwei Zhao 
10096e9be3abSXianwei Zhao 	info->pctl = devm_pinctrl_register(dev, pctl_desc, info);
10106e9be3abSXianwei Zhao 	if (IS_ERR(info->pctl))
10116e9be3abSXianwei Zhao 		return dev_err_probe(dev, PTR_ERR(info->pctl), "Failed pinctrl registration\n");
10126e9be3abSXianwei Zhao 
10136e9be3abSXianwei Zhao 	for (i = 0; i < info->nbanks; i++) {
10146e9be3abSXianwei Zhao 		ret  = gpiochip_add_data(&info->banks[i].gpio_chip, &info->banks[i]);
10156e9be3abSXianwei Zhao 		if (ret)
10166e9be3abSXianwei Zhao 			return dev_err_probe(dev, ret, "Failed to add gpiochip(%d)!\n", i);
10176e9be3abSXianwei Zhao 	}
10186e9be3abSXianwei Zhao 
10196e9be3abSXianwei Zhao 	return 0;
10206e9be3abSXianwei Zhao }
10216e9be3abSXianwei Zhao 
10226e9be3abSXianwei Zhao static const struct of_device_id aml_pctl_of_match[] = {
10236e9be3abSXianwei Zhao 	{ .compatible = "amlogic,pinctrl-a4", },
10246e9be3abSXianwei Zhao 	{ /* sentinel */ }
10256e9be3abSXianwei Zhao };
10266e9be3abSXianwei Zhao MODULE_DEVICE_TABLE(of, aml_pctl_dt_match);
10276e9be3abSXianwei Zhao 
10286e9be3abSXianwei Zhao static struct platform_driver aml_pctl_driver = {
10296e9be3abSXianwei Zhao 	.driver = {
10306e9be3abSXianwei Zhao 		.name = "amlogic-pinctrl",
10316e9be3abSXianwei Zhao 		.of_match_table = aml_pctl_of_match,
10326e9be3abSXianwei Zhao 	},
10336e9be3abSXianwei Zhao 	.probe = aml_pctl_probe,
10346e9be3abSXianwei Zhao };
10356e9be3abSXianwei Zhao module_platform_driver(aml_pctl_driver);
10366e9be3abSXianwei Zhao 
10376e9be3abSXianwei Zhao MODULE_AUTHOR("Xianwei Zhao <xianwei.zhao@amlogic.com>");
10386e9be3abSXianwei Zhao MODULE_DESCRIPTION("Pin controller and GPIO driver for Amlogic SoC");
10396e9be3abSXianwei Zhao MODULE_LICENSE("Dual BSD/GPL");
1040