22/*
33 * CZ.NIC's Turris Omnia LEDs driver
44 *
5- * 2020, 2023 by Marek Behún <kabel@kernel.org>
5+ * 2020, 2023, 2024 by Marek Behún <kabel@kernel.org>
66 */
77
88#include <linux/i2c.h>
99#include <linux/led-class-multicolor.h>
1010#include <linux/module.h>
1111#include <linux/mutex.h>
1212#include <linux/of.h>
13+ #include <linux/turris-omnia-mcu-interface.h>
1314
1415#define OMNIA_BOARD_LEDS 12
1516#define OMNIA_LED_NUM_CHANNELS 3
@@ -56,66 +57,21 @@ struct omnia_leds {
5657 struct omnia_led leds [];
5758};
5859
59- static int omnia_cmd_write_u8 (const struct i2c_client * client , u8 cmd , u8 val )
60+ static int omnia_cmd_set_color (const struct i2c_client * client , u8 led , u8 r , u8 g , u8 b )
6061{
61- u8 buf [2 ] = { cmd , val };
62- int ret ;
63-
64- ret = i2c_master_send (client , buf , sizeof (buf ));
62+ u8 buf [5 ] = { CMD_LED_COLOR , led , r , g , b };
6563
66- return ret < 0 ? ret : 0 ;
67- }
68-
69- static int omnia_cmd_read_raw (struct i2c_adapter * adapter , u8 addr , u8 cmd ,
70- void * reply , size_t len )
71- {
72- struct i2c_msg msgs [2 ];
73- int ret ;
74-
75- msgs [0 ].addr = addr ;
76- msgs [0 ].flags = 0 ;
77- msgs [0 ].len = 1 ;
78- msgs [0 ].buf = & cmd ;
79- msgs [1 ].addr = addr ;
80- msgs [1 ].flags = I2C_M_RD ;
81- msgs [1 ].len = len ;
82- msgs [1 ].buf = reply ;
83-
84- ret = i2c_transfer (adapter , msgs , ARRAY_SIZE (msgs ));
85- if (likely (ret == ARRAY_SIZE (msgs )))
86- return 0 ;
87- else if (ret < 0 )
88- return ret ;
89- else
90- return - EIO ;
91- }
92-
93- static int omnia_cmd_read_u8 (const struct i2c_client * client , u8 cmd )
94- {
95- u8 reply ;
96- int err ;
97-
98- err = omnia_cmd_read_raw (client -> adapter , client -> addr , cmd , & reply , 1 );
99- if (err )
100- return err ;
101-
102- return reply ;
64+ return omnia_cmd_write (client , buf , sizeof (buf ));
10365}
10466
10567static int omnia_led_send_color_cmd (const struct i2c_client * client ,
10668 struct omnia_led * led )
10769{
108- char cmd [5 ];
10970 int ret ;
11071
111- cmd [0 ] = CMD_LED_COLOR ;
112- cmd [1 ] = led -> reg ;
113- cmd [2 ] = led -> subled_info [0 ].brightness ;
114- cmd [3 ] = led -> subled_info [1 ].brightness ;
115- cmd [4 ] = led -> subled_info [2 ].brightness ;
116-
11772 /* Send the color change command */
118- ret = i2c_master_send (client , cmd , 5 );
73+ ret = omnia_cmd_set_color (client , led -> reg , led -> subled_info [0 ].brightness ,
74+ led -> subled_info [1 ].brightness , led -> subled_info [2 ].brightness );
11975 if (ret < 0 )
12076 return ret ;
12177
@@ -351,14 +307,14 @@ static ssize_t brightness_show(struct device *dev, struct device_attribute *a,
351307 char * buf )
352308{
353309 struct i2c_client * client = to_i2c_client (dev );
354- int ret ;
355-
356- ret = omnia_cmd_read_u8 (client , CMD_LED_GET_BRIGHTNESS );
310+ u8 reply ;
311+ int err ;
357312
358- if (ret < 0 )
359- return ret ;
313+ err = omnia_cmd_read_u8 (client , CMD_LED_GET_BRIGHTNESS , & reply );
314+ if (err < 0 )
315+ return err ;
360316
361- return sysfs_emit (buf , "%d\n" , ret );
317+ return sysfs_emit (buf , "%d\n" , reply );
362318}
363319
364320static ssize_t brightness_store (struct device * dev , struct device_attribute * a ,
@@ -385,17 +341,16 @@ static ssize_t gamma_correction_show(struct device *dev,
385341{
386342 struct i2c_client * client = to_i2c_client (dev );
387343 struct omnia_leds * leds = i2c_get_clientdata (client );
388- int ret ;
344+ u8 reply = 0 ;
345+ int err ;
389346
390347 if (leds -> has_gamma_correction ) {
391- ret = omnia_cmd_read_u8 (client , CMD_GET_GAMMA_CORRECTION );
392- if (ret < 0 )
393- return ret ;
394- } else {
395- ret = 0 ;
348+ err = omnia_cmd_read_u8 (client , CMD_GET_GAMMA_CORRECTION , & reply );
349+ if (err < 0 )
350+ return err ;
396351 }
397352
398- return sysfs_emit (buf , "%d\n" , !!ret );
353+ return sysfs_emit (buf , "%d\n" , !!reply );
399354}
400355
401356static ssize_t gamma_correction_store (struct device * dev ,
@@ -426,26 +381,51 @@ static struct attribute *omnia_led_controller_attrs[] = {
426381};
427382ATTRIBUTE_GROUPS (omnia_led_controller );
428383
429- static int omnia_mcu_get_features (const struct i2c_client * client )
384+ static int omnia_mcu_get_features (const struct i2c_client * mcu_client )
430385{
431386 u16 reply ;
432387 int err ;
433388
434- err = omnia_cmd_read_raw (client -> adapter , OMNIA_MCU_I2C_ADDR ,
435- CMD_GET_STATUS_WORD , & reply , sizeof (reply ));
389+ err = omnia_cmd_read_u16 (mcu_client , CMD_GET_STATUS_WORD , & reply );
436390 if (err )
437391 return err ;
438392
439393 /* Check whether MCU firmware supports the CMD_GET_FEAUTRES command */
440- if (!(le16_to_cpu ( reply ) & STS_FEATURES_SUPPORTED ))
394+ if (!(reply & STS_FEATURES_SUPPORTED ))
441395 return 0 ;
442396
443- err = omnia_cmd_read_raw (client -> adapter , OMNIA_MCU_I2C_ADDR ,
444- CMD_GET_FEATURES , & reply , sizeof (reply ));
397+ err = omnia_cmd_read_u16 (mcu_client , CMD_GET_FEATURES , & reply );
445398 if (err )
446399 return err ;
447400
448- return le16_to_cpu (reply );
401+ return reply ;
402+ }
403+
404+ static int omnia_match_mcu_client (struct device * dev , void * data )
405+ {
406+ struct i2c_client * client ;
407+
408+ client = i2c_verify_client (dev );
409+ if (!client )
410+ return 0 ;
411+
412+ return client -> addr == OMNIA_MCU_I2C_ADDR ;
413+ }
414+
415+ static int omnia_find_mcu_and_get_features (struct device * dev )
416+ {
417+ struct device * mcu_dev ;
418+ int ret ;
419+
420+ mcu_dev = device_find_child (dev -> parent , NULL , omnia_match_mcu_client );
421+ if (!mcu_dev )
422+ return - ENODEV ;
423+
424+ ret = omnia_mcu_get_features (i2c_verify_client (mcu_dev ));
425+
426+ put_device (mcu_dev );
427+
428+ return ret ;
449429}
450430
451431static int omnia_leds_probe (struct i2c_client * client )
@@ -472,7 +452,7 @@ static int omnia_leds_probe(struct i2c_client *client)
472452 leds -> client = client ;
473453 i2c_set_clientdata (client , leds );
474454
475- ret = omnia_mcu_get_features ( client );
455+ ret = omnia_find_mcu_and_get_features ( dev );
476456 if (ret < 0 ) {
477457 dev_err (dev , "Cannot determine MCU supported features: %d\n" ,
478458 ret );
@@ -509,20 +489,11 @@ static int omnia_leds_probe(struct i2c_client *client)
509489
510490static void omnia_leds_remove (struct i2c_client * client )
511491{
512- u8 buf [5 ];
513-
514492 /* put all LEDs into default (HW triggered) mode */
515- omnia_cmd_write_u8 (client , CMD_LED_MODE ,
516- CMD_LED_MODE_LED (OMNIA_BOARD_LEDS ));
493+ omnia_cmd_write_u8 (client , CMD_LED_MODE , CMD_LED_MODE_LED (OMNIA_BOARD_LEDS ));
517494
518495 /* set all LEDs color to [255, 255, 255] */
519- buf [0 ] = CMD_LED_COLOR ;
520- buf [1 ] = OMNIA_BOARD_LEDS ;
521- buf [2 ] = 255 ;
522- buf [3 ] = 255 ;
523- buf [4 ] = 255 ;
524-
525- i2c_master_send (client , buf , 5 );
496+ omnia_cmd_set_color (client , OMNIA_BOARD_LEDS , 255 , 255 , 255 );
526497}
527498
528499static const struct of_device_id of_omnia_leds_match [] = {
0 commit comments