mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
Qualcomm ARM Based Driver Updates for v4.9
* Silence smem probe defer messages * Make scm explicitly non-modular * Assorted SMD bug fixes and minor changes * Add PM8018 RTC support -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXycjdAAoJEFKiBbHx2RXVVJAQAMZigw99xIh0vIlgQbquq3NF ih5HBow+yq+y744Zn9FJQvmPzGzPaoxTuvcvAh8M8qqoKpocolblEkcCgdgR62YK vKDHf8ZwTsR1t37jP35oUWE4xMNyHX5HFfDu267dwjzOpsFDYATotThTdp/T1muz uOWkmugrRGi04EfkVkX28uBEmvBmxDIAOrPclPifgYxpFlJ2d0/sC2SDtXwPR/Kk /Qb9aK659WUaqU2q0BmHKU2cgvo7oKa14vcriMgjU7jmzYKtvQrGmqt0YvCS320I XpYm4pDffG1HlOyz5a3KBakBzQRN24wQCXaSvVrY99B2/nLZtdVDnX29tw9mUioU GhfXanDMehgf4XJRwjhMsxiAYbSKEbaD5Rpr6rHebhPOVv8G4Yo36o4Q7yUr3Rpz pwFJdBMqA3S3roV318u0bgDjr4YjkYH7rRh1E8yjV7GFb9cMK0NPvfP8d/5l64Fk DE62Xl0eBmaHDd+gpousEAzZpIUp/TrTuGr0jhgLZbY+JMLHDlgiP8IZNx/EiZY4 PMN2xUFaqKVPw+OzWg4Weg6OirInpzOfvjaxyb10yQIaDb+FYJGrDcZjjKsf4MPS vlKjzC9GbfPa/XI5iq+ULGtF6T6g8Nv29pUdXb75oH6vOhca8wWSAvhscP151N79 /G13oF2ivpj+kvdLLfaX =yt6n -----END PGP SIGNATURE----- Merge tag 'qcom-drivers-for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/drivers Pull "Qualcomm ARM Based Driver Updates for v4.9" from Andy Gross: * Silence smem probe defer messages * Make scm explicitly non-modular * Assorted SMD bug fixes and minor changes * Add PM8018 RTC support * tag 'qcom-drivers-for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux: rtc: rtc-pm8xxx: Add support for pm8018 rtc soc: qcom: smd: Reset rx tail rather than tx soc: qcom: smd: Represent smd edges as devices soc: qcom: smd: Request irqs after parsing properties soc: qcom: smd: Simplify multi channel handling soc: qcom: smd: Correct compile stub prototypes firmware: qcom_scm: make it explicitly non-modular soc: qcom: smem: Silence probe defer error
This commit is contained in:
commit
fceec41b68
@ -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
|
||||
|
@ -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 <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@ -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");
|
||||
|
@ -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 },
|
||||
{ },
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -197,20 +200,6 @@ struct qcom_smd_channel {
|
||||
void *drvdata;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head dev_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];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -374,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);
|
||||
|
||||
@ -421,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);
|
||||
@ -891,8 +880,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 +898,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;
|
||||
}
|
||||
@ -973,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)
|
||||
@ -990,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;
|
||||
@ -1001,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);
|
||||
}
|
||||
|
||||
@ -1091,6 +1071,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 +1102,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.
|
||||
@ -1139,20 +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);
|
||||
|
||||
INIT_LIST_HEAD(&channel->dev_list);
|
||||
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);
|
||||
|
||||
@ -1175,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;
|
||||
@ -1190,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;
|
||||
@ -1202,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);
|
||||
}
|
||||
@ -1219,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;
|
||||
@ -1263,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);
|
||||
@ -1350,22 +1335,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) {
|
||||
@ -1400,18 +1369,121 @@ 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;
|
||||
}
|
||||
|
||||
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 */
|
||||
@ -1419,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[] = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -55,11 +55,16 @@ 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);
|
||||
|
||||
|
||||
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)
|
||||
@ -83,14 +88,20 @@ 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_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 */
|
||||
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);
|
||||
@ -104,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) \
|
||||
|
Loading…
Reference in New Issue
Block a user