blob: cef570bb1ef15e7fd2ac8460b3ed4a7118dcdfd6 [file] [log] [blame]
Satya Durga Srinivasu Prabhala377d32f2017-03-15 11:09:28 -07001/* Copyright (c) 2013-2015, 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/idr.h>
14#include <linux/slab.h>
15#include "esoc.h"
16
17static DEFINE_IDA(esoc_ida);
18
19/* SYSFS */
20static ssize_t
21esoc_name_show(struct device *dev, struct device_attribute *attr,
22 char *buf)
23{
24 return snprintf(buf, ESOC_NAME_LEN, "%s", to_esoc_clink(dev)->name);
25}
26
27static ssize_t
28esoc_link_show(struct device *dev, struct device_attribute *attr,
29 char *buf)
30{
31 return snprintf(buf, ESOC_LINK_LEN, "%s",
32 to_esoc_clink(dev)->link_name);
33}
34
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -070035static ssize_t
36esoc_link_info_show(struct device *dev, struct device_attribute *attr,
37 char *buf)
38{
39 return snprintf(buf, ESOC_LINK_LEN, "%s",
40 to_esoc_clink(dev)->link_info);
41}
42
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080043static struct device_attribute esoc_clink_attrs[] = {
44
45 __ATTR_RO(esoc_name),
46 __ATTR_RO(esoc_link),
Satya Durga Srinivasu Prabhalab8a2a4e2017-03-14 16:51:50 -070047 __ATTR_RO(esoc_link_info),
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080048 __ATTR_NULL,
49};
50
51static int esoc_bus_match(struct device *dev, struct device_driver *drv)
52{
53 int i = 0, match = 1;
54 struct esoc_clink *esoc_clink = to_esoc_clink(dev);
55 struct esoc_drv *esoc_drv = to_esoc_drv(drv);
56 int entries = esoc_drv->compat_entries;
57 struct esoc_compat *table = esoc_drv->compat_table;
58
59 for (i = 0; i < entries; i++) {
60 if (strcasecmp(esoc_clink->name, table[i].name) == 0)
61 return match;
62 }
63 return 0;
64}
65
66static int esoc_bus_probe(struct device *dev)
67{
68 int ret;
69 struct esoc_clink *esoc_clink = to_esoc_clink(dev);
70 struct esoc_drv *esoc_drv = to_esoc_drv(dev->driver);
71
72 ret = esoc_drv->probe(esoc_clink, esoc_drv);
73 if (ret) {
74 pr_err("failed to probe %s dev\n", esoc_clink->name);
75 return ret;
76 }
77 return 0;
78}
79
80struct bus_type esoc_bus_type = {
81 .name = "esoc",
82 .match = esoc_bus_match,
83 .dev_attrs = esoc_clink_attrs,
84};
85EXPORT_SYMBOL(esoc_bus_type);
86
87struct device esoc_bus = {
88 .init_name = "esoc-bus"
89};
90EXPORT_SYMBOL(esoc_bus);
91
92/* bus accessor */
93static void esoc_clink_release(struct device *dev)
94{
95 struct esoc_clink *esoc_clink = to_esoc_clink(dev);
96
97 ida_simple_remove(&esoc_ida, esoc_clink->id);
98 kfree(esoc_clink);
99}
100
101static int esoc_clink_match_id(struct device *dev, void *id)
102{
103 struct esoc_clink *esoc_clink = to_esoc_clink(dev);
104 int *esoc_id = (int *)id;
105
106 if (esoc_clink->id == *esoc_id) {
107 if (!try_module_get(esoc_clink->owner))
108 return 0;
109 return 1;
110 }
111 return 0;
112}
113
114static int esoc_clink_match_node(struct device *dev, void *id)
115{
116 struct esoc_clink *esoc_clink = to_esoc_clink(dev);
117 struct device_node *node = id;
118
119 if (esoc_clink->np == node) {
120 if (!try_module_get(esoc_clink->owner))
121 return 0;
122 return 1;
123 }
124 return 0;
125}
126
127void esoc_for_each_dev(void *data, int (*fn)(struct device *dev, void *))
128{
129 int ret;
130
131 ret = bus_for_each_dev(&esoc_bus_type, NULL, data, fn);
132}
133EXPORT_SYMBOL(esoc_for_each_dev);
134
135struct esoc_clink *get_esoc_clink(int id)
136{
137 struct esoc_clink *esoc_clink;
138 struct device *dev;
139
140 dev = bus_find_device(&esoc_bus_type, NULL, &id, esoc_clink_match_id);
Satya Durga Srinivasu Prabhala377d32f2017-03-15 11:09:28 -0700141 if (IS_ERR_OR_NULL(dev))
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800142 return NULL;
143 esoc_clink = to_esoc_clink(dev);
144 return esoc_clink;
145}
146EXPORT_SYMBOL(get_esoc_clink);
147
148struct esoc_clink *get_esoc_clink_by_node(struct device_node *node)
149{
150 struct esoc_clink *esoc_clink;
151 struct device *dev;
152
153 dev = bus_find_device(&esoc_bus_type, NULL, node,
154 esoc_clink_match_node);
Satya Durga Srinivasu Prabhala377d32f2017-03-15 11:09:28 -0700155 if (IS_ERR_OR_NULL(dev))
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800156 return NULL;
157 esoc_clink = to_esoc_clink(dev);
158 return esoc_clink;
159}
160
161void put_esoc_clink(struct esoc_clink *esoc_clink)
162{
163 module_put(esoc_clink->owner);
164}
165EXPORT_SYMBOL(put_esoc_clink);
166
167bool esoc_req_eng_enabled(struct esoc_clink *esoc_clink)
168{
169 return !esoc_clink->req_eng ? false : true;
170}
171EXPORT_SYMBOL(esoc_req_eng_enabled);
172
173bool esoc_cmd_eng_enabled(struct esoc_clink *esoc_clink)
174{
175 return !esoc_clink->cmd_eng ? false : true;
176}
177EXPORT_SYMBOL(esoc_cmd_eng_enabled);
178/* ssr operations */
179int esoc_clink_register_ssr(struct esoc_clink *esoc_clink)
180{
181 int ret;
182 int len;
183 char *subsys_name;
184
185 len = strlen("esoc") + sizeof(esoc_clink->id);
186 subsys_name = kzalloc(len, GFP_KERNEL);
Satya Durga Srinivasu Prabhala377d32f2017-03-15 11:09:28 -0700187 if (IS_ERR_OR_NULL(subsys_name))
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800188 return PTR_ERR(subsys_name);
189 snprintf(subsys_name, len, "esoc%d", esoc_clink->id);
190 esoc_clink->subsys.name = subsys_name;
191 esoc_clink->dev.of_node = esoc_clink->np;
192 esoc_clink->subsys.dev = &esoc_clink->dev;
193 esoc_clink->subsys_dev = subsys_register(&esoc_clink->subsys);
Satya Durga Srinivasu Prabhala377d32f2017-03-15 11:09:28 -0700194 if (IS_ERR_OR_NULL(esoc_clink->subsys_dev)) {
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800195 dev_err(&esoc_clink->dev, "failed to register ssr node\n");
196 ret = PTR_ERR(esoc_clink->subsys_dev);
197 goto subsys_err;
198 }
199 return 0;
200subsys_err:
201 kfree(subsys_name);
202 return ret;
203}
204EXPORT_SYMBOL(esoc_clink_register_ssr);
205
206void esoc_clink_unregister_ssr(struct esoc_clink *esoc_clink)
207{
208 subsys_unregister(esoc_clink->subsys_dev);
209 kfree(esoc_clink->subsys.name);
210}
211EXPORT_SYMBOL(esoc_clink_unregister_ssr);
212
213int esoc_clink_request_ssr(struct esoc_clink *esoc_clink)
214{
215 subsystem_restart_dev(esoc_clink->subsys_dev);
216 return 0;
217}
218EXPORT_SYMBOL(esoc_clink_request_ssr);
219
220/* bus operations */
221void esoc_clink_evt_notify(enum esoc_evt evt, struct esoc_clink *esoc_clink)
222{
223 unsigned long flags;
224
225 spin_lock_irqsave(&esoc_clink->notify_lock, flags);
226 notify_esoc_clients(esoc_clink, evt);
227 if (esoc_clink->req_eng && esoc_clink->req_eng->handle_clink_evt)
228 esoc_clink->req_eng->handle_clink_evt(evt, esoc_clink->req_eng);
229 if (esoc_clink->cmd_eng && esoc_clink->cmd_eng->handle_clink_evt)
230 esoc_clink->cmd_eng->handle_clink_evt(evt, esoc_clink->cmd_eng);
231 spin_unlock_irqrestore(&esoc_clink->notify_lock, flags);
232}
233EXPORT_SYMBOL(esoc_clink_evt_notify);
234
235void *get_esoc_clink_data(struct esoc_clink *esoc)
236{
237 return esoc->clink_data;
238}
239EXPORT_SYMBOL(get_esoc_clink_data);
240
241void set_esoc_clink_data(struct esoc_clink *esoc, void *data)
242{
243 esoc->clink_data = data;
244}
245EXPORT_SYMBOL(set_esoc_clink_data);
246
247void esoc_clink_queue_request(enum esoc_req req, struct esoc_clink *esoc_clink)
248{
249 unsigned long flags;
250 struct esoc_eng *req_eng;
251
252 spin_lock_irqsave(&esoc_clink->notify_lock, flags);
253 if (esoc_clink->req_eng != NULL) {
254 req_eng = esoc_clink->req_eng;
255 req_eng->handle_clink_req(req, req_eng);
256 }
257 spin_unlock_irqrestore(&esoc_clink->notify_lock, flags);
258}
259EXPORT_SYMBOL(esoc_clink_queue_request);
260
261void esoc_set_drv_data(struct esoc_clink *esoc_clink, void *data)
262{
263 dev_set_drvdata(&esoc_clink->dev, data);
264}
265EXPORT_SYMBOL(esoc_set_drv_data);
266
267void *esoc_get_drv_data(struct esoc_clink *esoc_clink)
268{
269 return dev_get_drvdata(&esoc_clink->dev);
270}
271EXPORT_SYMBOL(esoc_get_drv_data);
272
273/* bus registration functions */
274void esoc_clink_unregister(struct esoc_clink *esoc_clink)
275{
276 if (get_device(&esoc_clink->dev) != NULL) {
277 device_unregister(&esoc_clink->dev);
278 put_device(&esoc_clink->dev);
279 }
280}
281EXPORT_SYMBOL(esoc_clink_unregister);
282
283int esoc_clink_register(struct esoc_clink *esoc_clink)
284{
285 int id, err;
286 struct device *dev;
287
288 if (!esoc_clink->name || !esoc_clink->link_name ||
289 !esoc_clink->clink_ops) {
290 dev_err(esoc_clink->parent, "invalid esoc arguments\n");
291 return -EINVAL;
292 }
293 id = ida_simple_get(&esoc_ida, 0, ESOC_DEV_MAX, GFP_KERNEL);
294 if (id < 0) {
295 err = id;
296 goto exit_ida;
297 }
298 esoc_clink->id = id;
299 dev = &esoc_clink->dev;
300 dev->bus = &esoc_bus_type;
301 dev->release = esoc_clink_release;
302 if (!esoc_clink->parent)
303 dev->parent = &esoc_bus;
304 else
305 dev->parent = esoc_clink->parent;
306 dev_set_name(dev, "esoc%d", id);
307 err = device_register(dev);
308 if (err) {
309 dev_err(esoc_clink->parent, "esoc device register failed\n");
310 goto exit_ida;
311 }
312 spin_lock_init(&esoc_clink->notify_lock);
313 return 0;
314exit_ida:
315 ida_simple_remove(&esoc_ida, id);
316 pr_err("unable to register %s, err = %d\n", esoc_clink->name, err);
317 return err;
318}
319EXPORT_SYMBOL(esoc_clink_register);
320
321int esoc_clink_register_req_eng(struct esoc_clink *esoc_clink,
322 struct esoc_eng *eng)
323{
324 if (esoc_clink->req_eng)
325 return -EBUSY;
326 if (!eng->handle_clink_req)
327 return -EINVAL;
328 esoc_clink->req_eng = eng;
329 eng->esoc_clink = esoc_clink;
330 esoc_clink_evt_notify(ESOC_REQ_ENG_ON, esoc_clink);
331 return 0;
332}
333EXPORT_SYMBOL(esoc_clink_register_req_eng);
334
335int esoc_clink_register_cmd_eng(struct esoc_clink *esoc_clink,
336 struct esoc_eng *eng)
337{
338 if (esoc_clink->cmd_eng)
339 return -EBUSY;
340 esoc_clink->cmd_eng = eng;
341 eng->esoc_clink = esoc_clink;
342 esoc_clink_evt_notify(ESOC_CMD_ENG_ON, esoc_clink);
343 return 0;
344}
345EXPORT_SYMBOL(esoc_clink_register_cmd_eng);
346
347void esoc_clink_unregister_req_eng(struct esoc_clink *esoc_clink,
348 struct esoc_eng *eng)
349{
350 esoc_clink->req_eng = NULL;
351 esoc_clink_evt_notify(ESOC_REQ_ENG_OFF, esoc_clink);
352}
353EXPORT_SYMBOL(esoc_clink_unregister_req_eng);
354
355void esoc_clink_unregister_cmd_eng(struct esoc_clink *esoc_clink,
356 struct esoc_eng *eng)
357{
358 esoc_clink->cmd_eng = NULL;
359 esoc_clink_evt_notify(ESOC_CMD_ENG_OFF, esoc_clink);
360}
361EXPORT_SYMBOL(esoc_clink_unregister_cmd_eng);
362
363int esoc_drv_register(struct esoc_drv *driver)
364{
365 int ret;
366
367 driver->driver.bus = &esoc_bus_type;
368 driver->driver.probe = esoc_bus_probe;
369 ret = driver_register(&driver->driver);
370 if (ret)
371 return ret;
372 return 0;
373}
374EXPORT_SYMBOL(esoc_drv_register);
375
376static int __init esoc_init(void)
377{
378 int ret;
379
380 ret = device_register(&esoc_bus);
381 if (ret) {
382 pr_err("esoc bus device register fail\n");
383 return ret;
384 }
385 ret = bus_register(&esoc_bus_type);
386 if (ret) {
387 pr_err("esoc bus register fail\n");
388 return ret;
389 }
390 pr_debug("esoc bus registration done\n");
391 return 0;
392}
393
394subsys_initcall(esoc_init);
395MODULE_LICENSE("GPL v2");