On Mon, 27 Jan 2025 12:13:45 -0300 Jonathan Santos <Jonathan.Santos@xxxxxxxxxx> wrote: > From: Sergiu Cuciurean <sergiu.cuciurean@xxxxxxxxxx> > > The AD7768-1 has the ability to control other local hardware (such as gain > stages),to power down other blocks in the signal chain, or read local > status signals over the SPI interface. > > This change exports the AD7768-1's four gpios and makes them accessible > at an upper layer. > > Co-developed-by: Jonathan Santos <Jonathan.Santos@xxxxxxxxxx> > Signed-off-by: Jonathan Santos <Jonathan.Santos@xxxxxxxxxx> > Signed-off-by: Sergiu Cuciurean <sergiu.cuciurean@xxxxxxxxxx> As David observed, the direct mode release calls are missing. Also, there are a few places where you wrap lines much shorter than needed. > +static int ad7768_gpio_direction_output(struct gpio_chip *chip, > + unsigned int offset, int value) > +{ > + struct iio_dev *indio_dev = gpiochip_get_data(chip); > + struct ad7768_state *st = iio_priv(indio_dev); > + int ret; > + > + ret = iio_device_claim_direct_mode(indio_dev); > + if (ret) > + return ret; > + > + return regmap_update_bits(st->regmap, > + AD7768_REG_GPIO_CONTROL, > + BIT(offset), > + AD7768_GPIO_OUTPUT(offset)); Again, wrap less. > +} > + > +static int ad7768_gpio_get(struct gpio_chip *chip, unsigned int offset) > +{ > + struct iio_dev *indio_dev = gpiochip_get_data(chip); > + struct ad7768_state *st = iio_priv(indio_dev); > + unsigned int val; > + int ret; > + > + ret = iio_device_claim_direct_mode(indio_dev); You aren't releasing it. That should have deadlocked the second time you called this. > + if (ret) > + return ret; > + > + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val); > + if (ret < 0) > + return ret; > + > + if (val & BIT(offset)) > + ret = regmap_read(st->regmap, AD7768_REG_GPIO_WRITE, &val); > + else > + ret = regmap_read(st->regmap, AD7768_REG_GPIO_READ, &val); > + if (ret < 0) > + return ret; > + > + return !!(val & BIT(offset)); > +} > + > +static void ad7768_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) > +{ > + struct iio_dev *indio_dev = gpiochip_get_data(chip); > + struct ad7768_state *st = iio_priv(indio_dev); > + unsigned int val; > + int ret; > + > + ret = iio_device_claim_direct_mode(indio_dev); As above, needs a matching release. May mean you want to factor out the guts of this as a helper function so you can still do direct returns on error. > + if (ret) > + return; > + > + ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val); > + if (ret < 0) > + return; > + > + if (val & BIT(offset)) > + regmap_update_bits(st->regmap, > + AD7768_REG_GPIO_WRITE, > + BIT(offset), > + (value << offset)); Wrap a little less and drop the unnecessary brackets. regmap_update_bits(st->regmap, AD7768_REG_GPIO_WRITE, BIT(offset), value << offset); Also, check return value? > +} > + > + > +static int ad7768_gpio_init(struct iio_dev *indio_dev) > +{ > + struct ad7768_state *st = iio_priv(indio_dev); > + int ret; > + > + ret = regmap_write(st->regmap, AD7768_REG_GPIO_CONTROL, > + AD7768_GPIO_UNIVERSAL_EN); > + if (ret < 0) > + return ret; > + > + st->gpio_avail_map = AD7768_GPIO_CONTROL_MSK; > + st->gpiochip.label = "ad7768_1_gpios"; > + st->gpiochip.base = -1; > + st->gpiochip.ngpio = 4; > + st->gpiochip.parent = &st->spi->dev; > + st->gpiochip.can_sleep = true; > + st->gpiochip.direction_input = ad7768_gpio_direction_input; > + st->gpiochip.direction_output = ad7768_gpio_direction_output; > + st->gpiochip.get = ad7768_gpio_get; > + st->gpiochip.set = ad7768_gpio_set; > + st->gpiochip.request = ad7768_gpio_request; > + st->gpiochip.owner = THIS_MODULE; Might not be worth it but I'd be tempted to do st->gpiochip = (struct gpio_chip) { .label = "ad7768_1_gpios", .base = -1, .ngpio = 4, ... }; perhaps. This one is entirely up to your preference. > + > + return gpiochip_add_data(&st->gpiochip, indio_dev); > +} > +