From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753020AbbJZGMQ (ORCPT ); Mon, 26 Oct 2015 02:12:16 -0400 Received: from mail-bn1bon0077.outbound.protection.outlook.com ([157.56.111.77]:8992 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750883AbbJZGMN (ORCPT ); Mon, 26 Oct 2015 02:12:13 -0400 Authentication-Results: spf=pass (sender IP is 149.199.60.100) smtp.mailfrom=xilinx.com; vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=bestguesspass action=none header.from=xilinx.com; From: Kedareswara rao Appana To: , , , , CC: , , , , Kedareswara rao Appana Subject: [PATCH v8] can: xilinx: Convert to runtime_pm Date: Mon, 26 Oct 2015 11:41:54 +0530 Message-ID: <1445839914-26249-1-git-send-email-appanad@xilinx.com> X-Mailer: git-send-email 2.1.2 X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.0.0.1202-21900.005 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11FD005;1:cFfgMZeo/MHu2Jhed+jQK4ZMBMXAhV/WM2ywv77Uwjgs3hEh8mY24+Yl8P1GdNs8twe73rKsD0VKdp82X+llPfNLxScQacOIn1V5KzgxCyhIsmvuUssg0WvJBxJieSwQwlgT1xc5CHkvt3vHIldnt0Pfc1uoIytqBFx6GbDx8aihkOdV0Bkzg8SGj7/XyxFRosUM2tZ9pS1av9ueSBOdCDRClgByAFs4nBD3zbv0f9B1p9fWcd2q03hlhaSRYO49mv5mD5B4iT0JB53MSUazj7HcmMBmHdWNv3D15tztGUwLPbkzpDZQcPUH0skeVT6i2dxJicEWnQn09IvIIWAAqRXNA6km1vKj5/PCZjt0hxgbhlSETlqyi+p6K5M11u3ML7sOYi1ApmGAcA/BcKZZQQ== X-Forefront-Antispam-Report: CIP:149.199.60.100;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(438002)(199003)(189002)(103686003)(5008740100001)(106466001)(5001770100001)(229853001)(33646002)(86362001)(2201001)(92566002)(5001920100001)(42186005)(36386004)(81156007)(36756003)(45336002)(46386002)(48376002)(189998001)(5890100001)(50466002)(5001960100002)(52956003)(107886002)(4001430100002)(87936001)(11100500001)(5007970100001)(50226001)(90966002)(50986999)(4001450100002)(63266004)(6806005)(19580405001)(19580395003)(47776003)(5003940100001)(107986001)(5001870100001)(2101003);DIR:OUT;SFP:1101;SCL:1;SRVR:BN1BFFO11HUB056;H:xsj-pvapsmtpgw02;FPR:;SPF:Pass;PTR:unknown-60-100.xilinx.com,xapps1.xilinx.com;A:1;MX:1;LANG:en; MIME-Version: 1.0 Content-Type: text/plain X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;2:Dx7Mo+IOnGmBRW43sDs+YG+Tt7Il3s+AsTlgptzEzgtNRJ/n26205otEgiUplTt75MHUTAYJ1JjKfphyjMtHwM57+kVmCHPoyyDH1DCHu6u7ZdkYj5DzZtu5SAWSaH+ymsSitFEYr0PmCR2V/1DUb35fl1v/ntmA7SIZf7NU/a8=;3:h6N+4/9zYWVwN8Kn6QBEzTSBKhX/1UfkTwk2zN0vEdhSney2s+6r1HTDFEZkGO+u/Jj1Jv7QF45yTSZfdUXCRPrjD7PcSlWIwPMWaGxUNCKL3yob55zjgX5viG8/fE0OO66uQefZAuvhQdK6sXHMNbtVh4r+kv6qYw3dxTBupbRry1XjgQAqJAe69cauMwhpJfupWSXu/MOohL3QKEObqczxLu6dl8/d2NJy01UAh8m5/n7h5SqLkPn3iyGB/j8HvvN2ZTnzSXNEDs/B1RfeYA==;25:UKT3Bz2MnH/skyCykuO+jNSEkPybje9DP9Ys32jL5N2NU38BzNMsnDvEbO6okEn/wHt4FvNhb6V91TxwgWwyAw9n9qWDjyokGCEn35pkqUNc6HgHzMN/z+i5JcdyUz2hDdM/60Rcm1y/4HcLP5pKGxnoS9mAflZuOiPCXVQft3UbTXngILITcc3xDGAVGQlMaA37LSLF76ttCs31bcQiXg2r+Tzyxycf70xPVzxsgAQ8C5T4SpAYkuTEgACIfQLA+FGOfPXS8lJZZ8eADKFuBg== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(8251501001);SRVR:BN1BFFO11HUB056; X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;20:SMiU+KcRdmAaudZrj+sKwG5U8YHoLa2193CekZBVteW3998YWwePyBaT/ch5Zh0Su4Nc3PnaT7XsfZGBXFM42DN7oLbqD+xUaXI1EI+SYu2eNQ8VNB4Kq/87hNWleTYdWOO7ERW/ow3C5Bsi2nc9qqKkFYgdHbsh6fpSIyDRWbwLgxJlc5L8x1PvvDFY/rwHKa6yAFkPnnf8L8vDfQCQbbwvXwYXg6WoUeNh37VtI2yB0ttMujHsUFCJaUIUMUYaKe9J6B7hcRZIgHNFl63yABh1nCRUm4swtPEE+vBt6knRroaF7gd5WvTcJTbqb31fJDewRlj+wHRLHI/Nz/zzDybFzNKJo9IIuEFQhP76uJqVuvGZfl+6ofK2zIh7Wk0lQ7iEGXx4e4X1hlM6dYXhHg+yXR28inLvn/cQLDMeNH4tj+XTbV994b0DBdU0aD3OKiLjifIwMtVVCFrR9fgGGt1mWRXSRKbgpwJ9S2XDmecvFravfBteyoK2+mbaxucK;4:43dp4fVEd75zS2Azyg9RV2VkF7A7CzxAcv+AY5uyu9/ZAscaJMXlCd9pklMd/7PVfRzNsUJTPfWs0BmMsw0YjvPf2WRbIGXy/lc4dM41Sq74kxtE3L2i3uwLSWV4mgf/ZobQsZ651/3GzWt2Y9JYkREM1hII2NZMcQR3ZkSS34dGIqiyR9o0mOUAutxqvDcup1KumJzC+B9xdvHK86IOrQ+GasZT+Zu5nR0/OQ0TRHO1cSyYmrRHyK3pSm8rsBztC4Np/mZvh49IUbI6bJ+ihsTtpUE/0eINCQnw8/nALhMf0gVFaj+5Z9jBqwx3GoFat707pky4zHmGVU+OY/MZRyoRJH5oDiaien+JorRGfil4/fc6i6jQkj/FB1BoUB5lHYW7r6r79y0PK+zk6+7oZg== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(192813158149592); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(5005006)(8121501046)(520078)(10201501027)(3002001)(102215026);SRVR:BN1BFFO11HUB056;BCL:0;PCL:0;RULEID:;SRVR:BN1BFFO11HUB056; X-Forefront-PRVS: 0741C77572 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BN1BFFO11HUB056;23:/aqXrA7K/M1VW27jxSByVUYwTehh71whnlxsdo7?= =?us-ascii?Q?FYqFk2W54i1B/Zmcfz4qgfMWacNkocgmgCyJrWIPULeWifkVKphtaiL3anVH?= =?us-ascii?Q?xjd6f+pCRTQDgTUhPR5fFZo1f640RVoC149O7jvpo0gZJ6aklO/KfPd9o6zI?= =?us-ascii?Q?xfKkP9OtNeElu2fiim5C7j2rQ/mT0iJD+IdWYP3aSSRymfkuH0Zo82x8MmF+?= =?us-ascii?Q?V4D9MmwFwFVu3Z1BD2aot45RIctHn3v5e7MqGvwddlD+0ZPQdN66fm4oQZN0?= =?us-ascii?Q?VW3Gt4MWdvlZTA7ehdJ5Se6ZSG+Zp2kRxhmPQcmlxbpht/kg5oufOhUNm9Bb?= =?us-ascii?Q?RNQQwl6UW03JsOqIl31C6dFXQKsxDstmm/8GGMVkJXvdNYzc+5V3b618P6rN?= =?us-ascii?Q?ITmthFmepleLAdK26D8VB/Gu+45iuPJrPqERA2OJKb5IzhfV4jJ1Dyr3v+af?= =?us-ascii?Q?ZGuMcEzgLABlVdYpJ8iANLwVO+OqSAlrzsOBx0ot4+caljuHnM6ItSlo5dUV?= =?us-ascii?Q?EZJyDzTSwMz1YNeOIu+utVwL0eZdZ3YZ17mzsiXmBD/8sszVRv3NZsFSdVoD?= =?us-ascii?Q?Ndtq2q84K7y2szu5baDozgOX/Vn/egWpKf8++UWp5edgkUA9AMhCaS7PoyH7?= =?us-ascii?Q?nP+vGa07K4AfB4NhRBYwEMYBNc2JtvnheiX/sGThhKMKGTBIq09kfs6C5eta?= =?us-ascii?Q?QTKvNM3xe/2gOLQTZ/Z3xV0ySwQ9xPZa/CMPPGr/SbU+Eg/leiuqOKsmWMnm?= =?us-ascii?Q?EEM54MYSTGQnqI9a79uY9HBEPeTuGgwRemoXwdvt8USqLKgOQPEtcuh6DYqP?= =?us-ascii?Q?B9ArgN/jYbfP+yOBoxjDdSHXvOAUKhy3nNK7pYNTHjWrN0dVP5yMrUE5RjNG?= =?us-ascii?Q?l+2RmCeu5DJEYMvX5axPT4M7B+fNH/8Kv4Nsah/koxyTxBTtdm8lJh0knpMV?= =?us-ascii?Q?4WMDyXPkaY80KbrgC/3QM9rVF28JbbvVOGpe7LNeZGPQ5K9BwGDu2ALyAPEu?= =?us-ascii?Q?660gccCVrYRBvjN5yuNY1KqpB/cNUW2zIlka6CazXr2HCNdOOgIo+MA8amnE?= =?us-ascii?Q?NN6Z10eY4wF9rszkbb1mulAfvnkHGmew9dlxes8AmxQ9wcJVr8Np8S/KJPJa?= =?us-ascii?Q?PtwiBP/drR7/y4nb8IBcpxhxkH+rO4NvArgNUDSHNhYswX677zT6bypN2xNg?= =?us-ascii?Q?NraoYouy5Zva4ZK38BeHvjPsSrMFyTJlg7+zph6X3eKAwV9QZY1+WJRHF5g?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1;BN1BFFO11HUB056;5:QdlkUt6oZcGZ3JDVD5yWTj2a0vk+0dlBrrScTighk4ZNM2LXkZ97+J8KTiJyI4I24kZcdUhcV5ZAJXxFtLB0BISBu6Y9LaCXdOB/6br+DUUPKLxKSCDJL0hThIuWK9RTSoz+cbBKP7CjbKPFeJpBfw==;24:qRejjqQkBGrMt6QI5iRAwyuPf4wQdri443vq5cj7eXSeHCs130yW/xoccKIPvIG7frRoVQ8R5aMgjpnGOMXTuS1thg2QtaeFzx64Qe3HXRQ= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Oct 2015 06:12:10.2662 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c;Ip=[149.199.60.100];Helo=[xsj-pvapsmtpgw02] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN1BFFO11HUB056 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Instead of enabling/disabling clocks at several locations in the driver, Use the runtime_pm framework. This consolidates the actions for runtime PM In the appropriate callbacks and makes the driver more readable and mantainable. Signed-off-by: Kedareswara rao Appana --- Changes for v8: - Remove pm_runtime_irq_safe() API call from the probe as clk_prepare_enable Call canbe called from the atomic context as suggested by Marc. Changes for v7: - Removed the unnecessary clk_prepare/clk_unprepare calls From the probe and remove as suggested by Soren. Changes for v6: - Updated the driver with review comments as suggested by Marc. Changes for v5: - Updated with the review comments. Updated the remove fuction to use runtime_pm. Chnages for v4: - Updated with the review comments. Changes for v3: - Converted the driver to use runtime_pm. Changes for v2: - Removed the struct platform_device* from suspend/resume as suggest by Lothar drivers/net/can/xilinx_can.c | 176 +++++++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 75 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index fc55e8e..ad38065 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -32,6 +32,7 @@ #include #include #include +#include #define DRIVER_NAME "xilinx_can" @@ -138,7 +139,7 @@ struct xcan_priv { u32 (*read_reg)(const struct xcan_priv *priv, enum xcan_reg reg); void (*write_reg)(const struct xcan_priv *priv, enum xcan_reg reg, u32 val); - struct net_device *dev; + struct device *dev; void __iomem *reg_base; unsigned long irq_flags; struct clk *bus_clk; @@ -843,6 +844,13 @@ static int xcan_open(struct net_device *ndev) struct xcan_priv *priv = netdev_priv(ndev); int ret; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, ret); + return ret; + } + ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags, ndev->name, ndev); if (ret < 0) { @@ -850,29 +858,17 @@ static int xcan_open(struct net_device *ndev) goto err; } - ret = clk_prepare_enable(priv->can_clk); - if (ret) { - netdev_err(ndev, "unable to enable device clock\n"); - goto err_irq; - } - - ret = clk_prepare_enable(priv->bus_clk); - if (ret) { - netdev_err(ndev, "unable to enable bus clock\n"); - goto err_can_clk; - } - /* Set chip into reset mode */ ret = set_reset_mode(ndev); if (ret < 0) { netdev_err(ndev, "mode resetting failed!\n"); - goto err_bus_clk; + goto err_irq; } /* Common open */ ret = open_candev(ndev); if (ret) - goto err_bus_clk; + goto err_irq; ret = xcan_chip_start(ndev); if (ret < 0) { @@ -888,13 +884,11 @@ static int xcan_open(struct net_device *ndev) err_candev: close_candev(ndev); -err_bus_clk: - clk_disable_unprepare(priv->bus_clk); -err_can_clk: - clk_disable_unprepare(priv->can_clk); err_irq: free_irq(ndev->irq, ndev); err: + pm_runtime_put(priv->dev); + return ret; } @@ -911,12 +905,11 @@ static int xcan_close(struct net_device *ndev) netif_stop_queue(ndev); napi_disable(&priv->napi); xcan_chip_stop(ndev); - clk_disable_unprepare(priv->bus_clk); - clk_disable_unprepare(priv->can_clk); free_irq(ndev->irq, ndev); close_candev(ndev); can_led_event(ndev, CAN_LED_EVENT_STOP); + pm_runtime_put(priv->dev); return 0; } @@ -935,27 +928,20 @@ static int xcan_get_berr_counter(const struct net_device *ndev, struct xcan_priv *priv = netdev_priv(ndev); int ret; - ret = clk_prepare_enable(priv->can_clk); - if (ret) - goto err; - - ret = clk_prepare_enable(priv->bus_clk); - if (ret) - goto err_clk; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, ret); + return ret; + } bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); - clk_disable_unprepare(priv->bus_clk); - clk_disable_unprepare(priv->can_clk); + pm_runtime_put(priv->dev); return 0; - -err_clk: - clk_disable_unprepare(priv->can_clk); -err: - return ret; } @@ -968,15 +954,45 @@ static const struct net_device_ops xcan_netdev_ops = { /** * xcan_suspend - Suspend method for the driver - * @dev: Address of the platform_device structure + * @dev: Address of the device structure * * Put the driver into low power mode. - * Return: 0 always + * Return: 0 on success and failure value on error */ static int __maybe_unused xcan_suspend(struct device *dev) { - struct platform_device *pdev = dev_get_drvdata(dev); - struct net_device *ndev = platform_get_drvdata(pdev); + if (!device_may_wakeup(dev)) + return pm_runtime_force_suspend(dev); + + return 0; +} + +/** + * xcan_resume - Resume from suspend + * @dev: Address of the device structure + * + * Resume operation after suspend. + * Return: 0 on success and failure value on error + */ +static int __maybe_unused xcan_resume(struct device *dev) +{ + if (!device_may_wakeup(dev)) + return pm_runtime_force_resume(dev); + + return 0; + +} + +/** + * xcan_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the device structure + * + * Put the driver into low power mode. + * Return: 0 always + */ +static int __maybe_unused xcan_runtime_suspend(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); if (netif_running(ndev)) { @@ -987,43 +1003,55 @@ static int __maybe_unused xcan_suspend(struct device *dev) priv->write_reg(priv, XCAN_MSR_OFFSET, XCAN_MSR_SLEEP_MASK); priv->can.state = CAN_STATE_SLEEPING; - clk_disable(priv->bus_clk); - clk_disable(priv->can_clk); + clk_disable_unprepare(priv->bus_clk); + clk_disable_unprepare(priv->can_clk); return 0; } /** - * xcan_resume - Resume from suspend - * @dev: Address of the platformdevice structure + * xcan_runtime_resume - Runtime resume from suspend + * @dev: Address of the device structure * * Resume operation after suspend. * Return: 0 on success and failure value on error */ -static int __maybe_unused xcan_resume(struct device *dev) +static int __maybe_unused xcan_runtime_resume(struct device *dev) { - struct platform_device *pdev = dev_get_drvdata(dev); - struct net_device *ndev = platform_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); struct xcan_priv *priv = netdev_priv(ndev); int ret; + u32 isr, status; - ret = clk_enable(priv->bus_clk); + ret = clk_prepare_enable(priv->bus_clk); if (ret) { dev_err(dev, "Cannot enable clock.\n"); return ret; } - ret = clk_enable(priv->can_clk); + ret = clk_prepare_enable(priv->can_clk); if (ret) { dev_err(dev, "Cannot enable clock.\n"); clk_disable_unprepare(priv->bus_clk); return ret; } - priv->write_reg(priv, XCAN_MSR_OFFSET, 0); - priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); - priv->can.state = CAN_STATE_ERROR_ACTIVE; + priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); + isr = priv->read_reg(priv, XCAN_ISR_OFFSET); + status = priv->read_reg(priv, XCAN_SR_OFFSET); if (netif_running(ndev)) { + if (isr & XCAN_IXR_BSOFF_MASK) { + priv->can.state = CAN_STATE_BUS_OFF; + priv->write_reg(priv, XCAN_SRR_OFFSET, + XCAN_SRR_RESET_MASK); + } else if ((status & XCAN_SR_ESTAT_MASK) == + XCAN_SR_ESTAT_MASK) { + priv->can.state = CAN_STATE_ERROR_PASSIVE; + } else if (status & XCAN_SR_ERRWRN_MASK) { + priv->can.state = CAN_STATE_ERROR_WARNING; + } else { + priv->can.state = CAN_STATE_ERROR_ACTIVE; + } netif_device_attach(ndev); netif_start_queue(ndev); } @@ -1031,7 +1059,10 @@ static int __maybe_unused xcan_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(xcan_dev_pm_ops, xcan_suspend, xcan_resume); +static const struct dev_pm_ops xcan_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xcan_suspend, xcan_resume) + SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL) +}; /** * xcan_probe - Platform registration call @@ -1072,7 +1103,7 @@ static int xcan_probe(struct platform_device *pdev) return -ENOMEM; priv = netdev_priv(ndev); - priv->dev = ndev; + priv->dev = &pdev->dev; priv->can.bittiming_const = &xcan_bittiming_const; priv->can.do_set_mode = xcan_do_set_mode; priv->can.do_get_berr_counter = xcan_get_berr_counter; @@ -1114,21 +1145,17 @@ static int xcan_probe(struct platform_device *pdev) } } - ret = clk_prepare_enable(priv->can_clk); - if (ret) { - dev_err(&pdev->dev, "unable to enable device clock\n"); - goto err_free; - } - - ret = clk_prepare_enable(priv->bus_clk); - if (ret) { - dev_err(&pdev->dev, "unable to enable bus clock\n"); - goto err_unprepare_disable_dev; - } - priv->write_reg = xcan_write_reg_le; priv->read_reg = xcan_read_reg_le; + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", + __func__, ret); + goto err_pmdisable; + } + if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) { priv->write_reg = xcan_write_reg_be; priv->read_reg = xcan_read_reg_be; @@ -1141,22 +1168,23 @@ static int xcan_probe(struct platform_device *pdev) ret = register_candev(ndev); if (ret) { dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); - goto err_unprepare_disable_busclk; + goto err_disableclks; } devm_can_led_init(ndev); - clk_disable_unprepare(priv->bus_clk); - clk_disable_unprepare(priv->can_clk); + + pm_runtime_put(&pdev->dev); + netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth:%d\n", priv->reg_base, ndev->irq, priv->can.clock.freq, priv->tx_max); return 0; -err_unprepare_disable_busclk: - clk_disable_unprepare(priv->bus_clk); -err_unprepare_disable_dev: - clk_disable_unprepare(priv->can_clk); +err_disableclks: + pm_runtime_put(priv->dev); +err_pmdisable: + pm_runtime_disable(&pdev->dev); err_free: free_candev(ndev); err: @@ -1175,10 +1203,8 @@ static int xcan_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct xcan_priv *priv = netdev_priv(ndev); - if (set_reset_mode(ndev) < 0) - netdev_err(ndev, "mode resetting failed!\n"); - unregister_candev(ndev); + pm_runtime_disable(&pdev->dev); netif_napi_del(&priv->napi); free_candev(ndev); -- 2.1.2