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

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's 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
......@@ -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.
......
......@@ -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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment