From: patrick Date: Wed, 9 Nov 2022 13:46:11 +0000 (+0000) Subject: Implement reading/writing pins on qcpmicgpio(4). X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=e820f2e2aaf66c8c04da6fe7a6d57e564c6de9ff;p=openbsd Implement reading/writing pins on qcpmicgpio(4). --- diff --git a/sys/dev/fdt/qcpmicgpio.c b/sys/dev/fdt/qcpmicgpio.c index 174e9490346..7b3ed8e345c 100644 --- a/sys/dev/fdt/qcpmicgpio.c +++ b/sys/dev/fdt/qcpmicgpio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qcpmicgpio.c,v 1.1 2022/11/08 19:42:10 patrick Exp $ */ +/* $OpenBSD: qcpmicgpio.c,v 1.2 2022/11/09 13:46:11 patrick Exp $ */ /* * Copyright (c) 2022 Patrick Wildt * @@ -41,6 +41,18 @@ #define GPIO_PIN_OFF(x) (0x100 * (x)) #define GPIO_PIN_STATUS 0x10 #define GPIO_PIN_STATUS_ON (1 << 0) +#define GPIO_PIN_MODE 0x40 +#define GPIO_PIN_MODE_VALUE (1 << 0) +#define GPIO_PIN_MODE_DIR_SHIFT 4 +#define GPIO_PIN_MODE_DIR_MASK 0x7 +#define GPIO_PIN_MODE_DIR_LVMV_SHIFT 0 +#define GPIO_PIN_MODE_DIR_LVMV_MASK 0x3 +#define GPIO_PIN_MODE_DIR_DIGITAL_IN 0 +#define GPIO_PIN_MODE_DIR_DIGITAL_OUT 1 +#define GPIO_PIN_MODE_DIR_DIGITAL_IO 2 +#define GPIO_PIN_MODE_DIR_ANALOG_PT 3 +#define GPIO_PIN_LVMV_DOUT_CTL 0x44 +#define GPIO_PIN_LVMV_DOUT_CTL_INVERT (1U << 7) struct qcpmicgpio_softc { struct device sc_dev; @@ -50,6 +62,8 @@ struct qcpmicgpio_softc { int8_t sc_sid; uint16_t sc_addr; + int sc_is_lv_mv; + int sc_npins; struct gpio_controller sc_gc; }; @@ -65,6 +79,9 @@ struct cfdriver qcpmicgpio_cd = { NULL, "qcpmicgpio", DV_DULL }; +uint8_t qcpmicgpio_read(struct qcpmicgpio_softc *, uint16_t); +void qcpmicgpio_write(struct qcpmicgpio_softc *, uint16_t, uint8_t); + void qcpmicgpio_config_pin(void *, uint32_t *, int); int qcpmicgpio_get_pin(void *, uint32_t *); void qcpmicgpio_set_pin(void *, uint32_t *, int); @@ -82,10 +99,10 @@ qcpmicgpio_attach(struct device *parent, struct device *self, void *aux) { struct spmi_attach_args *saa = aux; struct qcpmicgpio_softc *sc = (struct qcpmicgpio_softc *)self; - int reg; + uint8_t reg; - reg = OF_getpropint(saa->sa_node, "reg", -1); - if (reg < 0) { + sc->sc_addr = OF_getpropint(saa->sa_node, "reg", -1); + if (sc->sc_addr < 0) { printf(": can't find registers\n"); return; } @@ -93,7 +110,6 @@ qcpmicgpio_attach(struct device *parent, struct device *self, void *aux) sc->sc_node = saa->sa_node; sc->sc_tag = saa->sa_tag; sc->sc_sid = saa->sa_sid; - sc->sc_addr = reg; if (OF_is_compatible(saa->sa_node, "qcom,pm8350-gpio")) sc->sc_npins = 10; @@ -107,6 +123,15 @@ qcpmicgpio_attach(struct device *parent, struct device *self, void *aux) return; } + if (qcpmicgpio_read(sc, GPIO_TYPE) != GPIO_TYPE_VAL) { + printf(": not a GPIO block\n"); + return; + } + + reg = qcpmicgpio_read(sc, GPIO_SUBTYPE); + if (reg == GPIO_SUBTYPE_GPIO_LV || reg == GPIO_SUBTYPE_GPIO_MV) + sc->sc_is_lv_mv = 1; + sc->sc_gc.gc_node = saa->sa_node; sc->sc_gc.gc_cookie = sc; sc->sc_gc.gc_config_pin = qcpmicgpio_config_pin; @@ -135,22 +160,39 @@ qcpmicgpio_get_pin(void *cookie, uint32_t *cells) struct qcpmicgpio_softc *sc = cookie; uint32_t pin = cells[0]; uint32_t flags = cells[1]; - int error, val; - uint32_t reg; + uint8_t reg; + int val = 0; if (pin >= sc->sc_npins) return 0; - error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL, - sc->sc_addr + GPIO_PIN_OFF(pin) + GPIO_PIN_STATUS, - ®, sizeof(reg)); - if (error) { - printf("%s: error reading GPIO\n", sc->sc_dev.dv_xname); - return error; + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + GPIO_PIN_MODE); + if (sc->sc_is_lv_mv) { + reg >>= GPIO_PIN_MODE_DIR_LVMV_SHIFT; + reg &= GPIO_PIN_MODE_DIR_LVMV_MASK; + } else { + reg >>= GPIO_PIN_MODE_DIR_SHIFT; + reg &= GPIO_PIN_MODE_DIR_MASK; + } + + if (reg == GPIO_PIN_MODE_DIR_DIGITAL_IN || + reg == GPIO_PIN_MODE_DIR_DIGITAL_IO) { + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + GPIO_PIN_STATUS); + val = !!(reg & GPIO_PIN_STATUS_ON); + } + + if (reg == GPIO_PIN_MODE_DIR_DIGITAL_OUT) { + if (sc->sc_is_lv_mv) { + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + + GPIO_PIN_LVMV_DOUT_CTL); + val = !!(reg & GPIO_PIN_LVMV_DOUT_CTL_INVERT); + } else { + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + + GPIO_PIN_MODE); + val = !!(reg & GPIO_PIN_MODE_VALUE); + } } - printf("%s: reg %x\n", sc->sc_dev.dv_xname, reg); - val = !!(reg & GPIO_PIN_STATUS_ON); if (flags & GPIO_ACTIVE_LOW) val = !val; return val; @@ -162,6 +204,7 @@ qcpmicgpio_set_pin(void *cookie, uint32_t *cells, int val) struct qcpmicgpio_softc *sc = cookie; uint32_t pin = cells[0]; uint32_t flags = cells[1]; + uint8_t reg; if (pin >= sc->sc_npins) return; @@ -169,5 +212,46 @@ qcpmicgpio_set_pin(void *cookie, uint32_t *cells, int val) if (flags & GPIO_ACTIVE_LOW) val = !val; - printf("%s\n", __func__); + if (sc->sc_is_lv_mv) { + qcpmicgpio_write(sc, GPIO_PIN_OFF(pin) + GPIO_PIN_MODE, + GPIO_PIN_MODE_DIR_DIGITAL_OUT); + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + + GPIO_PIN_LVMV_DOUT_CTL); + reg &= ~GPIO_PIN_LVMV_DOUT_CTL_INVERT; + if (val) + reg |= GPIO_PIN_LVMV_DOUT_CTL_INVERT; + qcpmicgpio_write(sc, GPIO_PIN_OFF(pin) + + GPIO_PIN_LVMV_DOUT_CTL, reg); + } else { + reg = qcpmicgpio_read(sc, GPIO_PIN_OFF(pin) + GPIO_PIN_MODE); + reg &= ~GPIO_PIN_MODE_VALUE; + if (val) + reg |= GPIO_PIN_MODE_VALUE; + qcpmicgpio_write(sc, GPIO_PIN_OFF(pin) + GPIO_PIN_MODE, reg); + } +} + +uint8_t +qcpmicgpio_read(struct qcpmicgpio_softc *sc, uint16_t reg) +{ + uint8_t val = 0; + int error; + + error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL, + sc->sc_addr + reg, &val, sizeof(val)); + if (error) + printf("%s: error reading\n", sc->sc_dev.dv_xname); + + return val; +} + +void +qcpmicgpio_write(struct qcpmicgpio_softc *sc, uint16_t reg, uint8_t val) +{ + int error; + + error = spmi_cmd_write(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_WRITEL, + sc->sc_addr + reg, &val, sizeof(val)); + if (error) + printf("%s: error writing\n", sc->sc_dev.dv_xname); }