Skip to content

Commit 46a2bb5

Browse files
Sagar Dhariagregkh
Sagar Dharia
authored andcommitted
slimbus: core: Add slim controllers support
This patch adds support to slim controllers in the slim core, including some utility functions invoked by the controller and slim device drivers. Signed-off-by: Srinivas Kandagatla <[email protected]> Reviwed-by: Mark Brown <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3648e78 commit 46a2bb5

File tree

3 files changed

+422
-0
lines changed

3 files changed

+422
-0
lines changed

drivers/slimbus/core.c

+306
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
#include <linux/errno.h>
88
#include <linux/slab.h>
99
#include <linux/init.h>
10+
#include <linux/idr.h>
1011
#include <linux/slimbus.h>
12+
#include "slimbus.h"
13+
14+
static DEFINE_IDA(ctrl_ida);
1115

1216
static const struct slim_device_id *slim_match(const struct slim_device_id *id,
1317
const struct slim_device *sbdev)
@@ -92,6 +96,308 @@ void slim_driver_unregister(struct slim_driver *drv)
9296
}
9397
EXPORT_SYMBOL_GPL(slim_driver_unregister);
9498

99+
static void slim_dev_release(struct device *dev)
100+
{
101+
struct slim_device *sbdev = to_slim_device(dev);
102+
103+
kfree(sbdev);
104+
}
105+
106+
static 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+
125+
static 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+
*/
155+
int 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+
}
179+
EXPORT_SYMBOL_GPL(slim_register_controller);
180+
181+
/* slim_remove_device: Remove the effect of slim_add_device() */
182+
static void slim_remove_device(struct slim_device *sbdev)
183+
{
184+
device_unregister(&sbdev->dev);
185+
}
186+
187+
static 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+
*/
198+
int 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+
}
206+
EXPORT_SYMBOL_GPL(slim_unregister_controller);
207+
208+
static 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+
*/
231+
void 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+
}
246+
EXPORT_SYMBOL_GPL(slim_report_absent);
247+
248+
static 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+
256+
static 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+
264+
static 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+
*/
288+
struct 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+
}
302+
EXPORT_SYMBOL_GPL(slim_get_device);
303+
304+
static 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+
345+
err:
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+
*/
363+
int 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+
}
382+
EXPORT_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+
*/
392+
int 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+
}
399+
EXPORT_SYMBOL_GPL(slim_get_logical_addr);
400+
95401
static void __exit slimbus_exit(void)
96402
{
97403
bus_unregister(&slimbus_bus);

0 commit comments

Comments
 (0)