aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDong Aisheng <b29396@freescale.com>2013-11-06 06:10:28 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:47:05 -0400
commit1252db8f4bab1122a8daf28af6208549f650dae0 (patch)
tree74aa4c78b5641c59114c3ed459215818a9f660e5
parent38f373d10d3d14972a73ad30a4ecaa83f8152c64 (diff)
ENGR00286724-8 can: flexcan: add self wakeup support
If wakeup is enabled, enter stop mode, else enter disabled mode. Self wake can only work on stop mode. For imx6q, the stop request has to be mannually assert on IOMUX GPR13[28:29] register, we use syscon to control that bit. Signed-off-by: Dong Aisheng <b29396@freescale.com>
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt2
-rw-r--r--drivers/net/can/flexcan.c82
2 files changed, 79 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index e57c610c3a78..487e8a63eff1 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -15,6 +15,8 @@ Required properties:
15Optional properties: 15Optional 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
19 bits is stored here.
18 20
19Below are gpios for tranceiver: 21Below are gpios for tranceiver:
20- trx_en_gpio : enable gpio 22- trx_en_gpio : enable gpio
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 152558de92f7..e99e4d04ee43 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -33,11 +33,14 @@
33#include <linux/io.h> 33#include <linux/io.h>
34#include <linux/kernel.h> 34#include <linux/kernel.h>
35#include <linux/list.h> 35#include <linux/list.h>
36#include <linux/mfd/syscon.h>
37#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
36#include <linux/module.h> 38#include <linux/module.h>
37#include <linux/of.h> 39#include <linux/of.h>
38#include <linux/of_device.h> 40#include <linux/of_device.h>
39#include <linux/platform_device.h> 41#include <linux/platform_device.h>
40#include <linux/pinctrl/consumer.h> 42#include <linux/pinctrl/consumer.h>
43#include <linux/regmap.h>
41 44
42#define DRV_NAME "flexcan" 45#define DRV_NAME "flexcan"
43 46
@@ -123,7 +126,8 @@
123 (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) 126 (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
124#define FLEXCAN_ESR_ALL_INT \ 127#define FLEXCAN_ESR_ALL_INT \
125 (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \ 128 (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
126 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT) 129 FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
130 FLEXCAN_ESR_WAK_INT)
127 131
128/* FLEXCAN interrupt flag register (IFLAG) bits */ 132/* FLEXCAN interrupt flag register (IFLAG) bits */
129#define FLEXCAN_TX_BUF_ID 8 133#define FLEXCAN_TX_BUF_ID 8
@@ -212,6 +216,8 @@ struct flexcan_priv {
212 struct clk *clk_per; 216 struct clk *clk_per;
213 struct flexcan_platform_data *pdata; 217 struct flexcan_platform_data *pdata;
214 const struct flexcan_devtype_data *devtype_data; 218 const struct flexcan_devtype_data *devtype_data;
219 struct regmap *gpr;
220 int id;
215}; 221};
216 222
217static struct flexcan_devtype_data fsl_p1010_devtype_data = { 223static struct flexcan_devtype_data fsl_p1010_devtype_data = {
@@ -259,6 +265,32 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
259} 265}
260#endif 266#endif
261 267
268static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
269{
270 int val;
271
272 /* enable stop request */
273 if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) {
274 val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ :
275 IMX6Q_GPR13_CAN1_STOP_REQ;
276 regmap_update_bits(priv->gpr, IOMUXC_GPR13,
277 val, val);
278 }
279}
280
281static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
282{
283 int val;
284
285 /* remove stop request */
286 if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) {
287 val = priv->id ? IMX6Q_GPR13_CAN2_STOP_REQ :
288 IMX6Q_GPR13_CAN1_STOP_REQ;
289 regmap_update_bits(priv->gpr, IOMUXC_GPR13,
290 val, 0);
291 }
292}
293
262/* 294/*
263 * Swtich transceiver on or off 295 * Swtich transceiver on or off
264 */ 296 */
@@ -623,6 +655,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
623 if (reg_esr & FLEXCAN_ESR_ALL_INT) 655 if (reg_esr & FLEXCAN_ESR_ALL_INT)
624 flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, &regs->esr); 656 flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, &regs->esr);
625 657
658 if (reg_esr & FLEXCAN_ESR_WAK_INT)
659 flexcan_exit_stop_mode(priv);
660
626 /* 661 /*
627 * schedule NAPI in case of: 662 * schedule NAPI in case of:
628 * - rx IRQ 663 * - rx IRQ
@@ -741,13 +776,14 @@ static int flexcan_chip_start(struct net_device *dev)
741 * enable warning int 776 * enable warning int
742 * choose format C 777 * choose format C
743 * disable local echo 778 * disable local echo
744 * 779 * enable self wakeup
745 */ 780 */
746 reg_mcr = flexcan_read(&regs->mcr); 781 reg_mcr = flexcan_read(&regs->mcr);
747 reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); 782 reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
748 reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT | 783 reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
749 FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | 784 FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
750 FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS | 785 FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
786 FLEXCAN_MCR_WAK_MSK | FLEXCAN_MCR_SLF_WAK |
751 FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID); 787 FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
752 netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); 788 netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
753 flexcan_write(reg_mcr, &regs->mcr); 789 flexcan_write(reg_mcr, &regs->mcr);
@@ -1003,6 +1039,7 @@ static int flexcan_probe(struct platform_device *pdev)
1003 resource_size_t mem_size; 1039 resource_size_t mem_size;
1004 int err, irq; 1040 int err, irq;
1005 u32 clock_freq = 0; 1041 u32 clock_freq = 0;
1042 int wakeup = 1;
1006 1043
1007 pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 1044 pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
1008 if (IS_ERR(pinctrl)) 1045 if (IS_ERR(pinctrl))
@@ -1098,6 +1135,23 @@ static int flexcan_probe(struct platform_device *pdev)
1098 1135
1099 devm_can_led_init(dev); 1136 devm_can_led_init(dev);
1100 1137
1138 if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) {
1139 priv->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
1140 "gpr");
1141 if (IS_ERR(priv->gpr)) {
1142 wakeup = 0;
1143 dev_dbg(&pdev->dev, "can not get grp\n");
1144 }
1145
1146 priv->id = of_alias_get_id(pdev->dev.of_node, "flexcan");
1147 if (priv->id < 0) {
1148 wakeup = 0;
1149 dev_dbg(&pdev->dev, "can not get alias id\n");
1150 }
1151 }
1152
1153 device_set_wakeup_capable(&pdev->dev, wakeup);
1154
1101 dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", 1155 dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
1102 priv->base, dev->irq); 1156 priv->base, dev->irq);
1103 1157
@@ -1139,11 +1193,21 @@ static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
1139 struct net_device *dev = platform_get_drvdata(pdev); 1193 struct net_device *dev = platform_get_drvdata(pdev);
1140 struct flexcan_priv *priv = netdev_priv(dev); 1194 struct flexcan_priv *priv = netdev_priv(dev);
1141 1195
1142 flexcan_chip_disable(priv);
1143
1144 if (netif_running(dev)) { 1196 if (netif_running(dev)) {
1145 netif_stop_queue(dev); 1197 netif_stop_queue(dev);
1146 netif_device_detach(dev); 1198 netif_device_detach(dev);
1199 /*
1200 * if wakeup is enabled, enter stop mode
1201 * else enter disabled mode.
1202 */
1203 if (device_may_wakeup(&pdev->dev)) {
1204 enable_irq_wake(dev->irq);
1205 flexcan_enter_stop_mode(priv);
1206 } else {
1207 flexcan_chip_disable(priv);
1208 }
1209 } else {
1210 flexcan_chip_disable(priv);
1147 } 1211 }
1148 priv->can.state = CAN_STATE_SLEEPING; 1212 priv->can.state = CAN_STATE_SLEEPING;
1149 1213
@@ -1159,8 +1223,16 @@ static int flexcan_resume(struct platform_device *pdev)
1159 if (netif_running(dev)) { 1223 if (netif_running(dev)) {
1160 netif_device_attach(dev); 1224 netif_device_attach(dev);
1161 netif_start_queue(dev); 1225 netif_start_queue(dev);
1226
1227 if (device_may_wakeup(&pdev->dev)) {
1228 disable_irq_wake(dev->irq);
1229 flexcan_exit_stop_mode(priv);
1230 } else {
1231 flexcan_chip_enable(priv);
1232 }
1233 } else {
1234 flexcan_chip_enable(priv);
1162 } 1235 }
1163 flexcan_chip_enable(priv);
1164 1236
1165 return 0; 1237 return 0;
1166} 1238}