Commit 833e24ae authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-6.5-20230515' of...

Merge tag 'linux-can-next-for-6.5-20230515' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2023-05-15

The 1st patch is by Ji-Ze Hong and adds support for the Fintek F81604
USB-CAN adapter.

Jiapeng Chong's patch removes unnecessary dev_err() functions from the
bxcan driver.

The next patch is by me an makes a CAN internal header file self
contained.

The remaining 19 patches are by Uwe Kleine-König, they all convert the
platform driver remove callback to return void.

* tag 'linux-can-next-for-6.5-20230515' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: (22 commits)
  can: xilinx: Convert to platform remove callback returning void
  can: ti_hecc: Convert to platform remove callback returning void
  can: sun4i_can: Convert to platform remove callback returning void
  can: softing: Convert to platform remove callback returning void
  can: sja1000_platform: Convert to platform remove callback returning void
  can: sja1000_isa: Convert to platform remove callback returning void
  can: rcar: Convert to platform remove callback returning void
  can: mscan: mpc5xxx_can: Convert to platform remove callback returning void
  can: m_can: Convert to platform remove callback returning void
  can: janz-ican3: Convert to platform remove callback returning void
  can: ifi_canfd: Convert to platform remove callback returning void
  can: grcan: Convert to platform remove callback returning void
  can: flexcan: Convert to platform remove callback returning void
  can: ctucanfd: Convert to platform remove callback returning void
  can: length: make header self contained
  can: cc770_platform: Convert to platform remove callback returning void
  can: bxcan: Remove unnecessary print function dev_err()
  can: cc770_isa: Convert to platform remove callback returning void
  can: usb: f81604: add Fintek F81604 support
  can: c_can: Convert to platform remove callback returning void
  ...
====================

Link: https://lore.kernel.org/r/20230515205759.1003118-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e7480a44 2a3e1636
......@@ -7966,6 +7966,12 @@ S: Maintained
F: drivers/hwmon/f75375s.c
F: include/linux/f75375s.h
FINTEK F81604 USB to 2xCANBUS DEVICE DRIVER
M: Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>
L: linux-can@vger.kernel.org
S: Maintained
F: drivers/net/can/usb/f81604.c
FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE
M: Clemens Ladisch <clemens@ladisch.de>
M: Takashi Sakamoto <o-takashi@sakamocchi.jp>
......
......@@ -1346,7 +1346,7 @@ static int at91_can_probe(struct platform_device *pdev)
return err;
}
static int at91_can_remove(struct platform_device *pdev)
static void at91_can_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct at91_priv *priv = netdev_priv(dev);
......@@ -1362,8 +1362,6 @@ static int at91_can_remove(struct platform_device *pdev)
clk_put(priv->clk);
free_candev(dev);
return 0;
}
static const struct platform_device_id at91_can_id_table[] = {
......@@ -1381,7 +1379,7 @@ MODULE_DEVICE_TABLE(platform, at91_can_id_table);
static struct platform_driver at91_can_driver = {
.probe = at91_can_probe,
.remove = at91_can_remove,
.remove_new = at91_can_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(at91_can_dt_ids),
......
......@@ -954,22 +954,16 @@ static int bxcan_probe(struct platform_device *pdev)
}
rx_irq = platform_get_irq_byname(pdev, "rx0");
if (rx_irq < 0) {
dev_err(dev, "failed to get rx0 irq\n");
if (rx_irq < 0)
return rx_irq;
}
tx_irq = platform_get_irq_byname(pdev, "tx");
if (tx_irq < 0) {
dev_err(dev, "failed to get tx irq\n");
if (tx_irq < 0)
return tx_irq;
}
sce_irq = platform_get_irq_byname(pdev, "sce");
if (sce_irq < 0) {
dev_err(dev, "failed to get sce irq\n");
if (sce_irq < 0)
return sce_irq;
}
ndev = alloc_candev(sizeof(struct bxcan_priv), BXCAN_TX_MB_NUM);
if (!ndev) {
......@@ -1027,7 +1021,7 @@ static int bxcan_probe(struct platform_device *pdev)
return err;
}
static int bxcan_remove(struct platform_device *pdev)
static void bxcan_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct bxcan_priv *priv = netdev_priv(ndev);
......@@ -1036,7 +1030,6 @@ static int bxcan_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->clk);
can_rx_offload_del(&priv->offload);
free_candev(ndev);
return 0;
}
static int __maybe_unused bxcan_suspend(struct device *dev)
......@@ -1088,7 +1081,7 @@ static struct platform_driver bxcan_driver = {
.of_match_table = bxcan_of_match,
},
.probe = bxcan_probe,
.remove = bxcan_remove,
.remove_new = bxcan_remove,
};
module_platform_driver(bxcan_driver);
......
......@@ -410,7 +410,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
return ret;
}
static int c_can_plat_remove(struct platform_device *pdev)
static void c_can_plat_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct c_can_priv *priv = netdev_priv(dev);
......@@ -418,8 +418,6 @@ static int c_can_plat_remove(struct platform_device *pdev)
unregister_c_can_dev(dev);
pm_runtime_disable(priv->device);
free_c_can_dev(dev);
return 0;
}
#ifdef CONFIG_PM
......@@ -487,7 +485,7 @@ static struct platform_driver c_can_plat_driver = {
.of_match_table = c_can_of_table,
},
.probe = c_can_plat_probe,
.remove = c_can_plat_remove,
.remove_new = c_can_plat_remove,
.suspend = c_can_suspend,
.resume = c_can_resume,
.id_table = c_can_id_table,
......
......@@ -285,7 +285,7 @@ static int cc770_isa_probe(struct platform_device *pdev)
return err;
}
static int cc770_isa_remove(struct platform_device *pdev)
static void cc770_isa_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
......@@ -303,13 +303,11 @@ static int cc770_isa_remove(struct platform_device *pdev)
release_region(port[idx], CC770_IOSIZE);
}
free_cc770dev(dev);
return 0;
}
static struct platform_driver cc770_isa_driver = {
.probe = cc770_isa_probe,
.remove = cc770_isa_remove,
.remove_new = cc770_isa_remove,
.driver = {
.name = KBUILD_MODNAME,
},
......
......@@ -230,7 +230,7 @@ static int cc770_platform_probe(struct platform_device *pdev)
return err;
}
static int cc770_platform_remove(struct platform_device *pdev)
static void cc770_platform_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
......@@ -242,8 +242,6 @@ static int cc770_platform_remove(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, resource_size(mem));
return 0;
}
static const struct of_device_id cc770_platform_table[] = {
......@@ -259,7 +257,7 @@ static struct platform_driver cc770_platform_driver = {
.of_match_table = cc770_platform_table,
},
.probe = cc770_platform_probe,
.remove = cc770_platform_remove,
.remove_new = cc770_platform_remove,
};
module_platform_driver(cc770_platform_driver);
......@@ -86,7 +86,7 @@ static int ctucan_platform_probe(struct platform_device *pdev)
* This function frees all the resources allocated to the device.
* Return: 0 always
*/
static int ctucan_platform_remove(struct platform_device *pdev)
static void ctucan_platform_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ctucan_priv *priv = netdev_priv(ndev);
......@@ -97,8 +97,6 @@ static int ctucan_platform_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
......@@ -113,7 +111,7 @@ MODULE_DEVICE_TABLE(of, ctucan_of_match);
static struct platform_driver ctucanfd_driver = {
.probe = ctucan_platform_probe,
.remove = ctucan_platform_remove,
.remove_new = ctucan_platform_remove,
.driver = {
.name = DRV_NAME,
.pm = &ctucan_platform_pm_ops,
......
......@@ -2218,7 +2218,7 @@ static int flexcan_probe(struct platform_device *pdev)
return err;
}
static int flexcan_remove(struct platform_device *pdev)
static void flexcan_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
......@@ -2227,8 +2227,6 @@ static int flexcan_remove(struct platform_device *pdev)
unregister_flexcandev(dev);
pm_runtime_disable(&pdev->dev);
free_candev(dev);
return 0;
}
static int __maybe_unused flexcan_suspend(struct device *device)
......@@ -2379,7 +2377,7 @@ static struct platform_driver flexcan_driver = {
.of_match_table = flexcan_of_match,
},
.probe = flexcan_probe,
.remove = flexcan_remove,
.remove_new = flexcan_remove,
.id_table = flexcan_id_table,
};
......
......@@ -1696,7 +1696,7 @@ static int grcan_probe(struct platform_device *ofdev)
return err;
}
static int grcan_remove(struct platform_device *ofdev)
static void grcan_remove(struct platform_device *ofdev)
{
struct net_device *dev = platform_get_drvdata(ofdev);
struct grcan_priv *priv = netdev_priv(dev);
......@@ -1706,8 +1706,6 @@ static int grcan_remove(struct platform_device *ofdev)
irq_dispose_mapping(dev->irq);
netif_napi_del(&priv->napi);
free_candev(dev);
return 0;
}
static const struct of_device_id grcan_match[] = {
......@@ -1726,7 +1724,7 @@ static struct platform_driver grcan_driver = {
.of_match_table = grcan_match,
},
.probe = grcan_probe,
.remove = grcan_remove,
.remove_new = grcan_remove,
};
module_platform_driver(grcan_driver);
......
......@@ -1013,15 +1013,13 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
return ret;
}
static int ifi_canfd_plat_remove(struct platform_device *pdev)
static void ifi_canfd_plat_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
unregister_candev(ndev);
platform_set_drvdata(pdev, NULL);
free_candev(ndev);
return 0;
}
static const struct of_device_id ifi_canfd_of_table[] = {
......@@ -1036,7 +1034,7 @@ static struct platform_driver ifi_canfd_plat_driver = {
.of_match_table = ifi_canfd_of_table,
},
.probe = ifi_canfd_plat_probe,
.remove = ifi_canfd_plat_remove,
.remove_new = ifi_canfd_plat_remove,
};
module_platform_driver(ifi_canfd_plat_driver);
......
......@@ -2023,7 +2023,7 @@ static int ican3_probe(struct platform_device *pdev)
return ret;
}
static int ican3_remove(struct platform_device *pdev)
static void ican3_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ican3_dev *mod = netdev_priv(ndev);
......@@ -2042,8 +2042,6 @@ static int ican3_remove(struct platform_device *pdev)
iounmap(mod->dpm);
free_candev(ndev);
return 0;
}
static struct platform_driver ican3_driver = {
......@@ -2051,7 +2049,7 @@ static struct platform_driver ican3_driver = {
.name = DRV_NAME,
},
.probe = ican3_probe,
.remove = ican3_remove,
.remove_new = ican3_remove,
};
module_platform_driver(ican3_driver);
......
......@@ -164,7 +164,7 @@ static __maybe_unused int m_can_resume(struct device *dev)
return m_can_class_resume(dev);
}
static int m_can_plat_remove(struct platform_device *pdev)
static void m_can_plat_remove(struct platform_device *pdev)
{
struct m_can_plat_priv *priv = platform_get_drvdata(pdev);
struct m_can_classdev *mcan_class = &priv->cdev;
......@@ -172,8 +172,6 @@ static int m_can_plat_remove(struct platform_device *pdev)
m_can_class_unregister(mcan_class);
m_can_class_free_dev(mcan_class->net);
return 0;
}
static int __maybe_unused m_can_runtime_suspend(struct device *dev)
......@@ -223,7 +221,7 @@ static struct platform_driver m_can_plat_driver = {
.pm = &m_can_pmops,
},
.probe = m_can_plat_probe,
.remove = m_can_plat_remove,
.remove_new = m_can_plat_remove,
};
module_platform_driver(m_can_plat_driver);
......
......@@ -349,7 +349,7 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
return err;
}
static int mpc5xxx_can_remove(struct platform_device *ofdev)
static void mpc5xxx_can_remove(struct platform_device *ofdev)
{
const struct of_device_id *match;
const struct mpc5xxx_can_data *data;
......@@ -365,8 +365,6 @@ static int mpc5xxx_can_remove(struct platform_device *ofdev)
iounmap(priv->reg_base);
irq_dispose_mapping(dev->irq);
free_candev(dev);
return 0;
}
#ifdef CONFIG_PM
......@@ -437,7 +435,7 @@ static struct platform_driver mpc5xxx_can_driver = {
.of_match_table = mpc5xxx_can_table,
},
.probe = mpc5xxx_can_probe,
.remove = mpc5xxx_can_remove,
.remove_new = mpc5xxx_can_remove,
#ifdef CONFIG_PM
.suspend = mpc5xxx_can_suspend,
.resume = mpc5xxx_can_resume,
......
......@@ -824,7 +824,7 @@ static int rcar_can_probe(struct platform_device *pdev)
return err;
}
static int rcar_can_remove(struct platform_device *pdev)
static void rcar_can_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct rcar_can_priv *priv = netdev_priv(ndev);
......@@ -832,7 +832,6 @@ static int rcar_can_remove(struct platform_device *pdev)
unregister_candev(ndev);
netif_napi_del(&priv->napi);
free_candev(ndev);
return 0;
}
static int __maybe_unused rcar_can_suspend(struct device *dev)
......@@ -908,7 +907,7 @@ static struct platform_driver rcar_can_driver = {
.pm = &rcar_can_pm_ops,
},
.probe = rcar_can_probe,
.remove = rcar_can_remove,
.remove_new = rcar_can_remove,
};
module_platform_driver(rcar_can_driver);
......
......@@ -2078,7 +2078,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
return err;
}
static int rcar_canfd_remove(struct platform_device *pdev)
static void rcar_canfd_remove(struct platform_device *pdev)
{
struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev);
u32 ch;
......@@ -2096,8 +2096,6 @@ static int rcar_canfd_remove(struct platform_device *pdev)
clk_disable_unprepare(gpriv->clkp);
reset_control_assert(gpriv->rstc1);
reset_control_assert(gpriv->rstc2);
return 0;
}
static int __maybe_unused rcar_canfd_suspend(struct device *dev)
......@@ -2130,7 +2128,7 @@ static struct platform_driver rcar_canfd_driver = {
.pm = &rcar_canfd_pm_ops,
},
.probe = rcar_canfd_probe,
.remove = rcar_canfd_remove,
.remove_new = rcar_canfd_remove,
};
module_platform_driver(rcar_canfd_driver);
......
......@@ -223,7 +223,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
return err;
}
static int sja1000_isa_remove(struct platform_device *pdev)
static void sja1000_isa_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
......@@ -241,13 +241,11 @@ static int sja1000_isa_remove(struct platform_device *pdev)
release_region(port[idx], SJA1000_IOSIZE);
}
free_sja1000dev(dev);
return 0;
}
static struct platform_driver sja1000_isa_driver = {
.probe = sja1000_isa_probe,
.remove = sja1000_isa_remove,
.remove_new = sja1000_isa_remove,
.driver = {
.name = DRV_NAME,
},
......
......@@ -317,19 +317,17 @@ static int sp_probe(struct platform_device *pdev)
return err;
}
static int sp_remove(struct platform_device *pdev)
static void sp_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_sja1000dev(dev);
free_sja1000dev(dev);
return 0;
}
static struct platform_driver sp_driver = {
.probe = sp_probe,
.remove = sp_remove,
.remove_new = sp_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = sp_of_table,
......
......@@ -729,7 +729,7 @@ static const struct attribute_group softing_pdev_group = {
/*
* platform driver
*/
static int softing_pdev_remove(struct platform_device *pdev)
static void softing_pdev_remove(struct platform_device *pdev)
{
struct softing *card = platform_get_drvdata(pdev);
int j;
......@@ -747,7 +747,6 @@ static int softing_pdev_remove(struct platform_device *pdev)
iounmap(card->dpram);
kfree(card);
return 0;
}
static int softing_pdev_probe(struct platform_device *pdev)
......@@ -855,7 +854,7 @@ static struct platform_driver softing_driver = {
.name = KBUILD_MODNAME,
},
.probe = softing_pdev_probe,
.remove = softing_pdev_remove,
.remove_new = softing_pdev_remove,
};
module_platform_driver(softing_driver);
......
......@@ -791,14 +791,12 @@ static const struct of_device_id sun4ican_of_match[] = {
MODULE_DEVICE_TABLE(of, sun4ican_of_match);
static int sun4ican_remove(struct platform_device *pdev)
static void sun4ican_remove(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
unregister_netdev(dev);
free_candev(dev);
return 0;
}
static int sun4ican_probe(struct platform_device *pdev)
......@@ -901,7 +899,7 @@ static struct platform_driver sun4i_can_driver = {
.of_match_table = sun4ican_of_match,
},
.probe = sun4ican_probe,
.remove = sun4ican_remove,
.remove_new = sun4ican_remove,
};
module_platform_driver(sun4i_can_driver);
......
......@@ -963,7 +963,7 @@ static int ti_hecc_probe(struct platform_device *pdev)
return err;
}
static int ti_hecc_remove(struct platform_device *pdev)
static void ti_hecc_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct ti_hecc_priv *priv = netdev_priv(ndev);
......@@ -973,8 +973,6 @@ static int ti_hecc_remove(struct platform_device *pdev)
clk_put(priv->clk);
can_rx_offload_del(&priv->offload);
free_candev(ndev);
return 0;
}
#ifdef CONFIG_PM
......@@ -1028,7 +1026,7 @@ static struct platform_driver ti_hecc_driver = {
.of_match_table = ti_hecc_dt_ids,
},
.probe = ti_hecc_probe,
.remove = ti_hecc_remove,
.remove_new = ti_hecc_remove,
.suspend = ti_hecc_suspend,
.resume = ti_hecc_resume,
};
......
......@@ -38,6 +38,18 @@ config CAN_ETAS_ES58X
To compile this driver as a module, choose M here: the module
will be called etas_es58x.
config CAN_F81604
tristate "Fintek F81604 USB to 2CAN interface"
help
This driver supports the Fintek F81604 USB to 2CAN interface.
The device can support CAN2.0A/B protocol and also support
2 output pins to control external terminator (optional).
To compile this driver as a module, choose M here: the module will
be called f81604.
(see also https://www.fintek.com.tw).
config CAN_GS_USB
tristate "Geschwister Schneider UG and candleLight compatible interfaces"
help
......
......@@ -7,6 +7,7 @@ obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB) += esd_usb.o
obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/
obj-$(CONFIG_CAN_F81604) += f81604.o
obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o
......
// SPDX-License-Identifier: GPL-2.0
/* Fintek F81604 USB-to-2CAN controller driver.
*
* Copyright (C) 2023 Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>
*/
#include <linux/bitfield.h>
#include <linux/netdevice.h>
#include <linux/units.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/platform/sja1000.h>
#include <asm-generic/unaligned.h>
/* vendor and product id */
#define F81604_VENDOR_ID 0x2c42
#define F81604_PRODUCT_ID 0x1709
#define F81604_CAN_CLOCK (12 * MEGA)
#define F81604_MAX_DEV 2
#define F81604_SET_DEVICE_RETRY 10
#define F81604_USB_TIMEOUT 2000
#define F81604_SET_GET_REGISTER 0xA0
#define F81604_PORT_OFFSET 0x1000
#define F81604_MAX_RX_URBS 4
#define F81604_CMD_DATA 0x00
#define F81604_DLC_LEN_MASK GENMASK(3, 0)
#define F81604_DLC_EFF_BIT BIT(7)
#define F81604_DLC_RTR_BIT BIT(6)
#define F81604_SFF_SHIFT 5
#define F81604_EFF_SHIFT 3
#define F81604_BRP_MASK GENMASK(5, 0)
#define F81604_SJW_MASK GENMASK(7, 6)
#define F81604_SEG1_MASK GENMASK(3, 0)
#define F81604_SEG2_MASK GENMASK(6, 4)
#define F81604_CLEAR_ALC 0
#define F81604_CLEAR_ECC 1
#define F81604_CLEAR_OVERRUN 2
/* device setting */
#define F81604_CTRL_MODE_REG 0x80
#define F81604_TX_ONESHOT (0x03 << 3)
#define F81604_TX_NORMAL (0x01 << 3)
#define F81604_RX_AUTO_RELEASE_BUF BIT(1)
#define F81604_INT_WHEN_CHANGE BIT(0)
#define F81604_TERMINATOR_REG 0x105
#define F81604_CAN0_TERM BIT(2)
#define F81604_CAN1_TERM BIT(3)
#define F81604_TERMINATION_DISABLED CAN_TERMINATION_DISABLED
#define F81604_TERMINATION_ENABLED 120
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
#define F81604_SJA1000_MOD 0x00
#define F81604_SJA1000_CMR 0x01
#define F81604_SJA1000_IR 0x03
#define F81604_SJA1000_IER 0x04
#define F81604_SJA1000_ALC 0x0B
#define F81604_SJA1000_ECC 0x0C
#define F81604_SJA1000_RXERR 0x0E
#define F81604_SJA1000_TXERR 0x0F
#define F81604_SJA1000_ACCC0 0x10
#define F81604_SJA1000_ACCM0 0x14
#define F81604_MAX_FILTER_CNT 4
/* Common registers - manual section 6.5 */
#define F81604_SJA1000_BTR0 0x06
#define F81604_SJA1000_BTR1 0x07
#define F81604_SJA1000_BTR1_SAMPLE_TRIPLE BIT(7)
#define F81604_SJA1000_OCR 0x08
#define F81604_SJA1000_CDR 0x1F
/* mode register */
#define F81604_SJA1000_MOD_RM 0x01
#define F81604_SJA1000_MOD_LOM 0x02
#define F81604_SJA1000_MOD_STM 0x04
/* commands */
#define F81604_SJA1000_CMD_CDO 0x08
/* interrupt sources */
#define F81604_SJA1000_IRQ_BEI 0x80
#define F81604_SJA1000_IRQ_ALI 0x40
#define F81604_SJA1000_IRQ_EPI 0x20
#define F81604_SJA1000_IRQ_DOI 0x08
#define F81604_SJA1000_IRQ_EI 0x04
#define F81604_SJA1000_IRQ_TI 0x02
#define F81604_SJA1000_IRQ_RI 0x01
#define F81604_SJA1000_IRQ_ALL 0xFF
#define F81604_SJA1000_IRQ_OFF 0x00
/* status register content */
#define F81604_SJA1000_SR_BS 0x80
#define F81604_SJA1000_SR_ES 0x40
#define F81604_SJA1000_SR_TCS 0x08
/* ECC register */
#define F81604_SJA1000_ECC_SEG 0x1F
#define F81604_SJA1000_ECC_DIR 0x20
#define F81604_SJA1000_ECC_BIT 0x00
#define F81604_SJA1000_ECC_FORM 0x40
#define F81604_SJA1000_ECC_STUFF 0x80
#define F81604_SJA1000_ECC_MASK 0xc0
/* ALC register */
#define F81604_SJA1000_ALC_MASK 0x1f
/* table of devices that work with this driver */
static const struct usb_device_id f81604_table[] = {
{ USB_DEVICE(F81604_VENDOR_ID, F81604_PRODUCT_ID) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, f81604_table);
static const struct ethtool_ops f81604_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
static const u16 f81604_termination[] = { F81604_TERMINATION_DISABLED,
F81604_TERMINATION_ENABLED };
struct f81604_priv {
struct net_device *netdev[F81604_MAX_DEV];
};
struct f81604_port_priv {
struct can_priv can;
struct net_device *netdev;
struct sk_buff *echo_skb;
unsigned long clear_flags;
struct work_struct clear_reg_work;
struct usb_device *dev;
struct usb_interface *intf;
struct usb_anchor urbs_anchor;
};
/* Interrupt endpoint data format:
* Byte 0: Status register.
* Byte 1: Interrupt register.
* Byte 2: Interrupt enable register.
* Byte 3: Arbitration lost capture(ALC) register.
* Byte 4: Error code capture(ECC) register.
* Byte 5: Error warning limit register.
* Byte 6: RX error counter register.
* Byte 7: TX error counter register.
* Byte 8: Reserved.
*/
struct f81604_int_data {
u8 sr;
u8 isrc;
u8 ier;
u8 alc;
u8 ecc;
u8 ewlr;
u8 rxerr;
u8 txerr;
u8 val;
} __packed __aligned(4);
struct f81604_sff {
__be16 id;
u8 data[CAN_MAX_DLEN];
} __packed __aligned(2);
struct f81604_eff {
__be32 id;
u8 data[CAN_MAX_DLEN];
} __packed __aligned(2);
struct f81604_can_frame {
u8 cmd;
/* According for F81604 DLC define:
* bit 3~0: data length (0~8)
* bit6: is RTR flag.
* bit7: is EFF frame.
*/
u8 dlc;
union {
struct f81604_sff sff;
struct f81604_eff eff;
};
} __packed __aligned(2);
static const u8 bulk_in_addr[F81604_MAX_DEV] = { 2, 4 };
static const u8 bulk_out_addr[F81604_MAX_DEV] = { 1, 3 };
static const u8 int_in_addr[F81604_MAX_DEV] = { 1, 3 };
static int f81604_write(struct usb_device *dev, u16 reg, u8 data)
{
int ret;
ret = usb_control_msg_send(dev, 0, F81604_SET_GET_REGISTER,
USB_TYPE_VENDOR | USB_DIR_OUT, 0, reg,
&data, sizeof(data), F81604_USB_TIMEOUT,
GFP_KERNEL);
if (ret)
dev_err(&dev->dev, "%s: reg: %x data: %x failed: %pe\n",
__func__, reg, data, ERR_PTR(ret));
return ret;
}
static int f81604_read(struct usb_device *dev, u16 reg, u8 *data)
{
int ret;
ret = usb_control_msg_recv(dev, 0, F81604_SET_GET_REGISTER,
USB_TYPE_VENDOR | USB_DIR_IN, 0, reg, data,
sizeof(*data), F81604_USB_TIMEOUT,
GFP_KERNEL);
if (ret < 0)
dev_err(&dev->dev, "%s: reg: %x failed: %pe\n", __func__, reg,
ERR_PTR(ret));
return ret;
}
static int f81604_update_bits(struct usb_device *dev, u16 reg, u8 mask,
u8 data)
{
int ret;
u8 tmp;
ret = f81604_read(dev, reg, &tmp);
if (ret)
return ret;
tmp &= ~mask;
tmp |= (mask & data);
return f81604_write(dev, reg, tmp);
}
static int f81604_sja1000_write(struct f81604_port_priv *priv, u16 reg,
u8 data)
{
int port = priv->netdev->dev_port;
int real_reg;
real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET;
return f81604_write(priv->dev, real_reg, data);
}
static int f81604_sja1000_read(struct f81604_port_priv *priv, u16 reg,
u8 *data)
{
int port = priv->netdev->dev_port;
int real_reg;
real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET;
return f81604_read(priv->dev, real_reg, data);
}
static int f81604_set_reset_mode(struct f81604_port_priv *priv)
{
int ret, i;
u8 tmp;
/* disable interrupts */
ret = f81604_sja1000_write(priv, F81604_SJA1000_IER,
F81604_SJA1000_IRQ_OFF);
if (ret)
return ret;
for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) {
ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp);
if (ret)
return ret;
/* check reset bit */
if (tmp & F81604_SJA1000_MOD_RM) {
priv->can.state = CAN_STATE_STOPPED;
return 0;
}
/* reset chip */
ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD,
F81604_SJA1000_MOD_RM);
if (ret)
return ret;
}
return -EPERM;
}
static int f81604_set_normal_mode(struct f81604_port_priv *priv)
{
u8 tmp, ier = 0;
u8 mod_reg = 0;
int ret, i;
for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) {
ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp);
if (ret)
return ret;
/* check reset bit */
if ((tmp & F81604_SJA1000_MOD_RM) == 0) {
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts, RI handled by bulk-in */
ier = F81604_SJA1000_IRQ_ALL & ~F81604_SJA1000_IRQ_RI;
if (!(priv->can.ctrlmode &
CAN_CTRLMODE_BERR_REPORTING))
ier &= ~F81604_SJA1000_IRQ_BEI;
return f81604_sja1000_write(priv, F81604_SJA1000_IER,
ier);
}
/* set chip to normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
mod_reg |= F81604_SJA1000_MOD_LOM;
if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
mod_reg |= F81604_SJA1000_MOD_STM;
ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD, mod_reg);
if (ret)
return ret;
}
return -EPERM;
}
static int f81604_chipset_init(struct f81604_port_priv *priv)
{
int i, ret;
/* set clock divider and output control register */
ret = f81604_sja1000_write(priv, F81604_SJA1000_CDR,
CDR_CBP | CDR_PELICAN);
if (ret)
return ret;
/* set acceptance filter (accept all) */
for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) {
ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCC0 + i, 0);
if (ret)
return ret;
}
for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) {
ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCM0 + i,
0xFF);
if (ret)
return ret;
}
return f81604_sja1000_write(priv, F81604_SJA1000_OCR,
OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL |
OCR_MODE_NORMAL);
}
static void f81604_process_rx_packet(struct net_device *netdev,
struct f81604_can_frame *frame)
{
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf;
struct sk_buff *skb;
if (frame->cmd != F81604_CMD_DATA)
return;
skb = alloc_can_skb(netdev, &cf);
if (!skb) {
stats->rx_dropped++;
return;
}
cf->len = can_cc_dlc2len(frame->dlc & F81604_DLC_LEN_MASK);
if (frame->dlc & F81604_DLC_EFF_BIT) {
cf->can_id = get_unaligned_be32(&frame->eff.id) >>
F81604_EFF_SHIFT;
cf->can_id |= CAN_EFF_FLAG;
if (!(frame->dlc & F81604_DLC_RTR_BIT))
memcpy(cf->data, frame->eff.data, cf->len);
} else {
cf->can_id = get_unaligned_be16(&frame->sff.id) >>
F81604_SFF_SHIFT;
if (!(frame->dlc & F81604_DLC_RTR_BIT))
memcpy(cf->data, frame->sff.data, cf->len);
}
if (frame->dlc & F81604_DLC_RTR_BIT)
cf->can_id |= CAN_RTR_FLAG;
else
stats->rx_bytes += cf->len;
stats->rx_packets++;
netif_rx(skb);
}
static void f81604_read_bulk_callback(struct urb *urb)
{
struct f81604_can_frame *frame = urb->transfer_buffer;
struct net_device *netdev = urb->context;
int ret;
if (!netif_device_present(netdev))
return;
if (urb->status)
netdev_info(netdev, "%s: URB aborted %pe\n", __func__,
ERR_PTR(urb->status));
switch (urb->status) {
case 0: /* success */
break;
case -ENOENT:
case -EPIPE:
case -EPROTO:
case -ESHUTDOWN:
return;
default:
goto resubmit_urb;
}
if (urb->actual_length != sizeof(*frame)) {
netdev_warn(netdev, "URB length %u not equal to %zu\n",
urb->actual_length, sizeof(*frame));
goto resubmit_urb;
}
f81604_process_rx_packet(netdev, frame);
resubmit_urb:
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret == -ENODEV)
netif_device_detach(netdev);
else if (ret)
netdev_err(netdev,
"%s: failed to resubmit read bulk urb: %pe\n",
__func__, ERR_PTR(ret));
}
static void f81604_handle_tx(struct f81604_port_priv *priv,
struct f81604_int_data *data)
{
struct net_device *netdev = priv->netdev;
struct net_device_stats *stats = &netdev->stats;
/* transmission buffer released */
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(data->sr & F81604_SJA1000_SR_TCS)) {
stats->tx_errors++;
can_free_echo_skb(netdev, 0, NULL);
} else {
/* transmission complete */
stats->tx_bytes += can_get_echo_skb(netdev, 0, NULL);
stats->tx_packets++;
}
netif_wake_queue(netdev);
}
static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv,
struct f81604_int_data *data)
{
enum can_state can_state = priv->can.state;
struct net_device *netdev = priv->netdev;
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf;
struct sk_buff *skb;
/* Note: ALC/ECC will not auto clear by read here, must be cleared by
* read register (via clear_reg_work).
*/
skb = alloc_can_err_skb(netdev, &cf);
if (skb) {
cf->can_id |= CAN_ERR_CNT;
cf->data[6] = data->txerr;
cf->data[7] = data->rxerr;
}
if (data->isrc & F81604_SJA1000_IRQ_DOI) {
/* data overrun interrupt */
netdev_dbg(netdev, "data overrun interrupt\n");
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
}
stats->rx_over_errors++;
stats->rx_errors++;
set_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags);
}
if (data->isrc & F81604_SJA1000_IRQ_EI) {
/* error warning interrupt */
netdev_dbg(netdev, "error warning interrupt\n");
if (data->sr & F81604_SJA1000_SR_BS)
can_state = CAN_STATE_BUS_OFF;
else if (data->sr & F81604_SJA1000_SR_ES)
can_state = CAN_STATE_ERROR_WARNING;
else
can_state = CAN_STATE_ERROR_ACTIVE;
}
if (data->isrc & F81604_SJA1000_IRQ_BEI) {
/* bus error interrupt */
netdev_dbg(netdev, "bus error interrupt\n");
priv->can.can_stats.bus_error++;
stats->rx_errors++;
if (skb) {
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
/* set error type */
switch (data->ecc & F81604_SJA1000_ECC_MASK) {
case F81604_SJA1000_ECC_BIT:
cf->data[2] |= CAN_ERR_PROT_BIT;
break;
case F81604_SJA1000_ECC_FORM:
cf->data[2] |= CAN_ERR_PROT_FORM;
break;
case F81604_SJA1000_ECC_STUFF:
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
break;
}
/* set error location */
cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG;
/* Error occurred during transmission? */
if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0)
cf->data[2] |= CAN_ERR_PROT_TX;
}
set_bit(F81604_CLEAR_ECC, &priv->clear_flags);
}
if (data->isrc & F81604_SJA1000_IRQ_EPI) {
if (can_state == CAN_STATE_ERROR_PASSIVE)
can_state = CAN_STATE_ERROR_WARNING;
else
can_state = CAN_STATE_ERROR_PASSIVE;
/* error passive interrupt */
netdev_dbg(netdev, "error passive interrupt: %d\n", can_state);
}
if (data->isrc & F81604_SJA1000_IRQ_ALI) {
/* arbitration lost interrupt */
netdev_dbg(netdev, "arbitration lost interrupt\n");
priv->can.can_stats.arbitration_lost++;
if (skb) {
cf->can_id |= CAN_ERR_LOSTARB;
cf->data[0] = data->alc & F81604_SJA1000_ALC_MASK;
}
set_bit(F81604_CLEAR_ALC, &priv->clear_flags);
}
if (can_state != priv->can.state) {
enum can_state tx_state, rx_state;
tx_state = data->txerr >= data->rxerr ? can_state : 0;
rx_state = data->txerr <= data->rxerr ? can_state : 0;
can_change_state(netdev, cf, tx_state, rx_state);
if (can_state == CAN_STATE_BUS_OFF)
can_bus_off(netdev);
}
if (priv->clear_flags)
schedule_work(&priv->clear_reg_work);
if (skb)
netif_rx(skb);
}
static void f81604_read_int_callback(struct urb *urb)
{
struct f81604_int_data *data = urb->transfer_buffer;
struct net_device *netdev = urb->context;
struct f81604_port_priv *priv;
int ret;
priv = netdev_priv(netdev);
if (!netif_device_present(netdev))
return;
if (urb->status)
netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__,
ERR_PTR(urb->status));
switch (urb->status) {
case 0: /* success */
break;
case -ENOENT:
case -EPIPE:
case -EPROTO:
case -ESHUTDOWN:
return;
default:
goto resubmit_urb;
}
/* handle Errors */
if (data->isrc & (F81604_SJA1000_IRQ_DOI | F81604_SJA1000_IRQ_EI |
F81604_SJA1000_IRQ_BEI | F81604_SJA1000_IRQ_EPI |
F81604_SJA1000_IRQ_ALI))
f81604_handle_can_bus_errors(priv, data);
/* handle TX */
if (priv->can.state != CAN_STATE_BUS_OFF &&
(data->isrc & F81604_SJA1000_IRQ_TI))
f81604_handle_tx(priv, data);
resubmit_urb:
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret == -ENODEV)
netif_device_detach(netdev);
else if (ret)
netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n",
__func__, ERR_PTR(ret));
}
static void f81604_unregister_urbs(struct f81604_port_priv *priv)
{
usb_kill_anchored_urbs(&priv->urbs_anchor);
}
static int f81604_register_urbs(struct f81604_port_priv *priv)
{
struct net_device *netdev = priv->netdev;
struct f81604_int_data *int_data;
int id = netdev->dev_port;
struct urb *int_urb;
int rx_urb_cnt;
int ret;
for (rx_urb_cnt = 0; rx_urb_cnt < F81604_MAX_RX_URBS; ++rx_urb_cnt) {
struct f81604_can_frame *frame;
struct urb *rx_urb;
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
ret = -ENOMEM;
break;
}
frame = kmalloc(sizeof(*frame), GFP_KERNEL);
if (!frame) {
usb_free_urb(rx_urb);
ret = -ENOMEM;
break;
}
usb_fill_bulk_urb(rx_urb, priv->dev,
usb_rcvbulkpipe(priv->dev, bulk_in_addr[id]),
frame, sizeof(*frame),
f81604_read_bulk_callback, netdev);
rx_urb->transfer_flags |= URB_FREE_BUFFER;
usb_anchor_urb(rx_urb, &priv->urbs_anchor);
ret = usb_submit_urb(rx_urb, GFP_KERNEL);
if (ret) {
usb_unanchor_urb(rx_urb);
usb_free_urb(rx_urb);
break;
}
/* Drop reference, USB core will take care of freeing it */
usb_free_urb(rx_urb);
}
if (rx_urb_cnt == 0) {
netdev_warn(netdev, "%s: submit rx urb failed: %pe\n",
__func__, ERR_PTR(ret));
goto error;
}
int_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!int_urb) {
ret = -ENOMEM;
goto error;
}
int_data = kmalloc(sizeof(*int_data), GFP_KERNEL);
if (!int_data) {
usb_free_urb(int_urb);
ret = -ENOMEM;
goto error;
}
usb_fill_int_urb(int_urb, priv->dev,
usb_rcvintpipe(priv->dev, int_in_addr[id]), int_data,
sizeof(*int_data), f81604_read_int_callback, netdev,
1);
int_urb->transfer_flags |= URB_FREE_BUFFER;
usb_anchor_urb(int_urb, &priv->urbs_anchor);
ret = usb_submit_urb(int_urb, GFP_KERNEL);
if (ret) {
usb_unanchor_urb(int_urb);
usb_free_urb(int_urb);
netdev_warn(netdev, "%s: submit int urb failed: %pe\n",
__func__, ERR_PTR(ret));
goto error;
}
/* Drop reference, USB core will take care of freeing it */
usb_free_urb(int_urb);
return 0;
error:
f81604_unregister_urbs(priv);
return ret;
}
static int f81604_start(struct net_device *netdev)
{
struct f81604_port_priv *priv = netdev_priv(netdev);
int ret;
u8 mode;
u8 tmp;
mode = F81604_RX_AUTO_RELEASE_BUF | F81604_INT_WHEN_CHANGE;
/* Set TR/AT mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
mode |= F81604_TX_ONESHOT;
else
mode |= F81604_TX_NORMAL;
ret = f81604_sja1000_write(priv, F81604_CTRL_MODE_REG, mode);
if (ret)
return ret;
/* set reset mode */
ret = f81604_set_reset_mode(priv);
if (ret)
return ret;
ret = f81604_chipset_init(priv);
if (ret)
return ret;
/* Clear error counters and error code capture */
ret = f81604_sja1000_write(priv, F81604_SJA1000_TXERR, 0);
if (ret)
return ret;
ret = f81604_sja1000_write(priv, F81604_SJA1000_RXERR, 0);
if (ret)
return ret;
/* Read clear for ECC/ALC/IR register */
ret = f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp);
if (ret)
return ret;
ret = f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp);
if (ret)
return ret;
ret = f81604_sja1000_read(priv, F81604_SJA1000_IR, &tmp);
if (ret)
return ret;
ret = f81604_register_urbs(priv);
if (ret)
return ret;
ret = f81604_set_normal_mode(priv);
if (ret) {
f81604_unregister_urbs(priv);
return ret;
}
return 0;
}
static int f81604_set_bittiming(struct net_device *dev)
{
struct f81604_port_priv *priv = netdev_priv(dev);
struct can_bittiming *bt = &priv->can.bittiming;
u8 btr0, btr1;
int ret;
btr0 = FIELD_PREP(F81604_BRP_MASK, bt->brp - 1) |
FIELD_PREP(F81604_SJW_MASK, bt->sjw - 1);
btr1 = FIELD_PREP(F81604_SEG1_MASK,
bt->prop_seg + bt->phase_seg1 - 1) |
FIELD_PREP(F81604_SEG2_MASK, bt->phase_seg2 - 1);
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= F81604_SJA1000_BTR1_SAMPLE_TRIPLE;
ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR0, btr0);
if (ret) {
netdev_warn(dev, "%s: Set BTR0 failed: %pe\n", __func__,
ERR_PTR(ret));
return ret;
}
ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR1, btr1);
if (ret) {
netdev_warn(dev, "%s: Set BTR1 failed: %pe\n", __func__,
ERR_PTR(ret));
return ret;
}
return 0;
}
static int f81604_set_mode(struct net_device *netdev, enum can_mode mode)
{
int ret;
switch (mode) {
case CAN_MODE_START:
ret = f81604_start(netdev);
if (!ret && netif_queue_stopped(netdev))
netif_wake_queue(netdev);
break;
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static void f81604_write_bulk_callback(struct urb *urb)
{
struct net_device *netdev = urb->context;
if (!netif_device_present(netdev))
return;
if (urb->status)
netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__,
ERR_PTR(urb->status));
}
static void f81604_clear_reg_work(struct work_struct *work)
{
struct f81604_port_priv *priv;
u8 tmp;
priv = container_of(work, struct f81604_port_priv, clear_reg_work);
/* dummy read for clear Arbitration lost capture(ALC) register. */
if (test_and_clear_bit(F81604_CLEAR_ALC, &priv->clear_flags))
f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp);
/* dummy read for clear Error code capture(ECC) register. */
if (test_and_clear_bit(F81604_CLEAR_ECC, &priv->clear_flags))
f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp);
/* dummy write for clear data overrun flag. */
if (test_and_clear_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags))
f81604_sja1000_write(priv, F81604_SJA1000_CMR,
F81604_SJA1000_CMD_CDO);
}
static netdev_tx_t f81604_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct can_frame *cf = (struct can_frame *)skb->data;
struct f81604_port_priv *priv = netdev_priv(netdev);
struct net_device_stats *stats = &netdev->stats;
struct f81604_can_frame *frame;
struct urb *write_urb;
int ret;
if (can_dev_dropped_skb(netdev, skb))
return NETDEV_TX_OK;
netif_stop_queue(netdev);
write_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!write_urb)
goto nomem_urb;
frame = kzalloc(sizeof(*frame), GFP_ATOMIC);
if (!frame)
goto nomem_buf;
usb_fill_bulk_urb(write_urb, priv->dev,
usb_sndbulkpipe(priv->dev,
bulk_out_addr[netdev->dev_port]),
frame, sizeof(*frame), f81604_write_bulk_callback,
priv->netdev);
write_urb->transfer_flags |= URB_FREE_BUFFER;
frame->cmd = F81604_CMD_DATA;
frame->dlc = cf->len;
if (cf->can_id & CAN_RTR_FLAG)
frame->dlc |= F81604_DLC_RTR_BIT;
if (cf->can_id & CAN_EFF_FLAG) {
u32 id = (cf->can_id & CAN_EFF_MASK) << F81604_EFF_SHIFT;
put_unaligned_be32(id, &frame->eff.id);
frame->dlc |= F81604_DLC_EFF_BIT;
if (!(cf->can_id & CAN_RTR_FLAG))
memcpy(&frame->eff.data, cf->data, cf->len);
} else {
u32 id = (cf->can_id & CAN_SFF_MASK) << F81604_SFF_SHIFT;
put_unaligned_be16(id, &frame->sff.id);
if (!(cf->can_id & CAN_RTR_FLAG))
memcpy(&frame->sff.data, cf->data, cf->len);
}
can_put_echo_skb(skb, netdev, 0, 0);
ret = usb_submit_urb(write_urb, GFP_ATOMIC);
if (ret) {
netdev_err(netdev, "%s: failed to resubmit tx bulk urb: %pe\n",
__func__, ERR_PTR(ret));
can_free_echo_skb(netdev, 0, NULL);
stats->tx_dropped++;
stats->tx_errors++;
if (ret == -ENODEV)
netif_device_detach(netdev);
else
netif_wake_queue(netdev);
}
/* let usb core take care of this urb */
usb_free_urb(write_urb);
return NETDEV_TX_OK;
nomem_buf:
usb_free_urb(write_urb);
nomem_urb:
dev_kfree_skb(skb);
stats->tx_dropped++;
stats->tx_errors++;
netif_wake_queue(netdev);
return NETDEV_TX_OK;
}
static int f81604_get_berr_counter(const struct net_device *netdev,
struct can_berr_counter *bec)
{
struct f81604_port_priv *priv = netdev_priv(netdev);
u8 txerr, rxerr;
int ret;
ret = f81604_sja1000_read(priv, F81604_SJA1000_TXERR, &txerr);
if (ret)
return ret;
ret = f81604_sja1000_read(priv, F81604_SJA1000_RXERR, &rxerr);
if (ret)
return ret;
bec->txerr = txerr;
bec->rxerr = rxerr;
return 0;
}
/* Open USB device */
static int f81604_open(struct net_device *netdev)
{
int ret;
ret = open_candev(netdev);
if (ret)
return ret;
ret = f81604_start(netdev);
if (ret) {
if (ret == -ENODEV)
netif_device_detach(netdev);
close_candev(netdev);
return ret;
}
netif_start_queue(netdev);
return 0;
}
/* Close USB device */
static int f81604_close(struct net_device *netdev)
{
struct f81604_port_priv *priv = netdev_priv(netdev);
f81604_set_reset_mode(priv);
netif_stop_queue(netdev);
cancel_work_sync(&priv->clear_reg_work);
close_candev(netdev);
f81604_unregister_urbs(priv);
return 0;
}
static const struct net_device_ops f81604_netdev_ops = {
.ndo_open = f81604_open,
.ndo_stop = f81604_close,
.ndo_start_xmit = f81604_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static const struct can_bittiming_const f81604_bittiming_const = {
.name = KBUILD_MODNAME,
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 64,
.brp_inc = 1,
};
/* Called by the usb core when driver is unloaded or device is removed */
static void f81604_disconnect(struct usb_interface *intf)
{
struct f81604_priv *priv = usb_get_intfdata(intf);
int i;
for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
if (!priv->netdev[i])
continue;
unregister_netdev(priv->netdev[i]);
free_candev(priv->netdev[i]);
}
}
static int __f81604_set_termination(struct usb_device *dev, int idx, u16 term)
{
u8 mask, data = 0;
if (idx == 0)
mask = F81604_CAN0_TERM;
else
mask = F81604_CAN1_TERM;
if (term)
data = mask;
return f81604_update_bits(dev, F81604_TERMINATOR_REG, mask, data);
}
static int f81604_set_termination(struct net_device *netdev, u16 term)
{
struct f81604_port_priv *port_priv = netdev_priv(netdev);
ASSERT_RTNL();
return __f81604_set_termination(port_priv->dev, netdev->dev_port,
term);
}
static int f81604_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct net_device *netdev;
struct f81604_priv *priv;
int i, ret;
priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
usb_set_intfdata(intf, priv);
for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
ret = __f81604_set_termination(dev, i, 0);
if (ret) {
dev_err(&intf->dev,
"Setting termination of CH#%d failed: %pe\n",
i, ERR_PTR(ret));
return ret;
}
}
for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) {
struct f81604_port_priv *port_priv;
netdev = alloc_candev(sizeof(*port_priv), 1);
if (!netdev) {
dev_err(&intf->dev, "Couldn't alloc candev: %d\n", i);
ret = -ENOMEM;
goto failure_cleanup;
}
port_priv = netdev_priv(netdev);
INIT_WORK(&port_priv->clear_reg_work, f81604_clear_reg_work);
init_usb_anchor(&port_priv->urbs_anchor);
port_priv->intf = intf;
port_priv->dev = dev;
port_priv->netdev = netdev;
port_priv->can.clock.freq = F81604_CAN_CLOCK;
port_priv->can.termination_const = f81604_termination;
port_priv->can.termination_const_cnt =
ARRAY_SIZE(f81604_termination);
port_priv->can.bittiming_const = &f81604_bittiming_const;
port_priv->can.do_set_bittiming = f81604_set_bittiming;
port_priv->can.do_set_mode = f81604_set_mode;
port_priv->can.do_set_termination = f81604_set_termination;
port_priv->can.do_get_berr_counter = f81604_get_berr_counter;
port_priv->can.ctrlmode_supported =
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_PRESUME_ACK;
netdev->ethtool_ops = &f81604_ethtool_ops;
netdev->netdev_ops = &f81604_netdev_ops;
netdev->flags |= IFF_ECHO;
netdev->dev_port = i;
SET_NETDEV_DEV(netdev, &intf->dev);
ret = register_candev(netdev);
if (ret) {
netdev_err(netdev, "register CAN device failed: %pe\n",
ERR_PTR(ret));
free_candev(netdev);
goto failure_cleanup;
}
priv->netdev[i] = netdev;
}
return 0;
failure_cleanup:
f81604_disconnect(intf);
return ret;
}
static struct usb_driver f81604_driver = {
.name = KBUILD_MODNAME,
.probe = f81604_probe,
.disconnect = f81604_disconnect,
.id_table = f81604_table,
};
module_usb_driver(f81604_driver);
MODULE_AUTHOR("Ji-Ze Hong (Peter Hong) <peter_hong@fintek.com.tw>");
MODULE_DESCRIPTION("Fintek F81604 USB to 2xCANBUS");
MODULE_LICENSE("GPL");
......@@ -1898,20 +1898,18 @@ static int xcan_probe(struct platform_device *pdev)
* This function frees all the resources allocated to the device.
* Return: 0 always
*/
static int xcan_remove(struct platform_device *pdev)
static void xcan_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
unregister_candev(ndev);
pm_runtime_disable(&pdev->dev);
free_candev(ndev);
return 0;
}
static struct platform_driver xcan_driver = {
.probe = xcan_probe,
.remove = xcan_remove,
.remove_new = xcan_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &xcan_dev_pm_ops,
......
......@@ -6,6 +6,9 @@
#ifndef _CAN_LENGTH_H
#define _CAN_LENGTH_H
#include <linux/can.h>
#include <linux/can/netlink.h>
/*
* Size of a Classical CAN Standard Frame
*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment