Skip to content

Commit

Permalink
Merge tag 'linux-can-next-for-5.12-20210106' of git://git.kernel.org/…
Browse files Browse the repository at this point in the history
…pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-01-06

The first 16 patches are by me and target the tcan4x5x SPI glue driver for the
m_can CAN driver. First there are a several cleanup commits, then the SPI
regmap part is converted to 8 bits per word, to make it possible to use that
driver on SPI controllers that only support the 8 bit per word mode (such as
the SPI cores on the raspberry pi).

Oliver Hartkopp contributes a patch for the CAN_RAW protocol. The getsockopt()
for CAN_RAW_FILTER is changed to return -ERANGE if the filterset does not fit
into the provided user space buffer.

The last two patches are by Joakim Zhang and add wakeup support to the flexcan
driver for the i.MX8QM SoC. The dt-bindings docs are extended to describe the
added property.

* tag 'linux-can-next-for-5.12-20210106' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next:
  can: flexcan: add CAN wakeup function for i.MX8QM
  dt-bindings: can: fsl,flexcan: add fsl,scu-index property to indicate a resource
  can: raw: return -ERANGE when filterset does not fit into user space buffer
  can: tcan4x5x: add support for half-duplex controllers
  can: tcan4x5x: rework SPI access
  can: tcan4x5x: add {wr,rd}_table
  can: tcan4x5x: add max_raw_{read,write} of 256
  can: tcan4x5x: tcan4x5x_regmap: set reg_stride to 4
  can: tcan4x5x: fix max register value
  can: tcan4x5x: tcan4x5x_regmap_init(): use spi as context pointer
  can: tcan4x5x: tcan4x5x_regmap_write(): remove not needed casts and replace 4 by sizeof
  can: tcan4x5x: rename regmap_spi_gather_write() -> tcan4x5x_regmap_gather_write()
  can: tcan4x5x: remove regmap async support
  can: tcan4x5x: tcan4x5x_bus: remove not needed read_flag_mask
  can: tcan4x5x: mark struct regmap_bus tcan4x5x_bus as constant
  can: tcan4x5x: move regmap code into seperate file
  can: tcan4x5x: rename tcan4x5x.c -> tcan4x5x-core.c
  can: tcan4x5x: beautify indention of tcan4x5x_of_match and tcan4x5x_id_table
  can: tcan4x5x: replace DEVICE_NAME by KBUILD_MODNAME
====================

Link: https://lore.kernel.org/r/20210107094900.173046-1-mkl@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jan 7, 2021
2 parents 8209f5b + 812f011 commit c10b377
Show file tree
Hide file tree
Showing 7 changed files with 340 additions and 132 deletions.
11 changes: 11 additions & 0 deletions Documentation/devicetree/bindings/net/can/fsl,flexcan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ properties:
description:
Enable CAN remote wakeup.

fsl,scu-index:
description: |
The scu index of CAN instance.
For SoCs with SCU support, need setup stop mode via SCU firmware, so this
property can help indicate a resource. It supports up to 3 CAN instances
now.
$ref: /schemas/types.yaml#/definitions/uint8
minimum: 0
maximum: 2

required:
- compatible
- reg
Expand Down Expand Up @@ -137,4 +147,5 @@ examples:
clocks = <&clks 1>, <&clks 2>;
clock-names = "ipg", "per";
fsl,stop-mode = <&gpr 0x34 28>;
fsl,scu-index = /bits/ 8 <1>;
};
123 changes: 106 additions & 17 deletions drivers/net/can/flexcan.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//
// Based on code originally by Andrey Volkov <avolkov@varma-el.com>

#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/bitfield.h>
#include <linux/can.h>
#include <linux/can/dev.h>
Expand All @@ -17,6 +18,7 @@
#include <linux/can/rx-offload.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware/imx/sci.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
Expand Down Expand Up @@ -242,6 +244,8 @@
#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9)
/* support memory detection and correction */
#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10)
/* Setup stop mode with SCU firmware to support wakeup */
#define FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW BIT(11)

/* Structure of the message buffer */
struct flexcan_mb {
Expand Down Expand Up @@ -347,6 +351,7 @@ struct flexcan_priv {
u8 mb_count;
u8 mb_size;
u8 clk_src; /* clock source of CAN Protocol Engine */
u8 scu_idx;

u64 rx_mask;
u64 tx_mask;
Expand All @@ -358,6 +363,9 @@ struct flexcan_priv {
struct regulator *reg_xceiver;
struct flexcan_stop_mode stm;

/* IPC handle when setup stop mode by System Controller firmware(scfw) */
struct imx_sc_ipc *sc_ipc_handle;

/* Read and Write APIs */
u32 (*read)(void __iomem *addr);
void (*write)(u32 val, void __iomem *addr);
Expand Down Expand Up @@ -387,7 +395,7 @@ static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
FLEXCAN_QUIRK_SUPPORT_FD,
FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW,
};

static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
Expand Down Expand Up @@ -546,18 +554,42 @@ static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
priv->write(reg_mcr, &regs->mcr);
}

static int flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
{
u8 idx = priv->scu_idx;
u32 rsrc_id, val;

rsrc_id = IMX_SC_R_CAN(idx);

if (enabled)
val = 1;
else
val = 0;

/* stop mode request via scu firmware */
return imx_sc_misc_set_control(priv->sc_ipc_handle, rsrc_id,
IMX_SC_C_IPG_STOP, val);
}

static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr;
int ret;

reg_mcr = priv->read(&regs->mcr);
reg_mcr |= FLEXCAN_MCR_SLF_WAK;
priv->write(reg_mcr, &regs->mcr);

/* enable stop request */
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) {
ret = flexcan_stop_mode_enable_scfw(priv, true);
if (ret < 0)
return ret;
} else {
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
}

return flexcan_low_power_enter_ack(priv);
}
Expand All @@ -566,10 +598,17 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
{
struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr;
int ret;

/* remove stop request */
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 0);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) {
ret = flexcan_stop_mode_enable_scfw(priv, false);
if (ret < 0)
return ret;
} else {
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 0);
}

reg_mcr = priv->read(&regs->mcr);
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
Expand Down Expand Up @@ -1867,7 +1906,7 @@ static void unregister_flexcandev(struct net_device *dev)
unregister_candev(dev);
}

static int flexcan_setup_stop_mode(struct platform_device *pdev)
static int flexcan_setup_stop_mode_gpr(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct device_node *np = pdev->dev.of_node;
Expand Down Expand Up @@ -1912,18 +1951,65 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
"gpr %s req_gpr=0x02%x req_bit=%u\n",
gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit);

device_set_wakeup_capable(&pdev->dev, true);

if (of_property_read_bool(np, "wakeup-source"))
device_set_wakeup_enable(&pdev->dev, true);

return 0;

out_put_node:
of_node_put(gpr_np);
return ret;
}

static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct flexcan_priv *priv;
u8 scu_idx;
int ret;

ret = of_property_read_u8(pdev->dev.of_node, "fsl,scu-index", &scu_idx);
if (ret < 0) {
dev_dbg(&pdev->dev, "failed to get scu index\n");
return ret;
}

priv = netdev_priv(dev);
priv->scu_idx = scu_idx;

/* this function could be defered probe, return -EPROBE_DEFER */
return imx_scu_get_handle(&priv->sc_ipc_handle);
}

/* flexcan_setup_stop_mode - Setup stop mode for wakeup
*
* Return: = 0 setup stop mode successfully or doesn't support this feature
* < 0 fail to setup stop mode (could be defered probe)
*/
static int flexcan_setup_stop_mode(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct flexcan_priv *priv;
int ret;

priv = netdev_priv(dev);

if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW)
ret = flexcan_setup_stop_mode_scfw(pdev);
else if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR)
ret = flexcan_setup_stop_mode_gpr(pdev);
else
/* return 0 directly if doesn't support stop mode feature */
return 0;

if (ret)
return ret;

device_set_wakeup_capable(&pdev->dev, true);

if (of_property_read_bool(pdev->dev.of_node, "wakeup-source"))
device_set_wakeup_enable(&pdev->dev, true);

return 0;
}

static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
{ .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
Expand Down Expand Up @@ -2054,17 +2140,20 @@ static int flexcan_probe(struct platform_device *pdev)
goto failed_register;
}

err = flexcan_setup_stop_mode(pdev);
if (err < 0) {
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev, "setup stop mode failed\n");
goto failed_setup_stop_mode;
}

of_can_transceiver(dev);
devm_can_led_init(dev);

if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
err = flexcan_setup_stop_mode(pdev);
if (err)
dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
}

return 0;

failed_setup_stop_mode:
unregister_flexcandev(dev);
failed_register:
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/can/m_can/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ obj-$(CONFIG_CAN_M_CAN) += m_can.o
obj-$(CONFIG_CAN_M_CAN_PCI) += m_can_pci.o
obj-$(CONFIG_CAN_M_CAN_PLATFORM) += m_can_platform.o
obj-$(CONFIG_CAN_M_CAN_TCAN4X5X) += tcan4x5x.o

tcan4x5x-objs :=
tcan4x5x-objs += tcan4x5x-core.o
tcan4x5x-objs += tcan4x5x-regmap.o
Loading

0 comments on commit c10b377

Please sign in to comment.