1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
6 * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/types.h>
12 #include <linux/idr.h>
13 #include <linux/mcb.h>
15 static DEFINE_IDA(mcb_ida
);
17 static const struct mcb_device_id
*mcb_match_id(const struct mcb_device_id
*ids
,
18 struct mcb_device
*dev
)
22 if (ids
->device
== dev
->id
)
31 static int mcb_match(struct device
*dev
, struct device_driver
*drv
)
33 struct mcb_driver
*mdrv
= to_mcb_driver(drv
);
34 struct mcb_device
*mdev
= to_mcb_device(dev
);
35 const struct mcb_device_id
*found_id
;
37 found_id
= mcb_match_id(mdrv
->id_table
, mdev
);
44 static int mcb_uevent(struct device
*dev
, struct kobj_uevent_env
*env
)
46 struct mcb_device
*mdev
= to_mcb_device(dev
);
49 ret
= add_uevent_var(env
, "MODALIAS=mcb:16z%03d", mdev
->id
);
56 static int mcb_probe(struct device
*dev
)
58 struct mcb_driver
*mdrv
= to_mcb_driver(dev
->driver
);
59 struct mcb_device
*mdev
= to_mcb_device(dev
);
60 const struct mcb_device_id
*found_id
;
61 struct module
*carrier_mod
;
64 found_id
= mcb_match_id(mdrv
->id_table
, mdev
);
68 carrier_mod
= mdev
->dev
.parent
->driver
->owner
;
69 if (!try_module_get(carrier_mod
))
73 ret
= mdrv
->probe(mdev
, found_id
);
75 module_put(carrier_mod
);
80 static int mcb_remove(struct device
*dev
)
82 struct mcb_driver
*mdrv
= to_mcb_driver(dev
->driver
);
83 struct mcb_device
*mdev
= to_mcb_device(dev
);
84 struct module
*carrier_mod
;
88 carrier_mod
= mdev
->dev
.parent
->driver
->owner
;
89 module_put(carrier_mod
);
91 put_device(&mdev
->dev
);
96 static void mcb_shutdown(struct device
*dev
)
98 struct mcb_driver
*mdrv
= to_mcb_driver(dev
->driver
);
99 struct mcb_device
*mdev
= to_mcb_device(dev
);
101 if (mdrv
&& mdrv
->shutdown
)
102 mdrv
->shutdown(mdev
);
105 static ssize_t
revision_show(struct device
*dev
, struct device_attribute
*attr
,
108 struct mcb_bus
*bus
= to_mcb_bus(dev
);
110 return scnprintf(buf
, PAGE_SIZE
, "%d\n", bus
->revision
);
112 static DEVICE_ATTR_RO(revision
);
114 static ssize_t
model_show(struct device
*dev
, struct device_attribute
*attr
,
117 struct mcb_bus
*bus
= to_mcb_bus(dev
);
119 return scnprintf(buf
, PAGE_SIZE
, "%c\n", bus
->model
);
121 static DEVICE_ATTR_RO(model
);
123 static ssize_t
minor_show(struct device
*dev
, struct device_attribute
*attr
,
126 struct mcb_bus
*bus
= to_mcb_bus(dev
);
128 return scnprintf(buf
, PAGE_SIZE
, "%d\n", bus
->minor
);
130 static DEVICE_ATTR_RO(minor
);
132 static ssize_t
name_show(struct device
*dev
, struct device_attribute
*attr
,
135 struct mcb_bus
*bus
= to_mcb_bus(dev
);
137 return scnprintf(buf
, PAGE_SIZE
, "%s\n", bus
->name
);
139 static DEVICE_ATTR_RO(name
);
141 static struct attribute
*mcb_bus_attrs
[] = {
142 &dev_attr_revision
.attr
,
143 &dev_attr_model
.attr
,
144 &dev_attr_minor
.attr
,
149 static const struct attribute_group mcb_carrier_group
= {
150 .attrs
= mcb_bus_attrs
,
153 static const struct attribute_group
*mcb_carrier_groups
[] = {
159 static struct bus_type mcb_bus_type
= {
162 .uevent
= mcb_uevent
,
164 .remove
= mcb_remove
,
165 .shutdown
= mcb_shutdown
,
168 static struct device_type mcb_carrier_device_type
= {
169 .name
= "mcb-carrier",
170 .groups
= mcb_carrier_groups
,
174 * __mcb_register_driver() - Register a @mcb_driver at the system
175 * @drv: The @mcb_driver
176 * @owner: The @mcb_driver's module
177 * @mod_name: The name of the @mcb_driver's module
179 * Register a @mcb_driver at the system. Perform some sanity checks, if
180 * the .probe and .remove methods are provided by the driver.
182 int __mcb_register_driver(struct mcb_driver
*drv
, struct module
*owner
,
183 const char *mod_name
)
185 if (!drv
->probe
|| !drv
->remove
)
188 drv
->driver
.owner
= owner
;
189 drv
->driver
.bus
= &mcb_bus_type
;
190 drv
->driver
.mod_name
= mod_name
;
192 return driver_register(&drv
->driver
);
194 EXPORT_SYMBOL_NS_GPL(__mcb_register_driver
, MCB
);
197 * mcb_unregister_driver() - Unregister a @mcb_driver from the system
198 * @drv: The @mcb_driver
200 * Unregister a @mcb_driver from the system.
202 void mcb_unregister_driver(struct mcb_driver
*drv
)
204 driver_unregister(&drv
->driver
);
206 EXPORT_SYMBOL_NS_GPL(mcb_unregister_driver
, MCB
);
208 static void mcb_release_dev(struct device
*dev
)
210 struct mcb_device
*mdev
= to_mcb_device(dev
);
212 mcb_bus_put(mdev
->bus
);
217 * mcb_device_register() - Register a mcb_device
218 * @bus: The @mcb_bus of the device
219 * @dev: The @mcb_device
221 * Register a specific @mcb_device at a @mcb_bus and the system itself.
223 int mcb_device_register(struct mcb_bus
*bus
, struct mcb_device
*dev
)
228 device_initialize(&dev
->dev
);
230 dev
->dev
.bus
= &mcb_bus_type
;
231 dev
->dev
.parent
= bus
->dev
.parent
;
232 dev
->dev
.release
= mcb_release_dev
;
233 dev
->dma_dev
= bus
->carrier
;
236 dev_set_name(&dev
->dev
, "mcb%d-16z%03d-%d:%d:%d",
237 bus
->bus_nr
, device_id
, dev
->inst
, dev
->group
, dev
->var
);
239 ret
= device_add(&dev
->dev
);
241 pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
242 device_id
, bus
->bus_nr
, ret
);
252 EXPORT_SYMBOL_NS_GPL(mcb_device_register
, MCB
);
254 static void mcb_free_bus(struct device
*dev
)
256 struct mcb_bus
*bus
= to_mcb_bus(dev
);
258 put_device(bus
->carrier
);
259 ida_simple_remove(&mcb_ida
, bus
->bus_nr
);
264 * mcb_alloc_bus() - Allocate a new @mcb_bus
266 * Allocate a new @mcb_bus.
268 struct mcb_bus
*mcb_alloc_bus(struct device
*carrier
)
274 bus
= kzalloc(sizeof(struct mcb_bus
), GFP_KERNEL
);
276 return ERR_PTR(-ENOMEM
);
278 bus_nr
= ida_simple_get(&mcb_ida
, 0, 0, GFP_KERNEL
);
284 bus
->bus_nr
= bus_nr
;
285 bus
->carrier
= get_device(carrier
);
287 device_initialize(&bus
->dev
);
288 bus
->dev
.parent
= carrier
;
289 bus
->dev
.bus
= &mcb_bus_type
;
290 bus
->dev
.type
= &mcb_carrier_device_type
;
291 bus
->dev
.release
= &mcb_free_bus
;
293 dev_set_name(&bus
->dev
, "mcb:%d", bus_nr
);
294 rc
= device_add(&bus
->dev
);
304 EXPORT_SYMBOL_NS_GPL(mcb_alloc_bus
, MCB
);
306 static int __mcb_devices_unregister(struct device
*dev
, void *data
)
308 device_unregister(dev
);
312 static void mcb_devices_unregister(struct mcb_bus
*bus
)
314 bus_for_each_dev(&mcb_bus_type
, NULL
, NULL
, __mcb_devices_unregister
);
317 * mcb_release_bus() - Free a @mcb_bus
318 * @bus: The @mcb_bus to release
320 * Release an allocated @mcb_bus from the system.
322 void mcb_release_bus(struct mcb_bus
*bus
)
324 mcb_devices_unregister(bus
);
326 EXPORT_SYMBOL_NS_GPL(mcb_release_bus
, MCB
);
329 * mcb_bus_put() - Increment refcnt
332 * Get a @mcb_bus' ref
334 struct mcb_bus
*mcb_bus_get(struct mcb_bus
*bus
)
337 get_device(&bus
->dev
);
341 EXPORT_SYMBOL_NS_GPL(mcb_bus_get
, MCB
);
344 * mcb_bus_put() - Decrement refcnt
347 * Release a @mcb_bus' ref
349 void mcb_bus_put(struct mcb_bus
*bus
)
352 put_device(&bus
->dev
);
354 EXPORT_SYMBOL_NS_GPL(mcb_bus_put
, MCB
);
357 * mcb_alloc_dev() - Allocate a device
358 * @bus: The @mcb_bus the device is part of
360 * Allocate a @mcb_device and add bus.
362 struct mcb_device
*mcb_alloc_dev(struct mcb_bus
*bus
)
364 struct mcb_device
*dev
;
366 dev
= kzalloc(sizeof(struct mcb_device
), GFP_KERNEL
);
374 EXPORT_SYMBOL_NS_GPL(mcb_alloc_dev
, MCB
);
377 * mcb_free_dev() - Free @mcb_device
378 * @dev: The device to free
382 void mcb_free_dev(struct mcb_device
*dev
)
386 EXPORT_SYMBOL_NS_GPL(mcb_free_dev
, MCB
);
388 static int __mcb_bus_add_devices(struct device
*dev
, void *data
)
390 struct mcb_device
*mdev
= to_mcb_device(dev
);
396 retval
= device_attach(dev
);
398 dev_err(dev
, "Error adding device (%d)\n", retval
);
400 mdev
->is_added
= true;
406 * mcb_bus_add_devices() - Add devices in the bus' internal device list
407 * @bus: The @mcb_bus we add the devices
409 * Add devices in the bus' internal device list to the system.
411 void mcb_bus_add_devices(const struct mcb_bus
*bus
)
413 bus_for_each_dev(&mcb_bus_type
, NULL
, NULL
, __mcb_bus_add_devices
);
415 EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices
, MCB
);
418 * mcb_get_resource() - get a resource for a mcb device
419 * @dev: the mcb device
420 * @type: the type of resource
422 struct resource
*mcb_get_resource(struct mcb_device
*dev
, unsigned int type
)
424 if (type
== IORESOURCE_MEM
)
426 else if (type
== IORESOURCE_IRQ
)
431 EXPORT_SYMBOL_NS_GPL(mcb_get_resource
, MCB
);
434 * mcb_request_mem() - Request memory
435 * @dev: The @mcb_device the memory is for
436 * @name: The name for the memory reference.
438 * Request memory for a @mcb_device. If @name is NULL the driver name will
441 struct resource
*mcb_request_mem(struct mcb_device
*dev
, const char *name
)
443 struct resource
*mem
;
447 name
= dev
->dev
.driver
->name
;
449 size
= resource_size(&dev
->mem
);
451 mem
= request_mem_region(dev
->mem
.start
, size
, name
);
453 return ERR_PTR(-EBUSY
);
457 EXPORT_SYMBOL_NS_GPL(mcb_request_mem
, MCB
);
460 * mcb_release_mem() - Release memory requested by device
461 * @dev: The @mcb_device that requested the memory
463 * Release memory that was prior requested via @mcb_request_mem().
465 void mcb_release_mem(struct resource
*mem
)
469 size
= resource_size(mem
);
470 release_mem_region(mem
->start
, size
);
472 EXPORT_SYMBOL_NS_GPL(mcb_release_mem
, MCB
);
474 static int __mcb_get_irq(struct mcb_device
*dev
)
476 struct resource
*irq
;
478 irq
= mcb_get_resource(dev
, IORESOURCE_IRQ
);
484 * mcb_get_irq() - Get device's IRQ number
485 * @dev: The @mcb_device the IRQ is for
487 * Get the IRQ number of a given @mcb_device.
489 int mcb_get_irq(struct mcb_device
*dev
)
491 struct mcb_bus
*bus
= dev
->bus
;
494 return bus
->get_irq(dev
);
496 return __mcb_get_irq(dev
);
498 EXPORT_SYMBOL_NS_GPL(mcb_get_irq
, MCB
);
500 static int mcb_init(void)
502 return bus_register(&mcb_bus_type
);
505 static void mcb_exit(void)
507 ida_destroy(&mcb_ida
);
508 bus_unregister(&mcb_bus_type
);
511 /* mcb must be initialized after PCI but before the chameleon drivers.
512 * That means we must use some initcall between subsys_initcall and
515 fs_initcall(mcb_init
);
516 module_exit(mcb_exit
);
518 MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
519 MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
520 MODULE_LICENSE("GPL v2");