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