can: peak_usb: add support of ethtool set_phys_id()
authorStephane Grosjean <s.grosjean@peak-system.com>
Tue, 9 Mar 2021 08:21:26 +0000 (09:21 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 30 Mar 2021 09:14:47 +0000 (11:14 +0200)
This patch makes it possible to specifically flash the LED of a CAN
port of the CAN-USB interfaces of PEAK-System.

Link: https://lore.kernel.org/r/20210309122141.3276927-1-mkl@pengutronix.de
Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
[mkl: use common prefix PCAN_ for defines]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/peak_usb/pcan_usb_core.h
drivers/net/can/usb/peak_usb/pcan_usb_fd.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.c
drivers/net/can/usb/peak_usb/pcan_usb_pro.h

index e393e84..ba509ae 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/netdevice.h>
 #include <linux/usb.h>
 #include <linux/module.h>
+#include <linux/ethtool.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -40,6 +41,7 @@
 #define PCAN_USB_CMD_REGISTER  9
 #define PCAN_USB_CMD_EXT_VCC   10
 #define PCAN_USB_CMD_ERR_FR    11
+#define PCAN_USB_CMD_LED       12
 
 /* PCAN_USB_CMD_SET_BUS number arg */
 #define PCAN_USB_BUS_XCVER             2
@@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
        return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args);
 }
 
+static int pcan_usb_set_led(struct peak_usb_device *dev, u8 onoff)
+{
+       u8 args[PCAN_USB_CMD_ARGS_LEN] = {
+               [0] = !!onoff,
+       };
+
+       return pcan_usb_send_cmd(dev, PCAN_USB_CMD_LED, PCAN_USB_SET, args);
+}
+
 /*
  * set bittiming value to can
  */
@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf)
        return 0;
 }
 
+static int pcan_usb_set_phys_id(struct net_device *netdev,
+                               enum ethtool_phys_id_state state)
+{
+       struct peak_usb_device *dev = netdev_priv(netdev);
+       int err = 0;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               /* call ON/OFF twice a second */
+               return 2;
+
+       case ETHTOOL_ID_OFF:
+               err = pcan_usb_set_led(dev, 0);
+               break;
+
+       case ETHTOOL_ID_ON:
+               fallthrough;
+
+       case ETHTOOL_ID_INACTIVE:
+               /* restore LED default */
+               err = pcan_usb_set_led(dev, 1);
+               break;
+
+       default:
+               break;
+       }
+
+       return err;
+}
+
+static const struct ethtool_ops pcan_usb_ethtool_ops = {
+       .set_phys_id = pcan_usb_set_phys_id,
+};
+
 /*
  * describe the PCAN-USB adapter
  */
@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb),
 
+       .ethtool_ops = &pcan_usb_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 16,
        .ts_period = 24575, /* calibration period in ts. */
index 29227b5..ad006ed 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/usb.h>
+#include <linux/ethtool.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -820,6 +821,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 
        netdev->flags |= IFF_ECHO; /* we support local echo */
 
+       /* add ethtool support */
+       netdev->ethtool_ops = peak_usb_adapter->ethtool_ops;
+
        init_usb_anchor(&dev->rx_submitted);
 
        init_usb_anchor(&dev->tx_submitted);
index 4b1528a..e15b4c7 100644 (file)
@@ -46,6 +46,8 @@ struct peak_usb_adapter {
        const struct can_bittiming_const * const data_bittiming_const;
        unsigned int ctrl_count;
 
+       const struct ethtool_ops *ethtool_ops;
+
        int (*intf_probe)(struct usb_interface *intf);
 
        int (*dev_init)(struct peak_usb_device *dev);
index bae0785..b3e56ee 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/netdevice.h>
 #include <linux/usb.h>
 #include <linux/module.h>
+#include <linux/ethtool.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -1006,6 +1007,31 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev)
        }
 }
 
+/* blink LED's */
+static int pcan_usb_fd_set_phys_id(struct net_device *netdev,
+                                  enum ethtool_phys_id_state state)
+{
+       struct peak_usb_device *dev = netdev_priv(netdev);
+       int err = 0;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_FAST);
+               break;
+       case ETHTOOL_ID_INACTIVE:
+               err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF);
+               break;
+       default:
+               break;
+       }
+
+       return err;
+}
+
+static const struct ethtool_ops pcan_usb_fd_ethtool_ops = {
+       .set_phys_id = pcan_usb_fd_set_phys_id,
+};
+
 /* describes the PCAN-USB FD adapter */
 static const struct can_bittiming_const pcan_usb_fd_const = {
        .name = "pcan_usb_fd",
@@ -1047,6 +1073,8 @@ const struct peak_usb_adapter pcan_usb_fd = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
 
+       .ethtool_ops = &pcan_usb_fd_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 32,
        .ts_period = 1000000, /* calibration period in ts. */
@@ -1120,6 +1148,8 @@ const struct peak_usb_adapter pcan_usb_chip = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
 
+       .ethtool_ops = &pcan_usb_fd_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 32,
        .ts_period = 1000000, /* calibration period in ts. */
@@ -1193,6 +1223,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
 
+       .ethtool_ops = &pcan_usb_fd_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 32,
        .ts_period = 1000000, /* calibration period in ts. */
@@ -1266,6 +1298,8 @@ const struct peak_usb_adapter pcan_usb_x6 = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
 
+       .ethtool_ops = &pcan_usb_fd_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 32,
        .ts_period = 1000000, /* calibration period in ts. */
index 902900d..b314d2e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/netdevice.h>
 #include <linux/usb.h>
 #include <linux/module.h>
+#include <linux/ethtool.h>
 
 #include <linux/can.h>
 #include <linux/can/dev.h>
@@ -906,7 +907,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
        usb_if->dev[dev->ctrl_idx] = dev;
 
        /* set LED in default state (end of init phase) */
-       pcan_usb_pro_set_led(dev, 0, 1);
+       pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
 
        kfree(bi);
        kfree(fi);
@@ -990,6 +991,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf)
        return 0;
 }
 
+static int pcan_usb_pro_set_phys_id(struct net_device *netdev,
+                                   enum ethtool_phys_id_state state)
+{
+       struct peak_usb_device *dev = netdev_priv(netdev);
+       int err = 0;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               /* fast blinking forever */
+               err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_BLINK_FAST,
+                                          0xffffffff);
+               break;
+
+       case ETHTOOL_ID_INACTIVE:
+               /* restore LED default */
+               err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
+               break;
+
+       default:
+               break;
+       }
+
+       return err;
+}
+
+static const struct ethtool_ops pcan_usb_pro_ethtool_ops = {
+       .set_phys_id = pcan_usb_pro_set_phys_id,
+};
+
 /*
  * describe the PCAN-USB Pro adapter
  */
@@ -1018,6 +1048,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
        /* size of device private data */
        .sizeof_dev_private = sizeof(struct pcan_usb_pro_device),
 
+       .ethtool_ops = &pcan_usb_pro_ethtool_ops,
+
        /* timestamps usage */
        .ts_used_bits = 32,
        .ts_period = 1000000, /* calibration period in ts. */
index 6bb1235..6f45043 100644 (file)
@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid {
        __le32 serial_num;
 };
 
+#define PCAN_USBPRO_LED_DEVICE         0x00
+#define PCAN_USBPRO_LED_BLINK_FAST     0x01
+#define PCAN_USBPRO_LED_BLINK_SLOW     0x02
+#define PCAN_USBPRO_LED_ON             0x03
+#define PCAN_USBPRO_LED_OFF            0x04
+
 struct __packed pcan_usb_pro_setled {
        u8  data_type;
        u8  channel;