forked from mirrors/linux
		
	net: phy: Add a binding for PHY LEDs
Define common binding parsing for all PHY drivers with LEDs using phylib. Parse the DT as part of the phy_probe and add LEDs to the linux LED class infrastructure. For the moment, provide a dummy brightness function, which will later be replaced with a call into the PHY driver. This allows testing since the LED core might otherwise reject an LED whose brightness cannot be set. Add a dependency on LED_CLASS. It either needs to be built in, or not enabled, since a modular build can result in linker errors. Signed-off-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									e5029edd53
								
							
						
					
					
						commit
						01e5b728e9
					
				
					 3 changed files with 93 additions and 0 deletions
				
			
		|  | @ -18,6 +18,7 @@ menuconfig PHYLIB | |||
| 	depends on NETDEVICES | ||||
| 	select MDIO_DEVICE | ||||
| 	select MDIO_DEVRES | ||||
| 	depends on LEDS_CLASS || LEDS_CLASS=n | ||||
| 	help | ||||
| 	  Ethernet controllers are usually attached to PHY | ||||
| 	  devices.  This option provides infrastructure for | ||||
|  |  | |||
|  | @ -19,10 +19,12 @@ | |||
| #include <linux/interrupt.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/mdio.h> | ||||
| #include <linux/mii.h> | ||||
| #include <linux/mm.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/netdevice.h> | ||||
| #include <linux/phy.h> | ||||
| #include <linux/phy_led_triggers.h> | ||||
|  | @ -674,6 +676,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, | |||
| 	device_initialize(&mdiodev->dev); | ||||
| 
 | ||||
| 	dev->state = PHY_DOWN; | ||||
| 	INIT_LIST_HEAD(&dev->leds); | ||||
| 
 | ||||
| 	mutex_init(&dev->lock); | ||||
| 	INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); | ||||
|  | @ -2988,6 +2991,74 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv) | |||
| 	return phydrv->config_intr && phydrv->handle_interrupt; | ||||
| } | ||||
| 
 | ||||
| /* Dummy implementation until calls into PHY driver are added */ | ||||
| static int phy_led_set_brightness(struct led_classdev *led_cdev, | ||||
| 				  enum led_brightness value) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int of_phy_led(struct phy_device *phydev, | ||||
| 		      struct device_node *led) | ||||
| { | ||||
| 	struct device *dev = &phydev->mdio.dev; | ||||
| 	struct led_init_data init_data = {}; | ||||
| 	struct led_classdev *cdev; | ||||
| 	struct phy_led *phyled; | ||||
| 	int err; | ||||
| 
 | ||||
| 	phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL); | ||||
| 	if (!phyled) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	cdev = &phyled->led_cdev; | ||||
| 
 | ||||
| 	err = of_property_read_u8(led, "reg", &phyled->index); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	cdev->brightness_set_blocking = phy_led_set_brightness; | ||||
| 	cdev->max_brightness = 1; | ||||
| 	init_data.devicename = dev_name(&phydev->mdio.dev); | ||||
| 	init_data.fwnode = of_fwnode_handle(led); | ||||
| 	init_data.devname_mandatory = true; | ||||
| 
 | ||||
| 	err = devm_led_classdev_register_ext(dev, cdev, &init_data); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	list_add(&phyled->list, &phydev->leds); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int of_phy_leds(struct phy_device *phydev) | ||||
| { | ||||
| 	struct device_node *node = phydev->mdio.dev.of_node; | ||||
| 	struct device_node *leds, *led; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!IS_ENABLED(CONFIG_OF_MDIO)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (!node) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	leds = of_get_child_by_name(node, "leds"); | ||||
| 	if (!leds) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for_each_available_child_of_node(leds, led) { | ||||
| 		err = of_phy_led(phydev, led); | ||||
| 		if (err) { | ||||
| 			of_node_put(led); | ||||
| 			return err; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * fwnode_mdio_find_device - Given a fwnode, find the mdio_device | ||||
|  * @fwnode: pointer to the mdio_device's fwnode | ||||
|  | @ -3183,6 +3254,11 @@ static int phy_probe(struct device *dev) | |||
| 	/* Set the state to READY by default */ | ||||
| 	phydev->state = PHY_READY; | ||||
| 
 | ||||
| 	/* Get the LEDs from the device tree, and instantiate standard
 | ||||
| 	 * LEDs for them. | ||||
| 	 */ | ||||
| 	err = of_phy_leds(phydev); | ||||
| 
 | ||||
| out: | ||||
| 	/* Re-assert the reset signal on error */ | ||||
| 	if (err) | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include <linux/compiler.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/ethtool.h> | ||||
| #include <linux/leds.h> | ||||
| #include <linux/linkmode.h> | ||||
| #include <linux/netlink.h> | ||||
| #include <linux/mdio.h> | ||||
|  | @ -600,6 +601,7 @@ struct macsec_ops; | |||
|  * @phy_num_led_triggers: Number of triggers in @phy_led_triggers | ||||
|  * @led_link_trigger: LED trigger for link up/down | ||||
|  * @last_triggered: last LED trigger for link speed | ||||
|  * @leds: list of PHY LED structures | ||||
|  * @master_slave_set: User requested master/slave configuration | ||||
|  * @master_slave_get: Current master/slave advertisement | ||||
|  * @master_slave_state: Current master/slave configuration | ||||
|  | @ -699,6 +701,7 @@ struct phy_device { | |||
| 
 | ||||
| 	struct phy_led_trigger *led_link_trigger; | ||||
| #endif | ||||
| 	struct list_head leds; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Interrupt number for this PHY | ||||
|  | @ -834,6 +837,19 @@ struct phy_plca_status { | |||
| 	bool pst; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct phy_led: An LED driven by the PHY | ||||
|  * | ||||
|  * @list: List of LEDs | ||||
|  * @led_cdev: Standard LED class structure | ||||
|  * @index: Number of the LED | ||||
|  */ | ||||
| struct phy_led { | ||||
| 	struct list_head list; | ||||
| 	struct led_classdev led_cdev; | ||||
| 	u8 index; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct phy_driver - Driver structure for a particular PHY type | ||||
|  * | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Andrew Lunn
						Andrew Lunn