qcom-ctrl.c (ad7fcbc308b050e3c27c545021663d2cd73f8b23) qcom-ctrl.c (c088c335b49228ca1759dca5676f1534b0ac13a5)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2011-2017, The Linux Foundation
4 */
5
6#include <linux/irq.h>
7#include <linux/kernel.h>
8#include <linux/init.h>
9#include <linux/slab.h>
10#include <linux/io.h>
11#include <linux/interrupt.h>
12#include <linux/platform_device.h>
13#include <linux/delay.h>
14#include <linux/clk.h>
15#include <linux/of.h>
16#include <linux/dma-mapping.h>
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2011-2017, The Linux Foundation
4 */
5
6#include <linux/irq.h>
7#include <linux/kernel.h>
8#include <linux/init.h>
9#include <linux/slab.h>
10#include <linux/io.h>
11#include <linux/interrupt.h>
12#include <linux/platform_device.h>
13#include <linux/delay.h>
14#include <linux/clk.h>
15#include <linux/of.h>
16#include <linux/dma-mapping.h>
17#include <linux/pm_runtime.h>
17#include "slimbus.h"
18
19/* Manager registers */
20#define MGR_CFG 0x200
21#define MGR_STATUS 0x204
22#define MGR_INT_EN 0x210
23#define MGR_INT_STAT 0x214
24#define MGR_INT_CLR 0x218

--- 35 unchanged lines hidden (view full) ---

60#define ROOT_FREQ 11
61#define REF_CLK_GEAR 15
62#define INTR_WAKE 19
63
64#define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
65 ((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16))
66
67#define SLIM_ROOT_FREQ 24576000
18#include "slimbus.h"
19
20/* Manager registers */
21#define MGR_CFG 0x200
22#define MGR_STATUS 0x204
23#define MGR_INT_EN 0x210
24#define MGR_INT_STAT 0x214
25#define MGR_INT_CLR 0x218

--- 35 unchanged lines hidden (view full) ---

61#define ROOT_FREQ 11
62#define REF_CLK_GEAR 15
63#define INTR_WAKE 19
64
65#define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
66 ((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16))
67
68#define SLIM_ROOT_FREQ 24576000
69#define QCOM_SLIM_AUTOSUSPEND 1000
68
69/* MAX message size over control channel */
70#define SLIM_MSGQ_BUF_LEN 40
71#define QCOM_TX_MSGS 2
72#define QCOM_RX_MSGS 8
73#define QCOM_BUF_ALLOC_RETRIES 10
74
75#define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))

--- 194 unchanged lines hidden (view full) ---

270 ret = qcom_slim_handle_tx_irq(ctrl, stat);
271
272 if (stat & MGR_INT_RX_MSG_RCVD)
273 ret = qcom_slim_handle_rx_irq(ctrl, stat);
274
275 return ret;
276}
277
70
71/* MAX message size over control channel */
72#define SLIM_MSGQ_BUF_LEN 40
73#define QCOM_TX_MSGS 2
74#define QCOM_RX_MSGS 8
75#define QCOM_BUF_ALLOC_RETRIES 10
76
77#define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))

--- 194 unchanged lines hidden (view full) ---

272 ret = qcom_slim_handle_tx_irq(ctrl, stat);
273
274 if (stat & MGR_INT_RX_MSG_RCVD)
275 ret = qcom_slim_handle_rx_irq(ctrl, stat);
276
277 return ret;
278}
279
280static int qcom_clk_pause_wakeup(struct slim_controller *sctrl)
281{
282 struct qcom_slim_ctrl *ctrl = dev_get_drvdata(sctrl->dev);
283
284 clk_prepare_enable(ctrl->hclk);
285 clk_prepare_enable(ctrl->rclk);
286 enable_irq(ctrl->irq);
287
288 writel_relaxed(1, ctrl->base + FRM_WAKEUP);
289 /* Make sure framer wakeup write goes through before ISR fires */
290 mb();
291 /*
292 * HW Workaround: Currently, slave is reporting lost-sync messages
293 * after SLIMbus comes out of clock pause.
294 * Transaction with slave fail before slave reports that message
295 * Give some time for that report to come
296 * SLIMbus wakes up in clock gear 10 at 24.576MHz. With each superframe
297 * being 250 usecs, we wait for 5-10 superframes here to ensure
298 * we get the message
299 */
300 usleep_range(1250, 2500);
301 return 0;
302}
303
278void *slim_alloc_txbuf(struct qcom_slim_ctrl *ctrl, struct slim_msg_txn *txn,
279 struct completion *done)
280{
281 unsigned long flags;
282 int idx;
283
284 spin_lock_irqsave(&ctrl->tx.lock, flags);
285 if (((ctrl->tx.head + 1) % ctrl->tx.n) == ctrl->tx.tail) {

--- 220 unchanged lines hidden (view full) ---

506 ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
507 if (!ctrl->base) {
508 dev_err(&pdev->dev, "IOremap failed\n");
509 return -ENOMEM;
510 }
511
512 sctrl->set_laddr = qcom_set_laddr;
513 sctrl->xfer_msg = qcom_xfer_msg;
304void *slim_alloc_txbuf(struct qcom_slim_ctrl *ctrl, struct slim_msg_txn *txn,
305 struct completion *done)
306{
307 unsigned long flags;
308 int idx;
309
310 spin_lock_irqsave(&ctrl->tx.lock, flags);
311 if (((ctrl->tx.head + 1) % ctrl->tx.n) == ctrl->tx.tail) {

--- 220 unchanged lines hidden (view full) ---

532 ctrl->base = devm_ioremap_resource(ctrl->dev, slim_mem);
533 if (!ctrl->base) {
534 dev_err(&pdev->dev, "IOremap failed\n");
535 return -ENOMEM;
536 }
537
538 sctrl->set_laddr = qcom_set_laddr;
539 sctrl->xfer_msg = qcom_xfer_msg;
540 sctrl->wakeup = qcom_clk_pause_wakeup;
514 ctrl->tx.n = QCOM_TX_MSGS;
515 ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN;
516 ctrl->rx.n = QCOM_RX_MSGS;
517 ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN;
518 ctrl->wr_comp = kzalloc(sizeof(struct completion *) * QCOM_TX_MSGS,
519 GFP_KERNEL);
520 if (!ctrl->wr_comp)
521 return -ENOMEM;

--- 91 unchanged lines hidden (view full) ---

613 destroy_workqueue(ctrl->rxwq);
614 return ret;
615}
616
617static int qcom_slim_remove(struct platform_device *pdev)
618{
619 struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev);
620
541 ctrl->tx.n = QCOM_TX_MSGS;
542 ctrl->tx.sl_sz = SLIM_MSGQ_BUF_LEN;
543 ctrl->rx.n = QCOM_RX_MSGS;
544 ctrl->rx.sl_sz = SLIM_MSGQ_BUF_LEN;
545 ctrl->wr_comp = kzalloc(sizeof(struct completion *) * QCOM_TX_MSGS,
546 GFP_KERNEL);
547 if (!ctrl->wr_comp)
548 return -ENOMEM;

--- 91 unchanged lines hidden (view full) ---

640 destroy_workqueue(ctrl->rxwq);
641 return ret;
642}
643
644static int qcom_slim_remove(struct platform_device *pdev)
645{
646 struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev);
647
621 disable_irq(ctrl->irq);
622 clk_disable_unprepare(ctrl->hclk);
623 clk_disable_unprepare(ctrl->rclk);
648 pm_runtime_disable(&pdev->dev);
624 slim_unregister_controller(&ctrl->ctrl);
625 destroy_workqueue(ctrl->rxwq);
626 return 0;
627}
628
649 slim_unregister_controller(&ctrl->ctrl);
650 destroy_workqueue(ctrl->rxwq);
651 return 0;
652}
653
654/*
655 * If PM_RUNTIME is not defined, these 2 functions become helper
656 * functions to be called from system suspend/resume.
657 */
658#ifdef CONFIG_PM
659static int qcom_slim_runtime_suspend(struct device *device)
660{
661 struct platform_device *pdev = to_platform_device(device);
662 struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev);
663 int ret;
664
665 dev_dbg(device, "pm_runtime: suspending...\n");
666 ret = slim_ctrl_clk_pause(&ctrl->ctrl, false, SLIM_CLK_UNSPECIFIED);
667 if (ret) {
668 dev_err(device, "clk pause not entered:%d", ret);
669 } else {
670 disable_irq(ctrl->irq);
671 clk_disable_unprepare(ctrl->hclk);
672 clk_disable_unprepare(ctrl->rclk);
673 }
674 return ret;
675}
676
677static int qcom_slim_runtime_resume(struct device *device)
678{
679 struct platform_device *pdev = to_platform_device(device);
680 struct qcom_slim_ctrl *ctrl = platform_get_drvdata(pdev);
681 int ret = 0;
682
683 dev_dbg(device, "pm_runtime: resuming...\n");
684 ret = slim_ctrl_clk_pause(&ctrl->ctrl, true, 0);
685 if (ret)
686 dev_err(device, "clk pause not exited:%d", ret);
687 return ret;
688}
689#endif
690
691#ifdef CONFIG_PM_SLEEP
692static int qcom_slim_suspend(struct device *dev)
693{
694 int ret = 0;
695
696 if (!pm_runtime_enabled(dev) ||
697 (!pm_runtime_suspended(dev))) {
698 dev_dbg(dev, "system suspend");
699 ret = qcom_slim_runtime_suspend(dev);
700 }
701
702 return ret;
703}
704
705static int qcom_slim_resume(struct device *dev)
706{
707 if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
708 int ret;
709
710 dev_dbg(dev, "system resume");
711 ret = qcom_slim_runtime_resume(dev);
712 if (!ret) {
713 pm_runtime_mark_last_busy(dev);
714 pm_request_autosuspend(dev);
715 }
716 return ret;
717
718 }
719 return 0;
720}
721#endif /* CONFIG_PM_SLEEP */
722
629static const struct dev_pm_ops qcom_slim_dev_pm_ops = {
630 SET_SYSTEM_SLEEP_PM_OPS(qcom_slim_suspend, qcom_slim_resume)
631 SET_RUNTIME_PM_OPS(
632 qcom_slim_runtime_suspend,
633 qcom_slim_runtime_resume,
634 NULL
635 )
636};

--- 5 unchanged lines hidden (view full) ---

642};
643
644static struct platform_driver qcom_slim_driver = {
645 .probe = qcom_slim_probe,
646 .remove = qcom_slim_remove,
647 .driver = {
648 .name = "qcom_slim_ctrl",
649 .of_match_table = qcom_slim_dt_match,
723static const struct dev_pm_ops qcom_slim_dev_pm_ops = {
724 SET_SYSTEM_SLEEP_PM_OPS(qcom_slim_suspend, qcom_slim_resume)
725 SET_RUNTIME_PM_OPS(
726 qcom_slim_runtime_suspend,
727 qcom_slim_runtime_resume,
728 NULL
729 )
730};

--- 5 unchanged lines hidden (view full) ---

736};
737
738static struct platform_driver qcom_slim_driver = {
739 .probe = qcom_slim_probe,
740 .remove = qcom_slim_remove,
741 .driver = {
742 .name = "qcom_slim_ctrl",
743 .of_match_table = qcom_slim_dt_match,
744 .pm = &qcom_slim_dev_pm_ops,
650 },
651};
652module_platform_driver(qcom_slim_driver);
653
654MODULE_LICENSE("GPL v2");
655MODULE_DESCRIPTION("Qualcomm SLIMbus Controller");
745 },
746};
747module_platform_driver(qcom_slim_driver);
748
749MODULE_LICENSE("GPL v2");
750MODULE_DESCRIPTION("Qualcomm SLIMbus Controller");