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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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, ®, &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