162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Fintek F81604 USB-to-2CAN controller driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2023 Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/netdevice.h> 862306a36Sopenharmony_ci#include <linux/units.h> 962306a36Sopenharmony_ci#include <linux/usb.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/can.h> 1262306a36Sopenharmony_ci#include <linux/can/dev.h> 1362306a36Sopenharmony_ci#include <linux/can/error.h> 1462306a36Sopenharmony_ci#include <linux/can/platform/sja1000.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm-generic/unaligned.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* vendor and product id */ 1962306a36Sopenharmony_ci#define F81604_VENDOR_ID 0x2c42 2062306a36Sopenharmony_ci#define F81604_PRODUCT_ID 0x1709 2162306a36Sopenharmony_ci#define F81604_CAN_CLOCK (12 * MEGA) 2262306a36Sopenharmony_ci#define F81604_MAX_DEV 2 2362306a36Sopenharmony_ci#define F81604_SET_DEVICE_RETRY 10 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define F81604_USB_TIMEOUT 2000 2662306a36Sopenharmony_ci#define F81604_SET_GET_REGISTER 0xA0 2762306a36Sopenharmony_ci#define F81604_PORT_OFFSET 0x1000 2862306a36Sopenharmony_ci#define F81604_MAX_RX_URBS 4 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define F81604_CMD_DATA 0x00 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define F81604_DLC_LEN_MASK GENMASK(3, 0) 3362306a36Sopenharmony_ci#define F81604_DLC_EFF_BIT BIT(7) 3462306a36Sopenharmony_ci#define F81604_DLC_RTR_BIT BIT(6) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define F81604_SFF_SHIFT 5 3762306a36Sopenharmony_ci#define F81604_EFF_SHIFT 3 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define F81604_BRP_MASK GENMASK(5, 0) 4062306a36Sopenharmony_ci#define F81604_SJW_MASK GENMASK(7, 6) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define F81604_SEG1_MASK GENMASK(3, 0) 4362306a36Sopenharmony_ci#define F81604_SEG2_MASK GENMASK(6, 4) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define F81604_CLEAR_ALC 0 4662306a36Sopenharmony_ci#define F81604_CLEAR_ECC 1 4762306a36Sopenharmony_ci#define F81604_CLEAR_OVERRUN 2 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* device setting */ 5062306a36Sopenharmony_ci#define F81604_CTRL_MODE_REG 0x80 5162306a36Sopenharmony_ci#define F81604_TX_ONESHOT (0x03 << 3) 5262306a36Sopenharmony_ci#define F81604_TX_NORMAL (0x01 << 3) 5362306a36Sopenharmony_ci#define F81604_RX_AUTO_RELEASE_BUF BIT(1) 5462306a36Sopenharmony_ci#define F81604_INT_WHEN_CHANGE BIT(0) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define F81604_TERMINATOR_REG 0x105 5762306a36Sopenharmony_ci#define F81604_CAN0_TERM BIT(2) 5862306a36Sopenharmony_ci#define F81604_CAN1_TERM BIT(3) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define F81604_TERMINATION_DISABLED CAN_TERMINATION_DISABLED 6162306a36Sopenharmony_ci#define F81604_TERMINATION_ENABLED 120 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* SJA1000 registers - manual section 6.4 (Pelican Mode) */ 6462306a36Sopenharmony_ci#define F81604_SJA1000_MOD 0x00 6562306a36Sopenharmony_ci#define F81604_SJA1000_CMR 0x01 6662306a36Sopenharmony_ci#define F81604_SJA1000_IR 0x03 6762306a36Sopenharmony_ci#define F81604_SJA1000_IER 0x04 6862306a36Sopenharmony_ci#define F81604_SJA1000_ALC 0x0B 6962306a36Sopenharmony_ci#define F81604_SJA1000_ECC 0x0C 7062306a36Sopenharmony_ci#define F81604_SJA1000_RXERR 0x0E 7162306a36Sopenharmony_ci#define F81604_SJA1000_TXERR 0x0F 7262306a36Sopenharmony_ci#define F81604_SJA1000_ACCC0 0x10 7362306a36Sopenharmony_ci#define F81604_SJA1000_ACCM0 0x14 7462306a36Sopenharmony_ci#define F81604_MAX_FILTER_CNT 4 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Common registers - manual section 6.5 */ 7762306a36Sopenharmony_ci#define F81604_SJA1000_BTR0 0x06 7862306a36Sopenharmony_ci#define F81604_SJA1000_BTR1 0x07 7962306a36Sopenharmony_ci#define F81604_SJA1000_BTR1_SAMPLE_TRIPLE BIT(7) 8062306a36Sopenharmony_ci#define F81604_SJA1000_OCR 0x08 8162306a36Sopenharmony_ci#define F81604_SJA1000_CDR 0x1F 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* mode register */ 8462306a36Sopenharmony_ci#define F81604_SJA1000_MOD_RM 0x01 8562306a36Sopenharmony_ci#define F81604_SJA1000_MOD_LOM 0x02 8662306a36Sopenharmony_ci#define F81604_SJA1000_MOD_STM 0x04 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* commands */ 8962306a36Sopenharmony_ci#define F81604_SJA1000_CMD_CDO 0x08 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* interrupt sources */ 9262306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_BEI 0x80 9362306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_ALI 0x40 9462306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_EPI 0x20 9562306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_DOI 0x08 9662306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_EI 0x04 9762306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_TI 0x02 9862306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_RI 0x01 9962306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_ALL 0xFF 10062306a36Sopenharmony_ci#define F81604_SJA1000_IRQ_OFF 0x00 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* status register content */ 10362306a36Sopenharmony_ci#define F81604_SJA1000_SR_BS 0x80 10462306a36Sopenharmony_ci#define F81604_SJA1000_SR_ES 0x40 10562306a36Sopenharmony_ci#define F81604_SJA1000_SR_TCS 0x08 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* ECC register */ 10862306a36Sopenharmony_ci#define F81604_SJA1000_ECC_SEG 0x1F 10962306a36Sopenharmony_ci#define F81604_SJA1000_ECC_DIR 0x20 11062306a36Sopenharmony_ci#define F81604_SJA1000_ECC_BIT 0x00 11162306a36Sopenharmony_ci#define F81604_SJA1000_ECC_FORM 0x40 11262306a36Sopenharmony_ci#define F81604_SJA1000_ECC_STUFF 0x80 11362306a36Sopenharmony_ci#define F81604_SJA1000_ECC_MASK 0xc0 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* ALC register */ 11662306a36Sopenharmony_ci#define F81604_SJA1000_ALC_MASK 0x1f 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* table of devices that work with this driver */ 11962306a36Sopenharmony_cistatic const struct usb_device_id f81604_table[] = { 12062306a36Sopenharmony_ci { USB_DEVICE(F81604_VENDOR_ID, F81604_PRODUCT_ID) }, 12162306a36Sopenharmony_ci {} /* Terminating entry */ 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, f81604_table); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic const struct ethtool_ops f81604_ethtool_ops = { 12762306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const u16 f81604_termination[] = { F81604_TERMINATION_DISABLED, 13162306a36Sopenharmony_ci F81604_TERMINATION_ENABLED }; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct f81604_priv { 13462306a36Sopenharmony_ci struct net_device *netdev[F81604_MAX_DEV]; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct f81604_port_priv { 13862306a36Sopenharmony_ci struct can_priv can; 13962306a36Sopenharmony_ci struct net_device *netdev; 14062306a36Sopenharmony_ci struct sk_buff *echo_skb; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci unsigned long clear_flags; 14362306a36Sopenharmony_ci struct work_struct clear_reg_work; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci struct usb_device *dev; 14662306a36Sopenharmony_ci struct usb_interface *intf; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci struct usb_anchor urbs_anchor; 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* Interrupt endpoint data format: 15262306a36Sopenharmony_ci * Byte 0: Status register. 15362306a36Sopenharmony_ci * Byte 1: Interrupt register. 15462306a36Sopenharmony_ci * Byte 2: Interrupt enable register. 15562306a36Sopenharmony_ci * Byte 3: Arbitration lost capture(ALC) register. 15662306a36Sopenharmony_ci * Byte 4: Error code capture(ECC) register. 15762306a36Sopenharmony_ci * Byte 5: Error warning limit register. 15862306a36Sopenharmony_ci * Byte 6: RX error counter register. 15962306a36Sopenharmony_ci * Byte 7: TX error counter register. 16062306a36Sopenharmony_ci * Byte 8: Reserved. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_cistruct f81604_int_data { 16362306a36Sopenharmony_ci u8 sr; 16462306a36Sopenharmony_ci u8 isrc; 16562306a36Sopenharmony_ci u8 ier; 16662306a36Sopenharmony_ci u8 alc; 16762306a36Sopenharmony_ci u8 ecc; 16862306a36Sopenharmony_ci u8 ewlr; 16962306a36Sopenharmony_ci u8 rxerr; 17062306a36Sopenharmony_ci u8 txerr; 17162306a36Sopenharmony_ci u8 val; 17262306a36Sopenharmony_ci} __packed __aligned(4); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct f81604_sff { 17562306a36Sopenharmony_ci __be16 id; 17662306a36Sopenharmony_ci u8 data[CAN_MAX_DLEN]; 17762306a36Sopenharmony_ci} __packed __aligned(2); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct f81604_eff { 18062306a36Sopenharmony_ci __be32 id; 18162306a36Sopenharmony_ci u8 data[CAN_MAX_DLEN]; 18262306a36Sopenharmony_ci} __packed __aligned(2); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistruct f81604_can_frame { 18562306a36Sopenharmony_ci u8 cmd; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* According for F81604 DLC define: 18862306a36Sopenharmony_ci * bit 3~0: data length (0~8) 18962306a36Sopenharmony_ci * bit6: is RTR flag. 19062306a36Sopenharmony_ci * bit7: is EFF frame. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci u8 dlc; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci union { 19562306a36Sopenharmony_ci struct f81604_sff sff; 19662306a36Sopenharmony_ci struct f81604_eff eff; 19762306a36Sopenharmony_ci }; 19862306a36Sopenharmony_ci} __packed __aligned(2); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const u8 bulk_in_addr[F81604_MAX_DEV] = { 2, 4 }; 20162306a36Sopenharmony_cistatic const u8 bulk_out_addr[F81604_MAX_DEV] = { 1, 3 }; 20262306a36Sopenharmony_cistatic const u8 int_in_addr[F81604_MAX_DEV] = { 1, 3 }; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int f81604_write(struct usb_device *dev, u16 reg, u8 data) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int ret; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ret = usb_control_msg_send(dev, 0, F81604_SET_GET_REGISTER, 20962306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_DIR_OUT, 0, reg, 21062306a36Sopenharmony_ci &data, sizeof(data), F81604_USB_TIMEOUT, 21162306a36Sopenharmony_ci GFP_KERNEL); 21262306a36Sopenharmony_ci if (ret) 21362306a36Sopenharmony_ci dev_err(&dev->dev, "%s: reg: %x data: %x failed: %pe\n", 21462306a36Sopenharmony_ci __func__, reg, data, ERR_PTR(ret)); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return ret; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int f81604_read(struct usb_device *dev, u16 reg, u8 *data) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci int ret; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = usb_control_msg_recv(dev, 0, F81604_SET_GET_REGISTER, 22462306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_DIR_IN, 0, reg, data, 22562306a36Sopenharmony_ci sizeof(*data), F81604_USB_TIMEOUT, 22662306a36Sopenharmony_ci GFP_KERNEL); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (ret < 0) 22962306a36Sopenharmony_ci dev_err(&dev->dev, "%s: reg: %x failed: %pe\n", __func__, reg, 23062306a36Sopenharmony_ci ERR_PTR(ret)); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int f81604_update_bits(struct usb_device *dev, u16 reg, u8 mask, 23662306a36Sopenharmony_ci u8 data) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int ret; 23962306a36Sopenharmony_ci u8 tmp; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ret = f81604_read(dev, reg, &tmp); 24262306a36Sopenharmony_ci if (ret) 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci tmp &= ~mask; 24662306a36Sopenharmony_ci tmp |= (mask & data); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return f81604_write(dev, reg, tmp); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int f81604_sja1000_write(struct f81604_port_priv *priv, u16 reg, 25262306a36Sopenharmony_ci u8 data) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci int port = priv->netdev->dev_port; 25562306a36Sopenharmony_ci int real_reg; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET; 25862306a36Sopenharmony_ci return f81604_write(priv->dev, real_reg, data); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int f81604_sja1000_read(struct f81604_port_priv *priv, u16 reg, 26262306a36Sopenharmony_ci u8 *data) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci int port = priv->netdev->dev_port; 26562306a36Sopenharmony_ci int real_reg; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET; 26862306a36Sopenharmony_ci return f81604_read(priv->dev, real_reg, data); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int f81604_set_reset_mode(struct f81604_port_priv *priv) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci int ret, i; 27462306a36Sopenharmony_ci u8 tmp; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* disable interrupts */ 27762306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_IER, 27862306a36Sopenharmony_ci F81604_SJA1000_IRQ_OFF); 27962306a36Sopenharmony_ci if (ret) 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) { 28362306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp); 28462306a36Sopenharmony_ci if (ret) 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* check reset bit */ 28862306a36Sopenharmony_ci if (tmp & F81604_SJA1000_MOD_RM) { 28962306a36Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* reset chip */ 29462306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD, 29562306a36Sopenharmony_ci F81604_SJA1000_MOD_RM); 29662306a36Sopenharmony_ci if (ret) 29762306a36Sopenharmony_ci return ret; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return -EPERM; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int f81604_set_normal_mode(struct f81604_port_priv *priv) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci u8 tmp, ier = 0; 30662306a36Sopenharmony_ci u8 mod_reg = 0; 30762306a36Sopenharmony_ci int ret, i; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) { 31062306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp); 31162306a36Sopenharmony_ci if (ret) 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* check reset bit */ 31562306a36Sopenharmony_ci if ((tmp & F81604_SJA1000_MOD_RM) == 0) { 31662306a36Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 31762306a36Sopenharmony_ci /* enable interrupts, RI handled by bulk-in */ 31862306a36Sopenharmony_ci ier = F81604_SJA1000_IRQ_ALL & ~F81604_SJA1000_IRQ_RI; 31962306a36Sopenharmony_ci if (!(priv->can.ctrlmode & 32062306a36Sopenharmony_ci CAN_CTRLMODE_BERR_REPORTING)) 32162306a36Sopenharmony_ci ier &= ~F81604_SJA1000_IRQ_BEI; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return f81604_sja1000_write(priv, F81604_SJA1000_IER, 32462306a36Sopenharmony_ci ier); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* set chip to normal mode */ 32862306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 32962306a36Sopenharmony_ci mod_reg |= F81604_SJA1000_MOD_LOM; 33062306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) 33162306a36Sopenharmony_ci mod_reg |= F81604_SJA1000_MOD_STM; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD, mod_reg); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return -EPERM; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic int f81604_chipset_init(struct f81604_port_priv *priv) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci int i, ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* set clock divider and output control register */ 34662306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_CDR, 34762306a36Sopenharmony_ci CDR_CBP | CDR_PELICAN); 34862306a36Sopenharmony_ci if (ret) 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* set acceptance filter (accept all) */ 35262306a36Sopenharmony_ci for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) { 35362306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCC0 + i, 0); 35462306a36Sopenharmony_ci if (ret) 35562306a36Sopenharmony_ci return ret; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) { 35962306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCM0 + i, 36062306a36Sopenharmony_ci 0xFF); 36162306a36Sopenharmony_ci if (ret) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return f81604_sja1000_write(priv, F81604_SJA1000_OCR, 36662306a36Sopenharmony_ci OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL | 36762306a36Sopenharmony_ci OCR_MODE_NORMAL); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void f81604_process_rx_packet(struct net_device *netdev, 37162306a36Sopenharmony_ci struct f81604_can_frame *frame) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 37462306a36Sopenharmony_ci struct can_frame *cf; 37562306a36Sopenharmony_ci struct sk_buff *skb; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (frame->cmd != F81604_CMD_DATA) 37862306a36Sopenharmony_ci return; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci skb = alloc_can_skb(netdev, &cf); 38162306a36Sopenharmony_ci if (!skb) { 38262306a36Sopenharmony_ci stats->rx_dropped++; 38362306a36Sopenharmony_ci return; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci cf->len = can_cc_dlc2len(frame->dlc & F81604_DLC_LEN_MASK); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (frame->dlc & F81604_DLC_EFF_BIT) { 38962306a36Sopenharmony_ci cf->can_id = get_unaligned_be32(&frame->eff.id) >> 39062306a36Sopenharmony_ci F81604_EFF_SHIFT; 39162306a36Sopenharmony_ci cf->can_id |= CAN_EFF_FLAG; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!(frame->dlc & F81604_DLC_RTR_BIT)) 39462306a36Sopenharmony_ci memcpy(cf->data, frame->eff.data, cf->len); 39562306a36Sopenharmony_ci } else { 39662306a36Sopenharmony_ci cf->can_id = get_unaligned_be16(&frame->sff.id) >> 39762306a36Sopenharmony_ci F81604_SFF_SHIFT; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (!(frame->dlc & F81604_DLC_RTR_BIT)) 40062306a36Sopenharmony_ci memcpy(cf->data, frame->sff.data, cf->len); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (frame->dlc & F81604_DLC_RTR_BIT) 40462306a36Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 40562306a36Sopenharmony_ci else 40662306a36Sopenharmony_ci stats->rx_bytes += cf->len; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci stats->rx_packets++; 40962306a36Sopenharmony_ci netif_rx(skb); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void f81604_read_bulk_callback(struct urb *urb) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct f81604_can_frame *frame = urb->transfer_buffer; 41562306a36Sopenharmony_ci struct net_device *netdev = urb->context; 41662306a36Sopenharmony_ci int ret; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!netif_device_present(netdev)) 41962306a36Sopenharmony_ci return; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (urb->status) 42262306a36Sopenharmony_ci netdev_info(netdev, "%s: URB aborted %pe\n", __func__, 42362306a36Sopenharmony_ci ERR_PTR(urb->status)); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci switch (urb->status) { 42662306a36Sopenharmony_ci case 0: /* success */ 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci case -ENOENT: 43062306a36Sopenharmony_ci case -EPIPE: 43162306a36Sopenharmony_ci case -EPROTO: 43262306a36Sopenharmony_ci case -ESHUTDOWN: 43362306a36Sopenharmony_ci return; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci default: 43662306a36Sopenharmony_ci goto resubmit_urb; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (urb->actual_length != sizeof(*frame)) { 44062306a36Sopenharmony_ci netdev_warn(netdev, "URB length %u not equal to %zu\n", 44162306a36Sopenharmony_ci urb->actual_length, sizeof(*frame)); 44262306a36Sopenharmony_ci goto resubmit_urb; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci f81604_process_rx_packet(netdev, frame); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ciresubmit_urb: 44862306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_ATOMIC); 44962306a36Sopenharmony_ci if (ret == -ENODEV) 45062306a36Sopenharmony_ci netif_device_detach(netdev); 45162306a36Sopenharmony_ci else if (ret) 45262306a36Sopenharmony_ci netdev_err(netdev, 45362306a36Sopenharmony_ci "%s: failed to resubmit read bulk urb: %pe\n", 45462306a36Sopenharmony_ci __func__, ERR_PTR(ret)); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic void f81604_handle_tx(struct f81604_port_priv *priv, 45862306a36Sopenharmony_ci struct f81604_int_data *data) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 46162306a36Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* transmission buffer released */ 46462306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT && 46562306a36Sopenharmony_ci !(data->sr & F81604_SJA1000_SR_TCS)) { 46662306a36Sopenharmony_ci stats->tx_errors++; 46762306a36Sopenharmony_ci can_free_echo_skb(netdev, 0, NULL); 46862306a36Sopenharmony_ci } else { 46962306a36Sopenharmony_ci /* transmission complete */ 47062306a36Sopenharmony_ci stats->tx_bytes += can_get_echo_skb(netdev, 0, NULL); 47162306a36Sopenharmony_ci stats->tx_packets++; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci netif_wake_queue(netdev); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, 47862306a36Sopenharmony_ci struct f81604_int_data *data) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci enum can_state can_state = priv->can.state; 48162306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 48262306a36Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 48362306a36Sopenharmony_ci struct can_frame *cf; 48462306a36Sopenharmony_ci struct sk_buff *skb; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Note: ALC/ECC will not auto clear by read here, must be cleared by 48762306a36Sopenharmony_ci * read register (via clear_reg_work). 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci skb = alloc_can_err_skb(netdev, &cf); 49162306a36Sopenharmony_ci if (skb) { 49262306a36Sopenharmony_ci cf->can_id |= CAN_ERR_CNT; 49362306a36Sopenharmony_ci cf->data[6] = data->txerr; 49462306a36Sopenharmony_ci cf->data[7] = data->rxerr; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (data->isrc & F81604_SJA1000_IRQ_DOI) { 49862306a36Sopenharmony_ci /* data overrun interrupt */ 49962306a36Sopenharmony_ci netdev_dbg(netdev, "data overrun interrupt\n"); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (skb) { 50262306a36Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 50362306a36Sopenharmony_ci cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci stats->rx_over_errors++; 50762306a36Sopenharmony_ci stats->rx_errors++; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci set_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (data->isrc & F81604_SJA1000_IRQ_EI) { 51362306a36Sopenharmony_ci /* error warning interrupt */ 51462306a36Sopenharmony_ci netdev_dbg(netdev, "error warning interrupt\n"); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (data->sr & F81604_SJA1000_SR_BS) 51762306a36Sopenharmony_ci can_state = CAN_STATE_BUS_OFF; 51862306a36Sopenharmony_ci else if (data->sr & F81604_SJA1000_SR_ES) 51962306a36Sopenharmony_ci can_state = CAN_STATE_ERROR_WARNING; 52062306a36Sopenharmony_ci else 52162306a36Sopenharmony_ci can_state = CAN_STATE_ERROR_ACTIVE; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (data->isrc & F81604_SJA1000_IRQ_BEI) { 52562306a36Sopenharmony_ci /* bus error interrupt */ 52662306a36Sopenharmony_ci netdev_dbg(netdev, "bus error interrupt\n"); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci priv->can.can_stats.bus_error++; 52962306a36Sopenharmony_ci stats->rx_errors++; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (skb) { 53262306a36Sopenharmony_ci cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* set error type */ 53562306a36Sopenharmony_ci switch (data->ecc & F81604_SJA1000_ECC_MASK) { 53662306a36Sopenharmony_ci case F81604_SJA1000_ECC_BIT: 53762306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT; 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci case F81604_SJA1000_ECC_FORM: 54062306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_FORM; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case F81604_SJA1000_ECC_STUFF: 54362306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_STUFF; 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci default: 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* set error location */ 55062306a36Sopenharmony_ci cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Error occurred during transmission? */ 55362306a36Sopenharmony_ci if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) 55462306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_TX; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci set_bit(F81604_CLEAR_ECC, &priv->clear_flags); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (data->isrc & F81604_SJA1000_IRQ_EPI) { 56162306a36Sopenharmony_ci if (can_state == CAN_STATE_ERROR_PASSIVE) 56262306a36Sopenharmony_ci can_state = CAN_STATE_ERROR_WARNING; 56362306a36Sopenharmony_ci else 56462306a36Sopenharmony_ci can_state = CAN_STATE_ERROR_PASSIVE; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* error passive interrupt */ 56762306a36Sopenharmony_ci netdev_dbg(netdev, "error passive interrupt: %d\n", can_state); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (data->isrc & F81604_SJA1000_IRQ_ALI) { 57162306a36Sopenharmony_ci /* arbitration lost interrupt */ 57262306a36Sopenharmony_ci netdev_dbg(netdev, "arbitration lost interrupt\n"); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci priv->can.can_stats.arbitration_lost++; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (skb) { 57762306a36Sopenharmony_ci cf->can_id |= CAN_ERR_LOSTARB; 57862306a36Sopenharmony_ci cf->data[0] = data->alc & F81604_SJA1000_ALC_MASK; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci set_bit(F81604_CLEAR_ALC, &priv->clear_flags); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (can_state != priv->can.state) { 58562306a36Sopenharmony_ci enum can_state tx_state, rx_state; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci tx_state = data->txerr >= data->rxerr ? can_state : 0; 58862306a36Sopenharmony_ci rx_state = data->txerr <= data->rxerr ? can_state : 0; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci can_change_state(netdev, cf, tx_state, rx_state); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (can_state == CAN_STATE_BUS_OFF) 59362306a36Sopenharmony_ci can_bus_off(netdev); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (priv->clear_flags) 59762306a36Sopenharmony_ci schedule_work(&priv->clear_reg_work); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (skb) 60062306a36Sopenharmony_ci netif_rx(skb); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic void f81604_read_int_callback(struct urb *urb) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct f81604_int_data *data = urb->transfer_buffer; 60662306a36Sopenharmony_ci struct net_device *netdev = urb->context; 60762306a36Sopenharmony_ci struct f81604_port_priv *priv; 60862306a36Sopenharmony_ci int ret; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci priv = netdev_priv(netdev); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (!netif_device_present(netdev)) 61362306a36Sopenharmony_ci return; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (urb->status) 61662306a36Sopenharmony_ci netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__, 61762306a36Sopenharmony_ci ERR_PTR(urb->status)); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci switch (urb->status) { 62062306a36Sopenharmony_ci case 0: /* success */ 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci case -ENOENT: 62462306a36Sopenharmony_ci case -EPIPE: 62562306a36Sopenharmony_ci case -EPROTO: 62662306a36Sopenharmony_ci case -ESHUTDOWN: 62762306a36Sopenharmony_ci return; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci default: 63062306a36Sopenharmony_ci goto resubmit_urb; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* handle Errors */ 63462306a36Sopenharmony_ci if (data->isrc & (F81604_SJA1000_IRQ_DOI | F81604_SJA1000_IRQ_EI | 63562306a36Sopenharmony_ci F81604_SJA1000_IRQ_BEI | F81604_SJA1000_IRQ_EPI | 63662306a36Sopenharmony_ci F81604_SJA1000_IRQ_ALI)) 63762306a36Sopenharmony_ci f81604_handle_can_bus_errors(priv, data); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* handle TX */ 64062306a36Sopenharmony_ci if (priv->can.state != CAN_STATE_BUS_OFF && 64162306a36Sopenharmony_ci (data->isrc & F81604_SJA1000_IRQ_TI)) 64262306a36Sopenharmony_ci f81604_handle_tx(priv, data); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciresubmit_urb: 64562306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_ATOMIC); 64662306a36Sopenharmony_ci if (ret == -ENODEV) 64762306a36Sopenharmony_ci netif_device_detach(netdev); 64862306a36Sopenharmony_ci else if (ret) 64962306a36Sopenharmony_ci netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n", 65062306a36Sopenharmony_ci __func__, ERR_PTR(ret)); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic void f81604_unregister_urbs(struct f81604_port_priv *priv) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci usb_kill_anchored_urbs(&priv->urbs_anchor); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int f81604_register_urbs(struct f81604_port_priv *priv) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 66162306a36Sopenharmony_ci struct f81604_int_data *int_data; 66262306a36Sopenharmony_ci int id = netdev->dev_port; 66362306a36Sopenharmony_ci struct urb *int_urb; 66462306a36Sopenharmony_ci int rx_urb_cnt; 66562306a36Sopenharmony_ci int ret; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci for (rx_urb_cnt = 0; rx_urb_cnt < F81604_MAX_RX_URBS; ++rx_urb_cnt) { 66862306a36Sopenharmony_ci struct f81604_can_frame *frame; 66962306a36Sopenharmony_ci struct urb *rx_urb; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci rx_urb = usb_alloc_urb(0, GFP_KERNEL); 67262306a36Sopenharmony_ci if (!rx_urb) { 67362306a36Sopenharmony_ci ret = -ENOMEM; 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci frame = kmalloc(sizeof(*frame), GFP_KERNEL); 67862306a36Sopenharmony_ci if (!frame) { 67962306a36Sopenharmony_ci usb_free_urb(rx_urb); 68062306a36Sopenharmony_ci ret = -ENOMEM; 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci usb_fill_bulk_urb(rx_urb, priv->dev, 68562306a36Sopenharmony_ci usb_rcvbulkpipe(priv->dev, bulk_in_addr[id]), 68662306a36Sopenharmony_ci frame, sizeof(*frame), 68762306a36Sopenharmony_ci f81604_read_bulk_callback, netdev); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci rx_urb->transfer_flags |= URB_FREE_BUFFER; 69062306a36Sopenharmony_ci usb_anchor_urb(rx_urb, &priv->urbs_anchor); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = usb_submit_urb(rx_urb, GFP_KERNEL); 69362306a36Sopenharmony_ci if (ret) { 69462306a36Sopenharmony_ci usb_unanchor_urb(rx_urb); 69562306a36Sopenharmony_ci usb_free_urb(rx_urb); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Drop reference, USB core will take care of freeing it */ 70062306a36Sopenharmony_ci usb_free_urb(rx_urb); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (rx_urb_cnt == 0) { 70462306a36Sopenharmony_ci netdev_warn(netdev, "%s: submit rx urb failed: %pe\n", 70562306a36Sopenharmony_ci __func__, ERR_PTR(ret)); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci goto error; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci int_urb = usb_alloc_urb(0, GFP_KERNEL); 71162306a36Sopenharmony_ci if (!int_urb) { 71262306a36Sopenharmony_ci ret = -ENOMEM; 71362306a36Sopenharmony_ci goto error; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci int_data = kmalloc(sizeof(*int_data), GFP_KERNEL); 71762306a36Sopenharmony_ci if (!int_data) { 71862306a36Sopenharmony_ci usb_free_urb(int_urb); 71962306a36Sopenharmony_ci ret = -ENOMEM; 72062306a36Sopenharmony_ci goto error; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci usb_fill_int_urb(int_urb, priv->dev, 72462306a36Sopenharmony_ci usb_rcvintpipe(priv->dev, int_in_addr[id]), int_data, 72562306a36Sopenharmony_ci sizeof(*int_data), f81604_read_int_callback, netdev, 72662306a36Sopenharmony_ci 1); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci int_urb->transfer_flags |= URB_FREE_BUFFER; 72962306a36Sopenharmony_ci usb_anchor_urb(int_urb, &priv->urbs_anchor); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci ret = usb_submit_urb(int_urb, GFP_KERNEL); 73262306a36Sopenharmony_ci if (ret) { 73362306a36Sopenharmony_ci usb_unanchor_urb(int_urb); 73462306a36Sopenharmony_ci usb_free_urb(int_urb); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci netdev_warn(netdev, "%s: submit int urb failed: %pe\n", 73762306a36Sopenharmony_ci __func__, ERR_PTR(ret)); 73862306a36Sopenharmony_ci goto error; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Drop reference, USB core will take care of freeing it */ 74262306a36Sopenharmony_ci usb_free_urb(int_urb); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cierror: 74762306a36Sopenharmony_ci f81604_unregister_urbs(priv); 74862306a36Sopenharmony_ci return ret; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic int f81604_start(struct net_device *netdev) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct f81604_port_priv *priv = netdev_priv(netdev); 75462306a36Sopenharmony_ci int ret; 75562306a36Sopenharmony_ci u8 mode; 75662306a36Sopenharmony_ci u8 tmp; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci mode = F81604_RX_AUTO_RELEASE_BUF | F81604_INT_WHEN_CHANGE; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Set TR/AT mode */ 76162306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) 76262306a36Sopenharmony_ci mode |= F81604_TX_ONESHOT; 76362306a36Sopenharmony_ci else 76462306a36Sopenharmony_ci mode |= F81604_TX_NORMAL; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_CTRL_MODE_REG, mode); 76762306a36Sopenharmony_ci if (ret) 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* set reset mode */ 77162306a36Sopenharmony_ci ret = f81604_set_reset_mode(priv); 77262306a36Sopenharmony_ci if (ret) 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci ret = f81604_chipset_init(priv); 77662306a36Sopenharmony_ci if (ret) 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* Clear error counters and error code capture */ 78062306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_TXERR, 0); 78162306a36Sopenharmony_ci if (ret) 78262306a36Sopenharmony_ci return ret; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_RXERR, 0); 78562306a36Sopenharmony_ci if (ret) 78662306a36Sopenharmony_ci return ret; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* Read clear for ECC/ALC/IR register */ 78962306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp); 79062306a36Sopenharmony_ci if (ret) 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp); 79462306a36Sopenharmony_ci if (ret) 79562306a36Sopenharmony_ci return ret; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_IR, &tmp); 79862306a36Sopenharmony_ci if (ret) 79962306a36Sopenharmony_ci return ret; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ret = f81604_register_urbs(priv); 80262306a36Sopenharmony_ci if (ret) 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ret = f81604_set_normal_mode(priv); 80662306a36Sopenharmony_ci if (ret) { 80762306a36Sopenharmony_ci f81604_unregister_urbs(priv); 80862306a36Sopenharmony_ci return ret; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int f81604_set_bittiming(struct net_device *dev) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct f81604_port_priv *priv = netdev_priv(dev); 81762306a36Sopenharmony_ci struct can_bittiming *bt = &priv->can.bittiming; 81862306a36Sopenharmony_ci u8 btr0, btr1; 81962306a36Sopenharmony_ci int ret; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci btr0 = FIELD_PREP(F81604_BRP_MASK, bt->brp - 1) | 82262306a36Sopenharmony_ci FIELD_PREP(F81604_SJW_MASK, bt->sjw - 1); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci btr1 = FIELD_PREP(F81604_SEG1_MASK, 82562306a36Sopenharmony_ci bt->prop_seg + bt->phase_seg1 - 1) | 82662306a36Sopenharmony_ci FIELD_PREP(F81604_SEG2_MASK, bt->phase_seg2 - 1); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) 82962306a36Sopenharmony_ci btr1 |= F81604_SJA1000_BTR1_SAMPLE_TRIPLE; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR0, btr0); 83262306a36Sopenharmony_ci if (ret) { 83362306a36Sopenharmony_ci netdev_warn(dev, "%s: Set BTR0 failed: %pe\n", __func__, 83462306a36Sopenharmony_ci ERR_PTR(ret)); 83562306a36Sopenharmony_ci return ret; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR1, btr1); 83962306a36Sopenharmony_ci if (ret) { 84062306a36Sopenharmony_ci netdev_warn(dev, "%s: Set BTR1 failed: %pe\n", __func__, 84162306a36Sopenharmony_ci ERR_PTR(ret)); 84262306a36Sopenharmony_ci return ret; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return 0; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic int f81604_set_mode(struct net_device *netdev, enum can_mode mode) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci int ret; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci switch (mode) { 85362306a36Sopenharmony_ci case CAN_MODE_START: 85462306a36Sopenharmony_ci ret = f81604_start(netdev); 85562306a36Sopenharmony_ci if (!ret && netif_queue_stopped(netdev)) 85662306a36Sopenharmony_ci netif_wake_queue(netdev); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci default: 86062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic void f81604_write_bulk_callback(struct urb *urb) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct net_device *netdev = urb->context; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (!netif_device_present(netdev)) 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (urb->status) 87462306a36Sopenharmony_ci netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__, 87562306a36Sopenharmony_ci ERR_PTR(urb->status)); 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic void f81604_clear_reg_work(struct work_struct *work) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct f81604_port_priv *priv; 88162306a36Sopenharmony_ci u8 tmp; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci priv = container_of(work, struct f81604_port_priv, clear_reg_work); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* dummy read for clear Arbitration lost capture(ALC) register. */ 88662306a36Sopenharmony_ci if (test_and_clear_bit(F81604_CLEAR_ALC, &priv->clear_flags)) 88762306a36Sopenharmony_ci f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* dummy read for clear Error code capture(ECC) register. */ 89062306a36Sopenharmony_ci if (test_and_clear_bit(F81604_CLEAR_ECC, &priv->clear_flags)) 89162306a36Sopenharmony_ci f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* dummy write for clear data overrun flag. */ 89462306a36Sopenharmony_ci if (test_and_clear_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags)) 89562306a36Sopenharmony_ci f81604_sja1000_write(priv, F81604_SJA1000_CMR, 89662306a36Sopenharmony_ci F81604_SJA1000_CMD_CDO); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic netdev_tx_t f81604_start_xmit(struct sk_buff *skb, 90062306a36Sopenharmony_ci struct net_device *netdev) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct can_frame *cf = (struct can_frame *)skb->data; 90362306a36Sopenharmony_ci struct f81604_port_priv *priv = netdev_priv(netdev); 90462306a36Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 90562306a36Sopenharmony_ci struct f81604_can_frame *frame; 90662306a36Sopenharmony_ci struct urb *write_urb; 90762306a36Sopenharmony_ci int ret; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (can_dev_dropped_skb(netdev, skb)) 91062306a36Sopenharmony_ci return NETDEV_TX_OK; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci netif_stop_queue(netdev); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci write_urb = usb_alloc_urb(0, GFP_ATOMIC); 91562306a36Sopenharmony_ci if (!write_urb) 91662306a36Sopenharmony_ci goto nomem_urb; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci frame = kzalloc(sizeof(*frame), GFP_ATOMIC); 91962306a36Sopenharmony_ci if (!frame) 92062306a36Sopenharmony_ci goto nomem_buf; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci usb_fill_bulk_urb(write_urb, priv->dev, 92362306a36Sopenharmony_ci usb_sndbulkpipe(priv->dev, 92462306a36Sopenharmony_ci bulk_out_addr[netdev->dev_port]), 92562306a36Sopenharmony_ci frame, sizeof(*frame), f81604_write_bulk_callback, 92662306a36Sopenharmony_ci priv->netdev); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci write_urb->transfer_flags |= URB_FREE_BUFFER; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci frame->cmd = F81604_CMD_DATA; 93162306a36Sopenharmony_ci frame->dlc = cf->len; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (cf->can_id & CAN_RTR_FLAG) 93462306a36Sopenharmony_ci frame->dlc |= F81604_DLC_RTR_BIT; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (cf->can_id & CAN_EFF_FLAG) { 93762306a36Sopenharmony_ci u32 id = (cf->can_id & CAN_EFF_MASK) << F81604_EFF_SHIFT; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci put_unaligned_be32(id, &frame->eff.id); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci frame->dlc |= F81604_DLC_EFF_BIT; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (!(cf->can_id & CAN_RTR_FLAG)) 94462306a36Sopenharmony_ci memcpy(&frame->eff.data, cf->data, cf->len); 94562306a36Sopenharmony_ci } else { 94662306a36Sopenharmony_ci u32 id = (cf->can_id & CAN_SFF_MASK) << F81604_SFF_SHIFT; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci put_unaligned_be16(id, &frame->sff.id); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (!(cf->can_id & CAN_RTR_FLAG)) 95162306a36Sopenharmony_ci memcpy(&frame->sff.data, cf->data, cf->len); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci can_put_echo_skb(skb, netdev, 0, 0); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci ret = usb_submit_urb(write_urb, GFP_ATOMIC); 95762306a36Sopenharmony_ci if (ret) { 95862306a36Sopenharmony_ci netdev_err(netdev, "%s: failed to resubmit tx bulk urb: %pe\n", 95962306a36Sopenharmony_ci __func__, ERR_PTR(ret)); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci can_free_echo_skb(netdev, 0, NULL); 96262306a36Sopenharmony_ci stats->tx_dropped++; 96362306a36Sopenharmony_ci stats->tx_errors++; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (ret == -ENODEV) 96662306a36Sopenharmony_ci netif_device_detach(netdev); 96762306a36Sopenharmony_ci else 96862306a36Sopenharmony_ci netif_wake_queue(netdev); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* let usb core take care of this urb */ 97262306a36Sopenharmony_ci usb_free_urb(write_urb); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return NETDEV_TX_OK; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cinomem_buf: 97762306a36Sopenharmony_ci usb_free_urb(write_urb); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cinomem_urb: 98062306a36Sopenharmony_ci dev_kfree_skb(skb); 98162306a36Sopenharmony_ci stats->tx_dropped++; 98262306a36Sopenharmony_ci stats->tx_errors++; 98362306a36Sopenharmony_ci netif_wake_queue(netdev); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return NETDEV_TX_OK; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic int f81604_get_berr_counter(const struct net_device *netdev, 98962306a36Sopenharmony_ci struct can_berr_counter *bec) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct f81604_port_priv *priv = netdev_priv(netdev); 99262306a36Sopenharmony_ci u8 txerr, rxerr; 99362306a36Sopenharmony_ci int ret; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_TXERR, &txerr); 99662306a36Sopenharmony_ci if (ret) 99762306a36Sopenharmony_ci return ret; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci ret = f81604_sja1000_read(priv, F81604_SJA1000_RXERR, &rxerr); 100062306a36Sopenharmony_ci if (ret) 100162306a36Sopenharmony_ci return ret; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci bec->txerr = txerr; 100462306a36Sopenharmony_ci bec->rxerr = rxerr; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci return 0; 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci/* Open USB device */ 101062306a36Sopenharmony_cistatic int f81604_open(struct net_device *netdev) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci int ret; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ret = open_candev(netdev); 101562306a36Sopenharmony_ci if (ret) 101662306a36Sopenharmony_ci return ret; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ret = f81604_start(netdev); 101962306a36Sopenharmony_ci if (ret) { 102062306a36Sopenharmony_ci if (ret == -ENODEV) 102162306a36Sopenharmony_ci netif_device_detach(netdev); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci close_candev(netdev); 102462306a36Sopenharmony_ci return ret; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci netif_start_queue(netdev); 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/* Close USB device */ 103262306a36Sopenharmony_cistatic int f81604_close(struct net_device *netdev) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct f81604_port_priv *priv = netdev_priv(netdev); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci f81604_set_reset_mode(priv); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci netif_stop_queue(netdev); 103962306a36Sopenharmony_ci cancel_work_sync(&priv->clear_reg_work); 104062306a36Sopenharmony_ci close_candev(netdev); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci f81604_unregister_urbs(priv); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci return 0; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic const struct net_device_ops f81604_netdev_ops = { 104862306a36Sopenharmony_ci .ndo_open = f81604_open, 104962306a36Sopenharmony_ci .ndo_stop = f81604_close, 105062306a36Sopenharmony_ci .ndo_start_xmit = f81604_start_xmit, 105162306a36Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 105262306a36Sopenharmony_ci}; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic const struct can_bittiming_const f81604_bittiming_const = { 105562306a36Sopenharmony_ci .name = KBUILD_MODNAME, 105662306a36Sopenharmony_ci .tseg1_min = 1, 105762306a36Sopenharmony_ci .tseg1_max = 16, 105862306a36Sopenharmony_ci .tseg2_min = 1, 105962306a36Sopenharmony_ci .tseg2_max = 8, 106062306a36Sopenharmony_ci .sjw_max = 4, 106162306a36Sopenharmony_ci .brp_min = 1, 106262306a36Sopenharmony_ci .brp_max = 64, 106362306a36Sopenharmony_ci .brp_inc = 1, 106462306a36Sopenharmony_ci}; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci/* Called by the usb core when driver is unloaded or device is removed */ 106762306a36Sopenharmony_cistatic void f81604_disconnect(struct usb_interface *intf) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct f81604_priv *priv = usb_get_intfdata(intf); 107062306a36Sopenharmony_ci int i; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { 107362306a36Sopenharmony_ci if (!priv->netdev[i]) 107462306a36Sopenharmony_ci continue; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci unregister_netdev(priv->netdev[i]); 107762306a36Sopenharmony_ci free_candev(priv->netdev[i]); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int __f81604_set_termination(struct usb_device *dev, int idx, u16 term) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci u8 mask, data = 0; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (idx == 0) 108662306a36Sopenharmony_ci mask = F81604_CAN0_TERM; 108762306a36Sopenharmony_ci else 108862306a36Sopenharmony_ci mask = F81604_CAN1_TERM; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (term) 109162306a36Sopenharmony_ci data = mask; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return f81604_update_bits(dev, F81604_TERMINATOR_REG, mask, data); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int f81604_set_termination(struct net_device *netdev, u16 term) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct f81604_port_priv *port_priv = netdev_priv(netdev); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci ASSERT_RTNL(); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return __f81604_set_termination(port_priv->dev, netdev->dev_port, 110362306a36Sopenharmony_ci term); 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic int f81604_probe(struct usb_interface *intf, 110762306a36Sopenharmony_ci const struct usb_device_id *id) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 111062306a36Sopenharmony_ci struct net_device *netdev; 111162306a36Sopenharmony_ci struct f81604_priv *priv; 111262306a36Sopenharmony_ci int i, ret; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL); 111562306a36Sopenharmony_ci if (!priv) 111662306a36Sopenharmony_ci return -ENOMEM; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci usb_set_intfdata(intf, priv); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { 112162306a36Sopenharmony_ci ret = __f81604_set_termination(dev, i, 0); 112262306a36Sopenharmony_ci if (ret) { 112362306a36Sopenharmony_ci dev_err(&intf->dev, 112462306a36Sopenharmony_ci "Setting termination of CH#%d failed: %pe\n", 112562306a36Sopenharmony_ci i, ERR_PTR(ret)); 112662306a36Sopenharmony_ci return ret; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { 113162306a36Sopenharmony_ci struct f81604_port_priv *port_priv; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci netdev = alloc_candev(sizeof(*port_priv), 1); 113462306a36Sopenharmony_ci if (!netdev) { 113562306a36Sopenharmony_ci dev_err(&intf->dev, "Couldn't alloc candev: %d\n", i); 113662306a36Sopenharmony_ci ret = -ENOMEM; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci goto failure_cleanup; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci port_priv = netdev_priv(netdev); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci INIT_WORK(&port_priv->clear_reg_work, f81604_clear_reg_work); 114462306a36Sopenharmony_ci init_usb_anchor(&port_priv->urbs_anchor); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci port_priv->intf = intf; 114762306a36Sopenharmony_ci port_priv->dev = dev; 114862306a36Sopenharmony_ci port_priv->netdev = netdev; 114962306a36Sopenharmony_ci port_priv->can.clock.freq = F81604_CAN_CLOCK; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci port_priv->can.termination_const = f81604_termination; 115262306a36Sopenharmony_ci port_priv->can.termination_const_cnt = 115362306a36Sopenharmony_ci ARRAY_SIZE(f81604_termination); 115462306a36Sopenharmony_ci port_priv->can.bittiming_const = &f81604_bittiming_const; 115562306a36Sopenharmony_ci port_priv->can.do_set_bittiming = f81604_set_bittiming; 115662306a36Sopenharmony_ci port_priv->can.do_set_mode = f81604_set_mode; 115762306a36Sopenharmony_ci port_priv->can.do_set_termination = f81604_set_termination; 115862306a36Sopenharmony_ci port_priv->can.do_get_berr_counter = f81604_get_berr_counter; 115962306a36Sopenharmony_ci port_priv->can.ctrlmode_supported = 116062306a36Sopenharmony_ci CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | 116162306a36Sopenharmony_ci CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_BERR_REPORTING | 116262306a36Sopenharmony_ci CAN_CTRLMODE_PRESUME_ACK; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci netdev->ethtool_ops = &f81604_ethtool_ops; 116562306a36Sopenharmony_ci netdev->netdev_ops = &f81604_netdev_ops; 116662306a36Sopenharmony_ci netdev->flags |= IFF_ECHO; 116762306a36Sopenharmony_ci netdev->dev_port = i; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &intf->dev); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci ret = register_candev(netdev); 117262306a36Sopenharmony_ci if (ret) { 117362306a36Sopenharmony_ci netdev_err(netdev, "register CAN device failed: %pe\n", 117462306a36Sopenharmony_ci ERR_PTR(ret)); 117562306a36Sopenharmony_ci free_candev(netdev); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci goto failure_cleanup; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci priv->netdev[i] = netdev; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cifailure_cleanup: 118662306a36Sopenharmony_ci f81604_disconnect(intf); 118762306a36Sopenharmony_ci return ret; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic struct usb_driver f81604_driver = { 119162306a36Sopenharmony_ci .name = KBUILD_MODNAME, 119262306a36Sopenharmony_ci .probe = f81604_probe, 119362306a36Sopenharmony_ci .disconnect = f81604_disconnect, 119462306a36Sopenharmony_ci .id_table = f81604_table, 119562306a36Sopenharmony_ci}; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cimodule_usb_driver(f81604_driver); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ciMODULE_AUTHOR("Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>"); 120062306a36Sopenharmony_ciMODULE_DESCRIPTION("Fintek F81604 USB to 2xCANBUS"); 120162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1202