From 951a5af92276f5b2f1b8834bd5eef96d8788f66b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 1 Jul 2016 14:18:59 -0700 Subject: [PATCH 1/8] soc: qcom: smem: Silence probe defer error If we fail to get the hwspinlock due to probe defer, we shouldn't print an error message. Just be silent in this case. Cc: Bjorn Andersson Signed-off-by: Stephen Boyd Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 2e1aa9f130f4..18ec52f2078a 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -740,7 +740,8 @@ static int qcom_smem_probe(struct platform_device *pdev) hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); if (hwlock_id < 0) { - dev_err(&pdev->dev, "failed to retrieve hwlock\n"); + if (hwlock_id != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to retrieve hwlock\n"); return hwlock_id; } From dea8524218099ff73ffd1ebd08d97ce6a45b7e0e Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 4 Jul 2016 11:01:56 -0400 Subject: [PATCH 2/8] firmware: qcom_scm: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/firmware/Kconfig:config QCOM_SCM drivers/firmware/Kconfig: bool ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Andy Gross Cc: David Brown Cc: linux-arm-msm@vger.kernel.org Cc: linux-soc@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Andy Gross --- drivers/firmware/qcom_scm.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index e64a501adbf4..d95c70227c05 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1,4 +1,7 @@ -/* Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. +/* + * Qualcomm SCM driver + * + * Copyright (c) 2010,2015, The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. * * This program is free software; you can redistribute it and/or modify @@ -12,7 +15,7 @@ * */ #include -#include +#include #include #include #include @@ -376,8 +379,6 @@ static const struct of_device_id qcom_scm_dt_match[] = { {} }; -MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); - static struct platform_driver qcom_scm_driver = { .driver = { .name = "qcom_scm", @@ -414,14 +415,4 @@ static int __init qcom_scm_init(void) return platform_driver_register(&qcom_scm_driver); } - subsys_initcall(qcom_scm_init); - -static void __exit qcom_scm_exit(void) -{ - platform_driver_unregister(&qcom_scm_driver); -} -module_exit(qcom_scm_exit); - -MODULE_DESCRIPTION("Qualcomm SCM driver"); -MODULE_LICENSE("GPL v2"); From 3a1281848830fcb3202cfd7ffe62d19641471d05 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 9 Aug 2016 17:36:02 -0700 Subject: [PATCH 3/8] soc: qcom: smd: Correct compile stub prototypes The prototypes for the compile stubs was not properly marked as static inline, this patch corrects this. Fixes: f79a917e69e1 ("Merge tag 'qcom-soc-for-4.7-2' into net-next") Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- include/linux/soc/qcom/smd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h index cbb0f06c41b2..910ce1d9ba89 100644 --- a/include/linux/soc/qcom/smd.h +++ b/include/linux/soc/qcom/smd.h @@ -83,14 +83,14 @@ qcom_smd_open_channel(struct qcom_smd_channel *channel, return NULL; } -void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel) +static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel) { /* This shouldn't be possible */ WARN_ON(1); return NULL; } -void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data) +static inline void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data) { /* This shouldn't be possible */ WARN_ON(1); From 0a0c08cae01b33b29abd24608d3800986546f0af Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 9 Aug 2016 17:39:19 -0700 Subject: [PATCH 4/8] soc: qcom: smd: Simplify multi channel handling Multi-channel clients split between several drivers need a way to close individual channels, as these drivers might be removed individually. With this in place the responsibility of closing additionally opened channels to the client as well only concerning smd about the primary channel. With this approach we will only trigger removal of SMD devices based on the state of the primary channel, however we get in sync with how rpmsg works. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smd.c | 34 ++++++++++++++++------------------ include/linux/soc/qcom/smd.h | 7 +++++++ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index ac1957dfdf24..63e72eb9baa7 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -197,7 +197,6 @@ struct qcom_smd_channel { void *drvdata; struct list_head list; - struct list_head dev_list; }; /** @@ -891,8 +890,6 @@ static int qcom_smd_dev_remove(struct device *dev) struct qcom_smd_device *qsdev = to_smd_device(dev); struct qcom_smd_driver *qsdrv = to_smd_driver(dev); struct qcom_smd_channel *channel = qsdev->channel; - struct qcom_smd_channel *tmp; - struct qcom_smd_channel *ch; qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING); @@ -911,15 +908,9 @@ static int qcom_smd_dev_remove(struct device *dev) if (qsdrv->remove) qsdrv->remove(qsdev); - /* - * The client is now gone, close and release all channels associated - * with this sdev - */ - list_for_each_entry_safe(ch, tmp, &channel->dev_list, dev_list) { - qcom_smd_channel_close(ch); - list_del(&ch->dev_list); - ch->qsdev = NULL; - } + /* The client is now gone, close the primary channel */ + qcom_smd_channel_close(channel); + channel->qsdev = NULL; return 0; } @@ -1091,6 +1082,8 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name) * * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't * ready. + * + * Any channels returned must be closed with a call to qcom_smd_close_channel() */ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent, const char *name, @@ -1120,15 +1113,21 @@ struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent, return ERR_PTR(ret); } - /* - * Append the list of channel to the channels associated with the sdev - */ - list_add_tail(&channel->dev_list, &sdev->channel->dev_list); - return channel; } EXPORT_SYMBOL(qcom_smd_open_channel); +/** + * qcom_smd_close_channel() - close an additionally opened channel + * @channel: channel handle, returned by qcom_smd_open_channel() + */ +void qcom_smd_close_channel(struct qcom_smd_channel *channel) +{ + qcom_smd_channel_close(channel); + channel->qsdev = NULL; +} +EXPORT_SYMBOL(qcom_smd_close_channel); + /* * Allocate the qcom_smd_channel object for a newly found smd channel, * retrieving and validating the smem items involved. @@ -1150,7 +1149,6 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed if (!channel) return ERR_PTR(-ENOMEM); - INIT_LIST_HEAD(&channel->dev_list); channel->edge = edge; channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); if (!channel->name) diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h index 910ce1d9ba89..324b1decfffb 100644 --- a/include/linux/soc/qcom/smd.h +++ b/include/linux/soc/qcom/smd.h @@ -55,6 +55,7 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv); struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel, const char *name, qcom_smd_cb_t cb); +void qcom_smd_close_channel(struct qcom_smd_channel *channel); void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel); void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data); int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); @@ -83,6 +84,12 @@ qcom_smd_open_channel(struct qcom_smd_channel *channel, return NULL; } +static inline void qcom_smd_close_channel(struct qcom_smd_channel *channel) +{ + /* This shouldn't be possible */ + WARN_ON(1); +} + static inline void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel) { /* This shouldn't be possible */ From 381a0b4ce45b2ad809b79049e6316a83d5eaa2ea Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 9 Aug 2016 17:42:55 -0700 Subject: [PATCH 5/8] soc: qcom: smd: Request irqs after parsing properties The code exectued by the interrupt handler depends on the values parsed after requesting the irq, just to be save we should therefor move the request_irq() call to be done after parsing the properties. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smd.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index 63e72eb9baa7..679f7778a4e3 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -1348,22 +1348,6 @@ static int qcom_smd_parse_edge(struct device *dev, edge->of_node = of_node_get(node); - irq = irq_of_parse_and_map(node, 0); - if (irq < 0) { - dev_err(dev, "required smd interrupt missing\n"); - return -EINVAL; - } - - ret = devm_request_irq(dev, irq, - qcom_smd_edge_intr, IRQF_TRIGGER_RISING, - node->name, edge); - if (ret) { - dev_err(dev, "failed to request smd irq\n"); - return ret; - } - - edge->irq = irq; - key = "qcom,smd-edge"; ret = of_property_read_u32(node, key, &edge->edge_id); if (ret) { @@ -1398,6 +1382,22 @@ static int qcom_smd_parse_edge(struct device *dev, return -EINVAL; } + irq = irq_of_parse_and_map(node, 0); + if (irq < 0) { + dev_err(dev, "required smd interrupt missing\n"); + return -EINVAL; + } + + ret = devm_request_irq(dev, irq, + qcom_smd_edge_intr, IRQF_TRIGGER_RISING, + node->name, edge); + if (ret) { + dev_err(dev, "failed to request smd irq\n"); + return ret; + } + + edge->irq = irq; + return 0; } From da0573026c2d3d445c39385024bfc3ce6beebe09 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 15 Aug 2016 11:15:57 -0700 Subject: [PATCH 6/8] soc: qcom: smd: Represent smd edges as devices By representing each edge as its own device the channels are no longer tied to being parented by the same smd device and as such an edge can live as children of e.g. remoteproc instances. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smd.c | 199 ++++++++++++++++++++++------------- include/linux/soc/qcom/smd.h | 18 ++++ 2 files changed, 141 insertions(+), 76 deletions(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index 679f7778a4e3..f20816bef1b5 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -95,7 +95,7 @@ static const struct { /** * struct qcom_smd_edge - representing a remote processor - * @smd: handle to qcom_smd + * @dev: device for this edge * @of_node: of_node handle for information related to this edge * @edge_id: identifier of this edge * @remote_pid: identifier of remote processor @@ -111,7 +111,8 @@ static const struct { * @state_work: work item for edge state changes */ struct qcom_smd_edge { - struct qcom_smd *smd; + struct device dev; + struct device_node *of_node; unsigned edge_id; unsigned remote_pid; @@ -135,6 +136,8 @@ struct qcom_smd_edge { struct work_struct state_work; }; +#define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev) + /* * SMD channel states. */ @@ -199,19 +202,6 @@ struct qcom_smd_channel { struct list_head list; }; -/** - * struct qcom_smd - smd struct - * @dev: device struct - * @num_edges: number of entries in @edges - * @edges: array of edges to be handled - */ -struct qcom_smd { - struct device *dev; - - unsigned num_edges; - struct qcom_smd_edge edges[0]; -}; - /* * Format of the smd_info smem items, for byte aligned channels. */ @@ -420,7 +410,7 @@ static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel, if (channel->state == state) return; - dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state); + dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state); SET_TX_CHANNEL_FLAG(channel, fDSR, is_open); SET_TX_CHANNEL_FLAG(channel, fCTS, is_open); @@ -964,13 +954,12 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel) struct qcom_smd_device *qsdev; struct qcom_smd_edge *edge = channel->edge; struct device_node *node; - struct qcom_smd *smd = edge->smd; int ret; if (channel->qsdev) return -EEXIST; - dev_dbg(smd->dev, "registering '%s'\n", channel->name); + dev_dbg(&edge->dev, "registering '%s'\n", channel->name); qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL); if (!qsdev) @@ -981,7 +970,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel) edge->of_node->name, node ? node->name : channel->name); - qsdev->dev.parent = smd->dev; + qsdev->dev.parent = &edge->dev; qsdev->dev.bus = &qcom_smd_bus; qsdev->dev.release = qcom_smd_release_device; qsdev->dev.of_node = node; @@ -992,7 +981,7 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel) ret = device_register(&qsdev->dev); if (ret) { - dev_err(smd->dev, "device_register failed: %d\n", ret); + dev_err(&edge->dev, "device_register failed: %d\n", ret); put_device(&qsdev->dev); } @@ -1138,19 +1127,18 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed char *name) { struct qcom_smd_channel *channel; - struct qcom_smd *smd = edge->smd; size_t fifo_size; size_t info_size; void *fifo_base; void *info; int ret; - channel = devm_kzalloc(smd->dev, sizeof(*channel), GFP_KERNEL); + channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); channel->edge = edge; - channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); + channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL); if (!channel->name) return ERR_PTR(-ENOMEM); @@ -1173,7 +1161,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed } else if (info_size == 2 * sizeof(struct smd_channel_info)) { channel->info = info; } else { - dev_err(smd->dev, + dev_err(&edge->dev, "channel info of size %zu not supported\n", info_size); ret = -EINVAL; goto free_name_and_channel; @@ -1188,7 +1176,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed /* The channel consist of a rx and tx fifo of equal size */ fifo_size /= 2; - dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", + dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", name, info_size, fifo_size); channel->tx_fifo = fifo_base; @@ -1200,8 +1188,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed return channel; free_name_and_channel: - devm_kfree(smd->dev, channel->name); - devm_kfree(smd->dev, channel); + devm_kfree(&edge->dev, channel->name); + devm_kfree(&edge->dev, channel); return ERR_PTR(ret); } @@ -1217,7 +1205,6 @@ static void qcom_channel_scan_worker(struct work_struct *work) struct qcom_smd_alloc_entry *alloc_tbl; struct qcom_smd_alloc_entry *entry; struct qcom_smd_channel *channel; - struct qcom_smd *smd = edge->smd; unsigned long flags; unsigned fifo_id; unsigned info_id; @@ -1261,7 +1248,7 @@ static void qcom_channel_scan_worker(struct work_struct *work) list_add(&channel->list, &edge->channels); spin_unlock_irqrestore(&edge->channels_lock, flags); - dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); + dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name); set_bit(i, edge->allocated[tbl]); wake_up_interruptible(&edge->new_channel_event); @@ -1401,15 +1388,102 @@ static int qcom_smd_parse_edge(struct device *dev, return 0; } -static int qcom_smd_probe(struct platform_device *pdev) +/* + * Release function for an edge. + * Reset the state of each associated channel and free the edge context. + */ +static void qcom_smd_edge_release(struct device *dev) +{ + struct qcom_smd_channel *channel; + struct qcom_smd_edge *edge = to_smd_edge(dev); + + list_for_each_entry(channel, &edge->channels, list) { + SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); + SET_RX_CHANNEL_INFO(channel, head, 0); + SET_RX_CHANNEL_INFO(channel, tail, 0); + } + + kfree(edge); +} + +/** + * qcom_smd_register_edge() - register an edge based on an device_node + * @parent: parent device for the edge + * @node: device_node describing the edge + * + * Returns an edge reference, or negative ERR_PTR() on failure. + */ +struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, + struct device_node *node) { struct qcom_smd_edge *edge; - struct device_node *node; - struct qcom_smd *smd; - size_t array_size; - int num_edges; int ret; - int i = 0; + + edge = kzalloc(sizeof(*edge), GFP_KERNEL); + if (!edge) + return ERR_PTR(-ENOMEM); + + init_waitqueue_head(&edge->new_channel_event); + + edge->dev.parent = parent; + edge->dev.release = qcom_smd_edge_release; + dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name); + ret = device_register(&edge->dev); + if (ret) { + pr_err("failed to register smd edge\n"); + return ERR_PTR(ret); + } + + ret = qcom_smd_parse_edge(&edge->dev, node, edge); + if (ret) { + dev_err(&edge->dev, "failed to parse smd edge\n"); + goto unregister_dev; + } + + schedule_work(&edge->scan_work); + + return edge; + +unregister_dev: + put_device(&edge->dev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(qcom_smd_register_edge); + +static int qcom_smd_remove_device(struct device *dev, void *data) +{ + device_unregister(dev); + of_node_put(dev->of_node); + put_device(dev); + + return 0; +} + +/** + * qcom_smd_unregister_edge() - release an edge and its children + * @edge: edge reference acquired from qcom_smd_register_edge + */ +int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) +{ + int ret; + + disable_irq(edge->irq); + cancel_work_sync(&edge->scan_work); + cancel_work_sync(&edge->state_work); + + ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device); + if (ret) + dev_warn(&edge->dev, "can't remove smd device: %d\n", ret); + + device_unregister(&edge->dev); + + return 0; +} +EXPORT_SYMBOL(qcom_smd_unregister_edge); + +static int qcom_smd_probe(struct platform_device *pdev) +{ + struct device_node *node; void *p; /* Wait for smem */ @@ -1417,59 +1491,32 @@ static int qcom_smd_probe(struct platform_device *pdev) if (PTR_ERR(p) == -EPROBE_DEFER) return PTR_ERR(p); - num_edges = of_get_available_child_count(pdev->dev.of_node); - array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge); - smd = devm_kzalloc(&pdev->dev, array_size, GFP_KERNEL); - if (!smd) - return -ENOMEM; - smd->dev = &pdev->dev; - - smd->num_edges = num_edges; - for_each_available_child_of_node(pdev->dev.of_node, node) { - edge = &smd->edges[i++]; - edge->smd = smd; - init_waitqueue_head(&edge->new_channel_event); - - ret = qcom_smd_parse_edge(&pdev->dev, node, edge); - if (ret) - continue; - - schedule_work(&edge->scan_work); - } - - platform_set_drvdata(pdev, smd); + for_each_available_child_of_node(pdev->dev.of_node, node) + qcom_smd_register_edge(&pdev->dev, node); return 0; } +static int qcom_smd_remove_edge(struct device *dev, void *data) +{ + struct qcom_smd_edge *edge = to_smd_edge(dev); + + return qcom_smd_unregister_edge(edge); +} + /* * Shut down all smd clients by making sure that each edge stops processing * events and scanning for new channels, then call destroy on the devices. */ static int qcom_smd_remove(struct platform_device *pdev) { - struct qcom_smd_channel *channel; - struct qcom_smd_edge *edge; - struct qcom_smd *smd = platform_get_drvdata(pdev); - int i; + int ret; - for (i = 0; i < smd->num_edges; i++) { - edge = &smd->edges[i]; + ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge); + if (ret) + dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret); - disable_irq(edge->irq); - cancel_work_sync(&edge->scan_work); - cancel_work_sync(&edge->state_work); - - /* No need to lock here, because the writer is gone */ - list_for_each_entry(channel, &edge->channels, list) { - if (!channel->qsdev) - continue; - - qcom_smd_destroy_device(channel); - } - } - - return 0; + return ret; } static const struct of_device_id qcom_smd_of_match[] = { diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h index 324b1decfffb..f148e0ffbec7 100644 --- a/include/linux/soc/qcom/smd.h +++ b/include/linux/soc/qcom/smd.h @@ -61,6 +61,10 @@ void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data); int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); +struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, + struct device_node *node); +int qcom_smd_unregister_edge(struct qcom_smd_edge *edge); + #else static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv) @@ -111,6 +115,20 @@ static inline int qcom_smd_send(struct qcom_smd_channel *channel, return -ENXIO; } +static inline struct qcom_smd_edge * +qcom_smd_register_edge(struct device *parent, + struct device_node *node) +{ + return ERR_PTR(-ENXIO); +} + +static inline int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) +{ + /* This shouldn't be possible */ + WARN_ON(1); + return -ENXIO; +} + #endif #define module_qcom_smd_driver(__smd_driver) \ From 4e21a95d7fbc526d35d860ec34c468e04f53672f Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 26 Aug 2016 14:59:17 -0700 Subject: [PATCH 7/8] soc: qcom: smd: Reset rx tail rather than tx The local end of each SMD channel is responsible for updating the tx head and the rx tail, as such we should not touch the tx tail during a reset. Reported-by: Jeremy McNicoll Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index f20816bef1b5..322034ab9d37 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -363,7 +363,7 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel) SET_TX_CHANNEL_FLAG(channel, fSTATE, 1); SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); SET_TX_CHANNEL_INFO(channel, head, 0); - SET_TX_CHANNEL_INFO(channel, tail, 0); + SET_RX_CHANNEL_INFO(channel, tail, 0); qcom_smd_signal_channel(channel); From 23c282d62f573263db679e6b4c9f2da82aa24f96 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 11 Aug 2016 15:16:44 +0200 Subject: [PATCH 8/8] rtc: rtc-pm8xxx: Add support for pm8018 rtc In order to support RTC on Qualcomm MDM9615 SoC, add support for the pm8018 rtc in rtc-pm8xxx driver. Reviewed-by: Bjorn Andersson Acked-by: Alexandre Belloni Signed-off-by: Neil Armstrong Signed-off-by: Andy Gross --- Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt | 1 + drivers/rtc/rtc-pm8xxx.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt index f24f33409164..37a088f9a648 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt @@ -62,6 +62,7 @@ The below bindings specify the set of valid subnodes. "qcom,pm8058-rtc" "qcom,pm8921-rtc" "qcom,pm8941-rtc" + "qcom,pm8018-rtc" - reg: Usage: required diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 795fcbd02ea3..fac835530671 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -428,6 +428,7 @@ static const struct pm8xxx_rtc_regs pm8941_regs = { */ static const struct of_device_id pm8xxx_id_table[] = { { .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs }, + { .compatible = "qcom,pm8018-rtc", .data = &pm8921_regs }, { .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs }, { .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs }, { },