Marek, can I have you Acked-by for this? Marc On 7/12/19 11:51 AM, marcel.schmidt@xxxxxxxxxxxxxxxxxxx wrote: > From: Marcel Schmidt <marcel.schmidt@xxxxxxxxxxxxxxxxxxx> > > Updates the ifi_canfd platform driver and adds an universal > interface that enables the usage of its functionalities outside of > this platform driver. > > It was implemented with respect to role models like SJA1000 or C_Can. > Therefore the driver is split into three files. > ifi_canfd_platform.c contains the platform specific implementations > and remains functional the same. ifi_canfd.c+h enables common IFI-CANFD > functionalities usable for other drivers. > > Signed-off-by: Marcel Schmidt <marcel.schmidt@xxxxxxxxxxxxxxxxxxx> > --- > drivers/net/can/ifi_canfd/Kconfig | 10 +- > drivers/net/can/ifi_canfd/Makefile | 3 +- > drivers/net/can/ifi_canfd/ifi_canfd.c | 554 ++++++------------ > drivers/net/can/ifi_canfd/ifi_canfd.h | 341 +++++++++++ > .../net/can/ifi_canfd/ifi_canfd_platform.c | 121 ++++ > 5 files changed, 639 insertions(+), 390 deletions(-) > create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd.h > create mode 100644 drivers/net/can/ifi_canfd/ifi_canfd_platform.c > > diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig > index ce0197641a59..22f5d8322a2e 100644 > --- a/drivers/net/can/ifi_canfd/Kconfig > +++ b/drivers/net/can/ifi_canfd/Kconfig > @@ -1,9 +1,15 @@ > # SPDX-License-Identifier: GPL-2.0-only > -config CAN_IFI_CANFD > +menuconfig CAN_IFI_CANFD > + tristate "IFI_CAN_FD devices" > depends on HAS_IOMEM > - tristate "IFI CAN_FD IP" > + > +if CAN_IFI_CANFD > + > +config CAN_IFI_CANFD_PLATFORM > + tristate "Generic Platform Bus based IFI CAN_FD driver" > ---help--- > This driver adds support for the I/F/I CAN_FD soft IP block > connected to the "platform bus" (Linux abstraction for directly > to the processor attached devices). The CAN_FD is most often > synthesised into an FPGA or CPLD. > +endif > diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile > index 0cd724f10d1e..8d58c38975a5 100644 > --- a/drivers/net/can/ifi_canfd/Makefile > +++ b/drivers/net/can/ifi_canfd/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0-only > # > -# Makefile for the IFI CANFD controller driver. > +# Makefile for the IFI CANFD controller drivers. > # > > obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o > +obj-$(CONFIG_CAN_IFI_CANFD_PLATFORM) += ifi_canfd_platform.o > diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c > index fedd927ba6ed..706e0c267c1e 100644 > --- a/drivers/net/can/ifi_canfd/ifi_canfd.c > +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c > @@ -23,207 +23,36 @@ > #include <linux/platform_device.h> > > #include <linux/can/dev.h> > +#include "ifi_canfd.h" > > -#define IFI_CANFD_STCMD 0x0 > -#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD > -#define IFI_CANFD_STCMD_ENABLE BIT(0) > -#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2) > -#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3) > -#define IFI_CANFD_STCMD_BUSOFF BIT(4) > -#define IFI_CANFD_STCMD_ERROR_WARNING BIT(5) > -#define IFI_CANFD_STCMD_BUSMONITOR BIT(16) > -#define IFI_CANFD_STCMD_LOOPBACK BIT(18) > -#define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) > -#define IFI_CANFD_STCMD_ENABLE_ISO BIT(25) > -#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING BIT(26) > -#define IFI_CANFD_STCMD_NORMAL_MODE ((u32)BIT(31)) > - > -#define IFI_CANFD_RXSTCMD 0x4 > -#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0) > -#define IFI_CANFD_RXSTCMD_RESET BIT(7) > -#define IFI_CANFD_RXSTCMD_EMPTY BIT(8) > -#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13) > - > -#define IFI_CANFD_TXSTCMD 0x8 > -#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0) > -#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1) > -#define IFI_CANFD_TXSTCMD_RESET BIT(7) > -#define IFI_CANFD_TXSTCMD_EMPTY BIT(8) > -#define IFI_CANFD_TXSTCMD_FULL BIT(12) > -#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) > - > -#define IFI_CANFD_INTERRUPT 0xc > -#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF BIT(0) > -#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) > -#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG BIT(2) > -#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC BIT(3) > -#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) > -#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) > -#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) > -#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24) > -#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25) > -#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31)) > - > -#define IFI_CANFD_IRQMASK 0x10 > -#define IFI_CANFD_IRQMASK_ERROR_BUSOFF BIT(0) > -#define IFI_CANFD_IRQMASK_ERROR_WARNING BIT(1) > -#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG BIT(2) > -#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC BIT(3) > -#define IFI_CANFD_IRQMASK_SET_ERR BIT(7) > -#define IFI_CANFD_IRQMASK_SET_TS BIT(15) > -#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16) > -#define IFI_CANFD_IRQMASK_SET_TX BIT(23) > -#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24) > -#define IFI_CANFD_IRQMASK_SET_RX ((u32)BIT(31)) > - > -#define IFI_CANFD_TIME 0x14 > -#define IFI_CANFD_FTIME 0x18 > -#define IFI_CANFD_TIME_TIMEB_OFF 0 > -#define IFI_CANFD_TIME_TIMEA_OFF 8 > -#define IFI_CANFD_TIME_PRESCALE_OFF 16 > -#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8 25 > -#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6 28 > -#define IFI_CANFD_TIME_SET_SJW_4_12_6_6 BIT(6) > -#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6 BIT(7) > -#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6 BIT(14) > -#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6 BIT(15) > - > -#define IFI_CANFD_TDELAY 0x1c > -#define IFI_CANFD_TDELAY_DEFAULT 0xb > -#define IFI_CANFD_TDELAY_MASK 0x3fff > -#define IFI_CANFD_TDELAY_ABS BIT(14) > -#define IFI_CANFD_TDELAY_EN BIT(15) > - > -#define IFI_CANFD_ERROR 0x20 > -#define IFI_CANFD_ERROR_TX_OFFSET 0 > -#define IFI_CANFD_ERROR_TX_MASK 0xff > -#define IFI_CANFD_ERROR_RX_OFFSET 16 > -#define IFI_CANFD_ERROR_RX_MASK 0xff > - > -#define IFI_CANFD_ERRCNT 0x24 > - > -#define IFI_CANFD_SUSPEND 0x28 > - > -#define IFI_CANFD_REPEAT 0x2c > - > -#define IFI_CANFD_TRAFFIC 0x30 > - > -#define IFI_CANFD_TSCONTROL 0x34 > - > -#define IFI_CANFD_TSC 0x38 > - > -#define IFI_CANFD_TST 0x3c > - > -#define IFI_CANFD_RES1 0x40 > - > -#define IFI_CANFD_ERROR_CTR 0x44 > -#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899 > -#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0) > -#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1) > -#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2) > -#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3) > -#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4) > -#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5) > -#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6) > -#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8) > -#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9) > -#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10) > -#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11) > -#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12) > -#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13) > -#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14) > -#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16 > -#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0xff > -#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30) > -#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31)) > - > -#define IFI_CANFD_PAR 0x48 > - > -#define IFI_CANFD_CANCLOCK 0x4c > - > -#define IFI_CANFD_SYSCLOCK 0x50 > - > -#define IFI_CANFD_VER 0x54 > -#define IFI_CANFD_VER_REV_MASK 0xff > -#define IFI_CANFD_VER_REV_MIN_SUPPORTED 0x15 > - > -#define IFI_CANFD_IP_ID 0x58 > -#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD > - > -#define IFI_CANFD_TEST 0x5c > - > -#define IFI_CANFD_RXFIFO_TS_63_32 0x60 > - > -#define IFI_CANFD_RXFIFO_TS_31_0 0x64 > - > -#define IFI_CANFD_RXFIFO_DLC 0x68 > -#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0 > -#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf > -#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4) > -#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5) > -#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6) > -#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7) > -#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8 > -#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x1ff > -#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24 > -#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff > - > -#define IFI_CANFD_RXFIFO_ID 0x6c > -#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0 > -#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK CAN_SFF_MASK > -#define IFI_CANFD_RXFIFO_ID_ID_STD_OFFSET 0 > -#define IFI_CANFD_RXFIFO_ID_ID_STD_WIDTH 10 > -#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK > -#define IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET 11 > -#define IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH 18 > -#define IFI_CANFD_RXFIFO_ID_IDE BIT(29) > - > -#define IFI_CANFD_RXFIFO_DATA 0x70 /* 0x70..0xac */ > - > -#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0 > - > -#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4 > - > -#define IFI_CANFD_TXFIFO_DLC 0xb8 > -#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0 > -#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf > -#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4) > -#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5) > -#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6) > -#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24 > -#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff > - > -#define IFI_CANFD_TXFIFO_ID 0xbc > -#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0 > -#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK CAN_SFF_MASK > -#define IFI_CANFD_TXFIFO_ID_ID_STD_OFFSET 0 > -#define IFI_CANFD_TXFIFO_ID_ID_STD_WIDTH 10 > -#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK > -#define IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET 11 > -#define IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH 18 > -#define IFI_CANFD_TXFIFO_ID_IDE BIT(29) > - > -#define IFI_CANFD_TXFIFO_DATA 0xc0 /* 0xb0..0xfc */ > - > -#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0) > -#define IFI_CANFD_FILTER_MASK_EXT BIT(29) > -#define IFI_CANFD_FILTER_MASK_EDL BIT(30) > -#define IFI_CANFD_FILTER_MASK_VALID ((u32)BIT(31)) > - > -#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4) > -#define IFI_CANFD_FILTER_IDENT_IDE BIT(29) > -#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30) > -#define IFI_CANFD_FILTER_IDENT_VALID ((u32)BIT(31)) > - > -/* IFI CANFD private data structure */ > -struct ifi_canfd_priv { > - struct can_priv can; /* must be the first member */ > - struct napi_struct napi; > - struct net_device *ndev; > - void __iomem *base; > +static const struct can_bittiming_const ifi_canfd_bittiming_const = { > + .name = KBUILD_MODNAME, > + .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ > + .tseg1_max = 256, > + .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ > + .tseg2_max = 256, > + .sjw_max = 128, > + .brp_min = 2, > + .brp_max = 512, > + .brp_inc = 1, > }; > > -static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable) > +static void ifi_canfd_irq_clear(struct net_device *ndev) > +{ > + struct ifi_canfd_priv *priv = netdev_priv(ndev); > + u32 ifi_reg_status = readl(priv->base + IFI_CANFD_INTERRUPT); > + > + /* Clear pending IFI CAN controller interrupts */ > + writel(ifi_reg_status, priv->base + IFI_CANFD_INTERRUPT); > + > + /* Unlock, reset and enable the error counter. */ > + writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC, > + priv->base + IFI_CANFD_ERROR_CTR); > + writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); > + writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); > +} > + > +void ifi_canfd_irq_enable(struct net_device *ndev, bool enable, u8 clear) > { > struct ifi_canfd_priv *priv = netdev_priv(ndev); > u32 enirq = 0; > @@ -243,8 +72,87 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable) > IFI_CANFD_IRQMASK_SET_TX | > IFI_CANFD_IRQMASK_SET_RX | enirq, > priv->base + IFI_CANFD_IRQMASK); > + > + if (clear) > + ifi_canfd_irq_clear(ndev); > +} > +EXPORT_SYMBOL_GPL(ifi_canfd_irq_enable); > + > +static void ifi_canfd_set_bittiming(struct net_device *ndev) > +{ > + struct ifi_canfd_priv *priv = netdev_priv(ndev); > + const struct can_bittiming *bt = &priv->can.bittiming; > + const struct can_bittiming *dbt = &priv->can.data_bittiming; > + u16 brp, sjw, tseg1, tseg2, tdc; > + > + /* Configure bit timing */ > + brp = bt->brp - 2; > + sjw = bt->sjw - 1; > + tseg1 = bt->prop_seg + bt->phase_seg1 - 1; > + tseg2 = bt->phase_seg2 - 2; > + writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | > + (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | > + (brp << IFI_CANFD_TIME_PRESCALE_OFF) | > + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), > + priv->base + IFI_CANFD_TIME); > + > + /* Configure data bit timing */ > + brp = dbt->brp - 2; > + sjw = dbt->sjw - 1; > + tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; > + tseg2 = dbt->phase_seg2 - 2; > + writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | > + (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | > + (brp << IFI_CANFD_TIME_PRESCALE_OFF) | > + (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), > + priv->base + IFI_CANFD_FTIME); > + > + /* Configure transmitter delay */ > + tdc = dbt->brp * (dbt->prop_seg + dbt->phase_seg1); > + tdc &= IFI_CANFD_TDELAY_MASK; > + writel(IFI_CANFD_TDELAY_EN | tdc, priv->base + IFI_CANFD_TDELAY); > } > > +static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id, > + bool enable, u32 mask, u32 ident) > +{ > + struct ifi_canfd_priv *priv = netdev_priv(ndev); > + > + if (!enable) { > + mask = 0; > + ident = 0; > + } > + > + writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id)); > + writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id)); > +} > + > +void ifi_canfd_set_filters(struct net_device *ndev, bool enable) > +{ > + /* Receive all CAN frames (standard ID) */ > + ifi_canfd_set_filter(ndev, 0, enable, > + IFI_CANFD_FILTER_MASK_VALID | > + IFI_CANFD_FILTER_MASK_EXT, > + IFI_CANFD_FILTER_IDENT_VALID); > + > + /* Receive all CAN frames (extended ID) */ > + ifi_canfd_set_filter(ndev, 1, enable, > + IFI_CANFD_FILTER_MASK_VALID | > + IFI_CANFD_FILTER_MASK_EXT, > + IFI_CANFD_FILTER_IDENT_VALID | > + IFI_CANFD_FILTER_IDENT_IDE); > + > + /* Receive all CANFD frames */ > + ifi_canfd_set_filter(ndev, 2, enable, > + IFI_CANFD_FILTER_MASK_VALID | > + IFI_CANFD_FILTER_MASK_EDL | > + IFI_CANFD_FILTER_MASK_EXT, > + IFI_CANFD_FILTER_IDENT_VALID | > + IFI_CANFD_FILTER_IDENT_CANFD | > + IFI_CANFD_FILTER_IDENT_IDE); > +} > +EXPORT_SYMBOL_GPL(ifi_canfd_set_filters); > + > static void ifi_canfd_read_fifo(struct net_device *ndev) > { > struct net_device_stats *stats = &ndev->stats; > @@ -480,7 +388,7 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev, > case CAN_STATE_BUS_OFF: > /* bus-off state */ > priv->can.state = CAN_STATE_BUS_OFF; > - ifi_canfd_irq_enable(ndev, 0); > + ifi_canfd_irq_enable(ndev, 0, 0); > priv->can.can_stats.bus_off++; > can_bus_off(ndev); > break; > @@ -566,7 +474,7 @@ static int ifi_canfd_handle_state_errors(struct net_device *ndev) > return work_done; > } > > -static int ifi_canfd_poll(struct napi_struct *napi, int quota) > +int ifi_canfd_poll(struct napi_struct *napi, int quota) > { > struct net_device *ndev = napi->dev; > struct ifi_canfd_priv *priv = netdev_priv(ndev); > @@ -590,13 +498,14 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) > > if (work_done < quota) { > napi_complete_done(napi, work_done); > - ifi_canfd_irq_enable(ndev, 1); > + ifi_canfd_irq_enable(ndev, 1, 0); > } > > return work_done; > } > +EXPORT_SYMBOL_GPL(ifi_canfd_poll); > > -static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) > +irqreturn_t ifi_canfd_isr(int irq, void *dev_id) > { > struct net_device *ndev = (struct net_device *)dev_id; > struct ifi_canfd_priv *priv = netdev_priv(ndev); > @@ -612,6 +521,9 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) > const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ); > u32 isr; > > + if (priv->pre_irq) > + priv->pre_irq(priv); > + > isr = readl(priv->base + IFI_CANFD_INTERRUPT); > > /* No interrupt */ > @@ -623,7 +535,7 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) > > /* RX IRQ or bus warning, start NAPI */ > if (isr & rx_irq_mask) { > - ifi_canfd_irq_enable(ndev, 0); > + ifi_canfd_irq_enable(ndev, 0, 0); > napi_schedule(&priv->napi); > } > > @@ -637,88 +549,10 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) > if (isr & tx_irq_mask) > netif_wake_queue(ndev); > > - return IRQ_HANDLED; > -} > - > -static const struct can_bittiming_const ifi_canfd_bittiming_const = { > - .name = KBUILD_MODNAME, > - .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ > - .tseg1_max = 256, > - .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ > - .tseg2_max = 256, > - .sjw_max = 128, > - .brp_min = 2, > - .brp_max = 512, > - .brp_inc = 1, > -}; > - > -static void ifi_canfd_set_bittiming(struct net_device *ndev) > -{ > - struct ifi_canfd_priv *priv = netdev_priv(ndev); > - const struct can_bittiming *bt = &priv->can.bittiming; > - const struct can_bittiming *dbt = &priv->can.data_bittiming; > - u16 brp, sjw, tseg1, tseg2, tdc; > + if (priv->post_irq) > + priv->post_irq(priv); > > - /* Configure bit timing */ > - brp = bt->brp - 2; > - sjw = bt->sjw - 1; > - tseg1 = bt->prop_seg + bt->phase_seg1 - 1; > - tseg2 = bt->phase_seg2 - 2; > - writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | > - (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | > - (brp << IFI_CANFD_TIME_PRESCALE_OFF) | > - (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), > - priv->base + IFI_CANFD_TIME); > - > - /* Configure data bit timing */ > - brp = dbt->brp - 2; > - sjw = dbt->sjw - 1; > - tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; > - tseg2 = dbt->phase_seg2 - 2; > - writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) | > - (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) | > - (brp << IFI_CANFD_TIME_PRESCALE_OFF) | > - (sjw << IFI_CANFD_TIME_SJW_OFF_7_9_8_8), > - priv->base + IFI_CANFD_FTIME); > - > - /* Configure transmitter delay */ > - tdc = dbt->brp * (dbt->prop_seg + dbt->phase_seg1); > - tdc &= IFI_CANFD_TDELAY_MASK; > - writel(IFI_CANFD_TDELAY_EN | tdc, priv->base + IFI_CANFD_TDELAY); > -} > - > -static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id, > - const u32 mask, const u32 ident) > -{ > - struct ifi_canfd_priv *priv = netdev_priv(ndev); > - > - writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id)); > - writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id)); > -} > - > -static void ifi_canfd_set_filters(struct net_device *ndev) > -{ > - /* Receive all CAN frames (standard ID) */ > - ifi_canfd_set_filter(ndev, 0, > - IFI_CANFD_FILTER_MASK_VALID | > - IFI_CANFD_FILTER_MASK_EXT, > - IFI_CANFD_FILTER_IDENT_VALID); > - > - /* Receive all CAN frames (extended ID) */ > - ifi_canfd_set_filter(ndev, 1, > - IFI_CANFD_FILTER_MASK_VALID | > - IFI_CANFD_FILTER_MASK_EXT, > - IFI_CANFD_FILTER_IDENT_VALID | > - IFI_CANFD_FILTER_IDENT_IDE); > - > - /* Receive all CANFD frames */ > - ifi_canfd_set_filter(ndev, 2, > - IFI_CANFD_FILTER_MASK_VALID | > - IFI_CANFD_FILTER_MASK_EDL | > - IFI_CANFD_FILTER_MASK_EXT, > - IFI_CANFD_FILTER_IDENT_VALID | > - IFI_CANFD_FILTER_IDENT_CANFD | > - IFI_CANFD_FILTER_IDENT_IDE); > + return IRQ_HANDLED; > } > > static void ifi_canfd_start(struct net_device *ndev) > @@ -732,7 +566,7 @@ static void ifi_canfd_start(struct net_device *ndev) > priv->base + IFI_CANFD_STCMD); > > ifi_canfd_set_bittiming(ndev); > - ifi_canfd_set_filters(ndev); > + ifi_canfd_set_filters(ndev, 1); > > /* Reset FIFOs */ > writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD); > @@ -766,13 +600,7 @@ static void ifi_canfd_start(struct net_device *ndev) > > priv->can.state = CAN_STATE_ERROR_ACTIVE; > > - ifi_canfd_irq_enable(ndev, 1); > - > - /* Unlock, reset and enable the error counter. */ > - writel(IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC, > - priv->base + IFI_CANFD_ERROR_CTR); > - writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); > - writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); > + ifi_canfd_irq_enable(ndev, 1, 1); > > /* Enable controller */ > writel(stcmd, priv->base + IFI_CANFD_STCMD); > @@ -800,20 +628,6 @@ static void ifi_canfd_stop(struct net_device *ndev) > priv->can.state = CAN_STATE_STOPPED; > } > > -static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode) > -{ > - switch (mode) { > - case CAN_MODE_START: > - ifi_canfd_start(ndev); > - netif_wake_queue(ndev); > - break; > - default: > - return -EOPNOTSUPP; > - } > - > - return 0; > -} > - > static int ifi_canfd_open(struct net_device *ndev) > { > struct ifi_canfd_priv *priv = netdev_priv(ndev); > @@ -826,11 +640,14 @@ static int ifi_canfd_open(struct net_device *ndev) > } > > /* Register interrupt handler */ > - ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED, > - ndev->name, ndev); > - if (ret < 0) { > - netdev_err(ndev, "Failed to request interrupt\n"); > - goto err_irq; > + if (!(priv->flags & IFI_CANFD_CUSTOM_IRQ_HANDLING)) { > + ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED, > + ndev->name, ndev); > + if (ret < 0) { > + netdev_err(ndev, > + "Failed to request interrupt: %i\n", ret); > + goto err_irq; > + } > } > > ifi_canfd_start(ndev); > @@ -854,7 +671,8 @@ static int ifi_canfd_close(struct net_device *ndev) > > ifi_canfd_stop(ndev); > > - free_irq(ndev->irq, ndev); > + if (!(priv->flags & IFI_CANFD_CUSTOM_IRQ_HANDLING)) > + free_irq(ndev->irq, ndev); > > close_candev(ndev); > > @@ -937,52 +755,32 @@ static const struct net_device_ops ifi_canfd_netdev_ops = { > .ndo_change_mtu = can_change_mtu, > }; > > -static int ifi_canfd_plat_probe(struct platform_device *pdev) > +static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode) > { > - struct device *dev = &pdev->dev; > - struct net_device *ndev; > - struct ifi_canfd_priv *priv; > - struct resource *res; > - void __iomem *addr; > - int irq, ret; > - u32 id, rev; > - > - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > - addr = devm_ioremap_resource(dev, res); > - irq = platform_get_irq(pdev, 0); > - if (IS_ERR(addr) || irq < 0) > - return -EINVAL; > - > - id = readl(addr + IFI_CANFD_IP_ID); > - if (id != IFI_CANFD_IP_ID_VALUE) { > - dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id); > - return -EINVAL; > + switch (mode) { > + case CAN_MODE_START: > + ifi_canfd_start(ndev); > + netif_wake_queue(ndev); > + break; > + default: > + return -EOPNOTSUPP; > } > > - rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK; > - if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) { > - dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n", > - rev, IFI_CANFD_VER_REV_MIN_SUPPORTED); > - return -EINVAL; > - } > + return 0; > +} > > - ndev = alloc_candev(sizeof(*priv), 1); > - if (!ndev) > - return -ENOMEM; > +struct net_device *alloc_ifi_canfd_dev(int sizeof_priv, int echo_skb_max) > +{ > + struct net_device *ndev; > + struct ifi_canfd_priv *priv; > > - ndev->irq = irq; > - ndev->flags |= IFF_ECHO; /* we support local echo */ > - ndev->netdev_ops = &ifi_canfd_netdev_ops; > + ndev = alloc_candev(sizeof(struct ifi_canfd_priv) + sizeof_priv, > + echo_skb_max); > + if (!ndev) > + return NULL; > > priv = netdev_priv(ndev); > priv->ndev = ndev; > - priv->base = addr; > - > - netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64); > - > - priv->can.state = CAN_STATE_STOPPED; > - > - priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK); > > priv->can.bittiming_const = &ifi_canfd_bittiming_const; > priv->can.data_bittiming_const = &ifi_canfd_bittiming_const; > @@ -999,54 +797,36 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) > CAN_CTRLMODE_FD_NON_ISO | > CAN_CTRLMODE_BERR_REPORTING; > > - platform_set_drvdata(pdev, ndev); > - SET_NETDEV_DEV(ndev, dev); > + return ndev; > +} > +EXPORT_SYMBOL_GPL(alloc_ifi_canfd_dev); > > - ret = register_candev(ndev); > - if (ret) { > - dev_err(dev, "Failed to register (ret=%d)\n", ret); > - goto err_reg; > - } > +void free_ifi_canfd_dev(struct net_device *ndev) > +{ > + free_candev(ndev); > +} > +EXPORT_SYMBOL_GPL(free_ifi_canfd_dev); > > - devm_can_led_init(ndev); > +int register_ifi_canfd_dev(struct net_device *ndev) > +{ > + int ret; > > - dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n", > - priv->base, ndev->irq, priv->can.clock.freq); > + ndev->netdev_ops = &ifi_canfd_netdev_ops; > + ndev->flags |= IFF_ECHO; > > - return 0; > + ret = register_candev(ndev); > + if (!ret) > + devm_can_led_init(ndev); > > -err_reg: > - free_candev(ndev); > return ret; > } > +EXPORT_SYMBOL_GPL(register_ifi_canfd_dev); > > -static int ifi_canfd_plat_remove(struct platform_device *pdev) > +void unregister_ifi_canfd_dev(struct net_device *ndev) > { > - struct net_device *ndev = platform_get_drvdata(pdev); > - > unregister_candev(ndev); > - platform_set_drvdata(pdev, NULL); > - free_candev(ndev); > - > - return 0; > } > - > -static const struct of_device_id ifi_canfd_of_table[] = { > - { .compatible = "ifi,canfd-1.0", .data = NULL }, > - { /* sentinel */ }, > -}; > -MODULE_DEVICE_TABLE(of, ifi_canfd_of_table); > - > -static struct platform_driver ifi_canfd_plat_driver = { > - .driver = { > - .name = KBUILD_MODNAME, > - .of_match_table = ifi_canfd_of_table, > - }, > - .probe = ifi_canfd_plat_probe, > - .remove = ifi_canfd_plat_remove, > -}; > - > -module_platform_driver(ifi_canfd_plat_driver); > +EXPORT_SYMBOL_GPL(unregister_ifi_canfd_dev); > > MODULE_AUTHOR("Marek Vasut <marex@xxxxxxx>"); > MODULE_LICENSE("GPL v2"); > diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.h b/drivers/net/can/ifi_canfd/ifi_canfd.h > new file mode 100644 > index 000000000000..1954157615d8 > --- /dev/null > +++ b/drivers/net/can/ifi_canfd/ifi_canfd.h > @@ -0,0 +1,341 @@ > +/* > + * CAN bus driver for IFI CANFD controller > + * > + * Copyright (C) 2016 Marek Vasut <marex@xxxxxxx> > + * > + * Details about this controller can be found at > + * http://www.ifi-pld.de/IP/CANFD/canfd.html > + * > + * This file is licensed under the terms of the GNU General Public > + * License version 2. This program is licensed "as is" without any > + * warranty of any kind, whether express or implied. > + */ > +#ifndef IFI_CANFD_H_ > +#define IFI_CANFD_H_ > + > +#define IFI_CANFD_STCMD 0x0 > +#define IFI_CANFD_STCMD_HARDRESET 0xDEADCAFD > +#define IFI_CANFD_STCMD_ENABLE BIT(0) > +#define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2) > +#define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3) > +#define IFI_CANFD_STCMD_BUSOFF BIT(4) > +#define IFI_CANFD_STCMD_ERROR_WARNING BIT(5) > +#define IFI_CANFD_STCMD_BUSMONITOR BIT(16) > +#define IFI_CANFD_STCMD_LOOPBACK BIT(18) > +#define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) > +#define IFI_CANFD_STCMD_ENABLE_ISO BIT(25) > +#define IFI_CANFD_STCMD_ENABLE_7_9_8_8_TIMING BIT(26) > +#define IFI_CANFD_STCMD_NORMAL_MODE ((u32)BIT(31)) > + > +#define IFI_CANFD_RXSTCMD 0x4 > +#define IFI_CANFD_RXSTCMD_REMOVE_MSG BIT(0) > +#define IFI_CANFD_RXSTCMD_RESET BIT(7) > +#define IFI_CANFD_RXSTCMD_EMPTY BIT(8) > +#define IFI_CANFD_RXSTCMD_OVERFLOW BIT(13) > +#define IFI_CANFD_RXSTCMD_FIFO_NUMBER 0xFFFF0000 > +#define IFI_CANFD_RXSTCMD_FIFO_NUMBER_OFF 16 > + > +#define IFI_CANFD_TXSTCMD 0x8 > +#define IFI_CANFD_TXSTCMD_ADD_MSG BIT(0) > +#define IFI_CANFD_TXSTCMD_HIGH_PRIO BIT(1) > +#define IFI_CANFD_TXSTCMD_REMOVE_PEND_MSG BIT(6) > +#define IFI_CANFD_TXSTCMD_RESET BIT(7) > +#define IFI_CANFD_TXSTCMD_EMPTY BIT(8) > +#define IFI_CANFD_TXSTCMD_FULL BIT(12) > +#define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) > + > +#define IFI_CANFD_INTERRUPT 0xc > +#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF BIT(0) > +#define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) > +#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG BIT(2) > +#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC BIT(3) > +#define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) > +#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) > +#define IFI_CANFD_INTERRUPT_TXFIFO_OVERFLOW BIT(21) > +#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) > +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY BIT(24) > +#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER BIT(25) > +#define IFI_CANFD_INTERRUPT_RXFIFO_OVERFLOW BIT(30) > +#define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31)) > + > +#define IFI_CANFD_IRQMASK 0x10 > +#define IFI_CANFD_IRQMASK_ERROR_BUSOFF BIT(0) > +#define IFI_CANFD_IRQMASK_ERROR_WARNING BIT(1) > +#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG BIT(2) > +#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC BIT(3) > +#define IFI_CANFD_IRQMASK_SET_ERR BIT(7) > +#define IFI_CANFD_IRQMASK_SET_TS BIT(15) > +#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16) > +#define IFI_CANFD_IRQMASK_SET_TX BIT(23) > +#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY BIT(24) > +#define IFI_CANFD_IRQMASK_RXFIFO_OVERFLOW BIT(30) > +#define IFI_CANFD_IRQMASK_SET_RX ((u32)BIT(31)) > + > +#define IFI_CANFD_TIME 0x14 > +#define IFI_CANFD_FTIME 0x18 > +#define IFI_CANFD_TIME_TIMEB_OFF 0 > +#define IFI_CANFD_TIME_TIMEA_OFF 8 > +#define IFI_CANFD_TIME_PRESCALE_OFF 16 > +#define IFI_CANFD_TIME_SJW_OFF_7_9_8_8 25 > +#define IFI_CANFD_TIME_SJW_OFF_4_12_6_6 28 > +#define IFI_CANFD_TIME_SET_SJW_4_12_6_6 BIT(6) > +#define IFI_CANFD_TIME_SET_TIMEB_4_12_6_6 BIT(7) > +#define IFI_CANFD_TIME_SET_PRESC_4_12_6_6 BIT(14) > +#define IFI_CANFD_TIME_SET_TIMEA_4_12_6_6 BIT(15) > + > +#define IFI_CANFD_TDELAY 0x1c > +#define IFI_CANFD_TDELAY_DEFAULT 0xb > +#define IFI_CANFD_TDELAY_MASK 0x3fff > +#define IFI_CANFD_TDELAY_ABS BIT(14) > +#define IFI_CANFD_TDELAY_EN BIT(15) > + > +#define IFI_CANFD_ERROR 0x20 > +#define IFI_CANFD_ERROR_TX_OFFSET 0 > +#define IFI_CANFD_ERROR_TX_MASK 0xff > +#define IFI_CANFD_ERROR_RX_OFFSET 16 > +#define IFI_CANFD_ERROR_RX_MASK 0xff > + > +#define IFI_CANFD_ERRCNT 0x24 > + > +#define IFI_CANFD_SUSPEND 0x28 > + > +#define IFI_CANFD_REPEAT 0x2c > + > +#define IFI_CANFD_TRAFFIC 0x30 > + > +#define IFI_CANFD_TSCONTROL 0x34 > + > +#define IFI_CANFD_TSC 0x38 > + > +#define IFI_CANFD_TST 0x3c > + > +#define IFI_CANFD_RES1 0x40 > + > +#define IFI_CANFD_ERROR_CTR 0x44 > +#define IFI_CANFD_ERROR_CTR_UNLOCK_MAGIC 0x21302899 > +#define IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST BIT(0) > +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST BIT(1) > +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST BIT(2) > +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST BIT(3) > +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST BIT(4) > +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST BIT(5) > +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST BIT(6) > +#define IFI_CANFD_ERROR_CTR_OVERLOAD_ALL BIT(8) > +#define IFI_CANFD_ERROR_CTR_ACK_ERROR_ALL BIT(9) > +#define IFI_CANFD_ERROR_CTR_BIT0_ERROR_ALL BIT(10) > +#define IFI_CANFD_ERROR_CTR_BIT1_ERROR_ALL BIT(11) > +#define IFI_CANFD_ERROR_CTR_STUFF_ERROR_ALL BIT(12) > +#define IFI_CANFD_ERROR_CTR_CRC_ERROR_ALL BIT(13) > +#define IFI_CANFD_ERROR_CTR_FORM_ERROR_ALL BIT(14) > +#define IFI_CANFD_ERROR_CTR_BITPOSITION_OFFSET 16 > +#define IFI_CANFD_ERROR_CTR_ERROR_FIRST_MASK 0x000000FF > +#define IFI_CANFD_ERROR_CTR_ERROR_ALL_MASK 0x00007F00 > +#define IFI_CANFD_ERROR_CTR_BITPOSITION_MASK 0x03ff0000 > +#define IFI_CANFD_ERROR_CTR_ERRORFRAME_RESET BIT(26) > +#define IFI_CANFD_ERROR_CTR_OVERLOAD_RESET BIT(27) > +#define IFI_CANFD_ERROR_CTR_ERRORFRAME_PEND BIT(28) > +#define IFI_CANFD_ERROR_CTR_OVERLOAD_PEND BIT(29) > +#define IFI_CANFD_ERROR_CTR_ER_RESET BIT(30) > +#define IFI_CANFD_ERROR_CTR_ER_ENABLE ((u32)BIT(31)) > + > +#define IFI_CANFD_PAR 0x48 > +#define IFI_CANFD_PAR_TX_SIZE 0x000000FF > +#define IFI_CANFD_PAR_RX_SIZE 0x0000FF00 > +#define IFI_CANFD_PAR_SINGLE_CLOCK BIT(16) > +#define IFI_CANFD_PAR_NO_TSTAMP BIT(17) > +#define IFI_CANFD_PAR_NO_FILTER BIT(18) > +#define IFI_CANFD_PAR_NO_BUSSTAT BIT(19) > + > +#define IFI_CANFD_CANCLOCK 0x4c > + > +#define IFI_CANFD_SYSCLOCK 0x50 > + > +#define IFI_CANFD_VER 0x54 > +#define IFI_CANFD_VER_REV_MASK 0xff > +#define IFI_CANFD_VER_REV_MIN_SUPPORTED 0x15 > + > +#define IFI_CANFD_IP_ID 0x58 > +#define IFI_CANFD_IP_ID_VALUE 0xD073CAFD > + > +#define IFI_CANFD_TEST 0x5c > + > +#define IFI_CANFD_RXFIFO_TS_63_32 0x60 > + > +#define IFI_CANFD_RXFIFO_TS_31_0 0x64 > + > +#define IFI_CANFD_RXFIFO_DLC 0x68 > +#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET 0 > +#define IFI_CANFD_RXFIFO_DLC_DLC_MASK 0xf > +#define IFI_CANFD_RXFIFO_DLC_RTR BIT(4) > +#define IFI_CANFD_RXFIFO_DLC_EDL BIT(5) > +#define IFI_CANFD_RXFIFO_DLC_BRS BIT(6) > +#define IFI_CANFD_RXFIFO_DLC_ESI BIT(7) > +#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET 8 > +#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK 0x0001ff00 > +#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET 24 > +#define IFI_CANFD_RXFIFO_DLC_FNR_MASK 0xff000000 > + > +#define IFI_CANFD_RXFIFO_ID 0x6c > +#define IFI_CANFD_RXFIFO_ID_ID_OFFSET 0 > +#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK CAN_SFF_MASK > +#define IFI_CANFD_RXFIFO_ID_ID_STD_OFFSET 0 > +#define IFI_CANFD_RXFIFO_ID_ID_STD_WIDTH 10 > +#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK > +#define IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET 11 > +#define IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH 18 > +#define IFI_CANFD_RXFIFO_ID_IDE BIT(29) > + > +#define IFI_CANFD_RXFIFO_DATA 0x70 > + > +#define IFI_CANFD_TXFIFO_SUSPEND_US 0xb0 > + > +#define IFI_CANFD_TXFIFO_REPEATCOUNT 0xb4 > + > +#define IFI_CANFD_TXFIFO_DLC 0xb8 > +#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET 0 > +#define IFI_CANFD_TXFIFO_DLC_DLC_MASK 0xf > +#define IFI_CANFD_TXFIFO_DLC_RTR BIT(4) > +#define IFI_CANFD_TXFIFO_DLC_EDL BIT(5) > +#define IFI_CANFD_TXFIFO_DLC_BRS BIT(6) > +#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET 24 > +#define IFI_CANFD_TXFIFO_DLC_FNR_MASK 0xff > + > +#define IFI_CANFD_TXFIFO_ID 0xbc > +#define IFI_CANFD_TXFIFO_ID_ID_OFFSET 0 > +#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK CAN_SFF_MASK > +#define IFI_CANFD_TXFIFO_ID_ID_STD_OFFSET 0 > +#define IFI_CANFD_TXFIFO_ID_ID_STD_WIDTH 10 > +#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK CAN_EFF_MASK > +#define IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET 11 > +#define IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH 18 > +#define IFI_CANFD_TXFIFO_ID_IDE BIT(29) > + > +#define IFI_CANFD_TXFIFO_DATA 0xc0 > + > +#define IFI_CANFD_FILTER_MASK(n) (0x800 + ((n) * 8) + 0) > +#define IFI_CANFD_FILTER_MASK_EXT BIT(29) > +#define IFI_CANFD_FILTER_MASK_EDL BIT(30) > +#define IFI_CANFD_FILTER_MASK_VALID ((u32)BIT(31)) > + > +#define IFI_CANFD_FILTER_IDENT(n) (0x800 + ((n) * 8) + 4) > +#define IFI_CANFD_FILTER_IDENT_IDE BIT(29) > +#define IFI_CANFD_FILTER_IDENT_CANFD BIT(30) > +#define IFI_CANFD_FILTER_IDENT_VALID ((u32)BIT(31)) > + > +#define IFI_CANFD_CUSTOM_IRQ_HANDLING 0x1 > + > +/** > + * struct ifi_canfd_priv - IFI CANFD device > + * @can: CAN common private data > + * @napi: Structure for NAPI scheduling > + * @ndev: Network Device data > + * @base: Base address > + * @priv: additional field for device specific specific programming > + * @flags: Custom mode flags > + * @pre_irq: function pointers for custom pre-irq functionality > + * @post_irq: function pointers for custom post-irq functionality > + * > + * Contains common fields of an IFI CANFD device > + */ > +struct ifi_canfd_priv { > + struct can_priv can; /* must be the first member */ > + struct napi_struct napi; > + struct net_device *ndev; > + void __iomem *base; > + > + void *priv; /* custom content */ > + u16 flags; /* custom mode flags*/ > + > + void (*pre_irq)(const struct ifi_canfd_priv *priv); > + void (*post_irq)(const struct ifi_canfd_priv *priv); > +}; > + > +/** > + * ifi_canfd_irq_enable() - Enable/disable interrupt mode > + * @ndev: Network device (CAN) > + * @enable: flag 1-enable,0-disable > + * @clear: flag to clear interrupts when set to 1 > + * > + * Enables/disables/clears interrupts on request > + * > + * Return: None > + */ > +void ifi_canfd_irq_enable(struct net_device *ndev, bool enable, u8 clear); > + > +/** > + * ifi_canfd_set_filters() - Set Filter masks and IDs > + * @ndev: Network device (CAN) > + * @enable: enable/disable flag > + * > + * Sets filter masks and IDs for standard/extended CAN and CANFD frames > + * > + * Return: None > + */ > +void ifi_canfd_set_filters(struct net_device *ndev, bool enable); > + > +/** > + * ifi_canfd_poll() - NAPI polling function > + * @napi: Structure for NAPI scheduling similar to tasklet but with weighting > + * @quota: Places a limit on the amount of work the driver may do. > + * If and only if the return value is less than the budget, your driver > + * must reenable interrupts and turn off polling > + * > + * Polls driver to pick up all available packets when interrupt is serviced > + * > + * Return: No. of packets processed > + */ > +int ifi_canfd_poll(struct napi_struct *napi, int quota); > + > +/** > + * ifi_canfd_isr() > + * @irq: IRQ Number > + * @dev_id: Device ID > + * > + * This function is executed on reception of an interrupt > + * > + * Return: Interrupt handling status > + */ > +irqreturn_t ifi_canfd_isr(int irq, void *dev_id); > + > +/** > + * alloc_ifi_canfd_dev() - Allocate CAN device > + * @sizeof_priv: size of device interface > + * @echo_skb_max: max. number of sockets > + * > + * Allocates a CAN device > + * > + * Return: Network device allocated > + */ > +struct net_device *alloc_ifi_canfd_dev(int sizeof_priv, int echo_skb_max); > + > +/** > + * free_ifi_canfd_dev() - Free CAN device > + * @ndev: Network device (CAN) > + * > + * Frees previously allocated CAN device > + * > + * Return: None > + */ > +void free_ifi_canfd_dev(struct net_device *ndev); > + > +/** > + * register_ifi_canfd_dev() - Register CAN device > + * @ndev: Network device (CAN) > + * > + * Registers CAN device and sets netdev_ops structure > + * > + * Return: return code register_candev > + */ > +int register_ifi_canfd_dev(struct net_device *ndev); > + > +/** > + * unregister_ifi_canfd_dev() - Unregister CAN device > + * @ndev: Network device (CAN) > + * > + * Unregisters CAN device > + * > + * Return: None > + */ > +void unregister_ifi_canfd_dev(struct net_device *ndev); > + > +#endif /* IFI_CANFD_H_ */ > diff --git a/drivers/net/can/ifi_canfd/ifi_canfd_platform.c b/drivers/net/can/ifi_canfd/ifi_canfd_platform.c > new file mode 100644 > index 000000000000..2bbcfc2d77ce > --- /dev/null > +++ b/drivers/net/can/ifi_canfd/ifi_canfd_platform.c > @@ -0,0 +1,121 @@ > +/* > + * CAN bus driver for IFI CANFD controller > + * > + * Copyright (C) 2016 Marek Vasut <marex@xxxxxxx> > + * > + * Details about this controller can be found at > + * http://www.ifi-pld.de/IP/CANFD/canfd.html > + * > + * This file is licensed under the terms of the GNU General Public > + * License version 2. This program is licensed "as is" without any > + * warranty of any kind, whether express or implied. > + */ > +#include <linux/clk.h> > +#include <linux/delay.h> > +#include <linux/interrupt.h> > +#include <linux/io.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/netdevice.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/platform_device.h> > + > +#include <linux/can/dev.h> > +#include "ifi_canfd.h" > + > +static int ifi_canfd_plat_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct net_device *ndev; > + struct ifi_canfd_priv *priv; > + struct resource *res; > + void __iomem *addr; > + int irq, ret; > + u32 id, rev; > + > + dev_err(dev, "IFI-FD Probe start\n"); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + addr = devm_ioremap_resource(dev, res); > + irq = platform_get_irq(pdev, 0); > + if (IS_ERR(addr) || irq < 0) > + return -EINVAL; > + > + id = readl(addr + IFI_CANFD_IP_ID); > + if (id != IFI_CANFD_IP_ID_VALUE) { > + dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id); > + return -EINVAL; > + } > + > + rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK; > + if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) { > + dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n", > + rev, IFI_CANFD_VER_REV_MIN_SUPPORTED); > + return -EINVAL; > + } > + > + ndev = alloc_ifi_canfd_dev(0, 1); > + if (!ndev) > + return -ENOMEM; > + > + priv = netdev_priv(ndev); > + > + priv->can.state = CAN_STATE_STOPPED; > + priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK); > + > + ndev->irq = irq; > + priv->base = addr; > + > + netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64); > + > + platform_set_drvdata(pdev, ndev); > + SET_NETDEV_DEV(ndev, dev); > + > + ret = register_ifi_canfd_dev(ndev); > + if (ret) { > + dev_err(dev, "Failed to register (ret=%d)\n", ret); > + goto err_reg; > + } > + > + dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n", > + priv->base, ndev->irq, priv->can.clock.freq); > + > + return 0; > + > +err_reg: > + free_ifi_canfd_dev(ndev); > + return ret; > +} > + > +static int ifi_canfd_plat_remove(struct platform_device *pdev) > +{ > + struct net_device *ndev = platform_get_drvdata(pdev); > + > + unregister_ifi_canfd_dev(ndev); > + platform_set_drvdata(pdev, NULL); > + free_ifi_canfd_dev(ndev); > + > + return 0; > +} > + > +static const struct of_device_id ifi_canfd_of_table[] = { > + { .compatible = "ifi,canfd-1.0", .data = NULL }, > + { /* sentinel */ }, > +}; > +MODULE_DEVICE_TABLE(of, ifi_canfd_of_table); > + > +static struct platform_driver ifi_canfd_plat_driver = { > + .driver = { > + .name = KBUILD_MODNAME, > + .of_match_table = ifi_canfd_of_table, > + }, > + .probe = ifi_canfd_plat_probe, > + .remove = ifi_canfd_plat_remove, > +}; > + > +module_platform_driver(ifi_canfd_plat_driver); > + > +MODULE_AUTHOR("Marek Vasut <marex@xxxxxxx>"); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller"); > -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Attachment:
signature.asc
Description: OpenPGP digital signature