diff options
author | Dong Aisheng <b29396@freescale.com> | 2014-02-24 01:25:12 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:57:45 -0400 |
commit | 86b9f774641a71883e02fcad8562bb8432ac7ce9 (patch) | |
tree | 9d29190cf7734d88db1faaef879403c2bc54d7e2 | |
parent | 43486fbef10c525fb5c23f4de11811c48fe0db46 (diff) |
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>
-rw-r--r-- | Documentation/devicetree/bindings/net/can/fsl-flexcan.txt | 9 | ||||
-rw-r--r-- | arch/arm/boot/dts/imx6qdl.dtsi | 6 | ||||
-rw-r--r-- | drivers/net/can/flexcan.c | 94 |
3 files changed, 76 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt index 487e8a63eff1..0a4dfaab4a54 100644 --- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt | |||
@@ -15,8 +15,13 @@ Required properties: | |||
15 | Optional properties: | 15 | Optional properties: |
16 | 16 | ||
17 | - clock-frequency : The oscillator frequency driving the flexcan device | 17 | - clock-frequency : The oscillator frequency driving the flexcan device |
18 | - gpr: phandle to general purpose register node. The remote wakeup control | 18 | - stop-mode: register bits of stop mode control, the format is |
19 | bits is stored here. | 19 | <&gpr req_gpr req_bit ack_gpr ack_bit>. |
20 | gpr is the phandle to general purpose register node. | ||
21 | req_gpr is the gpr register offset of CAN stop request. | ||
22 | req_bit is the bit offset of CAN stop request. | ||
23 | ack_gpr is the gpr register offset of CAN stop acknowledge. | ||
24 | ack_bit is the bit offset of CAN stop acknowledge. | ||
20 | 25 | ||
21 | Below are gpios for tranceiver: | 26 | Below are gpios for tranceiver: |
22 | - trx_en_gpio : enable gpio | 27 | - trx_en_gpio : enable gpio |
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index ea8ec2a501d0..847310166f60 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi | |||
@@ -15,8 +15,6 @@ | |||
15 | 15 | ||
16 | / { | 16 | / { |
17 | aliases { | 17 | aliases { |
18 | flexcan0 = &flexcan1; | ||
19 | flexcan1 = &flexcan2; | ||
20 | gpio0 = &gpio1; | 18 | gpio0 = &gpio1; |
21 | gpio1 = &gpio2; | 19 | gpio1 = &gpio2; |
22 | gpio2 = &gpio3; | 20 | gpio2 = &gpio3; |
@@ -382,7 +380,7 @@ | |||
382 | interrupts = <0 110 0x04>; | 380 | interrupts = <0 110 0x04>; |
383 | clocks = <&clks 108>, <&clks 109>; | 381 | clocks = <&clks 108>, <&clks 109>; |
384 | clock-names = "ipg", "per"; | 382 | clock-names = "ipg", "per"; |
385 | gpr = <&gpr>; | 383 | stop-mode = <&gpr 0x34 28 0x10 17>; |
386 | status = "disabled"; | 384 | status = "disabled"; |
387 | }; | 385 | }; |
388 | 386 | ||
@@ -392,7 +390,7 @@ | |||
392 | interrupts = <0 111 0x04>; | 390 | interrupts = <0 111 0x04>; |
393 | clocks = <&clks 110>, <&clks 111>; | 391 | clocks = <&clks 110>, <&clks 111>; |
394 | clock-names = "ipg", "per"; | 392 | clock-names = "ipg", "per"; |
395 | gpr = <&gpr>; | 393 | stop-mode = <&gpr 0x34 29 0x10 18>; |
396 | status = "disabled"; | 394 | status = "disabled"; |
397 | }; | 395 | }; |
398 | 396 | ||
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index a89765b81df5..82c022b313cd 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c | |||
@@ -205,6 +205,13 @@ struct flexcan_devtype_data { | |||
205 | u32 features; /* hardware controller features */ | 205 | u32 features; /* hardware controller features */ |
206 | }; | 206 | }; |
207 | 207 | ||
208 | struct flexcan_stop_mode { | ||
209 | struct regmap *gpr; | ||
210 | u8 req_gpr; | ||
211 | u8 req_bit; | ||
212 | u8 ack_gpr; | ||
213 | u8 ack_bit; | ||
214 | }; | ||
208 | struct flexcan_priv { | 215 | struct flexcan_priv { |
209 | struct can_priv can; | 216 | struct can_priv can; |
210 | struct net_device *dev; | 217 | struct net_device *dev; |
@@ -218,7 +225,7 @@ struct flexcan_priv { | |||
218 | struct clk *clk_per; | 225 | struct clk *clk_per; |
219 | struct flexcan_platform_data *pdata; | 226 | struct flexcan_platform_data *pdata; |
220 | const struct flexcan_devtype_data *devtype_data; | 227 | const struct flexcan_devtype_data *devtype_data; |
221 | struct regmap *gpr; | 228 | struct flexcan_stop_mode stm; |
222 | int id; | 229 | int id; |
223 | }; | 230 | }; |
224 | 231 | ||
@@ -269,28 +276,18 @@ static inline void flexcan_write(u32 val, void __iomem *addr) | |||
269 | 276 | ||
270 | static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) | 277 | static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv) |
271 | { | 278 | { |
272 | int val; | ||
273 | |||
274 | /* enable stop request */ | 279 | /* enable stop request */ |
275 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { | 280 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) |
276 | val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ : | 281 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
277 | IMX6Q_GPR13_CAN1_STOP_REQ; | 282 | 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); |
278 | regmap_update_bits(priv->gpr, IOMUXC_GPR13, | ||
279 | val, val); | ||
280 | } | ||
281 | } | 283 | } |
282 | 284 | ||
283 | static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) | 285 | static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv) |
284 | { | 286 | { |
285 | int val; | ||
286 | |||
287 | /* remove stop request */ | 287 | /* remove stop request */ |
288 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { | 288 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) |
289 | val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ : | 289 | regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, |
290 | IMX6Q_GPR13_CAN1_STOP_REQ; | 290 | 1 << priv->stm.req_bit, 0); |
291 | regmap_update_bits(priv->gpr, IOMUXC_GPR13, | ||
292 | val, 0); | ||
293 | } | ||
294 | } | 291 | } |
295 | 292 | ||
296 | /* | 293 | /* |
@@ -1019,6 +1016,56 @@ static void unregister_flexcandev(struct net_device *dev) | |||
1019 | unregister_candev(dev); | 1016 | unregister_candev(dev); |
1020 | } | 1017 | } |
1021 | 1018 | ||
1019 | static int flexcan_of_parse_stop_mode(struct platform_device *pdev) | ||
1020 | { | ||
1021 | struct net_device *dev = platform_get_drvdata(pdev); | ||
1022 | struct device_node *np = pdev->dev.of_node; | ||
1023 | struct device_node *node; | ||
1024 | struct flexcan_priv *priv; | ||
1025 | phandle phandle; | ||
1026 | u32 out_val[5]; | ||
1027 | int ret; | ||
1028 | |||
1029 | if (!np) | ||
1030 | return -EINVAL; | ||
1031 | /* | ||
1032 | * stop mode property format is: | ||
1033 | * <&gpr req_gpr req_bit ack_gpr ack_bit>. | ||
1034 | */ | ||
1035 | ret = of_property_read_u32_array(np, "stop-mode", out_val, 5); | ||
1036 | if (ret) { | ||
1037 | dev_dbg(&pdev->dev, "no stop-mode property\n"); | ||
1038 | return ret; | ||
1039 | } | ||
1040 | phandle = *out_val; | ||
1041 | |||
1042 | node = of_find_node_by_phandle(phandle); | ||
1043 | if (!node) { | ||
1044 | dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); | ||
1045 | return PTR_ERR(node); | ||
1046 | } | ||
1047 | |||
1048 | priv = netdev_priv(dev); | ||
1049 | priv->stm.gpr = syscon_node_to_regmap(node); | ||
1050 | if (IS_ERR(priv->stm.gpr)) { | ||
1051 | dev_dbg(&pdev->dev, "could not find gpr regmap\n"); | ||
1052 | return PTR_ERR(priv->stm.gpr); | ||
1053 | } | ||
1054 | |||
1055 | of_node_put(node); | ||
1056 | |||
1057 | priv->stm.req_gpr = out_val[1]; | ||
1058 | priv->stm.req_bit = out_val[2]; | ||
1059 | priv->stm.ack_gpr = out_val[3]; | ||
1060 | priv->stm.ack_bit = out_val[4]; | ||
1061 | |||
1062 | dev_dbg(&pdev->dev, "gpr %s req_gpr 0x%x req_bit %u ack_gpr 0x%x ack_bit %u\n", | ||
1063 | node->full_name, priv->stm.req_gpr, | ||
1064 | priv->stm.req_bit, priv->stm.ack_gpr, | ||
1065 | priv->stm.ack_bit); | ||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1022 | static const struct of_device_id flexcan_of_match[] = { | 1069 | static const struct of_device_id flexcan_of_match[] = { |
1023 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, | 1070 | { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, |
1024 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, | 1071 | { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, |
@@ -1143,17 +1190,10 @@ static int flexcan_probe(struct platform_device *pdev) | |||
1143 | devm_can_led_init(dev); | 1190 | devm_can_led_init(dev); |
1144 | 1191 | ||
1145 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { | 1192 | if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) { |
1146 | priv->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | 1193 | err = flexcan_of_parse_stop_mode(pdev); |
1147 | "gpr"); | 1194 | if (err) { |
1148 | if (IS_ERR(priv->gpr)) { | ||
1149 | wakeup = 0; | ||
1150 | dev_dbg(&pdev->dev, "can not get grp\n"); | ||
1151 | } | ||
1152 | |||
1153 | priv->id = of_alias_get_id(pdev->dev.of_node, "flexcan"); | ||
1154 | if (priv->id < 0) { | ||
1155 | wakeup = 0; | 1195 | wakeup = 0; |
1156 | dev_dbg(&pdev->dev, "can not get alias id\n"); | 1196 | dev_dbg(&pdev->dev, "failed to parse stop-mode\n"); |
1157 | } | 1197 | } |
1158 | } | 1198 | } |
1159 | 1199 | ||