summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/igc/igc_main.c
diff options
context:
space:
mode:
authorKurt Kanzenbach <kurt@linutronix.de>2021-06-29 07:43:32 +0300
committerTony Nguyen <anthony.l.nguyen@intel.com>2021-07-17 00:08:12 +0300
commitcf8331825a8d10e46fa574fdf015a65cb5a6db86 (patch)
treeb0366fa2c2c1f21958168612f4cbce1cfd86137d /drivers/net/ethernet/intel/igc/igc_main.c
parent73744262210c4560efb2d89385c6219739d16bbd (diff)
downloadlinux-cf8331825a8d10e46fa574fdf015a65cb5a6db86.tar.xz
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: Kurt Kanzenbach <kurt@linutronix.de> Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Tested-by: Dvora Fuxbrumer <dvorax.fuxbrumer@linux.intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_main.c')
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 11385c380947..100819dcc7dd 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -6130,6 +6130,134 @@ err_inval:
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);