Skip to content

Commit 00440bc

Browse files
6by9broonie
authored andcommitted
regulator: rpi-panel: Serialise operations.
The driver was using the regmap lock to serialise the individual accesses, but we really need to protect the timings of enabling the regulators, including any communication with the Atmel. Use a mutex within the driver to control overall accesses to the Atmel, instead of the regmap lock. Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com> Link: https://lore.kernel.org/r/20220124220129.158891-4-detlev.casanova@collabora.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 5665eee commit 00440bc

1 file changed

Lines changed: 80 additions & 11 deletions

File tree

drivers/regulator/rpi-panel-attiny-regulator.c

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,28 @@
2727
#define REG_POWERON 0x85
2828
#define REG_PWM 0x86
2929

30+
struct attiny_lcd {
31+
/* lock to serialise overall accesses to the Atmel */
32+
struct mutex lock;
33+
struct regmap *regmap;
34+
};
35+
3036
static const struct regmap_config attiny_regmap_config = {
3137
.reg_bits = 8,
3238
.val_bits = 8,
39+
.disable_locking = 1,
3340
.max_register = REG_PWM,
3441
.cache_type = REGCACHE_NONE,
3542
};
3643

3744
static int attiny_lcd_power_enable(struct regulator_dev *rdev)
3845
{
46+
struct mutex *lock = rdev_get_drvdata(rdev);
3947
unsigned int data;
4048
int ret, i;
4149

50+
mutex_lock(lock);
51+
4252
regmap_write(rdev->regmap, REG_POWERON, 1);
4353
msleep(80);
4454

@@ -63,33 +73,49 @@ static int attiny_lcd_power_enable(struct regulator_dev *rdev)
6373
*/
6474
regmap_write(rdev->regmap, REG_PORTA, BIT(2));
6575

76+
mutex_unlock(lock);
77+
6678
return 0;
6779
}
6880

6981
static int attiny_lcd_power_disable(struct regulator_dev *rdev)
7082
{
83+
struct mutex *lock = rdev_get_drvdata(rdev);
84+
85+
mutex_lock(lock);
86+
7187
regmap_write(rdev->regmap, REG_PWM, 0);
7288
regmap_write(rdev->regmap, REG_POWERON, 0);
7389
msleep(30);
90+
91+
mutex_unlock(lock);
92+
7493
return 0;
7594
}
7695

7796
static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
7897
{
98+
struct mutex *lock = rdev_get_drvdata(rdev);
7999
unsigned int data;
80100
int ret, i;
81101

102+
mutex_lock(lock);
103+
82104
for (i = 0; i < 10; i++) {
83105
ret = regmap_read(rdev->regmap, REG_POWERON, &data);
84106
if (!ret)
85107
break;
86108
usleep_range(10000, 12000);
87109
}
88-
if (ret < 0)
110+
if (ret < 0) {
111+
mutex_unlock(lock);
89112
return ret;
113+
}
90114

91-
if (!(data & BIT(0)))
115+
if (!(data & BIT(0))) {
116+
mutex_unlock(lock);
92117
return 0;
118+
}
93119

94120
for (i = 0; i < 10; i++) {
95121
ret = regmap_read(rdev->regmap, REG_PORTB, &data);
@@ -98,6 +124,8 @@ static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
98124
usleep_range(10000, 12000);
99125
}
100126

127+
mutex_unlock(lock);
128+
101129
if (ret < 0)
102130
return ret;
103131

@@ -125,10 +153,13 @@ static const struct regulator_desc attiny_regulator = {
125153

126154
static int attiny_update_status(struct backlight_device *bl)
127155
{
128-
struct regmap *regmap = bl_get_data(bl);
156+
struct attiny_lcd *state = bl_get_data(bl);
157+
struct regmap *regmap = state->regmap;
129158
int brightness = bl->props.brightness;
130159
int ret, i;
131160

161+
mutex_lock(&state->lock);
162+
132163
if (bl->props.power != FB_BLANK_UNBLANK ||
133164
bl->props.fb_blank != FB_BLANK_UNBLANK)
134165
brightness = 0;
@@ -139,20 +170,27 @@ static int attiny_update_status(struct backlight_device *bl)
139170
break;
140171
}
141172

173+
mutex_unlock(&state->lock);
174+
142175
return ret;
143176
}
144177

145178
static int attiny_get_brightness(struct backlight_device *bl)
146179
{
147-
struct regmap *regmap = bl_get_data(bl);
180+
struct attiny_lcd *state = bl_get_data(bl);
181+
struct regmap *regmap = state->regmap;
148182
int ret, brightness, i;
149183

184+
mutex_lock(&state->lock);
185+
150186
for (i = 0; i < 10; i++) {
151187
ret = regmap_read(regmap, REG_PWM, &brightness);
152188
if (!ret)
153189
break;
154190
}
155191

192+
mutex_unlock(&state->lock);
193+
156194
if (ret)
157195
return ret;
158196

@@ -174,22 +212,30 @@ static int attiny_i2c_probe(struct i2c_client *i2c,
174212
struct regulator_config config = { };
175213
struct backlight_device *bl;
176214
struct regulator_dev *rdev;
215+
struct attiny_lcd *state;
177216
struct regmap *regmap;
178217
unsigned int data;
179218
int ret;
180219

220+
state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL);
221+
if (!state)
222+
return -ENOMEM;
223+
224+
mutex_init(&state->lock);
225+
i2c_set_clientdata(i2c, state);
226+
181227
regmap = devm_regmap_init_i2c(i2c, &attiny_regmap_config);
182228
if (IS_ERR(regmap)) {
183229
ret = PTR_ERR(regmap);
184230
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
185231
ret);
186-
return ret;
232+
goto error;
187233
}
188234

189235
ret = regmap_read(regmap, REG_ID, &data);
190236
if (ret < 0) {
191237
dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret);
192-
return ret;
238+
goto error;
193239
}
194240

195241
switch (data) {
@@ -198,7 +244,8 @@ static int attiny_i2c_probe(struct i2c_client *i2c,
198244
break;
199245
default:
200246
dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data);
201-
return -ENODEV;
247+
ret = -ENODEV;
248+
goto error;
202249
}
203250

204251
regmap_write(regmap, REG_POWERON, 0);
@@ -208,23 +255,44 @@ static int attiny_i2c_probe(struct i2c_client *i2c,
208255
config.regmap = regmap;
209256
config.of_node = i2c->dev.of_node;
210257
config.init_data = &attiny_regulator_default;
258+
config.driver_data = &state->lock;
211259

212260
rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
213261
if (IS_ERR(rdev)) {
214262
dev_err(&i2c->dev, "Failed to register ATTINY regulator\n");
215-
return PTR_ERR(rdev);
263+
ret = PTR_ERR(rdev);
264+
goto error;
216265
}
217266

218267
props.type = BACKLIGHT_RAW;
219268
props.max_brightness = 0xff;
269+
270+
state->regmap = regmap;
271+
220272
bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev),
221-
&i2c->dev, regmap, &attiny_bl,
273+
&i2c->dev, state, &attiny_bl,
222274
&props);
223-
if (IS_ERR(bl))
224-
return PTR_ERR(bl);
275+
if (IS_ERR(bl)) {
276+
ret = PTR_ERR(bl);
277+
goto error;
278+
}
225279

226280
bl->props.brightness = 0xff;
227281

282+
return 0;
283+
284+
error:
285+
mutex_destroy(&state->lock);
286+
287+
return ret;
288+
}
289+
290+
static int attiny_i2c_remove(struct i2c_client *client)
291+
{
292+
struct attiny_lcd *state = i2c_get_clientdata(client);
293+
294+
mutex_destroy(&state->lock);
295+
228296
return 0;
229297
}
230298

@@ -240,6 +308,7 @@ static struct i2c_driver attiny_regulator_driver = {
240308
.of_match_table = of_match_ptr(attiny_dt_ids),
241309
},
242310
.probe = attiny_i2c_probe,
311+
.remove = attiny_i2c_remove,
243312
};
244313

245314
module_i2c_driver(attiny_regulator_driver);

0 commit comments

Comments
 (0)