--- zzzz-none-000/linux-4.4.271/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c 2023-04-19 10:22:29.000000000 +0000 @@ -39,6 +39,8 @@ #define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5 #define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9 #define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd +#define PMIC_GPIO_SUBTYPE_GPIO_LV 0x10 +#define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11 #define PMIC_MPP_REG_RT_STS 0x10 #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 @@ -47,8 +49,10 @@ #define PMIC_GPIO_REG_MODE_CTL 0x40 #define PMIC_GPIO_REG_DIG_VIN_CTL 0x41 #define PMIC_GPIO_REG_DIG_PULL_CTL 0x42 +#define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL 0x44 #define PMIC_GPIO_REG_DIG_OUT_CTL 0x45 #define PMIC_GPIO_REG_EN_CTL 0x46 +#define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL 0x4A /* PMIC_GPIO_REG_MODE_CTL */ #define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1 @@ -57,6 +61,12 @@ #define PMIC_GPIO_REG_MODE_DIR_SHIFT 4 #define PMIC_GPIO_REG_MODE_DIR_MASK 0x7 +#define PMIC_GPIO_MODE_DIGITAL_INPUT 0 +#define PMIC_GPIO_MODE_DIGITAL_OUTPUT 1 +#define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT 2 +#define PMIC_GPIO_MODE_ANALOG_PASS_THRU 3 +#define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK 0x3 + /* PMIC_GPIO_REG_DIG_VIN_CTL */ #define PMIC_GPIO_REG_VIN_SHIFT 0 #define PMIC_GPIO_REG_VIN_MASK 0x7 @@ -68,6 +78,11 @@ #define PMIC_GPIO_PULL_DOWN 4 #define PMIC_GPIO_PULL_DISABLE 5 +/* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */ +#define PMIC_GPIO_LV_MV_OUTPUT_INVERT 0x80 +#define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT 7 +#define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK 0xF + /* PMIC_GPIO_REG_DIG_OUT_CTL */ #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0 #define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3 @@ -87,9 +102,28 @@ #define PMIC_GPIO_PHYSICAL_OFFSET 1 +/* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */ +#define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK 0x3 + /* Qualcomm specific pin configurations */ #define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1) #define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2) +#define PMIC_GPIO_CONF_ATEST (PIN_CONFIG_END + 3) +#define PMIC_GPIO_CONF_ANALOG_PASS (PIN_CONFIG_END + 4) + +/* The index of each function in pmic_gpio_functions[] array */ +enum pmic_gpio_func_index { + PMIC_GPIO_FUNC_INDEX_NORMAL, + PMIC_GPIO_FUNC_INDEX_PAIRED, + PMIC_GPIO_FUNC_INDEX_FUNC1, + PMIC_GPIO_FUNC_INDEX_FUNC2, + PMIC_GPIO_FUNC_INDEX_FUNC3, + PMIC_GPIO_FUNC_INDEX_FUNC4, + PMIC_GPIO_FUNC_INDEX_DTEST1, + PMIC_GPIO_FUNC_INDEX_DTEST2, + PMIC_GPIO_FUNC_INDEX_DTEST3, + PMIC_GPIO_FUNC_INDEX_DTEST4, +}; /** * struct pmic_gpio_pad - keep current GPIO settings @@ -101,12 +135,15 @@ * open-drain or open-source mode. * @output_enabled: Set to true if GPIO output logic is enabled. * @input_enabled: Set to true if GPIO input buffer logic is enabled. + * @analog_pass: Set to true if GPIO is in analog-pass-through mode. + * @lv_mv_type: Set to true if GPIO subtype is GPIO_LV(0x10) or GPIO_MV(0x11). * @num_sources: Number of power-sources supported by this GPIO. * @power_source: Current power-source used. * @buffer_type: Push-pull, open-drain or open-source. * @pullup: Constant current which flow trough GPIO output buffer. * @strength: No, Low, Medium, High * @function: See pmic_gpio_functions[] + * @atest: the ATEST selection for GPIO analog-pass-through mode */ struct pmic_gpio_pad { u16 base; @@ -116,12 +153,15 @@ bool have_buffer; bool output_enabled; bool input_enabled; + bool analog_pass; + bool lv_mv_type; unsigned int num_sources; unsigned int power_source; unsigned int buffer_type; unsigned int pullup; unsigned int strength; unsigned int function; + unsigned int atest; }; struct pmic_gpio_state { @@ -134,12 +174,16 @@ static const struct pinconf_generic_params pmic_gpio_bindings[] = { {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0}, {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0}, + {"qcom,atest", PMIC_GPIO_CONF_ATEST, 0}, + {"qcom,analog-pass", PMIC_GPIO_CONF_ANALOG_PASS, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = { PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true), PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true), + PCONFDUMP(PMIC_GPIO_CONF_ATEST, "atest", NULL, true), + PCONFDUMP(PMIC_GPIO_CONF_ANALOG_PASS, "analog-pass", NULL, true), }; #endif @@ -152,10 +196,16 @@ }; static const char *const pmic_gpio_functions[] = { - PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, - PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, - PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, - PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, + [PMIC_GPIO_FUNC_INDEX_NORMAL] = PMIC_GPIO_FUNC_NORMAL, + [PMIC_GPIO_FUNC_INDEX_PAIRED] = PMIC_GPIO_FUNC_PAIRED, + [PMIC_GPIO_FUNC_INDEX_FUNC1] = PMIC_GPIO_FUNC_FUNC1, + [PMIC_GPIO_FUNC_INDEX_FUNC2] = PMIC_GPIO_FUNC_FUNC2, + [PMIC_GPIO_FUNC_INDEX_FUNC3] = PMIC_GPIO_FUNC_FUNC3, + [PMIC_GPIO_FUNC_INDEX_FUNC4] = PMIC_GPIO_FUNC_FUNC4, + [PMIC_GPIO_FUNC_INDEX_DTEST1] = PMIC_GPIO_FUNC_DTEST1, + [PMIC_GPIO_FUNC_INDEX_DTEST2] = PMIC_GPIO_FUNC_DTEST2, + [PMIC_GPIO_FUNC_INDEX_DTEST3] = PMIC_GPIO_FUNC_DTEST3, + [PMIC_GPIO_FUNC_INDEX_DTEST4] = PMIC_GPIO_FUNC_DTEST4, }; static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip) @@ -248,25 +298,67 @@ unsigned int val; int ret; + if (function > PMIC_GPIO_FUNC_INDEX_DTEST4) { + pr_err("function: %d is not defined\n", function); + return -EINVAL; + } + pad = pctldev->desc->pins[pin].drv_data; + /* + * Non-LV/MV subtypes only support 2 special functions, + * offsetting the dtestx function values by 2 + */ + if (!pad->lv_mv_type) { + if (function == PMIC_GPIO_FUNC_INDEX_FUNC3 || + function == PMIC_GPIO_FUNC_INDEX_FUNC4) { + pr_err("LV/MV subtype doesn't have func3/func4\n"); + return -EINVAL; + } + if (function >= PMIC_GPIO_FUNC_INDEX_DTEST1) + function -= (PMIC_GPIO_FUNC_INDEX_DTEST1 - + PMIC_GPIO_FUNC_INDEX_FUNC3); + } pad->function = function; - val = 0; - if (pad->output_enabled) { - if (pad->input_enabled) - val = 2; - else - val = 1; - } + if (pad->analog_pass) + val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; + else if (pad->output_enabled && pad->input_enabled) + val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; + else if (pad->output_enabled) + val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; + else + val = PMIC_GPIO_MODE_DIGITAL_INPUT; - val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + if (pad->lv_mv_type) { + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; - ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); - if (ret < 0) - return ret; + val = pad->atest - 1; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val); + if (ret < 0) + return ret; + + val = pad->out_value + << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; + val |= pad->function + & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); + if (ret < 0) + return ret; + } else { + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + } val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; @@ -342,6 +434,12 @@ case PMIC_GPIO_CONF_STRENGTH: arg = pad->strength; break; + case PMIC_GPIO_CONF_ATEST: + arg = pad->atest; + break; + case PMIC_GPIO_CONF_ANALOG_PASS: + arg = pad->analog_pass; + break; default: return -EINVAL; } @@ -416,6 +514,16 @@ return -EINVAL; pad->strength = arg; break; + case PMIC_GPIO_CONF_ATEST: + if (!pad->lv_mv_type || arg > 4) + return -EINVAL; + pad->atest = arg; + break; + case PMIC_GPIO_CONF_ANALOG_PASS: + if (!pad->lv_mv_type) + return -EINVAL; + pad->analog_pass = true; + break; default: return -EINVAL; } @@ -440,19 +548,46 @@ if (ret < 0) return ret; - val = 0; - if (pad->output_enabled) { - if (pad->input_enabled) - val = 2; - else - val = 1; - } + if (pad->analog_pass) + val = PMIC_GPIO_MODE_ANALOG_PASS_THRU; + else if (pad->output_enabled && pad->input_enabled) + val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT; + else if (pad->output_enabled) + val = PMIC_GPIO_MODE_DIGITAL_OUTPUT; + else + val = PMIC_GPIO_MODE_DIGITAL_INPUT; + + if (pad->lv_mv_type) { + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->atest - 1; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL, val); + if (ret < 0) + return ret; - val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + val = pad->out_value + << PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT; + val |= pad->function + & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; + ret = pmic_gpio_write(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL, val); + if (ret < 0) + return ret; + } else { + val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; + val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; - return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); + if (ret < 0) + return ret; + } + + return ret; } static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, @@ -460,7 +595,7 @@ { struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); struct pmic_gpio_pad *pad; - int ret, val; + int ret, val, function; static const char *const biases[] = { "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", @@ -482,7 +617,6 @@ if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) { seq_puts(s, " ---"); } else { - if (pad->input_enabled) { ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); if (ret < 0) @@ -491,14 +625,28 @@ ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; pad->out_value = ret; } + /* + * For the non-LV/MV subtypes only 2 special functions are + * available, offsetting the dtest function values by 2. + */ + function = pad->function; + if (!pad->lv_mv_type && + pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3) + function += PMIC_GPIO_FUNC_INDEX_DTEST1 - + PMIC_GPIO_FUNC_INDEX_FUNC3; - seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]); + if (pad->analog_pass) + seq_puts(s, " analog-pass"); + else + seq_printf(s, " %-4s", + pad->output_enabled ? "out" : "in"); + seq_printf(s, " %-7s", pmic_gpio_functions[function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %-27s", biases[pad->pullup]); seq_printf(s, " %-10s", buffer_types[pad->buffer_type]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); seq_printf(s, " %-7s", strengths[pad->strength]); + seq_printf(s, " atest-%d", pad->atest); } } @@ -549,7 +697,7 @@ pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; } - return pad->out_value; + return !!pad->out_value; } static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value) @@ -638,40 +786,71 @@ case PMIC_GPIO_SUBTYPE_GPIOC_8CH: pad->num_sources = 8; break; + case PMIC_GPIO_SUBTYPE_GPIO_LV: + pad->num_sources = 1; + pad->have_buffer = true; + pad->lv_mv_type = true; + break; + case PMIC_GPIO_SUBTYPE_GPIO_MV: + pad->num_sources = 2; + pad->have_buffer = true; + pad->lv_mv_type = true; + break; default: dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype); return -ENODEV; } - val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); - if (val < 0) - return val; + if (pad->lv_mv_type) { + val = pmic_gpio_read(state, pad, + PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL); + if (val < 0) + return val; + + pad->out_value = !!(val & PMIC_GPIO_LV_MV_OUTPUT_INVERT); + pad->function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK; + + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); + if (val < 0) + return val; - pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK; + } else { + val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); + if (val < 0) + return val; + + pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; + + dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; + dir &= PMIC_GPIO_REG_MODE_DIR_MASK; + pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; + pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; + } - dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; - dir &= PMIC_GPIO_REG_MODE_DIR_MASK; switch (dir) { - case 0: + case PMIC_GPIO_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; break; - case 1: + case PMIC_GPIO_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; break; - case 2: + case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT: pad->input_enabled = true; pad->output_enabled = true; break; + case PMIC_GPIO_MODE_ANALOG_PASS_THRU: + if (!pad->lv_mv_type) + return -ENODEV; + pad->analog_pass = true; + break; default: dev_err(state->dev, "unknown GPIO direction\n"); return -ENODEV; } - pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; - pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; - val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL); if (val < 0) return val; @@ -686,16 +865,20 @@ pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT; pad->pullup &= PMIC_GPIO_REG_PULL_MASK; - val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL); - if (val < 0) - return val; - pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK; pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT; pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK; + if (pad->lv_mv_type) { + val = pmic_gpio_read(state, pad, + PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL); + if (val < 0) + return val; + pad->atest = (val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK) + 1; + } + /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ pad->is_enabled = true; return 0; @@ -776,7 +959,7 @@ } state->chip = pmic_gpio_gpio_template; - state->chip.dev = dev; + state->chip.parent = dev; state->chip.base = -1; state->chip.ngpio = npins; state->chip.label = dev_name(dev); @@ -833,7 +1016,9 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8916-gpio" }, /* 4 GPIO's */ { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */ + { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */ { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */ + { .compatible = "qcom,spmi-gpio" }, /* Generic */ { }, }; @@ -848,7 +1033,17 @@ .remove = pmic_gpio_remove, }; -module_platform_driver(pmic_gpio_driver); +static int __init pmic_gpio_driver_init(void) +{ + return platform_driver_register(&pmic_gpio_driver); +} +arch_initcall(pmic_gpio_driver_init); + +static void __exit pmic_gpio_driver_exit(void) +{ + platform_driver_unregister(&pmic_gpio_driver); +} +module_exit(pmic_gpio_driver_exit); MODULE_AUTHOR("Ivan T. Ivanov "); MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver");