mirror of
https://github.com/torvalds/linux.git
synced 2026-06-05 04:56:13 +02:00
can: kvaser_usb: Add support to control CAN LEDs on device
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>
This commit is contained in:
parent
46647a8405
commit
478248f1bc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user