13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Pinctrl driver for Rockchip RK806 PMIC 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co., Ltd. 63d0407baSopenharmony_ci * 73d0407baSopenharmony_ci * Author: Xu Shengfei <xsf@rock-chips.com> 83d0407baSopenharmony_ci */ 93d0407baSopenharmony_ci 103d0407baSopenharmony_ci#include <linux/gpio/driver.h> 113d0407baSopenharmony_ci#include <linux/kernel.h> 123d0407baSopenharmony_ci#include <linux/mfd/rk806.h> 133d0407baSopenharmony_ci#include <linux/module.h> 143d0407baSopenharmony_ci#include <linux/of.h> 153d0407baSopenharmony_ci#include <linux/of_device.h> 163d0407baSopenharmony_ci#include <linux/pinctrl/consumer.h> 173d0407baSopenharmony_ci#include <linux/pinctrl/machine.h> 183d0407baSopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 193d0407baSopenharmony_ci#include <linux/pinctrl/pinconf.h> 203d0407baSopenharmony_ci#include <linux/pinctrl/pinctrl.h> 213d0407baSopenharmony_ci#include <linux/pinctrl/pinmux.h> 223d0407baSopenharmony_ci#include <linux/platform_device.h> 233d0407baSopenharmony_ci#include <linux/pm.h> 243d0407baSopenharmony_ci#include <linux/slab.h> 253d0407baSopenharmony_ci#include "pinctrl-utils.h" 263d0407baSopenharmony_ci 273d0407baSopenharmony_cistruct rk806_pin_function { 283d0407baSopenharmony_ci const char *name; 293d0407baSopenharmony_ci const char *const *groups; 303d0407baSopenharmony_ci unsigned int ngroups; 313d0407baSopenharmony_ci int mux_option; 323d0407baSopenharmony_ci}; 333d0407baSopenharmony_ci 343d0407baSopenharmony_cistruct rk806_pin_group { 353d0407baSopenharmony_ci const char *name; 363d0407baSopenharmony_ci const unsigned int pins[1]; 373d0407baSopenharmony_ci unsigned int npins; 383d0407baSopenharmony_ci}; 393d0407baSopenharmony_ci 403d0407baSopenharmony_ci/* 413d0407baSopenharmony_ci * @reg: gpio setting register; 423d0407baSopenharmony_ci * @fun_mask: functions select mask value, when set is gpio; 433d0407baSopenharmony_ci * @dir_mask: input or output mask value, when set is output, otherwise input; 443d0407baSopenharmony_ci * @val_mask: gpio set value, when set is level high, otherwise low; 453d0407baSopenharmony_ci * 463d0407baSopenharmony_ci * Different PMIC has different pin features, belowing 3 mask members are not 473d0407baSopenharmony_ci * all necessary for every PMIC. For example, RK805 has 2 pins that can be used 483d0407baSopenharmony_ci * as output only GPIOs, so func_mask and dir_mask are not needed. RK816 has 1 493d0407baSopenharmony_ci * pin that can be used as TS/GPIO, so fun_mask, dir_mask and val_mask are all 503d0407baSopenharmony_ci * necessary. 513d0407baSopenharmony_ci */ 523d0407baSopenharmony_cistruct rk806_pin_config { 533d0407baSopenharmony_ci u8 fun_reg; 543d0407baSopenharmony_ci u8 fun_msk; 553d0407baSopenharmony_ci u8 reg; 563d0407baSopenharmony_ci u8 dir_msk; 573d0407baSopenharmony_ci u8 val_msk; 583d0407baSopenharmony_ci}; 593d0407baSopenharmony_ci 603d0407baSopenharmony_cistruct rk806_pctrl_info { 613d0407baSopenharmony_ci struct rk806 *rk806; 623d0407baSopenharmony_ci struct device *dev; 633d0407baSopenharmony_ci struct pinctrl_dev *pctl; 643d0407baSopenharmony_ci struct gpio_chip gpio_chip; 653d0407baSopenharmony_ci struct pinctrl_desc pinctrl_desc; 663d0407baSopenharmony_ci const struct rk806_pin_function *functions; 673d0407baSopenharmony_ci unsigned int num_functions; 683d0407baSopenharmony_ci const struct rk806_pin_group *groups; 693d0407baSopenharmony_ci int num_pin_groups; 703d0407baSopenharmony_ci const struct pinctrl_pin_desc *pins; 713d0407baSopenharmony_ci unsigned int num_pins; 723d0407baSopenharmony_ci const struct rk806_pin_config *pin_cfg; 733d0407baSopenharmony_ci}; 743d0407baSopenharmony_ci 753d0407baSopenharmony_ci#define RK806_PWRCTRL1_DR BIT(0) 763d0407baSopenharmony_ci#define RK806_PWRCTRL2_DR BIT(1) 773d0407baSopenharmony_ci#define RK806_PWRCTRL3_DR BIT(2) 783d0407baSopenharmony_ci#define RK806_PWRCTRL1_DATA BIT(4) 793d0407baSopenharmony_ci#define RK806_PWRCTRL2_DATA BIT(5) 803d0407baSopenharmony_ci#define RK806_PWRCTRL3_DATA BIT(6) 813d0407baSopenharmony_ci#define RK806_PWRCTRL1_FUN 0x07 823d0407baSopenharmony_ci#define RK806_PWRCTRL2_FUN 0x70 833d0407baSopenharmony_ci#define RK806_PWRCTRL3_FUN 0x07 843d0407baSopenharmony_ci 853d0407baSopenharmony_cienum rk806_pinmux_option { 863d0407baSopenharmony_ci RK806_PINMUX_FUN0 = 0, 873d0407baSopenharmony_ci RK806_PINMUX_FUN1, 883d0407baSopenharmony_ci RK806_PINMUX_FUN2, 893d0407baSopenharmony_ci RK806_PINMUX_FUN3, 903d0407baSopenharmony_ci RK806_PINMUX_FUN4, 913d0407baSopenharmony_ci RK806_PINMUX_FUN5, 923d0407baSopenharmony_ci}; 933d0407baSopenharmony_ci 943d0407baSopenharmony_cienum { 953d0407baSopenharmony_ci RK806_GPIO_DVS1, 963d0407baSopenharmony_ci RK806_GPIO_DVS2, 973d0407baSopenharmony_ci RK806_GPIO_DVS3 983d0407baSopenharmony_ci}; 993d0407baSopenharmony_ci 1003d0407baSopenharmony_cistatic const char *const rk806_gpio_groups[] = { 1013d0407baSopenharmony_ci "gpio_pwrctrl1", 1023d0407baSopenharmony_ci "gpio_pwrctrl2", 1033d0407baSopenharmony_ci "gpio_pwrctrl3", 1043d0407baSopenharmony_ci}; 1053d0407baSopenharmony_ci 1063d0407baSopenharmony_cistatic const struct pinctrl_pin_desc rk806_pins_desc[] = { 1073d0407baSopenharmony_ci PINCTRL_PIN(RK806_GPIO_DVS1, "gpio_pwrctrl1"), /* dvs1 pin */ 1083d0407baSopenharmony_ci PINCTRL_PIN(RK806_GPIO_DVS2, "gpio_pwrctrl2"), /* dvs2 pin */ 1093d0407baSopenharmony_ci PINCTRL_PIN(RK806_GPIO_DVS3, "gpio_pwrctrl3") /* dvs3 pin */ 1103d0407baSopenharmony_ci}; 1113d0407baSopenharmony_ci 1123d0407baSopenharmony_cistatic const struct rk806_pin_function rk806_pin_functions[] = { 1133d0407baSopenharmony_ci { 1143d0407baSopenharmony_ci .name = "pin_fun0", 1153d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1163d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1173d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN0, 1183d0407baSopenharmony_ci }, 1193d0407baSopenharmony_ci { 1203d0407baSopenharmony_ci .name = "pin_fun1", 1213d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1223d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1233d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN1, 1243d0407baSopenharmony_ci }, 1253d0407baSopenharmony_ci { 1263d0407baSopenharmony_ci .name = "pin_fun2", 1273d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1283d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1293d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN2, 1303d0407baSopenharmony_ci }, 1313d0407baSopenharmony_ci { 1323d0407baSopenharmony_ci .name = "pin_fun3", 1333d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1343d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1353d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN3, 1363d0407baSopenharmony_ci }, 1373d0407baSopenharmony_ci { 1383d0407baSopenharmony_ci .name = "pin_fun4", 1393d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1403d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1413d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN4, 1423d0407baSopenharmony_ci }, 1433d0407baSopenharmony_ci { 1443d0407baSopenharmony_ci .name = "pin_fun5", 1453d0407baSopenharmony_ci .groups = rk806_gpio_groups, 1463d0407baSopenharmony_ci .ngroups = ARRAY_SIZE(rk806_gpio_groups), 1473d0407baSopenharmony_ci .mux_option = RK806_PINMUX_FUN5, 1483d0407baSopenharmony_ci }, 1493d0407baSopenharmony_ci 1503d0407baSopenharmony_ci}; 1513d0407baSopenharmony_ci 1523d0407baSopenharmony_cistatic const struct rk806_pin_group rk806_pin_groups[] = { 1533d0407baSopenharmony_ci { 1543d0407baSopenharmony_ci .name = "gpio_pwrctrl1", 1553d0407baSopenharmony_ci .pins = { RK806_GPIO_DVS1 }, 1563d0407baSopenharmony_ci .npins = 1, 1573d0407baSopenharmony_ci }, 1583d0407baSopenharmony_ci { 1593d0407baSopenharmony_ci .name = "gpio_pwrctrl2", 1603d0407baSopenharmony_ci .pins = { RK806_GPIO_DVS2 }, 1613d0407baSopenharmony_ci .npins = 1, 1623d0407baSopenharmony_ci }, 1633d0407baSopenharmony_ci { 1643d0407baSopenharmony_ci .name = "gpio_pwrctrl3", 1653d0407baSopenharmony_ci .pins = { RK806_GPIO_DVS3 }, 1663d0407baSopenharmony_ci .npins = 1, 1673d0407baSopenharmony_ci } 1683d0407baSopenharmony_ci}; 1693d0407baSopenharmony_ci 1703d0407baSopenharmony_cistatic struct rk806_pin_config rk806_gpio_cfgs[] = { 1713d0407baSopenharmony_ci { 1723d0407baSopenharmony_ci .fun_reg = RK806_SLEEP_CONFIG0, 1733d0407baSopenharmony_ci .fun_msk = RK806_PWRCTRL1_FUN, 1743d0407baSopenharmony_ci .reg = RK806_SLEEP_GPIO, 1753d0407baSopenharmony_ci .val_msk = RK806_PWRCTRL1_DATA, 1763d0407baSopenharmony_ci .dir_msk = RK806_PWRCTRL1_DR, 1773d0407baSopenharmony_ci }, 1783d0407baSopenharmony_ci { 1793d0407baSopenharmony_ci .fun_reg = RK806_SLEEP_CONFIG0, 1803d0407baSopenharmony_ci .fun_msk = RK806_PWRCTRL2_FUN, 1813d0407baSopenharmony_ci .reg = RK806_SLEEP_GPIO, 1823d0407baSopenharmony_ci .val_msk = RK806_PWRCTRL2_DATA, 1833d0407baSopenharmony_ci .dir_msk = RK806_PWRCTRL2_DR, 1843d0407baSopenharmony_ci }, 1853d0407baSopenharmony_ci { 1863d0407baSopenharmony_ci .fun_reg = RK806_SLEEP_CONFIG1, 1873d0407baSopenharmony_ci .fun_msk = RK806_PWRCTRL3_FUN, 1883d0407baSopenharmony_ci .reg = RK806_SLEEP_GPIO, 1893d0407baSopenharmony_ci .val_msk = RK806_PWRCTRL3_DATA, 1903d0407baSopenharmony_ci .dir_msk = RK806_PWRCTRL3_DR, 1913d0407baSopenharmony_ci } 1923d0407baSopenharmony_ci}; 1933d0407baSopenharmony_ci 1943d0407baSopenharmony_ci/* generic gpio chip */ 1953d0407baSopenharmony_cistatic int rk806_gpio_get(struct gpio_chip *chip, unsigned int offset) 1963d0407baSopenharmony_ci{ 1973d0407baSopenharmony_ci struct rk806_pctrl_info *pci = gpiochip_get_data(chip); 1983d0407baSopenharmony_ci int ret, val; 1993d0407baSopenharmony_ci 2003d0407baSopenharmony_ci if (!pci->pin_cfg[offset].val_msk) { 2013d0407baSopenharmony_ci dev_dbg(pci->dev, "getting gpio%d value is not support\n", 2023d0407baSopenharmony_ci offset); 2033d0407baSopenharmony_ci return -1; 2043d0407baSopenharmony_ci } 2053d0407baSopenharmony_ci 2063d0407baSopenharmony_ci ret = regmap_read(pci->rk806->regmap, pci->pin_cfg[offset].reg, &val); 2073d0407baSopenharmony_ci if (ret) { 2083d0407baSopenharmony_ci dev_err(pci->dev, "get gpio%d value failed\n", offset); 2093d0407baSopenharmony_ci return ret; 2103d0407baSopenharmony_ci } 2113d0407baSopenharmony_ci 2123d0407baSopenharmony_ci return !!(val & pci->pin_cfg[offset].val_msk); 2133d0407baSopenharmony_ci} 2143d0407baSopenharmony_ci 2153d0407baSopenharmony_cistatic void rk806_gpio_set(struct gpio_chip *chip, 2163d0407baSopenharmony_ci unsigned int offset, 2173d0407baSopenharmony_ci int value) 2183d0407baSopenharmony_ci{ 2193d0407baSopenharmony_ci struct rk806_pctrl_info *pci = gpiochip_get_data(chip); 2203d0407baSopenharmony_ci int ret; 2213d0407baSopenharmony_ci 2223d0407baSopenharmony_ci if (!pci->pin_cfg[offset].val_msk) 2233d0407baSopenharmony_ci return; 2243d0407baSopenharmony_ci 2253d0407baSopenharmony_ci ret = regmap_update_bits(pci->rk806->regmap, 2263d0407baSopenharmony_ci pci->pin_cfg[offset].reg, 2273d0407baSopenharmony_ci pci->pin_cfg[offset].val_msk, 2283d0407baSopenharmony_ci value ? pci->pin_cfg[offset].val_msk : 0); 2293d0407baSopenharmony_ci if (ret) 2303d0407baSopenharmony_ci dev_err(pci->dev, "set gpio%d value %d failed\n", 2313d0407baSopenharmony_ci offset, value); 2323d0407baSopenharmony_ci} 2333d0407baSopenharmony_ci 2343d0407baSopenharmony_cistatic int rk806_gpio_direction_input(struct gpio_chip *chip, 2353d0407baSopenharmony_ci unsigned int offset) 2363d0407baSopenharmony_ci{ 2373d0407baSopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 2383d0407baSopenharmony_ci} 2393d0407baSopenharmony_ci 2403d0407baSopenharmony_cistatic int rk806_gpio_direction_output(struct gpio_chip *chip, 2413d0407baSopenharmony_ci unsigned int offset, 2423d0407baSopenharmony_ci int value) 2433d0407baSopenharmony_ci{ 2443d0407baSopenharmony_ci rk806_gpio_set(chip, offset, value); 2453d0407baSopenharmony_ci return pinctrl_gpio_direction_output(chip->base + offset); 2463d0407baSopenharmony_ci} 2473d0407baSopenharmony_ci 2483d0407baSopenharmony_cistatic int rk806_gpio_get_direction(struct gpio_chip *chip, 2493d0407baSopenharmony_ci unsigned int offset) 2503d0407baSopenharmony_ci{ 2513d0407baSopenharmony_ci struct rk806_pctrl_info *pci = gpiochip_get_data(chip); 2523d0407baSopenharmony_ci unsigned int val; 2533d0407baSopenharmony_ci int ret; 2543d0407baSopenharmony_ci 2553d0407baSopenharmony_ci /* default output */ 2563d0407baSopenharmony_ci if (!pci->pin_cfg[offset].dir_msk) 2573d0407baSopenharmony_ci return 0; 2583d0407baSopenharmony_ci 2593d0407baSopenharmony_ci ret = regmap_read(pci->rk806->regmap, 2603d0407baSopenharmony_ci pci->pin_cfg[offset].reg, 2613d0407baSopenharmony_ci &val); 2623d0407baSopenharmony_ci if (ret) { 2633d0407baSopenharmony_ci dev_err(pci->dev, "get gpio%d direction failed\n", offset); 2643d0407baSopenharmony_ci return ret; 2653d0407baSopenharmony_ci } 2663d0407baSopenharmony_ci 2673d0407baSopenharmony_ci return !(val & pci->pin_cfg[offset].dir_msk); 2683d0407baSopenharmony_ci} 2693d0407baSopenharmony_ci 2703d0407baSopenharmony_cistatic struct gpio_chip rk806_gpio_chip = { 2713d0407baSopenharmony_ci .label = "rk806-gpio", 2723d0407baSopenharmony_ci .request = gpiochip_generic_request, 2733d0407baSopenharmony_ci .free = gpiochip_generic_free, 2743d0407baSopenharmony_ci .get_direction = rk806_gpio_get_direction, 2753d0407baSopenharmony_ci .get = rk806_gpio_get, 2763d0407baSopenharmony_ci .set = rk806_gpio_set, 2773d0407baSopenharmony_ci .direction_input = rk806_gpio_direction_input, 2783d0407baSopenharmony_ci .direction_output = rk806_gpio_direction_output, 2793d0407baSopenharmony_ci .can_sleep = true, 2803d0407baSopenharmony_ci .base = -1, 2813d0407baSopenharmony_ci .owner = THIS_MODULE, 2823d0407baSopenharmony_ci}; 2833d0407baSopenharmony_ci 2843d0407baSopenharmony_ci/* generic pinctrl */ 2853d0407baSopenharmony_cistatic int rk806_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) 2863d0407baSopenharmony_ci{ 2873d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 2883d0407baSopenharmony_ci 2893d0407baSopenharmony_ci return pci->num_pin_groups; 2903d0407baSopenharmony_ci} 2913d0407baSopenharmony_ci 2923d0407baSopenharmony_cistatic const char *rk806_pinctrl_get_group_name(struct pinctrl_dev *pctldev, 2933d0407baSopenharmony_ci unsigned int group) 2943d0407baSopenharmony_ci{ 2953d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 2963d0407baSopenharmony_ci 2973d0407baSopenharmony_ci return pci->groups[group].name; 2983d0407baSopenharmony_ci} 2993d0407baSopenharmony_ci 3003d0407baSopenharmony_cistatic int rk806_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, 3013d0407baSopenharmony_ci unsigned int group, 3023d0407baSopenharmony_ci const unsigned int **pins, 3033d0407baSopenharmony_ci unsigned int *num_pins) 3043d0407baSopenharmony_ci{ 3053d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3063d0407baSopenharmony_ci 3073d0407baSopenharmony_ci *pins = pci->groups[group].pins; 3083d0407baSopenharmony_ci *num_pins = pci->groups[group].npins; 3093d0407baSopenharmony_ci 3103d0407baSopenharmony_ci return 0; 3113d0407baSopenharmony_ci} 3123d0407baSopenharmony_ci 3133d0407baSopenharmony_cistatic const struct pinctrl_ops rk806_pinctrl_ops = { 3143d0407baSopenharmony_ci .get_groups_count = rk806_pinctrl_get_groups_count, 3153d0407baSopenharmony_ci .get_group_name = rk806_pinctrl_get_group_name, 3163d0407baSopenharmony_ci .get_group_pins = rk806_pinctrl_get_group_pins, 3173d0407baSopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, 3183d0407baSopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 3193d0407baSopenharmony_ci}; 3203d0407baSopenharmony_ci 3213d0407baSopenharmony_cistatic int rk806_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) 3223d0407baSopenharmony_ci{ 3233d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3243d0407baSopenharmony_ci 3253d0407baSopenharmony_ci return pci->num_functions; 3263d0407baSopenharmony_ci} 3273d0407baSopenharmony_ci 3283d0407baSopenharmony_cistatic const char *rk806_pinctrl_get_func_name(struct pinctrl_dev *pctldev, 3293d0407baSopenharmony_ci unsigned int function) 3303d0407baSopenharmony_ci{ 3313d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3323d0407baSopenharmony_ci 3333d0407baSopenharmony_ci return pci->functions[function].name; 3343d0407baSopenharmony_ci} 3353d0407baSopenharmony_ci 3363d0407baSopenharmony_cistatic int rk806_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, 3373d0407baSopenharmony_ci unsigned int function, 3383d0407baSopenharmony_ci const char *const **groups, 3393d0407baSopenharmony_ci unsigned int *const num_groups) 3403d0407baSopenharmony_ci{ 3413d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3423d0407baSopenharmony_ci 3433d0407baSopenharmony_ci *groups = pci->functions[function].groups; 3443d0407baSopenharmony_ci *num_groups = pci->functions[function].ngroups; 3453d0407baSopenharmony_ci 3463d0407baSopenharmony_ci return 0; 3473d0407baSopenharmony_ci} 3483d0407baSopenharmony_ci 3493d0407baSopenharmony_cistatic int _rk806_pinctrl_set_mux(struct pinctrl_dev *pctldev, 3503d0407baSopenharmony_ci unsigned int offset, 3513d0407baSopenharmony_ci int mux) 3523d0407baSopenharmony_ci{ 3533d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3543d0407baSopenharmony_ci int ret; 3553d0407baSopenharmony_ci 3563d0407baSopenharmony_ci if (!pci->pin_cfg[offset].fun_msk) 3573d0407baSopenharmony_ci return 0; 3583d0407baSopenharmony_ci 3593d0407baSopenharmony_ci mux <<= ffs(pci->pin_cfg[offset].fun_msk) - 1; 3603d0407baSopenharmony_ci ret = regmap_update_bits(pci->rk806->regmap, 3613d0407baSopenharmony_ci pci->pin_cfg[offset].fun_reg, 3623d0407baSopenharmony_ci pci->pin_cfg[offset].fun_msk, mux); 3633d0407baSopenharmony_ci 3643d0407baSopenharmony_ci if (ret) 3653d0407baSopenharmony_ci dev_err(pci->dev, "set gpio%d func%d failed\n", offset, mux); 3663d0407baSopenharmony_ci 3673d0407baSopenharmony_ci return ret; 3683d0407baSopenharmony_ci} 3693d0407baSopenharmony_ci 3703d0407baSopenharmony_cistatic int rk806_pinctrl_set_mux(struct pinctrl_dev *pctldev, 3713d0407baSopenharmony_ci unsigned int function, 3723d0407baSopenharmony_ci unsigned int group) 3733d0407baSopenharmony_ci{ 3743d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3753d0407baSopenharmony_ci int mux = pci->functions[function].mux_option; 3763d0407baSopenharmony_ci int offset = group; 3773d0407baSopenharmony_ci 3783d0407baSopenharmony_ci return _rk806_pinctrl_set_mux(pctldev, offset, mux); 3793d0407baSopenharmony_ci} 3803d0407baSopenharmony_ci 3813d0407baSopenharmony_cistatic int rk806_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 3823d0407baSopenharmony_ci struct pinctrl_gpio_range *range, 3833d0407baSopenharmony_ci unsigned int offset, bool input) 3843d0407baSopenharmony_ci{ 3853d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 3863d0407baSopenharmony_ci int ret; 3873d0407baSopenharmony_ci 3883d0407baSopenharmony_ci /* set direction */ 3893d0407baSopenharmony_ci if (!pci->pin_cfg[offset].dir_msk) 3903d0407baSopenharmony_ci return 0; 3913d0407baSopenharmony_ci 3923d0407baSopenharmony_ci ret = regmap_update_bits(pci->rk806->regmap, 3933d0407baSopenharmony_ci pci->pin_cfg[offset].reg, 3943d0407baSopenharmony_ci pci->pin_cfg[offset].dir_msk, 3953d0407baSopenharmony_ci input ? 0 : pci->pin_cfg[offset].dir_msk); 3963d0407baSopenharmony_ci if (ret) { 3973d0407baSopenharmony_ci dev_err(pci->dev, "set gpio%d direction failed\n", offset); 3983d0407baSopenharmony_ci return ret; 3993d0407baSopenharmony_ci } 4003d0407baSopenharmony_ci 4013d0407baSopenharmony_ci return ret; 4023d0407baSopenharmony_ci} 4033d0407baSopenharmony_ci 4043d0407baSopenharmony_cistatic int rk806_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, 4053d0407baSopenharmony_ci struct pinctrl_gpio_range *range, 4063d0407baSopenharmony_ci unsigned int offset) 4073d0407baSopenharmony_ci{ 4083d0407baSopenharmony_ci return _rk806_pinctrl_set_mux(pctldev, offset, RK806_PINMUX_FUN5); 4093d0407baSopenharmony_ci} 4103d0407baSopenharmony_ci 4113d0407baSopenharmony_cistatic const struct pinmux_ops rk806_pinmux_ops = { 4123d0407baSopenharmony_ci .gpio_request_enable = rk806_pinctrl_gpio_request_enable, 4133d0407baSopenharmony_ci .get_functions_count = rk806_pinctrl_get_funcs_count, 4143d0407baSopenharmony_ci .get_function_name = rk806_pinctrl_get_func_name, 4153d0407baSopenharmony_ci .get_function_groups = rk806_pinctrl_get_func_groups, 4163d0407baSopenharmony_ci .set_mux = rk806_pinctrl_set_mux, 4173d0407baSopenharmony_ci .gpio_set_direction = rk806_pmx_gpio_set_direction, 4183d0407baSopenharmony_ci}; 4193d0407baSopenharmony_ci 4203d0407baSopenharmony_cistatic int rk806_pinconf_get(struct pinctrl_dev *pctldev, 4213d0407baSopenharmony_ci unsigned int pin, 4223d0407baSopenharmony_ci unsigned long *config) 4233d0407baSopenharmony_ci{ 4243d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 4253d0407baSopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 4263d0407baSopenharmony_ci u32 arg = 0; 4273d0407baSopenharmony_ci 4283d0407baSopenharmony_ci switch (param) { 4293d0407baSopenharmony_ci case PIN_CONFIG_OUTPUT: 4303d0407baSopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 4313d0407baSopenharmony_ci arg = rk806_gpio_get(&pci->gpio_chip, pin); 4323d0407baSopenharmony_ci break; 4333d0407baSopenharmony_ci default: 4343d0407baSopenharmony_ci dev_err(pci->dev, "Properties not supported\n"); 4353d0407baSopenharmony_ci return -EOPNOTSUPP; 4363d0407baSopenharmony_ci } 4373d0407baSopenharmony_ci 4383d0407baSopenharmony_ci *config = pinconf_to_config_packed(param, (u16)arg); 4393d0407baSopenharmony_ci 4403d0407baSopenharmony_ci return 0; 4413d0407baSopenharmony_ci} 4423d0407baSopenharmony_ci 4433d0407baSopenharmony_cistatic int rk806_pinconf_set(struct pinctrl_dev *pctldev, 4443d0407baSopenharmony_ci unsigned int pin, 4453d0407baSopenharmony_ci unsigned long *configs, 4463d0407baSopenharmony_ci unsigned int num_configs) 4473d0407baSopenharmony_ci{ 4483d0407baSopenharmony_ci struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev); 4493d0407baSopenharmony_ci enum pin_config_param param; 4503d0407baSopenharmony_ci u32 i, arg = 0; 4513d0407baSopenharmony_ci 4523d0407baSopenharmony_ci for (i = 0; i < num_configs; i++) { 4533d0407baSopenharmony_ci param = pinconf_to_config_param(configs[i]); 4543d0407baSopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 4553d0407baSopenharmony_ci 4563d0407baSopenharmony_ci switch (param) { 4573d0407baSopenharmony_ci case PIN_CONFIG_OUTPUT: 4583d0407baSopenharmony_ci rk806_pmx_gpio_set_direction(pctldev, NULL, pin, false); 4593d0407baSopenharmony_ci rk806_gpio_set(&pci->gpio_chip, pin, arg); 4603d0407baSopenharmony_ci break; 4613d0407baSopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 4623d0407baSopenharmony_ci if (arg) 4633d0407baSopenharmony_ci rk806_pmx_gpio_set_direction(pctldev, 4643d0407baSopenharmony_ci NULL, 4653d0407baSopenharmony_ci pin, 4663d0407baSopenharmony_ci true); 4673d0407baSopenharmony_ci break; 4683d0407baSopenharmony_ci default: 4693d0407baSopenharmony_ci dev_err(pci->dev, "Properties not supported\n"); 4703d0407baSopenharmony_ci return -EOPNOTSUPP; 4713d0407baSopenharmony_ci } 4723d0407baSopenharmony_ci } 4733d0407baSopenharmony_ci 4743d0407baSopenharmony_ci return 0; 4753d0407baSopenharmony_ci} 4763d0407baSopenharmony_ci 4773d0407baSopenharmony_cistatic const struct pinconf_ops rk806_pinconf_ops = { 4783d0407baSopenharmony_ci .pin_config_get = rk806_pinconf_get, 4793d0407baSopenharmony_ci .pin_config_set = rk806_pinconf_set, 4803d0407baSopenharmony_ci}; 4813d0407baSopenharmony_ci 4823d0407baSopenharmony_cistatic struct pinctrl_desc rk806_pinctrl_desc = { 4833d0407baSopenharmony_ci .name = "rk806-pinctrl", 4843d0407baSopenharmony_ci .pctlops = &rk806_pinctrl_ops, 4853d0407baSopenharmony_ci .pmxops = &rk806_pinmux_ops, 4863d0407baSopenharmony_ci .confops = &rk806_pinconf_ops, 4873d0407baSopenharmony_ci .owner = THIS_MODULE, 4883d0407baSopenharmony_ci}; 4893d0407baSopenharmony_ci 4903d0407baSopenharmony_cistatic int rk806_pinctrl_probe(struct platform_device *pdev) 4913d0407baSopenharmony_ci{ 4923d0407baSopenharmony_ci struct rk806_pctrl_info *pci; 4933d0407baSopenharmony_ci struct device_node *np; 4943d0407baSopenharmony_ci int ret; 4953d0407baSopenharmony_ci 4963d0407baSopenharmony_ci pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL); 4973d0407baSopenharmony_ci if (!pci) 4983d0407baSopenharmony_ci return -ENOMEM; 4993d0407baSopenharmony_ci 5003d0407baSopenharmony_ci pci->dev = &pdev->dev; 5013d0407baSopenharmony_ci np = of_get_child_by_name(pdev->dev.parent->of_node, "pinctrl_rk806"); 5023d0407baSopenharmony_ci if (np) 5033d0407baSopenharmony_ci pci->dev->of_node = np; 5043d0407baSopenharmony_ci else 5053d0407baSopenharmony_ci pci->dev->of_node = pdev->dev.parent->of_node; 5063d0407baSopenharmony_ci pci->rk806 = dev_get_drvdata(pdev->dev.parent); 5073d0407baSopenharmony_ci 5083d0407baSopenharmony_ci platform_set_drvdata(pdev, pci); 5093d0407baSopenharmony_ci 5103d0407baSopenharmony_ci pci->pinctrl_desc = rk806_pinctrl_desc; 5113d0407baSopenharmony_ci pci->gpio_chip = rk806_gpio_chip; 5123d0407baSopenharmony_ci pci->pins = rk806_pins_desc; 5133d0407baSopenharmony_ci pci->num_pins = ARRAY_SIZE(rk806_pins_desc); 5143d0407baSopenharmony_ci pci->functions = rk806_pin_functions; 5153d0407baSopenharmony_ci pci->num_functions = ARRAY_SIZE(rk806_pin_functions); 5163d0407baSopenharmony_ci pci->groups = rk806_pin_groups; 5173d0407baSopenharmony_ci pci->num_pin_groups = ARRAY_SIZE(rk806_pin_groups); 5183d0407baSopenharmony_ci pci->pinctrl_desc.pins = rk806_pins_desc; 5193d0407baSopenharmony_ci pci->pinctrl_desc.npins = ARRAY_SIZE(rk806_pins_desc); 5203d0407baSopenharmony_ci pci->pin_cfg = rk806_gpio_cfgs; 5213d0407baSopenharmony_ci pci->gpio_chip.ngpio = ARRAY_SIZE(rk806_gpio_cfgs); 5223d0407baSopenharmony_ci 5233d0407baSopenharmony_ci pci->gpio_chip.parent = &pdev->dev; 5243d0407baSopenharmony_ci 5253d0407baSopenharmony_ci if (np) 5263d0407baSopenharmony_ci pci->gpio_chip.of_node = np; 5273d0407baSopenharmony_ci else 5283d0407baSopenharmony_ci pci->gpio_chip.of_node = pdev->dev.parent->of_node; 5293d0407baSopenharmony_ci 5303d0407baSopenharmony_ci /* Add gpiochip */ 5313d0407baSopenharmony_ci ret = devm_gpiochip_add_data(&pdev->dev, &pci->gpio_chip, pci); 5323d0407baSopenharmony_ci if (ret < 0) { 5333d0407baSopenharmony_ci dev_err(&pdev->dev, "Couldn't add gpiochip\n"); 5343d0407baSopenharmony_ci return ret; 5353d0407baSopenharmony_ci } 5363d0407baSopenharmony_ci 5373d0407baSopenharmony_ci /* Add pinctrl */ 5383d0407baSopenharmony_ci pci->pctl = devm_pinctrl_register(&pdev->dev, &pci->pinctrl_desc, pci); 5393d0407baSopenharmony_ci if (IS_ERR(pci->pctl)) { 5403d0407baSopenharmony_ci dev_err(&pdev->dev, "Couldn't add pinctrl\n"); 5413d0407baSopenharmony_ci return PTR_ERR(pci->pctl); 5423d0407baSopenharmony_ci } 5433d0407baSopenharmony_ci 5443d0407baSopenharmony_ci /* Add pin range */ 5453d0407baSopenharmony_ci ret = gpiochip_add_pin_range(&pci->gpio_chip, 5463d0407baSopenharmony_ci dev_name(&pdev->dev), 5473d0407baSopenharmony_ci 0, 5483d0407baSopenharmony_ci 0, 5493d0407baSopenharmony_ci pci->gpio_chip.ngpio); 5503d0407baSopenharmony_ci if (ret < 0) { 5513d0407baSopenharmony_ci dev_err(&pdev->dev, "Couldn't add gpiochip pin range\n"); 5523d0407baSopenharmony_ci return ret; 5533d0407baSopenharmony_ci } 5543d0407baSopenharmony_ci 5553d0407baSopenharmony_ci return 0; 5563d0407baSopenharmony_ci} 5573d0407baSopenharmony_ci 5583d0407baSopenharmony_cistatic struct platform_driver rk806_pinctrl_driver = { 5593d0407baSopenharmony_ci .probe = rk806_pinctrl_probe, 5603d0407baSopenharmony_ci .driver = { 5613d0407baSopenharmony_ci .name = "rk806-pinctrl", 5623d0407baSopenharmony_ci }, 5633d0407baSopenharmony_ci}; 5643d0407baSopenharmony_ci 5653d0407baSopenharmony_cistatic int __init rk806_pinctrl_driver_register(void) 5663d0407baSopenharmony_ci{ 5673d0407baSopenharmony_ci return platform_driver_register(&rk806_pinctrl_driver); 5683d0407baSopenharmony_ci} 5693d0407baSopenharmony_ci#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT 5703d0407baSopenharmony_cisubsys_initcall(rk806_pinctrl_driver_register); 5713d0407baSopenharmony_ci#else 5723d0407baSopenharmony_cifs_initcall_sync(rk806_pinctrl_driver_register); 5733d0407baSopenharmony_ci#endif 5743d0407baSopenharmony_ci 5753d0407baSopenharmony_ciMODULE_DESCRIPTION("RK806 pin control and GPIO driver"); 5763d0407baSopenharmony_ciMODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>"); 5773d0407baSopenharmony_ciMODULE_LICENSE("GPL v2"); 578