drivers/net/can/spi/hi311x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/spi/hi311x.c
Extension
.c
Size
26240 bytes
Lines
1045
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 hi3110_netdev_ops = {
	.ndo_open = hi3110_open,
	.ndo_stop = hi3110_stop,
	.ndo_start_xmit = hi3110_hard_start_xmit,
};

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

static const struct of_device_id hi3110_of_match[] = {
	{
		.compatible	= "holt,hi3110",
		.data		= (void *)CAN_HI3110_HI3110,
	},
	{ }
};
MODULE_DEVICE_TABLE(of, hi3110_of_match);

static const struct spi_device_id hi3110_id_table[] = {
	{
		.name		= "hi3110",
		.driver_data	= (kernel_ulong_t)CAN_HI3110_HI3110,
	},
	{ }
};
MODULE_DEVICE_TABLE(spi, hi3110_id_table);

static int hi3110_can_probe(struct spi_device *spi)
{
	struct device *dev = &spi->dev;
	struct net_device *net;
	struct hi3110_priv *priv;
	struct clk *clk;
	u32 freq;
	int ret;

	clk = devm_clk_get_optional(&spi->dev, NULL);
	if (IS_ERR(clk))
		return dev_err_probe(dev, PTR_ERR(clk), "no CAN clock source defined\n");

	if (clk) {
		freq = clk_get_rate(clk);
	} else {
		ret = device_property_read_u32(dev, "clock-frequency", &freq);
		if (ret)
			return dev_err_probe(dev, ret, "Failed to get clock-frequency!\n");
	}

	/* Sanity check */
	if (freq > 40000000)
		return -ERANGE;

	/* Allocate can/net device */
	net = alloc_candev(sizeof(struct hi3110_priv), HI3110_TX_ECHO_SKB_MAX);
	if (!net)
		return -ENOMEM;

	ret = clk_prepare_enable(clk);
	if (ret)
		goto out_free;

	net->netdev_ops = &hi3110_netdev_ops;
	net->ethtool_ops = &hi3110_ethtool_ops;
	net->flags |= IFF_ECHO;

	priv = netdev_priv(net);
	priv->can.bittiming_const = &hi3110_bittiming_const;
	priv->can.do_set_mode = hi3110_do_set_mode;
	priv->can.do_get_berr_counter = hi3110_get_berr_counter;
	priv->can.clock.freq = freq / 2;
	priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
		CAN_CTRLMODE_LOOPBACK |
		CAN_CTRLMODE_LISTENONLY |
		CAN_CTRLMODE_BERR_REPORTING;

	priv->model = (enum hi3110_model)(uintptr_t)spi_get_device_match_data(spi);
	priv->net = net;
	priv->clk = clk;

	spi_set_drvdata(spi, priv);

	/* Configure the SPI bus */
	spi->bits_per_word = 8;
	ret = spi_setup(spi);
	if (ret)
		goto out_clk;

	priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
	priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");

Annotation

Implementation Notes