Add support to turn on/off CAN LEDs on device. Reviewed-by: Vincent Mailhol Signed-off-by: Jimmy Assarsson --- Changes in v3: - Fix GCC compiler array warning (-Warray-bounds) reported by Simon Horman [1] - Add tag Reviewed-by Vincent Mailhol [1] https://lore.kernel.org/linux-can/aa90e02d-25d5-4f76-bd91-26795825c8a6@wanadoo.fr/T/#m1ea1889968a91b2610990c7f39feab74b72b4850 drivers/net/can/usb/kvaser_usb/kvaser_usb.h | 9 ++++ .../net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 53 ++++++++++++++++++ .../net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 54 +++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h index f6c77eca9f43..032dc1821f04 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb.h +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb.h @@ -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); diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c index 8e88b5917796..a4402b4845c6 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c @@ -12,6 +12,7 @@ * distinguish between ERROR_WARNING and ERROR_ACTIVE. */ +#include #include #include #include @@ -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, diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c index 6a45adcc45bd..a67855521ccc 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c @@ -10,6 +10,7 @@ * Copyright (C) 2015 Valeo S.A. */ +#include #include #include #include @@ -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, -- 2.49.0