162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MAX77620 pin control driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: 862306a36Sopenharmony_ci * Chaitanya Bandi <bandik@nvidia.com> 962306a36Sopenharmony_ci * Laxman Dewangan <ldewangan@nvidia.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/mfd/max77620.h> 1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/property.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2062306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2162306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2262306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "core.h" 2562306a36Sopenharmony_ci#include "pinconf.h" 2662306a36Sopenharmony_ci#include "pinctrl-utils.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MAX77620_PIN_NUM 8 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cienum max77620_pin_ppdrv { 3162306a36Sopenharmony_ci MAX77620_PIN_UNCONFIG_DRV, 3262306a36Sopenharmony_ci MAX77620_PIN_OD_DRV, 3362306a36Sopenharmony_ci MAX77620_PIN_PP_DRV, 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define MAX77620_ACTIVE_FPS_SOURCE (PIN_CONFIG_END + 1) 3762306a36Sopenharmony_ci#define MAX77620_ACTIVE_FPS_POWER_ON_SLOTS (PIN_CONFIG_END + 2) 3862306a36Sopenharmony_ci#define MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS (PIN_CONFIG_END + 3) 3962306a36Sopenharmony_ci#define MAX77620_SUSPEND_FPS_SOURCE (PIN_CONFIG_END + 4) 4062306a36Sopenharmony_ci#define MAX77620_SUSPEND_FPS_POWER_ON_SLOTS (PIN_CONFIG_END + 5) 4162306a36Sopenharmony_ci#define MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS (PIN_CONFIG_END + 6) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct max77620_pin_function { 4462306a36Sopenharmony_ci const char *name; 4562306a36Sopenharmony_ci const char * const *groups; 4662306a36Sopenharmony_ci unsigned int ngroups; 4762306a36Sopenharmony_ci int mux_option; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const struct pinconf_generic_params max77620_cfg_params[] = { 5162306a36Sopenharmony_ci { 5262306a36Sopenharmony_ci .property = "maxim,active-fps-source", 5362306a36Sopenharmony_ci .param = MAX77620_ACTIVE_FPS_SOURCE, 5462306a36Sopenharmony_ci }, { 5562306a36Sopenharmony_ci .property = "maxim,active-fps-power-up-slot", 5662306a36Sopenharmony_ci .param = MAX77620_ACTIVE_FPS_POWER_ON_SLOTS, 5762306a36Sopenharmony_ci }, { 5862306a36Sopenharmony_ci .property = "maxim,active-fps-power-down-slot", 5962306a36Sopenharmony_ci .param = MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS, 6062306a36Sopenharmony_ci }, { 6162306a36Sopenharmony_ci .property = "maxim,suspend-fps-source", 6262306a36Sopenharmony_ci .param = MAX77620_SUSPEND_FPS_SOURCE, 6362306a36Sopenharmony_ci }, { 6462306a36Sopenharmony_ci .property = "maxim,suspend-fps-power-up-slot", 6562306a36Sopenharmony_ci .param = MAX77620_SUSPEND_FPS_POWER_ON_SLOTS, 6662306a36Sopenharmony_ci }, { 6762306a36Sopenharmony_ci .property = "maxim,suspend-fps-power-down-slot", 6862306a36Sopenharmony_ci .param = MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS, 6962306a36Sopenharmony_ci }, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cienum max77620_alternate_pinmux_option { 7362306a36Sopenharmony_ci MAX77620_PINMUX_GPIO = 0, 7462306a36Sopenharmony_ci MAX77620_PINMUX_LOW_POWER_MODE_CONTROL_IN = 1, 7562306a36Sopenharmony_ci MAX77620_PINMUX_FLEXIBLE_POWER_SEQUENCER_OUT = 2, 7662306a36Sopenharmony_ci MAX77620_PINMUX_32K_OUT1 = 3, 7762306a36Sopenharmony_ci MAX77620_PINMUX_SD0_DYNAMIC_VOLTAGE_SCALING_IN = 4, 7862306a36Sopenharmony_ci MAX77620_PINMUX_SD1_DYNAMIC_VOLTAGE_SCALING_IN = 5, 7962306a36Sopenharmony_ci MAX77620_PINMUX_REFERENCE_OUT = 6, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct max77620_pingroup { 8362306a36Sopenharmony_ci const char *name; 8462306a36Sopenharmony_ci const unsigned int pins[1]; 8562306a36Sopenharmony_ci unsigned int npins; 8662306a36Sopenharmony_ci enum max77620_alternate_pinmux_option alt_option; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct max77620_pin_info { 9062306a36Sopenharmony_ci enum max77620_pin_ppdrv drv_type; 9162306a36Sopenharmony_ci int pull_config; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct max77620_fps_config { 9562306a36Sopenharmony_ci int active_fps_src; 9662306a36Sopenharmony_ci int active_power_up_slots; 9762306a36Sopenharmony_ci int active_power_down_slots; 9862306a36Sopenharmony_ci int suspend_fps_src; 9962306a36Sopenharmony_ci int suspend_power_up_slots; 10062306a36Sopenharmony_ci int suspend_power_down_slots; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct max77620_pctrl_info { 10462306a36Sopenharmony_ci struct device *dev; 10562306a36Sopenharmony_ci struct pinctrl_dev *pctl; 10662306a36Sopenharmony_ci struct regmap *rmap; 10762306a36Sopenharmony_ci int pins_current_opt[MAX77620_GPIO_NR]; 10862306a36Sopenharmony_ci const struct max77620_pin_function *functions; 10962306a36Sopenharmony_ci unsigned int num_functions; 11062306a36Sopenharmony_ci const struct max77620_pingroup *pin_groups; 11162306a36Sopenharmony_ci int num_pin_groups; 11262306a36Sopenharmony_ci const struct pinctrl_pin_desc *pins; 11362306a36Sopenharmony_ci unsigned int num_pins; 11462306a36Sopenharmony_ci struct max77620_pin_info pin_info[MAX77620_PIN_NUM]; 11562306a36Sopenharmony_ci struct max77620_fps_config fps_config[MAX77620_PIN_NUM]; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const struct pinctrl_pin_desc max77620_pins_desc[] = { 11962306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO0, "gpio0"), 12062306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO1, "gpio1"), 12162306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO2, "gpio2"), 12262306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO3, "gpio3"), 12362306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO4, "gpio4"), 12462306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO5, "gpio5"), 12562306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO6, "gpio6"), 12662306a36Sopenharmony_ci PINCTRL_PIN(MAX77620_GPIO7, "gpio7"), 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const char * const gpio_groups[] = { 13062306a36Sopenharmony_ci "gpio0", 13162306a36Sopenharmony_ci "gpio1", 13262306a36Sopenharmony_ci "gpio2", 13362306a36Sopenharmony_ci "gpio3", 13462306a36Sopenharmony_ci "gpio4", 13562306a36Sopenharmony_ci "gpio5", 13662306a36Sopenharmony_ci "gpio6", 13762306a36Sopenharmony_ci "gpio7", 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define FUNCTION_GROUP(fname, mux) \ 14162306a36Sopenharmony_ci { \ 14262306a36Sopenharmony_ci .name = fname, \ 14362306a36Sopenharmony_ci .groups = gpio_groups, \ 14462306a36Sopenharmony_ci .ngroups = ARRAY_SIZE(gpio_groups), \ 14562306a36Sopenharmony_ci .mux_option = MAX77620_PINMUX_##mux, \ 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic const struct max77620_pin_function max77620_pin_function[] = { 14962306a36Sopenharmony_ci FUNCTION_GROUP("gpio", GPIO), 15062306a36Sopenharmony_ci FUNCTION_GROUP("lpm-control-in", LOW_POWER_MODE_CONTROL_IN), 15162306a36Sopenharmony_ci FUNCTION_GROUP("fps-out", FLEXIBLE_POWER_SEQUENCER_OUT), 15262306a36Sopenharmony_ci FUNCTION_GROUP("32k-out1", 32K_OUT1), 15362306a36Sopenharmony_ci FUNCTION_GROUP("sd0-dvs-in", SD0_DYNAMIC_VOLTAGE_SCALING_IN), 15462306a36Sopenharmony_ci FUNCTION_GROUP("sd1-dvs-in", SD1_DYNAMIC_VOLTAGE_SCALING_IN), 15562306a36Sopenharmony_ci FUNCTION_GROUP("reference-out", REFERENCE_OUT), 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define MAX77620_PINGROUP(pg_name, pin_id, option) \ 15962306a36Sopenharmony_ci { \ 16062306a36Sopenharmony_ci .name = #pg_name, \ 16162306a36Sopenharmony_ci .pins = {MAX77620_##pin_id}, \ 16262306a36Sopenharmony_ci .npins = 1, \ 16362306a36Sopenharmony_ci .alt_option = MAX77620_PINMUX_##option, \ 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic const struct max77620_pingroup max77620_pingroups[] = { 16762306a36Sopenharmony_ci MAX77620_PINGROUP(gpio0, GPIO0, LOW_POWER_MODE_CONTROL_IN), 16862306a36Sopenharmony_ci MAX77620_PINGROUP(gpio1, GPIO1, FLEXIBLE_POWER_SEQUENCER_OUT), 16962306a36Sopenharmony_ci MAX77620_PINGROUP(gpio2, GPIO2, FLEXIBLE_POWER_SEQUENCER_OUT), 17062306a36Sopenharmony_ci MAX77620_PINGROUP(gpio3, GPIO3, FLEXIBLE_POWER_SEQUENCER_OUT), 17162306a36Sopenharmony_ci MAX77620_PINGROUP(gpio4, GPIO4, 32K_OUT1), 17262306a36Sopenharmony_ci MAX77620_PINGROUP(gpio5, GPIO5, SD0_DYNAMIC_VOLTAGE_SCALING_IN), 17362306a36Sopenharmony_ci MAX77620_PINGROUP(gpio6, GPIO6, SD1_DYNAMIC_VOLTAGE_SCALING_IN), 17462306a36Sopenharmony_ci MAX77620_PINGROUP(gpio7, GPIO7, REFERENCE_OUT), 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int max77620_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return mpci->num_pin_groups; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic const char *max77620_pinctrl_get_group_name( 18562306a36Sopenharmony_ci struct pinctrl_dev *pctldev, unsigned int group) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return mpci->pin_groups[group].name; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int max77620_pinctrl_get_group_pins( 19362306a36Sopenharmony_ci struct pinctrl_dev *pctldev, unsigned int group, 19462306a36Sopenharmony_ci const unsigned int **pins, unsigned int *num_pins) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci *pins = mpci->pin_groups[group].pins; 19962306a36Sopenharmony_ci *num_pins = mpci->pin_groups[group].npins; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const struct pinctrl_ops max77620_pinctrl_ops = { 20562306a36Sopenharmony_ci .get_groups_count = max77620_pinctrl_get_groups_count, 20662306a36Sopenharmony_ci .get_group_name = max77620_pinctrl_get_group_name, 20762306a36Sopenharmony_ci .get_group_pins = max77620_pinctrl_get_group_pins, 20862306a36Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, 20962306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 21062306a36Sopenharmony_ci}; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int max77620_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return mpci->num_functions; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic const char *max77620_pinctrl_get_func_name(struct pinctrl_dev *pctldev, 22062306a36Sopenharmony_ci unsigned int function) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return mpci->functions[function].name; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int max77620_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, 22862306a36Sopenharmony_ci unsigned int function, 22962306a36Sopenharmony_ci const char * const **groups, 23062306a36Sopenharmony_ci unsigned int * const num_groups) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci *groups = mpci->functions[function].groups; 23562306a36Sopenharmony_ci *num_groups = mpci->functions[function].ngroups; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int max77620_pinctrl_enable(struct pinctrl_dev *pctldev, 24162306a36Sopenharmony_ci unsigned int function, unsigned int group) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 24462306a36Sopenharmony_ci u8 val; 24562306a36Sopenharmony_ci int ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (function == MAX77620_PINMUX_GPIO) { 24862306a36Sopenharmony_ci val = 0; 24962306a36Sopenharmony_ci } else if (function == mpci->pin_groups[group].alt_option) { 25062306a36Sopenharmony_ci val = 1 << group; 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci dev_err(mpci->dev, "GPIO %u doesn't have function %u\n", 25362306a36Sopenharmony_ci group, function); 25462306a36Sopenharmony_ci return -EINVAL; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, MAX77620_REG_AME_GPIO, 25762306a36Sopenharmony_ci BIT(group), val); 25862306a36Sopenharmony_ci if (ret < 0) 25962306a36Sopenharmony_ci dev_err(mpci->dev, "REG AME GPIO update failed: %d\n", ret); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic const struct pinmux_ops max77620_pinmux_ops = { 26562306a36Sopenharmony_ci .get_functions_count = max77620_pinctrl_get_funcs_count, 26662306a36Sopenharmony_ci .get_function_name = max77620_pinctrl_get_func_name, 26762306a36Sopenharmony_ci .get_function_groups = max77620_pinctrl_get_func_groups, 26862306a36Sopenharmony_ci .set_mux = max77620_pinctrl_enable, 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int max77620_pinconf_get(struct pinctrl_dev *pctldev, 27262306a36Sopenharmony_ci unsigned int pin, unsigned long *config) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 27562306a36Sopenharmony_ci struct device *dev = mpci->dev; 27662306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 27762306a36Sopenharmony_ci unsigned int val; 27862306a36Sopenharmony_ci int arg = 0; 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci switch (param) { 28262306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 28362306a36Sopenharmony_ci if (mpci->pin_info[pin].drv_type == MAX77620_PIN_OD_DRV) 28462306a36Sopenharmony_ci arg = 1; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 28862306a36Sopenharmony_ci if (mpci->pin_info[pin].drv_type == MAX77620_PIN_PP_DRV) 28962306a36Sopenharmony_ci arg = 1; 29062306a36Sopenharmony_ci break; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 29362306a36Sopenharmony_ci ret = regmap_read(mpci->rmap, MAX77620_REG_PUE_GPIO, &val); 29462306a36Sopenharmony_ci if (ret < 0) { 29562306a36Sopenharmony_ci dev_err(dev, "Reg PUE_GPIO read failed: %d\n", ret); 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci if (val & BIT(pin)) 29962306a36Sopenharmony_ci arg = 1; 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 30362306a36Sopenharmony_ci ret = regmap_read(mpci->rmap, MAX77620_REG_PDE_GPIO, &val); 30462306a36Sopenharmony_ci if (ret < 0) { 30562306a36Sopenharmony_ci dev_err(dev, "Reg PDE_GPIO read failed: %d\n", ret); 30662306a36Sopenharmony_ci return ret; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci if (val & BIT(pin)) 30962306a36Sopenharmony_ci arg = 1; 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci default: 31362306a36Sopenharmony_ci dev_err(dev, "Properties not supported\n"); 31462306a36Sopenharmony_ci return -ENOTSUPP; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, (u16)arg); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int max77620_get_default_fps(struct max77620_pctrl_info *mpci, 32362306a36Sopenharmony_ci int addr, int *fps) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci unsigned int val; 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = regmap_read(mpci->rmap, addr, &val); 32962306a36Sopenharmony_ci if (ret < 0) { 33062306a36Sopenharmony_ci dev_err(mpci->dev, "Reg PUE_GPIO read failed: %d\n", ret); 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci *fps = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int max77620_set_fps_param(struct max77620_pctrl_info *mpci, 33962306a36Sopenharmony_ci int pin, int param) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct max77620_fps_config *fps_config = &mpci->fps_config[pin]; 34262306a36Sopenharmony_ci int addr, ret; 34362306a36Sopenharmony_ci int param_val; 34462306a36Sopenharmony_ci int mask, shift; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3)) 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci addr = MAX77620_REG_FPS_GPIO1 + pin - 1; 35062306a36Sopenharmony_ci switch (param) { 35162306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_SOURCE: 35262306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_SOURCE: 35362306a36Sopenharmony_ci mask = MAX77620_FPS_SRC_MASK; 35462306a36Sopenharmony_ci shift = MAX77620_FPS_SRC_SHIFT; 35562306a36Sopenharmony_ci param_val = fps_config->active_fps_src; 35662306a36Sopenharmony_ci if (param == MAX77620_SUSPEND_FPS_SOURCE) 35762306a36Sopenharmony_ci param_val = fps_config->suspend_fps_src; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS: 36162306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS: 36262306a36Sopenharmony_ci mask = MAX77620_FPS_PU_PERIOD_MASK; 36362306a36Sopenharmony_ci shift = MAX77620_FPS_PU_PERIOD_SHIFT; 36462306a36Sopenharmony_ci param_val = fps_config->active_power_up_slots; 36562306a36Sopenharmony_ci if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS) 36662306a36Sopenharmony_ci param_val = fps_config->suspend_power_up_slots; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS: 37062306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS: 37162306a36Sopenharmony_ci mask = MAX77620_FPS_PD_PERIOD_MASK; 37262306a36Sopenharmony_ci shift = MAX77620_FPS_PD_PERIOD_SHIFT; 37362306a36Sopenharmony_ci param_val = fps_config->active_power_down_slots; 37462306a36Sopenharmony_ci if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS) 37562306a36Sopenharmony_ci param_val = fps_config->suspend_power_down_slots; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci default: 37962306a36Sopenharmony_ci dev_err(mpci->dev, "Invalid parameter %d for pin %d\n", 38062306a36Sopenharmony_ci param, pin); 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (param_val < 0) 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift); 38862306a36Sopenharmony_ci if (ret < 0) 38962306a36Sopenharmony_ci dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return ret; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int max77620_pinconf_set(struct pinctrl_dev *pctldev, 39562306a36Sopenharmony_ci unsigned int pin, unsigned long *configs, 39662306a36Sopenharmony_ci unsigned int num_configs) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = pinctrl_dev_get_drvdata(pctldev); 39962306a36Sopenharmony_ci struct device *dev = mpci->dev; 40062306a36Sopenharmony_ci struct max77620_fps_config *fps_config; 40162306a36Sopenharmony_ci int param; 40262306a36Sopenharmony_ci u32 param_val; 40362306a36Sopenharmony_ci unsigned int val; 40462306a36Sopenharmony_ci unsigned int pu_val; 40562306a36Sopenharmony_ci unsigned int pd_val; 40662306a36Sopenharmony_ci int addr, ret; 40762306a36Sopenharmony_ci int i; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 41062306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 41162306a36Sopenharmony_ci param_val = pinconf_to_config_argument(configs[i]); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci switch (param) { 41462306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 41562306a36Sopenharmony_ci val = param_val ? 0 : 1; 41662306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, 41762306a36Sopenharmony_ci MAX77620_REG_GPIO0 + pin, 41862306a36Sopenharmony_ci MAX77620_CNFG_GPIO_DRV_MASK, 41962306a36Sopenharmony_ci val); 42062306a36Sopenharmony_ci if (ret) 42162306a36Sopenharmony_ci goto report_update_failure; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci mpci->pin_info[pin].drv_type = val ? 42462306a36Sopenharmony_ci MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV; 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 42862306a36Sopenharmony_ci val = param_val ? 1 : 0; 42962306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, 43062306a36Sopenharmony_ci MAX77620_REG_GPIO0 + pin, 43162306a36Sopenharmony_ci MAX77620_CNFG_GPIO_DRV_MASK, 43262306a36Sopenharmony_ci val); 43362306a36Sopenharmony_ci if (ret) 43462306a36Sopenharmony_ci goto report_update_failure; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci mpci->pin_info[pin].drv_type = val ? 43762306a36Sopenharmony_ci MAX77620_PIN_PP_DRV : MAX77620_PIN_OD_DRV; 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_SOURCE: 44162306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS: 44262306a36Sopenharmony_ci case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS: 44362306a36Sopenharmony_ci if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3)) 44462306a36Sopenharmony_ci return -EINVAL; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci fps_config = &mpci->fps_config[pin]; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if ((param == MAX77620_ACTIVE_FPS_SOURCE) && 44962306a36Sopenharmony_ci (param_val == MAX77620_FPS_SRC_DEF)) { 45062306a36Sopenharmony_ci addr = MAX77620_REG_FPS_GPIO1 + pin - 1; 45162306a36Sopenharmony_ci ret = max77620_get_default_fps( 45262306a36Sopenharmony_ci mpci, addr, 45362306a36Sopenharmony_ci &fps_config->active_fps_src); 45462306a36Sopenharmony_ci if (ret < 0) 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (param == MAX77620_ACTIVE_FPS_SOURCE) 46062306a36Sopenharmony_ci fps_config->active_fps_src = param_val; 46162306a36Sopenharmony_ci else if (param == MAX77620_ACTIVE_FPS_POWER_ON_SLOTS) 46262306a36Sopenharmony_ci fps_config->active_power_up_slots = param_val; 46362306a36Sopenharmony_ci else 46462306a36Sopenharmony_ci fps_config->active_power_down_slots = param_val; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ret = max77620_set_fps_param(mpci, pin, param); 46762306a36Sopenharmony_ci if (ret < 0) 46862306a36Sopenharmony_ci return ret; 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_SOURCE: 47262306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS: 47362306a36Sopenharmony_ci case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS: 47462306a36Sopenharmony_ci if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3)) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci fps_config = &mpci->fps_config[pin]; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if ((param == MAX77620_SUSPEND_FPS_SOURCE) && 48062306a36Sopenharmony_ci (param_val == MAX77620_FPS_SRC_DEF)) { 48162306a36Sopenharmony_ci addr = MAX77620_REG_FPS_GPIO1 + pin - 1; 48262306a36Sopenharmony_ci ret = max77620_get_default_fps( 48362306a36Sopenharmony_ci mpci, addr, 48462306a36Sopenharmony_ci &fps_config->suspend_fps_src); 48562306a36Sopenharmony_ci if (ret < 0) 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (param == MAX77620_SUSPEND_FPS_SOURCE) 49162306a36Sopenharmony_ci fps_config->suspend_fps_src = param_val; 49262306a36Sopenharmony_ci else if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS) 49362306a36Sopenharmony_ci fps_config->suspend_power_up_slots = param_val; 49462306a36Sopenharmony_ci else 49562306a36Sopenharmony_ci fps_config->suspend_power_down_slots = 49662306a36Sopenharmony_ci param_val; 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 50062306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 50162306a36Sopenharmony_ci pu_val = (param == PIN_CONFIG_BIAS_PULL_UP) ? 50262306a36Sopenharmony_ci BIT(pin) : 0; 50362306a36Sopenharmony_ci pd_val = (param == PIN_CONFIG_BIAS_PULL_DOWN) ? 50462306a36Sopenharmony_ci BIT(pin) : 0; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, 50762306a36Sopenharmony_ci MAX77620_REG_PUE_GPIO, 50862306a36Sopenharmony_ci BIT(pin), pu_val); 50962306a36Sopenharmony_ci if (ret < 0) { 51062306a36Sopenharmony_ci dev_err(dev, "PUE_GPIO update failed: %d\n", 51162306a36Sopenharmony_ci ret); 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci ret = regmap_update_bits(mpci->rmap, 51662306a36Sopenharmony_ci MAX77620_REG_PDE_GPIO, 51762306a36Sopenharmony_ci BIT(pin), pd_val); 51862306a36Sopenharmony_ci if (ret < 0) { 51962306a36Sopenharmony_ci dev_err(dev, "PDE_GPIO update failed: %d\n", 52062306a36Sopenharmony_ci ret); 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci default: 52662306a36Sopenharmony_ci dev_err(dev, "Properties not supported\n"); 52762306a36Sopenharmony_ci return -ENOTSUPP; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cireport_update_failure: 53462306a36Sopenharmony_ci dev_err(dev, "Reg 0x%02x update failed %d\n", 53562306a36Sopenharmony_ci MAX77620_REG_GPIO0 + pin, ret); 53662306a36Sopenharmony_ci return ret; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic const struct pinconf_ops max77620_pinconf_ops = { 54062306a36Sopenharmony_ci .pin_config_get = max77620_pinconf_get, 54162306a36Sopenharmony_ci .pin_config_set = max77620_pinconf_set, 54262306a36Sopenharmony_ci}; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic struct pinctrl_desc max77620_pinctrl_desc = { 54562306a36Sopenharmony_ci .pctlops = &max77620_pinctrl_ops, 54662306a36Sopenharmony_ci .pmxops = &max77620_pinmux_ops, 54762306a36Sopenharmony_ci .confops = &max77620_pinconf_ops, 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int max77620_pinctrl_probe(struct platform_device *pdev) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct max77620_chip *max77620 = dev_get_drvdata(pdev->dev.parent); 55362306a36Sopenharmony_ci struct max77620_pctrl_info *mpci; 55462306a36Sopenharmony_ci int i; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent)); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci mpci = devm_kzalloc(&pdev->dev, sizeof(*mpci), GFP_KERNEL); 55962306a36Sopenharmony_ci if (!mpci) 56062306a36Sopenharmony_ci return -ENOMEM; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci mpci->dev = &pdev->dev; 56362306a36Sopenharmony_ci mpci->rmap = max77620->rmap; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci mpci->pins = max77620_pins_desc; 56662306a36Sopenharmony_ci mpci->num_pins = ARRAY_SIZE(max77620_pins_desc); 56762306a36Sopenharmony_ci mpci->functions = max77620_pin_function; 56862306a36Sopenharmony_ci mpci->num_functions = ARRAY_SIZE(max77620_pin_function); 56962306a36Sopenharmony_ci mpci->pin_groups = max77620_pingroups; 57062306a36Sopenharmony_ci mpci->num_pin_groups = ARRAY_SIZE(max77620_pingroups); 57162306a36Sopenharmony_ci platform_set_drvdata(pdev, mpci); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci max77620_pinctrl_desc.name = dev_name(&pdev->dev); 57462306a36Sopenharmony_ci max77620_pinctrl_desc.pins = max77620_pins_desc; 57562306a36Sopenharmony_ci max77620_pinctrl_desc.npins = ARRAY_SIZE(max77620_pins_desc); 57662306a36Sopenharmony_ci max77620_pinctrl_desc.num_custom_params = 57762306a36Sopenharmony_ci ARRAY_SIZE(max77620_cfg_params); 57862306a36Sopenharmony_ci max77620_pinctrl_desc.custom_params = max77620_cfg_params; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci for (i = 0; i < MAX77620_PIN_NUM; ++i) { 58162306a36Sopenharmony_ci mpci->fps_config[i].active_fps_src = -1; 58262306a36Sopenharmony_ci mpci->fps_config[i].active_power_up_slots = -1; 58362306a36Sopenharmony_ci mpci->fps_config[i].active_power_down_slots = -1; 58462306a36Sopenharmony_ci mpci->fps_config[i].suspend_fps_src = -1; 58562306a36Sopenharmony_ci mpci->fps_config[i].suspend_power_up_slots = -1; 58662306a36Sopenharmony_ci mpci->fps_config[i].suspend_power_down_slots = -1; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci mpci->pctl = devm_pinctrl_register(&pdev->dev, &max77620_pinctrl_desc, 59062306a36Sopenharmony_ci mpci); 59162306a36Sopenharmony_ci if (IS_ERR(mpci->pctl)) { 59262306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); 59362306a36Sopenharmony_ci return PTR_ERR(mpci->pctl); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 60062306a36Sopenharmony_cistatic int max77620_suspend_fps_param[] = { 60162306a36Sopenharmony_ci MAX77620_SUSPEND_FPS_SOURCE, 60262306a36Sopenharmony_ci MAX77620_SUSPEND_FPS_POWER_ON_SLOTS, 60362306a36Sopenharmony_ci MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS, 60462306a36Sopenharmony_ci}; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int max77620_active_fps_param[] = { 60762306a36Sopenharmony_ci MAX77620_ACTIVE_FPS_SOURCE, 60862306a36Sopenharmony_ci MAX77620_ACTIVE_FPS_POWER_ON_SLOTS, 60962306a36Sopenharmony_ci MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS, 61062306a36Sopenharmony_ci}; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int max77620_pinctrl_suspend(struct device *dev) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = dev_get_drvdata(dev); 61562306a36Sopenharmony_ci int pin, p; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) { 61862306a36Sopenharmony_ci if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3)) 61962306a36Sopenharmony_ci continue; 62062306a36Sopenharmony_ci for (p = 0; p < 3; ++p) 62162306a36Sopenharmony_ci max77620_set_fps_param( 62262306a36Sopenharmony_ci mpci, pin, max77620_suspend_fps_param[p]); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci}; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic int max77620_pinctrl_resume(struct device *dev) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct max77620_pctrl_info *mpci = dev_get_drvdata(dev); 63162306a36Sopenharmony_ci int pin, p; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci for (pin = 0; pin < MAX77620_PIN_NUM; ++pin) { 63462306a36Sopenharmony_ci if ((pin < MAX77620_GPIO1) || (pin > MAX77620_GPIO3)) 63562306a36Sopenharmony_ci continue; 63662306a36Sopenharmony_ci for (p = 0; p < 3; ++p) 63762306a36Sopenharmony_ci max77620_set_fps_param( 63862306a36Sopenharmony_ci mpci, pin, max77620_active_fps_param[p]); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci#endif 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic const struct dev_pm_ops max77620_pinctrl_pm_ops = { 64662306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS( 64762306a36Sopenharmony_ci max77620_pinctrl_suspend, max77620_pinctrl_resume) 64862306a36Sopenharmony_ci}; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic const struct platform_device_id max77620_pinctrl_devtype[] = { 65162306a36Sopenharmony_ci { .name = "max77620-pinctrl", }, 65262306a36Sopenharmony_ci { .name = "max20024-pinctrl", }, 65362306a36Sopenharmony_ci {}, 65462306a36Sopenharmony_ci}; 65562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77620_pinctrl_devtype); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic struct platform_driver max77620_pinctrl_driver = { 65862306a36Sopenharmony_ci .driver = { 65962306a36Sopenharmony_ci .name = "max77620-pinctrl", 66062306a36Sopenharmony_ci .pm = &max77620_pinctrl_pm_ops, 66162306a36Sopenharmony_ci }, 66262306a36Sopenharmony_ci .probe = max77620_pinctrl_probe, 66362306a36Sopenharmony_ci .id_table = max77620_pinctrl_devtype, 66462306a36Sopenharmony_ci}; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cimodule_platform_driver(max77620_pinctrl_driver); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX77620/MAX20024 pin control driver"); 66962306a36Sopenharmony_ciMODULE_AUTHOR("Chaitanya Bandi<bandik@nvidia.com>"); 67062306a36Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>"); 67162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 672