Merge tag 'libnvdimm-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
[linux-2.6-microblaze.git] / drivers / soundwire / bus_type.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2015-17 Intel Corporation.
3
4 #include <linux/module.h>
5 #include <linux/mod_devicetable.h>
6 #include <linux/pm_domain.h>
7 #include <linux/soundwire/sdw.h>
8 #include <linux/soundwire/sdw_type.h>
9 #include "bus.h"
10 #include "sysfs_local.h"
11
12 /**
13  * sdw_get_device_id - find the matching SoundWire device id
14  * @slave: SoundWire Slave Device
15  * @drv: SoundWire Slave Driver
16  *
17  * The match is done by comparing the mfg_id and part_id from the
18  * struct sdw_device_id.
19  */
20 static const struct sdw_device_id *
21 sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv)
22 {
23         const struct sdw_device_id *id = drv->id_table;
24
25         while (id && id->mfg_id) {
26                 if (slave->id.mfg_id == id->mfg_id &&
27                     slave->id.part_id == id->part_id)
28                         return id;
29                 id++;
30         }
31
32         return NULL;
33 }
34
35 static int sdw_bus_match(struct device *dev, struct device_driver *ddrv)
36 {
37         struct sdw_slave *slave;
38         struct sdw_driver *drv;
39         int ret = 0;
40
41         if (is_sdw_slave(dev)) {
42                 slave = dev_to_sdw_dev(dev);
43                 drv = drv_to_sdw_driver(ddrv);
44
45                 ret = !!sdw_get_device_id(slave, drv);
46         }
47         return ret;
48 }
49
50 int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size)
51 {
52         /* modalias is sdw:m<mfg_id>p<part_id> */
53
54         return snprintf(buf, size, "sdw:m%04Xp%04X\n",
55                         slave->id.mfg_id, slave->id.part_id);
56 }
57
58 int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env)
59 {
60         struct sdw_slave *slave = dev_to_sdw_dev(dev);
61         char modalias[32];
62
63         sdw_slave_modalias(slave, modalias, sizeof(modalias));
64
65         if (add_uevent_var(env, "MODALIAS=%s", modalias))
66                 return -ENOMEM;
67
68         return 0;
69 }
70
71 struct bus_type sdw_bus_type = {
72         .name = "soundwire",
73         .match = sdw_bus_match,
74 };
75 EXPORT_SYMBOL_GPL(sdw_bus_type);
76
77 static int sdw_drv_probe(struct device *dev)
78 {
79         struct sdw_slave *slave = dev_to_sdw_dev(dev);
80         struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
81         const struct sdw_device_id *id;
82         int ret;
83
84         id = sdw_get_device_id(slave, drv);
85         if (!id)
86                 return -ENODEV;
87
88         slave->ops = drv->ops;
89
90         /*
91          * attach to power domain but don't turn on (last arg)
92          */
93         ret = dev_pm_domain_attach(dev, false);
94         if (ret)
95                 return ret;
96
97         ret = drv->probe(slave, id);
98         if (ret) {
99                 dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret);
100                 dev_pm_domain_detach(dev, false);
101                 return ret;
102         }
103
104         /* device is probed so let's read the properties now */
105         if (slave->ops && slave->ops->read_prop)
106                 slave->ops->read_prop(slave);
107
108         /* init the sysfs as we have properties now */
109         ret = sdw_slave_sysfs_init(slave);
110         if (ret < 0)
111                 dev_warn(dev, "Slave sysfs init failed:%d\n", ret);
112
113         /*
114          * Check for valid clk_stop_timeout, use DisCo worst case value of
115          * 300ms
116          *
117          * TODO: check the timeouts and driver removal case
118          */
119         if (slave->prop.clk_stop_timeout == 0)
120                 slave->prop.clk_stop_timeout = 300;
121
122         slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout,
123                                              slave->prop.clk_stop_timeout);
124
125         slave->probed = true;
126         complete(&slave->probe_complete);
127
128         dev_dbg(dev, "probe complete\n");
129
130         return 0;
131 }
132
133 static int sdw_drv_remove(struct device *dev)
134 {
135         struct sdw_slave *slave = dev_to_sdw_dev(dev);
136         struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
137         int ret = 0;
138
139         if (drv->remove)
140                 ret = drv->remove(slave);
141
142         dev_pm_domain_detach(dev, false);
143
144         return ret;
145 }
146
147 static void sdw_drv_shutdown(struct device *dev)
148 {
149         struct sdw_slave *slave = dev_to_sdw_dev(dev);
150         struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
151
152         if (drv->shutdown)
153                 drv->shutdown(slave);
154 }
155
156 /**
157  * __sdw_register_driver() - register a SoundWire Slave driver
158  * @drv: driver to register
159  * @owner: owning module/driver
160  *
161  * Return: zero on success, else a negative error code.
162  */
163 int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
164 {
165         drv->driver.bus = &sdw_bus_type;
166
167         if (!drv->probe) {
168                 pr_err("driver %s didn't provide SDW probe routine\n",
169                        drv->name);
170                 return -EINVAL;
171         }
172
173         drv->driver.owner = owner;
174         drv->driver.probe = sdw_drv_probe;
175
176         if (drv->remove)
177                 drv->driver.remove = sdw_drv_remove;
178
179         if (drv->shutdown)
180                 drv->driver.shutdown = sdw_drv_shutdown;
181
182         return driver_register(&drv->driver);
183 }
184 EXPORT_SYMBOL_GPL(__sdw_register_driver);
185
186 /**
187  * sdw_unregister_driver() - unregisters the SoundWire Slave driver
188  * @drv: driver to unregister
189  */
190 void sdw_unregister_driver(struct sdw_driver *drv)
191 {
192         driver_unregister(&drv->driver);
193 }
194 EXPORT_SYMBOL_GPL(sdw_unregister_driver);
195
196 static int __init sdw_bus_init(void)
197 {
198         sdw_debugfs_init();
199         return bus_register(&sdw_bus_type);
200 }
201
202 static void __exit sdw_bus_exit(void)
203 {
204         sdw_debugfs_exit();
205         bus_unregister(&sdw_bus_type);
206 }
207
208 postcore_initcall(sdw_bus_init);
209 module_exit(sdw_bus_exit);
210
211 MODULE_DESCRIPTION("SoundWire bus");
212 MODULE_LICENSE("GPL v2");