summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDong Aisheng <b29396@freescale.com>2014-02-24 14:25:12 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:20:42 +0300
commitcfe9ab6d7ff29ba6540dc4f6cc945be2e7b81ae4 (patch)
tree4ea858c4a7f738eb5516e299fedb746cfb4f0495
parent37abf02aa93eb9dfce7a91bb6b02caff6d1a76ca (diff)
MLK-10131 ENGR00300439-5 can: flexcan: parse stop mode control bits from device tree
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) (cherry picked from commit 6355208605715f7cb9ea8c37e29c577785f66898) Conflicts: arch/arm/boot/dts/imx6qdl.dtsi
-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.c95
3 files changed, 78 insertions, 28 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 5b5cc9625617..3fbe0fa84895 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -553,6 +553,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";
};
@@ -563,6 +564,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 50e71b8b8207..6cc0590ae833 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -33,10 +33,12 @@
#include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
@@ -254,6 +256,13 @@ struct flexcan_devtype_data {
u32 quirks; /* quirks needed for different IP cores */
};
+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;
@@ -267,8 +276,8 @@ struct flexcan_priv {
struct flexcan_platform_data *pdata;
const struct flexcan_devtype_data *devtype_data;
struct regulator *reg_xceiver;
- struct regmap *gpr;
int id;
+ struct flexcan_stop_mode stm;
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
@@ -326,28 +335,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->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
- 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->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);
}
static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
{
- int val;
-
/* remove stop request */
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
- 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->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
+ 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 +1182,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, },
@@ -1293,18 +1342,12 @@ static int flexcan_probe(struct platform_device *pdev)
devm_can_led_init(dev);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
- priv->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "gpr");
- if (IS_ERR(priv->gpr)) {
+ err = flexcan_of_parse_stop_mode(pdev);
+ if (err) {
wakeup = 0;
- dev_dbg(&pdev->dev, "can not get grp\n");
+ dev_dbg(&pdev->dev, "failed to parse stop-mode\n");
}
- priv->id = of_alias_get_id(pdev->dev.of_node, "flexcan");
- if (priv->id < 0) {
- wakeup = 0;
- dev_dbg(&pdev->dev, "can not get alias id\n");
- }
}
device_set_wakeup_capable(&pdev->dev, wakeup);