130757de2SMichael Ellerman /*
230757de2SMichael Ellerman * IBM PowerPC IBM eBus Infrastructure Support.
330757de2SMichael Ellerman *
430757de2SMichael Ellerman * Copyright (c) 2005 IBM Corporation
530757de2SMichael Ellerman * Joachim Fenkes <fenkes@de.ibm.com>
630757de2SMichael Ellerman * Heiko J Schick <schickhj@de.ibm.com>
730757de2SMichael Ellerman *
830757de2SMichael Ellerman * All rights reserved.
930757de2SMichael Ellerman *
1030757de2SMichael Ellerman * This source code is distributed under a dual license of GPL v2.0 and OpenIB
1130757de2SMichael Ellerman * BSD.
1230757de2SMichael Ellerman *
1330757de2SMichael Ellerman * OpenIB BSD License
1430757de2SMichael Ellerman *
1530757de2SMichael Ellerman * Redistribution and use in source and binary forms, with or without
1630757de2SMichael Ellerman * modification, are permitted provided that the following conditions are met:
1730757de2SMichael Ellerman *
1830757de2SMichael Ellerman * Redistributions of source code must retain the above copyright notice, this
1930757de2SMichael Ellerman * list of conditions and the following disclaimer.
2030757de2SMichael Ellerman *
2130757de2SMichael Ellerman * Redistributions in binary form must reproduce the above copyright notice,
2230757de2SMichael Ellerman * this list of conditions and the following disclaimer in the documentation
2330757de2SMichael Ellerman * and/or other materials
2430757de2SMichael Ellerman * provided with the distribution.
2530757de2SMichael Ellerman *
2630757de2SMichael Ellerman * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2730757de2SMichael Ellerman * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2830757de2SMichael Ellerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2930757de2SMichael Ellerman * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
3030757de2SMichael Ellerman * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3130757de2SMichael Ellerman * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3230757de2SMichael Ellerman * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3330757de2SMichael Ellerman * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
3430757de2SMichael Ellerman * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3530757de2SMichael Ellerman * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3630757de2SMichael Ellerman * POSSIBILITY OF SUCH DAMAGE.
3730757de2SMichael Ellerman */
3830757de2SMichael Ellerman
3930757de2SMichael Ellerman #include <linux/init.h>
4030757de2SMichael Ellerman #include <linux/export.h>
4130757de2SMichael Ellerman #include <linux/console.h>
4230757de2SMichael Ellerman #include <linux/kobject.h>
430a0f0d8bSChristoph Hellwig #include <linux/dma-map-ops.h>
4430757de2SMichael Ellerman #include <linux/interrupt.h>
4513a9a5d1SMarc Zyngier #include <linux/irqdomain.h>
4630757de2SMichael Ellerman #include <linux/of.h>
4730757de2SMichael Ellerman #include <linux/slab.h>
4830757de2SMichael Ellerman #include <linux/stat.h>
4930757de2SMichael Ellerman #include <linux/of_platform.h>
5081d7cac4SRob Herring #include <linux/platform_device.h>
5130757de2SMichael Ellerman #include <asm/ibmebus.h>
524336b933SOliver O'Halloran #include <asm/machdep.h>
5330757de2SMichael Ellerman
5430757de2SMichael Ellerman static struct device ibmebus_bus_device = { /* fake "parent" device */
5530757de2SMichael Ellerman .init_name = "ibmebus",
5630757de2SMichael Ellerman };
5730757de2SMichael Ellerman
5830757de2SMichael Ellerman struct bus_type ibmebus_bus_type;
5930757de2SMichael Ellerman
6030757de2SMichael Ellerman /* These devices will automatically be added to the bus during init */
6130757de2SMichael Ellerman static const struct of_device_id ibmebus_matches[] __initconst = {
6230757de2SMichael Ellerman { .compatible = "IBM,lhca" },
6330757de2SMichael Ellerman { .compatible = "IBM,lhea" },
6430757de2SMichael Ellerman {},
6530757de2SMichael Ellerman };
6630757de2SMichael Ellerman
ibmebus_alloc_coherent(struct device * dev,size_t size,dma_addr_t * dma_handle,gfp_t flag,unsigned long attrs)6730757de2SMichael Ellerman static void *ibmebus_alloc_coherent(struct device *dev,
6830757de2SMichael Ellerman size_t size,
6930757de2SMichael Ellerman dma_addr_t *dma_handle,
7030757de2SMichael Ellerman gfp_t flag,
7130757de2SMichael Ellerman unsigned long attrs)
7230757de2SMichael Ellerman {
7330757de2SMichael Ellerman void *mem;
7430757de2SMichael Ellerman
7530757de2SMichael Ellerman mem = kmalloc(size, flag);
7630757de2SMichael Ellerman *dma_handle = (dma_addr_t)mem;
7730757de2SMichael Ellerman
7830757de2SMichael Ellerman return mem;
7930757de2SMichael Ellerman }
8030757de2SMichael Ellerman
ibmebus_free_coherent(struct device * dev,size_t size,void * vaddr,dma_addr_t dma_handle,unsigned long attrs)8130757de2SMichael Ellerman static void ibmebus_free_coherent(struct device *dev,
8230757de2SMichael Ellerman size_t size, void *vaddr,
8330757de2SMichael Ellerman dma_addr_t dma_handle,
8430757de2SMichael Ellerman unsigned long attrs)
8530757de2SMichael Ellerman {
8630757de2SMichael Ellerman kfree(vaddr);
8730757de2SMichael Ellerman }
8830757de2SMichael Ellerman
ibmebus_map_page(struct device * dev,struct page * page,unsigned long offset,size_t size,enum dma_data_direction direction,unsigned long attrs)8930757de2SMichael Ellerman static dma_addr_t ibmebus_map_page(struct device *dev,
9030757de2SMichael Ellerman struct page *page,
9130757de2SMichael Ellerman unsigned long offset,
9230757de2SMichael Ellerman size_t size,
9330757de2SMichael Ellerman enum dma_data_direction direction,
9430757de2SMichael Ellerman unsigned long attrs)
9530757de2SMichael Ellerman {
9630757de2SMichael Ellerman return (dma_addr_t)(page_address(page) + offset);
9730757de2SMichael Ellerman }
9830757de2SMichael Ellerman
ibmebus_unmap_page(struct device * dev,dma_addr_t dma_addr,size_t size,enum dma_data_direction direction,unsigned long attrs)9930757de2SMichael Ellerman static void ibmebus_unmap_page(struct device *dev,
10030757de2SMichael Ellerman dma_addr_t dma_addr,
10130757de2SMichael Ellerman size_t size,
10230757de2SMichael Ellerman enum dma_data_direction direction,
10330757de2SMichael Ellerman unsigned long attrs)
10430757de2SMichael Ellerman {
10530757de2SMichael Ellerman return;
10630757de2SMichael Ellerman }
10730757de2SMichael Ellerman
ibmebus_map_sg(struct device * dev,struct scatterlist * sgl,int nents,enum dma_data_direction direction,unsigned long attrs)10830757de2SMichael Ellerman static int ibmebus_map_sg(struct device *dev,
10930757de2SMichael Ellerman struct scatterlist *sgl,
11030757de2SMichael Ellerman int nents, enum dma_data_direction direction,
11130757de2SMichael Ellerman unsigned long attrs)
11230757de2SMichael Ellerman {
11330757de2SMichael Ellerman struct scatterlist *sg;
11430757de2SMichael Ellerman int i;
11530757de2SMichael Ellerman
11630757de2SMichael Ellerman for_each_sg(sgl, sg, nents, i) {
11730757de2SMichael Ellerman sg->dma_address = (dma_addr_t) sg_virt(sg);
11830757de2SMichael Ellerman sg->dma_length = sg->length;
11930757de2SMichael Ellerman }
12030757de2SMichael Ellerman
12130757de2SMichael Ellerman return nents;
12230757de2SMichael Ellerman }
12330757de2SMichael Ellerman
ibmebus_unmap_sg(struct device * dev,struct scatterlist * sg,int nents,enum dma_data_direction direction,unsigned long attrs)12430757de2SMichael Ellerman static void ibmebus_unmap_sg(struct device *dev,
12530757de2SMichael Ellerman struct scatterlist *sg,
12630757de2SMichael Ellerman int nents, enum dma_data_direction direction,
12730757de2SMichael Ellerman unsigned long attrs)
12830757de2SMichael Ellerman {
12930757de2SMichael Ellerman return;
13030757de2SMichael Ellerman }
13130757de2SMichael Ellerman
ibmebus_dma_supported(struct device * dev,u64 mask)13230757de2SMichael Ellerman static int ibmebus_dma_supported(struct device *dev, u64 mask)
13330757de2SMichael Ellerman {
13430757de2SMichael Ellerman return mask == DMA_BIT_MASK(64);
13530757de2SMichael Ellerman }
13630757de2SMichael Ellerman
ibmebus_dma_get_required_mask(struct device * dev)13730757de2SMichael Ellerman static u64 ibmebus_dma_get_required_mask(struct device *dev)
13830757de2SMichael Ellerman {
13930757de2SMichael Ellerman return DMA_BIT_MASK(64);
14030757de2SMichael Ellerman }
14130757de2SMichael Ellerman
1425299709dSBart Van Assche static const struct dma_map_ops ibmebus_dma_ops = {
14330757de2SMichael Ellerman .alloc = ibmebus_alloc_coherent,
14430757de2SMichael Ellerman .free = ibmebus_free_coherent,
14530757de2SMichael Ellerman .map_sg = ibmebus_map_sg,
14630757de2SMichael Ellerman .unmap_sg = ibmebus_unmap_sg,
14730757de2SMichael Ellerman .dma_supported = ibmebus_dma_supported,
14830757de2SMichael Ellerman .get_required_mask = ibmebus_dma_get_required_mask,
14930757de2SMichael Ellerman .map_page = ibmebus_map_page,
15030757de2SMichael Ellerman .unmap_page = ibmebus_unmap_page,
15130757de2SMichael Ellerman };
15230757de2SMichael Ellerman
ibmebus_match_path(struct device * dev,const void * data)153418e3ea1SSuzuki K Poulose static int ibmebus_match_path(struct device *dev, const void *data)
15430757de2SMichael Ellerman {
15530757de2SMichael Ellerman struct device_node *dn = to_platform_device(dev)->dev.of_node;
1561c754b49SLiang He struct device_node *tn = of_find_node_by_path(data);
1571c754b49SLiang He
1581c754b49SLiang He of_node_put(tn);
1591c754b49SLiang He
1601c754b49SLiang He return (tn == dn);
16130757de2SMichael Ellerman }
16230757de2SMichael Ellerman
ibmebus_match_node(struct device * dev,const void * data)163418e3ea1SSuzuki K Poulose static int ibmebus_match_node(struct device *dev, const void *data)
16430757de2SMichael Ellerman {
16530757de2SMichael Ellerman return to_platform_device(dev)->dev.of_node == data;
16630757de2SMichael Ellerman }
16730757de2SMichael Ellerman
ibmebus_create_device(struct device_node * dn)16830757de2SMichael Ellerman static int ibmebus_create_device(struct device_node *dn)
16930757de2SMichael Ellerman {
17030757de2SMichael Ellerman struct platform_device *dev;
17130757de2SMichael Ellerman int ret;
17230757de2SMichael Ellerman
17330757de2SMichael Ellerman dev = of_device_alloc(dn, NULL, &ibmebus_bus_device);
17430757de2SMichael Ellerman if (!dev)
17530757de2SMichael Ellerman return -ENOMEM;
17630757de2SMichael Ellerman
17730757de2SMichael Ellerman dev->dev.bus = &ibmebus_bus_type;
1785657933dSBart Van Assche dev->dev.dma_ops = &ibmebus_dma_ops;
17930757de2SMichael Ellerman
18030757de2SMichael Ellerman ret = of_device_add(dev);
18130757de2SMichael Ellerman if (ret)
18230757de2SMichael Ellerman platform_device_put(dev);
18330757de2SMichael Ellerman return ret;
18430757de2SMichael Ellerman }
18530757de2SMichael Ellerman
ibmebus_create_devices(const struct of_device_id * matches)18630757de2SMichael Ellerman static int ibmebus_create_devices(const struct of_device_id *matches)
18730757de2SMichael Ellerman {
18830757de2SMichael Ellerman struct device_node *root, *child;
18930757de2SMichael Ellerman struct device *dev;
19030757de2SMichael Ellerman int ret = 0;
19130757de2SMichael Ellerman
19230757de2SMichael Ellerman root = of_find_node_by_path("/");
19330757de2SMichael Ellerman
19430757de2SMichael Ellerman for_each_child_of_node(root, child) {
19530757de2SMichael Ellerman if (!of_match_node(matches, child))
19630757de2SMichael Ellerman continue;
19730757de2SMichael Ellerman
19830757de2SMichael Ellerman dev = bus_find_device(&ibmebus_bus_type, NULL, child,
19930757de2SMichael Ellerman ibmebus_match_node);
20030757de2SMichael Ellerman if (dev) {
20130757de2SMichael Ellerman put_device(dev);
20230757de2SMichael Ellerman continue;
20330757de2SMichael Ellerman }
20430757de2SMichael Ellerman
20530757de2SMichael Ellerman ret = ibmebus_create_device(child);
20630757de2SMichael Ellerman if (ret) {
20730757de2SMichael Ellerman printk(KERN_ERR "%s: failed to create device (%i)",
20830757de2SMichael Ellerman __func__, ret);
20930757de2SMichael Ellerman of_node_put(child);
21030757de2SMichael Ellerman break;
21130757de2SMichael Ellerman }
21230757de2SMichael Ellerman }
21330757de2SMichael Ellerman
21430757de2SMichael Ellerman of_node_put(root);
21530757de2SMichael Ellerman return ret;
21630757de2SMichael Ellerman }
21730757de2SMichael Ellerman
ibmebus_register_driver(struct platform_driver * drv)21830757de2SMichael Ellerman int ibmebus_register_driver(struct platform_driver *drv)
21930757de2SMichael Ellerman {
22030757de2SMichael Ellerman /* If the driver uses devices that ibmebus doesn't know, add them */
22130757de2SMichael Ellerman ibmebus_create_devices(drv->driver.of_match_table);
22230757de2SMichael Ellerman
22330757de2SMichael Ellerman drv->driver.bus = &ibmebus_bus_type;
22430757de2SMichael Ellerman return driver_register(&drv->driver);
22530757de2SMichael Ellerman }
22630757de2SMichael Ellerman EXPORT_SYMBOL(ibmebus_register_driver);
22730757de2SMichael Ellerman
ibmebus_unregister_driver(struct platform_driver * drv)22830757de2SMichael Ellerman void ibmebus_unregister_driver(struct platform_driver *drv)
22930757de2SMichael Ellerman {
23030757de2SMichael Ellerman driver_unregister(&drv->driver);
23130757de2SMichael Ellerman }
23230757de2SMichael Ellerman EXPORT_SYMBOL(ibmebus_unregister_driver);
23330757de2SMichael Ellerman
ibmebus_request_irq(u32 ist,irq_handler_t handler,unsigned long irq_flags,const char * devname,void * dev_id)23430757de2SMichael Ellerman int ibmebus_request_irq(u32 ist, irq_handler_t handler,
23530757de2SMichael Ellerman unsigned long irq_flags, const char *devname,
23630757de2SMichael Ellerman void *dev_id)
23730757de2SMichael Ellerman {
23830757de2SMichael Ellerman unsigned int irq = irq_create_mapping(NULL, ist);
23930757de2SMichael Ellerman
24030757de2SMichael Ellerman if (!irq)
24130757de2SMichael Ellerman return -EINVAL;
24230757de2SMichael Ellerman
24330757de2SMichael Ellerman return request_irq(irq, handler, irq_flags, devname, dev_id);
24430757de2SMichael Ellerman }
24530757de2SMichael Ellerman EXPORT_SYMBOL(ibmebus_request_irq);
24630757de2SMichael Ellerman
ibmebus_free_irq(u32 ist,void * dev_id)24730757de2SMichael Ellerman void ibmebus_free_irq(u32 ist, void *dev_id)
24830757de2SMichael Ellerman {
24930757de2SMichael Ellerman unsigned int irq = irq_find_mapping(NULL, ist);
25030757de2SMichael Ellerman
25130757de2SMichael Ellerman free_irq(irq, dev_id);
25230757de2SMichael Ellerman irq_dispose_mapping(irq);
25330757de2SMichael Ellerman }
25430757de2SMichael Ellerman EXPORT_SYMBOL(ibmebus_free_irq);
25530757de2SMichael Ellerman
ibmebus_chomp(const char * in,size_t count)25630757de2SMichael Ellerman static char *ibmebus_chomp(const char *in, size_t count)
25730757de2SMichael Ellerman {
25830757de2SMichael Ellerman char *out = kmalloc(count + 1, GFP_KERNEL);
25930757de2SMichael Ellerman
26030757de2SMichael Ellerman if (!out)
26130757de2SMichael Ellerman return NULL;
26230757de2SMichael Ellerman
26330757de2SMichael Ellerman memcpy(out, in, count);
26430757de2SMichael Ellerman out[count] = '\0';
26530757de2SMichael Ellerman if (out[count - 1] == '\n')
26630757de2SMichael Ellerman out[count - 1] = '\0';
26730757de2SMichael Ellerman
26830757de2SMichael Ellerman return out;
26930757de2SMichael Ellerman }
27030757de2SMichael Ellerman
probe_store(const struct bus_type * bus,const char * buf,size_t count)27175cff725SGreg Kroah-Hartman static ssize_t probe_store(const struct bus_type *bus, const char *buf, size_t count)
27230757de2SMichael Ellerman {
27330757de2SMichael Ellerman struct device_node *dn = NULL;
27430757de2SMichael Ellerman struct device *dev;
27530757de2SMichael Ellerman char *path;
27630757de2SMichael Ellerman ssize_t rc = 0;
27730757de2SMichael Ellerman
27830757de2SMichael Ellerman path = ibmebus_chomp(buf, count);
27930757de2SMichael Ellerman if (!path)
28030757de2SMichael Ellerman return -ENOMEM;
28130757de2SMichael Ellerman
28230757de2SMichael Ellerman dev = bus_find_device(&ibmebus_bus_type, NULL, path,
28330757de2SMichael Ellerman ibmebus_match_path);
28430757de2SMichael Ellerman if (dev) {
28530757de2SMichael Ellerman put_device(dev);
28630757de2SMichael Ellerman printk(KERN_WARNING "%s: %s has already been probed\n",
28730757de2SMichael Ellerman __func__, path);
28830757de2SMichael Ellerman rc = -EEXIST;
28930757de2SMichael Ellerman goto out;
29030757de2SMichael Ellerman }
29130757de2SMichael Ellerman
29230757de2SMichael Ellerman if ((dn = of_find_node_by_path(path))) {
29330757de2SMichael Ellerman rc = ibmebus_create_device(dn);
29430757de2SMichael Ellerman of_node_put(dn);
29530757de2SMichael Ellerman } else {
29630757de2SMichael Ellerman printk(KERN_WARNING "%s: no such device node: %s\n",
29730757de2SMichael Ellerman __func__, path);
29830757de2SMichael Ellerman rc = -ENODEV;
29930757de2SMichael Ellerman }
30030757de2SMichael Ellerman
30130757de2SMichael Ellerman out:
30230757de2SMichael Ellerman kfree(path);
30330757de2SMichael Ellerman if (rc)
30430757de2SMichael Ellerman return rc;
30530757de2SMichael Ellerman return count;
30630757de2SMichael Ellerman }
307c1507ea8SGreg Kroah-Hartman static BUS_ATTR_WO(probe);
30830757de2SMichael Ellerman
remove_store(const struct bus_type * bus,const char * buf,size_t count)30975cff725SGreg Kroah-Hartman static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count)
31030757de2SMichael Ellerman {
31130757de2SMichael Ellerman struct device *dev;
31230757de2SMichael Ellerman char *path;
31330757de2SMichael Ellerman
31430757de2SMichael Ellerman path = ibmebus_chomp(buf, count);
31530757de2SMichael Ellerman if (!path)
31630757de2SMichael Ellerman return -ENOMEM;
31730757de2SMichael Ellerman
31830757de2SMichael Ellerman if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
31930757de2SMichael Ellerman ibmebus_match_path))) {
32030757de2SMichael Ellerman of_device_unregister(to_platform_device(dev));
32130757de2SMichael Ellerman put_device(dev);
32230757de2SMichael Ellerman
32330757de2SMichael Ellerman kfree(path);
32430757de2SMichael Ellerman return count;
32530757de2SMichael Ellerman } else {
32630757de2SMichael Ellerman printk(KERN_WARNING "%s: %s not on the bus\n",
32730757de2SMichael Ellerman __func__, path);
32830757de2SMichael Ellerman
32930757de2SMichael Ellerman kfree(path);
33030757de2SMichael Ellerman return -ENODEV;
33130757de2SMichael Ellerman }
33230757de2SMichael Ellerman }
333c1507ea8SGreg Kroah-Hartman static BUS_ATTR_WO(remove);
33430757de2SMichael Ellerman
33530757de2SMichael Ellerman static struct attribute *ibmbus_bus_attrs[] = {
33630757de2SMichael Ellerman &bus_attr_probe.attr,
33730757de2SMichael Ellerman &bus_attr_remove.attr,
33830757de2SMichael Ellerman NULL,
33930757de2SMichael Ellerman };
34030757de2SMichael Ellerman ATTRIBUTE_GROUPS(ibmbus_bus);
34130757de2SMichael Ellerman
ibmebus_bus_bus_match(struct device * dev,struct device_driver * drv)34230757de2SMichael Ellerman static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv)
34330757de2SMichael Ellerman {
34430757de2SMichael Ellerman const struct of_device_id *matches = drv->of_match_table;
34530757de2SMichael Ellerman
34630757de2SMichael Ellerman if (!matches)
34730757de2SMichael Ellerman return 0;
34830757de2SMichael Ellerman
34930757de2SMichael Ellerman return of_match_device(matches, dev) != NULL;
35030757de2SMichael Ellerman }
35130757de2SMichael Ellerman
ibmebus_bus_device_probe(struct device * dev)35230757de2SMichael Ellerman static int ibmebus_bus_device_probe(struct device *dev)
35330757de2SMichael Ellerman {
35430757de2SMichael Ellerman int error = -ENODEV;
35530757de2SMichael Ellerman struct platform_driver *drv;
35630757de2SMichael Ellerman struct platform_device *of_dev;
35730757de2SMichael Ellerman
35830757de2SMichael Ellerman drv = to_platform_driver(dev->driver);
35930757de2SMichael Ellerman of_dev = to_platform_device(dev);
36030757de2SMichael Ellerman
36130757de2SMichael Ellerman if (!drv->probe)
36230757de2SMichael Ellerman return error;
36330757de2SMichael Ellerman
36483c4a4eeSRob Herring get_device(dev);
36530757de2SMichael Ellerman
36630757de2SMichael Ellerman if (of_driver_match_device(dev, dev->driver))
36730757de2SMichael Ellerman error = drv->probe(of_dev);
36830757de2SMichael Ellerman if (error)
36983c4a4eeSRob Herring put_device(dev);
37030757de2SMichael Ellerman
37130757de2SMichael Ellerman return error;
37230757de2SMichael Ellerman }
37330757de2SMichael Ellerman
ibmebus_bus_device_remove(struct device * dev)374fc7a6209SUwe Kleine-König static void ibmebus_bus_device_remove(struct device *dev)
37530757de2SMichael Ellerman {
37630757de2SMichael Ellerman struct platform_device *of_dev = to_platform_device(dev);
37730757de2SMichael Ellerman struct platform_driver *drv = to_platform_driver(dev->driver);
37830757de2SMichael Ellerman
37930757de2SMichael Ellerman if (dev->driver && drv->remove)
38030757de2SMichael Ellerman drv->remove(of_dev);
38130757de2SMichael Ellerman }
38230757de2SMichael Ellerman
ibmebus_bus_device_shutdown(struct device * dev)38330757de2SMichael Ellerman static void ibmebus_bus_device_shutdown(struct device *dev)
38430757de2SMichael Ellerman {
38530757de2SMichael Ellerman struct platform_device *of_dev = to_platform_device(dev);
38630757de2SMichael Ellerman struct platform_driver *drv = to_platform_driver(dev->driver);
38730757de2SMichael Ellerman
38830757de2SMichael Ellerman if (dev->driver && drv->shutdown)
38930757de2SMichael Ellerman drv->shutdown(of_dev);
39030757de2SMichael Ellerman }
39130757de2SMichael Ellerman
39230757de2SMichael Ellerman /*
39330757de2SMichael Ellerman * ibmebus_bus_device_attrs
39430757de2SMichael Ellerman */
devspec_show(struct device * dev,struct device_attribute * attr,char * buf)39530757de2SMichael Ellerman static ssize_t devspec_show(struct device *dev,
39630757de2SMichael Ellerman struct device_attribute *attr, char *buf)
39730757de2SMichael Ellerman {
39830757de2SMichael Ellerman struct platform_device *ofdev;
39930757de2SMichael Ellerman
40030757de2SMichael Ellerman ofdev = to_platform_device(dev);
401b7c670d6SRob Herring return sprintf(buf, "%pOF\n", ofdev->dev.of_node);
40230757de2SMichael Ellerman }
403823a44acSGreg Kroah-Hartman static DEVICE_ATTR_RO(devspec);
40430757de2SMichael Ellerman
name_show(struct device * dev,struct device_attribute * attr,char * buf)40530757de2SMichael Ellerman static ssize_t name_show(struct device *dev,
40630757de2SMichael Ellerman struct device_attribute *attr, char *buf)
40730757de2SMichael Ellerman {
40830757de2SMichael Ellerman struct platform_device *ofdev;
40930757de2SMichael Ellerman
41030757de2SMichael Ellerman ofdev = to_platform_device(dev);
411b9ef7b4bSRob Herring return sprintf(buf, "%pOFn\n", ofdev->dev.of_node);
41230757de2SMichael Ellerman }
413823a44acSGreg Kroah-Hartman static DEVICE_ATTR_RO(name);
41430757de2SMichael Ellerman
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)41530757de2SMichael Ellerman static ssize_t modalias_show(struct device *dev,
41630757de2SMichael Ellerman struct device_attribute *attr, char *buf)
41730757de2SMichael Ellerman {
4180634c295SRob Herring return of_device_modalias(dev, buf, PAGE_SIZE);
41930757de2SMichael Ellerman }
420823a44acSGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
42130757de2SMichael Ellerman
422823a44acSGreg Kroah-Hartman static struct attribute *ibmebus_bus_device_attrs[] = {
423823a44acSGreg Kroah-Hartman &dev_attr_devspec.attr,
424823a44acSGreg Kroah-Hartman &dev_attr_name.attr,
425823a44acSGreg Kroah-Hartman &dev_attr_modalias.attr,
426823a44acSGreg Kroah-Hartman NULL,
42730757de2SMichael Ellerman };
428823a44acSGreg Kroah-Hartman ATTRIBUTE_GROUPS(ibmebus_bus_device);
42930757de2SMichael Ellerman
ibmebus_bus_modalias(const struct device * dev,struct kobj_uevent_env * env)430b7810ea8SStephen Rothwell static int ibmebus_bus_modalias(const struct device *dev, struct kobj_uevent_env *env)
431a77ad4bfSGreg Kroah-Hartman {
432a77ad4bfSGreg Kroah-Hartman return of_device_uevent_modalias(dev, env);
433a77ad4bfSGreg Kroah-Hartman }
434a77ad4bfSGreg Kroah-Hartman
43530757de2SMichael Ellerman struct bus_type ibmebus_bus_type = {
43630757de2SMichael Ellerman .name = "ibmebus",
437a77ad4bfSGreg Kroah-Hartman .uevent = ibmebus_bus_modalias,
43830757de2SMichael Ellerman .bus_groups = ibmbus_bus_groups,
43930757de2SMichael Ellerman .match = ibmebus_bus_bus_match,
44030757de2SMichael Ellerman .probe = ibmebus_bus_device_probe,
44130757de2SMichael Ellerman .remove = ibmebus_bus_device_remove,
44230757de2SMichael Ellerman .shutdown = ibmebus_bus_device_shutdown,
443823a44acSGreg Kroah-Hartman .dev_groups = ibmebus_bus_device_groups,
44430757de2SMichael Ellerman };
44530757de2SMichael Ellerman EXPORT_SYMBOL(ibmebus_bus_type);
44630757de2SMichael Ellerman
ibmebus_bus_init(void)44730757de2SMichael Ellerman static int __init ibmebus_bus_init(void)
44830757de2SMichael Ellerman {
44930757de2SMichael Ellerman int err;
45030757de2SMichael Ellerman
45130757de2SMichael Ellerman printk(KERN_INFO "IBM eBus Device Driver\n");
45230757de2SMichael Ellerman
45330757de2SMichael Ellerman err = bus_register(&ibmebus_bus_type);
45430757de2SMichael Ellerman if (err) {
45530757de2SMichael Ellerman printk(KERN_ERR "%s: failed to register IBM eBus.\n",
45630757de2SMichael Ellerman __func__);
45730757de2SMichael Ellerman return err;
45830757de2SMichael Ellerman }
45930757de2SMichael Ellerman
46030757de2SMichael Ellerman err = device_register(&ibmebus_bus_device);
46130757de2SMichael Ellerman if (err) {
46230757de2SMichael Ellerman printk(KERN_WARNING "%s: device_register returned %i\n",
46330757de2SMichael Ellerman __func__, err);
464*afda85b9Sruanjinjie put_device(&ibmebus_bus_device);
46530757de2SMichael Ellerman bus_unregister(&ibmebus_bus_type);
46630757de2SMichael Ellerman
46730757de2SMichael Ellerman return err;
46830757de2SMichael Ellerman }
46930757de2SMichael Ellerman
47030757de2SMichael Ellerman err = ibmebus_create_devices(ibmebus_matches);
47130757de2SMichael Ellerman if (err) {
47230757de2SMichael Ellerman device_unregister(&ibmebus_bus_device);
47330757de2SMichael Ellerman bus_unregister(&ibmebus_bus_type);
47430757de2SMichael Ellerman return err;
47530757de2SMichael Ellerman }
47630757de2SMichael Ellerman
47730757de2SMichael Ellerman return 0;
47830757de2SMichael Ellerman }
4794336b933SOliver O'Halloran machine_postcore_initcall(pseries, ibmebus_bus_init);
480