]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
can: kvaser_usb: Add support to control CAN LEDs on device
authorJimmy Assarsson <extja@kvaser.com>
Fri, 25 Jul 2025 12:34:42 +0000 (14:34 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 25 Jul 2025 16:01:18 +0000 (18:01 +0200)
Add support to turn on/off CAN LEDs on device.

Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
Signed-off-by: Jimmy Assarsson <extja@kvaser.com>
Link: https://patch.msgid.link/20250725123452.41-2-extja@kvaser.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c

index f6c77eca9f433fd25619a29906952c7c3acc7959..032dc1821f04fcff87e3f10b75d4ca320d852688 100644 (file)
@@ -54,6 +54,11 @@ enum kvaser_usb_leaf_family {
        KVASER_USBCAN,
 };
 
+enum kvaser_usb_led_state {
+       KVASER_USB_LED_ON = 0,
+       KVASER_USB_LED_OFF = 1,
+};
+
 #define KVASER_USB_HYDRA_MAX_CMD_LEN           128
 struct kvaser_usb_dev_card_data_hydra {
        u8 channel_to_he[KVASER_USB_MAX_NET_DEVICES];
@@ -149,6 +154,7 @@ struct kvaser_usb_net_priv {
  * @dev_get_software_details:  get software details
  * @dev_get_card_info:         get card info
  * @dev_get_capabilities:      discover device capabilities
+ * @dev_set_led:               turn on/off device LED
  *
  * @dev_set_opt_mode:          set ctrlmod
  * @dev_start_chip:            start the CAN controller
@@ -176,6 +182,9 @@ struct kvaser_usb_dev_ops {
        int (*dev_get_software_details)(struct kvaser_usb *dev);
        int (*dev_get_card_info)(struct kvaser_usb *dev);
        int (*dev_get_capabilities)(struct kvaser_usb *dev);
+       int (*dev_set_led)(struct kvaser_usb_net_priv *priv,
+                          enum kvaser_usb_led_state state,
+                          u16 duration_ms);
        int (*dev_set_opt_mode)(const struct kvaser_usb_net_priv *priv);
        int (*dev_start_chip)(struct kvaser_usb_net_priv *priv);
        int (*dev_stop_chip)(struct kvaser_usb_net_priv *priv);
index 8e88b5917796e7f38aa3b25eae411a305f071112..a4402b4845c61da7691484ec1d36d10192858c3b 100644 (file)
@@ -12,6 +12,7 @@
  *    distinguish between ERROR_WARNING and ERROR_ACTIVE.
  */
 
+#include <linux/bitfield.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/gfp.h>
@@ -67,6 +68,8 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt;
 #define CMD_SET_BUSPARAMS_RESP                 85
 #define CMD_GET_CAPABILITIES_REQ               95
 #define CMD_GET_CAPABILITIES_RESP              96
+#define CMD_LED_ACTION_REQ                     101
+#define CMD_LED_ACTION_RESP                    102
 #define CMD_RX_MESSAGE                         106
 #define CMD_MAP_CHANNEL_REQ                    200
 #define CMD_MAP_CHANNEL_RESP                   201
@@ -217,6 +220,22 @@ struct kvaser_cmd_get_busparams_res {
        u8 reserved[20];
 } __packed;
 
+/* The device has two LEDs per CAN channel
+ * The LSB of action field controls the state:
+ *   0 = ON
+ *   1 = OFF
+ * The remaining bits of action field is the LED index
+ */
+#define KVASER_USB_HYDRA_LED_IDX_MASK GENMASK(31, 1)
+#define KVASER_USB_HYDRA_LED_YELLOW_CH0_IDX 3
+#define KVASER_USB_HYDRA_LEDS_PER_CHANNEL 2
+struct kvaser_cmd_led_action_req {
+       u8 action;
+       u8 padding;
+       __le16 duration_ms;
+       u8 reserved[24];
+} __packed;
+
 /* Ctrl modes */
 #define KVASER_USB_HYDRA_CTRLMODE_NORMAL       0x01
 #define KVASER_USB_HYDRA_CTRLMODE_LISTEN       0x02
@@ -299,6 +318,8 @@ struct kvaser_cmd {
                struct kvaser_cmd_get_busparams_req get_busparams_req;
                struct kvaser_cmd_get_busparams_res get_busparams_res;
 
+               struct kvaser_cmd_led_action_req led_action_req;
+
                struct kvaser_cmd_chip_state_event chip_state_event;
 
                struct kvaser_cmd_set_ctrlmode set_ctrlmode;
@@ -1390,6 +1411,7 @@ static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev,
        /* Ignored commands */
        case CMD_SET_BUSPARAMS_RESP:
        case CMD_SET_BUSPARAMS_FD_RESP:
+       case CMD_LED_ACTION_RESP:
                break;
 
        default:
@@ -1946,6 +1968,36 @@ static int kvaser_usb_hydra_get_capabilities(struct kvaser_usb *dev)
        return 0;
 }
 
+static int kvaser_usb_hydra_set_led(struct kvaser_usb_net_priv *priv,
+                                   enum kvaser_usb_led_state state,
+                                   u16 duration_ms)
+{
+       struct kvaser_usb *dev = priv->dev;
+       struct kvaser_cmd *cmd;
+       size_t cmd_len;
+       int ret;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->header.cmd_no = CMD_LED_ACTION_REQ;
+       cmd_len = kvaser_usb_hydra_cmd_size(cmd);
+       kvaser_usb_hydra_set_cmd_dest_he(cmd, dev->card_data.hydra.sysdbg_he);
+       kvaser_usb_hydra_set_cmd_transid(cmd, kvaser_usb_hydra_get_next_transid(dev));
+
+       cmd->led_action_req.duration_ms = cpu_to_le16(duration_ms);
+       cmd->led_action_req.action = state |
+                                    FIELD_PREP(KVASER_USB_HYDRA_LED_IDX_MASK,
+                                               KVASER_USB_HYDRA_LED_YELLOW_CH0_IDX +
+                                               KVASER_USB_HYDRA_LEDS_PER_CHANNEL * priv->channel);
+
+       ret = kvaser_usb_send_cmd(dev, cmd, cmd_len);
+       kfree(cmd);
+
+       return ret;
+}
+
 static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv)
 {
        struct kvaser_usb *dev = priv->dev;
@@ -2149,6 +2201,7 @@ const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = {
        .dev_get_software_details = kvaser_usb_hydra_get_software_details,
        .dev_get_card_info = kvaser_usb_hydra_get_card_info,
        .dev_get_capabilities = kvaser_usb_hydra_get_capabilities,
+       .dev_set_led = kvaser_usb_hydra_set_led,
        .dev_set_opt_mode = kvaser_usb_hydra_set_opt_mode,
        .dev_start_chip = kvaser_usb_hydra_start_chip,
        .dev_stop_chip = kvaser_usb_hydra_stop_chip,
index 6a45adcc45bd971f9b186bfa422aeab4ab331d44..a67855521ccc5b6f9834f46f54caf54252eac0b8 100644 (file)
@@ -10,6 +10,7 @@
  * Copyright (C) 2015 Valeo S.A.
  */
 
+#include <linux/bitfield.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/gfp.h>
@@ -81,6 +82,8 @@
 #define CMD_FLUSH_QUEUE_REPLY          68
 #define CMD_GET_CAPABILITIES_REQ       95
 #define CMD_GET_CAPABILITIES_RESP      96
+#define CMD_LED_ACTION_REQ             101
+#define CMD_LED_ACTION_RESP            102
 
 #define CMD_LEAF_LOG_MESSAGE           106
 
@@ -173,6 +176,21 @@ struct kvaser_cmd_busparams {
        struct kvaser_usb_busparams busparams;
 } __packed;
 
+/* The device has one LED per CAN channel
+ * The LSB of action field controls the state:
+ *   0 = ON
+ *   1 = OFF
+ * The remaining bits of action field is the LED index
+ */
+#define KVASER_USB_LEAF_LED_IDX_MASK GENMASK(31, 1)
+#define KVASER_USB_LEAF_LED_YELLOW_CH0_IDX 2
+struct kvaser_cmd_led_action_req {
+       u8 tid;
+       u8 action;
+       __le16 duration_ms;
+       u8 padding[24];
+} __packed;
+
 struct kvaser_cmd_tx_can {
        u8 channel;
        u8 tid;
@@ -359,6 +377,8 @@ struct kvaser_cmd {
                struct kvaser_cmd_cardinfo cardinfo;
                struct kvaser_cmd_busparams busparams;
 
+               struct kvaser_cmd_led_action_req led_action_req;
+
                struct kvaser_cmd_rx_can_header rx_can_header;
                struct kvaser_cmd_tx_acknowledge_header tx_acknowledge_header;
 
@@ -409,6 +429,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
        [CMD_ERROR_EVENT]               = kvaser_fsize(u.leaf.error_event),
        /* ignored events: */
        [CMD_FLUSH_QUEUE_REPLY]         = CMD_SIZE_ANY,
+       [CMD_LED_ACTION_RESP]           = CMD_SIZE_ANY,
 };
 
 static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
@@ -423,6 +444,8 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
        [CMD_CAN_ERROR_EVENT]           = kvaser_fsize(u.usbcan.can_error_event),
        [CMD_ERROR_EVENT]               = kvaser_fsize(u.usbcan.error_event),
        [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event),
+       /* ignored events: */
+       [CMD_LED_ACTION_RESP]           = CMD_SIZE_ANY,
 };
 
 /* Summary of a kvaser error event, for a unified Leaf/Usbcan error
@@ -924,6 +947,34 @@ static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
        return 0;
 }
 
+static int kvaser_usb_leaf_set_led(struct kvaser_usb_net_priv *priv,
+                                  enum kvaser_usb_led_state state,
+                                  u16 duration_ms)
+{
+       struct kvaser_usb *dev = priv->dev;
+       struct kvaser_cmd *cmd;
+       int ret;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->id = CMD_LED_ACTION_REQ;
+       cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_led_action_req);
+       cmd->u.led_action_req.tid = 0xff;
+
+       cmd->u.led_action_req.duration_ms = cpu_to_le16(duration_ms);
+       cmd->u.led_action_req.action = state |
+                                      FIELD_PREP(KVASER_USB_LEAF_LED_IDX_MASK,
+                                                 KVASER_USB_LEAF_LED_YELLOW_CH0_IDX +
+                                                 priv->channel);
+
+       ret = kvaser_usb_send_cmd(dev, cmd, cmd->len);
+       kfree(cmd);
+
+       return ret;
+}
+
 static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
 {
        int err = 0;
@@ -1638,6 +1689,8 @@ static void kvaser_usb_leaf_handle_command(struct kvaser_usb *dev,
                if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                break;
+       case CMD_LED_ACTION_RESP:
+               break;
 
        default:
 warn:          dev_warn(&dev->intf->dev, "Unhandled command (%d)\n", cmd->id);
@@ -1927,6 +1980,7 @@ const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
        .dev_get_software_details = NULL,
        .dev_get_card_info = kvaser_usb_leaf_get_card_info,
        .dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
+       .dev_set_led = kvaser_usb_leaf_set_led,
        .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
        .dev_start_chip = kvaser_usb_leaf_start_chip,
        .dev_stop_chip = kvaser_usb_leaf_stop_chip,