Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / misc / mic / bus / cosm_bus.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel MIC Platform Software Stack (MPSS)
4  *
5  * Copyright(c) 2015 Intel Corporation.
6  *
7  * Intel MIC COSM Bus Driver
8  */
9 #include <linux/slab.h>
10 #include <linux/module.h>
11 #include <linux/idr.h>
12 #include "cosm_bus.h"
13
14 /* Unique numbering for cosm devices. */
15 static DEFINE_IDA(cosm_index_ida);
16
17 static int cosm_dev_probe(struct device *d)
18 {
19         struct cosm_device *dev = dev_to_cosm(d);
20         struct cosm_driver *drv = drv_to_cosm(dev->dev.driver);
21
22         return drv->probe(dev);
23 }
24
25 static int cosm_dev_remove(struct device *d)
26 {
27         struct cosm_device *dev = dev_to_cosm(d);
28         struct cosm_driver *drv = drv_to_cosm(dev->dev.driver);
29
30         drv->remove(dev);
31         return 0;
32 }
33
34 static struct bus_type cosm_bus = {
35         .name  = "cosm_bus",
36         .probe = cosm_dev_probe,
37         .remove = cosm_dev_remove,
38 };
39
40 int cosm_register_driver(struct cosm_driver *driver)
41 {
42         driver->driver.bus = &cosm_bus;
43         return driver_register(&driver->driver);
44 }
45 EXPORT_SYMBOL_GPL(cosm_register_driver);
46
47 void cosm_unregister_driver(struct cosm_driver *driver)
48 {
49         driver_unregister(&driver->driver);
50 }
51 EXPORT_SYMBOL_GPL(cosm_unregister_driver);
52
53 static inline void cosm_release_dev(struct device *d)
54 {
55         struct cosm_device *cdev = dev_to_cosm(d);
56
57         kfree(cdev);
58 }
59
60 struct cosm_device *
61 cosm_register_device(struct device *pdev, struct cosm_hw_ops *hw_ops)
62 {
63         struct cosm_device *cdev;
64         int ret;
65
66         cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
67         if (!cdev)
68                 return ERR_PTR(-ENOMEM);
69
70         cdev->dev.parent = pdev;
71         cdev->dev.release = cosm_release_dev;
72         cdev->hw_ops = hw_ops;
73         dev_set_drvdata(&cdev->dev, cdev);
74         cdev->dev.bus = &cosm_bus;
75
76         /* Assign a unique device index and hence name */
77         ret = ida_simple_get(&cosm_index_ida, 0, 0, GFP_KERNEL);
78         if (ret < 0)
79                 goto free_cdev;
80
81         cdev->index = ret;
82         cdev->dev.id = ret;
83         dev_set_name(&cdev->dev, "cosm-dev%u", cdev->index);
84
85         ret = device_register(&cdev->dev);
86         if (ret)
87                 goto ida_remove;
88         return cdev;
89 ida_remove:
90         ida_simple_remove(&cosm_index_ida, cdev->index);
91 free_cdev:
92         put_device(&cdev->dev);
93         return ERR_PTR(ret);
94 }
95 EXPORT_SYMBOL_GPL(cosm_register_device);
96
97 void cosm_unregister_device(struct cosm_device *dev)
98 {
99         int index = dev->index; /* save for after device release */
100
101         device_unregister(&dev->dev);
102         ida_simple_remove(&cosm_index_ida, index);
103 }
104 EXPORT_SYMBOL_GPL(cosm_unregister_device);
105
106 struct cosm_device *cosm_find_cdev_by_id(int id)
107 {
108         struct device *dev = subsys_find_device_by_id(&cosm_bus, id, NULL);
109
110         return dev ? container_of(dev, struct cosm_device, dev) : NULL;
111 }
112 EXPORT_SYMBOL_GPL(cosm_find_cdev_by_id);
113
114 static int __init cosm_init(void)
115 {
116         return bus_register(&cosm_bus);
117 }
118
119 static void __exit cosm_exit(void)
120 {
121         bus_unregister(&cosm_bus);
122         ida_destroy(&cosm_index_ida);
123 }
124
125 core_initcall(cosm_init);
126 module_exit(cosm_exit);
127
128 MODULE_AUTHOR("Intel Corporation");
129 MODULE_DESCRIPTION("Intel(R) MIC card OS state management bus driver");
130 MODULE_LICENSE("GPL v2");