Skip to content

Commit de3578c

Browse files
Aisheng Dongmarckleinebudde
authored andcommitted
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. Starting from IMX6, the flexcan stop mode control bits is SoC specific, move it out of IP driver and parse it from devicetree. Signed-off-by: Aisheng Dong <[email protected]> Signed-off-by: Joakim Zhang <[email protected]> Reviewed-by: Dong Aisheng <[email protected]> Signed-off-by: Marc Kleine-Budde <[email protected]>
1 parent b9c9c39 commit de3578c

File tree

1 file changed

+164
-9
lines changed

1 file changed

+164
-9
lines changed

drivers/net/can/flexcan.c

Lines changed: 164 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#include <linux/delay.h>
2020
#include <linux/interrupt.h>
2121
#include <linux/io.h>
22+
#include <linux/mfd/syscon.h>
2223
#include <linux/module.h>
2324
#include <linux/of.h>
2425
#include <linux/of_device.h>
2526
#include <linux/platform_device.h>
2627
#include <linux/regulator/consumer.h>
28+
#include <linux/regmap.h>
2729

2830
#define DRV_NAME "flexcan"
2931

@@ -131,7 +133,8 @@
131133
(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
132134
#define FLEXCAN_ESR_ALL_INT \
133135
(FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
134-
FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
136+
FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
137+
FLEXCAN_ESR_WAK_INT)
135138

136139
/* FLEXCAN interrupt flag register (IFLAG) bits */
137140
/* Errata ERR005829 step7: Reserve first valid MB */
@@ -189,6 +192,7 @@
189192
#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) /* Use timestamp based offloading */
190193
#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) /* No interrupt for error passive */
191194
#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) /* default to BE register access */
195+
#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) /* Setup stop mode to support wakeup */
192196

193197
/* Structure of the message buffer */
194198
struct flexcan_mb {
@@ -253,6 +257,14 @@ struct flexcan_devtype_data {
253257
u32 quirks; /* quirks needed for different IP cores */
254258
};
255259

260+
struct flexcan_stop_mode {
261+
struct regmap *gpr;
262+
u8 req_gpr;
263+
u8 req_bit;
264+
u8 ack_gpr;
265+
u8 ack_bit;
266+
};
267+
256268
struct flexcan_priv {
257269
struct can_priv can;
258270
struct can_rx_offload offload;
@@ -267,6 +279,7 @@ struct flexcan_priv {
267279
struct clk *clk_per;
268280
const struct flexcan_devtype_data *devtype_data;
269281
struct regulator *reg_xceiver;
282+
struct flexcan_stop_mode stm;
270283

271284
/* Read and Write APIs */
272285
u32 (*read)(void __iomem *addr);
@@ -290,7 +303,8 @@ static const struct flexcan_devtype_data fsl_imx28_devtype_data = {
290303

291304
static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
292305
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
293-
FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE,
306+
FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
307+
FLEXCAN_QUIRK_SETUP_STOP_MODE,
294308
};
295309

296310
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
@@ -350,6 +364,49 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr)
350364
iowrite32(val, addr);
351365
}
352366

367+
static void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable)
368+
{
369+
struct flexcan_regs __iomem *regs = priv->regs;
370+
u32 reg_mcr;
371+
372+
reg_mcr = priv->read(&regs->mcr);
373+
374+
if (enable)
375+
reg_mcr |= FLEXCAN_MCR_WAK_MSK;
376+
else
377+
reg_mcr &= ~FLEXCAN_MCR_WAK_MSK;
378+
379+
priv->write(reg_mcr, &regs->mcr);
380+
}
381+
382+
static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
383+
{
384+
struct flexcan_regs __iomem *regs = priv->regs;
385+
u32 reg_mcr;
386+
387+
reg_mcr = priv->read(&regs->mcr);
388+
reg_mcr |= FLEXCAN_MCR_SLF_WAK;
389+
priv->write(reg_mcr, &regs->mcr);
390+
391+
/* enable stop request */
392+
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
393+
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
394+
}
395+
396+
static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
397+
{
398+
struct flexcan_regs __iomem *regs = priv->regs;
399+
u32 reg_mcr;
400+
401+
/* remove stop request */
402+
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
403+
1 << priv->stm.req_bit, 0);
404+
405+
reg_mcr = priv->read(&regs->mcr);
406+
reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
407+
priv->write(reg_mcr, &regs->mcr);
408+
}
409+
353410
static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
354411
{
355412
struct flexcan_regs __iomem *regs = priv->regs;
@@ -1265,6 +1322,59 @@ static void unregister_flexcandev(struct net_device *dev)
12651322
unregister_candev(dev);
12661323
}
12671324

1325+
static int flexcan_setup_stop_mode(struct platform_device *pdev)
1326+
{
1327+
struct net_device *dev = platform_get_drvdata(pdev);
1328+
struct device_node *np = pdev->dev.of_node;
1329+
struct device_node *gpr_np;
1330+
struct flexcan_priv *priv;
1331+
phandle phandle;
1332+
u32 out_val[5];
1333+
int ret;
1334+
1335+
if (!np)
1336+
return -EINVAL;
1337+
1338+
/* stop mode property format is:
1339+
* <&gpr req_gpr req_bit ack_gpr ack_bit>.
1340+
*/
1341+
ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
1342+
ARRAY_SIZE(out_val));
1343+
if (ret) {
1344+
dev_dbg(&pdev->dev, "no stop-mode property\n");
1345+
return ret;
1346+
}
1347+
phandle = *out_val;
1348+
1349+
gpr_np = of_find_node_by_phandle(phandle);
1350+
if (!gpr_np) {
1351+
dev_dbg(&pdev->dev, "could not find gpr node by phandle\n");
1352+
return PTR_ERR(gpr_np);
1353+
}
1354+
1355+
priv = netdev_priv(dev);
1356+
priv->stm.gpr = syscon_node_to_regmap(gpr_np);
1357+
of_node_put(gpr_np);
1358+
if (IS_ERR(priv->stm.gpr)) {
1359+
dev_dbg(&pdev->dev, "could not find gpr regmap\n");
1360+
return PTR_ERR(priv->stm.gpr);
1361+
}
1362+
1363+
priv->stm.req_gpr = out_val[1];
1364+
priv->stm.req_bit = out_val[2];
1365+
priv->stm.ack_gpr = out_val[3];
1366+
priv->stm.ack_bit = out_val[4];
1367+
1368+
dev_dbg(&pdev->dev,
1369+
"gpr %s req_gpr=0x02%x req_bit=%u ack_gpr=0x02%x ack_bit=%u\n",
1370+
gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit,
1371+
priv->stm.ack_gpr, priv->stm.ack_bit);
1372+
1373+
device_set_wakeup_capable(&pdev->dev, true);
1374+
1375+
return 0;
1376+
}
1377+
12681378
static const struct of_device_id flexcan_of_match[] = {
12691379
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
12701380
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
@@ -1413,6 +1523,12 @@ static int flexcan_probe(struct platform_device *pdev)
14131523

14141524
devm_can_led_init(dev);
14151525

1526+
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
1527+
err = flexcan_setup_stop_mode(pdev);
1528+
if (err)
1529+
dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
1530+
}
1531+
14161532
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
14171533
priv->regs, dev->irq);
14181534

@@ -1443,9 +1559,17 @@ static int __maybe_unused flexcan_suspend(struct device *device)
14431559
int err;
14441560

14451561
if (netif_running(dev)) {
1446-
err = flexcan_chip_disable(priv);
1447-
if (err)
1448-
return err;
1562+
/* if wakeup is enabled, enter stop mode
1563+
* else enter disabled mode.
1564+
*/
1565+
if (device_may_wakeup(device)) {
1566+
enable_irq_wake(dev->irq);
1567+
flexcan_enter_stop_mode(priv);
1568+
} else {
1569+
err = flexcan_chip_disable(priv);
1570+
if (err)
1571+
return err;
1572+
}
14491573
netif_stop_queue(dev);
14501574
netif_device_detach(dev);
14511575
}
@@ -1464,14 +1588,45 @@ static int __maybe_unused flexcan_resume(struct device *device)
14641588
if (netif_running(dev)) {
14651589
netif_device_attach(dev);
14661590
netif_start_queue(dev);
1467-
err = flexcan_chip_enable(priv);
1468-
if (err)
1469-
return err;
1591+
if (device_may_wakeup(device)) {
1592+
disable_irq_wake(dev->irq);
1593+
} else {
1594+
err = flexcan_chip_enable(priv);
1595+
if (err)
1596+
return err;
1597+
}
14701598
}
14711599
return 0;
14721600
}
14731601

1474-
static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
1602+
static int __maybe_unused flexcan_noirq_suspend(struct device *device)
1603+
{
1604+
struct net_device *dev = dev_get_drvdata(device);
1605+
struct flexcan_priv *priv = netdev_priv(dev);
1606+
1607+
if (netif_running(dev) && device_may_wakeup(device))
1608+
flexcan_enable_wakeup_irq(priv, true);
1609+
1610+
return 0;
1611+
}
1612+
1613+
static int __maybe_unused flexcan_noirq_resume(struct device *device)
1614+
{
1615+
struct net_device *dev = dev_get_drvdata(device);
1616+
struct flexcan_priv *priv = netdev_priv(dev);
1617+
1618+
if (netif_running(dev) && device_may_wakeup(device)) {
1619+
flexcan_enable_wakeup_irq(priv, false);
1620+
flexcan_exit_stop_mode(priv);
1621+
}
1622+
1623+
return 0;
1624+
}
1625+
1626+
static const struct dev_pm_ops flexcan_pm_ops = {
1627+
SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume)
1628+
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(flexcan_noirq_suspend, flexcan_noirq_resume)
1629+
};
14751630

14761631
static struct platform_driver flexcan_driver = {
14771632
.driver = {

0 commit comments

Comments
 (0)