xref: /openbmc/linux/arch/powerpc/platforms/pseries/ibmebus.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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