Commit cf833182 authored by Kurt Kanzenbach's avatar Kurt Kanzenbach Committed by Tony Nguyen
Browse files

igc: Export LEDs



Each i225 has three LEDs. Export them via the LED class framework.

Each LED is controllable via sysfs. Example:

$ cd /sys/class/leds/igc_led0
$ cat brightness      # Current Mode
$ cat max_brightness  # 15
$ echo 0 > brightness # Mode 0
$ echo 1 > brightness # Mode 1

The brightness field here reflects the different LED modes ranging
from 0 to 15.

Signed-off-by: default avatarKurt Kanzenbach <kurt@linutronix.de>
Reviewed-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: default avatarDvora Fuxbrumer <dvorax.fuxbrumer@linux.intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 73744262
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -335,6 +335,7 @@ config IGC
	tristate "Intel(R) Ethernet Controller I225-LM/I225-V support"
	default n
	depends on PCI
	depends on LEDS_CLASS
	help
	  This driver supports Intel(R) Ethernet Controller I225-LM/I225-V
	  family of adapters.
+10 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/leds.h>

#include "igc_hw.h"

@@ -239,8 +240,17 @@ struct igc_adapter {
		struct timespec64 start;
		struct timespec64 period;
	} perout[IGC_N_PEROUT];

	/* LEDs */
	struct mutex led_mutex;
	struct led_classdev led0;
	struct led_classdev led1;
	struct led_classdev led2;
};

#define led_to_igc(ldev, led)                          \
	container_of(ldev, struct igc_adapter, led)

void igc_up(struct igc_adapter *adapter);
void igc_down(struct igc_adapter *adapter);
int igc_open(struct net_device *netdev);
+10 −0
Original line number Diff line number Diff line
@@ -144,6 +144,16 @@
#define IGC_CTRL_SDP0_DIR	0x00400000  /* SDP0 Data direction */
#define IGC_CTRL_SDP1_DIR	0x00800000  /* SDP1 Data direction */

/* LED Control */
#define IGC_LEDCTL_LED0_MODE_SHIFT	0
#define IGC_LEDCTL_LED0_MODE_MASK	GENMASK(3, 0)
#define IGC_LEDCTL_LED1_MODE_SHIFT	8
#define IGC_LEDCTL_LED1_MODE_MASK	GENMASK(11, 8)
#define IGC_LEDCTL_LED2_MODE_SHIFT	16
#define IGC_LEDCTL_LED2_MODE_MASK	GENMASK(19, 16)

#define IGC_CONNSW_AUTOSENSE_EN		0x1

/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
#define MAX_JUMBO_FRAME_SIZE	0x2600

+132 −0
Original line number Diff line number Diff line
@@ -6130,6 +6130,134 @@ int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx)
	return -EINVAL;
}

static void igc_select_led(struct igc_adapter *adapter, int led,
			   u32 *mask, u32 *shift)
{
	switch (led) {
	case 0:
		*mask  = IGC_LEDCTL_LED0_MODE_MASK;
		*shift = IGC_LEDCTL_LED0_MODE_SHIFT;
		break;
	case 1:
		*mask  = IGC_LEDCTL_LED1_MODE_MASK;
		*shift = IGC_LEDCTL_LED1_MODE_SHIFT;
		break;
	case 2:
		*mask  = IGC_LEDCTL_LED2_MODE_MASK;
		*shift = IGC_LEDCTL_LED2_MODE_SHIFT;
		break;
	default:
		*mask = *shift = 0;
		dev_err(&adapter->pdev->dev, "Unknown led %d selected!", led);
	}
}

static void igc_led_set(struct igc_adapter *adapter, int led, u16 brightness)
{
	struct igc_hw *hw = &adapter->hw;
	u32 shift, mask, ledctl;

	igc_select_led(adapter, led, &mask, &shift);

	mutex_lock(&adapter->led_mutex);
	ledctl = rd32(IGC_LEDCTL);
	ledctl &= ~mask;
	ledctl |= brightness << shift;
	wr32(IGC_LEDCTL, ledctl);
	mutex_unlock(&adapter->led_mutex);
}

static enum led_brightness igc_led_get(struct igc_adapter *adapter, int led)
{
	struct igc_hw *hw = &adapter->hw;
	u32 shift, mask, ledctl;

	igc_select_led(adapter, led, &mask, &shift);

	mutex_lock(&adapter->led_mutex);
	ledctl = rd32(IGC_LEDCTL);
	mutex_unlock(&adapter->led_mutex);

	return (ledctl & mask) >> shift;
}

static void igc_led0_set(struct led_classdev *ldev, enum led_brightness b)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led0);

	igc_led_set(adapter, 0, b);
}

static enum led_brightness igc_led0_get(struct led_classdev *ldev)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led0);

	return igc_led_get(adapter, 0);
}

static void igc_led1_set(struct led_classdev *ldev, enum led_brightness b)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led1);

	igc_led_set(adapter, 1, b);
}

static enum led_brightness igc_led1_get(struct led_classdev *ldev)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led1);

	return igc_led_get(adapter, 1);
}

static void igc_led2_set(struct led_classdev *ldev, enum led_brightness b)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led2);

	igc_led_set(adapter, 2, b);
}

static enum led_brightness igc_led2_get(struct led_classdev *ldev)
{
	struct igc_adapter *adapter = led_to_igc(ldev, led2);

	return igc_led_get(adapter, 2);
}

static int igc_led_setup(struct igc_adapter *adapter)
{
	/* Setup */
	mutex_init(&adapter->led_mutex);

	adapter->led0.name	     = "igc_led0";
	adapter->led0.max_brightness = 15;
	adapter->led0.brightness_set = igc_led0_set;
	adapter->led0.brightness_get = igc_led0_get;

	adapter->led1.name	     = "igc_led1";
	adapter->led1.max_brightness = 15;
	adapter->led1.brightness_set = igc_led1_set;
	adapter->led1.brightness_get = igc_led1_get;

	adapter->led2.name	     = "igc_led2";
	adapter->led2.max_brightness = 15;
	adapter->led2.brightness_set = igc_led2_set;
	adapter->led2.brightness_get = igc_led2_get;

	/* Register leds */
	led_classdev_register(&adapter->pdev->dev, &adapter->led0);
	led_classdev_register(&adapter->pdev->dev, &adapter->led1);
	led_classdev_register(&adapter->pdev->dev, &adapter->led2);

	return 0;
}

static void igc_led_destroy(struct igc_adapter *adapter)
{
	led_classdev_unregister(&adapter->led0);
	led_classdev_unregister(&adapter->led1);
	led_classdev_unregister(&adapter->led2);
}

/**
 * igc_probe - Device Initialization Routine
 * @pdev: PCI device information struct
@@ -6357,6 +6485,8 @@ static int igc_probe(struct pci_dev *pdev,

	pm_runtime_put_noidle(&pdev->dev);

	igc_led_setup(adapter);

	return 0;

err_register:
@@ -6398,6 +6528,8 @@ static void igc_remove(struct pci_dev *pdev)

	igc_ptp_stop(adapter);

	igc_led_destroy(adapter);

	set_bit(__IGC_DOWN, &adapter->state);

	del_timer_sync(&adapter->watchdog_timer);
+2 −0
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@
#define IGC_EECD		0x00010  /* EEPROM/Flash Control - RW */
#define IGC_CTRL_EXT		0x00018  /* Extended Device Control - RW */
#define IGC_MDIC		0x00020  /* MDI Control - RW */
#define IGC_LEDCTL		0x00E00	 /* LED Control - RW */
#define IGC_MDICNFG		0x00E04  /* MDC/MDIO Configuration - RW */
#define IGC_CONNSW		0x00034  /* Copper/Fiber switch control - RW */
#define IGC_VET			0x00038  /* VLAN Ether Type - RW */
#define IGC_I225_PHPM		0x00E14  /* I225 PHY Power Management */