bcm27xx: add support for linux v5.15
[openwrt/staging/chunkeey.git] / target / linux / bcm27xx / patches-5.15 / 950-0482-regulator-rpi-panel-Serialise-operations.patch
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.
5
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
9 with the Atmel.
10
11 Use a mutex within the driver to control overall accesses to
12 the Atmel, instead of the regmap lock.
13
14 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
15 ---
16 .../regulator/rpi-panel-attiny-regulator.c | 91 ++++++++++++++++---
17 1 file changed, 80 insertions(+), 11 deletions(-)
18
19 --- a/drivers/regulator/rpi-panel-attiny-regulator.c
20 +++ b/drivers/regulator/rpi-panel-attiny-regulator.c
21 @@ -27,18 +27,28 @@
22 #define REG_POWERON 0x85
23 #define REG_PWM 0x86
24
25 +struct attiny_lcd {
26 + /* lock to serialise overall accesses to the Atmel */
27 + struct mutex lock;
28 + struct regmap *regmap;
29 +};
30 +
31 static const struct regmap_config attiny_regmap_config = {
32 .reg_bits = 8,
33 .val_bits = 8,
34 + .disable_locking = 1,
35 .max_register = REG_PWM,
36 .cache_type = REGCACHE_NONE,
37 };
38
39 static int attiny_lcd_power_enable(struct regulator_dev *rdev)
40 {
41 + struct mutex *lock = rdev_get_drvdata(rdev);
42 unsigned int data;
43 int ret, i;
44
45 + mutex_lock(lock);
46 +
47 regmap_write(rdev->regmap, REG_POWERON, 1);
48 msleep(80);
49
50 @@ -63,33 +73,49 @@ static int attiny_lcd_power_enable(struc
51 */
52 regmap_write(rdev->regmap, REG_PORTA, BIT(2));
53
54 + mutex_unlock(lock);
55 +
56 return 0;
57 }
58
59 static int attiny_lcd_power_disable(struct regulator_dev *rdev)
60 {
61 + struct mutex *lock = rdev_get_drvdata(rdev);
62 +
63 + mutex_lock(lock);
64 +
65 regmap_write(rdev->regmap, REG_PWM, 0);
66 regmap_write(rdev->regmap, REG_POWERON, 0);
67 msleep(30);
68 +
69 + mutex_unlock(lock);
70 +
71 return 0;
72 }
73
74 static int attiny_lcd_power_is_enabled(struct regulator_dev *rdev)
75 {
76 + struct mutex *lock = rdev_get_drvdata(rdev);
77 unsigned int data;
78 int ret, i;
79
80 + mutex_lock(lock);
81 +
82 for (i = 0; i < 10; i++) {
83 ret = regmap_read(rdev->regmap, REG_POWERON, &data);
84 if (!ret)
85 break;
86 usleep_range(10000, 12000);
87 }
88 - if (ret < 0)
89 + if (ret < 0) {
90 + mutex_unlock(lock);
91 return ret;
92 + }
93
94 - if (!(data & BIT(0)))
95 + if (!(data & BIT(0))) {
96 + mutex_unlock(lock);
97 return 0;
98 + }
99
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);
104 }
105
106 + mutex_unlock(lock);
107 +
108 if (ret < 0)
109 return ret;
110
111 @@ -125,10 +153,13 @@ static const struct regulator_desc attin
112
113 static int attiny_update_status(struct backlight_device *bl)
114 {
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;
119 int ret, i;
120
121 + mutex_lock(&state->lock);
122 +
123 if (bl->props.power != FB_BLANK_UNBLANK ||
124 bl->props.fb_blank != FB_BLANK_UNBLANK)
125 brightness = 0;
126 @@ -139,20 +170,27 @@ static int attiny_update_status(struct b
127 break;
128 }
129
130 + mutex_unlock(&state->lock);
131 +
132 return ret;
133 }
134
135 static int attiny_get_brightness(struct backlight_device *bl)
136 {
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;
141
142 + mutex_lock(&state->lock);
143 +
144 for (i = 0; i < 10; i++) {
145 ret = regmap_read(regmap, REG_PWM, &brightness);
146 if (!ret)
147 break;
148 }
149
150 + mutex_unlock(&state->lock);
151 +
152 if (ret)
153 return ret;
154
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;
161 unsigned int data;
162 int ret;
163
164 + state = devm_kzalloc(&i2c->dev, sizeof(*state), GFP_KERNEL);
165 + if (!state)
166 + return -ENOMEM;
167 +
168 + mutex_init(&state->lock);
169 + i2c_set_clientdata(i2c, state);
170 +
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",
175 ret);
176 - return ret;
177 + goto error;
178 }
179
180 ret = regmap_read(regmap, REG_ID, &data);
181 if (ret < 0) {
182 dev_err(&i2c->dev, "Failed to read REG_ID reg: %d\n", ret);
183 - return ret;
184 + goto error;
185 }
186
187 switch (data) {
188 @@ -198,7 +244,8 @@ static int attiny_i2c_probe(struct i2c_c
189 break;
190 default:
191 dev_err(&i2c->dev, "Unknown Atmel firmware revision: 0x%02x\n", data);
192 - return -ENODEV;
193 + ret = -ENODEV;
194 + goto error;
195 }
196
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;
203
204 rdev = devm_regulator_register(&i2c->dev, &attiny_regulator, &config);
205 if (IS_ERR(rdev)) {
206 dev_err(&i2c->dev, "Failed to register ATTINY regulator\n");
207 - return PTR_ERR(rdev);
208 + ret = PTR_ERR(rdev);
209 + goto error;
210 }
211
212 props.type = BACKLIGHT_RAW;
213 props.max_brightness = 0xff;
214 +
215 + state->regmap = regmap;
216 +
217 bl = devm_backlight_device_register(&i2c->dev, dev_name(&i2c->dev),
218 - &i2c->dev, regmap, &attiny_bl,
219 + &i2c->dev, state, &attiny_bl,
220 &props);
221 - if (IS_ERR(bl))
222 - return PTR_ERR(bl);
223 + if (IS_ERR(bl)) {
224 + ret = PTR_ERR(bl);
225 + goto error;
226 + }
227
228 bl->props.brightness = 0xff;
229
230 return 0;
231 +
232 +error:
233 + mutex_destroy(&state->lock);
234 +
235 + return ret;
236 +}
237 +
238 +static int attiny_i2c_remove(struct i2c_client *client)
239 +{
240 + struct attiny_lcd *state = i2c_get_clientdata(client);
241 +
242 + mutex_destroy(&state->lock);
243 +
244 + return 0;
245 }
246
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),
250 },
251 .probe = attiny_i2c_probe,
252 + .remove = attiny_i2c_remove,
253 };
254
255 module_i2c_driver(attiny_regulator_driver);