diff options
-rw-r--r-- | drivers/net/can/m_can/m_can.c | 34 | ||||
-rw-r--r-- | drivers/net/can/m_can/m_can.h | 3 | ||||
-rw-r--r-- | drivers/net/can/m_can/m_can_platform.c | 23 |
3 files changed, 55 insertions, 5 deletions
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 41422f8f7930..f39686483d8d 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -22,6 +22,7 @@ #include <linux/can/dev.h> #include <linux/pinctrl/consumer.h> #include <linux/phy/phy.h> +#include <linux/hrtimer.h> #include "m_can.h" @@ -322,6 +323,9 @@ enum m_can_reg { #define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT #define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) +/* Hrtimer polling interval */ +#define HRTIMER_POLL_INTERVAL 1 + static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg) { return cdev->ops->read_reg(cdev, reg); @@ -1244,6 +1248,12 @@ static void m_can_start(struct net_device *dev) cdev->can.state = CAN_STATE_ERROR_ACTIVE; m_can_enable_all_interrupts(cdev); + + if (dev->irq == 0) { + dev_dbg(cdev->dev, "Start hrtimer\n"); + hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL), + HRTIMER_MODE_REL_PINNED); + } } static int m_can_set_mode(struct net_device *dev, enum can_mode mode) @@ -1407,6 +1417,11 @@ static void m_can_stop(struct net_device *dev) { struct m_can_classdev *cdev = netdev_priv(dev); + if (dev->irq == 0) { + dev_dbg(cdev->dev, "Stop hrtimer\n"); + hrtimer_cancel(&cdev->hrtimer); + } + /* disable all interrupts */ m_can_disable_all_interrupts(cdev); @@ -1625,6 +1640,18 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer) +{ + struct m_can_classdev *cdev = container_of(timer, struct + m_can_classdev, hrtimer); + + m_can_isr(0, cdev->net); + + hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL)); + + return HRTIMER_RESTART; +} + static int m_can_open(struct net_device *dev) { struct m_can_classdev *cdev = netdev_priv(dev); @@ -1660,10 +1687,10 @@ static int m_can_open(struct net_device *dev) err = request_threaded_irq(dev->irq, NULL, m_can_isr, IRQF_ONESHOT, dev->name, dev); - } else { + } + if (dev->irq > 0) err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name, dev); - } if (err < 0) { netdev_err(dev, "failed to request interrupt\n"); @@ -1851,6 +1878,9 @@ int m_can_class_register(struct m_can_classdev *m_can_dev) goto clk_disable; } + if (m_can_dev->net->irq == 0) + m_can_dev->hrtimer.function = &hrtimer_callback; + devm_can_led_init(m_can_dev->net); of_can_transceiver(m_can_dev->net); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 8cad1235afa0..7ed217b777db 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -12,6 +12,7 @@ #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/freezer.h> +#include <linux/hrtimer.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/clk.h> @@ -98,6 +99,8 @@ struct m_can_classdev { int is_peripheral; struct mram_cfg mcfg[MRAM_CFG_NUM]; + + struct hrtimer hrtimer; }; struct m_can_classdev *m_can_class_allocate_dev(struct device *dev); diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c index 45910fb5145c..ab8e056e2ee7 100644 --- a/drivers/net/can/m_can/m_can_platform.c +++ b/drivers/net/can/m_can/m_can_platform.c @@ -7,6 +7,7 @@ #include <linux/platform_device.h> #include <linux/phy/phy.h> +#include <linux/hrtimer.h> #include "m_can.h" @@ -82,11 +83,27 @@ static int m_can_plat_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can"); addr = devm_ioremap_resource(&pdev->dev, res); - irq = platform_get_irq_byname(pdev, "int0"); - if (IS_ERR(addr) || irq < 0) { - ret = -EINVAL; + if (IS_ERR(addr)) { + ret = PTR_ERR(addr); goto probe_fail; } + if (device_property_present(mcan_class->dev, "interrupts") || + device_property_present(mcan_class->dev, "interrupt-names")) { + irq = platform_get_irq_byname(pdev, "int0"); + if (irq == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto probe_fail; + } + if (irq < 0) { + ret = -EINVAL; + goto probe_fail; + } + } else { + irq = 0; + dev_dbg(mcan_class->dev, "Polling enabled, initialize hrtimer"); + hrtimer_init(&mcan_class->hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL_PINNED); + } /* message ram could be shared */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram"); |