Commit ea4c1787 authored by Matthias Schiffer's avatar Matthias Schiffer Committed by Marc Kleine-Budde
Browse files

can: m_can: pci: use custom bit timings for Elkhart Lake

The relevant datasheet [1] specifies nonstandard limits for the bit timing
parameters. While it is unclear what the exact effect of violating these
limits is, it seems like a good idea to adhere to the documentation.

[1] Intel Atom® x6000E Series, and Intel® Pentium® and Celeron® N and J
    Series Processors for IoT Applications Datasheet,
    Volume 2 (Book 3 of 3), July 2021, Revision 001

Fixes: cab7ffc0 ("can: m_can: add PCI glue driver for Intel Elkhart Lake")
Link: https://lore.kernel.org/all/9eba5d7c05a48ead4024ffa6e5926f191d8c6b38.1636967198.git.matthias.schiffer@ew.tq-group.com


Signed-off-by: default avatarMatthias Schiffer <matthias.schiffer@ew.tq-group.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent ea22ba40
Loading
Loading
Loading
Loading
+44 −4
Original line number Diff line number Diff line
@@ -18,9 +18,14 @@

#define M_CAN_PCI_MMIO_BAR		0

#define M_CAN_CLOCK_FREQ_EHL		200000000
#define CTL_CSR_INT_CTL_OFFSET		0x508

struct m_can_pci_config {
	const struct can_bittiming_const *bit_timing;
	const struct can_bittiming_const *data_timing;
	unsigned int clock_freq;
};

struct m_can_pci_priv {
	struct m_can_classdev cdev;

@@ -84,9 +89,40 @@ static struct m_can_ops m_can_pci_ops = {
	.read_fifo = iomap_read_fifo,
};

static const struct can_bittiming_const m_can_bittiming_const_ehl = {
	.name = KBUILD_MODNAME,
	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
	.tseg1_max = 64,
	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
	.tseg2_max = 128,
	.sjw_max = 128,
	.brp_min = 1,
	.brp_max = 512,
	.brp_inc = 1,
};

static const struct can_bittiming_const m_can_data_bittiming_const_ehl = {
	.name = KBUILD_MODNAME,
	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
	.tseg1_max = 16,
	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
	.tseg2_max = 8,
	.sjw_max = 4,
	.brp_min = 1,
	.brp_max = 32,
	.brp_inc = 1,
};

static const struct m_can_pci_config m_can_pci_ehl = {
	.bit_timing = &m_can_bittiming_const_ehl,
	.data_timing = &m_can_data_bittiming_const_ehl,
	.clock_freq = 200000000,
};

static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
	struct device *dev = &pci->dev;
	const struct m_can_pci_config *cfg;
	struct m_can_classdev *mcan_class;
	struct m_can_pci_priv *priv;
	void __iomem *base;
@@ -114,6 +150,8 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
	if (!mcan_class)
		return -ENOMEM;

	cfg = (const struct m_can_pci_config *)id->driver_data;

	priv = cdev_to_priv(mcan_class);

	priv->base = base;
@@ -125,7 +163,9 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
	mcan_class->dev = &pci->dev;
	mcan_class->net->irq = pci_irq_vector(pci, 0);
	mcan_class->pm_clock_support = 1;
	mcan_class->can.clock.freq = id->driver_data;
	mcan_class->bit_timing = cfg->bit_timing;
	mcan_class->data_timing = cfg->data_timing;
	mcan_class->can.clock.freq = cfg->clock_freq;
	mcan_class->ops = &m_can_pci_ops;

	pci_set_drvdata(pci, mcan_class);
@@ -178,8 +218,8 @@ static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops,
			 m_can_pci_suspend, m_can_pci_resume);

static const struct pci_device_id m_can_pci_id_table[] = {
	{ PCI_VDEVICE(INTEL, 0x4bc1), M_CAN_CLOCK_FREQ_EHL, },
	{ PCI_VDEVICE(INTEL, 0x4bc2), M_CAN_CLOCK_FREQ_EHL, },
	{ PCI_VDEVICE(INTEL, 0x4bc1), (kernel_ulong_t)&m_can_pci_ehl, },
	{ PCI_VDEVICE(INTEL, 0x4bc2), (kernel_ulong_t)&m_can_pci_ehl, },
	{  }	/* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, m_can_pci_id_table);