18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 118c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 128c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 138c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <dt-bindings/pinctrl/qcom,pmic-gpio.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "../core.h" 228c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define PMIC_GPIO_ADDRESS_RANGE 0x100 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* type and subtype registers base address offsets */ 278c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_TYPE 0x4 288c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_SUBTYPE 0x5 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* GPIO peripheral type and subtype out_values */ 318c2ecf20Sopenharmony_ci#define PMIC_GPIO_TYPE 0x10 328c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1 338c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5 348c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9 358c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd 368c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIO_LV 0x10 378c2ecf20Sopenharmony_ci#define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define PMIC_MPP_REG_RT_STS 0x10 408c2ecf20Sopenharmony_ci#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* control register base address offsets */ 438c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_CTL 0x40 448c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_DIG_VIN_CTL 0x41 458c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_DIG_PULL_CTL 0x42 468c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL 0x44 478c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_DIG_IN_CTL 0x43 488c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_DIG_OUT_CTL 0x45 498c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_EN_CTL 0x46 508c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL 0x4A 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_MODE_CTL */ 538c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1 548c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1 558c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7 568c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_DIR_SHIFT 4 578c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MODE_DIR_MASK 0x7 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define PMIC_GPIO_MODE_DIGITAL_INPUT 0 608c2ecf20Sopenharmony_ci#define PMIC_GPIO_MODE_DIGITAL_OUTPUT 1 618c2ecf20Sopenharmony_ci#define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT 2 628c2ecf20Sopenharmony_ci#define PMIC_GPIO_MODE_ANALOG_PASS_THRU 3 638c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK 0x3 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_DIG_VIN_CTL */ 668c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_VIN_SHIFT 0 678c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_VIN_MASK 0x7 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_DIG_PULL_CTL */ 708c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_PULL_SHIFT 0 718c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_PULL_MASK 0x7 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PMIC_GPIO_PULL_DOWN 4 748c2ecf20Sopenharmony_ci#define PMIC_GPIO_PULL_DISABLE 5 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */ 778c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_OUTPUT_INVERT 0x80 788c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT 7 798c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK 0xF 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_DIG_IN_CTL */ 828c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN 0x80 838c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK 0x7 848c2ecf20Sopenharmony_ci#define PMIC_GPIO_DIG_IN_DTEST_SEL_MASK 0xf 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_DIG_OUT_CTL */ 878c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0 888c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3 898c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4 908c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Output type - indicates pin should be configured as push-pull, 948c2ecf20Sopenharmony_ci * open drain or open source. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci#define PMIC_GPIO_OUT_BUF_CMOS 0 978c2ecf20Sopenharmony_ci#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1 988c2ecf20Sopenharmony_ci#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_EN_CTL */ 1018c2ecf20Sopenharmony_ci#define PMIC_GPIO_REG_MASTER_EN_SHIFT 7 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define PMIC_GPIO_PHYSICAL_OFFSET 1 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */ 1068c2ecf20Sopenharmony_ci#define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK 0x3 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* Qualcomm specific pin configurations */ 1098c2ecf20Sopenharmony_ci#define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1) 1108c2ecf20Sopenharmony_ci#define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2) 1118c2ecf20Sopenharmony_ci#define PMIC_GPIO_CONF_ATEST (PIN_CONFIG_END + 3) 1128c2ecf20Sopenharmony_ci#define PMIC_GPIO_CONF_ANALOG_PASS (PIN_CONFIG_END + 4) 1138c2ecf20Sopenharmony_ci#define PMIC_GPIO_CONF_DTEST_BUFFER (PIN_CONFIG_END + 5) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* The index of each function in pmic_gpio_functions[] array */ 1168c2ecf20Sopenharmony_cienum pmic_gpio_func_index { 1178c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_NORMAL, 1188c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_PAIRED, 1198c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC1, 1208c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC2, 1218c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC3, 1228c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC4, 1238c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_DTEST1, 1248c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_DTEST2, 1258c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_DTEST3, 1268c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_DTEST4, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/** 1308c2ecf20Sopenharmony_ci * struct pmic_gpio_pad - keep current GPIO settings 1318c2ecf20Sopenharmony_ci * @base: Address base in SPMI device. 1328c2ecf20Sopenharmony_ci * @is_enabled: Set to false when GPIO should be put in high Z state. 1338c2ecf20Sopenharmony_ci * @out_value: Cached pin output value 1348c2ecf20Sopenharmony_ci * @have_buffer: Set to true if GPIO output could be configured in push-pull, 1358c2ecf20Sopenharmony_ci * open-drain or open-source mode. 1368c2ecf20Sopenharmony_ci * @output_enabled: Set to true if GPIO output logic is enabled. 1378c2ecf20Sopenharmony_ci * @input_enabled: Set to true if GPIO input buffer logic is enabled. 1388c2ecf20Sopenharmony_ci * @analog_pass: Set to true if GPIO is in analog-pass-through mode. 1398c2ecf20Sopenharmony_ci * @lv_mv_type: Set to true if GPIO subtype is GPIO_LV(0x10) or GPIO_MV(0x11). 1408c2ecf20Sopenharmony_ci * @num_sources: Number of power-sources supported by this GPIO. 1418c2ecf20Sopenharmony_ci * @power_source: Current power-source used. 1428c2ecf20Sopenharmony_ci * @buffer_type: Push-pull, open-drain or open-source. 1438c2ecf20Sopenharmony_ci * @pullup: Constant current which flow trough GPIO output buffer. 1448c2ecf20Sopenharmony_ci * @strength: No, Low, Medium, High 1458c2ecf20Sopenharmony_ci * @function: See pmic_gpio_functions[] 1468c2ecf20Sopenharmony_ci * @atest: the ATEST selection for GPIO analog-pass-through mode 1478c2ecf20Sopenharmony_ci * @dtest_buffer: the DTEST buffer selection for digital input mode. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistruct pmic_gpio_pad { 1508c2ecf20Sopenharmony_ci u16 base; 1518c2ecf20Sopenharmony_ci bool is_enabled; 1528c2ecf20Sopenharmony_ci bool out_value; 1538c2ecf20Sopenharmony_ci bool have_buffer; 1548c2ecf20Sopenharmony_ci bool output_enabled; 1558c2ecf20Sopenharmony_ci bool input_enabled; 1568c2ecf20Sopenharmony_ci bool analog_pass; 1578c2ecf20Sopenharmony_ci bool lv_mv_type; 1588c2ecf20Sopenharmony_ci unsigned int num_sources; 1598c2ecf20Sopenharmony_ci unsigned int power_source; 1608c2ecf20Sopenharmony_ci unsigned int buffer_type; 1618c2ecf20Sopenharmony_ci unsigned int pullup; 1628c2ecf20Sopenharmony_ci unsigned int strength; 1638c2ecf20Sopenharmony_ci unsigned int function; 1648c2ecf20Sopenharmony_ci unsigned int atest; 1658c2ecf20Sopenharmony_ci unsigned int dtest_buffer; 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistruct pmic_gpio_state { 1698c2ecf20Sopenharmony_ci struct device *dev; 1708c2ecf20Sopenharmony_ci struct regmap *map; 1718c2ecf20Sopenharmony_ci struct pinctrl_dev *ctrl; 1728c2ecf20Sopenharmony_ci struct gpio_chip chip; 1738c2ecf20Sopenharmony_ci struct irq_chip irq; 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic const struct pinconf_generic_params pmic_gpio_bindings[] = { 1778c2ecf20Sopenharmony_ci {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0}, 1788c2ecf20Sopenharmony_ci {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0}, 1798c2ecf20Sopenharmony_ci {"qcom,atest", PMIC_GPIO_CONF_ATEST, 0}, 1808c2ecf20Sopenharmony_ci {"qcom,analog-pass", PMIC_GPIO_CONF_ANALOG_PASS, 0}, 1818c2ecf20Sopenharmony_ci {"qcom,dtest-buffer", PMIC_GPIO_CONF_DTEST_BUFFER, 0}, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 1858c2ecf20Sopenharmony_cistatic const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = { 1868c2ecf20Sopenharmony_ci PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true), 1878c2ecf20Sopenharmony_ci PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true), 1888c2ecf20Sopenharmony_ci PCONFDUMP(PMIC_GPIO_CONF_ATEST, "atest", NULL, true), 1898c2ecf20Sopenharmony_ci PCONFDUMP(PMIC_GPIO_CONF_ANALOG_PASS, "analog-pass", NULL, true), 1908c2ecf20Sopenharmony_ci PCONFDUMP(PMIC_GPIO_CONF_DTEST_BUFFER, "dtest-buffer", NULL, true), 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const char *const pmic_gpio_groups[] = { 1958c2ecf20Sopenharmony_ci "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", 1968c2ecf20Sopenharmony_ci "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", 1978c2ecf20Sopenharmony_ci "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", 1988c2ecf20Sopenharmony_ci "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", 1998c2ecf20Sopenharmony_ci "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic const char *const pmic_gpio_functions[] = { 2038c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_NORMAL] = PMIC_GPIO_FUNC_NORMAL, 2048c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_PAIRED] = PMIC_GPIO_FUNC_PAIRED, 2058c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_FUNC1] = PMIC_GPIO_FUNC_FUNC1, 2068c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_FUNC2] = PMIC_GPIO_FUNC_FUNC2, 2078c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_FUNC3] = PMIC_GPIO_FUNC_FUNC3, 2088c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_FUNC4] = PMIC_GPIO_FUNC_FUNC4, 2098c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_DTEST1] = PMIC_GPIO_FUNC_DTEST1, 2108c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_DTEST2] = PMIC_GPIO_FUNC_DTEST2, 2118c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_DTEST3] = PMIC_GPIO_FUNC_DTEST3, 2128c2ecf20Sopenharmony_ci [PMIC_GPIO_FUNC_INDEX_DTEST4] = PMIC_GPIO_FUNC_DTEST4, 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int pmic_gpio_read(struct pmic_gpio_state *state, 2168c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad, unsigned int addr) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci unsigned int val; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = regmap_read(state->map, pad->base + addr, &val); 2228c2ecf20Sopenharmony_ci if (ret < 0) 2238c2ecf20Sopenharmony_ci dev_err(state->dev, "read 0x%x failed\n", addr); 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci ret = val; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int pmic_gpio_write(struct pmic_gpio_state *state, 2318c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad, unsigned int addr, 2328c2ecf20Sopenharmony_ci unsigned int val) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci int ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci ret = regmap_write(state->map, pad->base + addr, val); 2378c2ecf20Sopenharmony_ci if (ret < 0) 2388c2ecf20Sopenharmony_ci dev_err(state->dev, "write 0x%x failed\n", addr); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci /* Every PIN is a group */ 2468c2ecf20Sopenharmony_ci return pctldev->desc->npins; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev, 2508c2ecf20Sopenharmony_ci unsigned pin) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci return pctldev->desc->pins[pin].name; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin, 2568c2ecf20Sopenharmony_ci const unsigned **pins, unsigned *num_pins) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci *pins = &pctldev->desc->pins[pin].number; 2598c2ecf20Sopenharmony_ci *num_pins = 1; 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic const struct pinctrl_ops pmic_gpio_pinctrl_ops = { 2648c2ecf20Sopenharmony_ci .get_groups_count = pmic_gpio_get_groups_count, 2658c2ecf20Sopenharmony_ci .get_group_name = pmic_gpio_get_group_name, 2668c2ecf20Sopenharmony_ci .get_group_pins = pmic_gpio_get_group_pins, 2678c2ecf20Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_group, 2688c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci return ARRAY_SIZE(pmic_gpio_functions); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev, 2778c2ecf20Sopenharmony_ci unsigned function) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return pmic_gpio_functions[function]; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev, 2838c2ecf20Sopenharmony_ci unsigned function, 2848c2ecf20Sopenharmony_ci const char *const **groups, 2858c2ecf20Sopenharmony_ci unsigned *const num_qgroups) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci *groups = pmic_gpio_groups; 2888c2ecf20Sopenharmony_ci *num_qgroups = pctldev->desc->npins; 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function, 2938c2ecf20Sopenharmony_ci unsigned pin) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 2968c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad; 2978c2ecf20Sopenharmony_ci unsigned int val; 2988c2ecf20Sopenharmony_ci int ret; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (function > PMIC_GPIO_FUNC_INDEX_DTEST4) { 3018c2ecf20Sopenharmony_ci pr_err("function: %d is not defined\n", function); 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci pad = pctldev->desc->pins[pin].drv_data; 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Non-LV/MV subtypes only support 2 special functions, 3088c2ecf20Sopenharmony_ci * offsetting the dtestx function values by 2 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (!pad->lv_mv_type) { 3118c2ecf20Sopenharmony_ci if (function == PMIC_GPIO_FUNC_INDEX_FUNC3 || 3128c2ecf20Sopenharmony_ci function == PMIC_GPIO_FUNC_INDEX_FUNC4) { 3138c2ecf20Sopenharmony_ci pr_err("LV/MV subtype doesn't have func3/func4\n"); 3148c2ecf20Sopenharmony_ci return -EINVAL; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci if (function >= PMIC_GPIO_FUNC_INDEX_DTEST1) 3178c2ecf20Sopenharmony_ci function -= (PMIC_GPIO_FUNC_INDEX_DTEST1 - 3188c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC3); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci pad->function = function; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (pad->analog_pass) 3248c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; 3258c2ecf20Sopenharmony_ci else if (pad->output_enabled && pad->input_enabled) 3268c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; 3278c2ecf20Sopenharmony_ci else if (pad->output_enabled) 3288c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_INPUT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (pad->lv_mv_type) { 3338c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 3348c2ecf20Sopenharmony_ci PMIC_GPIO_REG_MODE_CTL, val); 3358c2ecf20Sopenharmony_ci if (ret < 0) 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci val = pad->atest - 1; 3398c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 3408c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val); 3418c2ecf20Sopenharmony_ci if (ret < 0) 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci val = pad->out_value 3458c2ecf20Sopenharmony_ci << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; 3468c2ecf20Sopenharmony_ci val |= pad->function 3478c2ecf20Sopenharmony_ci & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; 3488c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 3498c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); 3508c2ecf20Sopenharmony_ci if (ret < 0) 3518c2ecf20Sopenharmony_ci return ret; 3528c2ecf20Sopenharmony_ci } else { 3538c2ecf20Sopenharmony_ci val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; 3548c2ecf20Sopenharmony_ci val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 3558c2ecf20Sopenharmony_ci val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); 3588c2ecf20Sopenharmony_ci if (ret < 0) 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct pinmux_ops pmic_gpio_pinmux_ops = { 3688c2ecf20Sopenharmony_ci .get_functions_count = pmic_gpio_get_functions_count, 3698c2ecf20Sopenharmony_ci .get_function_name = pmic_gpio_get_function_name, 3708c2ecf20Sopenharmony_ci .get_function_groups = pmic_gpio_get_function_groups, 3718c2ecf20Sopenharmony_ci .set_mux = pmic_gpio_set_mux, 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int pmic_gpio_config_get(struct pinctrl_dev *pctldev, 3758c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *config) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci unsigned param = pinconf_to_config_param(*config); 3788c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad; 3798c2ecf20Sopenharmony_ci unsigned arg; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci pad = pctldev->desc->pins[pin].drv_data; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci switch (param) { 3848c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 3858c2ecf20Sopenharmony_ci if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS) 3868c2ecf20Sopenharmony_ci return -EINVAL; 3878c2ecf20Sopenharmony_ci arg = 1; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 3908c2ecf20Sopenharmony_ci if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS) 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci arg = 1; 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_SOURCE: 3958c2ecf20Sopenharmony_ci if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci arg = 1; 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 4008c2ecf20Sopenharmony_ci if (pad->pullup != PMIC_GPIO_PULL_DOWN) 4018c2ecf20Sopenharmony_ci return -EINVAL; 4028c2ecf20Sopenharmony_ci arg = 1; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 4058c2ecf20Sopenharmony_ci if (pad->pullup != PMIC_GPIO_PULL_DISABLE) 4068c2ecf20Sopenharmony_ci return -EINVAL; 4078c2ecf20Sopenharmony_ci arg = 1; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 4108c2ecf20Sopenharmony_ci if (pad->pullup != PMIC_GPIO_PULL_UP_30) 4118c2ecf20Sopenharmony_ci return -EINVAL; 4128c2ecf20Sopenharmony_ci arg = 1; 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 4158c2ecf20Sopenharmony_ci if (pad->is_enabled) 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci arg = 1; 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci case PIN_CONFIG_POWER_SOURCE: 4208c2ecf20Sopenharmony_ci arg = pad->power_source; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 4238c2ecf20Sopenharmony_ci if (!pad->input_enabled) 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci arg = 1; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 4288c2ecf20Sopenharmony_ci arg = pad->out_value; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_PULL_UP: 4318c2ecf20Sopenharmony_ci arg = pad->pullup; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_STRENGTH: 4348c2ecf20Sopenharmony_ci arg = pad->strength; 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_ATEST: 4378c2ecf20Sopenharmony_ci arg = pad->atest; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_ANALOG_PASS: 4408c2ecf20Sopenharmony_ci arg = pad->analog_pass; 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_DTEST_BUFFER: 4438c2ecf20Sopenharmony_ci arg = pad->dtest_buffer; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci default: 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 4548c2ecf20Sopenharmony_ci unsigned long *configs, unsigned nconfs) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 4578c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad; 4588c2ecf20Sopenharmony_ci unsigned param, arg; 4598c2ecf20Sopenharmony_ci unsigned int val; 4608c2ecf20Sopenharmony_ci int i, ret; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci pad = pctldev->desc->pins[pin].drv_data; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci pad->is_enabled = true; 4658c2ecf20Sopenharmony_ci for (i = 0; i < nconfs; i++) { 4668c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 4678c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci switch (param) { 4708c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 4718c2ecf20Sopenharmony_ci pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS; 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 4748c2ecf20Sopenharmony_ci if (!pad->have_buffer) 4758c2ecf20Sopenharmony_ci return -EINVAL; 4768c2ecf20Sopenharmony_ci pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_SOURCE: 4798c2ecf20Sopenharmony_ci if (!pad->have_buffer) 4808c2ecf20Sopenharmony_ci return -EINVAL; 4818c2ecf20Sopenharmony_ci pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 4848c2ecf20Sopenharmony_ci pad->pullup = PMIC_GPIO_PULL_DISABLE; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 4878c2ecf20Sopenharmony_ci pad->pullup = PMIC_GPIO_PULL_UP_30; 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 4908c2ecf20Sopenharmony_ci if (arg) 4918c2ecf20Sopenharmony_ci pad->pullup = PMIC_GPIO_PULL_DOWN; 4928c2ecf20Sopenharmony_ci else 4938c2ecf20Sopenharmony_ci pad->pullup = PMIC_GPIO_PULL_DISABLE; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 4968c2ecf20Sopenharmony_ci pad->is_enabled = false; 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case PIN_CONFIG_POWER_SOURCE: 4998c2ecf20Sopenharmony_ci if (arg >= pad->num_sources) 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci pad->power_source = arg; 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 5048c2ecf20Sopenharmony_ci pad->input_enabled = arg ? true : false; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 5078c2ecf20Sopenharmony_ci pad->output_enabled = true; 5088c2ecf20Sopenharmony_ci pad->out_value = arg; 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_PULL_UP: 5118c2ecf20Sopenharmony_ci if (arg > PMIC_GPIO_PULL_UP_1P5_30) 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci pad->pullup = arg; 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_STRENGTH: 5168c2ecf20Sopenharmony_ci if (arg > PMIC_GPIO_STRENGTH_LOW) 5178c2ecf20Sopenharmony_ci return -EINVAL; 5188c2ecf20Sopenharmony_ci pad->strength = arg; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_ATEST: 5218c2ecf20Sopenharmony_ci if (!pad->lv_mv_type || arg > 4) 5228c2ecf20Sopenharmony_ci return -EINVAL; 5238c2ecf20Sopenharmony_ci pad->atest = arg; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_ANALOG_PASS: 5268c2ecf20Sopenharmony_ci if (!pad->lv_mv_type) 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci pad->analog_pass = true; 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci case PMIC_GPIO_CONF_DTEST_BUFFER: 5318c2ecf20Sopenharmony_ci if (arg > 4) 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci pad->dtest_buffer = arg; 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci default: 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val); 5438c2ecf20Sopenharmony_ci if (ret < 0) 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val); 5498c2ecf20Sopenharmony_ci if (ret < 0) 5508c2ecf20Sopenharmony_ci return ret; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT; 5538c2ecf20Sopenharmony_ci val |= pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val); 5568c2ecf20Sopenharmony_ci if (ret < 0) 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (pad->dtest_buffer == 0) { 5608c2ecf20Sopenharmony_ci val = 0; 5618c2ecf20Sopenharmony_ci } else { 5628c2ecf20Sopenharmony_ci if (pad->lv_mv_type) { 5638c2ecf20Sopenharmony_ci val = pad->dtest_buffer - 1; 5648c2ecf20Sopenharmony_ci val |= PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN; 5658c2ecf20Sopenharmony_ci } else { 5668c2ecf20Sopenharmony_ci val = BIT(pad->dtest_buffer - 1); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_IN_CTL, val); 5708c2ecf20Sopenharmony_ci if (ret < 0) 5718c2ecf20Sopenharmony_ci return ret; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (pad->analog_pass) 5748c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; 5758c2ecf20Sopenharmony_ci else if (pad->output_enabled && pad->input_enabled) 5768c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; 5778c2ecf20Sopenharmony_ci else if (pad->output_enabled) 5788c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; 5798c2ecf20Sopenharmony_ci else 5808c2ecf20Sopenharmony_ci val = PMIC_GPIO_MODE_DIGITAL_INPUT; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (pad->lv_mv_type) { 5838c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 5848c2ecf20Sopenharmony_ci PMIC_GPIO_REG_MODE_CTL, val); 5858c2ecf20Sopenharmony_ci if (ret < 0) 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci val = pad->atest - 1; 5898c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 5908c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val); 5918c2ecf20Sopenharmony_ci if (ret < 0) 5928c2ecf20Sopenharmony_ci return ret; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci val = pad->out_value 5958c2ecf20Sopenharmony_ci << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; 5968c2ecf20Sopenharmony_ci val |= pad->function 5978c2ecf20Sopenharmony_ci & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; 5988c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, 5998c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); 6008c2ecf20Sopenharmony_ci if (ret < 0) 6018c2ecf20Sopenharmony_ci return ret; 6028c2ecf20Sopenharmony_ci } else { 6038c2ecf20Sopenharmony_ci val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; 6048c2ecf20Sopenharmony_ci val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 6058c2ecf20Sopenharmony_ci val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); 6088c2ecf20Sopenharmony_ci if (ret < 0) 6098c2ecf20Sopenharmony_ci return ret; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return ret; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, 6208c2ecf20Sopenharmony_ci struct seq_file *s, unsigned pin) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 6238c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad; 6248c2ecf20Sopenharmony_ci int ret, val, function; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci static const char *const biases[] = { 6278c2ecf20Sopenharmony_ci "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", 6288c2ecf20Sopenharmony_ci "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull" 6298c2ecf20Sopenharmony_ci }; 6308c2ecf20Sopenharmony_ci static const char *const buffer_types[] = { 6318c2ecf20Sopenharmony_ci "push-pull", "open-drain", "open-source" 6328c2ecf20Sopenharmony_ci }; 6338c2ecf20Sopenharmony_ci static const char *const strengths[] = { 6348c2ecf20Sopenharmony_ci "no", "high", "medium", "low" 6358c2ecf20Sopenharmony_ci }; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci pad = pctldev->desc->pins[pin].drv_data; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) { 6448c2ecf20Sopenharmony_ci seq_puts(s, " ---"); 6458c2ecf20Sopenharmony_ci } else { 6468c2ecf20Sopenharmony_ci if (pad->input_enabled) { 6478c2ecf20Sopenharmony_ci ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); 6488c2ecf20Sopenharmony_ci if (ret < 0) 6498c2ecf20Sopenharmony_ci return; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; 6528c2ecf20Sopenharmony_ci pad->out_value = ret; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci /* 6558c2ecf20Sopenharmony_ci * For the non-LV/MV subtypes only 2 special functions are 6568c2ecf20Sopenharmony_ci * available, offsetting the dtest function values by 2. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_ci function = pad->function; 6598c2ecf20Sopenharmony_ci if (!pad->lv_mv_type && 6608c2ecf20Sopenharmony_ci pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3) 6618c2ecf20Sopenharmony_ci function += PMIC_GPIO_FUNC_INDEX_DTEST1 - 6628c2ecf20Sopenharmony_ci PMIC_GPIO_FUNC_INDEX_FUNC3; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (pad->analog_pass) 6658c2ecf20Sopenharmony_ci seq_puts(s, " analog-pass"); 6668c2ecf20Sopenharmony_ci else 6678c2ecf20Sopenharmony_ci seq_printf(s, " %-4s", 6688c2ecf20Sopenharmony_ci pad->output_enabled ? "out" : "in"); 6698c2ecf20Sopenharmony_ci seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); 6708c2ecf20Sopenharmony_ci seq_printf(s, " %-7s", pmic_gpio_functions[function]); 6718c2ecf20Sopenharmony_ci seq_printf(s, " vin-%d", pad->power_source); 6728c2ecf20Sopenharmony_ci seq_printf(s, " %-27s", biases[pad->pullup]); 6738c2ecf20Sopenharmony_ci seq_printf(s, " %-10s", buffer_types[pad->buffer_type]); 6748c2ecf20Sopenharmony_ci seq_printf(s, " %-7s", strengths[pad->strength]); 6758c2ecf20Sopenharmony_ci seq_printf(s, " atest-%d", pad->atest); 6768c2ecf20Sopenharmony_ci seq_printf(s, " dtest-%d", pad->dtest_buffer); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic const struct pinconf_ops pmic_gpio_pinconf_ops = { 6818c2ecf20Sopenharmony_ci .is_generic = true, 6828c2ecf20Sopenharmony_ci .pin_config_group_get = pmic_gpio_config_get, 6838c2ecf20Sopenharmony_ci .pin_config_group_set = pmic_gpio_config_set, 6848c2ecf20Sopenharmony_ci .pin_config_group_dbg_show = pmic_gpio_config_dbg_show, 6858c2ecf20Sopenharmony_ci}; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = gpiochip_get_data(chip); 6908c2ecf20Sopenharmony_ci unsigned long config; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return pmic_gpio_config_set(state->ctrl, pin, &config, 1); 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic int pmic_gpio_direction_output(struct gpio_chip *chip, 6988c2ecf20Sopenharmony_ci unsigned pin, int val) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = gpiochip_get_data(chip); 7018c2ecf20Sopenharmony_ci unsigned long config; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return pmic_gpio_config_set(state->ctrl, pin, &config, 1); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int pmic_gpio_get(struct gpio_chip *chip, unsigned pin) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = gpiochip_get_data(chip); 7118c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad; 7128c2ecf20Sopenharmony_ci int ret; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci pad = state->ctrl->desc->pins[pin].drv_data; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!pad->is_enabled) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (pad->input_enabled) { 7208c2ecf20Sopenharmony_ci ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); 7218c2ecf20Sopenharmony_ci if (ret < 0) 7228c2ecf20Sopenharmony_ci return ret; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return !!pad->out_value; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = gpiochip_get_data(chip); 7338c2ecf20Sopenharmony_ci unsigned long config; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci pmic_gpio_config_set(state->ctrl, pin, &config, 1); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic int pmic_gpio_of_xlate(struct gpio_chip *chip, 7418c2ecf20Sopenharmony_ci const struct of_phandle_args *gpio_desc, 7428c2ecf20Sopenharmony_ci u32 *flags) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci if (chip->of_gpio_n_cells < 2) 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (flags) 7488c2ecf20Sopenharmony_ci *flags = gpio_desc->args[1]; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = gpiochip_get_data(chip); 7568c2ecf20Sopenharmony_ci unsigned i; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci for (i = 0; i < chip->ngpio; i++) { 7598c2ecf20Sopenharmony_ci pmic_gpio_config_dbg_show(state->ctrl, s, i); 7608c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic const struct gpio_chip pmic_gpio_gpio_template = { 7658c2ecf20Sopenharmony_ci .direction_input = pmic_gpio_direction_input, 7668c2ecf20Sopenharmony_ci .direction_output = pmic_gpio_direction_output, 7678c2ecf20Sopenharmony_ci .get = pmic_gpio_get, 7688c2ecf20Sopenharmony_ci .set = pmic_gpio_set, 7698c2ecf20Sopenharmony_ci .request = gpiochip_generic_request, 7708c2ecf20Sopenharmony_ci .free = gpiochip_generic_free, 7718c2ecf20Sopenharmony_ci .of_xlate = pmic_gpio_of_xlate, 7728c2ecf20Sopenharmony_ci .dbg_show = pmic_gpio_dbg_show, 7738c2ecf20Sopenharmony_ci}; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic int pmic_gpio_populate(struct pmic_gpio_state *state, 7768c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci int type, subtype, val, dir; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE); 7818c2ecf20Sopenharmony_ci if (type < 0) 7828c2ecf20Sopenharmony_ci return type; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (type != PMIC_GPIO_TYPE) { 7858c2ecf20Sopenharmony_ci dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n", 7868c2ecf20Sopenharmony_ci type, pad->base); 7878c2ecf20Sopenharmony_ci return -ENODEV; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE); 7918c2ecf20Sopenharmony_ci if (subtype < 0) 7928c2ecf20Sopenharmony_ci return subtype; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci switch (subtype) { 7958c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIO_4CH: 7968c2ecf20Sopenharmony_ci pad->have_buffer = true; 7978c2ecf20Sopenharmony_ci fallthrough; 7988c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIOC_4CH: 7998c2ecf20Sopenharmony_ci pad->num_sources = 4; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIO_8CH: 8028c2ecf20Sopenharmony_ci pad->have_buffer = true; 8038c2ecf20Sopenharmony_ci fallthrough; 8048c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIOC_8CH: 8058c2ecf20Sopenharmony_ci pad->num_sources = 8; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIO_LV: 8088c2ecf20Sopenharmony_ci pad->num_sources = 1; 8098c2ecf20Sopenharmony_ci pad->have_buffer = true; 8108c2ecf20Sopenharmony_ci pad->lv_mv_type = true; 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci case PMIC_GPIO_SUBTYPE_GPIO_MV: 8138c2ecf20Sopenharmony_ci pad->num_sources = 2; 8148c2ecf20Sopenharmony_ci pad->have_buffer = true; 8158c2ecf20Sopenharmony_ci pad->lv_mv_type = true; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci default: 8188c2ecf20Sopenharmony_ci dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype); 8198c2ecf20Sopenharmony_ci return -ENODEV; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (pad->lv_mv_type) { 8238c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, 8248c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL); 8258c2ecf20Sopenharmony_ci if (val < 0) 8268c2ecf20Sopenharmony_ci return val; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci pad->out_value = !!(val & PMIC_GPIO_LV_MV_OUTPUT_INVERT); 8298c2ecf20Sopenharmony_ci pad->function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); 8328c2ecf20Sopenharmony_ci if (val < 0) 8338c2ecf20Sopenharmony_ci return val; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK; 8368c2ecf20Sopenharmony_ci } else { 8378c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); 8388c2ecf20Sopenharmony_ci if (val < 0) 8398c2ecf20Sopenharmony_ci return val; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; 8448c2ecf20Sopenharmony_ci dir &= PMIC_GPIO_REG_MODE_DIR_MASK; 8458c2ecf20Sopenharmony_ci pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 8468c2ecf20Sopenharmony_ci pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci switch (dir) { 8508c2ecf20Sopenharmony_ci case PMIC_GPIO_MODE_DIGITAL_INPUT: 8518c2ecf20Sopenharmony_ci pad->input_enabled = true; 8528c2ecf20Sopenharmony_ci pad->output_enabled = false; 8538c2ecf20Sopenharmony_ci break; 8548c2ecf20Sopenharmony_ci case PMIC_GPIO_MODE_DIGITAL_OUTPUT: 8558c2ecf20Sopenharmony_ci pad->input_enabled = false; 8568c2ecf20Sopenharmony_ci pad->output_enabled = true; 8578c2ecf20Sopenharmony_ci break; 8588c2ecf20Sopenharmony_ci case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT: 8598c2ecf20Sopenharmony_ci pad->input_enabled = true; 8608c2ecf20Sopenharmony_ci pad->output_enabled = true; 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci case PMIC_GPIO_MODE_ANALOG_PASS_THRU: 8638c2ecf20Sopenharmony_ci if (!pad->lv_mv_type) 8648c2ecf20Sopenharmony_ci return -ENODEV; 8658c2ecf20Sopenharmony_ci pad->analog_pass = true; 8668c2ecf20Sopenharmony_ci break; 8678c2ecf20Sopenharmony_ci default: 8688c2ecf20Sopenharmony_ci dev_err(state->dev, "unknown GPIO direction\n"); 8698c2ecf20Sopenharmony_ci return -ENODEV; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL); 8738c2ecf20Sopenharmony_ci if (val < 0) 8748c2ecf20Sopenharmony_ci return val; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT; 8778c2ecf20Sopenharmony_ci pad->power_source &= PMIC_GPIO_REG_VIN_MASK; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL); 8808c2ecf20Sopenharmony_ci if (val < 0) 8818c2ecf20Sopenharmony_ci return val; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT; 8848c2ecf20Sopenharmony_ci pad->pullup &= PMIC_GPIO_REG_PULL_MASK; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_IN_CTL); 8878c2ecf20Sopenharmony_ci if (val < 0) 8888c2ecf20Sopenharmony_ci return val; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (pad->lv_mv_type && (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN)) 8918c2ecf20Sopenharmony_ci pad->dtest_buffer = 8928c2ecf20Sopenharmony_ci (val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK) + 1; 8938c2ecf20Sopenharmony_ci else if (!pad->lv_mv_type) 8948c2ecf20Sopenharmony_ci pad->dtest_buffer = ffs(val); 8958c2ecf20Sopenharmony_ci else 8968c2ecf20Sopenharmony_ci pad->dtest_buffer = 0; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL); 8998c2ecf20Sopenharmony_ci if (val < 0) 9008c2ecf20Sopenharmony_ci return val; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; 9038c2ecf20Sopenharmony_ci pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT; 9068c2ecf20Sopenharmony_ci pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (pad->lv_mv_type) { 9098c2ecf20Sopenharmony_ci val = pmic_gpio_read(state, pad, 9108c2ecf20Sopenharmony_ci PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL); 9118c2ecf20Sopenharmony_ci if (val < 0) 9128c2ecf20Sopenharmony_ci return val; 9138c2ecf20Sopenharmony_ci pad->atest = (val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK) + 1; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ 9178c2ecf20Sopenharmony_ci pad->is_enabled = true; 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic int pmic_gpio_domain_translate(struct irq_domain *domain, 9228c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec, 9238c2ecf20Sopenharmony_ci unsigned long *hwirq, 9248c2ecf20Sopenharmony_ci unsigned int *type) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = container_of(domain->host_data, 9278c2ecf20Sopenharmony_ci struct pmic_gpio_state, 9288c2ecf20Sopenharmony_ci chip); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (fwspec->param_count != 2 || 9318c2ecf20Sopenharmony_ci fwspec->param[0] < 1 || fwspec->param[0] > state->chip.ngpio) 9328c2ecf20Sopenharmony_ci return -EINVAL; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci *hwirq = fwspec->param[0] - PMIC_GPIO_PHYSICAL_OFFSET; 9358c2ecf20Sopenharmony_ci *type = fwspec->param[1]; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip, 9418c2ecf20Sopenharmony_ci unsigned int offset) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci return offset + PMIC_GPIO_PHYSICAL_OFFSET; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip, 9478c2ecf20Sopenharmony_ci unsigned int child_hwirq, 9488c2ecf20Sopenharmony_ci unsigned int child_type, 9498c2ecf20Sopenharmony_ci unsigned int *parent_hwirq, 9508c2ecf20Sopenharmony_ci unsigned int *parent_type) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci *parent_hwirq = child_hwirq + 0xc0; 9538c2ecf20Sopenharmony_ci *parent_type = child_type; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic int pmic_gpio_probe(struct platform_device *pdev) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct irq_domain *parent_domain; 9618c2ecf20Sopenharmony_ci struct device_node *parent_node; 9628c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9638c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pindesc; 9648c2ecf20Sopenharmony_ci struct pinctrl_desc *pctrldesc; 9658c2ecf20Sopenharmony_ci struct pmic_gpio_pad *pad, *pads; 9668c2ecf20Sopenharmony_ci struct pmic_gpio_state *state; 9678c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 9688c2ecf20Sopenharmony_ci int ret, npins, i; 9698c2ecf20Sopenharmony_ci u32 reg; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "reg", ®); 9728c2ecf20Sopenharmony_ci if (ret < 0) { 9738c2ecf20Sopenharmony_ci dev_err(dev, "missing base address"); 9748c2ecf20Sopenharmony_ci return ret; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci npins = (uintptr_t) device_get_match_data(&pdev->dev); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 9808c2ecf20Sopenharmony_ci if (!state) 9818c2ecf20Sopenharmony_ci return -ENOMEM; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, state); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci state->dev = &pdev->dev; 9868c2ecf20Sopenharmony_ci state->map = dev_get_regmap(dev->parent, NULL); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); 9898c2ecf20Sopenharmony_ci if (!pindesc) 9908c2ecf20Sopenharmony_ci return -ENOMEM; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL); 9938c2ecf20Sopenharmony_ci if (!pads) 9948c2ecf20Sopenharmony_ci return -ENOMEM; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); 9978c2ecf20Sopenharmony_ci if (!pctrldesc) 9988c2ecf20Sopenharmony_ci return -ENOMEM; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci pctrldesc->pctlops = &pmic_gpio_pinctrl_ops; 10018c2ecf20Sopenharmony_ci pctrldesc->pmxops = &pmic_gpio_pinmux_ops; 10028c2ecf20Sopenharmony_ci pctrldesc->confops = &pmic_gpio_pinconf_ops; 10038c2ecf20Sopenharmony_ci pctrldesc->owner = THIS_MODULE; 10048c2ecf20Sopenharmony_ci pctrldesc->name = dev_name(dev); 10058c2ecf20Sopenharmony_ci pctrldesc->pins = pindesc; 10068c2ecf20Sopenharmony_ci pctrldesc->npins = npins; 10078c2ecf20Sopenharmony_ci pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings); 10088c2ecf20Sopenharmony_ci pctrldesc->custom_params = pmic_gpio_bindings; 10098c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 10108c2ecf20Sopenharmony_ci pctrldesc->custom_conf_items = pmic_conf_items; 10118c2ecf20Sopenharmony_ci#endif 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++, pindesc++) { 10148c2ecf20Sopenharmony_ci pad = &pads[i]; 10158c2ecf20Sopenharmony_ci pindesc->drv_data = pad; 10168c2ecf20Sopenharmony_ci pindesc->number = i; 10178c2ecf20Sopenharmony_ci pindesc->name = pmic_gpio_groups[i]; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci ret = pmic_gpio_populate(state, pad); 10228c2ecf20Sopenharmony_ci if (ret < 0) 10238c2ecf20Sopenharmony_ci return ret; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci state->chip = pmic_gpio_gpio_template; 10278c2ecf20Sopenharmony_ci state->chip.parent = dev; 10288c2ecf20Sopenharmony_ci state->chip.base = -1; 10298c2ecf20Sopenharmony_ci state->chip.ngpio = npins; 10308c2ecf20Sopenharmony_ci state->chip.label = dev_name(dev); 10318c2ecf20Sopenharmony_ci state->chip.of_gpio_n_cells = 2; 10328c2ecf20Sopenharmony_ci state->chip.can_sleep = false; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci state->ctrl = devm_pinctrl_register(dev, pctrldesc, state); 10358c2ecf20Sopenharmony_ci if (IS_ERR(state->ctrl)) 10368c2ecf20Sopenharmony_ci return PTR_ERR(state->ctrl); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci parent_node = of_irq_find_parent(state->dev->of_node); 10398c2ecf20Sopenharmony_ci if (!parent_node) 10408c2ecf20Sopenharmony_ci return -ENXIO; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci parent_domain = irq_find_host(parent_node); 10438c2ecf20Sopenharmony_ci of_node_put(parent_node); 10448c2ecf20Sopenharmony_ci if (!parent_domain) 10458c2ecf20Sopenharmony_ci return -ENXIO; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci state->irq.name = "spmi-gpio", 10488c2ecf20Sopenharmony_ci state->irq.irq_ack = irq_chip_ack_parent, 10498c2ecf20Sopenharmony_ci state->irq.irq_mask = irq_chip_mask_parent, 10508c2ecf20Sopenharmony_ci state->irq.irq_unmask = irq_chip_unmask_parent, 10518c2ecf20Sopenharmony_ci state->irq.irq_set_type = irq_chip_set_type_parent, 10528c2ecf20Sopenharmony_ci state->irq.irq_set_wake = irq_chip_set_wake_parent, 10538c2ecf20Sopenharmony_ci state->irq.flags = IRQCHIP_MASK_ON_SUSPEND, 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci girq = &state->chip.irq; 10568c2ecf20Sopenharmony_ci girq->chip = &state->irq; 10578c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 10588c2ecf20Sopenharmony_ci girq->handler = handle_level_irq; 10598c2ecf20Sopenharmony_ci girq->fwnode = of_node_to_fwnode(state->dev->of_node); 10608c2ecf20Sopenharmony_ci girq->parent_domain = parent_domain; 10618c2ecf20Sopenharmony_ci girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq; 10628c2ecf20Sopenharmony_ci girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell; 10638c2ecf20Sopenharmony_ci girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq; 10648c2ecf20Sopenharmony_ci girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci ret = gpiochip_add_data(&state->chip, state); 10678c2ecf20Sopenharmony_ci if (ret) { 10688c2ecf20Sopenharmony_ci dev_err(state->dev, "can't add gpio chip\n"); 10698c2ecf20Sopenharmony_ci return ret; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* 10738c2ecf20Sopenharmony_ci * For DeviceTree-supported systems, the gpio core checks the 10748c2ecf20Sopenharmony_ci * pinctrl's device node for the "gpio-ranges" property. 10758c2ecf20Sopenharmony_ci * If it is present, it takes care of adding the pin ranges 10768c2ecf20Sopenharmony_ci * for the driver. In this case the driver can skip ahead. 10778c2ecf20Sopenharmony_ci * 10788c2ecf20Sopenharmony_ci * In order to remain compatible with older, existing DeviceTree 10798c2ecf20Sopenharmony_ci * files which don't set the "gpio-ranges" property or systems that 10808c2ecf20Sopenharmony_ci * utilize ACPI the driver has to call gpiochip_add_pin_range(). 10818c2ecf20Sopenharmony_ci */ 10828c2ecf20Sopenharmony_ci if (!of_property_read_bool(dev->of_node, "gpio-ranges")) { 10838c2ecf20Sopenharmony_ci ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, 10848c2ecf20Sopenharmony_ci npins); 10858c2ecf20Sopenharmony_ci if (ret) { 10868c2ecf20Sopenharmony_ci dev_err(dev, "failed to add pin range\n"); 10878c2ecf20Sopenharmony_ci goto err_range; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cierr_range: 10948c2ecf20Sopenharmony_ci gpiochip_remove(&state->chip); 10958c2ecf20Sopenharmony_ci return ret; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int pmic_gpio_remove(struct platform_device *pdev) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct pmic_gpio_state *state = platform_get_drvdata(pdev); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci gpiochip_remove(&state->chip); 11038c2ecf20Sopenharmony_ci return 0; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic const struct of_device_id pmic_gpio_of_match[] = { 11078c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8005-gpio", .data = (void *) 4 }, 11088c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8916-gpio", .data = (void *) 4 }, 11098c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8941-gpio", .data = (void *) 36 }, 11108c2ecf20Sopenharmony_ci /* pm8950 has 8 GPIOs with holes on 3 */ 11118c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8950-gpio", .data = (void *) 8 }, 11128c2ecf20Sopenharmony_ci { .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 }, 11138c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8994-gpio", .data = (void *) 22 }, 11148c2ecf20Sopenharmony_ci { .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 }, 11158c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8998-gpio", .data = (void *) 26 }, 11168c2ecf20Sopenharmony_ci { .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 }, 11178c2ecf20Sopenharmony_ci { .compatible = "qcom,pma8084-gpio", .data = (void *) 22 }, 11188c2ecf20Sopenharmony_ci /* pms405 has 12 GPIOs with holes on 1, 9, and 10 */ 11198c2ecf20Sopenharmony_ci { .compatible = "qcom,pms405-gpio", .data = (void *) 12 }, 11208c2ecf20Sopenharmony_ci /* pm660 has 13 GPIOs with holes on 1, 5, 6, 7, 8 and 10 */ 11218c2ecf20Sopenharmony_ci { .compatible = "qcom,pm660-gpio", .data = (void *) 13 }, 11228c2ecf20Sopenharmony_ci /* pm660l has 12 GPIOs with holes on 1, 2, 10, 11 and 12 */ 11238c2ecf20Sopenharmony_ci { .compatible = "qcom,pm660l-gpio", .data = (void *) 12 }, 11248c2ecf20Sopenharmony_ci /* pm8150 has 10 GPIOs with holes on 2, 5, 7 and 8 */ 11258c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8150-gpio", .data = (void *) 10 }, 11268c2ecf20Sopenharmony_ci /* pm8150b has 12 GPIOs with holes on 3, r and 7 */ 11278c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8150b-gpio", .data = (void *) 12 }, 11288c2ecf20Sopenharmony_ci /* pm8150l has 12 GPIOs with holes on 7 */ 11298c2ecf20Sopenharmony_ci { .compatible = "qcom,pm8150l-gpio", .data = (void *) 12 }, 11308c2ecf20Sopenharmony_ci { .compatible = "qcom,pm6150-gpio", .data = (void *) 10 }, 11318c2ecf20Sopenharmony_ci { .compatible = "qcom,pm6150l-gpio", .data = (void *) 12 }, 11328c2ecf20Sopenharmony_ci { }, 11338c2ecf20Sopenharmony_ci}; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pmic_gpio_of_match); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic struct platform_driver pmic_gpio_driver = { 11388c2ecf20Sopenharmony_ci .driver = { 11398c2ecf20Sopenharmony_ci .name = "qcom-spmi-gpio", 11408c2ecf20Sopenharmony_ci .of_match_table = pmic_gpio_of_match, 11418c2ecf20Sopenharmony_ci }, 11428c2ecf20Sopenharmony_ci .probe = pmic_gpio_probe, 11438c2ecf20Sopenharmony_ci .remove = pmic_gpio_remove, 11448c2ecf20Sopenharmony_ci}; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cimodule_platform_driver(pmic_gpio_driver); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>"); 11498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver"); 11508c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:qcom-spmi-gpio"); 11518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1152