|
19 | 19 | #include <linux/interrupt.h>
|
20 | 20 | #include <linux/io.h>
|
21 | 21 | #include <linux/kernel.h>
|
| 22 | +#include <linux/list.h> |
22 | 23 | #include <linux/mdio.h>
|
23 | 24 | #include <linux/mii.h>
|
24 | 25 | #include <linux/mm.h>
|
25 | 26 | #include <linux/module.h>
|
| 27 | +#include <linux/of.h> |
26 | 28 | #include <linux/netdevice.h>
|
27 | 29 | #include <linux/phy.h>
|
28 | 30 | #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,
|
674 | 676 | device_initialize(&mdiodev->dev);
|
675 | 677 |
|
676 | 678 | dev->state = PHY_DOWN;
|
| 679 | + INIT_LIST_HEAD(&dev->leds); |
677 | 680 |
|
678 | 681 | mutex_init(&dev->lock);
|
679 | 682 | INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
|
@@ -2988,6 +2991,74 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
|
2988 | 2991 | return phydrv->config_intr && phydrv->handle_interrupt;
|
2989 | 2992 | }
|
2990 | 2993 |
|
| 2994 | +/* Dummy implementation until calls into PHY driver are added */ |
| 2995 | +static int phy_led_set_brightness(struct led_classdev *led_cdev, |
| 2996 | + enum led_brightness value) |
| 2997 | +{ |
| 2998 | + return 0; |
| 2999 | +} |
| 3000 | + |
| 3001 | +static int of_phy_led(struct phy_device *phydev, |
| 3002 | + struct device_node *led) |
| 3003 | +{ |
| 3004 | + struct device *dev = &phydev->mdio.dev; |
| 3005 | + struct led_init_data init_data = {}; |
| 3006 | + struct led_classdev *cdev; |
| 3007 | + struct phy_led *phyled; |
| 3008 | + int err; |
| 3009 | + |
| 3010 | + phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL); |
| 3011 | + if (!phyled) |
| 3012 | + return -ENOMEM; |
| 3013 | + |
| 3014 | + cdev = &phyled->led_cdev; |
| 3015 | + |
| 3016 | + err = of_property_read_u8(led, "reg", &phyled->index); |
| 3017 | + if (err) |
| 3018 | + return err; |
| 3019 | + |
| 3020 | + cdev->brightness_set_blocking = phy_led_set_brightness; |
| 3021 | + cdev->max_brightness = 1; |
| 3022 | + init_data.devicename = dev_name(&phydev->mdio.dev); |
| 3023 | + init_data.fwnode = of_fwnode_handle(led); |
| 3024 | + init_data.devname_mandatory = true; |
| 3025 | + |
| 3026 | + err = devm_led_classdev_register_ext(dev, cdev, &init_data); |
| 3027 | + if (err) |
| 3028 | + return err; |
| 3029 | + |
| 3030 | + list_add(&phyled->list, &phydev->leds); |
| 3031 | + |
| 3032 | + return 0; |
| 3033 | +} |
| 3034 | + |
| 3035 | +static int of_phy_leds(struct phy_device *phydev) |
| 3036 | +{ |
| 3037 | + struct device_node *node = phydev->mdio.dev.of_node; |
| 3038 | + struct device_node *leds, *led; |
| 3039 | + int err; |
| 3040 | + |
| 3041 | + if (!IS_ENABLED(CONFIG_OF_MDIO)) |
| 3042 | + return 0; |
| 3043 | + |
| 3044 | + if (!node) |
| 3045 | + return 0; |
| 3046 | + |
| 3047 | + leds = of_get_child_by_name(node, "leds"); |
| 3048 | + if (!leds) |
| 3049 | + return 0; |
| 3050 | + |
| 3051 | + for_each_available_child_of_node(leds, led) { |
| 3052 | + err = of_phy_led(phydev, led); |
| 3053 | + if (err) { |
| 3054 | + of_node_put(led); |
| 3055 | + return err; |
| 3056 | + } |
| 3057 | + } |
| 3058 | + |
| 3059 | + return 0; |
| 3060 | +} |
| 3061 | + |
2991 | 3062 | /**
|
2992 | 3063 | * fwnode_mdio_find_device - Given a fwnode, find the mdio_device
|
2993 | 3064 | * @fwnode: pointer to the mdio_device's fwnode
|
@@ -3183,6 +3254,11 @@ static int phy_probe(struct device *dev)
|
3183 | 3254 | /* Set the state to READY by default */
|
3184 | 3255 | phydev->state = PHY_READY;
|
3185 | 3256 |
|
| 3257 | + /* Get the LEDs from the device tree, and instantiate standard |
| 3258 | + * LEDs for them. |
| 3259 | + */ |
| 3260 | + err = of_phy_leds(phydev); |
| 3261 | + |
3186 | 3262 | out:
|
3187 | 3263 | /* Re-assert the reset signal on error */
|
3188 | 3264 | if (err)
|
|
0 commit comments