@@ -31,6 +31,43 @@ qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en
3131	return  0 ;
3232}
3333
34+ static  int 
35+ qca8k_get_control_led_reg (int  port_num , int  led_num , struct  qca8k_led_pattern_en  * reg_info )
36+ {
37+ 	reg_info -> reg  =  QCA8K_LED_CTRL_REG (led_num );
38+ 
39+ 	/* 6 total control rule: 
40+ 	 * 3 control rules for phy0-3 that applies to all their leds 
41+ 	 * 3 control rules for phy4 
42+ 	 */ 
43+ 	if  (port_num  ==  4 )
44+ 		reg_info -> shift  =  QCA8K_LED_PHY4_CONTROL_RULE_SHIFT ;
45+ 	else 
46+ 		reg_info -> shift  =  QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT ;
47+ 
48+ 	return  0 ;
49+ }
50+ 
51+ static  int 
52+ qca8k_parse_netdev (unsigned long  rules , u32  * offload_trigger )
53+ {
54+ 	/* Parsing specific to netdev trigger */ 
55+ 	if  (test_bit (TRIGGER_NETDEV_TX , & rules ))
56+ 		* offload_trigger  |= QCA8K_LED_TX_BLINK_MASK ;
57+ 	if  (test_bit (TRIGGER_NETDEV_RX , & rules ))
58+ 		* offload_trigger  |= QCA8K_LED_RX_BLINK_MASK ;
59+ 
60+ 	if  (rules  &&  !* offload_trigger )
61+ 		return  - EOPNOTSUPP ;
62+ 
63+ 	/* Enable some default rule by default to the requested mode: 
64+ 	 * - Blink at 4Hz by default 
65+ 	 */ 
66+ 	* offload_trigger  |= QCA8K_LED_BLINK_4HZ ;
67+ 
68+ 	return  0 ;
69+ }
70+ 
3471static  int 
3572qca8k_led_brightness_set (struct  qca8k_led  * led ,
3673			 enum  led_brightness  brightness )
@@ -164,6 +201,119 @@ qca8k_cled_blink_set(struct led_classdev *ldev,
164201	return  0 ;
165202}
166203
204+ static  int 
205+ qca8k_cled_trigger_offload (struct  led_classdev  * ldev , bool  enable )
206+ {
207+ 	struct  qca8k_led  * led  =  container_of (ldev , struct  qca8k_led , cdev );
208+ 
209+ 	struct  qca8k_led_pattern_en  reg_info ;
210+ 	struct  qca8k_priv  * priv  =  led -> priv ;
211+ 	u32  mask , val  =  QCA8K_LED_ALWAYS_OFF ;
212+ 
213+ 	qca8k_get_enable_led_reg (led -> port_num , led -> led_num , & reg_info );
214+ 
215+ 	if  (enable )
216+ 		val  =  QCA8K_LED_RULE_CONTROLLED ;
217+ 
218+ 	if  (led -> port_num  ==  0  ||  led -> port_num  ==  4 ) {
219+ 		mask  =  QCA8K_LED_PATTERN_EN_MASK ;
220+ 		val  <<= QCA8K_LED_PATTERN_EN_SHIFT ;
221+ 	} else  {
222+ 		mask  =  QCA8K_LED_PHY123_PATTERN_EN_MASK ;
223+ 	}
224+ 
225+ 	return  regmap_update_bits (priv -> regmap , reg_info .reg , mask  << reg_info .shift ,
226+ 				  val  << reg_info .shift );
227+ }
228+ 
229+ static  bool 
230+ qca8k_cled_hw_control_status (struct  led_classdev  * ldev )
231+ {
232+ 	struct  qca8k_led  * led  =  container_of (ldev , struct  qca8k_led , cdev );
233+ 
234+ 	struct  qca8k_led_pattern_en  reg_info ;
235+ 	struct  qca8k_priv  * priv  =  led -> priv ;
236+ 	u32  val ;
237+ 
238+ 	qca8k_get_enable_led_reg (led -> port_num , led -> led_num , & reg_info );
239+ 
240+ 	regmap_read (priv -> regmap , reg_info .reg , & val );
241+ 
242+ 	val  >>= reg_info .shift ;
243+ 
244+ 	if  (led -> port_num  ==  0  ||  led -> port_num  ==  4 ) {
245+ 		val  &= QCA8K_LED_PATTERN_EN_MASK ;
246+ 		val  >>= QCA8K_LED_PATTERN_EN_SHIFT ;
247+ 	} else  {
248+ 		val  &= QCA8K_LED_PHY123_PATTERN_EN_MASK ;
249+ 	}
250+ 
251+ 	return  val  ==  QCA8K_LED_RULE_CONTROLLED ;
252+ }
253+ 
254+ static  int 
255+ qca8k_cled_hw_control_is_supported (struct  led_classdev  * ldev , unsigned long  rules )
256+ {
257+ 	u32  offload_trigger  =  0 ;
258+ 
259+ 	return  qca8k_parse_netdev (rules , & offload_trigger );
260+ }
261+ 
262+ static  int 
263+ qca8k_cled_hw_control_set (struct  led_classdev  * ldev , unsigned long  rules )
264+ {
265+ 	struct  qca8k_led  * led  =  container_of (ldev , struct  qca8k_led , cdev );
266+ 	struct  qca8k_led_pattern_en  reg_info ;
267+ 	struct  qca8k_priv  * priv  =  led -> priv ;
268+ 	u32  offload_trigger  =  0 ;
269+ 	int  ret ;
270+ 
271+ 	ret  =  qca8k_parse_netdev (rules , & offload_trigger );
272+ 	if  (ret )
273+ 		return  ret ;
274+ 
275+ 	ret  =  qca8k_cled_trigger_offload (ldev , true);
276+ 	if  (ret )
277+ 		return  ret ;
278+ 
279+ 	qca8k_get_control_led_reg (led -> port_num , led -> led_num , & reg_info );
280+ 
281+ 	return  regmap_update_bits (priv -> regmap , reg_info .reg ,
282+ 				  QCA8K_LED_RULE_MASK  << reg_info .shift ,
283+ 				  offload_trigger  << reg_info .shift );
284+ }
285+ 
286+ static  int 
287+ qca8k_cled_hw_control_get (struct  led_classdev  * ldev , unsigned long  * rules )
288+ {
289+ 	struct  qca8k_led  * led  =  container_of (ldev , struct  qca8k_led , cdev );
290+ 	struct  qca8k_led_pattern_en  reg_info ;
291+ 	struct  qca8k_priv  * priv  =  led -> priv ;
292+ 	u32  val ;
293+ 	int  ret ;
294+ 
295+ 	/* With hw control not active return err */ 
296+ 	if  (!qca8k_cled_hw_control_status (ldev ))
297+ 		return  - EINVAL ;
298+ 
299+ 	qca8k_get_control_led_reg (led -> port_num , led -> led_num , & reg_info );
300+ 
301+ 	ret  =  regmap_read (priv -> regmap , reg_info .reg , & val );
302+ 	if  (ret )
303+ 		return  ret ;
304+ 
305+ 	val  >>= reg_info .shift ;
306+ 	val  &= QCA8K_LED_RULE_MASK ;
307+ 
308+ 	/* Parsing specific to netdev trigger */ 
309+ 	if  (val  &  QCA8K_LED_TX_BLINK_MASK )
310+ 		set_bit (TRIGGER_NETDEV_TX , rules );
311+ 	if  (val  &  QCA8K_LED_RX_BLINK_MASK )
312+ 		set_bit (TRIGGER_NETDEV_RX , rules );
313+ 
314+ 	return  0 ;
315+ }
316+ 
167317static  int 
168318qca8k_parse_port_leds (struct  qca8k_priv  * priv , struct  fwnode_handle  * port , int  port_num )
169319{
@@ -224,6 +374,10 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
224374		port_led -> cdev .max_brightness  =  1 ;
225375		port_led -> cdev .brightness_set_blocking  =  qca8k_cled_brightness_set_blocking ;
226376		port_led -> cdev .blink_set  =  qca8k_cled_blink_set ;
377+ 		port_led -> cdev .hw_control_is_supported  =  qca8k_cled_hw_control_is_supported ;
378+ 		port_led -> cdev .hw_control_set  =  qca8k_cled_hw_control_set ;
379+ 		port_led -> cdev .hw_control_get  =  qca8k_cled_hw_control_get ;
380+ 		port_led -> cdev .hw_control_trigger  =  "netdev" ;
227381		init_data .default_label  =  ":port" ;
228382		init_data .fwnode  =  led ;
229383		init_data .devname_mandatory  =  true;
0 commit comments