]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00300439-5 can: flexcan: parse stop mode control bits from device tree
authorDong Aisheng <b29396@freescale.com>
Mon, 24 Feb 2014 06:25:12 +0000 (14:25 +0800)
committerNitin Garg <nitin.garg@freescale.com>
Fri, 16 Jan 2015 03:17:30 +0000 (21:17 -0600)
Starting from IMX6, the flexcan stop mode control bits is SoC specific,
move it out of IP driver and parse it from devicetree.
It's good from maintain perspective and can avoid adding too many SoC
specifi bits in driver but with no IP changes when the IMX SoC series
keep growing.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
(cherry picked from commit 97b99b59c9f09d58ea35f3c0cf58665c20f2e292)

Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
arch/arm/boot/dts/imx6qdl.dtsi
drivers/net/can/flexcan.c

index d5b8d9f1e723213219722bf403f05d237e81bab4..d8ffe34ec8a0b021f25eb4a85c0d0afbc308a47c 100644 (file)
@@ -16,8 +16,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
index a0d8bf59d878dbfb297553174c239028912cd21a..a1d98493d7e005f7f9d2fc87cabd5c1597800243 100644 (file)
@@ -17,8 +17,6 @@
 
 / {
        aliases {
-               flexcan0 = &flexcan1;
-               flexcan1 = &flexcan2;
                gpio0 = &gpio1;
                gpio1 = &gpio2;
                gpio2 = &gpio3;
                                clocks = <&clks IMX6QDL_CLK_CAN1_IPG>,
                                         <&clks IMX6QDL_CLK_CAN1_SERIAL>;
                                clock-names = "ipg", "per";
-                               gpr = <&gpr>;
+                               stop-mode = <&gpr 0x34 28 0x10 17>;
                                status = "disabled";
                        };
 
                                clocks = <&clks IMX6QDL_CLK_CAN2_IPG>,
                                         <&clks IMX6QDL_CLK_CAN2_SERIAL>;
                                clock-names = "ipg", "per";
-                               gpr = <&gpr>;
+                               stop-mode = <&gpr 0x34 29 0x10 18>;
                                status = "disabled";
                        };
 
index eec2265a1ddbb2c7294b66b558a063ecda2b2a09..b5e3640008a2f607597c64f8de551d7b5504e33c 100644 (file)
@@ -207,6 +207,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 net_device *dev;
@@ -221,7 +228,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;
 };
 
@@ -275,28 +282,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)
@@ -1129,6 +1126,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, },
@@ -1235,17 +1282,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");
                }
        }