drivers/net/can/grcan.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/grcan.c
Extension
.c
Size
50197 bytes
Lines
1735
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 grcan_netdev_ops = {
	.ndo_open	= grcan_open,
	.ndo_stop	= grcan_close,
	.ndo_start_xmit	= grcan_start_xmit,
};

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

static int grcan_setup_netdev(struct platform_device *ofdev,
			      void __iomem *base,
			      int irq, u32 ambafreq, bool txbug)
{
	struct net_device *dev;
	struct grcan_priv *priv;
	struct grcan_registers __iomem *regs;
	int err;

	dev = alloc_candev(sizeof(struct grcan_priv), 0);
	if (!dev)
		return -ENOMEM;

	dev->irq = irq;
	dev->flags |= IFF_ECHO;
	dev->netdev_ops = &grcan_netdev_ops;
	dev->ethtool_ops = &grcan_ethtool_ops;
	dev->sysfs_groups[0] = &sysfs_grcan_group;

	priv = netdev_priv(dev);
	memcpy(&priv->config, &grcan_module_config,
	       sizeof(struct grcan_device_config));
	priv->dev = dev;
	priv->ofdev_dev = &ofdev->dev;
	priv->regs = base;
	priv->can.bittiming_const = &grcan_bittiming_const;
	priv->can.do_set_bittiming = grcan_set_bittiming;
	priv->can.do_set_mode = grcan_set_mode;
	priv->can.do_get_berr_counter = grcan_get_berr_counter;
	priv->can.clock.freq = ambafreq;
	priv->can.ctrlmode_supported =
		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT;
	priv->need_txbug_workaround = txbug;

	/* Discover if triple sampling is supported by hardware */
	regs = priv->regs;
	grcan_set_bits(&regs->ctrl, GRCAN_CTRL_RESET);
	grcan_set_bits(&regs->conf, GRCAN_CONF_SAM);
	if (grcan_read_bits(&regs->conf, GRCAN_CONF_SAM)) {
		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
		dev_dbg(&ofdev->dev, "Hardware supports triple-sampling\n");
	}

	spin_lock_init(&priv->lock);

	if (priv->need_txbug_workaround) {
		timer_setup(&priv->rr_timer, grcan_running_reset, 0);
		timer_setup(&priv->hang_timer, grcan_initiate_running_reset, 0);
	}

	netif_napi_add_weight(dev, &priv->napi, grcan_poll, GRCAN_NAPI_WEIGHT);

	SET_NETDEV_DEV(dev, &ofdev->dev);
	dev_info(&ofdev->dev, "regs=0x%p, irq=%d, clock=%d\n",
		 priv->regs, dev->irq, priv->can.clock.freq);

	err = register_candev(dev);
	if (err)
		goto exit_free_candev;

	platform_set_drvdata(ofdev, dev);

	/* Reset device to allow bit-timing to be set. No need to call
	 * grcan_reset at this stage. That is done in grcan_open.
	 */
	grcan_write_reg(&regs->ctrl, GRCAN_CTRL_RESET);

	return 0;
exit_free_candev:
	free_candev(dev);
	return err;
}

static int grcan_probe(struct platform_device *ofdev)
{
	struct device_node *np = ofdev->dev.of_node;
	struct device_node *sysid_parent;
	u32 sysid, ambafreq;
	int irq, err;
	void __iomem *base;

Annotation

Implementation Notes