From: Gregor Herburger <gregor.herburger@ew.tq-group.com>
The mcp251xfd devices allow two pins to be configured as gpio. Add this
functionality to driver.
Signed-off-by: Gregor Herburger <gregor.herburger@ew.tq-group.com>
Tested-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
---
drivers/net/can/spi/mcp251xfd/Kconfig | 1 +
.../net/can/spi/mcp251xfd/mcp251xfd-core.c | 172 ++++++++++++++++++
drivers/net/can/spi/mcp251xfd/mcp251xfd.h | 2 +
3 files changed, 175 insertions(+)
diff --git a/drivers/net/can/spi/mcp251xfd/Kconfig b/drivers/net/can/spi/mcp251xfd/Kconfig
index 877e4356010d..7c29846e6051 100644
--- a/drivers/net/can/spi/mcp251xfd/Kconfig
+++ b/drivers/net/can/spi/mcp251xfd/Kconfig
@@ -5,6 +5,7 @@ config CAN_MCP251XFD
select CAN_RX_OFFLOAD
select REGMAP
select WANT_DEV_COREDUMP
+ select GPIOLIB
help
Driver for the Microchip MCP251XFD SPI FD-CAN controller
family.
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index ea41f04ae1a6..88035d4404b5 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -1797,6 +1797,172 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv)
return 0;
}
+static const char * const mcp251xfd_gpio_names[] = { "GPIO0", "GPIO1" };
+
+static int mcp251xfd_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 pin_mask = MCP251XFD_REG_IOCON_PM(offset);
+ int ret;
+
+ if (priv->rx_int && offset == 1) {
+ netdev_err(priv->ndev, "Can't use GPIO 1 with RX-INT!\n");
+ return -EINVAL;
+ }
+
+ ret = pm_runtime_resume_and_get(priv->ndev->dev.parent);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON,
+ pin_mask, pin_mask);
+}
+
+static void mcp251xfd_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+
+ pm_runtime_put(priv->ndev->dev.parent);
+}
+
+static int mcp251xfd_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 mask = MCP251XFD_REG_IOCON_TRIS(offset);
+ u32 val;
+ int ret;
+
+ ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val);
+ if (ret)
+ return ret;
+
+ if (mask & val)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int mcp251xfd_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 mask = MCP251XFD_REG_IOCON_GPIO(offset);
+ u32 val;
+ int ret;
+
+ ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val);
+ if (ret)
+ return ret;
+
+ return !!(mask & val);
+}
+
+static int mcp251xfd_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bit)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 val;
+ int ret;
+
+ ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val);
+ if (ret)
+ return ret;
+
+ *bit = FIELD_GET(MCP251XFD_REG_IOCON_GPIO_MASK, val) & *mask;
+
+ return 0;
+}
+
+static int mcp251xfd_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset);
+ u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset);
+ u32 val;
+
+ if (value)
+ val = val_mask;
+ else
+ val = 0;
+
+ return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON,
+ dir_mask | val_mask, val);
+}
+
+static int mcp251xfd_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset);
+
+ return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON,
+ dir_mask, dir_mask);
+}
+
+static int mcp251xfd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset);
+ u32 val;
+ int ret;
+
+ if (value)
+ val = val_mask;
+ else
+ val = 0;
+
+ ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, val_mask, val);
+ if (ret)
+ dev_err(&priv->spi->dev, "Failed to set GPIO %u: %d\n", offset, ret);
+
+ return ret;
+}
+
+static int mcp251xfd_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct mcp251xfd_priv *priv = gpiochip_get_data(chip);
+ u32 val;
+ int ret;
+
+ val = FIELD_PREP(MCP251XFD_REG_IOCON_LAT_MASK, *bits);
+
+ ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON,
+ MCP251XFD_REG_IOCON_LAT_MASK, val);
+ if (ret)
+ dev_err(&priv->spi->dev, "Failed to set GPIOs %d\n", ret);
+
+ return ret;
+}
+
+static int mcp251fdx_gpio_setup(struct mcp251xfd_priv *priv)
+{
+ struct gpio_chip *gc = &priv->gc;
+
+ if (!device_property_present(&priv->spi->dev, "gpio-controller"))
+ return 0;
+
+ gc->label = dev_name(&priv->spi->dev);
+ gc->parent = &priv->spi->dev;
+ gc->owner = THIS_MODULE;
+ gc->request = mcp251xfd_gpio_request;
+ gc->free = mcp251xfd_gpio_free;
+ gc->get_direction = mcp251xfd_gpio_get_direction;
+ gc->direction_output = mcp251xfd_gpio_direction_output;
+ gc->direction_input = mcp251xfd_gpio_direction_input;
+ gc->get = mcp251xfd_gpio_get;
+ gc->get_multiple = mcp251xfd_gpio_get_multiple;
+ gc->set = mcp251xfd_gpio_set;
+ gc->set_multiple = mcp251xfd_gpio_set_multiple;
+ gc->base = -1;
+ gc->can_sleep = true;
+ gc->ngpio = ARRAY_SIZE(mcp251xfd_gpio_names);
+ gc->names = mcp251xfd_gpio_names;
+
+ return devm_gpiochip_add_data(&priv->spi->dev, gc, priv);
+}
+
static int
mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
u32 *effective_speed_hz_slow,
@@ -1930,6 +2096,12 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
mcp251xfd_ethtool_init(priv);
+ err = mcp251fdx_gpio_setup(priv);
+ if (err) {
+ dev_err_probe(&priv->spi->dev, err, "Failed to register gpio-controller.\n");
+ goto out_runtime_disable;
+ }
+
err = register_candev(ndev);
if (err)
goto out_runtime_disable;
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index bd28510a6583..085d7101e595 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -15,6 +15,7 @@
#include <linux/can/dev.h>
#include <linux/can/rx-offload.h>
#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/regmap.h>
@@ -676,6 +677,7 @@ struct mcp251xfd_priv {
struct mcp251xfd_devtype_data devtype_data;
struct can_berr_counter bec;
+ struct gpio_chip gc;
};
#define MCP251XFD_IS(_model) \
--
2.34.1
On Fri, Sep 26, 2025 at 3:30 PM Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> wrote: > > From: Gregor Herburger <gregor.herburger@ew.tq-group.com> > > The mcp251xfd devices allow two pins to be configured as gpio. Add this > functionality to driver. > > Signed-off-by: Gregor Herburger <gregor.herburger@ew.tq-group.com> > Tested-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> > Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> > --- > drivers/net/can/spi/mcp251xfd/Kconfig | 1 + > .../net/can/spi/mcp251xfd/mcp251xfd-core.c | 172 ++++++++++++++++++ > drivers/net/can/spi/mcp251xfd/mcp251xfd.h | 2 + > 3 files changed, 175 insertions(+) > > diff --git a/drivers/net/can/spi/mcp251xfd/Kconfig b/drivers/net/can/spi/mcp251xfd/Kconfig > index 877e4356010d..7c29846e6051 100644 > --- a/drivers/net/can/spi/mcp251xfd/Kconfig > +++ b/drivers/net/can/spi/mcp251xfd/Kconfig > @@ -5,6 +5,7 @@ config CAN_MCP251XFD > select CAN_RX_OFFLOAD > select REGMAP > select WANT_DEV_COREDUMP > + select GPIOLIB > help > Driver for the Microchip MCP251XFD SPI FD-CAN controller > family. > diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c > index ea41f04ae1a6..88035d4404b5 100644 > --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c > +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c > @@ -1797,6 +1797,172 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv) > return 0; > } > > +static const char * const mcp251xfd_gpio_names[] = { "GPIO0", "GPIO1" }; > + > +static int mcp251xfd_gpio_request(struct gpio_chip *chip, unsigned int offset) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 pin_mask = MCP251XFD_REG_IOCON_PM(offset); > + int ret; > + > + if (priv->rx_int && offset == 1) { > + netdev_err(priv->ndev, "Can't use GPIO 1 with RX-INT!\n"); > + return -EINVAL; > + } > + > + ret = pm_runtime_resume_and_get(priv->ndev->dev.parent); > + if (ret) > + return ret; > + > + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, > + pin_mask, pin_mask); > +} > + > +static void mcp251xfd_gpio_free(struct gpio_chip *chip, unsigned int offset) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + > + pm_runtime_put(priv->ndev->dev.parent); > +} > + > +static int mcp251xfd_gpio_get_direction(struct gpio_chip *chip, > + unsigned int offset) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 mask = MCP251XFD_REG_IOCON_TRIS(offset); > + u32 val; > + int ret; > + > + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); > + if (ret) > + return ret; > + > + if (mask & val) > + return GPIO_LINE_DIRECTION_IN; > + > + return GPIO_LINE_DIRECTION_OUT; > +} > + > +static int mcp251xfd_gpio_get(struct gpio_chip *chip, unsigned int offset) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 mask = MCP251XFD_REG_IOCON_GPIO(offset); > + u32 val; > + int ret; > + > + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); > + if (ret) > + return ret; > + > + return !!(mask & val); > +} > + > +static int mcp251xfd_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, > + unsigned long *bit) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 val; > + int ret; > + > + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); > + if (ret) > + return ret; > + > + *bit = FIELD_GET(MCP251XFD_REG_IOCON_GPIO_MASK, val) & *mask; > + > + return 0; > +} > + > +static int mcp251xfd_gpio_direction_output(struct gpio_chip *chip, > + unsigned int offset, int value) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset); > + u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset); > + u32 val; > + > + if (value) > + val = val_mask; > + else > + val = 0; > + > + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, > + dir_mask | val_mask, val); > +} > + > +static int mcp251xfd_gpio_direction_input(struct gpio_chip *chip, > + unsigned int offset) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset); > + > + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, > + dir_mask, dir_mask); > +} > + > +static int mcp251xfd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset); > + u32 val; > + int ret; > + > + if (value) > + val = val_mask; > + else > + val = 0; > + > + ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, val_mask, val); > + if (ret) > + dev_err(&priv->spi->dev, "Failed to set GPIO %u: %d\n", offset, ret); Why do you loudly complain here but not in other callbacks? I assume it's because you had a log here in your previous version (the one rebased on v6.16) and just didn't remove it when you switched to the new API? Maybe just do `return regmap_update...`? Otherwise looks good. With that addressed: Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> > + > + return ret; > +} > + > +static int mcp251xfd_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, > + unsigned long *bits) > +{ > + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); > + u32 val; > + int ret; > + > + val = FIELD_PREP(MCP251XFD_REG_IOCON_LAT_MASK, *bits); > + > + ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, > + MCP251XFD_REG_IOCON_LAT_MASK, val); > + if (ret) > + dev_err(&priv->spi->dev, "Failed to set GPIOs %d\n", ret); > + > + return ret; > +} > + > +static int mcp251fdx_gpio_setup(struct mcp251xfd_priv *priv) > +{ > + struct gpio_chip *gc = &priv->gc; > + > + if (!device_property_present(&priv->spi->dev, "gpio-controller")) > + return 0; > + > + gc->label = dev_name(&priv->spi->dev); > + gc->parent = &priv->spi->dev; > + gc->owner = THIS_MODULE; > + gc->request = mcp251xfd_gpio_request; > + gc->free = mcp251xfd_gpio_free; > + gc->get_direction = mcp251xfd_gpio_get_direction; > + gc->direction_output = mcp251xfd_gpio_direction_output; > + gc->direction_input = mcp251xfd_gpio_direction_input; > + gc->get = mcp251xfd_gpio_get; > + gc->get_multiple = mcp251xfd_gpio_get_multiple; > + gc->set = mcp251xfd_gpio_set; > + gc->set_multiple = mcp251xfd_gpio_set_multiple; > + gc->base = -1; > + gc->can_sleep = true; > + gc->ngpio = ARRAY_SIZE(mcp251xfd_gpio_names); > + gc->names = mcp251xfd_gpio_names; > + > + return devm_gpiochip_add_data(&priv->spi->dev, gc, priv); > +} > + > static int > mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id, > u32 *effective_speed_hz_slow, > @@ -1930,6 +2096,12 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv) > > mcp251xfd_ethtool_init(priv); > > + err = mcp251fdx_gpio_setup(priv); > + if (err) { > + dev_err_probe(&priv->spi->dev, err, "Failed to register gpio-controller.\n"); > + goto out_runtime_disable; > + } > + > err = register_candev(ndev); > if (err) > goto out_runtime_disable; > diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h > index bd28510a6583..085d7101e595 100644 > --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h > +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h > @@ -15,6 +15,7 @@ > #include <linux/can/dev.h> > #include <linux/can/rx-offload.h> > #include <linux/gpio/consumer.h> > +#include <linux/gpio/driver.h> > #include <linux/kernel.h> > #include <linux/netdevice.h> > #include <linux/regmap.h> > @@ -676,6 +677,7 @@ struct mcp251xfd_priv { > > struct mcp251xfd_devtype_data devtype_data; > struct can_berr_counter bec; > + struct gpio_chip gc; > }; > > #define MCP251XFD_IS(_model) \ > -- > 2.34.1 >
On 9/29/2025 7:08 PM, Bartosz Golaszewski wrote: > On Fri, Sep 26, 2025 at 3:30 PM Viken Dadhaniya > <viken.dadhaniya@oss.qualcomm.com> wrote: >> >> From: Gregor Herburger <gregor.herburger@ew.tq-group.com> >> >> The mcp251xfd devices allow two pins to be configured as gpio. Add this >> functionality to driver. >> >> Signed-off-by: Gregor Herburger <gregor.herburger@ew.tq-group.com> >> Tested-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> >> Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com> >> --- >> drivers/net/can/spi/mcp251xfd/Kconfig | 1 + >> .../net/can/spi/mcp251xfd/mcp251xfd-core.c | 172 ++++++++++++++++++ >> drivers/net/can/spi/mcp251xfd/mcp251xfd.h | 2 + >> 3 files changed, 175 insertions(+) >> >> diff --git a/drivers/net/can/spi/mcp251xfd/Kconfig b/drivers/net/can/spi/mcp251xfd/Kconfig >> index 877e4356010d..7c29846e6051 100644 >> --- a/drivers/net/can/spi/mcp251xfd/Kconfig >> +++ b/drivers/net/can/spi/mcp251xfd/Kconfig >> @@ -5,6 +5,7 @@ config CAN_MCP251XFD >> select CAN_RX_OFFLOAD >> select REGMAP >> select WANT_DEV_COREDUMP >> + select GPIOLIB >> help >> Driver for the Microchip MCP251XFD SPI FD-CAN controller >> family. >> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c >> index ea41f04ae1a6..88035d4404b5 100644 >> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c >> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c >> @@ -1797,6 +1797,172 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv) >> return 0; >> } >> >> +static const char * const mcp251xfd_gpio_names[] = { "GPIO0", "GPIO1" }; >> + >> +static int mcp251xfd_gpio_request(struct gpio_chip *chip, unsigned int offset) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 pin_mask = MCP251XFD_REG_IOCON_PM(offset); >> + int ret; >> + >> + if (priv->rx_int && offset == 1) { >> + netdev_err(priv->ndev, "Can't use GPIO 1 with RX-INT!\n"); >> + return -EINVAL; >> + } >> + >> + ret = pm_runtime_resume_and_get(priv->ndev->dev.parent); >> + if (ret) >> + return ret; >> + >> + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, >> + pin_mask, pin_mask); >> +} >> + >> +static void mcp251xfd_gpio_free(struct gpio_chip *chip, unsigned int offset) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + >> + pm_runtime_put(priv->ndev->dev.parent); >> +} >> + >> +static int mcp251xfd_gpio_get_direction(struct gpio_chip *chip, >> + unsigned int offset) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 mask = MCP251XFD_REG_IOCON_TRIS(offset); >> + u32 val; >> + int ret; >> + >> + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); >> + if (ret) >> + return ret; >> + >> + if (mask & val) >> + return GPIO_LINE_DIRECTION_IN; >> + >> + return GPIO_LINE_DIRECTION_OUT; >> +} >> + >> +static int mcp251xfd_gpio_get(struct gpio_chip *chip, unsigned int offset) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 mask = MCP251XFD_REG_IOCON_GPIO(offset); >> + u32 val; >> + int ret; >> + >> + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); >> + if (ret) >> + return ret; >> + >> + return !!(mask & val); >> +} >> + >> +static int mcp251xfd_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, >> + unsigned long *bit) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 val; >> + int ret; >> + >> + ret = regmap_read(priv->map_reg, MCP251XFD_REG_IOCON, &val); >> + if (ret) >> + return ret; >> + >> + *bit = FIELD_GET(MCP251XFD_REG_IOCON_GPIO_MASK, val) & *mask; >> + >> + return 0; >> +} >> + >> +static int mcp251xfd_gpio_direction_output(struct gpio_chip *chip, >> + unsigned int offset, int value) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset); >> + u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset); >> + u32 val; >> + >> + if (value) >> + val = val_mask; >> + else >> + val = 0; >> + >> + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, >> + dir_mask | val_mask, val); >> +} >> + >> +static int mcp251xfd_gpio_direction_input(struct gpio_chip *chip, >> + unsigned int offset) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 dir_mask = MCP251XFD_REG_IOCON_TRIS(offset); >> + >> + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, >> + dir_mask, dir_mask); >> +} >> + >> +static int mcp251xfd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 val_mask = MCP251XFD_REG_IOCON_LAT(offset); >> + u32 val; >> + int ret; >> + >> + if (value) >> + val = val_mask; >> + else >> + val = 0; >> + >> + ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, val_mask, val); >> + if (ret) >> + dev_err(&priv->spi->dev, "Failed to set GPIO %u: %d\n", offset, ret); > > Why do you loudly complain here but not in other callbacks? I assume > it's because you had a log here in your previous version (the one > rebased on v6.16) and just didn't remove it when you switched to the > new API? Maybe just do `return regmap_update...`? Sure, I’ll update and post v6. > > Otherwise looks good. With that addressed: > > Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> > >> + >> + return ret; >> +} >> + >> +static int mcp251xfd_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, >> + unsigned long *bits) >> +{ >> + struct mcp251xfd_priv *priv = gpiochip_get_data(chip); >> + u32 val; >> + int ret; >> + >> + val = FIELD_PREP(MCP251XFD_REG_IOCON_LAT_MASK, *bits); >> + >> + ret = regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, >> + MCP251XFD_REG_IOCON_LAT_MASK, val); >> + if (ret) >> + dev_err(&priv->spi->dev, "Failed to set GPIOs %d\n", ret); >> + >> + return ret; >> +} >> + >> +static int mcp251fdx_gpio_setup(struct mcp251xfd_priv *priv) >> +{ >> + struct gpio_chip *gc = &priv->gc; >> + >> + if (!device_property_present(&priv->spi->dev, "gpio-controller")) >> + return 0; >> + >> + gc->label = dev_name(&priv->spi->dev); >> + gc->parent = &priv->spi->dev; >> + gc->owner = THIS_MODULE; >> + gc->request = mcp251xfd_gpio_request; >> + gc->free = mcp251xfd_gpio_free; >> + gc->get_direction = mcp251xfd_gpio_get_direction; >> + gc->direction_output = mcp251xfd_gpio_direction_output; >> + gc->direction_input = mcp251xfd_gpio_direction_input; >> + gc->get = mcp251xfd_gpio_get; >> + gc->get_multiple = mcp251xfd_gpio_get_multiple; >> + gc->set = mcp251xfd_gpio_set; >> + gc->set_multiple = mcp251xfd_gpio_set_multiple; >> + gc->base = -1; >> + gc->can_sleep = true; >> + gc->ngpio = ARRAY_SIZE(mcp251xfd_gpio_names); >> + gc->names = mcp251xfd_gpio_names; >> + >> + return devm_gpiochip_add_data(&priv->spi->dev, gc, priv); >> +} >> + >> static int >> mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id, >> u32 *effective_speed_hz_slow, >> @@ -1930,6 +2096,12 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv) >> >> mcp251xfd_ethtool_init(priv); >> >> + err = mcp251fdx_gpio_setup(priv); >> + if (err) { >> + dev_err_probe(&priv->spi->dev, err, "Failed to register gpio-controller.\n"); >> + goto out_runtime_disable; >> + } >> + >> err = register_candev(ndev); >> if (err) >> goto out_runtime_disable; >> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h >> index bd28510a6583..085d7101e595 100644 >> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h >> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h >> @@ -15,6 +15,7 @@ >> #include <linux/can/dev.h> >> #include <linux/can/rx-offload.h> >> #include <linux/gpio/consumer.h> >> +#include <linux/gpio/driver.h> >> #include <linux/kernel.h> >> #include <linux/netdevice.h> >> #include <linux/regmap.h> >> @@ -676,6 +677,7 @@ struct mcp251xfd_priv { >> >> struct mcp251xfd_devtype_data devtype_data; >> struct can_berr_counter bec; >> + struct gpio_chip gc; >> }; >> >> #define MCP251XFD_IS(_model) \ >> -- >> 2.34.1 >>
© 2016 - 2025 Red Hat, Inc.