diff options
-rw-r--r-- | Documentation/devicetree/bindings/net/can/fsl-flexcan.txt | 9 | ||||
-rw-r--r-- | arch/arm/boot/dts/imx6qdl.dtsi | 2 | ||||
-rw-r--r-- | drivers/net/can/flexcan.c | 94 |
3 files changed, 76 insertions, 29 deletions
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index e988579c320b..00ff7d6c9f64 100644 --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt @@ -17,8 +17,13 @@ Optional properties: - clock-frequency : The oscillator frequency driving the flexcan device - xceiver-supply: Regulator that powers the CAN transceiver -- gpr: phandle to general purpose register node. The remote wakeup control - bits is stored here. +- stop-mode: register bits of stop mode control, the format is + <&gpr req_gpr req_bit ack_gpr ack_bit>. + gpr is the phandle to general purpose register node. + req_gpr is the gpr register offset of CAN stop request. + req_bit is the bit offset of CAN stop request. + ack_gpr is the gpr register offset of CAN stop acknowledge. + ack_bit is the bit offset of CAN stop acknowledge. - trx_en_gpio : enable gpio - trx_stby_gpio : standby gpio - trx_nerr_gpio : NERR gpio diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 5902585661a3..9407b5024b27 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -503,6 +503,7 @@ clocks = <&clks IMX6QDL_CLK_CAN1_IPG>, <&clks IMX6QDL_CLK_CAN1_SERIAL>; clock-names = "ipg", "per"; + stop-mode = <&gpr 0x34 28 0x10 17>; status = "disabled"; }; @@ -513,6 +514,7 @@ clocks = <&clks IMX6QDL_CLK_CAN2_IPG>, <&clks IMX6QDL_CLK_CAN2_SERIAL>; clock-names = "ipg", "per"; + stop-mode = <&gpr 0x34 29 0x10 18>; status = "disabled"; }; diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 169f4d6c546a..aef8b26cc0e9 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -250,6 +250,13 @@ struct flexcan_devtype_data { u32 features; /* hardware controller features */ }; +struct flexcan_stop_mode { + struct regmap *gpr; + u8 req_gpr; + u8 req_bit; + u8 ack_gpr; + u8 ack_bit; +}; struct flexcan_priv { struct can_priv can; struct napi_struct napi; @@ -263,7 +270,7 @@ struct flexcan_priv { struct flexcan_platform_data *pdata; const struct flexcan_devtype_data *devtype_data; struct regulator *reg_xceiver; - struct regmap *gpr; + struct flexcan_stop_mode stm; int id; }; @@ -320,28 +327,18 @@ static inline void flexcan_write(u32 val, void __iomem *addr) static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) { - int val; - /* enable stop request */ - if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { - val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ : - IMX6Q_GPR13_CAN1_STOP_REQ; - regmap_update_bits(priv->gpr, IOMUXC_GPR13, - val, val); - } + if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); } static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) { - int val; - /* remove stop request */ - if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { - val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ : - IMX6Q_GPR13_CAN1_STOP_REQ; - regmap_update_bits(priv->gpr, IOMUXC_GPR13, - val, 0); - } + if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) + regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, + 1 << priv->stm.req_bit, 0); } static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) @@ -1183,6 +1180,56 @@ static void unregister_flexcandev(struct net_device *dev) unregister_candev(dev); } +static int flexcan_of_parse_stop_mode(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + struct device_node *node; + struct flexcan_priv *priv; + phandle phandle; + u32 out_val[5]; + int ret; + + if (!np) + return -EINVAL; + /* + * stop mode property format is: + * <&gpr req_gpr req_bit ack_gpr ack_bit>. + */ + ret = of_property_read_u32_array(np, "stop-mode", out_val, 5); + if (ret) { + dev_dbg(&pdev->dev, "no stop-mode property\n"); + return ret; + } + phandle = *out_val; + + node = of_find_node_by_phandle(phandle); + if (!node) { + dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); + return PTR_ERR(node); + } + + priv = netdev_priv(dev); + priv->stm.gpr = syscon_node_to_regmap(node); + if (IS_ERR(priv->stm.gpr)) { + dev_dbg(&pdev->dev, "could not find gpr regmap\n"); + return PTR_ERR(priv->stm.gpr); + } + + of_node_put(node); + + priv->stm.req_gpr = out_val[1]; + priv->stm.req_bit = out_val[2]; + priv->stm.ack_gpr = out_val[3]; + priv->stm.ack_bit = out_val[4]; + + dev_dbg(&pdev->dev, "gpr %s req_gpr 0x%x req_bit %u ack_gpr 0x%x ack_bit %u\n", + node->full_name, priv->stm.req_gpr, + priv->stm.req_bit, priv->stm.ack_gpr, + priv->stm.ack_bit); + return 0; +} + static const struct of_device_id flexcan_of_match[] = { { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, @@ -1294,17 +1341,10 @@ static int flexcan_probe(struct platform_device *pdev) devm_can_led_init(dev); if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { - priv->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "gpr"); - if (IS_ERR(priv->gpr)) { - wakeup = 0; - dev_dbg(&pdev->dev, "can not get grp\n"); - } - - priv->id = of_alias_get_id(pdev->dev.of_node, "flexcan"); - if (priv->id < 0) { + err = flexcan_of_parse_stop_mode(pdev); + if (err) { wakeup = 0; - dev_dbg(&pdev->dev, "can not get alias id\n"); + dev_dbg(&pdev->dev, "failed to parse stop-mode\n"); } } |