Commit d8d4a14a authored by Martin Blumenstingl's avatar Martin Blumenstingl
Browse files

net: phy: realtek: Add support for LED configuration on RTL8211F



Add support for reading the LED configuration for the (up to) three
LEDs from device-tree for the Realtek RTL8211F PHY.

The register layout for this is very simple:
- 10Mbit/s link at LCR[0,5,10] for LED{0,1,2}
- 100Mbit/s link at LCR[1,6,11] for LED{0,1,2}
- 1000Mbit/s link at LCR[3,8,13] for LED{0,1,2}
- RX/TX activity at LCR[4,9,14] for LED{0,1,2}
- EEE at EEELCR[1,2,3] for LED{0,1,2}

Re-configure the LEDs only when specified in device-tree, otherwise keep
the configuration set using pin-strapping or the settings from the
bootloader.

Signed-off-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
parent 03b35fc4
Loading
Loading
Loading
Loading
+97 −0
Original line number Diff line number Diff line
@@ -7,8 +7,10 @@
 *
 * Copyright (c) 2004 Freescale Semiconductor, Inc.
 */
#include <dt-bindings/net/realtek-rtl8211f.h>
#include <linux/bitops.h>
#include <linux/phy.h>
#include <linux/property.h>
#include <linux/module.h>
#include <linux/delay.h>

@@ -36,10 +38,20 @@
#define RTL8211F_ALDPS_ENABLE			BIT(2)
#define RTL8211F_ALDPS_XTAL_OFF			BIT(12)

#define RTL8211F_LED_CONFIG_PAGE		0xd04
#define RTL8211F_LCR				0x10
#define RTL8211F_LCR_LED0_LINK_10		BIT(0)
#define RTL8211F_LCR_LED0_LINK_100		BIT(1)
#define RTL8211F_LCR_LED0_LINK_1000		BIT(3)
#define RTL8211F_LCR_LED0_ACTIVITY		BIT(4)
#define RTL8211F_EEELCR				0x11
#define RTL8211F_EEELCR_LED0_EEE_ENABLE		BIT(1)

#define RTL8211E_CTRL_DELAY			BIT(13)
#define RTL8211E_TX_DELAY			BIT(12)
#define RTL8211E_RX_DELAY			BIT(11)


#define RTL8201F_ISR				0x1e
#define RTL8201F_ISR_ANERR			BIT(15)
#define RTL8201F_ISR_DUPLEX			BIT(13)
@@ -286,6 +298,79 @@ static int rtl8211c_config_init(struct phy_device *phydev)
			    CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
}

static int rtl8211f_modify_led_register(struct phy_device *phydev,
					unsigned int led, u32 regnum, u16 mask,
					bool set_bit)
{
	u8 led_reg_width = regnum == RTL8211F_LCR ? 5 : 1;
	u16 reg_mask = mask << (led * led_reg_width);

	return phy_modify_paged(phydev, RTL8211F_LED_CONFIG_PAGE, regnum,
				reg_mask, set_bit ? reg_mask : 0);
}

static int rtl8211f_config_init_led(struct phy_device *phydev, unsigned int num)
{
	struct device *dev = &phydev->mdio.dev;
	char led_property[29];
	u32 mode;
	int ret;

	ret = sprintf(led_property, "realtek,led-%u-mode", num);
	if (ret < 0)
		return ret;

	ret = device_property_read_u32(dev, led_property, &mode);
	if (ret) {
		dev_dbg(dev,
			"Keeping LED%u configuration from pin-strapping or bootloader",
			num);
		return 0;
	}

	ret = rtl8211f_modify_led_register(phydev, num, RTL8211F_LCR,
					   RTL8211F_LCR_LED0_LINK_10,
					   mode & RTL8211F_LED_LINK_10);
	if (ret) {
		dev_err(dev, "Failed to update the LED%u LINK_10 bit\n", num);
		return ret;
	}

	ret = rtl8211f_modify_led_register(phydev, num, RTL8211F_LCR,
					   RTL8211F_LCR_LED0_LINK_100,
					   mode & RTL8211F_LED_LINK_100);
	if (ret) {
		dev_err(dev, "Failed to update the LED%u LINK_100 bit\n", num);
		return ret;
	}

	ret = rtl8211f_modify_led_register(phydev, num, RTL8211F_LCR,
					   RTL8211F_LCR_LED0_LINK_1000,
					   mode & RTL8211F_LED_LINK_1000);
	if (ret) {
		dev_err(dev, "Failed to update the LED%u LINK_1000 bit\n", num);
		return ret;
	}

	ret = rtl8211f_modify_led_register(phydev, num, RTL8211F_LCR,
					   RTL8211F_LCR_LED0_ACTIVITY,
					   mode & RTL8211F_LED_ACTIVITY);
	if (ret) {
		dev_err(dev, "Failed to update the LED%u ACTIVITY bit\n", num);
		return ret;
	}

	ret = rtl8211f_modify_led_register(phydev, num, RTL8211F_EEELCR,
					   RTL8211F_EEELCR_LED0_EEE_ENABLE,
					   mode & RTL8211F_LED_EEE);
	if (ret) {
		dev_err(dev, "Failed to update the LED%u EEE_ENABLE bit\n", num);
		return ret;
	}

	return 0;
}

static int rtl8211f_config_init(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
@@ -351,6 +436,18 @@ static int rtl8211f_config_init(struct phy_device *phydev)
			val_rxdly ? "enabled" : "disabled");
	}

	ret = rtl8211f_config_init_led(phydev, 0);
	if (ret)
		return ret;

	ret = rtl8211f_config_init_led(phydev, 1);
	if (ret)
		return ret;

	ret = rtl8211f_config_init_led(phydev, 2);
	if (ret)
		return ret;

	return 0;
}