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