summaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch')
-rw-r--r--meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch139
1 files changed, 139 insertions, 0 deletions
diff --git a/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch
new file mode 100644
index 0000000..65f33af
--- /dev/null
+++ b/meta-rcar-gen2/recipes-kernel/linux/linux-renesas/0015-can-rcar_can-support-all-input-clocks.patch
@@ -0,0 +1,139 @@
+From 862e2b6af9413b43ef044979b934cab07bfd33e5 Mon Sep 17 00:00:00 2001
+From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+Date: Fri, 1 Aug 2014 01:23:32 +0400
+Subject: [PATCH] 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: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
+---
+ drivers/net/can/rcar_can.c | 42 ++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 36 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c
+index 5268d21..c02fcf3 100644
+--- a/drivers/net/can/rcar_can.c
++++ b/drivers/net/can/rcar_can.c
+@@ -87,6 +87,7 @@ struct rcar_can_priv {
+ struct napi_struct napi;
+ struct rcar_can_regs __iomem *regs;
+ struct clk *clk;
++ struct clk *can_clk;
+ u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
+ u32 tx_head;
+ u32 tx_tail;
+@@ -505,14 +506,20 @@ static int rcar_can_open(struct net_device *ndev)
+
+ err = clk_prepare_enable(priv->clk);
+ if (err) {
+- netdev_err(ndev, "clk_prepare_enable() failed, error %d\n",
++ netdev_err(ndev, "failed to enable periperal clock, error %d\n",
+ err);
+ 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);
+ if (err) {
+ netdev_err(ndev, "open_candev() failed, error %d\n", err);
+- goto out_clock;
++ goto out_can_clock;
+ }
+ napi_enable(&priv->napi);
+ 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)
+ out_close:
+ napi_disable(&priv->napi);
+ close_candev(ndev);
++out_can_clock:
++ clk_disable_unprepare(priv->can_clk);
+ out_clock:
+ clk_disable_unprepare(priv->clk);
+ out:
+@@ -565,6 +574,7 @@ static int rcar_can_close(struct net_device *ndev)
+ rcar_can_stop(ndev);
+ free_irq(ndev->irq, ndev);
+ napi_disable(&priv->napi);
++ clk_disable_unprepare(priv->can_clk);
+ clk_disable_unprepare(priv->clk);
+ close_candev(ndev);
+ can_led_event(ndev, CAN_LED_EVENT_STOP);
+@@ -715,6 +725,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev,
+ 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)
+ {
+ struct rcar_can_platform_data *pdata;
+@@ -722,6 +738,7 @@ static int rcar_can_probe(struct platform_device *pdev)
+ struct net_device *ndev;
+ struct resource *mem;
+ void __iomem *addr;
++ u32 clock_select;
+ int err = -ENODEV;
+ int irq;
+
+@@ -730,6 +747,7 @@ static int rcar_can_probe(struct platform_device *pdev)
+ dev_err(&pdev->dev, "No platform data provided!\n");
+ goto fail;
+ }
++ clock_select = pdata->clock_select;
+
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+@@ -753,10 +771,22 @@ static int rcar_can_probe(struct platform_device *pdev)
+
+ 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)) {
+ 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;
+ }
+
+@@ -765,8 +795,8 @@ static int rcar_can_probe(struct platform_device *pdev)
+ ndev->flags |= IFF_ECHO;
+ priv->ndev = ndev;
+ priv->regs = addr;
+- priv->clock_select = pdata->clock_select;
+- priv->can.clock.freq = clk_get_rate(priv->clk);
++ priv->clock_select = clock_select;
++ priv->can.clock.freq = clk_get_rate(priv->can_clk);
+ priv->can.bittiming_const = &rcar_can_bittiming_const;
+ priv->can.do_set_mode = rcar_can_do_set_mode;
+ priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
+--
+1.9.1
+