diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 01:10:09 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 01:10:09 +0300 |
commit | 2911ed9f47b47cb5ab87d03314b3b9fe008e607f (patch) | |
tree | 7357e609aac80001b12a3933122060a777e67578 /drivers/slimbus | |
parent | 7240153a9bdb77217b99b76fd73105bce12770be (diff) | |
parent | 93f998879cd95b3e4f2836e7b17d6d5ae035cf90 (diff) | |
download | linux-2911ed9f47b47cb5ab87d03314b3b9fe008e607f.tar.xz |
Merge tag 'char-misc-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char / misc driver updates from Greg KH:
"Here is the big char/misc driver update for 5.11-rc1.
Continuing the tradition of previous -rc1 pulls, there seems to be
more and more tiny driver subsystems flowing through this tree.
Lots of different things, all of which have been in linux-next for a
while with no reported issues:
- extcon driver updates
- habannalab driver updates
- mei driver updates
- uio driver updates
- binder fixes and features added
- soundwire driver updates
- mhi bus driver updates
- phy driver updates
- coresight driver updates
- fpga driver updates
- speakup driver updates
- slimbus driver updates
- various small char and misc driver updates"
* tag 'char-misc-5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (305 commits)
extcon: max77693: Fix modalias string
extcon: fsa9480: Support TI TSU6111 variant
extcon: fsa9480: Rewrite bindings in YAML and extend
dt-bindings: extcon: add binding for TUSB320
extcon: Add driver for TI TUSB320
slimbus: qcom: fix potential NULL dereference in qcom_slim_prg_slew()
siox: Make remove callback return void
siox: Use bus_type functions for probe, remove and shutdown
spmi: Add driver shutdown support
spmi: fix some coding style issues at the spmi core
spmi: get rid of a warning when built with W=1
uio: uio_hv_generic: use devm_kzalloc() for private data alloc
uio: uio_fsl_elbc_gpcm: use device-managed allocators
uio: uio_aec: use devm_kzalloc() for uio_info object
uio: uio_cif: use devm_kzalloc() for uio_info object
uio: uio_netx: use devm_kzalloc() for or uio_info object
uio: uio_mf624: use devm_kzalloc() for uio_info object
uio: uio_sercos3: use device-managed functions for simple allocs
uio: uio_dmem_genirq: finalize conversion of probe to devm_ handlers
uio: uio_dmem_genirq: convert simple allocations to device-managed
...
Diffstat (limited to 'drivers/slimbus')
-rw-r--r-- | drivers/slimbus/Kconfig | 3 | ||||
-rw-r--r-- | drivers/slimbus/messaging.c | 1 | ||||
-rw-r--r-- | drivers/slimbus/qcom-ctrl.c | 9 | ||||
-rw-r--r-- | drivers/slimbus/qcom-ngd-ctrl.c | 133 | ||||
-rw-r--r-- | drivers/slimbus/slimbus.h | 2 |
5 files changed, 131 insertions, 17 deletions
diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig index 8cd595148d17..1235b7dc8496 100644 --- a/drivers/slimbus/Kconfig +++ b/drivers/slimbus/Kconfig @@ -22,9 +22,10 @@ config SLIM_QCOM_CTRL config SLIM_QCOM_NGD_CTRL tristate "Qualcomm SLIMbus Satellite Non-Generic Device Component" - depends on HAS_IOMEM && DMA_ENGINE && NET + depends on HAS_IOMEM && DMA_ENGINE && NET && QCOM_RPROC_COMMON depends on ARCH_QCOM || COMPILE_TEST select QCOM_QMI_HELPERS + select QCOM_PDR_HELPERS help Select driver if Qualcomm's SLIMbus Satellite Non-Generic Device Component is programmed using Linux kernel. diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c index d5879142dbef..f2b5d347d227 100644 --- a/drivers/slimbus/messaging.c +++ b/drivers/slimbus/messaging.c @@ -258,6 +258,7 @@ int slim_xfer_msg(struct slim_device *sbdev, struct slim_val_inf *msg, case SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION: case SLIM_MSG_MC_CLEAR_INFORMATION: txn->rl += msg->num_bytes; + break; default: break; } diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index 4aad2566f52d..f04b961b96cd 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c @@ -472,15 +472,10 @@ static void qcom_slim_rxwq(struct work_struct *work) static void qcom_slim_prg_slew(struct platform_device *pdev, struct qcom_slim_ctrl *ctrl) { - struct resource *slew_mem; - if (!ctrl->slew_reg) { /* SLEW RATE register for this SLIMbus */ - slew_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "slew"); - ctrl->slew_reg = devm_ioremap(&pdev->dev, slew_mem->start, - resource_size(slew_mem)); - if (!ctrl->slew_reg) + ctrl->slew_reg = devm_platform_ioremap_resource_byname(pdev, "slew"); + if (IS_ERR(ctrl->slew_reg)) return; } diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 218aefc3531c..c054e83ab636 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -13,9 +13,13 @@ #include <linux/slimbus.h> #include <linux/delay.h> #include <linux/pm_runtime.h> +#include <linux/mutex.h> +#include <linux/notifier.h> +#include <linux/remoteproc/qcom_rproc.h> #include <linux/of.h> #include <linux/io.h> #include <linux/soc/qcom/qmi.h> +#include <linux/soc/qcom/pdr.h> #include <net/sock.h> #include "slimbus.h" @@ -155,8 +159,15 @@ struct qcom_slim_ngd_ctrl { struct qcom_slim_ngd_dma_desc txdesc[QCOM_SLIM_NGD_DESC_NUM]; struct completion reconf; struct work_struct m_work; + struct work_struct ngd_up_work; struct workqueue_struct *mwq; + struct completion qmi_up; spinlock_t tx_buf_lock; + struct mutex tx_lock; + struct mutex ssr_lock; + struct notifier_block nb; + void *notifier; + struct pdr_handle *pdr; enum qcom_slim_ngd_state state; dma_addr_t rx_phys_base; dma_addr_t tx_phys_base; @@ -423,7 +434,7 @@ static int qcom_slim_qmi_send_power_request(struct qcom_slim_ngd_ctrl *ctrl, return 0; } -static struct qmi_msg_handler qcom_slim_qmi_msg_handlers[] = { +static const struct qmi_msg_handler qcom_slim_qmi_msg_handlers[] = { { .type = QMI_RESPONSE, .msg_id = SLIMBUS_QMI_POWER_RESP_V01, @@ -678,7 +689,6 @@ static int qcom_slim_ngd_init_rx_msgq(struct qcom_slim_ngd_ctrl *ctrl) ctrl->rx_base = dma_alloc_coherent(dev, size, &ctrl->rx_phys_base, GFP_KERNEL); if (!ctrl->rx_base) { - dev_err(dev, "dma_alloc_coherent failed\n"); ret = -ENOMEM; goto rel_rx; } @@ -717,7 +727,6 @@ static int qcom_slim_ngd_init_tx_msgq(struct qcom_slim_ngd_ctrl *ctrl) ctrl->tx_base = dma_alloc_coherent(dev, size, &ctrl->tx_phys_base, GFP_KERNEL); if (!ctrl->tx_base) { - dev_err(dev, "dma_alloc_coherent failed\n"); ret = -EINVAL; goto rel_tx; } @@ -868,14 +877,18 @@ static int qcom_slim_ngd_xfer_msg(struct slim_controller *sctrl, if (txn->msg && txn->msg->wbuf) memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes); + mutex_lock(&ctrl->tx_lock); ret = qcom_slim_ngd_tx_msg_post(ctrl, pbuf, txn->rl); - if (ret) + if (ret) { + mutex_unlock(&ctrl->tx_lock); return ret; + } timeout = wait_for_completion_timeout(&tx_sent, HZ); if (!timeout) { dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc, txn->mt); + mutex_unlock(&ctrl->tx_lock); return -ETIMEDOUT; } @@ -884,10 +897,12 @@ static int qcom_slim_ngd_xfer_msg(struct slim_controller *sctrl, if (!timeout) { dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc, txn->mt); + mutex_unlock(&ctrl->tx_lock); return -ETIMEDOUT; } } + mutex_unlock(&ctrl->tx_lock); return 0; } @@ -1200,11 +1215,21 @@ capability_retry: } } +static int qcom_slim_ngd_update_device_status(struct device *dev, void *null) +{ + slim_report_absent(to_slim_device(dev)); + + return 0; +} + static int qcom_slim_ngd_runtime_resume(struct device *dev) { struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; + if (!ctrl->qmi.handle) + return 0; + if (ctrl->state >= QCOM_SLIM_NGD_CTRL_ASLEEP) ret = qcom_slim_ngd_power_up(ctrl); if (ret) { @@ -1267,7 +1292,7 @@ static int qcom_slim_ngd_qmi_new_server(struct qmi_handle *hdl, qmi->svc_info.sq_node = service->node; qmi->svc_info.sq_port = service->port; - qcom_slim_ngd_enable(ctrl, true); + complete(&ctrl->qmi_up); return 0; } @@ -1280,13 +1305,12 @@ static void qcom_slim_ngd_qmi_del_server(struct qmi_handle *hdl, struct qcom_slim_ngd_ctrl *ctrl = container_of(qmi, struct qcom_slim_ngd_ctrl, qmi); + reinit_completion(&ctrl->qmi_up); qmi->svc_info.sq_node = 0; qmi->svc_info.sq_port = 0; - - qcom_slim_ngd_enable(ctrl, false); } -static struct qmi_ops qcom_slim_ngd_qmi_svc_event_ops = { +static const struct qmi_ops qcom_slim_ngd_qmi_svc_event_ops = { .new_server = qcom_slim_ngd_qmi_new_server, .del_server = qcom_slim_ngd_qmi_del_server, }; @@ -1333,6 +1357,72 @@ static const struct of_device_id qcom_slim_ngd_dt_match[] = { MODULE_DEVICE_TABLE(of, qcom_slim_ngd_dt_match); +static void qcom_slim_ngd_down(struct qcom_slim_ngd_ctrl *ctrl) +{ + mutex_lock(&ctrl->ssr_lock); + device_for_each_child(ctrl->ctrl.dev, NULL, + qcom_slim_ngd_update_device_status); + qcom_slim_ngd_enable(ctrl, false); + mutex_unlock(&ctrl->ssr_lock); +} + +static void qcom_slim_ngd_up_worker(struct work_struct *work) +{ + struct qcom_slim_ngd_ctrl *ctrl; + + ctrl = container_of(work, struct qcom_slim_ngd_ctrl, ngd_up_work); + + /* Make sure qmi service is up before continuing */ + wait_for_completion_interruptible(&ctrl->qmi_up); + + mutex_lock(&ctrl->ssr_lock); + qcom_slim_ngd_enable(ctrl, true); + mutex_unlock(&ctrl->ssr_lock); +} + +static int qcom_slim_ngd_ssr_pdr_notify(struct qcom_slim_ngd_ctrl *ctrl, + unsigned long action) +{ + switch (action) { + case QCOM_SSR_BEFORE_SHUTDOWN: + case SERVREG_SERVICE_STATE_DOWN: + /* Make sure the last dma xfer is finished */ + mutex_lock(&ctrl->tx_lock); + if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) { + pm_runtime_get_noresume(ctrl->dev); + ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN; + qcom_slim_ngd_down(ctrl); + qcom_slim_ngd_exit_dma(ctrl); + } + mutex_unlock(&ctrl->tx_lock); + break; + case QCOM_SSR_AFTER_POWERUP: + case SERVREG_SERVICE_STATE_UP: + schedule_work(&ctrl->ngd_up_work); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static int qcom_slim_ngd_ssr_notify(struct notifier_block *nb, + unsigned long action, + void *data) +{ + struct qcom_slim_ngd_ctrl *ctrl = container_of(nb, + struct qcom_slim_ngd_ctrl, nb); + + return qcom_slim_ngd_ssr_pdr_notify(ctrl, action); +} + +static void slim_pd_status(int state, char *svc_path, void *priv) +{ + struct qcom_slim_ngd_ctrl *ctrl = (struct qcom_slim_ngd_ctrl *)priv; + + qcom_slim_ngd_ssr_pdr_notify(ctrl, state); +} static int of_qcom_slim_ngd_register(struct device *parent, struct qcom_slim_ngd_ctrl *ctrl) { @@ -1397,6 +1487,7 @@ static int qcom_slim_ngd_probe(struct platform_device *pdev) } INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker); + INIT_WORK(&ctrl->ngd_up_work, qcom_slim_ngd_up_worker); ctrl->mwq = create_singlethread_workqueue("ngd_master"); if (!ctrl->mwq) { dev_err(&pdev->dev, "Failed to start master worker\n"); @@ -1419,6 +1510,7 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) struct qcom_slim_ngd_ctrl *ctrl; struct resource *res; int ret; + struct pdr_service *pds; ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); if (!ctrl) @@ -1444,6 +1536,11 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) return ret; } + ctrl->nb.notifier_call = qcom_slim_ngd_ssr_notify; + ctrl->notifier = qcom_register_ssr_notifier("lpass", &ctrl->nb); + if (IS_ERR(ctrl->notifier)) + return PTR_ERR(ctrl->notifier); + ctrl->dev = dev; ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3; ctrl->framer.superfreq = @@ -1457,9 +1554,24 @@ static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev) ctrl->ctrl.wakeup = NULL; ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN; + mutex_init(&ctrl->tx_lock); + mutex_init(&ctrl->ssr_lock); spin_lock_init(&ctrl->tx_buf_lock); init_completion(&ctrl->reconf); init_completion(&ctrl->qmi.qmi_comp); + init_completion(&ctrl->qmi_up); + + ctrl->pdr = pdr_handle_alloc(slim_pd_status, ctrl); + if (IS_ERR(ctrl->pdr)) { + dev_err(dev, "Failed to init PDR handle\n"); + return PTR_ERR(ctrl->pdr); + } + + pds = pdr_add_lookup(ctrl->pdr, "avs/audio", "msm/adsp/audio_pd"); + if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { + dev_err(dev, "pdr add lookup failed: %d\n", ret); + return PTR_ERR(pds); + } platform_driver_register(&qcom_slim_ngd_driver); return of_qcom_slim_ngd_register(dev, ctrl); @@ -1477,6 +1589,8 @@ static int qcom_slim_ngd_remove(struct platform_device *pdev) struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); + pdr_handle_release(ctrl->pdr); + qcom_unregister_ssr_notifier(ctrl->notifier, &ctrl->nb); qcom_slim_ngd_enable(ctrl, false); qcom_slim_ngd_exit_dma(ctrl); qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi); @@ -1503,6 +1617,9 @@ static int __maybe_unused qcom_slim_ngd_runtime_suspend(struct device *dev) struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; + if (!ctrl->qmi.handle) + return 0; + ret = qcom_slim_qmi_power_request(ctrl, false); if (ret && ret != -EBUSY) dev_info(ctrl->dev, "slim resource not idle:%d\n", ret); diff --git a/drivers/slimbus/slimbus.h b/drivers/slimbus/slimbus.h index c73035915f1d..00a7f112574b 100644 --- a/drivers/slimbus/slimbus.h +++ b/drivers/slimbus/slimbus.h @@ -244,7 +244,7 @@ enum slim_ch_data_fmt { }; /** - * enum slim_ch_aux_fmt: SLIMbus channel Aux Field format IDs according to + * enum slim_ch_aux_bit_fmt: SLIMbus channel Aux Field format IDs according to * Table 63 of SLIMbus Spec 2.0 * @SLIM_CH_AUX_FMT_NOT_APPLICABLE: Undefined * @SLIM_CH_AUX_FMT_ZCUV_TUNNEL_IEC60958: ZCUV for tunneling IEC60958 |