summaryrefslogtreecommitdiff
path: root/drivers/net/can/flexcan.c
diff options
context:
space:
mode:
authorDong Aisheng <b29396@freescale.com>2014-02-24 14:25:12 +0800
committerOctavian Purdila <octavian.purdila@nxp.com>2017-02-23 14:21:42 +0200
commit1030a379ce4e7bb66ffd18f83cd81fe5f40766c2 (patch)
treebefd3b55d0f4275decbb021d958dab60f7c50419 /drivers/net/can/flexcan.c
parent2166556c18ad7a17b774f89196f398dcecff5fd5 (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
Diffstat (limited to 'drivers/net/can/flexcan.c')
-rw-r--r--drivers/net/can/flexcan.c95
1 files changed, 69 insertions, 26 deletions
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index bedab96a2aab..feeca6a96c3b 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);