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
, const struct device_driver
*drv
)
33 const 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(const struct device
*dev
, struct kobj_uevent_env
*env
)
46 const 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
);
82 static void mcb_remove(struct device
*dev
)
84 struct mcb_driver
*mdrv
= to_mcb_driver(dev
->driver
);
85 struct mcb_device
*mdev
= to_mcb_device(dev
);
86 struct module
*carrier_mod
;
90 carrier_mod
= mdev
->dev
.parent
->driver
->owner
;
91 module_put(carrier_mod
);
93 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 const struct bus_type mcb_bus_type
= {
162 .uevent
= mcb_uevent
,
164 .remove
= mcb_remove
,
165 .shutdown
= mcb_shutdown
,
168 static const 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
);
249 put_device(&dev
->dev
);
253 EXPORT_SYMBOL_NS_GPL(mcb_device_register
, "MCB");
255 static void mcb_free_bus(struct device
*dev
)
257 struct mcb_bus
*bus
= to_mcb_bus(dev
);
259 put_device(bus
->carrier
);
260 ida_free(&mcb_ida
, bus
->bus_nr
);
265 * mcb_alloc_bus() - Allocate a new @mcb_bus
266 * @carrier: generic &struct device for the carrier device
268 * Allocate a new @mcb_bus.
270 struct mcb_bus
*mcb_alloc_bus(struct device
*carrier
)
276 bus
= kzalloc(sizeof(struct mcb_bus
), GFP_KERNEL
);
278 return ERR_PTR(-ENOMEM
);
280 bus_nr
= ida_alloc(&mcb_ida
, GFP_KERNEL
);
283 return ERR_PTR(bus_nr
);
286 bus
->bus_nr
= bus_nr
;
287 bus
->carrier
= get_device(carrier
);
289 device_initialize(&bus
->dev
);
290 bus
->dev
.parent
= carrier
;
291 bus
->dev
.bus
= &mcb_bus_type
;
292 bus
->dev
.type
= &mcb_carrier_device_type
;
293 bus
->dev
.release
= mcb_free_bus
;
295 dev_set_name(&bus
->dev
, "mcb:%d", bus_nr
);
296 rc
= device_add(&bus
->dev
);
303 put_device(&bus
->dev
);
306 EXPORT_SYMBOL_NS_GPL(mcb_alloc_bus
, "MCB");
308 static int __mcb_devices_unregister(struct device
*dev
, void *data
)
310 device_unregister(dev
);
314 static void mcb_devices_unregister(struct mcb_bus
*bus
)
316 bus_for_each_dev(bus
->dev
.bus
, NULL
, NULL
, __mcb_devices_unregister
);
319 * mcb_release_bus() - Free a @mcb_bus
320 * @bus: The @mcb_bus to release
322 * Release an allocated @mcb_bus from the system.
324 void mcb_release_bus(struct mcb_bus
*bus
)
326 mcb_devices_unregister(bus
);
328 EXPORT_SYMBOL_NS_GPL(mcb_release_bus
, "MCB");
331 * mcb_bus_get() - Increment refcnt
334 * Get a @mcb_bus' ref
336 struct mcb_bus
*mcb_bus_get(struct mcb_bus
*bus
)
339 get_device(&bus
->dev
);
343 EXPORT_SYMBOL_NS_GPL(mcb_bus_get
, "MCB");
346 * mcb_bus_put() - Decrement refcnt
349 * Release a @mcb_bus' ref
351 void mcb_bus_put(struct mcb_bus
*bus
)
354 put_device(&bus
->dev
);
356 EXPORT_SYMBOL_NS_GPL(mcb_bus_put
, "MCB");
359 * mcb_alloc_dev() - Allocate a device
360 * @bus: The @mcb_bus the device is part of
362 * Allocate a @mcb_device and add bus.
364 struct mcb_device
*mcb_alloc_dev(struct mcb_bus
*bus
)
366 struct mcb_device
*dev
;
368 dev
= kzalloc(sizeof(struct mcb_device
), GFP_KERNEL
);
376 EXPORT_SYMBOL_NS_GPL(mcb_alloc_dev
, "MCB");
379 * mcb_free_dev() - Free @mcb_device
380 * @dev: The device to free
384 void mcb_free_dev(struct mcb_device
*dev
)
388 EXPORT_SYMBOL_NS_GPL(mcb_free_dev
, "MCB");
390 static int __mcb_bus_add_devices(struct device
*dev
, void *data
)
394 retval
= device_attach(dev
);
396 dev_err(dev
, "Error adding device (%d)\n", retval
);
404 * mcb_bus_add_devices() - Add devices in the bus' internal device list
405 * @bus: The @mcb_bus we add the devices
407 * Add devices in the bus' internal device list to the system.
409 void mcb_bus_add_devices(const struct mcb_bus
*bus
)
411 bus_for_each_dev(bus
->dev
.bus
, NULL
, NULL
, __mcb_bus_add_devices
);
413 EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices
, "MCB");
416 * mcb_get_resource() - get a resource for a mcb device
417 * @dev: the mcb device
418 * @type: the type of resource
420 struct resource
*mcb_get_resource(struct mcb_device
*dev
, unsigned int type
)
422 if (type
== IORESOURCE_MEM
)
424 else if (type
== IORESOURCE_IRQ
)
429 EXPORT_SYMBOL_NS_GPL(mcb_get_resource
, "MCB");
432 * mcb_request_mem() - Request memory
433 * @dev: The @mcb_device the memory is for
434 * @name: The name for the memory reference.
436 * Request memory for a @mcb_device. If @name is NULL the driver name will
439 struct resource
*mcb_request_mem(struct mcb_device
*dev
, const char *name
)
441 struct resource
*mem
;
445 name
= dev
->dev
.driver
->name
;
447 size
= resource_size(&dev
->mem
);
449 mem
= request_mem_region(dev
->mem
.start
, size
, name
);
451 return ERR_PTR(-EBUSY
);
455 EXPORT_SYMBOL_NS_GPL(mcb_request_mem
, "MCB");
458 * mcb_release_mem() - Release memory requested by device
459 * @mem: The memory resource to be released
461 * Release memory that was prior requested via @mcb_request_mem().
463 void mcb_release_mem(struct resource
*mem
)
467 size
= resource_size(mem
);
468 release_mem_region(mem
->start
, size
);
470 EXPORT_SYMBOL_NS_GPL(mcb_release_mem
, "MCB");
472 static int __mcb_get_irq(struct mcb_device
*dev
)
474 struct resource
*irq
;
476 irq
= mcb_get_resource(dev
, IORESOURCE_IRQ
);
482 * mcb_get_irq() - Get device's IRQ number
483 * @dev: The @mcb_device the IRQ is for
485 * Get the IRQ number of a given @mcb_device.
487 int mcb_get_irq(struct mcb_device
*dev
)
489 struct mcb_bus
*bus
= dev
->bus
;
492 return bus
->get_irq(dev
);
494 return __mcb_get_irq(dev
);
496 EXPORT_SYMBOL_NS_GPL(mcb_get_irq
, "MCB");
498 static int mcb_init(void)
500 return bus_register(&mcb_bus_type
);
503 static void mcb_exit(void)
505 ida_destroy(&mcb_ida
);
506 bus_unregister(&mcb_bus_type
);
509 /* mcb must be initialized after PCI but before the chameleon drivers.
510 * That means we must use some initcall between subsys_initcall and
513 fs_initcall(mcb_init
);
514 module_exit(mcb_exit
);
516 MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
517 MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
518 MODULE_LICENSE("GPL v2");