1eadff302SIvan T. Ivanov /* 2eadff302SIvan T. Ivanov * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. 3eadff302SIvan T. Ivanov * 4eadff302SIvan T. Ivanov * This program is free software; you can redistribute it and/or modify 5eadff302SIvan T. Ivanov * it under the terms of the GNU General Public License version 2 and 6eadff302SIvan T. Ivanov * only version 2 as published by the Free Software Foundation. 7eadff302SIvan T. Ivanov * 8eadff302SIvan T. Ivanov * This program is distributed in the hope that it will be useful, 9eadff302SIvan T. Ivanov * but WITHOUT ANY WARRANTY; without even the implied warranty of 10eadff302SIvan T. Ivanov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11eadff302SIvan T. Ivanov * GNU General Public License for more details. 12eadff302SIvan T. Ivanov */ 13eadff302SIvan T. Ivanov 14eadff302SIvan T. Ivanov #include <linux/gpio.h> 15eadff302SIvan T. Ivanov #include <linux/module.h> 16eadff302SIvan T. Ivanov #include <linux/of.h> 17eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf-generic.h> 18eadff302SIvan T. Ivanov #include <linux/pinctrl/pinconf.h> 19eadff302SIvan T. Ivanov #include <linux/pinctrl/pinmux.h> 20eadff302SIvan T. Ivanov #include <linux/platform_device.h> 21eadff302SIvan T. Ivanov #include <linux/regmap.h> 22eadff302SIvan T. Ivanov #include <linux/slab.h> 23eadff302SIvan T. Ivanov #include <linux/types.h> 24eadff302SIvan T. Ivanov 25eadff302SIvan T. Ivanov #include <dt-bindings/pinctrl/qcom,pmic-gpio.h> 26eadff302SIvan T. Ivanov 27eadff302SIvan T. Ivanov #include "../core.h" 28eadff302SIvan T. Ivanov #include "../pinctrl-utils.h" 29eadff302SIvan T. Ivanov 30eadff302SIvan T. Ivanov #define PMIC_GPIO_ADDRESS_RANGE 0x100 31eadff302SIvan T. Ivanov 32eadff302SIvan T. Ivanov /* type and subtype registers base address offsets */ 33eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_TYPE 0x4 34eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_SUBTYPE 0x5 35eadff302SIvan T. Ivanov 36eadff302SIvan T. Ivanov /* GPIO peripheral type and subtype out_values */ 37eadff302SIvan T. Ivanov #define PMIC_GPIO_TYPE 0x10 38eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1 39eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5 40eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9 41eadff302SIvan T. Ivanov #define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd 42eadff302SIvan T. Ivanov 43eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS 0x10 44eadff302SIvan T. Ivanov #define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1 45eadff302SIvan T. Ivanov 46eadff302SIvan T. Ivanov /* control register base address offsets */ 47eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_CTL 0x40 48eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_VIN_CTL 0x41 49eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_PULL_CTL 0x42 50eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_DIG_OUT_CTL 0x45 51eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_EN_CTL 0x46 52eadff302SIvan T. Ivanov 53eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_MODE_CTL */ 54eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1 55eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1 56eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7 57eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_SHIFT 4 58eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MODE_DIR_MASK 0x7 59eadff302SIvan T. Ivanov 60eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_VIN_CTL */ 61eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_SHIFT 0 62eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_VIN_MASK 0x7 63eadff302SIvan T. Ivanov 64eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_PULL_CTL */ 65eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_SHIFT 0 66eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_PULL_MASK 0x7 67eadff302SIvan T. Ivanov 68eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DOWN 4 69eadff302SIvan T. Ivanov #define PMIC_GPIO_PULL_DISABLE 5 70eadff302SIvan T. Ivanov 71eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_DIG_OUT_CTL */ 72eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0 73eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3 74eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4 75eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3 76eadff302SIvan T. Ivanov 77eadff302SIvan T. Ivanov /* 78eadff302SIvan T. Ivanov * Output type - indicates pin should be configured as push-pull, 79eadff302SIvan T. Ivanov * open drain or open source. 80eadff302SIvan T. Ivanov */ 81eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_CMOS 0 82eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1 83eadff302SIvan T. Ivanov #define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2 84eadff302SIvan T. Ivanov 85eadff302SIvan T. Ivanov /* PMIC_GPIO_REG_EN_CTL */ 86eadff302SIvan T. Ivanov #define PMIC_GPIO_REG_MASTER_EN_SHIFT 7 87eadff302SIvan T. Ivanov 88eadff302SIvan T. Ivanov #define PMIC_GPIO_PHYSICAL_OFFSET 1 89eadff302SIvan T. Ivanov 90eadff302SIvan T. Ivanov /* Qualcomm specific pin configurations */ 91eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1) 92eadff302SIvan T. Ivanov #define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2) 93eadff302SIvan T. Ivanov 94eadff302SIvan T. Ivanov /** 95eadff302SIvan T. Ivanov * struct pmic_gpio_pad - keep current GPIO settings 96eadff302SIvan T. Ivanov * @base: Address base in SPMI device. 97eadff302SIvan T. Ivanov * @irq: IRQ number which this GPIO generate. 98eadff302SIvan T. Ivanov * @is_enabled: Set to false when GPIO should be put in high Z state. 99eadff302SIvan T. Ivanov * @out_value: Cached pin output value 100eadff302SIvan T. Ivanov * @have_buffer: Set to true if GPIO output could be configured in push-pull, 101eadff302SIvan T. Ivanov * open-drain or open-source mode. 102eadff302SIvan T. Ivanov * @output_enabled: Set to true if GPIO output logic is enabled. 103eadff302SIvan T. Ivanov * @input_enabled: Set to true if GPIO input buffer logic is enabled. 104eadff302SIvan T. Ivanov * @num_sources: Number of power-sources supported by this GPIO. 105eadff302SIvan T. Ivanov * @power_source: Current power-source used. 106eadff302SIvan T. Ivanov * @buffer_type: Push-pull, open-drain or open-source. 107eadff302SIvan T. Ivanov * @pullup: Constant current which flow trough GPIO output buffer. 108eadff302SIvan T. Ivanov * @strength: No, Low, Medium, High 109eadff302SIvan T. Ivanov * @function: See pmic_gpio_functions[] 110eadff302SIvan T. Ivanov */ 111eadff302SIvan T. Ivanov struct pmic_gpio_pad { 112eadff302SIvan T. Ivanov u16 base; 113eadff302SIvan T. Ivanov int irq; 114eadff302SIvan T. Ivanov bool is_enabled; 115eadff302SIvan T. Ivanov bool out_value; 116eadff302SIvan T. Ivanov bool have_buffer; 117eadff302SIvan T. Ivanov bool output_enabled; 118eadff302SIvan T. Ivanov bool input_enabled; 119eadff302SIvan T. Ivanov unsigned int num_sources; 120eadff302SIvan T. Ivanov unsigned int power_source; 121eadff302SIvan T. Ivanov unsigned int buffer_type; 122eadff302SIvan T. Ivanov unsigned int pullup; 123eadff302SIvan T. Ivanov unsigned int strength; 124eadff302SIvan T. Ivanov unsigned int function; 125eadff302SIvan T. Ivanov }; 126eadff302SIvan T. Ivanov 127eadff302SIvan T. Ivanov struct pmic_gpio_state { 128eadff302SIvan T. Ivanov struct device *dev; 129eadff302SIvan T. Ivanov struct regmap *map; 130eadff302SIvan T. Ivanov struct pinctrl_dev *ctrl; 131eadff302SIvan T. Ivanov struct gpio_chip chip; 132eadff302SIvan T. Ivanov }; 133eadff302SIvan T. Ivanov 134f684e4acSLinus Walleij static const struct pinconf_generic_params pmic_gpio_bindings[] = { 1357382b623SSoren Brinkmann {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0}, 1367382b623SSoren Brinkmann {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0}, 137eadff302SIvan T. Ivanov }; 138eadff302SIvan T. Ivanov 1394f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS 1407382b623SSoren Brinkmann static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = { 1417382b623SSoren Brinkmann PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true), 1427382b623SSoren Brinkmann PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true), 143eadff302SIvan T. Ivanov }; 1444f06266aSArnd Bergmann #endif 145eadff302SIvan T. Ivanov 146eadff302SIvan T. Ivanov static const char *const pmic_gpio_groups[] = { 147eadff302SIvan T. Ivanov "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", 148eadff302SIvan T. Ivanov "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", 149eadff302SIvan T. Ivanov "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", 150eadff302SIvan T. Ivanov "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", 151eadff302SIvan T. Ivanov "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", 152eadff302SIvan T. Ivanov }; 153eadff302SIvan T. Ivanov 154eadff302SIvan T. Ivanov static const char *const pmic_gpio_functions[] = { 155eadff302SIvan T. Ivanov PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, 156eadff302SIvan T. Ivanov PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, 157eadff302SIvan T. Ivanov PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, 158eadff302SIvan T. Ivanov PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, 159eadff302SIvan T. Ivanov }; 160eadff302SIvan T. Ivanov 161eadff302SIvan T. Ivanov static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip) 162eadff302SIvan T. Ivanov { 163eadff302SIvan T. Ivanov return container_of(chip, struct pmic_gpio_state, chip); 164eadff302SIvan T. Ivanov }; 165eadff302SIvan T. Ivanov 166eadff302SIvan T. Ivanov static int pmic_gpio_read(struct pmic_gpio_state *state, 167eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, unsigned int addr) 168eadff302SIvan T. Ivanov { 169eadff302SIvan T. Ivanov unsigned int val; 170eadff302SIvan T. Ivanov int ret; 171eadff302SIvan T. Ivanov 172eadff302SIvan T. Ivanov ret = regmap_read(state->map, pad->base + addr, &val); 173eadff302SIvan T. Ivanov if (ret < 0) 174eadff302SIvan T. Ivanov dev_err(state->dev, "read 0x%x failed\n", addr); 175eadff302SIvan T. Ivanov else 176eadff302SIvan T. Ivanov ret = val; 177eadff302SIvan T. Ivanov 178eadff302SIvan T. Ivanov return ret; 179eadff302SIvan T. Ivanov } 180eadff302SIvan T. Ivanov 181eadff302SIvan T. Ivanov static int pmic_gpio_write(struct pmic_gpio_state *state, 182eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, unsigned int addr, 183eadff302SIvan T. Ivanov unsigned int val) 184eadff302SIvan T. Ivanov { 185eadff302SIvan T. Ivanov int ret; 186eadff302SIvan T. Ivanov 187eadff302SIvan T. Ivanov ret = regmap_write(state->map, pad->base + addr, val); 188eadff302SIvan T. Ivanov if (ret < 0) 189eadff302SIvan T. Ivanov dev_err(state->dev, "write 0x%x failed\n", addr); 190eadff302SIvan T. Ivanov 191eadff302SIvan T. Ivanov return ret; 192eadff302SIvan T. Ivanov } 193eadff302SIvan T. Ivanov 194eadff302SIvan T. Ivanov static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev) 195eadff302SIvan T. Ivanov { 196eadff302SIvan T. Ivanov /* Every PIN is a group */ 197eadff302SIvan T. Ivanov return pctldev->desc->npins; 198eadff302SIvan T. Ivanov } 199eadff302SIvan T. Ivanov 200eadff302SIvan T. Ivanov static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev, 201eadff302SIvan T. Ivanov unsigned pin) 202eadff302SIvan T. Ivanov { 203eadff302SIvan T. Ivanov return pctldev->desc->pins[pin].name; 204eadff302SIvan T. Ivanov } 205eadff302SIvan T. Ivanov 206eadff302SIvan T. Ivanov static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin, 207eadff302SIvan T. Ivanov const unsigned **pins, unsigned *num_pins) 208eadff302SIvan T. Ivanov { 209eadff302SIvan T. Ivanov *pins = &pctldev->desc->pins[pin].number; 210eadff302SIvan T. Ivanov *num_pins = 1; 211eadff302SIvan T. Ivanov return 0; 212eadff302SIvan T. Ivanov } 213eadff302SIvan T. Ivanov 214eadff302SIvan T. Ivanov static const struct pinctrl_ops pmic_gpio_pinctrl_ops = { 215eadff302SIvan T. Ivanov .get_groups_count = pmic_gpio_get_groups_count, 216eadff302SIvan T. Ivanov .get_group_name = pmic_gpio_get_group_name, 217eadff302SIvan T. Ivanov .get_group_pins = pmic_gpio_get_group_pins, 2187382b623SSoren Brinkmann .dt_node_to_map = pinconf_generic_dt_node_to_map_group, 219eadff302SIvan T. Ivanov .dt_free_map = pinctrl_utils_dt_free_map, 220eadff302SIvan T. Ivanov }; 221eadff302SIvan T. Ivanov 222eadff302SIvan T. Ivanov static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev) 223eadff302SIvan T. Ivanov { 224eadff302SIvan T. Ivanov return ARRAY_SIZE(pmic_gpio_functions); 225eadff302SIvan T. Ivanov } 226eadff302SIvan T. Ivanov 227eadff302SIvan T. Ivanov static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev, 228eadff302SIvan T. Ivanov unsigned function) 229eadff302SIvan T. Ivanov { 230eadff302SIvan T. Ivanov return pmic_gpio_functions[function]; 231eadff302SIvan T. Ivanov } 232eadff302SIvan T. Ivanov 233eadff302SIvan T. Ivanov static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev, 234eadff302SIvan T. Ivanov unsigned function, 235eadff302SIvan T. Ivanov const char *const **groups, 236eadff302SIvan T. Ivanov unsigned *const num_qgroups) 237eadff302SIvan T. Ivanov { 238eadff302SIvan T. Ivanov *groups = pmic_gpio_groups; 239eadff302SIvan T. Ivanov *num_qgroups = pctldev->desc->npins; 240eadff302SIvan T. Ivanov return 0; 241eadff302SIvan T. Ivanov } 242eadff302SIvan T. Ivanov 243eadff302SIvan T. Ivanov static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function, 244eadff302SIvan T. Ivanov unsigned pin) 245eadff302SIvan T. Ivanov { 246eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 247eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 248eadff302SIvan T. Ivanov unsigned int val; 249eadff302SIvan T. Ivanov int ret; 250eadff302SIvan T. Ivanov 251eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data; 252eadff302SIvan T. Ivanov 253eadff302SIvan T. Ivanov pad->function = function; 254eadff302SIvan T. Ivanov 255eadff302SIvan T. Ivanov val = 0; 256eadff302SIvan T. Ivanov if (pad->output_enabled) { 257eadff302SIvan T. Ivanov if (pad->input_enabled) 258eadff302SIvan T. Ivanov val = 2; 259eadff302SIvan T. Ivanov else 260eadff302SIvan T. Ivanov val = 1; 261eadff302SIvan T. Ivanov } 262eadff302SIvan T. Ivanov 263eadff302SIvan T. Ivanov val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 264eadff302SIvan T. Ivanov val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 265eadff302SIvan T. Ivanov 266eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); 267eadff302SIvan T. Ivanov if (ret < 0) 268eadff302SIvan T. Ivanov return ret; 269eadff302SIvan T. Ivanov 270eadff302SIvan T. Ivanov val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT; 271eadff302SIvan T. Ivanov 272eadff302SIvan T. Ivanov return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val); 273eadff302SIvan T. Ivanov } 274eadff302SIvan T. Ivanov 275eadff302SIvan T. Ivanov static const struct pinmux_ops pmic_gpio_pinmux_ops = { 276eadff302SIvan T. Ivanov .get_functions_count = pmic_gpio_get_functions_count, 277eadff302SIvan T. Ivanov .get_function_name = pmic_gpio_get_function_name, 278eadff302SIvan T. Ivanov .get_function_groups = pmic_gpio_get_function_groups, 279eadff302SIvan T. Ivanov .set_mux = pmic_gpio_set_mux, 280eadff302SIvan T. Ivanov }; 281eadff302SIvan T. Ivanov 282eadff302SIvan T. Ivanov static int pmic_gpio_config_get(struct pinctrl_dev *pctldev, 283eadff302SIvan T. Ivanov unsigned int pin, unsigned long *config) 284eadff302SIvan T. Ivanov { 285eadff302SIvan T. Ivanov unsigned param = pinconf_to_config_param(*config); 286eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 287eadff302SIvan T. Ivanov unsigned arg; 288eadff302SIvan T. Ivanov 289eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data; 290eadff302SIvan T. Ivanov 291eadff302SIvan T. Ivanov switch (param) { 292eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_PUSH_PULL: 293eadff302SIvan T. Ivanov arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS; 294eadff302SIvan T. Ivanov break; 295eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_DRAIN: 296eadff302SIvan T. Ivanov arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; 297eadff302SIvan T. Ivanov break; 298eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_SOURCE: 299eadff302SIvan T. Ivanov arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; 300eadff302SIvan T. Ivanov break; 301eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN: 302eadff302SIvan T. Ivanov arg = pad->pullup == PMIC_GPIO_PULL_DOWN; 303eadff302SIvan T. Ivanov break; 304eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE: 305eadff302SIvan T. Ivanov arg = pad->pullup = PMIC_GPIO_PULL_DISABLE; 306eadff302SIvan T. Ivanov break; 307eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP: 308eadff302SIvan T. Ivanov arg = pad->pullup == PMIC_GPIO_PULL_UP_30; 309eadff302SIvan T. Ivanov break; 310eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 311eadff302SIvan T. Ivanov arg = !pad->is_enabled; 312eadff302SIvan T. Ivanov break; 313eadff302SIvan T. Ivanov case PIN_CONFIG_POWER_SOURCE: 314eadff302SIvan T. Ivanov arg = pad->power_source; 315eadff302SIvan T. Ivanov break; 316eadff302SIvan T. Ivanov case PIN_CONFIG_INPUT_ENABLE: 317eadff302SIvan T. Ivanov arg = pad->input_enabled; 318eadff302SIvan T. Ivanov break; 319eadff302SIvan T. Ivanov case PIN_CONFIG_OUTPUT: 320eadff302SIvan T. Ivanov arg = pad->out_value; 321eadff302SIvan T. Ivanov break; 322eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_PULL_UP: 323eadff302SIvan T. Ivanov arg = pad->pullup; 324eadff302SIvan T. Ivanov break; 325eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_STRENGTH: 326eadff302SIvan T. Ivanov arg = pad->strength; 327eadff302SIvan T. Ivanov break; 328eadff302SIvan T. Ivanov default: 329eadff302SIvan T. Ivanov return -EINVAL; 330eadff302SIvan T. Ivanov } 331eadff302SIvan T. Ivanov 332eadff302SIvan T. Ivanov *config = pinconf_to_config_packed(param, arg); 333eadff302SIvan T. Ivanov return 0; 334eadff302SIvan T. Ivanov } 335eadff302SIvan T. Ivanov 336eadff302SIvan T. Ivanov static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 337eadff302SIvan T. Ivanov unsigned long *configs, unsigned nconfs) 338eadff302SIvan T. Ivanov { 339eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 340eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 341eadff302SIvan T. Ivanov unsigned param, arg; 342eadff302SIvan T. Ivanov unsigned int val; 343eadff302SIvan T. Ivanov int i, ret; 344eadff302SIvan T. Ivanov 345eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data; 346eadff302SIvan T. Ivanov 347eadff302SIvan T. Ivanov for (i = 0; i < nconfs; i++) { 348eadff302SIvan T. Ivanov param = pinconf_to_config_param(configs[i]); 349eadff302SIvan T. Ivanov arg = pinconf_to_config_argument(configs[i]); 350eadff302SIvan T. Ivanov 351eadff302SIvan T. Ivanov switch (param) { 352eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_PUSH_PULL: 353eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS; 354eadff302SIvan T. Ivanov break; 355eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_DRAIN: 356eadff302SIvan T. Ivanov if (!pad->have_buffer) 357eadff302SIvan T. Ivanov return -EINVAL; 358eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; 359eadff302SIvan T. Ivanov break; 360eadff302SIvan T. Ivanov case PIN_CONFIG_DRIVE_OPEN_SOURCE: 361eadff302SIvan T. Ivanov if (!pad->have_buffer) 362eadff302SIvan T. Ivanov return -EINVAL; 363eadff302SIvan T. Ivanov pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; 364eadff302SIvan T. Ivanov break; 365eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_DISABLE: 366eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DISABLE; 367eadff302SIvan T. Ivanov break; 368eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_UP: 369eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_UP_30; 370eadff302SIvan T. Ivanov break; 371eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_PULL_DOWN: 372eadff302SIvan T. Ivanov if (arg) 373eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DOWN; 374eadff302SIvan T. Ivanov else 375eadff302SIvan T. Ivanov pad->pullup = PMIC_GPIO_PULL_DISABLE; 376eadff302SIvan T. Ivanov break; 377eadff302SIvan T. Ivanov case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 378eadff302SIvan T. Ivanov pad->is_enabled = false; 379eadff302SIvan T. Ivanov break; 380eadff302SIvan T. Ivanov case PIN_CONFIG_POWER_SOURCE: 381eadff302SIvan T. Ivanov if (arg > pad->num_sources) 382eadff302SIvan T. Ivanov return -EINVAL; 383eadff302SIvan T. Ivanov pad->power_source = arg; 384eadff302SIvan T. Ivanov break; 385eadff302SIvan T. Ivanov case PIN_CONFIG_INPUT_ENABLE: 386eadff302SIvan T. Ivanov pad->input_enabled = arg ? true : false; 387eadff302SIvan T. Ivanov break; 388eadff302SIvan T. Ivanov case PIN_CONFIG_OUTPUT: 389eadff302SIvan T. Ivanov pad->output_enabled = true; 390eadff302SIvan T. Ivanov pad->out_value = arg; 391eadff302SIvan T. Ivanov break; 392eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_PULL_UP: 393eadff302SIvan T. Ivanov if (arg > PMIC_GPIO_PULL_UP_1P5_30) 394eadff302SIvan T. Ivanov return -EINVAL; 395eadff302SIvan T. Ivanov pad->pullup = arg; 396eadff302SIvan T. Ivanov break; 397eadff302SIvan T. Ivanov case PMIC_GPIO_CONF_STRENGTH: 398eadff302SIvan T. Ivanov if (arg > PMIC_GPIO_STRENGTH_LOW) 399eadff302SIvan T. Ivanov return -EINVAL; 400eadff302SIvan T. Ivanov pad->strength = arg; 401eadff302SIvan T. Ivanov break; 402eadff302SIvan T. Ivanov default: 403eadff302SIvan T. Ivanov return -EINVAL; 404eadff302SIvan T. Ivanov } 405eadff302SIvan T. Ivanov } 406eadff302SIvan T. Ivanov 407eadff302SIvan T. Ivanov val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT; 408eadff302SIvan T. Ivanov 409eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val); 410eadff302SIvan T. Ivanov if (ret < 0) 411eadff302SIvan T. Ivanov return ret; 412eadff302SIvan T. Ivanov 413eadff302SIvan T. Ivanov val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT; 414eadff302SIvan T. Ivanov 415eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val); 416eadff302SIvan T. Ivanov if (ret < 0) 417eadff302SIvan T. Ivanov return ret; 418eadff302SIvan T. Ivanov 419eadff302SIvan T. Ivanov val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT; 420eadff302SIvan T. Ivanov val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; 421eadff302SIvan T. Ivanov 422eadff302SIvan T. Ivanov ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val); 423eadff302SIvan T. Ivanov if (ret < 0) 424eadff302SIvan T. Ivanov return ret; 425eadff302SIvan T. Ivanov 426eadff302SIvan T. Ivanov val = 0; 427eadff302SIvan T. Ivanov if (pad->output_enabled) { 428eadff302SIvan T. Ivanov if (pad->input_enabled) 429eadff302SIvan T. Ivanov val = 2; 430eadff302SIvan T. Ivanov else 431eadff302SIvan T. Ivanov val = 1; 432eadff302SIvan T. Ivanov } 433eadff302SIvan T. Ivanov 434eadff302SIvan T. Ivanov val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT; 435eadff302SIvan T. Ivanov val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 436eadff302SIvan T. Ivanov val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 437eadff302SIvan T. Ivanov 438eadff302SIvan T. Ivanov return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val); 439eadff302SIvan T. Ivanov } 440eadff302SIvan T. Ivanov 441eadff302SIvan T. Ivanov static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, 442eadff302SIvan T. Ivanov struct seq_file *s, unsigned pin) 443eadff302SIvan T. Ivanov { 444eadff302SIvan T. Ivanov struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev); 445eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 446eadff302SIvan T. Ivanov int ret, val; 447eadff302SIvan T. Ivanov 448eadff302SIvan T. Ivanov static const char *const biases[] = { 449eadff302SIvan T. Ivanov "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", 450eadff302SIvan T. Ivanov "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull" 451eadff302SIvan T. Ivanov }; 452eadff302SIvan T. Ivanov static const char *const buffer_types[] = { 453eadff302SIvan T. Ivanov "push-pull", "open-drain", "open-source" 454eadff302SIvan T. Ivanov }; 455eadff302SIvan T. Ivanov static const char *const strengths[] = { 456eadff302SIvan T. Ivanov "no", "high", "medium", "low" 457eadff302SIvan T. Ivanov }; 458eadff302SIvan T. Ivanov 459eadff302SIvan T. Ivanov pad = pctldev->desc->pins[pin].drv_data; 460eadff302SIvan T. Ivanov 461eadff302SIvan T. Ivanov seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET); 462eadff302SIvan T. Ivanov 463eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL); 464eadff302SIvan T. Ivanov 465eadff302SIvan T. Ivanov if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) { 466eadff302SIvan T. Ivanov seq_puts(s, " ---"); 467eadff302SIvan T. Ivanov } else { 468eadff302SIvan T. Ivanov 469eadff302SIvan T. Ivanov if (!pad->input_enabled) { 470eadff302SIvan T. Ivanov ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); 471eadff302SIvan T. Ivanov if (!ret) { 472eadff302SIvan T. Ivanov ret &= PMIC_MPP_REG_RT_STS_VAL_MASK; 473eadff302SIvan T. Ivanov pad->out_value = ret; 474eadff302SIvan T. Ivanov } 475eadff302SIvan T. Ivanov } 476eadff302SIvan T. Ivanov 477eadff302SIvan T. Ivanov seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); 478eadff302SIvan T. Ivanov seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]); 479eadff302SIvan T. Ivanov seq_printf(s, " vin-%d", pad->power_source); 480eadff302SIvan T. Ivanov seq_printf(s, " %-27s", biases[pad->pullup]); 481eadff302SIvan T. Ivanov seq_printf(s, " %-10s", buffer_types[pad->buffer_type]); 482eadff302SIvan T. Ivanov seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); 483eadff302SIvan T. Ivanov seq_printf(s, " %-7s", strengths[pad->strength]); 484eadff302SIvan T. Ivanov } 485eadff302SIvan T. Ivanov } 486eadff302SIvan T. Ivanov 487eadff302SIvan T. Ivanov static const struct pinconf_ops pmic_gpio_pinconf_ops = { 4887382b623SSoren Brinkmann .is_generic = true, 489eadff302SIvan T. Ivanov .pin_config_group_get = pmic_gpio_config_get, 490eadff302SIvan T. Ivanov .pin_config_group_set = pmic_gpio_config_set, 491eadff302SIvan T. Ivanov .pin_config_group_dbg_show = pmic_gpio_config_dbg_show, 492eadff302SIvan T. Ivanov }; 493eadff302SIvan T. Ivanov 494eadff302SIvan T. Ivanov static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin) 495eadff302SIvan T. Ivanov { 496eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 497eadff302SIvan T. Ivanov unsigned long config; 498eadff302SIvan T. Ivanov 499eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); 500eadff302SIvan T. Ivanov 501eadff302SIvan T. Ivanov return pmic_gpio_config_set(state->ctrl, pin, &config, 1); 502eadff302SIvan T. Ivanov } 503eadff302SIvan T. Ivanov 504eadff302SIvan T. Ivanov static int pmic_gpio_direction_output(struct gpio_chip *chip, 505eadff302SIvan T. Ivanov unsigned pin, int val) 506eadff302SIvan T. Ivanov { 507eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 508eadff302SIvan T. Ivanov unsigned long config; 509eadff302SIvan T. Ivanov 510eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); 511eadff302SIvan T. Ivanov 512eadff302SIvan T. Ivanov return pmic_gpio_config_set(state->ctrl, pin, &config, 1); 513eadff302SIvan T. Ivanov } 514eadff302SIvan T. Ivanov 515eadff302SIvan T. Ivanov static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin) 516eadff302SIvan T. Ivanov { 517eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 518eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 519eadff302SIvan T. Ivanov int ret; 520eadff302SIvan T. Ivanov 521eadff302SIvan T. Ivanov pad = state->ctrl->desc->pins[pin].drv_data; 522eadff302SIvan T. Ivanov 523eadff302SIvan T. Ivanov if (!pad->is_enabled) 524eadff302SIvan T. Ivanov return -EINVAL; 525eadff302SIvan T. Ivanov 526eadff302SIvan T. Ivanov if (pad->input_enabled) { 527eadff302SIvan T. Ivanov ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS); 528eadff302SIvan T. Ivanov if (ret < 0) 529eadff302SIvan T. Ivanov return ret; 530eadff302SIvan T. Ivanov 531eadff302SIvan T. Ivanov pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK; 532eadff302SIvan T. Ivanov } 533eadff302SIvan T. Ivanov 534eadff302SIvan T. Ivanov return pad->out_value; 535eadff302SIvan T. Ivanov } 536eadff302SIvan T. Ivanov 537eadff302SIvan T. Ivanov static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value) 538eadff302SIvan T. Ivanov { 539eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 540eadff302SIvan T. Ivanov unsigned long config; 541eadff302SIvan T. Ivanov 542eadff302SIvan T. Ivanov config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); 543eadff302SIvan T. Ivanov 544eadff302SIvan T. Ivanov pmic_gpio_config_set(state->ctrl, pin, &config, 1); 545eadff302SIvan T. Ivanov } 546eadff302SIvan T. Ivanov 547eadff302SIvan T. Ivanov static int pmic_gpio_request(struct gpio_chip *chip, unsigned base) 548eadff302SIvan T. Ivanov { 549eadff302SIvan T. Ivanov return pinctrl_request_gpio(chip->base + base); 550eadff302SIvan T. Ivanov } 551eadff302SIvan T. Ivanov 552eadff302SIvan T. Ivanov static void pmic_gpio_free(struct gpio_chip *chip, unsigned base) 553eadff302SIvan T. Ivanov { 554eadff302SIvan T. Ivanov pinctrl_free_gpio(chip->base + base); 555eadff302SIvan T. Ivanov } 556eadff302SIvan T. Ivanov 557eadff302SIvan T. Ivanov static int pmic_gpio_of_xlate(struct gpio_chip *chip, 558eadff302SIvan T. Ivanov const struct of_phandle_args *gpio_desc, 559eadff302SIvan T. Ivanov u32 *flags) 560eadff302SIvan T. Ivanov { 561eadff302SIvan T. Ivanov if (chip->of_gpio_n_cells < 2) 562eadff302SIvan T. Ivanov return -EINVAL; 563eadff302SIvan T. Ivanov 564eadff302SIvan T. Ivanov if (flags) 565eadff302SIvan T. Ivanov *flags = gpio_desc->args[1]; 566eadff302SIvan T. Ivanov 567eadff302SIvan T. Ivanov return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET; 568eadff302SIvan T. Ivanov } 569eadff302SIvan T. Ivanov 570eadff302SIvan T. Ivanov static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin) 571eadff302SIvan T. Ivanov { 572eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 573eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad; 574eadff302SIvan T. Ivanov 575eadff302SIvan T. Ivanov pad = state->ctrl->desc->pins[pin].drv_data; 576eadff302SIvan T. Ivanov 577eadff302SIvan T. Ivanov return pad->irq; 578eadff302SIvan T. Ivanov } 579eadff302SIvan T. Ivanov 580eadff302SIvan T. Ivanov static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 581eadff302SIvan T. Ivanov { 582eadff302SIvan T. Ivanov struct pmic_gpio_state *state = to_gpio_state(chip); 583eadff302SIvan T. Ivanov unsigned i; 584eadff302SIvan T. Ivanov 585eadff302SIvan T. Ivanov for (i = 0; i < chip->ngpio; i++) { 586eadff302SIvan T. Ivanov pmic_gpio_config_dbg_show(state->ctrl, s, i); 587eadff302SIvan T. Ivanov seq_puts(s, "\n"); 588eadff302SIvan T. Ivanov } 589eadff302SIvan T. Ivanov } 590eadff302SIvan T. Ivanov 591eadff302SIvan T. Ivanov static const struct gpio_chip pmic_gpio_gpio_template = { 592eadff302SIvan T. Ivanov .direction_input = pmic_gpio_direction_input, 593eadff302SIvan T. Ivanov .direction_output = pmic_gpio_direction_output, 594eadff302SIvan T. Ivanov .get = pmic_gpio_get, 595eadff302SIvan T. Ivanov .set = pmic_gpio_set, 596eadff302SIvan T. Ivanov .request = pmic_gpio_request, 597eadff302SIvan T. Ivanov .free = pmic_gpio_free, 598eadff302SIvan T. Ivanov .of_xlate = pmic_gpio_of_xlate, 599eadff302SIvan T. Ivanov .to_irq = pmic_gpio_to_irq, 600eadff302SIvan T. Ivanov .dbg_show = pmic_gpio_dbg_show, 601eadff302SIvan T. Ivanov }; 602eadff302SIvan T. Ivanov 603eadff302SIvan T. Ivanov static int pmic_gpio_populate(struct pmic_gpio_state *state, 604eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad) 605eadff302SIvan T. Ivanov { 606eadff302SIvan T. Ivanov int type, subtype, val, dir; 607eadff302SIvan T. Ivanov 608eadff302SIvan T. Ivanov type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE); 609eadff302SIvan T. Ivanov if (type < 0) 610eadff302SIvan T. Ivanov return type; 611eadff302SIvan T. Ivanov 612eadff302SIvan T. Ivanov if (type != PMIC_GPIO_TYPE) { 613eadff302SIvan T. Ivanov dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n", 614eadff302SIvan T. Ivanov type, pad->base); 615eadff302SIvan T. Ivanov return -ENODEV; 616eadff302SIvan T. Ivanov } 617eadff302SIvan T. Ivanov 618eadff302SIvan T. Ivanov subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE); 619eadff302SIvan T. Ivanov if (subtype < 0) 620eadff302SIvan T. Ivanov return subtype; 621eadff302SIvan T. Ivanov 622eadff302SIvan T. Ivanov switch (subtype) { 623eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIO_4CH: 624eadff302SIvan T. Ivanov pad->have_buffer = true; 625eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIOC_4CH: 626eadff302SIvan T. Ivanov pad->num_sources = 4; 627eadff302SIvan T. Ivanov break; 628eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIO_8CH: 629eadff302SIvan T. Ivanov pad->have_buffer = true; 630eadff302SIvan T. Ivanov case PMIC_GPIO_SUBTYPE_GPIOC_8CH: 631eadff302SIvan T. Ivanov pad->num_sources = 8; 632eadff302SIvan T. Ivanov break; 633eadff302SIvan T. Ivanov default: 634eadff302SIvan T. Ivanov dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype); 635eadff302SIvan T. Ivanov return -ENODEV; 636eadff302SIvan T. Ivanov } 637eadff302SIvan T. Ivanov 638eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL); 639eadff302SIvan T. Ivanov if (val < 0) 640eadff302SIvan T. Ivanov return val; 641eadff302SIvan T. Ivanov 642eadff302SIvan T. Ivanov pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT; 643eadff302SIvan T. Ivanov 644eadff302SIvan T. Ivanov dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT; 645eadff302SIvan T. Ivanov dir &= PMIC_GPIO_REG_MODE_DIR_MASK; 646eadff302SIvan T. Ivanov switch (dir) { 647eadff302SIvan T. Ivanov case 0: 648eadff302SIvan T. Ivanov pad->input_enabled = true; 649eadff302SIvan T. Ivanov pad->output_enabled = false; 650eadff302SIvan T. Ivanov break; 651eadff302SIvan T. Ivanov case 1: 652eadff302SIvan T. Ivanov pad->input_enabled = false; 653eadff302SIvan T. Ivanov pad->output_enabled = true; 654eadff302SIvan T. Ivanov break; 655eadff302SIvan T. Ivanov case 2: 656eadff302SIvan T. Ivanov pad->input_enabled = true; 657eadff302SIvan T. Ivanov pad->output_enabled = true; 658eadff302SIvan T. Ivanov break; 659eadff302SIvan T. Ivanov default: 660eadff302SIvan T. Ivanov dev_err(state->dev, "unknown GPIO direction\n"); 661eadff302SIvan T. Ivanov return -ENODEV; 662eadff302SIvan T. Ivanov } 663eadff302SIvan T. Ivanov 664eadff302SIvan T. Ivanov pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT; 665eadff302SIvan T. Ivanov pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK; 666eadff302SIvan T. Ivanov 667eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL); 668eadff302SIvan T. Ivanov if (val < 0) 669eadff302SIvan T. Ivanov return val; 670eadff302SIvan T. Ivanov 671eadff302SIvan T. Ivanov pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT; 672eadff302SIvan T. Ivanov pad->power_source &= PMIC_GPIO_REG_VIN_MASK; 673eadff302SIvan T. Ivanov 674eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL); 675eadff302SIvan T. Ivanov if (val < 0) 676eadff302SIvan T. Ivanov return val; 677eadff302SIvan T. Ivanov 678eadff302SIvan T. Ivanov pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT; 679eadff302SIvan T. Ivanov pad->pullup &= PMIC_GPIO_REG_PULL_MASK; 680eadff302SIvan T. Ivanov 681eadff302SIvan T. Ivanov val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL); 682eadff302SIvan T. Ivanov if (val < 0) 683eadff302SIvan T. Ivanov return val; 684eadff302SIvan T. Ivanov 685eadff302SIvan T. Ivanov pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT; 686eadff302SIvan T. Ivanov pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK; 687eadff302SIvan T. Ivanov 688eadff302SIvan T. Ivanov pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT; 689eadff302SIvan T. Ivanov pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK; 690eadff302SIvan T. Ivanov 691eadff302SIvan T. Ivanov /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ 692eadff302SIvan T. Ivanov pad->is_enabled = true; 693eadff302SIvan T. Ivanov return 0; 694eadff302SIvan T. Ivanov } 695eadff302SIvan T. Ivanov 696eadff302SIvan T. Ivanov static int pmic_gpio_probe(struct platform_device *pdev) 697eadff302SIvan T. Ivanov { 698eadff302SIvan T. Ivanov struct device *dev = &pdev->dev; 699eadff302SIvan T. Ivanov struct pinctrl_pin_desc *pindesc; 700eadff302SIvan T. Ivanov struct pinctrl_desc *pctrldesc; 701eadff302SIvan T. Ivanov struct pmic_gpio_pad *pad, *pads; 702eadff302SIvan T. Ivanov struct pmic_gpio_state *state; 703eadff302SIvan T. Ivanov int ret, npins, i; 704eadff302SIvan T. Ivanov u32 res[2]; 705eadff302SIvan T. Ivanov 706eadff302SIvan T. Ivanov ret = of_property_read_u32_array(dev->of_node, "reg", res, 2); 707eadff302SIvan T. Ivanov if (ret < 0) { 708eadff302SIvan T. Ivanov dev_err(dev, "missing base address and/or range"); 709eadff302SIvan T. Ivanov return ret; 710eadff302SIvan T. Ivanov } 711eadff302SIvan T. Ivanov 712eadff302SIvan T. Ivanov npins = res[1] / PMIC_GPIO_ADDRESS_RANGE; 713eadff302SIvan T. Ivanov 714eadff302SIvan T. Ivanov if (!npins) 715eadff302SIvan T. Ivanov return -EINVAL; 716eadff302SIvan T. Ivanov 717eadff302SIvan T. Ivanov BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups)); 718eadff302SIvan T. Ivanov 719eadff302SIvan T. Ivanov state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 720eadff302SIvan T. Ivanov if (!state) 721eadff302SIvan T. Ivanov return -ENOMEM; 722eadff302SIvan T. Ivanov 723eadff302SIvan T. Ivanov platform_set_drvdata(pdev, state); 724eadff302SIvan T. Ivanov 725eadff302SIvan T. Ivanov state->dev = &pdev->dev; 726eadff302SIvan T. Ivanov state->map = dev_get_regmap(dev->parent, NULL); 727eadff302SIvan T. Ivanov 728eadff302SIvan T. Ivanov pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); 729eadff302SIvan T. Ivanov if (!pindesc) 730eadff302SIvan T. Ivanov return -ENOMEM; 731eadff302SIvan T. Ivanov 732eadff302SIvan T. Ivanov pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL); 733eadff302SIvan T. Ivanov if (!pads) 734eadff302SIvan T. Ivanov return -ENOMEM; 735eadff302SIvan T. Ivanov 736eadff302SIvan T. Ivanov pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); 737eadff302SIvan T. Ivanov if (!pctrldesc) 738eadff302SIvan T. Ivanov return -ENOMEM; 739eadff302SIvan T. Ivanov 740eadff302SIvan T. Ivanov pctrldesc->pctlops = &pmic_gpio_pinctrl_ops; 741eadff302SIvan T. Ivanov pctrldesc->pmxops = &pmic_gpio_pinmux_ops; 742eadff302SIvan T. Ivanov pctrldesc->confops = &pmic_gpio_pinconf_ops; 743eadff302SIvan T. Ivanov pctrldesc->owner = THIS_MODULE; 744eadff302SIvan T. Ivanov pctrldesc->name = dev_name(dev); 745eadff302SIvan T. Ivanov pctrldesc->pins = pindesc; 746eadff302SIvan T. Ivanov pctrldesc->npins = npins; 747f684e4acSLinus Walleij pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings); 748f684e4acSLinus Walleij pctrldesc->custom_params = pmic_gpio_bindings; 7494f06266aSArnd Bergmann #ifdef CONFIG_DEBUG_FS 750f684e4acSLinus Walleij pctrldesc->custom_conf_items = pmic_conf_items; 7514f06266aSArnd Bergmann #endif 752eadff302SIvan T. Ivanov 753eadff302SIvan T. Ivanov for (i = 0; i < npins; i++, pindesc++) { 754eadff302SIvan T. Ivanov pad = &pads[i]; 755eadff302SIvan T. Ivanov pindesc->drv_data = pad; 756eadff302SIvan T. Ivanov pindesc->number = i; 757eadff302SIvan T. Ivanov pindesc->name = pmic_gpio_groups[i]; 758eadff302SIvan T. Ivanov 759eadff302SIvan T. Ivanov pad->irq = platform_get_irq(pdev, i); 760eadff302SIvan T. Ivanov if (pad->irq < 0) 761eadff302SIvan T. Ivanov return pad->irq; 762eadff302SIvan T. Ivanov 763eadff302SIvan T. Ivanov pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE; 764eadff302SIvan T. Ivanov 765eadff302SIvan T. Ivanov ret = pmic_gpio_populate(state, pad); 766eadff302SIvan T. Ivanov if (ret < 0) 767eadff302SIvan T. Ivanov return ret; 768eadff302SIvan T. Ivanov } 769eadff302SIvan T. Ivanov 770eadff302SIvan T. Ivanov state->chip = pmic_gpio_gpio_template; 771eadff302SIvan T. Ivanov state->chip.dev = dev; 772eadff302SIvan T. Ivanov state->chip.base = -1; 773eadff302SIvan T. Ivanov state->chip.ngpio = npins; 774eadff302SIvan T. Ivanov state->chip.label = dev_name(dev); 775eadff302SIvan T. Ivanov state->chip.of_gpio_n_cells = 2; 776eadff302SIvan T. Ivanov state->chip.can_sleep = false; 777eadff302SIvan T. Ivanov 778eadff302SIvan T. Ivanov state->ctrl = pinctrl_register(pctrldesc, dev, state); 779eadff302SIvan T. Ivanov if (!state->ctrl) 780eadff302SIvan T. Ivanov return -ENODEV; 781eadff302SIvan T. Ivanov 782eadff302SIvan T. Ivanov ret = gpiochip_add(&state->chip); 783eadff302SIvan T. Ivanov if (ret) { 784eadff302SIvan T. Ivanov dev_err(state->dev, "can't add gpio chip\n"); 785eadff302SIvan T. Ivanov goto err_chip; 786eadff302SIvan T. Ivanov } 787eadff302SIvan T. Ivanov 788eadff302SIvan T. Ivanov ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); 789eadff302SIvan T. Ivanov if (ret) { 790eadff302SIvan T. Ivanov dev_err(dev, "failed to add pin range\n"); 791eadff302SIvan T. Ivanov goto err_range; 792eadff302SIvan T. Ivanov } 793eadff302SIvan T. Ivanov 794eadff302SIvan T. Ivanov return 0; 795eadff302SIvan T. Ivanov 796eadff302SIvan T. Ivanov err_range: 797eadff302SIvan T. Ivanov gpiochip_remove(&state->chip); 798eadff302SIvan T. Ivanov err_chip: 799eadff302SIvan T. Ivanov pinctrl_unregister(state->ctrl); 800eadff302SIvan T. Ivanov return ret; 801eadff302SIvan T. Ivanov } 802eadff302SIvan T. Ivanov 803eadff302SIvan T. Ivanov static int pmic_gpio_remove(struct platform_device *pdev) 804eadff302SIvan T. Ivanov { 805eadff302SIvan T. Ivanov struct pmic_gpio_state *state = platform_get_drvdata(pdev); 806eadff302SIvan T. Ivanov 807eadff302SIvan T. Ivanov gpiochip_remove(&state->chip); 808eadff302SIvan T. Ivanov pinctrl_unregister(state->ctrl); 809eadff302SIvan T. Ivanov return 0; 810eadff302SIvan T. Ivanov } 811eadff302SIvan T. Ivanov 812eadff302SIvan T. Ivanov static const struct of_device_id pmic_gpio_of_match[] = { 813eadff302SIvan T. Ivanov { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */ 814eadff302SIvan T. Ivanov { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */ 815eadff302SIvan T. Ivanov { }, 816eadff302SIvan T. Ivanov }; 817eadff302SIvan T. Ivanov 818eadff302SIvan T. Ivanov MODULE_DEVICE_TABLE(of, pmic_gpio_of_match); 819eadff302SIvan T. Ivanov 820eadff302SIvan T. Ivanov static struct platform_driver pmic_gpio_driver = { 821eadff302SIvan T. Ivanov .driver = { 822eadff302SIvan T. Ivanov .name = "qcom-spmi-gpio", 823eadff302SIvan T. Ivanov .of_match_table = pmic_gpio_of_match, 824eadff302SIvan T. Ivanov }, 825eadff302SIvan T. Ivanov .probe = pmic_gpio_probe, 826eadff302SIvan T. Ivanov .remove = pmic_gpio_remove, 827eadff302SIvan T. Ivanov }; 828eadff302SIvan T. Ivanov 829eadff302SIvan T. Ivanov module_platform_driver(pmic_gpio_driver); 830eadff302SIvan T. Ivanov 831eadff302SIvan T. Ivanov MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>"); 832eadff302SIvan T. Ivanov MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver"); 833eadff302SIvan T. Ivanov MODULE_ALIAS("platform:qcom-spmi-gpio"); 834eadff302SIvan T. Ivanov MODULE_LICENSE("GPL v2"); 835