Commit 185f690f authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-5.15-20210819' of...

Merge tag 'linux-can-next-for-5.15-20210819' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
linux-can-next-for-5.15-20210819

The first patch is by me, for the mailmap file and maps the email
address of two former ESD employees to a newly created role account.

The next 3 patches are by Oleksij Rempel and add support for GPIO
based switchable CAN bus termination.

The next 3 patches are by Vincent Mailhol. The first one changes the
CAN netlink interface to not bail out if the user switched off
unsupported features. The next one adds Vincent as the maintainer of
the etas_es58x driver and the last one cleans up the documentation of
struct es58x_fd_tx_conf_msg.

The next patch is by me, for the mcp251xfd driver and marks some
instances of struct mcp251xfd_priv as const. Lad Prabhakar contributes
2 patches for the rcar_canfd driver, that add support for RZ/G2L
family.

The next 5 patches target the m_can/tcan45x5 driver. 2 are by me an
fix trivial checkpatch warnings. The remaining 3 patches are by Matt
Kline and improve the performance on the SPI based tcan4x5x chip by
batching FIFO reads and writes.

The last 7 patches are for the c_can driver. Dario Binacchi's patch
converts the DT bindings to yaml, 2 patches by me fix a typo and
rename a macro to properly represent the usage. The last 4 patches are
again by Dario Binacchi and provide a performance improvement for the
TX path by operating the TX mailboxes as a true FIFO.

* tag 'linux-can-next-for-5.15-20210819' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: (22 commits)
  can: c_can: cache frames to operate as a true FIFO
  can: c_can: support tx ring algorithm
  can: c_can: exit c_can_do_tx() early if no frames have been sent
  can: c_can: remove struct c_can_priv::priv field
  can: c_can: rename IF_RX -> IF_NAPI
  can: c_can: c_can_do_tx(): fix typo in comment
  dt-bindings: net: can: c_can: convert to json-schema
  can: m_can: Batch FIFO writes during CAN transmit
  can: m_can: Batch FIFO reads during CAN receive
  can: m_can: Disable IRQs on FIFO bus errors
  can: m_can: fix block comment style
  can: tcan4x5x: cdev_to_priv(): remove stray empty line
  can: rcar_canfd: Add support for RZ/G2L family
  dt-bindings: net: can: renesas,rcar-canfd: Document RZ/G2L SoC
  can: mcp251xfd: mark some instances of struct mcp251xfd_priv as const
  can: etas_es58x: clean-up documentation of struct es58x_fd_tx_conf_msg
  MAINTAINERS: add Vincent MAILHOL as maintainer for the ETAS ES58X CAN/USB driver
  can: netlink: allow user to turn off unsupported features
  can: dev: provide optional GPIO based termination support
  dt-bindings: can: fsl,flexcan: enable termination-* bindings
  ...
====================

Link: https://lore.kernel.org/r/20210819133913.657715-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 5c8a2bb4 387da6bc
...@@ -229,6 +229,7 @@ Matthew Wilcox <willy@infradead.org> <mawilcox@microsoft.com> ...@@ -229,6 +229,7 @@ Matthew Wilcox <willy@infradead.org> <mawilcox@microsoft.com>
Matthew Wilcox <willy@infradead.org> <willy@debian.org> Matthew Wilcox <willy@infradead.org> <willy@debian.org>
Matthew Wilcox <willy@infradead.org> <willy@linux.intel.com> Matthew Wilcox <willy@infradead.org> <willy@linux.intel.com>
Matthew Wilcox <willy@infradead.org> <willy@parisc-linux.org> Matthew Wilcox <willy@infradead.org> <willy@parisc-linux.org>
Matthias Fuchs <socketcan@esd.eu> <matthias.fuchs@esd.eu>
Matthieu CASTET <castet.matthieu@free.fr> Matthieu CASTET <castet.matthieu@free.fr>
Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting> Matt Ranostay <matt.ranostay@konsulko.com> <matt@ranostay.consulting>
Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com> Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com>
...@@ -341,6 +342,7 @@ Sumit Semwal <sumit.semwal@ti.com> ...@@ -341,6 +342,7 @@ Sumit Semwal <sumit.semwal@ti.com>
Takashi YOSHII <takashi.yoshii.zj@renesas.com> Takashi YOSHII <takashi.yoshii.zj@renesas.com>
Tejun Heo <htejun@gmail.com> Tejun Heo <htejun@gmail.com>
Thomas Graf <tgraf@suug.ch> Thomas Graf <tgraf@suug.ch>
Thomas Körper <socketcan@esd.eu> <thomas.koerper@esd.eu>
Thomas Pedersen <twp@codeaurora.org> Thomas Pedersen <twp@codeaurora.org>
Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com> Tiezhu Yang <yangtiezhu@loongson.cn> <kernelpatch@126.com>
Todor Tomov <todor.too@gmail.com> <todor.tomov@linaro.org> Todor Tomov <todor.too@gmail.com> <todor.tomov@linaro.org>
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/can/bosch,c_can.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch C_CAN/D_CAN controller Device Tree Bindings
description: Bosch C_CAN/D_CAN controller for CAN bus
maintainers:
- Dario Binacchi <dariobin@libero.it>
allOf:
- $ref: can-controller.yaml#
properties:
compatible:
oneOf:
- enum:
- bosch,c_can
- bosch,d_can
- ti,dra7-d_can
- ti,am3352-d_can
- items:
- enum:
- ti,am4372-d_can
- const: ti,am3352-d_can
reg:
maxItems: 1
interrupts:
minItems: 1
maxItems: 4
power-domains:
description: |
Should contain a phandle to a PM domain provider node and an args
specifier containing the DCAN device id value. It's mandatory for
Keystone 2 66AK2G SoCs only.
maxItems: 1
clocks:
description: |
CAN functional clock phandle.
maxItems: 1
clock-names:
maxItems: 1
syscon-raminit:
description: |
Handle to system control region that contains the RAMINIT register,
register offset to the RAMINIT register and the CAN instance number (0
offset).
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: The phandle to the system control region.
- description: The register offset.
- description: The CAN instance number.
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
if:
properties:
compatible:
contains:
enum:
- bosch,d_can
then:
properties:
interrupts:
minItems: 4
maxItems: 4
items:
- description: Error and status IRQ
- description: Message object IRQ
- description: RAM ECC correctable error IRQ
- description: RAM ECC non-correctable error IRQ
else:
properties:
interrupts:
maxItems: 1
items:
- description: Error and status IRQ
additionalProperties: false
examples:
- |
#include <dt-bindings/reset/altr,rst-mgr.h>
can@ffc00000 {
compatible = "bosch,d_can";
reg = <0xffc00000 0x1000>;
interrupts = <0 131 4>, <0 132 4>, <0 133 4>, <0 134 4>;
clocks = <&can0_clk>;
resets = <&rst CAN0_RESET>;
};
- |
can@0 {
compatible = "ti,am3352-d_can";
reg = <0x0 0x2000>;
clocks = <&dcan1_fck>;
clock-names = "fck";
syscon-raminit = <&scm_conf 0x644 1>;
interrupts = <55>;
};
Bosch C_CAN/D_CAN controller Device Tree Bindings
-------------------------------------------------
Required properties:
- compatible : Should be "bosch,c_can" for C_CAN controllers and
"bosch,d_can" for D_CAN controllers.
Can be "ti,dra7-d_can", "ti,am3352-d_can" or
"ti,am4372-d_can".
- reg : physical base address and size of the C_CAN/D_CAN
registers map
- interrupts : property with a value describing the interrupt
number
The following are mandatory properties for DRA7x, AM33xx and AM43xx SoCs only:
- ti,hwmods : Must be "d_can<n>" or "c_can<n>", n being the
instance number
The following are mandatory properties for Keystone 2 66AK2G SoCs only:
- power-domains : Should contain a phandle to a PM domain provider node
and an args specifier containing the DCAN device id
value. This property is as per the binding,
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.yaml
- clocks : CAN functional clock phandle. This property is as per the
binding,
Documentation/devicetree/bindings/clock/ti,sci-clk.yaml
Optional properties:
- syscon-raminit : Handle to system control region that contains the
RAMINIT register, register offset to the RAMINIT
register and the CAN instance number (0 offset).
Note: "ti,hwmods" field is used to fetch the base address and irq
resources from TI, omap hwmod data base during device registration.
Future plan is to migrate hwmod data base contents into device tree
blob so that, all the required data will be used from device tree dts
file.
Example:
Step1: SoC common .dtsi file
dcan1: d_can@481d0000 {
compatible = "bosch,d_can";
reg = <0x481d0000 0x2000>;
interrupts = <55>;
interrupt-parent = <&intc>;
status = "disabled";
};
(or)
dcan1: d_can@481d0000 {
compatible = "bosch,d_can";
ti,hwmods = "d_can1";
reg = <0x481d0000 0x2000>;
interrupts = <55>;
interrupt-parent = <&intc>;
status = "disabled";
};
Step 2: board specific .dts file
&dcan1 {
status = "okay";
};
...@@ -13,6 +13,15 @@ properties: ...@@ -13,6 +13,15 @@ properties:
$nodename: $nodename:
pattern: "^can(@.*)?$" pattern: "^can(@.*)?$"
termination-gpios:
description: GPIO pin to enable CAN bus termination.
maxItems: 1
termination-ohms:
description: The resistance value of the CAN bus termination resistor.
minimum: 1
maximum: 65535
additionalProperties: true additionalProperties: true
... ...
...@@ -119,6 +119,9 @@ properties: ...@@ -119,6 +119,9 @@ properties:
minimum: 0 minimum: 0
maximum: 2 maximum: 2
termination-gpios: true
termination-ohms: true
required: required:
- compatible - compatible
- reg - reg
...@@ -148,3 +151,17 @@ examples: ...@@ -148,3 +151,17 @@ examples:
fsl,stop-mode = <&gpr 0x34 28>; fsl,stop-mode = <&gpr 0x34 28>;
fsl,scu-index = /bits/ 8 <1>; fsl,scu-index = /bits/ 8 <1>;
}; };
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
can@2090000 {
compatible = "fsl,imx6q-flexcan";
reg = <0x02090000 0x4000>;
interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks 1>, <&clks 2>;
clock-names = "ipg", "per";
fsl,stop-mode = <&gpr 0x34 28>;
termination-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
termination-ohms = <120>;
};
...@@ -30,13 +30,15 @@ properties: ...@@ -30,13 +30,15 @@ properties:
- renesas,r8a77995-canfd # R-Car D3 - renesas,r8a77995-canfd # R-Car D3
- const: renesas,rcar-gen3-canfd # R-Car Gen3 and RZ/G2 - const: renesas,rcar-gen3-canfd # R-Car Gen3 and RZ/G2
- items:
- enum:
- renesas,r9a07g044-canfd # RZ/G2{L,LC}
- const: renesas,rzg2l-canfd # RZ/G2L family
reg: reg:
maxItems: 1 maxItems: 1
interrupts: interrupts: true
items:
- description: Channel interrupt
- description: Global interrupt
clocks: clocks:
maxItems: 3 maxItems: 3
...@@ -50,8 +52,7 @@ properties: ...@@ -50,8 +52,7 @@ properties:
power-domains: power-domains:
maxItems: 1 maxItems: 1
resets: resets: true
maxItems: 1
renesas,no-can-fd: renesas,no-can-fd:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
...@@ -91,6 +92,62 @@ required: ...@@ -91,6 +92,62 @@ required:
- channel0 - channel0
- channel1 - channel1
if:
properties:
compatible:
contains:
enum:
- renesas,rzg2l-canfd
then:
properties:
interrupts:
items:
- description: CAN global error interrupt
- description: CAN receive FIFO interrupt
- description: CAN0 error interrupt
- description: CAN0 transmit interrupt
- description: CAN0 transmit/receive FIFO receive completion interrupt
- description: CAN1 error interrupt
- description: CAN1 transmit interrupt
- description: CAN1 transmit/receive FIFO receive completion interrupt
interrupt-names:
items:
- const: g_err
- const: g_recc
- const: ch0_err
- const: ch0_rec
- const: ch0_trx
- const: ch1_err
- const: ch1_rec
- const: ch1_trx
resets:
maxItems: 2
reset-names:
items:
- const: rstp_n
- const: rstc_n
required:
- interrupt-names
- reset-names
else:
properties:
interrupts:
items:
- description: Channel interrupt
- description: Global interrupt
interrupt-names:
items:
- const: ch_int
- const: g_int
resets:
maxItems: 1
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
...@@ -6905,6 +6905,12 @@ M: Mark Einon <mark.einon@gmail.com> ...@@ -6905,6 +6905,12 @@ M: Mark Einon <mark.einon@gmail.com>
S: Odd Fixes S: Odd Fixes
F: drivers/net/ethernet/agere/ F: drivers/net/ethernet/agere/
ETAS ES58X CAN/USB DRIVER
M: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
L: linux-can@vger.kernel.org
S: Maintained
F: drivers/net/can/usb/etas_es58x/
ETHERNET BRIDGE ETHERNET BRIDGE
M: Roopa Prabhu <roopa@nvidia.com> M: Roopa Prabhu <roopa@nvidia.com>
M: Nikolay Aleksandrov <nikolay@nvidia.com> M: Nikolay Aleksandrov <nikolay@nvidia.com>
......
...@@ -176,6 +176,13 @@ struct c_can_raminit { ...@@ -176,6 +176,13 @@ struct c_can_raminit {
bool needs_pulse; bool needs_pulse;
}; };
/* c_can tx ring structure */
struct c_can_tx_ring {
unsigned int head;
unsigned int tail;
unsigned int obj_num;
};
/* c_can private data structure */ /* c_can private data structure */
struct c_can_priv { struct c_can_priv {
struct can_priv can; /* must be the first member */ struct can_priv can; /* must be the first member */
...@@ -190,17 +197,16 @@ struct c_can_priv { ...@@ -190,17 +197,16 @@ struct c_can_priv {
unsigned int msg_obj_tx_first; unsigned int msg_obj_tx_first;
unsigned int msg_obj_tx_last; unsigned int msg_obj_tx_last;
u32 msg_obj_rx_mask; u32 msg_obj_rx_mask;
atomic_t tx_active;
atomic_t sie_pending; atomic_t sie_pending;
unsigned long tx_dir; unsigned long tx_dir;
int last_status; int last_status;
struct c_can_tx_ring tx;
u16 (*read_reg)(const struct c_can_priv *priv, enum reg index); u16 (*read_reg)(const struct c_can_priv *priv, enum reg index);
void (*write_reg)(const struct c_can_priv *priv, enum reg index, u16 val); void (*write_reg)(const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32)(const struct c_can_priv *priv, enum reg index); u32 (*read_reg32)(const struct c_can_priv *priv, enum reg index);
void (*write_reg32)(const struct c_can_priv *priv, enum reg index, u32 val); void (*write_reg32)(const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base; void __iomem *base;
const u16 *regs; const u16 *regs;
void *priv; /* for board-specific data */
enum c_can_dev_id type; enum c_can_dev_id type;
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */ struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */
void (*raminit)(const struct c_can_priv *priv, bool enable); void (*raminit)(const struct c_can_priv *priv, bool enable);
...@@ -220,4 +226,19 @@ int c_can_power_down(struct net_device *dev); ...@@ -220,4 +226,19 @@ int c_can_power_down(struct net_device *dev);
void c_can_set_ethtool_ops(struct net_device *dev); void c_can_set_ethtool_ops(struct net_device *dev);
static inline u8 c_can_get_tx_head(const struct c_can_tx_ring *ring)
{
return ring->head & (ring->obj_num - 1);
}
static inline u8 c_can_get_tx_tail(const struct c_can_tx_ring *ring)
{
return ring->tail & (ring->obj_num - 1);
}
static inline u8 c_can_get_tx_free(const struct c_can_tx_ring *ring)
{
return ring->obj_num - (ring->head - ring->tail);
}
#endif /* C_CAN_H */ #endif /* C_CAN_H */
...@@ -160,8 +160,8 @@ ...@@ -160,8 +160,8 @@
#define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB) #define IF_MCONT_TX (IF_MCONT_TXIE | IF_MCONT_EOB)
/* Use IF1 for RX and IF2 for TX */ /* Use IF1 in NAPI path and IF2 in TX path */
#define IF_RX 0 #define IF_NAPI 0
#define IF_TX 1 #define IF_TX 1
/* minimum timeout for checking BUSY status */ /* minimum timeout for checking BUSY status */
...@@ -427,24 +427,51 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface, ...@@ -427,24 +427,51 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP); c_can_object_put(dev, iface, obj, IF_COMM_RCV_SETUP);
} }
static bool c_can_tx_busy(const struct c_can_priv *priv,
const struct c_can_tx_ring *tx_ring)
{
if (c_can_get_tx_free(tx_ring) > 0)
return false;
netif_stop_queue(priv->dev);
/* Memory barrier before checking tx_free (head and tail) */
smp_mb();
if (c_can_get_tx_free(tx_ring) == 0) {
netdev_dbg(priv->dev,
"Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n",
tx_ring->head, tx_ring->tail,
tx_ring->head - tx_ring->tail);
return true;
}
netif_start_queue(priv->dev);
return false;
}
static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct can_frame *frame = (struct can_frame *)skb->data; struct can_frame *frame = (struct can_frame *)skb->data;
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
u32 idx, obj; struct c_can_tx_ring *tx_ring = &priv->tx;
u32 idx, obj, cmd = IF_COMM_TX;
if (can_dropped_invalid_skb(dev, skb)) if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK; return NETDEV_TX_OK;
/* This is not a FIFO. C/D_CAN sends out the buffers
* prioritized. The lowest buffer number wins.
*/
idx = fls(atomic_read(&priv->tx_active));
obj = idx + priv->msg_obj_tx_first;
/* If this is the last buffer, stop the xmit queue */ if (c_can_tx_busy(priv, tx_ring))
if (idx == priv->msg_obj_tx_num - 1) return NETDEV_TX_BUSY;
idx = c_can_get_tx_head(tx_ring);
tx_ring->head++;
if (c_can_get_tx_free(tx_ring) == 0)
netif_stop_queue(dev); netif_stop_queue(dev);
if (idx < c_can_get_tx_tail(tx_ring))
cmd &= ~IF_COMM_TXRQST; /* Cache the message */
/* Store the message in the interface so we can call /* Store the message in the interface so we can call
* can_put_echo_skb(). We must do this before we enable * can_put_echo_skb(). We must do this before we enable
* transmit as we might race against do_tx(). * transmit as we might race against do_tx().
...@@ -452,11 +479,8 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb, ...@@ -452,11 +479,8 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
c_can_setup_tx_object(dev, IF_TX, frame, idx); c_can_setup_tx_object(dev, IF_TX, frame, idx);
priv->dlc[idx] = frame->len; priv->dlc[idx] = frame->len;
can_put_echo_skb(skb, dev, idx, 0); can_put_echo_skb(skb, dev, idx, 0);
obj = idx + priv->msg_obj_tx_first;
/* Update the active bits */ c_can_object_put(dev, IF_TX, obj, cmd);
atomic_add(BIT(idx), &priv->tx_active);
/* Start transmission */
c_can_object_put(dev, IF_TX, obj, IF_COMM_TX);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
...@@ -529,13 +553,13 @@ static void c_can_configure_msg_objects(struct net_device *dev) ...@@ -529,13 +553,13 @@ static void c_can_configure_msg_objects(struct net_device *dev)
/* first invalidate all message objects */ /* first invalidate all message objects */
for (i = priv->msg_obj_rx_first; i <= priv->msg_obj_num; i++) for (i = priv->msg_obj_rx_first; i <= priv->msg_obj_num; i++)
c_can_inval_msg_object(dev, IF_RX, i); c_can_inval_msg_object(dev, IF_NAPI, i);
/* setup receive message objects */ /* setup receive message objects */
for (i = priv->msg_obj_rx_first; i < priv->msg_obj_rx_last; i++) for (i = priv->msg_obj_rx_first; i < priv->msg_obj_rx_last; i++)
c_can_setup_receive_object(dev, IF_RX, i, 0, 0, IF_MCONT_RCV); c_can_setup_receive_object(dev, IF_NAPI, i, 0, 0, IF_MCONT_RCV);
c_can_setup_receive_object(dev, IF_RX, priv->msg_obj_rx_last, 0, 0, c_can_setup_receive_object(dev, IF_NAPI, priv->msg_obj_rx_last, 0, 0,
IF_MCONT_RCV_EOB); IF_MCONT_RCV_EOB);
} }
...@@ -567,6 +591,7 @@ static int c_can_software_reset(struct net_device *dev) ...@@ -567,6 +591,7 @@ static int c_can_software_reset(struct net_device *dev)
static int c_can_chip_config(struct net_device *dev) static int c_can_chip_config(struct net_device *dev)
{ {
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
struct c_can_tx_ring *tx_ring = &priv->tx;
int err; int err;
err = c_can_software_reset(dev); err = c_can_software_reset(dev);
...@@ -598,7 +623,8 @@ static int c_can_chip_config(struct net_device *dev) ...@@ -598,7 +623,8 @@ static int c_can_chip_config(struct net_device *dev)
priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);
/* Clear all internal status */ /* Clear all internal status */
atomic_set(&priv->tx_active, 0); tx_ring->head = 0;
tx_ring->tail = 0;
priv->tx_dir = 0; priv->tx_dir = 0;
/* set bittiming params */ /* set bittiming params */
...@@ -696,40 +722,57 @@ static int c_can_get_berr_counter(const struct net_device *dev, ...@@ -696,40 +722,57 @@ static int c_can_get_berr_counter(const struct net_device *dev,
static void c_can_do_tx(struct net_device *dev) static void c_can_do_tx(struct net_device *dev)
{ {
struct c_can_priv *priv = netdev_priv(dev); struct c_can_priv *priv = netdev_priv(dev);
struct c_can_tx_ring *tx_ring = &priv->tx;
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
u32 idx, obj, pkts = 0, bytes = 0, pend, clr; u32 idx, obj, pkts = 0, bytes = 0, pend;
u8 tail;
if (priv->msg_obj_tx_last > 32) if (priv->msg_obj_tx_last > 32)
pend = priv->read_reg32(priv, C_CAN_INTPND3_REG); pend = priv->read_reg32(priv, C_CAN_INTPND3_REG);
else else
pend = priv->read_reg(priv, C_CAN_INTPND2_REG); pend = priv->read_reg(priv, C_CAN_INTPND2_REG);
clr = pend;
while ((idx = ffs(pend))) { while ((idx = ffs(pend))) {
idx--; idx--;
pend &= ~BIT(idx); pend &= ~BIT(idx);
obj = idx + priv->msg_obj_tx_first; obj = idx + priv->msg_obj_tx_first;
/* We use IF_RX interface instead of IF_TX because we /* We use IF_NAPI interface instead of IF_TX because we
* are called from c_can_poll(), which runs inside * are called from c_can_poll(), which runs inside
* NAPI. We are not trasmitting. * NAPI. We are not transmitting.
*/ */
c_can_inval_tx_object(dev, IF_RX, obj); c_can_inval_tx_object(dev, IF_NAPI, obj);
can_get_echo_skb(dev, idx, NULL); can_get_echo_skb(dev, idx, NULL);
bytes += priv->dlc[idx]; bytes += priv->dlc[idx];
pkts++; pkts++;
} }
/* Clear the bits in the tx_active mask */ if (!pkts)
atomic_sub(clr, &priv->tx_active); return;
if (clr & BIT(priv->msg_obj_tx_num - 1)) tx_ring->tail += pkts;
netif_wake_queue(dev); if (c_can_get_tx_free(tx_ring)) {
/* Make sure that anybody stopping the queue after
* this sees the new tx_ring->tail.
*/
smp_mb();
netif_wake_queue(priv->dev);
}
if (pkts) { stats->tx_bytes += bytes;
stats->tx_bytes += bytes; stats->tx_packets += pkts;
stats->tx_packets += pkts; can_led_event(dev, CAN_LED_EVENT_TX);
can_led_event(dev, CAN_LED_EVENT_TX);
tail = c_can_get_tx_tail(tx_ring);
if (tail == 0) {
u8 head = c_can_get_tx_head(tx_ring);
/* Start transmission for all cached messages */
for (idx = tail; idx < head; idx++) {
obj = idx + priv->msg_obj_tx_first;
c_can_object_put(dev, IF_NAPI, obj, IF_COMM_TXRQST);
}
} }
} }
...@@ -766,14 +809,14 @@ static u32 c_can_adjust_pending(u32 pend, u32 rx_mask) ...@@ -766,14 +809,14 @@ static u32 c_can_adjust_pending(u32 pend, u32 rx_mask)
static inline void c_can_rx_object_get(struct net_device *dev, static inline void c_can_rx_object_get(struct net_device *dev,
struct c_can_priv *priv, u32 obj) struct c_can_priv *priv, u32 obj)
{ {
c_can_object_get(dev, IF_RX, obj, priv->comm_rcv_high); c_can_object_get(dev, IF_NAPI, obj, priv->comm_rcv_high);
} }
static inline void c_can_rx_finalize(struct net_device *dev, static inline void c_can_rx_finalize(struct net_device *dev,
struct c_can_priv *priv, u32 obj) struct c_can_priv *priv, u32 obj)
{ {
if (priv->type != BOSCH_D_CAN) if (priv->type != BOSCH_D_CAN)
c_can_object_get(dev, IF_RX, obj, IF_COMM_CLR_NEWDAT); c_can_object_get(dev, IF_NAPI, obj, IF_COMM_CLR_NEWDAT);
} }
static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
...@@ -785,10 +828,12 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, ...@@ -785,10 +828,12 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
pend &= ~BIT(obj - 1); pend &= ~BIT(obj - 1);
c_can_rx_object_get(dev, priv, obj); c_can_rx_object_get(dev, priv, obj);
ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_RX)); ctrl = priv->read_reg(priv, C_CAN_IFACE(MSGCTRL_REG, IF_NAPI));
if (ctrl & IF_MCONT_MSGLST) { if (ctrl & IF_MCONT_MSGLST) {
int n = c_can_handle_lost_msg_obj(dev, IF_RX, obj, ctrl); int n;
n = c_can_handle_lost_msg_obj(dev, IF_NAPI, obj, ctrl);
pkts += n; pkts += n;
quota -= n; quota -= n;
...@@ -803,7 +848,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv, ...@@ -803,7 +848,7 @@ static int c_can_read_objects(struct net_device *dev, struct c_can_priv *priv,
continue; continue;
/* read the data from the message object */ /* read the data from the message object */
c_can_read_msg_object(dev, IF_RX, ctrl); c_can_read_msg_object(dev, IF_NAPI, ctrl);
c_can_rx_finalize(dev, priv, obj); c_can_rx_finalize(dev, priv, obj);
...@@ -1205,6 +1250,10 @@ struct net_device *alloc_c_can_dev(int msg_obj_num) ...@@ -1205,6 +1250,10 @@ struct net_device *alloc_c_can_dev(int msg_obj_num)
priv->msg_obj_tx_last = priv->msg_obj_tx_last =
priv->msg_obj_tx_first + priv->msg_obj_tx_num - 1; priv->msg_obj_tx_first + priv->msg_obj_tx_num - 1;
priv->tx.head = 0;
priv->tx.tail = 0;
priv->tx.obj_num = msg_obj_tx_num;
netif_napi_add(dev, &priv->napi, c_can_poll, priv->msg_obj_rx_num); netif_napi_add(dev, &priv->napi, c_can_poll, priv->msg_obj_rx_num);
priv->dev = dev; priv->dev = dev;
......
...@@ -385,7 +385,6 @@ static int c_can_plat_probe(struct platform_device *pdev) ...@@ -385,7 +385,6 @@ static int c_can_plat_probe(struct platform_device *pdev)
priv->base = addr; priv->base = addr;
priv->device = &pdev->dev; priv->device = &pdev->dev;
priv->can.clock.freq = clk_get_rate(clk); priv->can.clock.freq = clk_get_rate(clk);
priv->priv = clk;
priv->type = drvdata->id; priv->type = drvdata->id;
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/skb.h> #include <linux/can/skb.h>
#include <linux/can/led.h> #include <linux/can/led.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#define MOD_DESC "CAN device driver interface" #define MOD_DESC "CAN device driver interface"
...@@ -400,10 +401,69 @@ void close_candev(struct net_device *dev) ...@@ -400,10 +401,69 @@ void close_candev(struct net_device *dev)
} }
EXPORT_SYMBOL_GPL(close_candev); EXPORT_SYMBOL_GPL(close_candev);
static int can_set_termination(struct net_device *ndev, u16 term)
{
struct can_priv *priv = netdev_priv(ndev);
int set;
if (term == priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_ENABLED])
set = 1;
else
set = 0;
gpiod_set_value(priv->termination_gpio, set);
return 0;
}
static int can_get_termination(struct net_device *ndev)
{
struct can_priv *priv = netdev_priv(ndev);
struct device *dev = ndev->dev.parent;
struct gpio_desc *gpio;
u32 term;
int ret;
/* Disabling termination by default is the safe choice: Else if many
* bus participants enable it, no communication is possible at all.
*/
gpio = devm_gpiod_get_optional(dev, "termination", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return dev_err_probe(dev, PTR_ERR(gpio),
"Cannot get termination-gpios\n");
if (!gpio)
return 0;
ret = device_property_read_u32(dev, "termination-ohms", &term);
if (ret) {
netdev_err(ndev, "Cannot get termination-ohms: %pe\n",
ERR_PTR(ret));
return ret;
}
if (term > U16_MAX) {
netdev_err(ndev, "Invalid termination-ohms value (%u > %u)\n",
term, U16_MAX);
return -EINVAL;
}
priv->termination_const_cnt = ARRAY_SIZE(priv->termination_gpio_ohms);
priv->termination_const = priv->termination_gpio_ohms;
priv->termination_gpio = gpio;
priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_DISABLED] =
CAN_TERMINATION_DISABLED;
priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_ENABLED] = term;
priv->do_set_termination = can_set_termination;
return 0;
}
/* Register the CAN network device */ /* Register the CAN network device */
int register_candev(struct net_device *dev) int register_candev(struct net_device *dev)
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
int err;
/* Ensure termination_const, termination_const_cnt and /* Ensure termination_const, termination_const_cnt and
* do_set_termination consistency. All must be either set or * do_set_termination consistency. All must be either set or
...@@ -419,6 +479,12 @@ int register_candev(struct net_device *dev) ...@@ -419,6 +479,12 @@ int register_candev(struct net_device *dev)
if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt) if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
return -EINVAL; return -EINVAL;
if (!priv->termination_const) {
err = can_get_termination(dev);
if (err)
return err;
}
dev->rtnl_link_ops = &can_link_ops; dev->rtnl_link_ops = &can_link_ops;
netif_carrier_off(dev); netif_carrier_off(dev);
......
...@@ -116,7 +116,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -116,7 +116,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
maskedflags = cm->flags & cm->mask; maskedflags = cm->flags & cm->mask;
/* check whether provided bits are allowed to be passed */ /* check whether provided bits are allowed to be passed */
if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic)) if (maskedflags & ~(priv->ctrlmode_supported | ctrlstatic))
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* do not check for static fd-non-iso if 'fd' is disabled */ /* do not check for static fd-non-iso if 'fd' is disabled */
......
This diff is collapsed.
...@@ -65,9 +65,9 @@ struct m_can_ops { ...@@ -65,9 +65,9 @@ struct m_can_ops {
int (*clear_interrupts)(struct m_can_classdev *cdev); int (*clear_interrupts)(struct m_can_classdev *cdev);
u32 (*read_reg)(struct m_can_classdev *cdev, int reg); u32 (*read_reg)(struct m_can_classdev *cdev, int reg);
int (*write_reg)(struct m_can_classdev *cdev, int reg, int val); int (*write_reg)(struct m_can_classdev *cdev, int reg, int val);
u32 (*read_fifo)(struct m_can_classdev *cdev, int addr_offset); int (*read_fifo)(struct m_can_classdev *cdev, int addr_offset, void *val, size_t val_count);
int (*write_fifo)(struct m_can_classdev *cdev, int addr_offset, int (*write_fifo)(struct m_can_classdev *cdev, int addr_offset,
int val); const void *val, size_t val_count);
int (*init)(struct m_can_classdev *cdev); int (*init)(struct m_can_classdev *cdev);
}; };
...@@ -101,7 +101,7 @@ void m_can_class_free_dev(struct net_device *net); ...@@ -101,7 +101,7 @@ void m_can_class_free_dev(struct net_device *net);
int m_can_class_register(struct m_can_classdev *cdev); int m_can_class_register(struct m_can_classdev *cdev);
void m_can_class_unregister(struct m_can_classdev *cdev); void m_can_class_unregister(struct m_can_classdev *cdev);
int m_can_class_get_clocks(struct m_can_classdev *cdev); int m_can_class_get_clocks(struct m_can_classdev *cdev);
void m_can_init_ram(struct m_can_classdev *priv); int m_can_init_ram(struct m_can_classdev *priv);
int m_can_class_suspend(struct device *dev); int m_can_class_suspend(struct device *dev);
int m_can_class_resume(struct device *dev); int m_can_class_resume(struct device *dev);
......
...@@ -39,11 +39,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg) ...@@ -39,11 +39,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
return readl(priv->base + reg); return readl(priv->base + reg);
} }
static u32 iomap_read_fifo(struct m_can_classdev *cdev, int offset) static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
{ {
struct m_can_pci_priv *priv = cdev_to_priv(cdev); struct m_can_pci_priv *priv = cdev_to_priv(cdev);
return readl(priv->base + offset); ioread32_rep(priv->base + offset, val, val_count);
return 0;
} }
static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val) static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
...@@ -55,11 +57,12 @@ static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val) ...@@ -55,11 +57,12 @@ static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
return 0; return 0;
} }
static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, int val) static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
const void *val, size_t val_count)
{ {
struct m_can_pci_priv *priv = cdev_to_priv(cdev); struct m_can_pci_priv *priv = cdev_to_priv(cdev);
writel(val, priv->base + offset); iowrite32_rep(priv->base + offset, val, val_count);
return 0; return 0;
} }
......
...@@ -29,11 +29,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg) ...@@ -29,11 +29,13 @@ static u32 iomap_read_reg(struct m_can_classdev *cdev, int reg)
return readl(priv->base + reg); return readl(priv->base + reg);
} }
static u32 iomap_read_fifo(struct m_can_classdev *cdev, int offset) static int iomap_read_fifo(struct m_can_classdev *cdev, int offset, void *val, size_t val_count)
{ {
struct m_can_plat_priv *priv = cdev_to_priv(cdev); struct m_can_plat_priv *priv = cdev_to_priv(cdev);
return readl(priv->mram_base + offset); ioread32_rep(priv->mram_base + offset, val, val_count);
return 0;
} }
static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val) static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
...@@ -45,11 +47,12 @@ static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val) ...@@ -45,11 +47,12 @@ static int iomap_write_reg(struct m_can_classdev *cdev, int reg, int val)
return 0; return 0;
} }
static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, int val) static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
const void *val, size_t val_count)
{ {
struct m_can_plat_priv *priv = cdev_to_priv(cdev); struct m_can_plat_priv *priv = cdev_to_priv(cdev);
writel(val, priv->mram_base + offset); iowrite32_rep(priv->base + offset, val, val_count);
return 0; return 0;
} }
...@@ -127,7 +130,9 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -127,7 +130,9 @@ static int m_can_plat_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mcan_class); platform_set_drvdata(pdev, mcan_class);
m_can_init_ram(mcan_class); ret = m_can_init_ram(mcan_class);
if (ret)
goto probe_fail;
pm_runtime_enable(mcan_class->dev); pm_runtime_enable(mcan_class->dev);
ret = m_can_class_register(mcan_class); ret = m_can_class_register(mcan_class);
......
...@@ -105,7 +105,6 @@ ...@@ -105,7 +105,6 @@
static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev) static inline struct tcan4x5x_priv *cdev_to_priv(struct m_can_classdev *cdev)
{ {
return container_of(cdev, struct tcan4x5x_priv, cdev); return container_of(cdev, struct tcan4x5x_priv, cdev);
} }
static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv) static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
...@@ -154,14 +153,12 @@ static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg) ...@@ -154,14 +153,12 @@ static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg)
return val; return val;
} }
static u32 tcan4x5x_read_fifo(struct m_can_classdev *cdev, int addr_offset) static int tcan4x5x_read_fifo(struct m_can_classdev *cdev, int addr_offset,
void *val, size_t val_count)
{ {
struct tcan4x5x_priv *priv = cdev_to_priv(cdev); struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
u32 val;
regmap_read(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, &val);
return val; return regmap_bulk_read(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val, val_count);
} }
static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val) static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val)
...@@ -172,11 +169,11 @@ static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val) ...@@ -172,11 +169,11 @@ static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val)
} }
static int tcan4x5x_write_fifo(struct m_can_classdev *cdev, static int tcan4x5x_write_fifo(struct m_can_classdev *cdev,
int addr_offset, int val) int addr_offset, const void *val, size_t val_count)
{ {
struct tcan4x5x_priv *priv = cdev_to_priv(cdev); struct tcan4x5x_priv *priv = cdev_to_priv(cdev);
return regmap_write(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val); return regmap_bulk_write(priv->regmap, TCAN4X5X_MRAM_START + addr_offset, val, val_count);
} }
static int tcan4x5x_power_enable(struct regulator *reg, int enable) static int tcan4x5x_power_enable(struct regulator *reg, int enable)
...@@ -238,7 +235,9 @@ static int tcan4x5x_init(struct m_can_classdev *cdev) ...@@ -238,7 +235,9 @@ static int tcan4x5x_init(struct m_can_classdev *cdev)
return ret; return ret;
/* Zero out the MCAN buffers */ /* Zero out the MCAN buffers */
m_can_init_ram(cdev); ret = m_can_init_ram(cdev);
if (ret)
return ret;
ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG, ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL); TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
......
This diff is collapsed.
...@@ -1456,7 +1456,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv, ...@@ -1456,7 +1456,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
} }
static void static void
mcp251xfd_hw_rx_obj_to_skb(struct mcp251xfd_priv *priv, mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj, const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
struct sk_buff *skb) struct sk_buff *skb)
{ {
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc) static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc)
{ {
struct mcp251xfd_priv *priv; const struct mcp251xfd_priv *priv;
u32 timestamp = 0; u32 timestamp = 0;
int err; int err;
...@@ -39,7 +39,7 @@ static void mcp251xfd_timestamp_work(struct work_struct *work) ...@@ -39,7 +39,7 @@ static void mcp251xfd_timestamp_work(struct work_struct *work)
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
} }
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv, void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp) struct sk_buff *skb, u32 timestamp)
{ {
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
......
...@@ -853,7 +853,7 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv); ...@@ -853,7 +853,7 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
const void *data, size_t data_size); const void *data, size_t data_size);
u16 mcp251xfd_crc16_compute(const void *data, size_t data_size); u16 mcp251xfd_crc16_compute(const void *data, size_t data_size);
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv, void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp); struct sk_buff *skb, u32 timestamp);
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv); void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv); void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
......
...@@ -96,23 +96,14 @@ struct es58x_fd_bittiming { ...@@ -96,23 +96,14 @@ struct es58x_fd_bittiming {
* @ctrlmode: type enum es58x_fd_ctrlmode. * @ctrlmode: type enum es58x_fd_ctrlmode.
* @canfd_enabled: boolean (0: Classical CAN, 1: CAN and/or CANFD). * @canfd_enabled: boolean (0: Classical CAN, 1: CAN and/or CANFD).
* @data_bittiming: Bittiming for flexible data-rate transmission. * @data_bittiming: Bittiming for flexible data-rate transmission.
* @tdc_enabled: Transmitter Delay Compensation switch (0: disabled, * @tdc_enabled: Transmitter Delay Compensation switch (0: TDC is
* 1: enabled). On very high bitrates, the delay between when the * disabled, 1: TDC is enabled).
* bit is sent and received on the CANTX and CANRX pins of the * @tdco: Transmitter Delay Compensation Offset.
* transceiver start to be significant enough for errors to occur * @tdcf: Transmitter Delay Compensation Filter window.
* and thus need to be compensated.
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time
* quanta, defining the delay between the start of the bit
* reception on the CANRX pin of the transceiver and the SSP
* (Secondary Sample Point). Valid values: 0 to 127.
* @tdcf: Transmitter Delay Compensation Filter window. Defines the
* minimum value for the SSP position, in time quanta. The
* feature is enabled when TDCF is configured to a value greater
* than TDCO. Valid values: 0 to 127.
* *
* Please refer to the microcontroller datasheet: "SAM * Please refer to the microcontroller datasheet: "SAM E70/S70/V70/V71
* E701/S70/V70/V71 Family" section 49 "Controller Area Network * Family" section 49 "Controller Area Network (MCAN)" for additional
* (MCAN)" for additional information. * information.
*/ */
struct es58x_fd_tx_conf_msg { struct es58x_fd_tx_conf_msg {
struct es58x_fd_bittiming nominal_bittiming; struct es58x_fd_bittiming nominal_bittiming;
......
...@@ -32,6 +32,12 @@ enum can_mode { ...@@ -32,6 +32,12 @@ enum can_mode {
CAN_MODE_SLEEP CAN_MODE_SLEEP
}; };
enum can_termination_gpio {
CAN_TERMINATION_GPIO_DISABLED = 0,
CAN_TERMINATION_GPIO_ENABLED,
CAN_TERMINATION_GPIO_MAX,
};
/* /*
* CAN common private data * CAN common private data
*/ */
...@@ -55,6 +61,8 @@ struct can_priv { ...@@ -55,6 +61,8 @@ struct can_priv {
unsigned int termination_const_cnt; unsigned int termination_const_cnt;
const u16 *termination_const; const u16 *termination_const;
u16 termination; u16 termination;
struct gpio_desc *termination_gpio;
u16 termination_gpio_ohms[CAN_TERMINATION_GPIO_MAX];
enum can_state state; enum can_state state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment