blob: 446735ca400b3d22ef9442a3107d7c136fb7b31d [file] [log] [blame]
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -07001/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/esoc_client.h>
14#include <linux/of.h>
15#include <linux/spinlock.h>
16#include "esoc.h"
17
18static DEFINE_SPINLOCK(notify_lock);
19static ATOMIC_NOTIFIER_HEAD(client_notify);
20
21static void devm_esoc_desc_release(struct device *dev, void *res)
22{
23 struct esoc_desc *esoc_desc = res;
24
25 kfree(esoc_desc->name);
26 kfree(esoc_desc->link);
27 put_esoc_clink(esoc_desc->priv);
28}
29
30static int devm_esoc_desc_match(struct device *dev, void *res, void *data)
31{
32 struct esoc_desc *esoc_desc = res;
33 return esoc_desc == data;
34}
35
36struct esoc_desc *devm_register_esoc_client(struct device *dev,
37 const char *name)
38{
39 int ret, index;
40 const char *client_desc;
41 char *esoc_prop;
42 const __be32 *parp;
43 struct device_node *esoc_node;
44 struct device_node *np = dev->of_node;
45 struct esoc_clink *esoc_clink;
46 struct esoc_desc *desc;
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -070047 char *esoc_name, *esoc_link, *esoc_link_info;
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080048
49 for (index = 0;; index++) {
50 esoc_prop = kasprintf(GFP_KERNEL, "esoc-%d", index);
Hanumant Singhf7fdd242016-05-11 14:59:37 -070051 if (IS_ERR_OR_NULL(esoc_prop))
52 return ERR_PTR(-ENOMEM);
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080053 parp = of_get_property(np, esoc_prop, NULL);
54 if (parp == NULL) {
55 dev_err(dev, "esoc device not present\n");
56 kfree(esoc_prop);
57 return NULL;
58 }
59 ret = of_property_read_string_index(np, "esoc-names", index,
60 &client_desc);
61 if (ret) {
62 dev_err(dev, "cannot find matching string\n");
63 kfree(esoc_prop);
64 return NULL;
65 }
66 if (strcmp(client_desc, name)) {
67 kfree(esoc_prop);
68 continue;
69 }
70 kfree(esoc_prop);
71 esoc_node = of_find_node_by_phandle(be32_to_cpup(parp));
72 esoc_clink = get_esoc_clink_by_node(esoc_node);
73 if (IS_ERR_OR_NULL(esoc_clink)) {
74 dev_err(dev, "matching esoc clink not present\n");
75 return ERR_PTR(-EPROBE_DEFER);
76 }
77 esoc_name = kasprintf(GFP_KERNEL, "esoc%d",
78 esoc_clink->id);
79 if (IS_ERR_OR_NULL(esoc_name)) {
80 dev_err(dev, "unable to allocate esoc name\n");
81 return ERR_PTR(-ENOMEM);
82 }
83 esoc_link = kasprintf(GFP_KERNEL, "%s", esoc_clink->link_name);
84 if (IS_ERR_OR_NULL(esoc_link)) {
85 dev_err(dev, "unable to allocate esoc link name\n");
86 kfree(esoc_name);
87 return ERR_PTR(-ENOMEM);
88 }
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -070089 esoc_link_info = kasprintf(GFP_KERNEL, "%s",
90 esoc_clink->link_info);
91 if (IS_ERR_OR_NULL(esoc_link_info)) {
92 dev_err(dev, "unable to alloc link info name\n");
93 kfree(esoc_name);
94 kfree(esoc_link);
95 return ERR_PTR(-ENOMEM);
96 }
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080097 desc = devres_alloc(devm_esoc_desc_release,
98 sizeof(*desc), GFP_KERNEL);
99 if (IS_ERR_OR_NULL(desc)) {
100 kfree(esoc_name);
101 kfree(esoc_link);
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -0700102 kfree(esoc_link_info);
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800103 dev_err(dev, "unable to allocate esoc descriptor\n");
104 return ERR_PTR(-ENOMEM);
105 }
106 desc->name = esoc_name;
107 desc->link = esoc_link;
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -0700108 desc->link_info = esoc_link_info;
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800109 desc->priv = esoc_clink;
110 devres_add(dev, desc);
111 return desc;
112 }
113 return NULL;
114}
115EXPORT_SYMBOL(devm_register_esoc_client);
116
117void devm_unregister_esoc_client(struct device *dev,
118 struct esoc_desc *esoc_desc)
119{
120 int ret;
121
122 ret = devres_release(dev, devm_esoc_desc_release,
123 devm_esoc_desc_match, esoc_desc);
124 WARN_ON(ret);
125}
126EXPORT_SYMBOL(devm_unregister_esoc_client);
127
128int esoc_register_client_notifier(struct notifier_block *nb)
129{
130 return atomic_notifier_chain_register(&client_notify, nb);
131}
132EXPORT_SYMBOL(esoc_register_client_notifier);
133
134void notify_esoc_clients(struct esoc_clink *esoc_clink, unsigned long evt)
135{
136 unsigned int id;
137 unsigned long flags;
138
139 spin_lock_irqsave(&notify_lock, flags);
140 id = esoc_clink->id;
141 atomic_notifier_call_chain(&client_notify, evt, &id);
142 spin_unlock_irqrestore(&notify_lock, flags);
143}
144EXPORT_SYMBOL(notify_esoc_clients);