From 06bab1f101337ae9469a7d2c6ac4de5db64e8160 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Apr 2025 09:36:28 +0200 Subject: [PATCH 1/4] regulator: rpi-panel-attiny: don't double-check GPIO range GPIO core already checks GPIO ranges, there's no need to check it again in the set() callback. Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250408-gpiochip-set-rv-regulator-v1-1-a18b6154b31a@linaro.org Signed-off-by: Mark Brown --- drivers/regulator/rpi-panel-attiny-regulator.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 6c3b6bfac961..f5ce50ced294 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -216,9 +216,6 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) struct attiny_lcd *state = gpiochip_get_data(gc); u8 last_val; - if (off >= NUM_GPIO) - return; - mutex_lock(&state->lock); last_val = attiny_get_port_state(state, mappings[off].reg); From 1326e295d6b4ffc9647bd4f073b787b4f79d6b6e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Apr 2025 09:36:29 +0200 Subject: [PATCH 2/4] regulator: rpi-panel-attiny: use devres for mutex management Simplify the probe() code and remove the remove() callback by using devres to manage the mutex resources. Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250408-gpiochip-set-rv-regulator-v1-2-a18b6154b31a@linaro.org Signed-off-by: Mark Brown --- .../regulator/rpi-panel-attiny-regulator.c | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index f5ce50ced294..5ff348939560 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -293,7 +294,10 @@ static int attiny_i2c_probe(struct i2c_client *i2c) if (!state) return -ENOMEM; - mutex_init(&state->lock); + ret = devm_mutex_init(&i2c->dev, &state->lock); + if (ret) + return ret; + i2c_set_clientdata(i2c, state); regmap = devm_regmap_init_i2c(i2c, &attiny_regmap_config); @@ -301,13 +305,13 @@ static int attiny_i2c_probe(struct i2c_client *i2c) ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - goto error; + return ret; } ret = attiny_i2c_read(i2c, REG_ID, &data); if (ret < 0) { dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret); - goto error; + return ret; } switch (data) { @@ -316,8 +320,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c) break; default: dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data); - ret = -ENODEV; - goto error; + return -ENODEV; } regmap_write(regmap, REG_POWERON, 0); @@ -333,8 +336,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c) rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config); if (IS_ERR(rdev)) { dev_err(&i2c->dev, "Failed to register ATTINY regulator\n"); - ret = PTR_ERR(rdev); - goto error; + return PTR_ERR(rdev); } props.type = BACKLIGHT_RAW; @@ -345,10 +347,8 @@ static int attiny_i2c_probe(struct i2c_client *i2c) bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev), &i2c->dev, state, &attiny_bl, &props); - if (IS_ERR(bl)) { - ret = PTR_ERR(bl); - goto error; - } + if (IS_ERR(bl)) + return PTR_ERR(bl); bl->props.brightness = 0xff; @@ -363,26 +363,12 @@ static int attiny_i2c_probe(struct i2c_client *i2c) state->gc.can_sleep = true; ret = devm_gpiochip_add_data(&i2c->dev, &state->gc, state); - if (ret) { + if (ret) dev_err(&i2c->dev, "Failed to create gpiochip: %d\n", ret); - goto error; - } - - return 0; - -error: - mutex_destroy(&state->lock); return ret; } -static void attiny_i2c_remove(struct i2c_client *client) -{ - struct attiny_lcd *state = i2c_get_clientdata(client); - - mutex_destroy(&state->lock); -} - static const struct of_device_id attiny_dt_ids[] = { { .compatible = "raspberrypi,7inch-touchscreen-panel-regulator" }, {}, @@ -396,7 +382,6 @@ static struct i2c_driver attiny_regulator_driver = { .of_match_table = attiny_dt_ids, }, .probe = attiny_i2c_probe, - .remove = attiny_i2c_remove, }; module_i2c_driver(attiny_regulator_driver); From 50faedda12e46918a11194a30c2bedf2b983fae2 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Apr 2025 09:36:30 +0200 Subject: [PATCH 3/4] regulator: rpi-panel-attiny: use lock guards for the state mutex Use mutex lock guards from linux/cleanup.h to simplify the driver code. Note that ret must be initialized in order to avoid a build warning as scoped_guard() is implemented as a for loop. Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250408-gpiochip-set-rv-regulator-v1-3-a18b6154b31a@linaro.org Signed-off-by: Mark Brown --- .../regulator/rpi-panel-attiny-regulator.c | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 5ff348939560..43a7c4737cb4 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -94,7 +95,7 @@ static int attiny_lcd_power_enable(struct regulator_dev *rdev) { struct attiny_lcd *state = rdev_get_drvdata(rdev); - mutex_lock(&state->lock); + guard(mutex)(&state->lock); /* Ensure bridge, and tp stay in reset */ attiny_set_port_state(state, REG_PORTC, 0); @@ -115,8 +116,6 @@ static int attiny_lcd_power_enable(struct regulator_dev *rdev) msleep(80); - mutex_unlock(&state->lock); - return 0; } @@ -124,7 +123,7 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) { struct attiny_lcd *state = rdev_get_drvdata(rdev); - mutex_lock(&state->lock); + guard(mutex)(&state->lock); regmap_write(rdev->regmap, REG_PWM, 0); usleep_range(5000, 10000); @@ -136,8 +135,6 @@ static int attiny_lcd_power_disable(struct regulator_dev *rdev) attiny_set_port_state(state, REG_PORTC, 0); msleep(30); - mutex_unlock(&state->lock); - return 0; } @@ -145,19 +142,17 @@ static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev) { struct attiny_lcd *state = rdev_get_drvdata(rdev); unsigned int data; - int ret, i; + int ret = 0, i; - mutex_lock(&state->lock); - - for (i = 0; i < 10; i++) { - ret = regmap_read(rdev->regmap, REG_PORTC, &data); - if (!ret) - break; - usleep_range(10000, 12000); + scoped_guard(mutex, &state->lock) { + for (i = 0; i < 10; i++) { + ret = regmap_read(rdev->regmap, REG_PORTC, &data); + if (!ret) + break; + usleep_range(10000, 12000); + } } - mutex_unlock(&state->lock); - if (ret < 0) return ret; @@ -190,7 +185,7 @@ static int attiny_update_status(struct backlight_device *bl) int brightness = backlight_get_brightness(bl); int ret, i; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); for (i = 0; i < 10; i++) { ret = regmap_write(regmap, REG_PWM, brightness); @@ -198,8 +193,6 @@ static int attiny_update_status(struct backlight_device *bl) break; } - mutex_unlock(&state->lock); - return ret; } @@ -217,7 +210,7 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) struct attiny_lcd *state = gpiochip_get_data(gc); u8 last_val; - mutex_lock(&state->lock); + guard(mutex)(&state->lock); last_val = attiny_get_port_state(state, mappings[off].reg); if (val) @@ -239,8 +232,6 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) msleep(100); } - - mutex_unlock(&state->lock); } static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) From 936df52c29b0d422665c5e84b0cffae61611411b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 8 Apr 2025 09:36:31 +0200 Subject: [PATCH 4/4] regulator: rpi-panel-attiny: use new GPIO line value setter callbacks struct gpio_chip now has callbacks for setting line values that return an integer, allowing to indicate failures. Convert the driver to using them. Signed-off-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250408-gpiochip-set-rv-regulator-v1-4-a18b6154b31a@linaro.org Signed-off-by: Mark Brown --- drivers/regulator/rpi-panel-attiny-regulator.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/rpi-panel-attiny-regulator.c b/drivers/regulator/rpi-panel-attiny-regulator.c index 43a7c4737cb4..58dbf8bffa5d 100644 --- a/drivers/regulator/rpi-panel-attiny-regulator.c +++ b/drivers/regulator/rpi-panel-attiny-regulator.c @@ -205,7 +205,7 @@ static int attiny_gpio_get_direction(struct gpio_chip *gc, unsigned int off) return GPIO_LINE_DIRECTION_OUT; } -static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) +static int attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) { struct attiny_lcd *state = gpiochip_get_data(gc); u8 last_val; @@ -232,6 +232,8 @@ static void attiny_gpio_set(struct gpio_chip *gc, unsigned int off, int val) msleep(100); } + + return 0; } static int attiny_i2c_read(struct i2c_client *client, u8 reg, unsigned int *buf) @@ -349,7 +351,7 @@ static int attiny_i2c_probe(struct i2c_client *i2c) state->gc.base = -1; state->gc.ngpio = NUM_GPIO; - state->gc.set = attiny_gpio_set; + state->gc.set_rv = attiny_gpio_set; state->gc.get_direction = attiny_gpio_get_direction; state->gc.can_sleep = true;