1 From 354dfe9793ff5f814830c6841ca07ef04bfd66e9 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Wed, 8 Sep 2021 15:02:05 +0100
4 Subject: [PATCH] regulator: rpi-panel: Serialise operations.
6 The driver was using the regmap lock to serialise the
7 individual accesses, but we really need to protect the
8 timings of enabling the regulators, including any communication
11 Use a mutex within the driver to control overall accesses to
12 the Atmel, instead of the regmap lock.
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
16 .../regulator/rpi-panel-attiny-regulator.c | 91 ++++++++++++++++---
17 1 file changed, 80 insertions(+), 11 deletions(-)
19 --- a/drivers/regulator/rpi-panel-attiny-regulator.c
20 +++ b/drivers/regulator/rpi-panel-attiny-regulator.c
22 #define REG_POWERON 0x85
26 + /* lock to serialise overall accesses to the Atmel */
28 + struct regmap *regmap;
31 static const struct regmap_config attiny_regmap_config = {
34 + .disable_locking = 1,
35 .max_register = REG_PWM,
36 .cache_type = REGCACHE_NONE,
39 static int attiny_lcd_power_enable(struct regulator_dev *rdev)
41 + struct mutex *lock = rdev_get_drvdata(rdev);
47 regmap_write(rdev->regmap, REG_POWERON, 1);
50 @@ -63,33 +73,49 @@ static int attiny_lcd_power_enable(struc
52 regmap_write(rdev->regmap, REG_PORTA, BIT(2));
59 static int attiny_lcd_power_disable(struct regulator_dev *rdev)
61 + struct mutex *lock = rdev_get_drvdata(rdev);
65 regmap_write(rdev->regmap, REG_PWM, 0);
66 regmap_write(rdev->regmap, REG_POWERON, 0);
74 static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
76 + struct mutex *lock = rdev_get_drvdata(rdev);
82 for (i = 0; i < 10; i++) {
83 ret = regmap_read(rdev->regmap, REG_POWERON, &data);
86 usleep_range(10000, 12000);
94 - if (!(data & BIT(0)))
95 + if (!(data & BIT(0))) {
100 for (i = 0; i < 10; i++) {
101 ret = regmap_read(rdev->regmap, REG_PORTB, &data);
102 @@ -98,6 +124,8 @@ static int attiny_lcd_power_is_enabled(s
103 usleep_range(10000, 12000);
106 + mutex_unlock(lock);
111 @@ -125,10 +153,13 @@ static const struct regulator_desc attin
113 static int attiny_update_status(struct backlight_device *bl)
115 - struct regmap *regmap = bl_get_data(bl);
116 + struct attiny_lcd *state = bl_get_data(bl);
117 + struct regmap *regmap = state->regmap;
118 int brightness = bl->props.brightness;
121 + mutex_lock(&state->lock);
123 if (bl->props.power != FB_BLANK_UNBLANK ||
124 bl->props.fb_blank != FB_BLANK_UNBLANK)
126 @@ -139,20 +170,27 @@ static int attiny_update_status(struct b
130 + mutex_unlock(&state->lock);
135 static int attiny_get_brightness(struct backlight_device *bl)
137 - struct regmap *regmap = bl_get_data(bl);
138 + struct attiny_lcd *state = bl_get_data(bl);
139 + struct regmap *regmap = state->regmap;
140 int ret, brightness, i;
142 + mutex_lock(&state->lock);
144 for (i = 0; i < 10; i++) {
145 ret = regmap_read(regmap, REG_PWM, &brightness);
150 + mutex_unlock(&state->lock);
155 @@ -174,22 +212,30 @@ static int attiny_i2c_probe(struct i2c_c
156 struct regulator_config config = { };
157 struct backlight_device *bl;
158 struct regulator_dev *rdev;
159 + struct attiny_lcd *state;
160 struct regmap *regmap;
164 + state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL);
168 + mutex_init(&state->lock);
169 + i2c_set_clientdata(i2c, state);
171 regmap = devm_regmap_init_i2c(i2c, &attiny_regmap_config);
172 if (IS_ERR(regmap)) {
173 ret = PTR_ERR(regmap);
174 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
180 ret = regmap_read(regmap, REG_ID, &data);
182 dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret);
188 @@ -198,7 +244,8 @@ static int attiny_i2c_probe(struct i2c_c
191 dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data);
197 regmap_write(regmap, REG_POWERON, 0);
198 @@ -208,24 +255,45 @@ static int attiny_i2c_probe(struct i2c_c
199 config.regmap = regmap;
200 config.of_node = i2c->dev.of_node;
201 config.init_data = &attiny_regulator_default;
202 + config.driver_data = &state->lock;
204 rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
206 dev_err(&i2c->dev, "Failed to register ATTINY regulator\n");
207 - return PTR_ERR(rdev);
208 + ret = PTR_ERR(rdev);
212 props.type = BACKLIGHT_RAW;
213 props.max_brightness = 0xff;
215 + state->regmap = regmap;
217 bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev),
218 - &i2c->dev, regmap, &attiny_bl,
219 + &i2c->dev, state, &attiny_bl,
222 - return PTR_ERR(bl);
228 bl->props.brightness = 0xff;
233 + mutex_destroy(&state->lock);
238 +static int attiny_i2c_remove(struct i2c_client *client)
240 + struct attiny_lcd *state = i2c_get_clientdata(client);
242 + mutex_destroy(&state->lock);
247 static const struct of_device_id attiny_dt_ids[] = {
248 @@ -240,6 +308,7 @@ static struct i2c_driver attiny_regulato
249 .of_match_table = of_match_ptr(attiny_dt_ids),
251 .probe = attiny_i2c_probe,
252 + .remove = attiny_i2c_remove,
255 module_i2c_driver(attiny_regulator_driver);