提交 10b3203e 编写于 作者: D David S. Miller

Merge tag 'linux-can-next-for-4.13-20170518' of...

Merge tag 'linux-can-next-for-4.13-20170518' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2017-05-18

this is a pull request of 4 patches for net-next/master.

All 4 patches are by Quentin Schulz, they add deep deep Suspend/Resume
support to the m_can driver.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -621,10 +621,8 @@ static int __m_can_get_berr_counter(const struct net_device *dev, ...@@ -621,10 +621,8 @@ static int __m_can_get_berr_counter(const struct net_device *dev,
return 0; return 0;
} }
static int m_can_get_berr_counter(const struct net_device *dev, static int m_can_clk_start(struct m_can_priv *priv)
struct can_berr_counter *bec)
{ {
struct m_can_priv *priv = netdev_priv(dev);
int err; int err;
err = clk_prepare_enable(priv->hclk); err = clk_prepare_enable(priv->hclk);
...@@ -632,15 +630,31 @@ static int m_can_get_berr_counter(const struct net_device *dev, ...@@ -632,15 +630,31 @@ static int m_can_get_berr_counter(const struct net_device *dev,
return err; return err;
err = clk_prepare_enable(priv->cclk); err = clk_prepare_enable(priv->cclk);
if (err) { if (err)
clk_disable_unprepare(priv->hclk); clk_disable_unprepare(priv->hclk);
return err;
}
__m_can_get_berr_counter(dev, bec); return err;
}
static void m_can_clk_stop(struct m_can_priv *priv)
{
clk_disable_unprepare(priv->cclk); clk_disable_unprepare(priv->cclk);
clk_disable_unprepare(priv->hclk); clk_disable_unprepare(priv->hclk);
}
static int m_can_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
struct m_can_priv *priv = netdev_priv(dev);
int err;
err = m_can_clk_start(priv);
if (err)
return err;
__m_can_get_berr_counter(dev, bec);
m_can_clk_stop(priv);
return 0; return 0;
} }
...@@ -1276,19 +1290,15 @@ static int m_can_open(struct net_device *dev) ...@@ -1276,19 +1290,15 @@ static int m_can_open(struct net_device *dev)
struct m_can_priv *priv = netdev_priv(dev); struct m_can_priv *priv = netdev_priv(dev);
int err; int err;
err = clk_prepare_enable(priv->hclk); err = m_can_clk_start(priv);
if (err) if (err)
return err; return err;
err = clk_prepare_enable(priv->cclk);
if (err)
goto exit_disable_hclk;
/* open the can device */ /* open the can device */
err = open_candev(dev); err = open_candev(dev);
if (err) { if (err) {
netdev_err(dev, "failed to open can device\n"); netdev_err(dev, "failed to open can device\n");
goto exit_disable_cclk; goto exit_disable_clks;
} }
/* register interrupt handler */ /* register interrupt handler */
...@@ -1310,10 +1320,8 @@ static int m_can_open(struct net_device *dev) ...@@ -1310,10 +1320,8 @@ static int m_can_open(struct net_device *dev)
exit_irq_fail: exit_irq_fail:
close_candev(dev); close_candev(dev);
exit_disable_cclk: exit_disable_clks:
clk_disable_unprepare(priv->cclk); m_can_clk_stop(priv);
exit_disable_hclk:
clk_disable_unprepare(priv->hclk);
return err; return err;
} }
...@@ -1324,9 +1332,6 @@ static void m_can_stop(struct net_device *dev) ...@@ -1324,9 +1332,6 @@ static void m_can_stop(struct net_device *dev)
/* disable all interrupts */ /* disable all interrupts */
m_can_disable_all_interrupts(priv); m_can_disable_all_interrupts(priv);
clk_disable_unprepare(priv->hclk);
clk_disable_unprepare(priv->cclk);
/* set the state as STOPPED */ /* set the state as STOPPED */
priv->can.state = CAN_STATE_STOPPED; priv->can.state = CAN_STATE_STOPPED;
} }
...@@ -1338,6 +1343,7 @@ static int m_can_close(struct net_device *dev) ...@@ -1338,6 +1343,7 @@ static int m_can_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
napi_disable(&priv->napi); napi_disable(&priv->napi);
m_can_stop(dev); m_can_stop(dev);
m_can_clk_stop(priv);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
close_candev(dev); close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP); can_led_event(dev, CAN_LED_EVENT_STOP);
...@@ -1489,11 +1495,23 @@ static int register_m_can_dev(struct net_device *dev) ...@@ -1489,11 +1495,23 @@ static int register_m_can_dev(struct net_device *dev)
return register_candev(dev); return register_candev(dev);
} }
static void m_can_init_ram(struct m_can_priv *priv)
{
int end, i, start;
/* initialize the entire Message RAM in use to avoid possible
* ECC/parity checksum errors when reading an uninitialized buffer
*/
start = priv->mcfg[MRAM_SIDF].off;
end = priv->mcfg[MRAM_TXB].off +
priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
for (i = start; i < end; i += 4)
writel(0x0, priv->mram_base + i);
}
static void m_can_of_parse_mram(struct m_can_priv *priv, static void m_can_of_parse_mram(struct m_can_priv *priv,
const u32 *mram_config_vals) const u32 *mram_config_vals)
{ {
int i, start, end;
priv->mcfg[MRAM_SIDF].off = mram_config_vals[0]; priv->mcfg[MRAM_SIDF].off = mram_config_vals[0];
priv->mcfg[MRAM_SIDF].num = mram_config_vals[1]; priv->mcfg[MRAM_SIDF].num = mram_config_vals[1];
priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off + priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
...@@ -1529,15 +1547,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv, ...@@ -1529,15 +1547,7 @@ static void m_can_of_parse_mram(struct m_can_priv *priv,
priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num, priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num); priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
/* initialize the entire Message RAM in use to avoid possible m_can_init_ram(priv);
* ECC/parity checksum errors when reading an uninitialized buffer
*/
start = priv->mcfg[MRAM_SIDF].off;
end = priv->mcfg[MRAM_TXB].off +
priv->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
for (i = start; i < end; i += 4)
writel(0x0, priv->mram_base + i);
} }
static int m_can_plat_probe(struct platform_device *pdev) static int m_can_plat_probe(struct platform_device *pdev)
...@@ -1658,6 +1668,8 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -1658,6 +1668,8 @@ static int m_can_plat_probe(struct platform_device *pdev)
return ret; return ret;
} }
/* TODO: runtime PM with power down or sleep mode */
static __maybe_unused int m_can_suspend(struct device *dev) static __maybe_unused int m_can_suspend(struct device *dev)
{ {
struct net_device *ndev = dev_get_drvdata(dev); struct net_device *ndev = dev_get_drvdata(dev);
...@@ -1666,10 +1678,10 @@ static __maybe_unused int m_can_suspend(struct device *dev) ...@@ -1666,10 +1678,10 @@ static __maybe_unused int m_can_suspend(struct device *dev)
if (netif_running(ndev)) { if (netif_running(ndev)) {
netif_stop_queue(ndev); netif_stop_queue(ndev);
netif_device_detach(ndev); netif_device_detach(ndev);
m_can_stop(ndev);
m_can_clk_stop(priv);
} }
/* TODO: enter low power */
priv->can.state = CAN_STATE_SLEEPING; priv->can.state = CAN_STATE_SLEEPING;
return 0; return 0;
...@@ -1680,11 +1692,18 @@ static __maybe_unused int m_can_resume(struct device *dev) ...@@ -1680,11 +1692,18 @@ static __maybe_unused int m_can_resume(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev); struct net_device *ndev = dev_get_drvdata(dev);
struct m_can_priv *priv = netdev_priv(ndev); struct m_can_priv *priv = netdev_priv(ndev);
/* TODO: exit low power */ m_can_init_ram(priv);
priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(ndev)) { if (netif_running(ndev)) {
int ret;
ret = m_can_clk_start(priv);
if (ret)
return ret;
m_can_start(ndev);
netif_device_attach(ndev); netif_device_attach(ndev);
netif_start_queue(ndev); netif_start_queue(ndev);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册