#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#ifdef CONFIG_ARCH_MXC_ARM64
+#include <soc/imx8/sc/sci.h>
+#endif
+
#define DRV_NAME "flexcan"
/* 8 for RX fifo and 2 error handling */
struct regmap *gpr;
int id;
struct flexcan_stop_mode stm;
+#ifdef CONFIG_ARCH_MXC_ARM64
+ sc_ipc_t ipc_handle;
+#endif
/* Selects the clock source to CAN Protocol Engine (PE), 1 by default*/
u32 clk_src;
priv->write(reg_mcr, ®s->mcr);
}
+#ifdef CONFIG_ARCH_MXC_ARM64
+static void imx8_ipg_stop_enable(struct flexcan_priv *priv, bool enabled)
+{
+ struct device_node *np = priv->dev->of_node;
+ u32 rsrc_id, val;
+ int idx;
+
+ idx = of_alias_get_id(np, "can");
+ if (idx == 0)
+ rsrc_id = SC_R_CAN_0;
+ else if (idx == 1)
+ rsrc_id = SC_R_CAN_1;
+ else
+ rsrc_id = SC_R_CAN_2;
+
+ val = enabled ? 1 : 0;
+ sc_misc_set_control(priv->ipc_handle, rsrc_id, SC_C_IPG_STOP, val);
+}
+#else
+static void imx8_ipg_stop_enable(struct flexcan_priv *priv, bool enabled) {}
+#endif
+
static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
{
- /* enable stop request */
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
- regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
- 1 << priv->stm.req_bit,
- 1 << priv->stm.req_bit);
+ if (priv->stm.gpr) {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
+ } else {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD)
+ imx8_ipg_stop_enable(priv, true);
+ }
}
static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
{
- /* remove stop request */
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
- regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
- 1 << priv->stm.req_bit, 0);
+ if (priv->stm.gpr) {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 0);
+ } else {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD)
+ imx8_ipg_stop_enable(priv, false);
+ }
}
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
priv->write(reg_esr & FLEXCAN_ESR_ALL_INT, ®s->esr);
}
- if (reg_esr & FLEXCAN_ESR_WAK_INT)
- flexcan_exit_stop_mode(priv);
-
/* state change interrupt or broken error state quirk fix is enabled */
if ((reg_esr & FLEXCAN_ESR_ERR_STATE) ||
(priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE |
unregister_candev(dev);
}
+#ifdef CONFIG_ARCH_MXC_ARM64
+static int imx8_sc_ipc_fetch(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct flexcan_priv *priv;
+ sc_err_t sc_err = SC_ERR_NONE;
+ u32 mu_id;
+
+ priv = netdev_priv(dev);
+
+ sc_err = sc_ipc_getMuID(&mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ netdev_err(dev, "FLEXCAN ipg stop: Get MU ID failed\n");
+ return sc_err;
+ }
+
+ sc_err = sc_ipc_open(&priv->ipc_handle, mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ netdev_err(dev, "FLEXCAN ipg stop: Open MU channel failed\n");
+ return sc_err;
+ }
+
+ return sc_err;
+}
+#else
+static int imx8_sc_ipc_fetch(struct platform_device *pdev) { return 0; }
+#endif
+
static int flexcan_of_parse_stop_mode(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
devm_can_led_init(dev);
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD) {
+ err = imx8_sc_ipc_fetch(pdev);
+ if (err) {
+ wakeup = 0;
+ dev_dbg(&pdev->dev, "failed to fetch scu ipc\n");
+ }
+ } else if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
err = flexcan_of_parse_stop_mode(pdev);
if (err) {
wakeup = 0;
struct net_device *dev = platform_get_drvdata(pdev);
struct flexcan_priv *priv = netdev_priv(dev);
+#ifdef CONFIG_ARCH_MXC_ARM64
+ sc_ipc_close(priv->ipc_handle);
+#endif
unregister_flexcandev(dev);
pm_runtime_disable(&pdev->dev);
can_rx_offload_del(&priv->offload);
} else {
flexcan_chip_stop(dev);
ret = pm_runtime_force_suspend(device);
+
+ pinctrl_pm_select_sleep_state(device);
}
}
priv->can.state = CAN_STATE_SLEEPING;
- pinctrl_pm_select_sleep_state(device);
-
return ret;
}