diff options
Diffstat (limited to 'drivers/net/can/m_can/m_can.c')
-rw-r--r-- | drivers/net/can/m_can/m_can.c | 34 |
1 files changed, 32 insertions, 2 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); |