xref: /kernel/linux/linux-6.6/drivers/net/can/usb/f81604.c (revision 62306a36)
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