162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * IBM PowerPC IBM eBus Infrastructure Support. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2005 IBM Corporation 562306a36Sopenharmony_ci * Joachim Fenkes <fenkes@de.ibm.com> 662306a36Sopenharmony_ci * Heiko J Schick <schickhj@de.ibm.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * All rights reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This source code is distributed under a dual license of GPL v2.0 and OpenIB 1162306a36Sopenharmony_ci * BSD. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * OpenIB BSD License 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1662306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Redistributions of source code must retain the above copyright notice, this 1962306a36Sopenharmony_ci * list of conditions and the following disclaimer. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Redistributions in binary form must reproduce the above copyright notice, 2262306a36Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 2362306a36Sopenharmony_ci * and/or other materials 2462306a36Sopenharmony_ci * provided with the distribution. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2762306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2862306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2962306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 3062306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3162306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3262306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3362306a36Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 3462306a36Sopenharmony_ci * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3562306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3662306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/init.h> 4062306a36Sopenharmony_ci#include <linux/export.h> 4162306a36Sopenharmony_ci#include <linux/console.h> 4262306a36Sopenharmony_ci#include <linux/kobject.h> 4362306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 4462306a36Sopenharmony_ci#include <linux/interrupt.h> 4562306a36Sopenharmony_ci#include <linux/irqdomain.h> 4662306a36Sopenharmony_ci#include <linux/of.h> 4762306a36Sopenharmony_ci#include <linux/slab.h> 4862306a36Sopenharmony_ci#include <linux/stat.h> 4962306a36Sopenharmony_ci#include <linux/of_platform.h> 5062306a36Sopenharmony_ci#include <linux/platform_device.h> 5162306a36Sopenharmony_ci#include <asm/ibmebus.h> 5262306a36Sopenharmony_ci#include <asm/machdep.h> 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct device ibmebus_bus_device = { /* fake "parent" device */ 5562306a36Sopenharmony_ci .init_name = "ibmebus", 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct bus_type ibmebus_bus_type; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* These devices will automatically be added to the bus during init */ 6162306a36Sopenharmony_cistatic const struct of_device_id ibmebus_matches[] __initconst = { 6262306a36Sopenharmony_ci { .compatible = "IBM,lhca" }, 6362306a36Sopenharmony_ci { .compatible = "IBM,lhea" }, 6462306a36Sopenharmony_ci {}, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void *ibmebus_alloc_coherent(struct device *dev, 6862306a36Sopenharmony_ci size_t size, 6962306a36Sopenharmony_ci dma_addr_t *dma_handle, 7062306a36Sopenharmony_ci gfp_t flag, 7162306a36Sopenharmony_ci unsigned long attrs) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci void *mem; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci mem = kmalloc(size, flag); 7662306a36Sopenharmony_ci *dma_handle = (dma_addr_t)mem; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return mem; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void ibmebus_free_coherent(struct device *dev, 8262306a36Sopenharmony_ci size_t size, void *vaddr, 8362306a36Sopenharmony_ci dma_addr_t dma_handle, 8462306a36Sopenharmony_ci unsigned long attrs) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci kfree(vaddr); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic dma_addr_t ibmebus_map_page(struct device *dev, 9062306a36Sopenharmony_ci struct page *page, 9162306a36Sopenharmony_ci unsigned long offset, 9262306a36Sopenharmony_ci size_t size, 9362306a36Sopenharmony_ci enum dma_data_direction direction, 9462306a36Sopenharmony_ci unsigned long attrs) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci return (dma_addr_t)(page_address(page) + offset); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void ibmebus_unmap_page(struct device *dev, 10062306a36Sopenharmony_ci dma_addr_t dma_addr, 10162306a36Sopenharmony_ci size_t size, 10262306a36Sopenharmony_ci enum dma_data_direction direction, 10362306a36Sopenharmony_ci unsigned long attrs) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int ibmebus_map_sg(struct device *dev, 10962306a36Sopenharmony_ci struct scatterlist *sgl, 11062306a36Sopenharmony_ci int nents, enum dma_data_direction direction, 11162306a36Sopenharmony_ci unsigned long attrs) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct scatterlist *sg; 11462306a36Sopenharmony_ci int i; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci for_each_sg(sgl, sg, nents, i) { 11762306a36Sopenharmony_ci sg->dma_address = (dma_addr_t) sg_virt(sg); 11862306a36Sopenharmony_ci sg->dma_length = sg->length; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return nents; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void ibmebus_unmap_sg(struct device *dev, 12562306a36Sopenharmony_ci struct scatterlist *sg, 12662306a36Sopenharmony_ci int nents, enum dma_data_direction direction, 12762306a36Sopenharmony_ci unsigned long attrs) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int ibmebus_dma_supported(struct device *dev, u64 mask) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return mask == DMA_BIT_MASK(64); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic u64 ibmebus_dma_get_required_mask(struct device *dev) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return DMA_BIT_MASK(64); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic const struct dma_map_ops ibmebus_dma_ops = { 14362306a36Sopenharmony_ci .alloc = ibmebus_alloc_coherent, 14462306a36Sopenharmony_ci .free = ibmebus_free_coherent, 14562306a36Sopenharmony_ci .map_sg = ibmebus_map_sg, 14662306a36Sopenharmony_ci .unmap_sg = ibmebus_unmap_sg, 14762306a36Sopenharmony_ci .dma_supported = ibmebus_dma_supported, 14862306a36Sopenharmony_ci .get_required_mask = ibmebus_dma_get_required_mask, 14962306a36Sopenharmony_ci .map_page = ibmebus_map_page, 15062306a36Sopenharmony_ci .unmap_page = ibmebus_unmap_page, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int ibmebus_match_path(struct device *dev, const void *data) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct device_node *dn = to_platform_device(dev)->dev.of_node; 15662306a36Sopenharmony_ci struct device_node *tn = of_find_node_by_path(data); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci of_node_put(tn); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return (tn == dn); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int ibmebus_match_node(struct device *dev, const void *data) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci return to_platform_device(dev)->dev.of_node == data; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int ibmebus_create_device(struct device_node *dn) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct platform_device *dev; 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dev = of_device_alloc(dn, NULL, &ibmebus_bus_device); 17462306a36Sopenharmony_ci if (!dev) 17562306a36Sopenharmony_ci return -ENOMEM; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci dev->dev.bus = &ibmebus_bus_type; 17862306a36Sopenharmony_ci dev->dev.dma_ops = &ibmebus_dma_ops; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = of_device_add(dev); 18162306a36Sopenharmony_ci if (ret) 18262306a36Sopenharmony_ci platform_device_put(dev); 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int ibmebus_create_devices(const struct of_device_id *matches) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct device_node *root, *child; 18962306a36Sopenharmony_ci struct device *dev; 19062306a36Sopenharmony_ci int ret = 0; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci root = of_find_node_by_path("/"); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci for_each_child_of_node(root, child) { 19562306a36Sopenharmony_ci if (!of_match_node(matches, child)) 19662306a36Sopenharmony_ci continue; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci dev = bus_find_device(&ibmebus_bus_type, NULL, child, 19962306a36Sopenharmony_ci ibmebus_match_node); 20062306a36Sopenharmony_ci if (dev) { 20162306a36Sopenharmony_ci put_device(dev); 20262306a36Sopenharmony_ci continue; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci ret = ibmebus_create_device(child); 20662306a36Sopenharmony_ci if (ret) { 20762306a36Sopenharmony_ci printk(KERN_ERR "%s: failed to create device (%i)", 20862306a36Sopenharmony_ci __func__, ret); 20962306a36Sopenharmony_ci of_node_put(child); 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci of_node_put(root); 21562306a36Sopenharmony_ci return ret; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint ibmebus_register_driver(struct platform_driver *drv) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci /* If the driver uses devices that ibmebus doesn't know, add them */ 22162306a36Sopenharmony_ci ibmebus_create_devices(drv->driver.of_match_table); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci drv->driver.bus = &ibmebus_bus_type; 22462306a36Sopenharmony_ci return driver_register(&drv->driver); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ciEXPORT_SYMBOL(ibmebus_register_driver); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_civoid ibmebus_unregister_driver(struct platform_driver *drv) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci driver_unregister(&drv->driver); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL(ibmebus_unregister_driver); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciint ibmebus_request_irq(u32 ist, irq_handler_t handler, 23562306a36Sopenharmony_ci unsigned long irq_flags, const char *devname, 23662306a36Sopenharmony_ci void *dev_id) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci unsigned int irq = irq_create_mapping(NULL, ist); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!irq) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return request_irq(irq, handler, irq_flags, devname, dev_id); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ciEXPORT_SYMBOL(ibmebus_request_irq); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_civoid ibmebus_free_irq(u32 ist, void *dev_id) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci unsigned int irq = irq_find_mapping(NULL, ist); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci free_irq(irq, dev_id); 25262306a36Sopenharmony_ci irq_dispose_mapping(irq); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ciEXPORT_SYMBOL(ibmebus_free_irq); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic char *ibmebus_chomp(const char *in, size_t count) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci char *out = kmalloc(count + 1, GFP_KERNEL); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!out) 26162306a36Sopenharmony_ci return NULL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci memcpy(out, in, count); 26462306a36Sopenharmony_ci out[count] = '\0'; 26562306a36Sopenharmony_ci if (out[count - 1] == '\n') 26662306a36Sopenharmony_ci out[count - 1] = '\0'; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return out; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic ssize_t probe_store(const struct bus_type *bus, const char *buf, size_t count) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct device_node *dn = NULL; 27462306a36Sopenharmony_ci struct device *dev; 27562306a36Sopenharmony_ci char *path; 27662306a36Sopenharmony_ci ssize_t rc = 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci path = ibmebus_chomp(buf, count); 27962306a36Sopenharmony_ci if (!path) 28062306a36Sopenharmony_ci return -ENOMEM; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci dev = bus_find_device(&ibmebus_bus_type, NULL, path, 28362306a36Sopenharmony_ci ibmebus_match_path); 28462306a36Sopenharmony_ci if (dev) { 28562306a36Sopenharmony_ci put_device(dev); 28662306a36Sopenharmony_ci printk(KERN_WARNING "%s: %s has already been probed\n", 28762306a36Sopenharmony_ci __func__, path); 28862306a36Sopenharmony_ci rc = -EEXIST; 28962306a36Sopenharmony_ci goto out; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if ((dn = of_find_node_by_path(path))) { 29362306a36Sopenharmony_ci rc = ibmebus_create_device(dn); 29462306a36Sopenharmony_ci of_node_put(dn); 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci printk(KERN_WARNING "%s: no such device node: %s\n", 29762306a36Sopenharmony_ci __func__, path); 29862306a36Sopenharmony_ci rc = -ENODEV; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciout: 30262306a36Sopenharmony_ci kfree(path); 30362306a36Sopenharmony_ci if (rc) 30462306a36Sopenharmony_ci return rc; 30562306a36Sopenharmony_ci return count; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_cistatic BUS_ATTR_WO(probe); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct device *dev; 31262306a36Sopenharmony_ci char *path; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci path = ibmebus_chomp(buf, count); 31562306a36Sopenharmony_ci if (!path) 31662306a36Sopenharmony_ci return -ENOMEM; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path, 31962306a36Sopenharmony_ci ibmebus_match_path))) { 32062306a36Sopenharmony_ci of_device_unregister(to_platform_device(dev)); 32162306a36Sopenharmony_ci put_device(dev); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci kfree(path); 32462306a36Sopenharmony_ci return count; 32562306a36Sopenharmony_ci } else { 32662306a36Sopenharmony_ci printk(KERN_WARNING "%s: %s not on the bus\n", 32762306a36Sopenharmony_ci __func__, path); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci kfree(path); 33062306a36Sopenharmony_ci return -ENODEV; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_cistatic BUS_ATTR_WO(remove); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic struct attribute *ibmbus_bus_attrs[] = { 33662306a36Sopenharmony_ci &bus_attr_probe.attr, 33762306a36Sopenharmony_ci &bus_attr_remove.attr, 33862306a36Sopenharmony_ci NULL, 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ciATTRIBUTE_GROUPS(ibmbus_bus); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci const struct of_device_id *matches = drv->of_match_table; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!matches) 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return of_match_device(matches, dev) != NULL; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic int ibmebus_bus_device_probe(struct device *dev) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci int error = -ENODEV; 35562306a36Sopenharmony_ci struct platform_driver *drv; 35662306a36Sopenharmony_ci struct platform_device *of_dev; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci drv = to_platform_driver(dev->driver); 35962306a36Sopenharmony_ci of_dev = to_platform_device(dev); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!drv->probe) 36262306a36Sopenharmony_ci return error; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci get_device(dev); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (of_driver_match_device(dev, dev->driver)) 36762306a36Sopenharmony_ci error = drv->probe(of_dev); 36862306a36Sopenharmony_ci if (error) 36962306a36Sopenharmony_ci put_device(dev); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return error; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void ibmebus_bus_device_remove(struct device *dev) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct platform_device *of_dev = to_platform_device(dev); 37762306a36Sopenharmony_ci struct platform_driver *drv = to_platform_driver(dev->driver); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (dev->driver && drv->remove) 38062306a36Sopenharmony_ci drv->remove(of_dev); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void ibmebus_bus_device_shutdown(struct device *dev) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct platform_device *of_dev = to_platform_device(dev); 38662306a36Sopenharmony_ci struct platform_driver *drv = to_platform_driver(dev->driver); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (dev->driver && drv->shutdown) 38962306a36Sopenharmony_ci drv->shutdown(of_dev); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/* 39362306a36Sopenharmony_ci * ibmebus_bus_device_attrs 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic ssize_t devspec_show(struct device *dev, 39662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct platform_device *ofdev; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ofdev = to_platform_device(dev); 40162306a36Sopenharmony_ci return sprintf(buf, "%pOF\n", ofdev->dev.of_node); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(devspec); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic ssize_t name_show(struct device *dev, 40662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct platform_device *ofdev; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ofdev = to_platform_device(dev); 41162306a36Sopenharmony_ci return sprintf(buf, "%pOFn\n", ofdev->dev.of_node); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, 41662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return of_device_modalias(dev, buf, PAGE_SIZE); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic struct attribute *ibmebus_bus_device_attrs[] = { 42362306a36Sopenharmony_ci &dev_attr_devspec.attr, 42462306a36Sopenharmony_ci &dev_attr_name.attr, 42562306a36Sopenharmony_ci &dev_attr_modalias.attr, 42662306a36Sopenharmony_ci NULL, 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ciATTRIBUTE_GROUPS(ibmebus_bus_device); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int ibmebus_bus_modalias(const struct device *dev, struct kobj_uevent_env *env) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci return of_device_uevent_modalias(dev, env); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistruct bus_type ibmebus_bus_type = { 43662306a36Sopenharmony_ci .name = "ibmebus", 43762306a36Sopenharmony_ci .uevent = ibmebus_bus_modalias, 43862306a36Sopenharmony_ci .bus_groups = ibmbus_bus_groups, 43962306a36Sopenharmony_ci .match = ibmebus_bus_bus_match, 44062306a36Sopenharmony_ci .probe = ibmebus_bus_device_probe, 44162306a36Sopenharmony_ci .remove = ibmebus_bus_device_remove, 44262306a36Sopenharmony_ci .shutdown = ibmebus_bus_device_shutdown, 44362306a36Sopenharmony_ci .dev_groups = ibmebus_bus_device_groups, 44462306a36Sopenharmony_ci}; 44562306a36Sopenharmony_ciEXPORT_SYMBOL(ibmebus_bus_type); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int __init ibmebus_bus_init(void) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int err; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci printk(KERN_INFO "IBM eBus Device Driver\n"); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci err = bus_register(&ibmebus_bus_type); 45462306a36Sopenharmony_ci if (err) { 45562306a36Sopenharmony_ci printk(KERN_ERR "%s: failed to register IBM eBus.\n", 45662306a36Sopenharmony_ci __func__); 45762306a36Sopenharmony_ci return err; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci err = device_register(&ibmebus_bus_device); 46162306a36Sopenharmony_ci if (err) { 46262306a36Sopenharmony_ci printk(KERN_WARNING "%s: device_register returned %i\n", 46362306a36Sopenharmony_ci __func__, err); 46462306a36Sopenharmony_ci put_device(&ibmebus_bus_device); 46562306a36Sopenharmony_ci bus_unregister(&ibmebus_bus_type); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return err; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci err = ibmebus_create_devices(ibmebus_matches); 47162306a36Sopenharmony_ci if (err) { 47262306a36Sopenharmony_ci device_unregister(&ibmebus_bus_device); 47362306a36Sopenharmony_ci bus_unregister(&ibmebus_bus_type); 47462306a36Sopenharmony_ci return err; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_cimachine_postcore_initcall(pseries, ibmebus_bus_init); 480