@@ -120,6 +120,9 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
120
120
if (pwm -> chip -> ops -> get_state ) {
121
121
pwm -> chip -> ops -> get_state (pwm -> chip , pwm , & pwm -> state );
122
122
trace_pwm_get (pwm , & pwm -> state );
123
+
124
+ if (IS_ENABLED (PWM_DEBUG ))
125
+ pwm -> last = pwm -> state ;
123
126
}
124
127
125
128
set_bit (PWMF_REQUESTED , & pwm -> flags );
@@ -232,17 +235,28 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
232
235
}
233
236
EXPORT_SYMBOL_GPL (pwm_get_chip_data );
234
237
235
- static bool pwm_ops_check (const struct pwm_ops * ops )
238
+ static bool pwm_ops_check (const struct pwm_chip * chip )
236
239
{
240
+
241
+ const struct pwm_ops * ops = chip -> ops ;
242
+
237
243
/* driver supports legacy, non-atomic operation */
238
- if (ops -> config && ops -> enable && ops -> disable )
239
- return true;
244
+ if (ops -> config && ops -> enable && ops -> disable ) {
245
+ if (IS_ENABLED (CONFIG_PWM_DEBUG ))
246
+ dev_warn (chip -> dev ,
247
+ "Driver needs updating to atomic API\n" );
240
248
241
- /* driver supports atomic operation */
242
- if (ops -> apply )
243
249
return true;
250
+ }
244
251
245
- return false;
252
+ if (!ops -> apply )
253
+ return false;
254
+
255
+ if (IS_ENABLED (CONFIG_PWM_DEBUG ) && !ops -> get_state )
256
+ dev_warn (chip -> dev ,
257
+ "Please implement the .get_state() callback\n" );
258
+
259
+ return true;
246
260
}
247
261
248
262
/**
@@ -266,7 +280,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
266
280
if (!chip || !chip -> dev || !chip -> ops || !chip -> npwm )
267
281
return - EINVAL ;
268
282
269
- if (!pwm_ops_check (chip -> ops ))
283
+ if (!pwm_ops_check (chip ))
270
284
return - EINVAL ;
271
285
272
286
mutex_lock (& pwm_lock );
@@ -450,6 +464,107 @@ void pwm_free(struct pwm_device *pwm)
450
464
}
451
465
EXPORT_SYMBOL_GPL (pwm_free );
452
466
467
+ void pwm_apply_state_debug (struct pwm_device * pwm ,
468
+ const struct pwm_state * state )
469
+ {
470
+ struct pwm_state * last = & pwm -> last ;
471
+ struct pwm_chip * chip = pwm -> chip ;
472
+ struct pwm_state s1 , s2 ;
473
+ int err ;
474
+
475
+ if (!IS_ENABLED (CONFIG_PWM_DEBUG ))
476
+ return ;
477
+
478
+ /* No reasonable diagnosis possible without .get_state() */
479
+ if (!chip -> ops -> get_state )
480
+ return ;
481
+
482
+ /*
483
+ * *state was just applied. Read out the hardware state and do some
484
+ * checks.
485
+ */
486
+
487
+ chip -> ops -> get_state (chip , pwm , & s1 );
488
+ trace_pwm_get (pwm , & s1 );
489
+
490
+ /*
491
+ * The lowlevel driver either ignored .polarity (which is a bug) or as
492
+ * best effort inverted .polarity and fixed .duty_cycle respectively.
493
+ * Undo this inversion and fixup for further tests.
494
+ */
495
+ if (s1 .enabled && s1 .polarity != state -> polarity ) {
496
+ s2 .polarity = state -> polarity ;
497
+ s2 .duty_cycle = s1 .period - s1 .duty_cycle ;
498
+ s2 .period = s1 .period ;
499
+ s2 .enabled = s1 .enabled ;
500
+ } else {
501
+ s2 = s1 ;
502
+ }
503
+
504
+ if (s2 .polarity != state -> polarity &&
505
+ state -> duty_cycle < state -> period )
506
+ dev_warn (chip -> dev , ".apply ignored .polarity\n" );
507
+
508
+ if (state -> enabled &&
509
+ last -> polarity == state -> polarity &&
510
+ last -> period > s2 .period &&
511
+ last -> period <= state -> period )
512
+ dev_warn (chip -> dev ,
513
+ ".apply didn't pick the best available period (requested: %u, applied: %u, possible: %u)\n" ,
514
+ state -> period , s2 .period , last -> period );
515
+
516
+ if (state -> enabled && state -> period < s2 .period )
517
+ dev_warn (chip -> dev ,
518
+ ".apply is supposed to round down period (requested: %u, applied: %u)\n" ,
519
+ state -> period , s2 .period );
520
+
521
+ if (state -> enabled &&
522
+ last -> polarity == state -> polarity &&
523
+ last -> period == s2 .period &&
524
+ last -> duty_cycle > s2 .duty_cycle &&
525
+ last -> duty_cycle <= state -> duty_cycle )
526
+ dev_warn (chip -> dev ,
527
+ ".apply didn't pick the best available duty cycle (requested: %u/%u, applied: %u/%u, possible: %u/%u)\n" ,
528
+ state -> duty_cycle , state -> period ,
529
+ s2 .duty_cycle , s2 .period ,
530
+ last -> duty_cycle , last -> period );
531
+
532
+ if (state -> enabled && state -> duty_cycle < s2 .duty_cycle )
533
+ dev_warn (chip -> dev ,
534
+ ".apply is supposed to round down duty_cycle (requested: %u/%u, applied: %u/%u)\n" ,
535
+ state -> duty_cycle , state -> period ,
536
+ s2 .duty_cycle , s2 .period );
537
+
538
+ if (!state -> enabled && s2 .enabled && s2 .duty_cycle > 0 )
539
+ dev_warn (chip -> dev ,
540
+ "requested disabled, but yielded enabled with duty > 0" );
541
+
542
+ /* reapply the state that the driver reported being configured. */
543
+ err = chip -> ops -> apply (chip , pwm , & s1 );
544
+ if (err ) {
545
+ * last = s1 ;
546
+ dev_err (chip -> dev , "failed to reapply current setting\n" );
547
+ return ;
548
+ }
549
+
550
+ trace_pwm_apply (pwm , & s1 );
551
+
552
+ chip -> ops -> get_state (chip , pwm , last );
553
+ trace_pwm_get (pwm , last );
554
+
555
+ /* reapplication of the current state should give an exact match */
556
+ if (s1 .enabled != last -> enabled ||
557
+ s1 .polarity != last -> polarity ||
558
+ (s1 .enabled && s1 .period != last -> period ) ||
559
+ (s1 .enabled && s1 .duty_cycle != last -> duty_cycle )) {
560
+ dev_err (chip -> dev ,
561
+ ".apply is not idempotent (ena=%d pol=%d %u/%u) -> (ena=%d pol=%d %u/%u)\n" ,
562
+ s1 .enabled , s1 .polarity , s1 .duty_cycle , s1 .period ,
563
+ last -> enabled , last -> polarity , last -> duty_cycle ,
564
+ last -> period );
565
+ }
566
+ }
567
+
453
568
/**
454
569
* pwm_apply_state() - atomically apply a new state to a PWM device
455
570
* @pwm: PWM device
@@ -480,6 +595,12 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
480
595
trace_pwm_apply (pwm , state );
481
596
482
597
pwm -> state = * state ;
598
+
599
+ /*
600
+ * only do this after pwm->state was applied as some
601
+ * implementations of .get_state depend on this
602
+ */
603
+ pwm_apply_state_debug (pwm , state );
483
604
} else {
484
605
/*
485
606
* FIXME: restore the initial state in case of error.
0 commit comments