summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt9
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi2
-rw-r--r--drivers/net/can/flexcan.c94
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");
}
}