22
22
#include <linux/i2c.h>
23
23
#include <linux/slab.h>
24
24
#include <linux/workqueue.h>
25
+ #include <linux/leds.h>
25
26
26
27
#define DRIVER_NAME "rook-fan-cpld"
27
28
29
+ #define LED_NAME_MAX_SZ 20
28
30
#define MAX_FAN_COUNT 8
29
31
30
32
#define MINOR_VERSION_REG 0x00
57
59
#define FAN_INT_PRES (1 << 1)
58
60
#define FAN_INT_ID (1 << 2)
59
61
62
+ #define FAN_LED_GREEN 1
63
+ #define FAN_LED_RED 2
60
64
61
65
static bool managed_leds = true;
62
66
module_param (managed_leds , bool , S_IRUSR | S_IWUSR );
@@ -92,12 +96,15 @@ static struct cpld_info cpld_infos[] = {
92
96
};
93
97
94
98
struct cpld_fan_data {
99
+ struct led_classdev cdev ;
95
100
bool ok ;
96
101
bool present ;
97
102
bool forward ;
98
103
u16 tach ;
99
104
u8 pwm ;
100
105
u8 ident ;
106
+ u8 index ;
107
+ char led_name [LED_NAME_MAX_SZ ];
101
108
};
102
109
103
110
struct cpld_data {
@@ -442,9 +449,9 @@ static s32 cpld_read_fan_led(struct cpld_data *data, u8 fan_id, u8 *val)
442
449
443
450
* val = 0 ;
444
451
if (green )
445
- * val += 1 ;
452
+ * val += FAN_LED_GREEN ;
446
453
if (red )
447
- * val += 2 ;
454
+ * val += FAN_LED_RED ;
448
455
449
456
return 0 ;
450
457
}
@@ -453,12 +460,15 @@ static s32 cpld_write_fan_led(struct cpld_data *cpld, u8 fan_id, u8 val)
453
460
{
454
461
int err = 0 ;
455
462
456
- if (val & 0x01 )
463
+ if (val > 3 )
464
+ return - EINVAL ;
465
+
466
+ if (val & FAN_LED_GREEN )
457
467
cpld -> green_led |= (1 << fan_id );
458
468
else
459
469
cpld -> green_led &= ~(1 << fan_id );
460
470
461
- if (val & 0x2 )
471
+ if (val & FAN_LED_RED )
462
472
cpld -> red_led |= (1 << fan_id );
463
473
else
464
474
cpld -> red_led &= ~(1 << fan_id );
@@ -472,6 +482,53 @@ static s32 cpld_write_fan_led(struct cpld_data *cpld, u8 fan_id, u8 val)
472
482
return err ;
473
483
}
474
484
485
+ static int brightness_set (struct led_classdev * led_cdev , u8 val )
486
+ {
487
+ struct cpld_fan_data * fan = container_of (led_cdev , struct cpld_fan_data ,
488
+ cdev );
489
+ struct cpld_data * data = dev_get_drvdata (led_cdev -> dev -> parent );
490
+
491
+ return cpld_write_fan_led (data , fan -> index , val );
492
+ }
493
+
494
+ static int brightness_get (struct led_classdev * led_cdev )
495
+ {
496
+ struct cpld_fan_data * fan = container_of (led_cdev , struct cpld_fan_data ,
497
+ cdev );
498
+ struct cpld_data * data = dev_get_drvdata (led_cdev -> dev -> parent );
499
+ int err ;
500
+ u8 val ;
501
+
502
+ err = cpld_read_fan_led (data , fan -> index , & val );
503
+ if (err )
504
+ return err ;
505
+
506
+ return val ;
507
+ }
508
+
509
+ static int led_init (struct cpld_fan_data * fan , struct i2c_client * client ,
510
+ int fan_index )
511
+ {
512
+ fan -> index = fan_index ;
513
+ fan -> cdev .brightness_set = brightness_set ;
514
+ fan -> cdev .brightness_get = brightness_get ;
515
+ scnprintf (fan -> led_name , LED_NAME_MAX_SZ , "fan%d" , fan -> index + 1 );
516
+ fan -> cdev .name = fan -> led_name ;
517
+
518
+ return led_classdev_register (& client -> dev , & fan -> cdev );
519
+ }
520
+
521
+ static void cpld_leds_unregister (struct cpld_data * cpld , int num_leds )
522
+ {
523
+ int i = 0 ;
524
+ struct cpld_fan_data * fan ;
525
+
526
+ for (i = 0 ; i < num_leds ; i ++ ) {
527
+ fan = fan_from_cpld (cpld , i );
528
+ led_classdev_unregister (& fan -> cdev );
529
+ }
530
+ }
531
+
475
532
static ssize_t cpld_fan_pwm_show (struct device * dev , struct device_attribute * da ,
476
533
char * buf )
477
534
{
@@ -773,6 +830,11 @@ static int cpld_init(struct cpld_data *cpld)
773
830
cpld_read_fan_id (cpld , i );
774
831
cpld_read_fan_tach (cpld , i );
775
832
cpld_read_fan_pwm (cpld , i );
833
+ err = led_init (fan , cpld -> client , i );
834
+ if (err ) {
835
+ cpld_leds_unregister (cpld , i );
836
+ return err ;
837
+ }
776
838
}
777
839
}
778
840
@@ -807,9 +869,8 @@ static int cpld_probe(struct i2c_client *client,
807
869
}
808
870
809
871
cpld = devm_kzalloc (dev , sizeof (struct cpld_data ), GFP_KERNEL );
810
- if (!cpld ) {
872
+ if (!cpld )
811
873
return - ENOMEM ;
812
- }
813
874
814
875
i2c_set_clientdata (client , cpld );
815
876
cpld -> client = client ;
@@ -824,9 +885,8 @@ static int cpld_probe(struct i2c_client *client,
824
885
825
886
hwmon_dev = devm_hwmon_device_register_with_groups (dev , client -> name ,
826
887
cpld , cpld -> groups );
827
- if (IS_ERR (hwmon_dev )) {
888
+ if (IS_ERR (hwmon_dev ))
828
889
return PTR_ERR (hwmon_dev );
829
- }
830
890
831
891
cpld -> hwmon_dev = hwmon_dev ;
832
892
@@ -845,6 +905,8 @@ static int cpld_remove(struct i2c_client *client)
845
905
cancel_delayed_work_sync (& cpld -> dwork );
846
906
mutex_unlock (& cpld -> lock );
847
907
908
+ cpld_leds_unregister (cpld , cpld -> info -> fan_count );
909
+
848
910
return 0 ;
849
911
}
850
912
0 commit comments