Commit 862e2b6a authored by Sergei Shtylyov's avatar Sergei Shtylyov Committed by Marc Kleine-Budde

can: rcar_can: support all input clocks

When writing the driver, I didn't give enough attention to the possible sources
of the CAN clock: although the value of the CLKR register was specified by the
platform data, the driver only handled one case, that is CAN clock being
sourced from the clkp1 clock, the same that clocks the whole CAN module. In
order to fix that overlook, we'll have to handle the CAN clock separately from
the peripheral clock (however, clkp1 will be specified for a CAN device only
once)...
Signed-off-by: default avatarSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent e0d1f481
...@@ -87,6 +87,7 @@ struct rcar_can_priv { ...@@ -87,6 +87,7 @@ struct rcar_can_priv {
struct napi_struct napi; struct napi_struct napi;
struct rcar_can_regs __iomem *regs; struct rcar_can_regs __iomem *regs;
struct clk *clk; struct clk *clk;
struct clk *can_clk;
u8 tx_dlc[RCAR_CAN_FIFO_DEPTH]; u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
u32 tx_head; u32 tx_head;
u32 tx_tail; u32 tx_tail;
...@@ -505,14 +506,20 @@ static int rcar_can_open(struct net_device *ndev) ...@@ -505,14 +506,20 @@ static int rcar_can_open(struct net_device *ndev)
err = clk_prepare_enable(priv->clk); err = clk_prepare_enable(priv->clk);
if (err) { if (err) {
netdev_err(ndev, "clk_prepare_enable() failed, error %d\n", netdev_err(ndev, "failed to enable periperal clock, error %d\n",
err); err);
goto out; goto out;
} }
err = clk_prepare_enable(priv->can_clk);
if (err) {
netdev_err(ndev, "failed to enable CAN clock, error %d\n",
err);
goto out_clock;
}
err = open_candev(ndev); err = open_candev(ndev);
if (err) { if (err) {
netdev_err(ndev, "open_candev() failed, error %d\n", err); netdev_err(ndev, "open_candev() failed, error %d\n", err);
goto out_clock; goto out_can_clock;
} }
napi_enable(&priv->napi); napi_enable(&priv->napi);
err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev); err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
...@@ -527,6 +534,8 @@ static int rcar_can_open(struct net_device *ndev) ...@@ -527,6 +534,8 @@ static int rcar_can_open(struct net_device *ndev)
out_close: out_close:
napi_disable(&priv->napi); napi_disable(&priv->napi);
close_candev(ndev); close_candev(ndev);
out_can_clock:
clk_disable_unprepare(priv->can_clk);
out_clock: out_clock:
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
out: out:
...@@ -565,6 +574,7 @@ static int rcar_can_close(struct net_device *ndev) ...@@ -565,6 +574,7 @@ static int rcar_can_close(struct net_device *ndev)
rcar_can_stop(ndev); rcar_can_stop(ndev);
free_irq(ndev->irq, ndev); free_irq(ndev->irq, ndev);
napi_disable(&priv->napi); napi_disable(&priv->napi);
clk_disable_unprepare(priv->can_clk);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
close_candev(ndev); close_candev(ndev);
can_led_event(ndev, CAN_LED_EVENT_STOP); can_led_event(ndev, CAN_LED_EVENT_STOP);
...@@ -715,6 +725,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev, ...@@ -715,6 +725,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev,
return 0; return 0;
} }
static const char * const clock_names[] = {
[CLKR_CLKP1] = "clkp1",
[CLKR_CLKP2] = "clkp2",
[CLKR_CLKEXT] = "can_clk",
};
static int rcar_can_probe(struct platform_device *pdev) static int rcar_can_probe(struct platform_device *pdev)
{ {
struct rcar_can_platform_data *pdata; struct rcar_can_platform_data *pdata;
...@@ -722,6 +738,7 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -722,6 +738,7 @@ static int rcar_can_probe(struct platform_device *pdev)
struct net_device *ndev; struct net_device *ndev;
struct resource *mem; struct resource *mem;
void __iomem *addr; void __iomem *addr;
u32 clock_select;
int err = -ENODEV; int err = -ENODEV;
int irq; int irq;
...@@ -730,6 +747,7 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -730,6 +747,7 @@ static int rcar_can_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "No platform data provided!\n"); dev_err(&pdev->dev, "No platform data provided!\n");
goto fail; goto fail;
} }
clock_select = pdata->clock_select;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!irq) { if (!irq) {
...@@ -753,10 +771,22 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -753,10 +771,22 @@ static int rcar_can_probe(struct platform_device *pdev)
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
priv->clk = devm_clk_get(&pdev->dev, NULL); priv->clk = devm_clk_get(&pdev->dev, "clkp1");
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
err = PTR_ERR(priv->clk); err = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", err); dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err);
goto fail_clk;
}
if (clock_select >= ARRAY_SIZE(clock_names)) {
err = -EINVAL;
dev_err(&pdev->dev, "invalid CAN clock selected\n");
goto fail_clk;
}
priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]);
if (IS_ERR(priv->can_clk)) {
err = PTR_ERR(priv->can_clk);
dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err);
goto fail_clk; goto fail_clk;
} }
...@@ -765,8 +795,8 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -765,8 +795,8 @@ static int rcar_can_probe(struct platform_device *pdev)
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
priv->ndev = ndev; priv->ndev = ndev;
priv->regs = addr; priv->regs = addr;
priv->clock_select = pdata->clock_select; priv->clock_select = clock_select;
priv->can.clock.freq = clk_get_rate(priv->clk); priv->can.clock.freq = clk_get_rate(priv->can_clk);
priv->can.bittiming_const = &rcar_can_bittiming_const; priv->can.bittiming_const = &rcar_can_bittiming_const;
priv->can.do_set_mode = rcar_can_do_set_mode; priv->can.do_set_mode = rcar_can_do_set_mode;
priv->can.do_get_berr_counter = rcar_can_get_berr_counter; priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment