9
9
#include <linux/i2c.h>
10
10
#include <linux/module.h>
11
11
#include <linux/of_graph.h>
12
+ #include <linux/pm_runtime.h>
12
13
#include <linux/regmap.h>
13
14
#include <linux/regulator/consumer.h>
14
15
@@ -100,7 +101,7 @@ struct ps8640 {
100
101
struct regulator_bulk_data supplies [2 ];
101
102
struct gpio_desc * gpio_reset ;
102
103
struct gpio_desc * gpio_powerdown ;
103
- bool powered ;
104
+ bool pre_enabled ;
104
105
};
105
106
106
107
static const struct regmap_config ps8640_regmap_config [] = {
@@ -148,8 +149,29 @@ static inline struct ps8640 *aux_to_ps8640(struct drm_dp_aux *aux)
148
149
return container_of (aux , struct ps8640 , aux );
149
150
}
150
151
151
- static ssize_t ps8640_aux_transfer (struct drm_dp_aux * aux ,
152
- struct drm_dp_aux_msg * msg )
152
+ static int ps8640_ensure_hpd (struct ps8640 * ps_bridge )
153
+ {
154
+ struct regmap * map = ps_bridge -> regmap [PAGE2_TOP_CNTL ];
155
+ struct device * dev = & ps_bridge -> page [PAGE2_TOP_CNTL ]-> dev ;
156
+ int status ;
157
+ int ret ;
158
+
159
+ /*
160
+ * Apparently something about the firmware in the chip signals that
161
+ * HPD goes high by reporting GPIO9 as high (even though HPD isn't
162
+ * actually connected to GPIO9).
163
+ */
164
+ ret = regmap_read_poll_timeout (map , PAGE2_GPIO_H , status ,
165
+ status & PS_GPIO9 , 20 * 1000 , 200 * 1000 );
166
+
167
+ if (ret < 0 )
168
+ dev_warn (dev , "HPD didn't go high: %d\n" , ret );
169
+
170
+ return ret ;
171
+ }
172
+
173
+ static ssize_t ps8640_aux_transfer_msg (struct drm_dp_aux * aux ,
174
+ struct drm_dp_aux_msg * msg )
153
175
{
154
176
struct ps8640 * ps_bridge = aux_to_ps8640 (aux );
155
177
struct regmap * map = ps_bridge -> regmap [PAGE0_DP_CNTL ];
@@ -274,38 +296,49 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux,
274
296
return len ;
275
297
}
276
298
277
- static int ps8640_bridge_vdo_control (struct ps8640 * ps_bridge ,
278
- const enum ps8640_vdo_control ctrl )
299
+ static ssize_t ps8640_aux_transfer (struct drm_dp_aux * aux ,
300
+ struct drm_dp_aux_msg * msg )
301
+ {
302
+ struct ps8640 * ps_bridge = aux_to_ps8640 (aux );
303
+ struct device * dev = & ps_bridge -> page [PAGE0_DP_CNTL ]-> dev ;
304
+ int ret ;
305
+
306
+ pm_runtime_get_sync (dev );
307
+ ret = ps8640_ensure_hpd (ps_bridge );
308
+ if (!ret )
309
+ ret = ps8640_aux_transfer_msg (aux , msg );
310
+ pm_runtime_mark_last_busy (dev );
311
+ pm_runtime_put_autosuspend (dev );
312
+
313
+ return ret ;
314
+ }
315
+
316
+ static void ps8640_bridge_vdo_control (struct ps8640 * ps_bridge ,
317
+ const enum ps8640_vdo_control ctrl )
279
318
{
280
319
struct regmap * map = ps_bridge -> regmap [PAGE3_DSI_CNTL1 ];
320
+ struct device * dev = & ps_bridge -> page [PAGE3_DSI_CNTL1 ]-> dev ;
281
321
u8 vdo_ctrl_buf [] = { VDO_CTL_ADD , ctrl };
282
322
int ret ;
283
323
284
324
ret = regmap_bulk_write (map , PAGE3_SET_ADD ,
285
325
vdo_ctrl_buf , sizeof (vdo_ctrl_buf ));
286
326
287
- if (ret < 0 ) {
288
- DRM_ERROR ("failed to %sable VDO: %d\n" ,
289
- ctrl == ENABLE ? "en" : "dis" , ret );
290
- return ret ;
291
- }
292
-
293
- return 0 ;
327
+ if (ret < 0 )
328
+ dev_err (dev , "failed to %sable VDO: %d\n" ,
329
+ ctrl == ENABLE ? "en" : "dis" , ret );
294
330
}
295
331
296
- static void ps8640_bridge_poweron (struct ps8640 * ps_bridge )
332
+ static int __maybe_unused ps8640_resume (struct device * dev )
297
333
{
298
- struct regmap * map = ps_bridge -> regmap [PAGE2_TOP_CNTL ];
299
- int ret , status ;
300
-
301
- if (ps_bridge -> powered )
302
- return ;
334
+ struct ps8640 * ps_bridge = dev_get_drvdata (dev );
335
+ int ret ;
303
336
304
337
ret = regulator_bulk_enable (ARRAY_SIZE (ps_bridge -> supplies ),
305
338
ps_bridge -> supplies );
306
339
if (ret < 0 ) {
307
- DRM_ERROR ( "cannot enable regulators %d\n" , ret );
308
- return ;
340
+ dev_err ( dev , "cannot enable regulators %d\n" , ret );
341
+ return ret ;
309
342
}
310
343
311
344
gpiod_set_value (ps_bridge -> gpio_powerdown , 0 );
@@ -314,86 +347,78 @@ static void ps8640_bridge_poweron(struct ps8640 *ps_bridge)
314
347
gpiod_set_value (ps_bridge -> gpio_reset , 0 );
315
348
316
349
/*
317
- * Wait for the ps8640 embedded MCU to be ready
318
- * First wait 200ms and then check the MCU ready flag every 20ms
350
+ * Mystery 200 ms delay for the "MCU to be ready". It's unclear if
351
+ * this is truly necessary since the MCU will already signal that
352
+ * things are "good to go" by signaling HPD on "gpio 9". See
353
+ * ps8640_ensure_hpd(). For now we'll keep this mystery delay just in
354
+ * case.
319
355
*/
320
356
msleep (200 );
321
357
322
- ret = regmap_read_poll_timeout (map , PAGE2_GPIO_H , status ,
323
- status & PS_GPIO9 , 20 * 1000 , 200 * 1000 );
324
-
325
- if (ret < 0 ) {
326
- DRM_ERROR ("failed read PAGE2_GPIO_H: %d\n" , ret );
327
- goto err_regulators_disable ;
328
- }
329
-
330
- msleep (50 );
331
-
332
- /*
333
- * The Manufacturer Command Set (MCS) is a device dependent interface
334
- * intended for factory programming of the display module default
335
- * parameters. Once the display module is configured, the MCS shall be
336
- * disabled by the manufacturer. Once disabled, all MCS commands are
337
- * ignored by the display interface.
338
- */
339
-
340
- ret = regmap_update_bits (map , PAGE2_MCS_EN , MCS_EN , 0 );
341
- if (ret < 0 ) {
342
- DRM_ERROR ("failed write PAGE2_MCS_EN: %d\n" , ret );
343
- goto err_regulators_disable ;
344
- }
345
-
346
- /* Switch access edp panel's edid through i2c */
347
- ret = regmap_write (map , PAGE2_I2C_BYPASS , I2C_BYPASS_EN );
348
- if (ret < 0 ) {
349
- DRM_ERROR ("failed write PAGE2_I2C_BYPASS: %d\n" , ret );
350
- goto err_regulators_disable ;
351
- }
352
-
353
- ps_bridge -> powered = true;
354
-
355
- return ;
356
-
357
- err_regulators_disable :
358
- regulator_bulk_disable (ARRAY_SIZE (ps_bridge -> supplies ),
359
- ps_bridge -> supplies );
358
+ return 0 ;
360
359
}
361
360
362
- static void ps8640_bridge_poweroff (struct ps8640 * ps_bridge )
361
+ static int __maybe_unused ps8640_suspend (struct device * dev )
363
362
{
363
+ struct ps8640 * ps_bridge = dev_get_drvdata (dev );
364
364
int ret ;
365
365
366
- if (!ps_bridge -> powered )
367
- return ;
368
-
369
366
gpiod_set_value (ps_bridge -> gpio_reset , 1 );
370
367
gpiod_set_value (ps_bridge -> gpio_powerdown , 1 );
371
368
ret = regulator_bulk_disable (ARRAY_SIZE (ps_bridge -> supplies ),
372
369
ps_bridge -> supplies );
373
370
if (ret < 0 )
374
- DRM_ERROR ( "cannot disable regulators %d\n" , ret );
371
+ dev_err ( dev , "cannot disable regulators %d\n" , ret );
375
372
376
- ps_bridge -> powered = false ;
373
+ return ret ;
377
374
}
378
375
376
+ static const struct dev_pm_ops ps8640_pm_ops = {
377
+ SET_RUNTIME_PM_OPS (ps8640_suspend , ps8640_resume , NULL )
378
+ SET_SYSTEM_SLEEP_PM_OPS (pm_runtime_force_suspend ,
379
+ pm_runtime_force_resume )
380
+ };
381
+
379
382
static void ps8640_pre_enable (struct drm_bridge * bridge )
380
383
{
381
384
struct ps8640 * ps_bridge = bridge_to_ps8640 (bridge );
385
+ struct regmap * map = ps_bridge -> regmap [PAGE2_TOP_CNTL ];
386
+ struct device * dev = & ps_bridge -> page [PAGE0_DP_CNTL ]-> dev ;
382
387
int ret ;
383
388
384
- ps8640_bridge_poweron (ps_bridge );
389
+ pm_runtime_get_sync (dev );
390
+ ps8640_ensure_hpd (ps_bridge );
385
391
386
- ret = ps8640_bridge_vdo_control (ps_bridge , ENABLE );
392
+ /*
393
+ * The Manufacturer Command Set (MCS) is a device dependent interface
394
+ * intended for factory programming of the display module default
395
+ * parameters. Once the display module is configured, the MCS shall be
396
+ * disabled by the manufacturer. Once disabled, all MCS commands are
397
+ * ignored by the display interface.
398
+ */
399
+
400
+ ret = regmap_update_bits (map , PAGE2_MCS_EN , MCS_EN , 0 );
401
+ if (ret < 0 )
402
+ dev_warn (dev , "failed write PAGE2_MCS_EN: %d\n" , ret );
403
+
404
+ /* Switch access edp panel's edid through i2c */
405
+ ret = regmap_write (map , PAGE2_I2C_BYPASS , I2C_BYPASS_EN );
387
406
if (ret < 0 )
388
- ps8640_bridge_poweroff (ps_bridge );
407
+ dev_warn (dev , "failed write PAGE2_MCS_EN: %d\n" , ret );
408
+
409
+ ps8640_bridge_vdo_control (ps_bridge , ENABLE );
410
+
411
+ ps_bridge -> pre_enabled = true;
389
412
}
390
413
391
414
static void ps8640_post_disable (struct drm_bridge * bridge )
392
415
{
393
416
struct ps8640 * ps_bridge = bridge_to_ps8640 (bridge );
394
417
418
+ ps_bridge -> pre_enabled = false;
419
+
395
420
ps8640_bridge_vdo_control (ps_bridge , DISABLE );
396
- ps8640_bridge_poweroff ( ps_bridge );
421
+ pm_runtime_put_sync_suspend ( & ps_bridge -> page [ PAGE0_DP_CNTL ] -> dev );
397
422
}
398
423
399
424
static int ps8640_bridge_attach (struct drm_bridge * bridge ,
@@ -426,7 +451,7 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
426
451
struct drm_connector * connector )
427
452
{
428
453
struct ps8640 * ps_bridge = bridge_to_ps8640 (bridge );
429
- bool poweroff = !ps_bridge -> powered ;
454
+ bool poweroff = !ps_bridge -> pre_enabled ;
430
455
struct edid * edid ;
431
456
432
457
/*
@@ -456,6 +481,12 @@ static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge,
456
481
return edid ;
457
482
}
458
483
484
+ static void ps8640_runtime_disable (void * data )
485
+ {
486
+ pm_runtime_dont_use_autosuspend (data );
487
+ pm_runtime_disable (data );
488
+ }
489
+
459
490
static const struct drm_bridge_funcs ps8640_bridge_funcs = {
460
491
.attach = ps8640_bridge_attach ,
461
492
.detach = ps8640_bridge_detach ,
@@ -586,6 +617,22 @@ static int ps8640_probe(struct i2c_client *client)
586
617
ps_bridge -> aux .transfer = ps8640_aux_transfer ;
587
618
drm_dp_aux_init (& ps_bridge -> aux );
588
619
620
+ pm_runtime_enable (dev );
621
+ /*
622
+ * Powering on ps8640 takes ~300ms. To avoid wasting time on power
623
+ * cycling ps8640 too often, set autosuspend_delay to 500ms to ensure
624
+ * the bridge wouldn't suspend in between each _aux_transfer_msg() call
625
+ * during EDID read (~20ms in my experiment) and in between the last
626
+ * _aux_transfer_msg() call during EDID read and the _pre_enable() call
627
+ * (~100ms in my experiment).
628
+ */
629
+ pm_runtime_set_autosuspend_delay (dev , 500 );
630
+ pm_runtime_use_autosuspend (dev );
631
+ pm_suspend_ignore_children (dev , true);
632
+ ret = devm_add_action_or_reset (dev , ps8640_runtime_disable , dev );
633
+ if (ret )
634
+ return ret ;
635
+
589
636
drm_bridge_add (& ps_bridge -> bridge );
590
637
591
638
ret = ps8640_bridge_host_attach (dev , ps_bridge );
@@ -620,6 +667,7 @@ static struct i2c_driver ps8640_driver = {
620
667
.driver = {
621
668
.name = "ps8640" ,
622
669
.of_match_table = ps8640_match ,
670
+ .pm = & ps8640_pm_ops ,
623
671
},
624
672
};
625
673
module_i2c_driver (ps8640_driver );
0 commit comments