can: peak_usb: include support for a new MCU
authorStephane Grosjean <s.grosjean@peak-system.com>
Tue, 19 Jul 2022 12:06:32 +0000 (14:06 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 19 Jul 2022 19:41:38 +0000 (21:41 +0200)
The CANFD-USB PCAN-USB FD interface undergoes an internal component
change that requires a slight modification of its drivers, which leads
them to dynamically use endpoint numbers provided by the interface
itself. In addition to a change in the calls to the USB functions
exported by the kernel, the detection of the USB interface dedicated
to CAN must also be modified, as some PEAK-System devices support
other interfaces than CAN.

Link: https://lore.kernel.org/all/20220719120632.26774-3-s.grosjean@peak-system.com
Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
[mkl: add missing cpu_to_le16() conversion]
[mkl: fix networking block comment style]
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/peak_usb/pcan_usb_fd.c

index 65487ec..3d7e0e3 100644 (file)
 #define PCAN_UFD_RX_BUFFER_SIZE                2048
 #define PCAN_UFD_TX_BUFFER_SIZE                512
 
+/* struct pcan_ufd_fw_info::type */
+#define PCAN_USBFD_TYPE_STD            1
+#define PCAN_USBFD_TYPE_EXT            2       /* includes EP numbers */
+
 /* read some versions info from the hw device */
 struct __packed pcan_ufd_fw_info {
        __le16  size_of;        /* sizeof this */
@@ -44,6 +48,13 @@ struct __packed pcan_ufd_fw_info {
        __le32  dev_id[2];      /* "device id" per CAN */
        __le32  ser_no;         /* S/N */
        __le32  flags;          /* special functions */
+
+       /* extended data when type == PCAN_USBFD_TYPE_EXT */
+       u8      cmd_out_ep;     /* ep for cmd */
+       u8      cmd_in_ep;      /* ep for replies */
+       u8      data_out_ep[2]; /* ep for CANx TX */
+       u8      data_in_ep;     /* ep for CAN RX */
+       u8      dummy[3];
 };
 
 /* handle device specific info used by the netdevices */
@@ -171,6 +182,9 @@ static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev)
 /* send PCAN-USB Pro FD commands synchronously */
 static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
 {
+       struct pcan_usb_fd_device *pdev =
+               container_of(dev, struct pcan_usb_fd_device, dev);
+       struct pcan_ufd_fw_info *fw_info = &pdev->usb_if->fw_info;
        void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
        int err = 0;
        u8 *packet_ptr;
@@ -200,7 +214,7 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
        do {
                err = usb_bulk_msg(dev->udev,
                                   usb_sndbulkpipe(dev->udev,
-                                                  PCAN_USBPRO_EP_CMDOUT),
+                                                  fw_info->cmd_out_ep),
                                   packet_ptr, packet_len,
                                   NULL, PCAN_UFD_CMD_TIMEOUT_MS);
                if (err) {
@@ -426,6 +440,9 @@ static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev,
 static int pcan_usb_fd_restart_async(struct peak_usb_device *dev,
                                     struct urb *urb, u8 *buf)
 {
+       struct pcan_usb_fd_device *pdev =
+               container_of(dev, struct pcan_usb_fd_device, dev);
+       struct pcan_ufd_fw_info *fw_info = &pdev->usb_if->fw_info;
        u8 *pc = buf;
 
        /* build the entire cmds list in the provided buffer, to go back into
@@ -439,7 +456,7 @@ static int pcan_usb_fd_restart_async(struct peak_usb_device *dev,
 
        /* complete the URB */
        usb_fill_bulk_urb(urb, dev->udev,
-                         usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT),
+                         usb_sndbulkpipe(dev->udev, fw_info->cmd_out_ep),
                          buf, pc - buf,
                          pcan_usb_pro_restart_complete, dev);
 
@@ -839,6 +856,15 @@ static int pcan_usb_fd_get_berr_counter(const struct net_device *netdev,
        return 0;
 }
 
+/* probe function for all PCAN-USB FD family usb interfaces */
+static int pcan_usb_fd_probe(struct usb_interface *intf)
+{
+       struct usb_host_interface *iface_desc = &intf->altsetting[0];
+
+       /* CAN interface is always interface #0 */
+       return iface_desc->desc.bInterfaceNumber;
+}
+
 /* stop interface (last chance before set bus off) */
 static int pcan_usb_fd_stop(struct peak_usb_device *dev)
 {
@@ -860,6 +886,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
 {
        struct pcan_usb_fd_device *pdev =
                        container_of(dev, struct pcan_usb_fd_device, dev);
+       struct pcan_ufd_fw_info *fw_info;
        int i, err = -ENOMEM;
 
        /* do this for 1st channel only */
@@ -878,10 +905,12 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                /* number of ts msgs to ignore before taking one into account */
                pdev->usb_if->cm_ignore_count = 5;
 
+               fw_info = &pdev->usb_if->fw_info;
+
                err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
                                            PCAN_USBPRO_INFO_FW,
-                                           &pdev->usb_if->fw_info,
-                                           sizeof(pdev->usb_if->fw_info));
+                                           fw_info,
+                                           sizeof(*fw_info));
                if (err) {
                        dev_err(dev->netdev->dev.parent,
                                "unable to read %s firmware info (err %d)\n",
@@ -895,14 +924,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                 */
                dev_info(dev->netdev->dev.parent,
                         "PEAK-System %s v%u fw v%u.%u.%u (%u channels)\n",
-                        dev->adapter->name, pdev->usb_if->fw_info.hw_version,
-                        pdev->usb_if->fw_info.fw_version[0],
-                        pdev->usb_if->fw_info.fw_version[1],
-                        pdev->usb_if->fw_info.fw_version[2],
+                        dev->adapter->name, fw_info->hw_version,
+                        fw_info->fw_version[0],
+                        fw_info->fw_version[1],
+                        fw_info->fw_version[2],
                         dev->adapter->ctrl_count);
 
                /* check for ability to switch between ISO/non-ISO modes */
-               if (pdev->usb_if->fw_info.fw_version[0] >= 2) {
+               if (fw_info->fw_version[0] >= 2) {
                        /* firmware >= 2.x supports ISO/non-ISO switching */
                        dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
                } else {
@@ -910,6 +939,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                        dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
                }
 
+               /* if vendor rsp is of type 2, then it contains EP numbers to
+                * use for cmds pipes. If not, then default EP should be used.
+                */
+               if (fw_info->type != cpu_to_le16(PCAN_USBFD_TYPE_EXT)) {
+                       fw_info->cmd_out_ep = PCAN_USBPRO_EP_CMDOUT;
+                       fw_info->cmd_in_ep = PCAN_USBPRO_EP_CMDIN;
+               }
+
                /* tell the hardware the can driver is running */
                err = pcan_usb_fd_drv_loaded(dev, 1);
                if (err) {
@@ -930,12 +967,23 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
                /* do a copy of the ctrlmode[_supported] too */
                dev->can.ctrlmode = ppdev->dev.can.ctrlmode;
                dev->can.ctrlmode_supported = ppdev->dev.can.ctrlmode_supported;
+
+               fw_info = &pdev->usb_if->fw_info;
        }
 
        pdev->usb_if->dev[dev->ctrl_idx] = dev;
        dev->device_number =
                le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]);
 
+       /* if vendor rsp is of type 2, then it contains EP numbers to
+        * use for data pipes. If not, then statically defined EP are used
+        * (see peak_usb_create_dev()).
+        */
+       if (fw_info->type == cpu_to_le16(PCAN_USBFD_TYPE_EXT)) {
+               dev->ep_msg_in = fw_info->data_in_ep;
+               dev->ep_msg_out = fw_info->data_out_ep[dev->ctrl_idx];
+       }
+
        /* set clock domain */
        for (i = 0; i < ARRAY_SIZE(pcan_usb_fd_clk_freq); i++)
                if (dev->adapter->clock.freq == pcan_usb_fd_clk_freq[i])
@@ -1091,7 +1139,7 @@ const struct peak_usb_adapter pcan_usb_fd = {
        .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE,
 
        /* device callbacks */
-       .intf_probe = pcan_usb_pro_probe,       /* same as PCAN-USB Pro */
+       .intf_probe = pcan_usb_fd_probe,
        .dev_init = pcan_usb_fd_init,
 
        .dev_exit = pcan_usb_fd_exit,