1 // SPDX-License-Identifier: GPL-2.0
3 * PCI Specific M_CAN Glue
5 * Copyright (C) 2018-2020 Intel Corporation
6 * Author: Felipe Balbi (Intel)
7 * Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
8 * Author: Raymond Tan <raymond.tan@intel.com>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/netdevice.h>
14 #include <linux/pci.h>
15 #include <linux/pm_runtime.h>
19 #define M_CAN_PCI_MMIO_BAR 0
21 #define CTL_CSR_INT_CTL_OFFSET 0x508
23 struct m_can_pci_config
{
24 const struct can_bittiming_const
*bit_timing
;
25 const struct can_bittiming_const
*data_timing
;
26 unsigned int clock_freq
;
29 struct m_can_pci_priv
{
30 struct m_can_classdev cdev
;
35 static inline struct m_can_pci_priv
*cdev_to_priv(struct m_can_classdev
*cdev
)
37 return container_of(cdev
, struct m_can_pci_priv
, cdev
);
40 static u32
iomap_read_reg(struct m_can_classdev
*cdev
, int reg
)
42 struct m_can_pci_priv
*priv
= cdev_to_priv(cdev
);
44 return readl(priv
->base
+ reg
);
47 static int iomap_read_fifo(struct m_can_classdev
*cdev
, int offset
, void *val
, size_t val_count
)
49 struct m_can_pci_priv
*priv
= cdev_to_priv(cdev
);
50 void __iomem
*src
= priv
->base
+ offset
;
53 *(unsigned int *)val
= ioread32(src
);
61 static int iomap_write_reg(struct m_can_classdev
*cdev
, int reg
, int val
)
63 struct m_can_pci_priv
*priv
= cdev_to_priv(cdev
);
65 writel(val
, priv
->base
+ reg
);
70 static int iomap_write_fifo(struct m_can_classdev
*cdev
, int offset
,
71 const void *val
, size_t val_count
)
73 struct m_can_pci_priv
*priv
= cdev_to_priv(cdev
);
74 void __iomem
*dst
= priv
->base
+ offset
;
77 iowrite32(*(unsigned int *)val
, dst
);
85 static struct m_can_ops m_can_pci_ops
= {
86 .read_reg
= iomap_read_reg
,
87 .write_reg
= iomap_write_reg
,
88 .write_fifo
= iomap_write_fifo
,
89 .read_fifo
= iomap_read_fifo
,
92 static const struct can_bittiming_const m_can_bittiming_const_ehl
= {
93 .name
= KBUILD_MODNAME
,
94 .tseg1_min
= 2, /* Time segment 1 = prop_seg + phase_seg1 */
96 .tseg2_min
= 1, /* Time segment 2 = phase_seg2 */
104 static const struct can_bittiming_const m_can_data_bittiming_const_ehl
= {
105 .name
= KBUILD_MODNAME
,
106 .tseg1_min
= 2, /* Time segment 1 = prop_seg + phase_seg1 */
108 .tseg2_min
= 1, /* Time segment 2 = phase_seg2 */
116 static const struct m_can_pci_config m_can_pci_ehl
= {
117 .bit_timing
= &m_can_bittiming_const_ehl
,
118 .data_timing
= &m_can_data_bittiming_const_ehl
,
119 .clock_freq
= 200000000,
122 static int m_can_pci_probe(struct pci_dev
*pci
, const struct pci_device_id
*id
)
124 struct device
*dev
= &pci
->dev
;
125 const struct m_can_pci_config
*cfg
;
126 struct m_can_classdev
*mcan_class
;
127 struct m_can_pci_priv
*priv
;
131 ret
= pcim_enable_device(pci
);
137 ret
= pcim_iomap_regions(pci
, BIT(M_CAN_PCI_MMIO_BAR
), pci_name(pci
));
141 base
= pcim_iomap_table(pci
)[M_CAN_PCI_MMIO_BAR
];
144 dev_err(dev
, "failed to map BARs\n");
148 mcan_class
= m_can_class_allocate_dev(&pci
->dev
,
149 sizeof(struct m_can_pci_priv
));
153 cfg
= (const struct m_can_pci_config
*)id
->driver_data
;
155 priv
= cdev_to_priv(mcan_class
);
159 ret
= pci_alloc_irq_vectors(pci
, 1, 1, PCI_IRQ_ALL_TYPES
);
163 mcan_class
->dev
= &pci
->dev
;
164 mcan_class
->net
->irq
= pci_irq_vector(pci
, 0);
165 mcan_class
->pm_clock_support
= 1;
166 mcan_class
->bit_timing
= cfg
->bit_timing
;
167 mcan_class
->data_timing
= cfg
->data_timing
;
168 mcan_class
->can
.clock
.freq
= cfg
->clock_freq
;
169 mcan_class
->ops
= &m_can_pci_ops
;
171 pci_set_drvdata(pci
, mcan_class
);
173 ret
= m_can_class_register(mcan_class
);
177 /* Enable interrupt control at CAN wrapper IP */
178 writel(0x1, base
+ CTL_CSR_INT_CTL_OFFSET
);
180 pm_runtime_set_autosuspend_delay(dev
, 1000);
181 pm_runtime_use_autosuspend(dev
);
182 pm_runtime_put_noidle(dev
);
183 pm_runtime_allow(dev
);
188 pci_free_irq_vectors(pci
);
192 static void m_can_pci_remove(struct pci_dev
*pci
)
194 struct m_can_classdev
*mcan_class
= pci_get_drvdata(pci
);
195 struct m_can_pci_priv
*priv
= cdev_to_priv(mcan_class
);
197 pm_runtime_forbid(&pci
->dev
);
198 pm_runtime_get_noresume(&pci
->dev
);
200 /* Disable interrupt control at CAN wrapper IP */
201 writel(0x0, priv
->base
+ CTL_CSR_INT_CTL_OFFSET
);
203 m_can_class_unregister(mcan_class
);
204 pci_free_irq_vectors(pci
);
207 static __maybe_unused
int m_can_pci_suspend(struct device
*dev
)
209 return m_can_class_suspend(dev
);
212 static __maybe_unused
int m_can_pci_resume(struct device
*dev
)
214 return m_can_class_resume(dev
);
217 static SIMPLE_DEV_PM_OPS(m_can_pci_pm_ops
,
218 m_can_pci_suspend
, m_can_pci_resume
);
220 static const struct pci_device_id m_can_pci_id_table
[] = {
221 { PCI_VDEVICE(INTEL
, 0x4bc1), (kernel_ulong_t
)&m_can_pci_ehl
, },
222 { PCI_VDEVICE(INTEL
, 0x4bc2), (kernel_ulong_t
)&m_can_pci_ehl
, },
223 { } /* Terminating Entry */
225 MODULE_DEVICE_TABLE(pci
, m_can_pci_id_table
);
227 static struct pci_driver m_can_pci_driver
= {
229 .probe
= m_can_pci_probe
,
230 .remove
= m_can_pci_remove
,
231 .id_table
= m_can_pci_id_table
,
233 .pm
= &m_can_pci_pm_ops
,
237 module_pci_driver(m_can_pci_driver
);
239 MODULE_AUTHOR("Felipe Balbi (Intel)");
240 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
241 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
242 MODULE_LICENSE("GPL");
243 MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller on PCI bus");