blob: ed53ae6bd1cc74c885719a442d102de5dba4fa84 [file] [log] [blame]
Sagar Dharia3648e782017-12-11 23:42:57 +00001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2011-2017, The Linux Foundation
4 */
5
6#include <linux/kernel.h>
7#include <linux/errno.h>
8#include <linux/slab.h>
9#include <linux/init.h>
Sagar Dharia46a2bb52017-12-11 23:42:58 +000010#include <linux/idr.h>
Sagar Dharia3648e782017-12-11 23:42:57 +000011#include <linux/slimbus.h>
Sagar Dharia46a2bb52017-12-11 23:42:58 +000012#include "slimbus.h"
13
14static DEFINE_IDA(ctrl_ida);
Sagar Dharia3648e782017-12-11 23:42:57 +000015
16static const struct slim_device_id *slim_match(const struct slim_device_id *id,
17 const struct slim_device *sbdev)
18{
19 while (id->manf_id != 0 || id->prod_code != 0) {
20 if (id->manf_id == sbdev->e_addr.manf_id &&
21 id->prod_code == sbdev->e_addr.prod_code)
22 return id;
23 id++;
24 }
25 return NULL;
26}
27
28static int slim_device_match(struct device *dev, struct device_driver *drv)
29{
30 struct slim_device *sbdev = to_slim_device(dev);
31 struct slim_driver *sbdrv = to_slim_driver(drv);
32
33 return !!slim_match(sbdrv->id_table, sbdev);
34}
35
36static int slim_device_probe(struct device *dev)
37{
38 struct slim_device *sbdev = to_slim_device(dev);
39 struct slim_driver *sbdrv = to_slim_driver(dev->driver);
40
41 return sbdrv->probe(sbdev);
42}
43
44static int slim_device_remove(struct device *dev)
45{
46 struct slim_device *sbdev = to_slim_device(dev);
47 struct slim_driver *sbdrv;
48
49 if (dev->driver) {
50 sbdrv = to_slim_driver(dev->driver);
51 if (sbdrv->remove)
52 sbdrv->remove(sbdev);
53 }
54
55 return 0;
56}
57
58struct bus_type slimbus_bus = {
59 .name = "slimbus",
60 .match = slim_device_match,
61 .probe = slim_device_probe,
62 .remove = slim_device_remove,
63};
64EXPORT_SYMBOL_GPL(slimbus_bus);
65
66/*
67 * __slim_driver_register() - Client driver registration with SLIMbus
68 *
69 * @drv:Client driver to be associated with client-device.
70 * @owner: owning module/driver
71 *
72 * This API will register the client driver with the SLIMbus
73 * It is called from the driver's module-init function.
74 */
75int __slim_driver_register(struct slim_driver *drv, struct module *owner)
76{
77 /* ID table and probe are mandatory */
78 if (!drv->id_table || !drv->probe)
79 return -EINVAL;
80
81 drv->driver.bus = &slimbus_bus;
82 drv->driver.owner = owner;
83
84 return driver_register(&drv->driver);
85}
86EXPORT_SYMBOL_GPL(__slim_driver_register);
87
88/*
89 * slim_driver_unregister() - Undo effect of slim_driver_register
90 *
91 * @drv: Client driver to be unregistered
92 */
93void slim_driver_unregister(struct slim_driver *drv)
94{
95 driver_unregister(&drv->driver);
96}
97EXPORT_SYMBOL_GPL(slim_driver_unregister);
98
Sagar Dharia46a2bb52017-12-11 23:42:58 +000099static void slim_dev_release(struct device *dev)
100{
101 struct slim_device *sbdev = to_slim_device(dev);
102
103 kfree(sbdev);
104}
105
106static int slim_add_device(struct slim_controller *ctrl,
107 struct slim_device *sbdev,
108 struct device_node *node)
109{
110 sbdev->dev.bus = &slimbus_bus;
111 sbdev->dev.parent = ctrl->dev;
112 sbdev->dev.release = slim_dev_release;
113 sbdev->dev.driver = NULL;
114 sbdev->ctrl = ctrl;
115
116 dev_set_name(&sbdev->dev, "%x:%x:%x:%x",
117 sbdev->e_addr.manf_id,
118 sbdev->e_addr.prod_code,
119 sbdev->e_addr.dev_index,
120 sbdev->e_addr.instance);
121
122 return device_register(&sbdev->dev);
123}
124
125static struct slim_device *slim_alloc_device(struct slim_controller *ctrl,
126 struct slim_eaddr *eaddr,
127 struct device_node *node)
128{
129 struct slim_device *sbdev;
130 int ret;
131
132 sbdev = kzalloc(sizeof(*sbdev), GFP_KERNEL);
133 if (!sbdev)
134 return NULL;
135
136 sbdev->e_addr = *eaddr;
137 ret = slim_add_device(ctrl, sbdev, node);
138 if (ret) {
139 kfree(sbdev);
140 return NULL;
141 }
142
143 return sbdev;
144}
145
146/*
147 * slim_register_controller() - Controller bring-up and registration.
148 *
149 * @ctrl: Controller to be registered.
150 *
151 * A controller is registered with the framework using this API.
152 * If devices on a controller were registered before controller,
153 * this will make sure that they get probed when controller is up
154 */
155int slim_register_controller(struct slim_controller *ctrl)
156{
157 int id;
158
159 id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
160 if (id < 0)
161 return id;
162
163 ctrl->id = id;
164
165 if (!ctrl->min_cg)
166 ctrl->min_cg = SLIM_MIN_CLK_GEAR;
167 if (!ctrl->max_cg)
168 ctrl->max_cg = SLIM_MAX_CLK_GEAR;
169
170 ida_init(&ctrl->laddr_ida);
171 idr_init(&ctrl->tid_idr);
172 mutex_init(&ctrl->lock);
173
174 dev_dbg(ctrl->dev, "Bus [%s] registered:dev:%p\n",
175 ctrl->name, ctrl->dev);
176
177 return 0;
178}
179EXPORT_SYMBOL_GPL(slim_register_controller);
180
181/* slim_remove_device: Remove the effect of slim_add_device() */
182static void slim_remove_device(struct slim_device *sbdev)
183{
184 device_unregister(&sbdev->dev);
185}
186
187static int slim_ctrl_remove_device(struct device *dev, void *null)
188{
189 slim_remove_device(to_slim_device(dev));
190 return 0;
191}
192
193/**
194 * slim_unregister_controller() - Controller tear-down.
195 *
196 * @ctrl: Controller to tear-down.
197 */
198int slim_unregister_controller(struct slim_controller *ctrl)
199{
200 /* Remove all clients */
201 device_for_each_child(ctrl->dev, NULL, slim_ctrl_remove_device);
202 ida_simple_remove(&ctrl_ida, ctrl->id);
203
204 return 0;
205}
206EXPORT_SYMBOL_GPL(slim_unregister_controller);
207
208static void slim_device_update_status(struct slim_device *sbdev,
209 enum slim_device_status status)
210{
211 struct slim_driver *sbdrv;
212
213 if (sbdev->status == status)
214 return;
215
216 sbdev->status = status;
217 if (!sbdev->dev.driver)
218 return;
219
220 sbdrv = to_slim_driver(sbdev->dev.driver);
221 if (sbdrv->device_status)
222 sbdrv->device_status(sbdev, sbdev->status);
223}
224
225/**
226 * slim_report_absent() - Controller calls this function when a device
227 * reports absent, OR when the device cannot be communicated with
228 *
229 * @sbdev: Device that cannot be reached, or sent report absent
230 */
231void slim_report_absent(struct slim_device *sbdev)
232{
233 struct slim_controller *ctrl = sbdev->ctrl;
234
235 if (!ctrl)
236 return;
237
238 /* invalidate logical addresses */
239 mutex_lock(&ctrl->lock);
240 sbdev->is_laddr_valid = false;
241 mutex_unlock(&ctrl->lock);
242
243 ida_simple_remove(&ctrl->laddr_ida, sbdev->laddr);
244 slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_DOWN);
245}
246EXPORT_SYMBOL_GPL(slim_report_absent);
247
248static bool slim_eaddr_equal(struct slim_eaddr *a, struct slim_eaddr *b)
249{
250 return (a->manf_id == b->manf_id &&
251 a->prod_code == b->prod_code &&
252 a->dev_index == b->dev_index &&
253 a->instance == b->instance);
254}
255
256static int slim_match_dev(struct device *dev, void *data)
257{
258 struct slim_eaddr *e_addr = data;
259 struct slim_device *sbdev = to_slim_device(dev);
260
261 return slim_eaddr_equal(&sbdev->e_addr, e_addr);
262}
263
264static struct slim_device *find_slim_device(struct slim_controller *ctrl,
265 struct slim_eaddr *eaddr)
266{
267 struct slim_device *sbdev;
268 struct device *dev;
269
270 dev = device_find_child(ctrl->dev, eaddr, slim_match_dev);
271 if (dev) {
272 sbdev = to_slim_device(dev);
273 return sbdev;
274 }
275
276 return NULL;
277}
278
279/**
280 * slim_get_device() - get handle to a device.
281 *
282 * @ctrl: Controller on which this device will be added/queried
283 * @e_addr: Enumeration address of the device to be queried
284 *
285 * Return: pointer to a device if it has already reported. Creates a new
286 * device and returns pointer to it if the device has not yet enumerated.
287 */
288struct slim_device *slim_get_device(struct slim_controller *ctrl,
289 struct slim_eaddr *e_addr)
290{
291 struct slim_device *sbdev;
292
293 sbdev = find_slim_device(ctrl, e_addr);
294 if (!sbdev) {
295 sbdev = slim_alloc_device(ctrl, e_addr, NULL);
296 if (!sbdev)
297 return ERR_PTR(-ENOMEM);
298 }
299
300 return sbdev;
301}
302EXPORT_SYMBOL_GPL(slim_get_device);
303
304static int slim_device_alloc_laddr(struct slim_device *sbdev,
305 bool report_present)
306{
307 struct slim_controller *ctrl = sbdev->ctrl;
308 u8 laddr;
309 int ret;
310
311 mutex_lock(&ctrl->lock);
312 if (ctrl->get_laddr) {
313 ret = ctrl->get_laddr(ctrl, &sbdev->e_addr, &laddr);
314 if (ret < 0)
315 goto err;
316 } else if (report_present) {
317 ret = ida_simple_get(&ctrl->laddr_ida,
318 0, SLIM_LA_MANAGER - 1, GFP_KERNEL);
319 if (ret < 0)
320 goto err;
321
322 laddr = ret;
323 } else {
324 ret = -EINVAL;
325 goto err;
326 }
327
328 if (ctrl->set_laddr) {
329 ret = ctrl->set_laddr(ctrl, &sbdev->e_addr, laddr);
330 if (ret) {
331 ret = -EINVAL;
332 goto err;
333 }
334 }
335
336 sbdev->laddr = laddr;
337 sbdev->is_laddr_valid = true;
338
339 slim_device_update_status(sbdev, SLIM_DEVICE_STATUS_UP);
340
341 dev_dbg(ctrl->dev, "setting slimbus l-addr:%x, ea:%x,%x,%x,%x\n",
342 laddr, sbdev->e_addr.manf_id, sbdev->e_addr.prod_code,
343 sbdev->e_addr.dev_index, sbdev->e_addr.instance);
344
345err:
346 mutex_unlock(&ctrl->lock);
347 return ret;
348
349}
350
351/**
352 * slim_device_report_present() - Report enumerated device.
353 *
354 * @ctrl: Controller with which device is enumerated.
355 * @e_addr: Enumeration address of the device.
356 * @laddr: Return logical address (if valid flag is false)
357 *
358 * Called by controller in response to REPORT_PRESENT. Framework will assign
359 * a logical address to this enumeration address.
360 * Function returns -EXFULL to indicate that all logical addresses are already
361 * taken.
362 */
363int slim_device_report_present(struct slim_controller *ctrl,
364 struct slim_eaddr *e_addr, u8 *laddr)
365{
366 struct slim_device *sbdev;
367 int ret;
368
369 sbdev = slim_get_device(ctrl, e_addr);
370 if (IS_ERR(sbdev))
371 return -ENODEV;
372
373 if (sbdev->is_laddr_valid) {
374 *laddr = sbdev->laddr;
375 return 0;
376 }
377
378 ret = slim_device_alloc_laddr(sbdev, true);
379
380 return ret;
381}
382EXPORT_SYMBOL_GPL(slim_device_report_present);
383
384/**
385 * slim_get_logical_addr() - get/allocate logical address of a SLIMbus device.
386 *
387 * @sbdev: client handle requesting the address.
388 *
389 * Return: zero if a logical address is valid or a new logical address
390 * has been assigned. error code in case of error.
391 */
392int slim_get_logical_addr(struct slim_device *sbdev)
393{
394 if (!sbdev->is_laddr_valid)
395 return slim_device_alloc_laddr(sbdev, false);
396
397 return 0;
398}
399EXPORT_SYMBOL_GPL(slim_get_logical_addr);
400
Sagar Dharia3648e782017-12-11 23:42:57 +0000401static void __exit slimbus_exit(void)
402{
403 bus_unregister(&slimbus_bus);
404}
405module_exit(slimbus_exit);
406
407static int __init slimbus_init(void)
408{
409 return bus_register(&slimbus_bus);
410}
411postcore_initcall(slimbus_init);
412
413MODULE_LICENSE("GPL v2");
414MODULE_DESCRIPTION("SLIMbus core");