drivers/net/can/ifi_canfd/ifi_canfd.c

Source file repositories/reference/linux-study-clean/drivers/net/can/ifi_canfd/ifi_canfd.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/ifi_canfd/ifi_canfd.c
Extension
.c
Size
30095 bytes
Lines
1065
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops ifi_canfd_netdev_ops = {
	.ndo_open	= ifi_canfd_open,
	.ndo_stop	= ifi_canfd_close,
	.ndo_start_xmit	= ifi_canfd_start_xmit,
};

static const struct ethtool_ops ifi_canfd_ethtool_ops = {
	.get_ts_info = ethtool_op_get_ts_info,
};

static int ifi_canfd_plat_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct net_device *ndev;
	struct ifi_canfd_priv *priv;
	void __iomem *addr;
	int irq, ret;
	u32 id, rev;

	addr = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(addr))
		return PTR_ERR(addr);

	irq = platform_get_irq(pdev, 0);
	if (irq < 0)
		return -EINVAL;

	id = readl(addr + IFI_CANFD_IP_ID);
	if (id != IFI_CANFD_IP_ID_VALUE) {
		dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
		return -EINVAL;
	}

	rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK;
	if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) {
		dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n",
			rev, IFI_CANFD_VER_REV_MIN_SUPPORTED);
		return -EINVAL;
	}

	ndev = alloc_candev(sizeof(*priv), 1);
	if (!ndev)
		return -ENOMEM;

	ndev->irq = irq;
	ndev->flags |= IFF_ECHO;	/* we support local echo */
	ndev->netdev_ops = &ifi_canfd_netdev_ops;
	ndev->ethtool_ops = &ifi_canfd_ethtool_ops;

	priv = netdev_priv(ndev);
	priv->ndev = ndev;
	priv->base = addr;

	netif_napi_add(ndev, &priv->napi, ifi_canfd_poll);

	priv->can.state = CAN_STATE_STOPPED;

	priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK);

	priv->can.bittiming_const = &ifi_canfd_bittiming_const;
	priv->can.fd.data_bittiming_const = &ifi_canfd_bittiming_const;
	priv->can.do_set_mode = ifi_canfd_set_mode;
	priv->can.do_get_berr_counter = ifi_canfd_get_berr_counter;

	/* IFI CANFD can do both Bosch FD and ISO FD */
	priv->can.ctrlmode = CAN_CTRLMODE_FD;

	/* IFI CANFD can do both Bosch FD and ISO FD */
	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
				       CAN_CTRLMODE_LISTENONLY |
				       CAN_CTRLMODE_FD |
				       CAN_CTRLMODE_FD_NON_ISO |
				       CAN_CTRLMODE_BERR_REPORTING;

	platform_set_drvdata(pdev, ndev);
	SET_NETDEV_DEV(ndev, dev);

	ret = register_candev(ndev);
	if (ret) {
		dev_err(dev, "Failed to register (ret=%d)\n", ret);
		goto err_reg;
	}

	dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
		 priv->base, ndev->irq, priv->can.clock.freq);

	return 0;

err_reg:
	free_candev(ndev);

Annotation

Implementation Notes