62
62
#define PCA955X_GPIO_HIGH LED_OFF
63
63
#define PCA955X_GPIO_LOW LED_FULL
64
64
65
+ #define PCA955X_BLINK_DEFAULT_MS 1000
66
+
65
67
enum pca955x_type {
66
68
pca9550 ,
67
69
pca9551 ,
@@ -74,33 +76,39 @@ struct pca955x_chipdef {
74
76
int bits ;
75
77
u8 slv_addr ; /* 7-bit slave address mask */
76
78
int slv_addr_shift ; /* Number of bits to ignore */
79
+ int blink_div ; /* PSC divider */
77
80
};
78
81
79
82
static const struct pca955x_chipdef pca955x_chipdefs [] = {
80
83
[pca9550 ] = {
81
84
.bits = 2 ,
82
85
.slv_addr = /* 110000x */ 0x60 ,
83
86
.slv_addr_shift = 1 ,
87
+ .blink_div = 44 ,
84
88
},
85
89
[pca9551 ] = {
86
90
.bits = 8 ,
87
91
.slv_addr = /* 1100xxx */ 0x60 ,
88
92
.slv_addr_shift = 3 ,
93
+ .blink_div = 38 ,
89
94
},
90
95
[pca9552 ] = {
91
96
.bits = 16 ,
92
97
.slv_addr = /* 1100xxx */ 0x60 ,
93
98
.slv_addr_shift = 3 ,
99
+ .blink_div = 44 ,
94
100
},
95
101
[ibm_pca9552 ] = {
96
102
.bits = 16 ,
97
103
.slv_addr = /* 0110xxx */ 0x30 ,
98
104
.slv_addr_shift = 3 ,
105
+ .blink_div = 44 ,
99
106
},
100
107
[pca9553 ] = {
101
108
.bits = 4 ,
102
109
.slv_addr = /* 110001x */ 0x62 ,
103
110
.slv_addr_shift = 1 ,
111
+ .blink_div = 44 ,
104
112
},
105
113
};
106
114
@@ -109,7 +117,9 @@ struct pca955x {
109
117
struct pca955x_led * leds ;
110
118
const struct pca955x_chipdef * chipdef ;
111
119
struct i2c_client * client ;
120
+ unsigned long active_blink ;
112
121
unsigned long active_pins ;
122
+ unsigned long blink_period ;
113
123
#ifdef CONFIG_LEDS_PCA955X_GPIO
114
124
struct gpio_chip gpio ;
115
125
#endif
@@ -154,7 +164,8 @@ static inline int pca955x_ledstate(u8 ls, int led_num)
154
164
155
165
/*
156
166
* Write to frequency prescaler register, used to program the
157
- * period of the PWM output. period = (PSCx + 1) / 38
167
+ * period of the PWM output. period = (PSCx + 1) / coeff
168
+ * Where for pca9551 chips coeff = 38 and for all other chips coeff = 44
158
169
*/
159
170
static int pca955x_write_psc (struct pca955x * pca955x , int n , u8 val )
160
171
{
@@ -235,6 +246,21 @@ static int pca955x_read_pwm(struct pca955x *pca955x, int n, u8 *val)
235
246
return 0 ;
236
247
}
237
248
249
+ static int pca955x_read_psc (struct pca955x * pca955x , int n , u8 * val )
250
+ {
251
+ int ret ;
252
+ u8 cmd ;
253
+
254
+ cmd = pca955x_num_input_regs (pca955x -> chipdef -> bits ) + (2 * n );
255
+ ret = i2c_smbus_read_byte_data (pca955x -> client , cmd );
256
+ if (ret < 0 ) {
257
+ dev_err (& pca955x -> client -> dev , "%s: reg 0x%x, err %d\n" , __func__ , n , ret );
258
+ return ret ;
259
+ }
260
+ * val = (u8 )ret ;
261
+ return 0 ;
262
+ }
263
+
238
264
static enum led_brightness pca955x_led_get (struct led_classdev * led_cdev )
239
265
{
240
266
struct pca955x_led * pca955x_led = led_to_pca955x (led_cdev );
@@ -248,14 +274,12 @@ static enum led_brightness pca955x_led_get(struct led_classdev *led_cdev)
248
274
249
275
switch (pca955x_ledstate (ls , pca955x_led -> led_num % 4 )) {
250
276
case PCA955X_LS_LED_ON :
277
+ case PCA955X_LS_BLINK0 :
251
278
ret = LED_FULL ;
252
279
break ;
253
280
case PCA955X_LS_LED_OFF :
254
281
ret = LED_OFF ;
255
282
break ;
256
- case PCA955X_LS_BLINK0 :
257
- ret = LED_HALF ;
258
- break ;
259
283
case PCA955X_LS_BLINK1 :
260
284
ret = pca955x_read_pwm (pca955x , 1 , & pwm );
261
285
if (ret )
@@ -283,29 +307,36 @@ static int pca955x_led_set(struct led_classdev *led_cdev,
283
307
if (ret )
284
308
goto out ;
285
309
286
- switch (value ) {
287
- case LED_FULL :
288
- ls = pca955x_ledsel (ls , bit , PCA955X_LS_LED_ON );
289
- break ;
290
- case LED_OFF :
291
- ls = pca955x_ledsel (ls , bit , PCA955X_LS_LED_OFF );
292
- break ;
293
- case LED_HALF :
294
- ls = pca955x_ledsel (ls , bit , PCA955X_LS_BLINK0 );
295
- break ;
296
- default :
297
- /*
298
- * Use PWM1 for all other values. This has the unwanted
299
- * side effect of making all LEDs on the chip share the
300
- * same brightness level if set to a value other than
301
- * OFF, HALF, or FULL. But, this is probably better than
302
- * just turning off for all other values.
303
- */
304
- ret = pca955x_write_pwm (pca955x , 1 , 255 - value );
305
- if (ret )
310
+ if (test_bit (pca955x_led -> led_num , & pca955x -> active_blink )) {
311
+ if (value == LED_OFF ) {
312
+ clear_bit (pca955x_led -> led_num , & pca955x -> active_blink );
313
+ ls = pca955x_ledsel (ls , bit , PCA955X_LS_LED_OFF );
314
+ } else {
315
+ /* No variable brightness for blinking LEDs */
306
316
goto out ;
307
- ls = pca955x_ledsel (ls , bit , PCA955X_LS_BLINK1 );
308
- break ;
317
+ }
318
+ } else {
319
+ switch (value ) {
320
+ case LED_FULL :
321
+ ls = pca955x_ledsel (ls , bit , PCA955X_LS_LED_ON );
322
+ break ;
323
+ case LED_OFF :
324
+ ls = pca955x_ledsel (ls , bit , PCA955X_LS_LED_OFF );
325
+ break ;
326
+ default :
327
+ /*
328
+ * Use PWM1 for all other values. This has the unwanted
329
+ * side effect of making all LEDs on the chip share the
330
+ * same brightness level if set to a value other than
331
+ * OFF or FULL. But, this is probably better than just
332
+ * turning off for all other values.
333
+ */
334
+ ret = pca955x_write_pwm (pca955x , 1 , 255 - value );
335
+ if (ret )
336
+ goto out ;
337
+ ls = pca955x_ledsel (ls , bit , PCA955X_LS_BLINK1 );
338
+ break ;
339
+ }
309
340
}
310
341
311
342
ret = pca955x_write_ls (pca955x , reg , ls );
@@ -316,6 +347,104 @@ static int pca955x_led_set(struct led_classdev *led_cdev,
316
347
return ret ;
317
348
}
318
349
350
+ static u8 pca955x_period_to_psc (struct pca955x * pca955x , unsigned long period )
351
+ {
352
+ /* psc register value = (blink period * coeff) - 1 */
353
+ period *= pca955x -> chipdef -> blink_div ;
354
+ period /= MSEC_PER_SEC ;
355
+ period -= 1 ;
356
+
357
+ return period ;
358
+ }
359
+
360
+ static unsigned long pca955x_psc_to_period (struct pca955x * pca955x , u8 psc )
361
+ {
362
+ unsigned long period = psc ;
363
+
364
+ /* blink period = (psc register value + 1) / coeff */
365
+ period += 1 ;
366
+ period *= MSEC_PER_SEC ;
367
+ period /= pca955x -> chipdef -> blink_div ;
368
+
369
+ return period ;
370
+ }
371
+
372
+ static int pca955x_led_blink (struct led_classdev * led_cdev ,
373
+ unsigned long * delay_on , unsigned long * delay_off )
374
+ {
375
+ struct pca955x_led * pca955x_led = led_to_pca955x (led_cdev );
376
+ struct pca955x * pca955x = pca955x_led -> pca955x ;
377
+ unsigned long period = * delay_on + * delay_off ;
378
+ int ret = 0 ;
379
+
380
+ mutex_lock (& pca955x -> lock );
381
+
382
+ if (period ) {
383
+ if (* delay_on != * delay_off ) {
384
+ ret = - EINVAL ;
385
+ goto out ;
386
+ }
387
+
388
+ if (period < pca955x_psc_to_period (pca955x , 0 ) ||
389
+ period > pca955x_psc_to_period (pca955x , 0xff )) {
390
+ ret = - EINVAL ;
391
+ goto out ;
392
+ }
393
+ } else {
394
+ period = pca955x -> active_blink ? pca955x -> blink_period :
395
+ PCA955X_BLINK_DEFAULT_MS ;
396
+ }
397
+
398
+ if (!pca955x -> active_blink ||
399
+ pca955x -> active_blink == BIT (pca955x_led -> led_num ) ||
400
+ pca955x -> blink_period == period ) {
401
+ u8 psc = pca955x_period_to_psc (pca955x , period );
402
+
403
+ if (!test_and_set_bit (pca955x_led -> led_num ,
404
+ & pca955x -> active_blink )) {
405
+ u8 ls ;
406
+ int reg = pca955x_led -> led_num / 4 ;
407
+ int bit = pca955x_led -> led_num % 4 ;
408
+
409
+ ret = pca955x_read_ls (pca955x , reg , & ls );
410
+ if (ret )
411
+ goto out ;
412
+
413
+ ls = pca955x_ledsel (ls , bit , PCA955X_LS_BLINK0 );
414
+ ret = pca955x_write_ls (pca955x , reg , ls );
415
+ if (ret )
416
+ goto out ;
417
+
418
+ /*
419
+ * Force 50% duty cycle to maintain the specified
420
+ * blink rate.
421
+ */
422
+ ret = pca955x_write_pwm (pca955x , 0 , 128 );
423
+ if (ret )
424
+ goto out ;
425
+ }
426
+
427
+ if (pca955x -> blink_period != period ) {
428
+ pca955x -> blink_period = period ;
429
+ ret = pca955x_write_psc (pca955x , 0 , psc );
430
+ if (ret )
431
+ goto out ;
432
+ }
433
+
434
+ period = pca955x_psc_to_period (pca955x , psc );
435
+ period /= 2 ;
436
+ * delay_on = period ;
437
+ * delay_off = period ;
438
+ } else {
439
+ ret = - EBUSY ;
440
+ }
441
+
442
+ out :
443
+ mutex_unlock (& pca955x -> lock );
444
+
445
+ return ret ;
446
+ }
447
+
319
448
#ifdef CONFIG_LEDS_PCA955X_GPIO
320
449
/*
321
450
* Read the INPUT register, which contains the state of LEDs.
@@ -450,8 +579,9 @@ static int pca955x_probe(struct i2c_client *client)
450
579
u8 ls1 [4 ];
451
580
u8 ls2 [4 ];
452
581
struct pca955x_platform_data * pdata ;
582
+ u8 psc0 ;
583
+ bool keep_psc0 = false;
453
584
bool set_default_label = false;
454
- bool keep_pwm = false;
455
585
char default_label [8 ];
456
586
457
587
chip = i2c_get_match_data (client );
@@ -502,6 +632,7 @@ static int pca955x_probe(struct i2c_client *client)
502
632
mutex_init (& pca955x -> lock );
503
633
pca955x -> client = client ;
504
634
pca955x -> chipdef = chip ;
635
+ pca955x -> blink_period = PCA955X_BLINK_DEFAULT_MS ;
505
636
506
637
init_data .devname_mandatory = false;
507
638
init_data .devicename = "pca955x" ;
@@ -533,11 +664,16 @@ static int pca955x_probe(struct i2c_client *client)
533
664
led = & pca955x_led -> led_cdev ;
534
665
led -> brightness_set_blocking = pca955x_led_set ;
535
666
led -> brightness_get = pca955x_led_get ;
667
+ led -> blink_set = pca955x_led_blink ;
536
668
537
669
if (pdata -> leds [i ].default_state == LEDS_DEFSTATE_OFF )
538
670
ls2 [reg ] = pca955x_ledsel (ls2 [reg ], bit , PCA955X_LS_LED_OFF );
539
671
else if (pdata -> leds [i ].default_state == LEDS_DEFSTATE_ON )
540
672
ls2 [reg ] = pca955x_ledsel (ls2 [reg ], bit , PCA955X_LS_LED_ON );
673
+ else if (pca955x_ledstate (ls2 [reg ], bit ) == PCA955X_LS_BLINK0 ) {
674
+ keep_psc0 = true;
675
+ set_bit (i , & pca955x -> active_blink );
676
+ }
541
677
542
678
init_data .fwnode = pdata -> leds [i ].fwnode ;
543
679
@@ -565,19 +701,6 @@ static int pca955x_probe(struct i2c_client *client)
565
701
return err ;
566
702
567
703
set_bit (i , & pca955x -> active_pins );
568
-
569
- /*
570
- * For default-state == "keep", let the core update the
571
- * brightness from the hardware, then check the
572
- * brightness to see if it's using PWM1. If so, PWM1
573
- * should not be written below.
574
- */
575
- if (pdata -> leds [i ].default_state == LEDS_DEFSTATE_KEEP ) {
576
- if (led -> brightness != LED_FULL &&
577
- led -> brightness != LED_OFF &&
578
- led -> brightness != LED_HALF )
579
- keep_pwm = true;
580
- }
581
704
}
582
705
}
583
706
@@ -589,22 +712,19 @@ static int pca955x_probe(struct i2c_client *client)
589
712
}
590
713
}
591
714
592
- /* PWM0 is used for half brightness or 50% duty cycle */
593
- err = pca955x_write_pwm (pca955x , 0 , 255 - LED_HALF );
594
- if (err )
595
- return err ;
596
-
597
- if (!keep_pwm ) {
598
- /* PWM1 is used for variable brightness, default to OFF */
599
- err = pca955x_write_pwm (pca955x , 1 , 0 );
600
- if (err )
601
- return err ;
715
+ if (keep_psc0 ) {
716
+ err = pca955x_read_psc (pca955x , 0 , & psc0 );
717
+ } else {
718
+ psc0 = pca955x_period_to_psc (pca955x , pca955x -> blink_period );
719
+ err = pca955x_write_psc (pca955x , 0 , psc0 );
602
720
}
603
721
604
- /* Set to fast frequency so we do not see flashing */
605
- err = pca955x_write_psc (pca955x , 0 , 0 );
606
722
if (err )
607
723
return err ;
724
+
725
+ pca955x -> blink_period = pca955x_psc_to_period (pca955x , psc0 );
726
+
727
+ /* Set PWM1 to fast frequency so we do not see flashing */
608
728
err = pca955x_write_psc (pca955x , 1 , 0 );
609
729
if (err )
610
730
return err ;
0 commit comments