14abe6533SAdrian Chadd /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 34abe6533SAdrian Chadd * 44abe6533SAdrian Chadd * Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org> 54abe6533SAdrian Chadd * 64abe6533SAdrian Chadd * Redistribution and use in source and binary forms, with or without 74abe6533SAdrian Chadd * modification, are permitted provided that the following conditions 84abe6533SAdrian Chadd * are met: 94abe6533SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 104abe6533SAdrian Chadd * notice unmodified, this list of conditions, and the following 114abe6533SAdrian Chadd * disclaimer. 124abe6533SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 134abe6533SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 144abe6533SAdrian Chadd * documentation and/or other materials provided with the distribution. 154abe6533SAdrian Chadd * 164abe6533SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174abe6533SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184abe6533SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194abe6533SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204abe6533SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214abe6533SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224abe6533SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234abe6533SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244abe6533SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254abe6533SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264abe6533SAdrian Chadd * SUCH DAMAGE. 274abe6533SAdrian Chadd */ 284abe6533SAdrian Chadd 294abe6533SAdrian Chadd /* 304abe6533SAdrian Chadd * This is a pinmux/gpio controller for the IPQ4018/IPQ4019. 314abe6533SAdrian Chadd */ 324abe6533SAdrian Chadd 334abe6533SAdrian Chadd #include <sys/cdefs.h> 344abe6533SAdrian Chadd __FBSDID("$FreeBSD$"); 354abe6533SAdrian Chadd 364abe6533SAdrian Chadd #include <sys/param.h> 374abe6533SAdrian Chadd #include <sys/systm.h> 384abe6533SAdrian Chadd #include <sys/bus.h> 394abe6533SAdrian Chadd 404abe6533SAdrian Chadd #include <sys/kernel.h> 414abe6533SAdrian Chadd #include <sys/module.h> 424abe6533SAdrian Chadd #include <sys/rman.h> 434abe6533SAdrian Chadd #include <sys/lock.h> 444abe6533SAdrian Chadd #include <sys/malloc.h> 454abe6533SAdrian Chadd #include <sys/mutex.h> 464abe6533SAdrian Chadd #include <sys/gpio.h> 474abe6533SAdrian Chadd 484abe6533SAdrian Chadd #include <machine/bus.h> 494abe6533SAdrian Chadd #include <machine/resource.h> 504abe6533SAdrian Chadd #include <dev/gpio/gpiobusvar.h> 514abe6533SAdrian Chadd 524abe6533SAdrian Chadd #include <dev/fdt/fdt_common.h> 534abe6533SAdrian Chadd #include <dev/ofw/ofw_bus.h> 544abe6533SAdrian Chadd #include <dev/ofw/ofw_bus_subr.h> 554abe6533SAdrian Chadd 564abe6533SAdrian Chadd #include <dev/fdt/fdt_pinctrl.h> 574abe6533SAdrian Chadd 584abe6533SAdrian Chadd #include "qcom_tlmm_var.h" 594abe6533SAdrian Chadd 604abe6533SAdrian Chadd #include "qcom_tlmm_ipq4018_reg.h" 614abe6533SAdrian Chadd #include "qcom_tlmm_ipq4018_hw.h" 624abe6533SAdrian Chadd 634abe6533SAdrian Chadd #include "gpio_if.h" 644abe6533SAdrian Chadd 654abe6533SAdrian Chadd /* 664abe6533SAdrian Chadd * Set the pin function. This is a hardware and pin specific mapping. 674abe6533SAdrian Chadd * 684abe6533SAdrian Chadd * Returns 0 if OK, an errno if an error was encountered. 694abe6533SAdrian Chadd */ 704abe6533SAdrian Chadd int 714abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_function(struct qcom_tlmm_softc *sc, 724abe6533SAdrian Chadd int pin, int function) 734abe6533SAdrian Chadd { 744abe6533SAdrian Chadd uint32_t reg; 754abe6533SAdrian Chadd 764abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 774abe6533SAdrian Chadd 784abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 794abe6533SAdrian Chadd return (EINVAL); 804abe6533SAdrian Chadd 814abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 824abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 834abe6533SAdrian Chadd reg &= ~(QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_MASK 844abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_SHIFT); 854abe6533SAdrian Chadd reg |= (function & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_MASK) 864abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_SHIFT; 874abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 884abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 894abe6533SAdrian Chadd 904abe6533SAdrian Chadd return (0); 914abe6533SAdrian Chadd } 924abe6533SAdrian Chadd 934abe6533SAdrian Chadd /* 944abe6533SAdrian Chadd * Get the pin function. This is a hardware and pin specific mapping. 954abe6533SAdrian Chadd * 964abe6533SAdrian Chadd * Returns 0 if OK, an errno if a nerror was encountered. 974abe6533SAdrian Chadd */ 984abe6533SAdrian Chadd int 994abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_function(struct qcom_tlmm_softc *sc, 1004abe6533SAdrian Chadd int pin, int *function) 1014abe6533SAdrian Chadd { 1024abe6533SAdrian Chadd uint32_t reg; 1034abe6533SAdrian Chadd 1044abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 1054abe6533SAdrian Chadd 1064abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 1074abe6533SAdrian Chadd return (EINVAL); 1084abe6533SAdrian Chadd 1094abe6533SAdrian Chadd 1104abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 1114abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 1124abe6533SAdrian Chadd reg = reg >> QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_SHIFT; 1134abe6533SAdrian Chadd reg &= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_MUX_MASK; 1144abe6533SAdrian Chadd *function = reg; 1154abe6533SAdrian Chadd 1164abe6533SAdrian Chadd return (0); 1174abe6533SAdrian Chadd } 1184abe6533SAdrian Chadd 1194abe6533SAdrian Chadd /* 1204abe6533SAdrian Chadd * Set the OE bit to be output. This assumes the port is configured 1214abe6533SAdrian Chadd * as a GPIO port. 1224abe6533SAdrian Chadd */ 1234abe6533SAdrian Chadd int 1244abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_oe_output(struct qcom_tlmm_softc *sc, 1254abe6533SAdrian Chadd int pin) 1264abe6533SAdrian Chadd { 1274abe6533SAdrian Chadd uint32_t reg; 1284abe6533SAdrian Chadd 1294abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 1304abe6533SAdrian Chadd 1314abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 1324abe6533SAdrian Chadd return (EINVAL); 1334abe6533SAdrian Chadd 1344abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 1354abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 1364abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OE_ENABLE; 1374abe6533SAdrian Chadd GPIO_WRITE(sc, 1384abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN(pin, QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), 1394abe6533SAdrian Chadd reg); 1404abe6533SAdrian Chadd 1414abe6533SAdrian Chadd return (0); 1424abe6533SAdrian Chadd } 1434abe6533SAdrian Chadd 1444abe6533SAdrian Chadd /* 1454abe6533SAdrian Chadd * Set the OE bit to be input. This assumes the port is configured 1464abe6533SAdrian Chadd * as a GPIO port. 1474abe6533SAdrian Chadd */ 1484abe6533SAdrian Chadd int 1494abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_oe_input(struct qcom_tlmm_softc *sc, 1504abe6533SAdrian Chadd int pin) 1514abe6533SAdrian Chadd { 1524abe6533SAdrian Chadd uint32_t reg; 1534abe6533SAdrian Chadd 1544abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 1554abe6533SAdrian Chadd 1564abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 1574abe6533SAdrian Chadd return (EINVAL); 1584abe6533SAdrian Chadd 1594abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 1604abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 1614abe6533SAdrian Chadd reg &= ~QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OE_ENABLE; 1624abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 1634abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 1644abe6533SAdrian Chadd 1654abe6533SAdrian Chadd return (0); 1664abe6533SAdrian Chadd } 1674abe6533SAdrian Chadd 1684abe6533SAdrian Chadd /* 1694abe6533SAdrian Chadd * Get the GPIO pin direction. is_output is set to true if the pin 1704abe6533SAdrian Chadd * is an output pin, false if it's set to an input pin. 1714abe6533SAdrian Chadd */ 1724abe6533SAdrian Chadd int 1734abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_oe_state(struct qcom_tlmm_softc *sc, 1744abe6533SAdrian Chadd int pin, bool *is_output) 1754abe6533SAdrian Chadd { 1764abe6533SAdrian Chadd uint32_t reg; 1774abe6533SAdrian Chadd 1784abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 1794abe6533SAdrian Chadd 1804abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 1814abe6533SAdrian Chadd return (EINVAL); 1824abe6533SAdrian Chadd 1834abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 1844abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 1854abe6533SAdrian Chadd *is_output = !! (reg & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OE_ENABLE); 1864abe6533SAdrian Chadd 1874abe6533SAdrian Chadd return (0); 1884abe6533SAdrian Chadd } 1894abe6533SAdrian Chadd 1904abe6533SAdrian Chadd 1914abe6533SAdrian Chadd /* 1924abe6533SAdrian Chadd * Set the given GPIO pin to the given value. 1934abe6533SAdrian Chadd */ 1944abe6533SAdrian Chadd int 1954abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_output_value(struct qcom_tlmm_softc *sc, 1964abe6533SAdrian Chadd uint32_t pin, unsigned int value) 1974abe6533SAdrian Chadd { 1984abe6533SAdrian Chadd uint32_t reg; 1994abe6533SAdrian Chadd 2004abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 2014abe6533SAdrian Chadd 2024abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 2034abe6533SAdrian Chadd return (EINVAL); 2044abe6533SAdrian Chadd 2054abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2064abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO)); 2074abe6533SAdrian Chadd if (value) 2084abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_IO_OUTPUT_EN; 2094abe6533SAdrian Chadd else 2104abe6533SAdrian Chadd reg &= ~QCOM_TLMM_IPQ4018_REG_PIN_IO_OUTPUT_EN; 2114abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2124abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO), reg); 2134abe6533SAdrian Chadd 2144abe6533SAdrian Chadd return (0); 2154abe6533SAdrian Chadd } 2164abe6533SAdrian Chadd 2174abe6533SAdrian Chadd /* 2184abe6533SAdrian Chadd * Get the input state of the current GPIO pin. 2194abe6533SAdrian Chadd */ 2204abe6533SAdrian Chadd int 2214abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_output_value(struct qcom_tlmm_softc *sc, 2224abe6533SAdrian Chadd uint32_t pin, unsigned int *val) 2234abe6533SAdrian Chadd { 2244abe6533SAdrian Chadd uint32_t reg; 2254abe6533SAdrian Chadd 2264abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 2274abe6533SAdrian Chadd 2284abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 2294abe6533SAdrian Chadd return (EINVAL); 2304abe6533SAdrian Chadd 2314abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2324abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO)); 2334abe6533SAdrian Chadd 2344abe6533SAdrian Chadd *val = !! (reg & QCOM_TLMM_IPQ4018_REG_PIN_IO_INPUT_STATUS); 2354abe6533SAdrian Chadd 2364abe6533SAdrian Chadd return (0); 2374abe6533SAdrian Chadd } 2384abe6533SAdrian Chadd 2394abe6533SAdrian Chadd 2404abe6533SAdrian Chadd /* 2414abe6533SAdrian Chadd * Get the input state of the current GPIO pin. 2424abe6533SAdrian Chadd */ 2434abe6533SAdrian Chadd int 2444abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_input_value(struct qcom_tlmm_softc *sc, 2454abe6533SAdrian Chadd uint32_t pin, unsigned int *val) 2464abe6533SAdrian Chadd { 2474abe6533SAdrian Chadd uint32_t reg; 2484abe6533SAdrian Chadd 2494abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 2504abe6533SAdrian Chadd 2514abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 2524abe6533SAdrian Chadd return (EINVAL); 2534abe6533SAdrian Chadd 2544abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2554abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO)); 2564abe6533SAdrian Chadd 2574abe6533SAdrian Chadd *val = !! (reg & QCOM_TLMM_IPQ4018_REG_PIN_IO_INPUT_STATUS); 2584abe6533SAdrian Chadd 2594abe6533SAdrian Chadd return (0); 2604abe6533SAdrian Chadd } 2614abe6533SAdrian Chadd 2624abe6533SAdrian Chadd /* 2634abe6533SAdrian Chadd * Toggle the current output pin value. 2644abe6533SAdrian Chadd */ 2654abe6533SAdrian Chadd int 2664abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_toggle_output_value( 2674abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin) 2684abe6533SAdrian Chadd { 2694abe6533SAdrian Chadd uint32_t reg; 2704abe6533SAdrian Chadd 2714abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 2724abe6533SAdrian Chadd 2734abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 2744abe6533SAdrian Chadd return (EINVAL); 2754abe6533SAdrian Chadd 2764abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2774abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO)); 2784abe6533SAdrian Chadd if ((reg & QCOM_TLMM_IPQ4018_REG_PIN_IO_OUTPUT_EN) == 0) 2794abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_IO_OUTPUT_EN; 2804abe6533SAdrian Chadd else 2814abe6533SAdrian Chadd reg &= ~QCOM_TLMM_IPQ4018_REG_PIN_IO_OUTPUT_EN; 2824abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 2834abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_IO), reg); 2844abe6533SAdrian Chadd 2854abe6533SAdrian Chadd return (0); 2864abe6533SAdrian Chadd } 2874abe6533SAdrian Chadd 2884abe6533SAdrian Chadd /* 2894abe6533SAdrian Chadd * Configure the pull-up / pull-down top-level configuration. 2904abe6533SAdrian Chadd * 2914abe6533SAdrian Chadd * This doesn't configure the resistor values, just what's enabled/disabled. 2924abe6533SAdrian Chadd */ 2934abe6533SAdrian Chadd int 2944abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_pupd_config( 2954abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, 2964abe6533SAdrian Chadd qcom_tlmm_pin_pupd_config_t pupd) 2974abe6533SAdrian Chadd { 2984abe6533SAdrian Chadd uint32_t reg; 2994abe6533SAdrian Chadd 3004abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 3014abe6533SAdrian Chadd 3024abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 3034abe6533SAdrian Chadd return (EINVAL); 3044abe6533SAdrian Chadd 3054abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 3064abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 3074abe6533SAdrian Chadd 3084abe6533SAdrian Chadd reg &= ~(QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_MASK 3094abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT); 3104abe6533SAdrian Chadd 3114abe6533SAdrian Chadd switch (pupd) { 3124abe6533SAdrian Chadd case QCOM_TLMM_PIN_PUPD_CONFIG_DISABLE: 3134abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_DISABLE 3144abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT; 3154abe6533SAdrian Chadd break; 3164abe6533SAdrian Chadd case QCOM_TLMM_PIN_PUPD_CONFIG_PULL_DOWN: 3174abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_PULLDOWN 3184abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT; 3194abe6533SAdrian Chadd break; 3204abe6533SAdrian Chadd case QCOM_TLMM_PIN_PUPD_CONFIG_PULL_UP: 3214abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_PULLUP 3224abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT; 3234abe6533SAdrian Chadd break; 3244abe6533SAdrian Chadd case QCOM_TLMM_PIN_PUPD_CONFIG_BUS_HOLD: 3254abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_BUSHOLD 3264abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT; 3274abe6533SAdrian Chadd break; 3284abe6533SAdrian Chadd } 3294abe6533SAdrian Chadd 3304abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 3314abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 3324abe6533SAdrian Chadd 3334abe6533SAdrian Chadd return (0); 3344abe6533SAdrian Chadd } 3354abe6533SAdrian Chadd 3364abe6533SAdrian Chadd /* 3374abe6533SAdrian Chadd * Fetch the current pull-up / pull-down configuration. 3384abe6533SAdrian Chadd */ 3394abe6533SAdrian Chadd int 3404abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_pupd_config( 3414abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, 3424abe6533SAdrian Chadd qcom_tlmm_pin_pupd_config_t *pupd) 3434abe6533SAdrian Chadd { 3444abe6533SAdrian Chadd uint32_t reg; 3454abe6533SAdrian Chadd 3464abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 3474abe6533SAdrian Chadd 3484abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 3494abe6533SAdrian Chadd return (EINVAL); 3504abe6533SAdrian Chadd 3514abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 3524abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 3534abe6533SAdrian Chadd 3544abe6533SAdrian Chadd reg >>= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_SHIFT; 3554abe6533SAdrian Chadd reg &= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_MASK; 3564abe6533SAdrian Chadd 3574abe6533SAdrian Chadd switch (reg) { 3584abe6533SAdrian Chadd case QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_DISABLE: 3594abe6533SAdrian Chadd *pupd = QCOM_TLMM_PIN_PUPD_CONFIG_DISABLE; 3604abe6533SAdrian Chadd break; 3614abe6533SAdrian Chadd case QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_PULLDOWN: 3624abe6533SAdrian Chadd *pupd = QCOM_TLMM_PIN_PUPD_CONFIG_PULL_DOWN; 3634abe6533SAdrian Chadd break; 3644abe6533SAdrian Chadd case QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_PUPD_PULLUP: 3654abe6533SAdrian Chadd *pupd = QCOM_TLMM_PIN_PUPD_CONFIG_PULL_UP; 3664abe6533SAdrian Chadd break; 3674abe6533SAdrian Chadd default: 3684abe6533SAdrian Chadd *pupd = QCOM_TLMM_PIN_PUPD_CONFIG_DISABLE; 3694abe6533SAdrian Chadd break; 3704abe6533SAdrian Chadd } 3714abe6533SAdrian Chadd 3724abe6533SAdrian Chadd return (0); 3734abe6533SAdrian Chadd } 3744abe6533SAdrian Chadd 3754abe6533SAdrian Chadd /* 3764abe6533SAdrian Chadd * Set the drive strength in mA. 3774abe6533SAdrian Chadd */ 3784abe6533SAdrian Chadd int 3794abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_drive_strength( 3804abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, uint8_t drv) 3814abe6533SAdrian Chadd { 3824abe6533SAdrian Chadd uint32_t reg; 3834abe6533SAdrian Chadd 3844abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 3854abe6533SAdrian Chadd 3864abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 3874abe6533SAdrian Chadd return (EINVAL); 3884abe6533SAdrian Chadd 3894abe6533SAdrian Chadd /* Convert mA to hardware */ 3904abe6533SAdrian Chadd if (drv > 16 || drv < 2) 3914abe6533SAdrian Chadd return (EINVAL); 3924abe6533SAdrian Chadd drv = (drv / 2) - 1; 3934abe6533SAdrian Chadd 3944abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 3954abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 3964abe6533SAdrian Chadd 3974abe6533SAdrian Chadd reg &= ~(QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_SHIFT 3984abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_MASK); 3994abe6533SAdrian Chadd reg |= (drv & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_MASK) 4004abe6533SAdrian Chadd << QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_SHIFT; 4014abe6533SAdrian Chadd 4024abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4034abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 4044abe6533SAdrian Chadd 4054abe6533SAdrian Chadd return (0); 4064abe6533SAdrian Chadd } 4074abe6533SAdrian Chadd 4084abe6533SAdrian Chadd /* 4094abe6533SAdrian Chadd * Get the drive strength in mA. 4104abe6533SAdrian Chadd */ 4114abe6533SAdrian Chadd int 4124abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_drive_strength( 4134abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, uint8_t *drv) 4144abe6533SAdrian Chadd { 4154abe6533SAdrian Chadd uint32_t reg; 4164abe6533SAdrian Chadd 4174abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 4184abe6533SAdrian Chadd 4194abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 4204abe6533SAdrian Chadd return (EINVAL); 4214abe6533SAdrian Chadd 4224abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4234abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 4244abe6533SAdrian Chadd 4254abe6533SAdrian Chadd *drv = (reg >> QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_SHIFT) 4264abe6533SAdrian Chadd & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_DRIVE_STRENGTH_MASK; 4274abe6533SAdrian Chadd 4284abe6533SAdrian Chadd *drv = (*drv + 1) * 2; 4294abe6533SAdrian Chadd 4304abe6533SAdrian Chadd return (0); 4314abe6533SAdrian Chadd } 4324abe6533SAdrian Chadd 4334abe6533SAdrian Chadd 4344abe6533SAdrian Chadd /* 4354abe6533SAdrian Chadd * Enable/disable whether this pin is passed through to a VM. 4364abe6533SAdrian Chadd */ 4374abe6533SAdrian Chadd int 4384abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_vm( 4394abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, bool enable) 4404abe6533SAdrian Chadd { 4414abe6533SAdrian Chadd uint32_t reg; 4424abe6533SAdrian Chadd 4434abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 4444abe6533SAdrian Chadd 4454abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 4464abe6533SAdrian Chadd return (EINVAL); 4474abe6533SAdrian Chadd 4484abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4494abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 4504abe6533SAdrian Chadd 4514abe6533SAdrian Chadd reg &= ~QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_VM_ENABLE; 4524abe6533SAdrian Chadd if (enable) 4534abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_VM_ENABLE; 4544abe6533SAdrian Chadd 4554abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4564abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 4574abe6533SAdrian Chadd 4584abe6533SAdrian Chadd return (0); 4594abe6533SAdrian Chadd } 4604abe6533SAdrian Chadd 4614abe6533SAdrian Chadd /* 4624abe6533SAdrian Chadd * Get the VM configuration bit. 4634abe6533SAdrian Chadd */ 4644abe6533SAdrian Chadd int 4654abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_vm( 4664abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, bool *enable) 4674abe6533SAdrian Chadd { 4684abe6533SAdrian Chadd uint32_t reg; 4694abe6533SAdrian Chadd 4704abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 4714abe6533SAdrian Chadd 4724abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 4734abe6533SAdrian Chadd return (EINVAL); 4744abe6533SAdrian Chadd 4754abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4764abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 4774abe6533SAdrian Chadd 4784abe6533SAdrian Chadd *enable = !! (reg & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_VM_ENABLE); 4794abe6533SAdrian Chadd 4804abe6533SAdrian Chadd return (0); 4814abe6533SAdrian Chadd } 4824abe6533SAdrian Chadd 4834abe6533SAdrian Chadd /* 4844abe6533SAdrian Chadd * Enable/disable open drain. 4854abe6533SAdrian Chadd */ 4864abe6533SAdrian Chadd int 4874abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_set_open_drain( 4884abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, bool enable) 4894abe6533SAdrian Chadd { 4904abe6533SAdrian Chadd uint32_t reg; 4914abe6533SAdrian Chadd 4924abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 4934abe6533SAdrian Chadd 4944abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 4954abe6533SAdrian Chadd return (EINVAL); 4964abe6533SAdrian Chadd 4974abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 4984abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 4994abe6533SAdrian Chadd 5004abe6533SAdrian Chadd reg &= ~QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OD_ENABLE; 5014abe6533SAdrian Chadd if (enable) 5024abe6533SAdrian Chadd reg |= QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OD_ENABLE; 5034abe6533SAdrian Chadd 5044abe6533SAdrian Chadd GPIO_WRITE(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 5054abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL), reg); 5064abe6533SAdrian Chadd 5074abe6533SAdrian Chadd return (0); 5084abe6533SAdrian Chadd } 5094abe6533SAdrian Chadd 5104abe6533SAdrian Chadd /* 5114abe6533SAdrian Chadd * Get the open drain configuration bit. 5124abe6533SAdrian Chadd */ 5134abe6533SAdrian Chadd int 5144abe6533SAdrian Chadd qcom_tlmm_ipq4018_hw_pin_get_open_drain( 5154abe6533SAdrian Chadd struct qcom_tlmm_softc *sc, uint32_t pin, bool *enable) 5164abe6533SAdrian Chadd { 5174abe6533SAdrian Chadd uint32_t reg; 5184abe6533SAdrian Chadd 5194abe6533SAdrian Chadd GPIO_LOCK_ASSERT(sc); 5204abe6533SAdrian Chadd 5214abe6533SAdrian Chadd if (pin >= sc->gpio_npins) 5224abe6533SAdrian Chadd return (EINVAL); 5234abe6533SAdrian Chadd 5244abe6533SAdrian Chadd reg = GPIO_READ(sc, QCOM_TLMM_IPQ4018_REG_PIN(pin, 5254abe6533SAdrian Chadd QCOM_TLMM_IPQ4018_REG_PIN_CONTROL)); 5264abe6533SAdrian Chadd 5274abe6533SAdrian Chadd *enable = !! (reg & QCOM_TLMM_IPQ4018_REG_PIN_CONTROL_OD_ENABLE); 5284abe6533SAdrian Chadd 5294abe6533SAdrian Chadd return (0); 5304abe6533SAdrian Chadd } 531