From nobody Wed Nov 24 06:41:57 2021 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id B5E5A18ABD8C; Wed, 24 Nov 2021 06:41:59 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4HzWdL3RpHz4knH; Wed, 24 Nov 2021 06:41:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8B431250DC; Wed, 24 Nov 2021 06:41:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 1AO6fvUR037204; Wed, 24 Nov 2021 06:41:57 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1AO6fvdA037203; Wed, 24 Nov 2021 06:41:57 GMT (envelope-from git) Date: Wed, 24 Nov 2021 06:41:57 GMT Message-Id: <202111240641.1AO6fvdA037203@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Wojciech Macek Subject: git: cb35af13f9f9 - main - TCA6408: Add driver for tca6408 gpio expander List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: wma X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: cb35af13f9f998946adcb08f53ac869864c4d11c Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1637736119; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=SnKcd8izOON/+NQUrL81nxgsaXF+1cBrwD65AnDVywE=; b=MqxG4N2TnJrdWdazItodkvNSxoZwrtdmo7EnY4YtAIVeH+aKPkIJjjn4Ts0JevKBCEx8sJ Ho0NLqXLfpaSzkT0S6URCcVbTpsAGq2MRE6YFdTaPbVt3ay5nsHnXKpEgHjDa0RkWG0s1p hVb0Y/fhy+sZEVlGmhs8zT5rL1ZsHpTNXwnKuA6HnbvDFv1onHYrE4Z9+eWMoEM/uTHN7U LnSr5T2XO1EWnHO6ce9dBAQfT6c89XY8fvqB2XnlNpXz9/u8EzzhqvY1W650IfbBpPR0tZ JfUWKktyRd0/mXyjk+Rt2tiRYE57V35zAyns623INYjb2W+kb9eWE5mP3S77Tg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1637736119; a=rsa-sha256; cv=none; b=IGfA0gKkG78E6WNoxk3PM3vM9cFj0Ivc2wclhGodPfIaFvLdZIvm2pfKeYL/Uxbp1IkP4N S3SnQAm9mrh1AnMkqf/BZJiQbt4fmyIK4UcR9QnBMjHP5iwWd9vGtC1N8QxfUJh0LbVPbu BGttm05kDFKg1O0gzDHttoa0VakJhry2j78QI7ach2xPnIEhBOCL/mn8uHRUFYNRzsV6yF GvNPl2B+OzXgOV2AMz7fRHCx9ZMtUZCYGW7Mk1ssL/CDNs7LLAXe2EyiV8Gy+e98ootfen e8d9A49Tb/tyUAotCunO4Yt1fwa1pvVfvCRvdusn9WdPU4/fHijuyz85uJ9hlQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by wma: URL: https://cgit.FreeBSD.org/src/commit/?id=cb35af13f9f998946adcb08f53ac869864c4d11c commit cb35af13f9f998946adcb08f53ac869864c4d11c Author: Hubert Mazur AuthorDate: 2021-10-22 11:51:45 +0000 Commit: Wojciech Macek CommitDate: 2021-11-24 06:40:38 +0000 TCA6408: Add driver for tca6408 gpio expander Driver for tca6408 gpio expander over i2c bus. Expose API for manipulating pin's direction, state and polarity inversion. Obtained from: Semihalf Sponsored by: Alstom Group Differential revision: https://reviews.freebsd.org/D32819 --- sys/arm64/conf/std.nxp | 1 + sys/conf/files | 1 + sys/dev/iicbus/gpio/tca6408.c | 380 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 382 insertions(+) diff --git a/sys/arm64/conf/std.nxp b/sys/arm64/conf/std.nxp index 05e74fca5170..75e57a6b2386 100644 --- a/sys/arm64/conf/std.nxp +++ b/sys/arm64/conf/std.nxp @@ -8,6 +8,7 @@ options SOC_NXP_LS # I2C device pca9547 # NPX I2C bus multiplexer device pcf8563 # NXP Real-time clock/calendar +device tca6408 # NXP I2C gpio expander # Serial (COM) ports device uart_ns8250 # ns8250-type UART driver diff --git a/sys/conf/files b/sys/conf/files index 6f0e321efe79..56ac8d60db31 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1870,6 +1870,7 @@ dev/iicbus/rtc/rx8803.c optional rx8803 iicbus fdt dev/iicbus/s35390a.c optional s35390a dev/iicbus/sy8106a.c optional sy8106a ext_resources fdt dev/iicbus/syr827.c optional syr827 ext_resources fdt +dev/iicbus/gpio/tca6408.c optional tca6408 fdt gpio dev/iicbus/gpio/tca6416.c optional tca6416 fdt dev/iicbus/pmic/fan53555.c optional fan53555 ext_resources fdt dev/iir/iir.c optional iir diff --git a/sys/dev/iicbus/gpio/tca6408.c b/sys/dev/iicbus/gpio/tca6408.c new file mode 100644 index 000000000000..d63fa8b64d56 --- /dev/null +++ b/sys/dev/iicbus/gpio/tca6408.c @@ -0,0 +1,380 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 Alstom Group. + * Copyright (c) 2021 Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_platform.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#define BIT(x) (1UL << (x)) + +#define TCA6408_READ_REG 0x0 +#define TCA6408_WRITE_REG 0x1 +#define TCA6408_POLARITY_REG 0x2 +#define TCA6408_CONFIG_REG 0x3 + +#define PINS_NUM 8 + +#define PIN_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT \ + | GPIO_PIN_INVIN) + +struct tca6408_softc { + device_t dev; + device_t bus_dev; + struct mtx mtx; +}; + +static int tca6408_read1(device_t dev, uint8_t offset, uint8_t *data); +static int tca6408_write1(device_t dev, uint8_t offset, uint8_t data); +static int tca6408_probe(device_t dev); +static int tca6408_attach(device_t dev); +static int tca6408_detach(device_t dev); +static device_t tca6408_get_bus(device_t dev); +static int tca6408_pin_max(device_t dev, int *pin); +static int tca6408_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags); +static int tca6408_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); +static int tca6408_pin_getname(device_t dev, uint32_t pin, char *name); +static int tca6408_pin_get(device_t dev, uint32_t pin, unsigned int *val); +static int tca6408_pin_set(device_t dev, uint32_t pin, unsigned int val); +static int tca6408_pin_toggle(device_t dev, uint32_t pin); +static int tca6408_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); + +static device_method_t tca6408_methods[] = { + DEVMETHOD(device_probe, tca6408_probe), + DEVMETHOD(device_attach, tca6408_attach), + DEVMETHOD(device_detach, tca6408_detach), + + DEVMETHOD(gpio_get_bus, tca6408_get_bus), + DEVMETHOD(gpio_pin_max, tca6408_pin_max), + DEVMETHOD(gpio_pin_getflags, tca6408_pin_getflags), + DEVMETHOD(gpio_pin_setflags, tca6408_pin_setflags), + DEVMETHOD(gpio_pin_getname, tca6408_pin_getname), + DEVMETHOD(gpio_pin_get, tca6408_pin_get), + DEVMETHOD(gpio_pin_set, tca6408_pin_set), + DEVMETHOD(gpio_pin_toggle, tca6408_pin_toggle), + DEVMETHOD(gpio_pin_getcaps, tca6408_pin_getcaps), + + DEVMETHOD_END +}; + +static driver_t tca6408_driver = { + "gpio", + tca6408_methods, + sizeof(struct tca6408_softc) +}; + +static struct ofw_compat_data tca6408_compat_data[] = { + { "ti,tca6408", 1 }, + { NULL, 0} +}; + +devclass_t tca6408_devclass; + +DRIVER_MODULE(tca6408, iicbus, tca6408_driver, tca6408_devclass, 0, 0); +IICBUS_FDT_PNP_INFO(tca6408_compat_data); + +static int +tca6408_read1(device_t dev, uint8_t offset, uint8_t *data) +{ + int error; + + error = iicdev_readfrom(dev, offset, (void *) data, 1, IIC_WAIT); + if (error != 0) + device_printf(dev, "Failed to read from device\n"); + + return (error); +} + +static int +tca6408_write1(device_t dev, uint8_t offset, uint8_t data) +{ + int error; + + error = iicdev_writeto(dev, offset, (void *) &data, 1, IIC_WAIT); + if (error != 0) + device_printf(dev, "Failed to write to device\n"); + + return (error); +} + +static int +tca6408_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, tca6408_compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "TCA6408 GPIO expander"); + + return (BUS_PROBE_DEFAULT); +} + +static int +tca6408_attach(device_t dev) +{ + struct tca6408_softc *sc; + + sc = device_get_softc(dev); + sc->dev = dev; + + mtx_init(&sc->mtx, "tca6408 gpio", "gpio", MTX_DEF); + + sc->bus_dev = gpiobus_attach_bus(dev); + if (sc->bus_dev == NULL) { + device_printf(dev, "Could not create busdev child\n"); + return (ENXIO); + } + + OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); + + return (0); +} + +static int +tca6408_detach(device_t dev) +{ + struct tca6408_softc *sc; + + sc = device_get_softc(dev); + + if (sc->bus_dev != NULL) + gpiobus_detach_bus(sc->bus_dev); + + mtx_destroy(&sc->mtx); + + return (0); +} + +static device_t +tca6408_get_bus(device_t dev) +{ + struct tca6408_softc *sc; + + sc = device_get_softc(dev); + + return (sc->bus_dev); +} + +static int +tca6408_pin_max(device_t dev, int *pin) +{ + + if (pin == NULL) + return (EINVAL); + + *pin = PINS_NUM - 1; + + return (0); +} + +static int +tca6408_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct tca6408_softc *sc; + uint8_t buffer; + int error; + + if (pin >= PINS_NUM || flags == NULL) + return (EINVAL); + + sc = device_get_softc(dev); + + error = tca6408_read1(dev, TCA6408_CONFIG_REG, &buffer); + if (error != 0) + return (error); + + *flags = (buffer & BIT(pin)) ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT; + + error = tca6408_read1(dev, TCA6408_POLARITY_REG, &buffer); + if (error != 0) + return (error); + + if (buffer & BIT(pin)) + *flags |= ((*flags & GPIO_PIN_INPUT) + ? GPIO_PIN_INVIN : GPIO_PIN_INVOUT); + + return (0); +} + +static int +tca6408_pin_setflags(device_t dev, uint32_t pin, unsigned int flags) +{ + uint8_t config_buf, inv_buf; + struct tca6408_softc *sc; + int error; + + if (pin >= PINS_NUM) + return (EINVAL); + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); + + error = tca6408_read1(dev, TCA6408_CONFIG_REG, &config_buf); + if (error != 0) + goto fail; + + error = tca6408_read1(dev, TCA6408_POLARITY_REG, &inv_buf); + if (error != 0) + goto fail; + + if (flags & GPIO_PIN_INPUT) + config_buf |= BIT(pin); + else if (flags & GPIO_PIN_OUTPUT) + config_buf &= ~BIT(pin); + + if (flags & GPIO_PIN_INVIN) + inv_buf |= BIT(pin); + else if (flags & GPIO_PIN_INVOUT) + inv_buf &= ~BIT(pin); + + error = tca6408_write1(dev, TCA6408_CONFIG_REG, config_buf); + if (error != 0) + goto fail; + + error = tca6408_write1(dev, TCA6408_POLARITY_REG, inv_buf); + +fail: + mtx_unlock(&sc->mtx); + + return (error); +} + +static int +tca6408_pin_getname(device_t dev, uint32_t pin, char *name) +{ + + if (pin >= PINS_NUM) + return (EINVAL); + + snprintf(name, GPIOMAXNAME, "tca6408_gpio_pin%d\n", pin); + + return (0); +} + +static int +tca6408_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + uint8_t buffer; + int error; + + if (pin >= PINS_NUM || val == NULL) + return (EINVAL); + + error = tca6408_read1(dev, TCA6408_READ_REG, &buffer); + if (error != 0) + return (error); + + *val = buffer & BIT(pin); + + return (0); +} + +static int +tca6408_pin_set(device_t dev, uint32_t pin, uint32_t val) +{ + struct tca6408_softc *sc; + uint8_t buffer; + int error; + + if (pin >= PINS_NUM) + return (EINVAL); + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); + + error = tca6408_read1(dev, TCA6408_WRITE_REG, &buffer); + if (error != 0) + goto fail; + + if (val != 0) + buffer |= BIT(pin); + else + buffer &= ~BIT(pin); + + error = tca6408_write1(dev, TCA6408_WRITE_REG, buffer); + +fail: + mtx_unlock(&sc->mtx); + + return (error); +} + +static int +tca6408_pin_toggle(device_t dev, uint32_t pin) +{ + struct tca6408_softc *sc; + uint8_t buffer; + int error; + + if (pin >= PINS_NUM) + return (EINVAL); + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); + + error = tca6408_read1(dev, TCA6408_WRITE_REG, &buffer); + if (error) + goto fail; + + buffer ^= BIT(pin); + error = tca6408_write1(dev, TCA6408_WRITE_REG, buffer); + +fail: + mtx_unlock(&sc->mtx); + + return (error); +} + +static int +tca6408_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + + if (pin >= PINS_NUM) + return (EINVAL); + + *caps = PIN_CAPS; + + return (0); +} +