125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| 
 | |
| /*
 | |
|  * Add an IPMI platform device.
 | |
|  */
 | |
| 
 | |
| #include <linux/platform_device.h>
 | |
| #include "ipmi_plat_data.h"
 | |
| #include "ipmi_si.h"
 | |
| 
 | |
| struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
 | |
| 					  struct ipmi_plat_data *p)
 | |
| {
 | |
| 	struct platform_device *pdev;
 | |
| 	unsigned int num_r = 1, size = 0, pidx = 0;
 | |
| 	struct resource r[4];
 | |
| 	struct property_entry pr[6];
 | |
| 	u32 flags;
 | |
| 	int rv;
 | |
| 
 | |
| 	memset(pr, 0, sizeof(pr));
 | |
| 	memset(r, 0, sizeof(r));
 | |
| 
 | |
| 	if (p->iftype == IPMI_PLAT_IF_SI) {
 | |
| 		if (p->type == SI_BT)
 | |
| 			size = 3;
 | |
| 		else if (p->type != SI_TYPE_INVALID)
 | |
| 			size = 2;
 | |
| 
 | |
| 		if (p->regsize == 0)
 | |
| 			p->regsize = DEFAULT_REGSIZE;
 | |
| 		if (p->regspacing == 0)
 | |
| 			p->regspacing = p->regsize;
 | |
| 
 | |
| 		pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);
 | |
| 	} else if (p->iftype == IPMI_PLAT_IF_SSIF) {
 | |
| 		pr[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", p->addr);
 | |
| 	}
 | |
| 
 | |
| 	if (p->slave_addr)
 | |
| 		pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);
 | |
| 	pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);
 | |
| 	if (p->regshift)
 | |
| 		pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);
 | |
| 	pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);
 | |
| 	/* Last entry must be left NULL to terminate it. */
 | |
| 
 | |
| 	pdev = platform_device_alloc(name, inst);
 | |
| 	if (!pdev) {
 | |
| 		pr_err("Error allocating IPMI platform device %s.%d\n",
 | |
| 		       name, inst);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (size == 0)
 | |
| 		/* An invalid or SSIF interface, no resources. */
 | |
| 		goto add_properties;
 | |
| 
 | |
| 	/*
 | |
| 	 * Register spacing is derived from the resources in
 | |
| 	 * the IPMI platform code.
 | |
| 	 */
 | |
| 
 | |
| 	if (p->space == IPMI_IO_ADDR_SPACE)
 | |
| 		flags = IORESOURCE_IO;
 | |
| 	else
 | |
| 		flags = IORESOURCE_MEM;
 | |
| 
 | |
| 	r[0].start = p->addr;
 | |
| 	r[0].end = r[0].start + p->regsize - 1;
 | |
| 	r[0].name = "IPMI Address 1";
 | |
| 	r[0].flags = flags;
 | |
| 
 | |
| 	if (size > 1) {
 | |
| 		r[1].start = r[0].start + p->regspacing;
 | |
| 		r[1].end = r[1].start + p->regsize - 1;
 | |
| 		r[1].name = "IPMI Address 2";
 | |
| 		r[1].flags = flags;
 | |
| 		num_r++;
 | |
| 	}
 | |
| 
 | |
| 	if (size > 2) {
 | |
| 		r[2].start = r[1].start + p->regspacing;
 | |
| 		r[2].end = r[2].start + p->regsize - 1;
 | |
| 		r[2].name = "IPMI Address 3";
 | |
| 		r[2].flags = flags;
 | |
| 		num_r++;
 | |
| 	}
 | |
| 
 | |
| 	if (p->irq) {
 | |
| 		r[num_r].start = p->irq;
 | |
| 		r[num_r].end = p->irq;
 | |
| 		r[num_r].name = "IPMI IRQ";
 | |
| 		r[num_r].flags = IORESOURCE_IRQ;
 | |
| 		num_r++;
 | |
| 	}
 | |
| 
 | |
| 	rv = platform_device_add_resources(pdev, r, num_r);
 | |
| 	if (rv) {
 | |
| 		dev_err(&pdev->dev,
 | |
| 			"Unable to add hard-code resources: %d\n", rv);
 | |
| 		goto err;
 | |
| 	}
 | |
|  add_properties:
 | |
| 	rv = device_create_managed_software_node(&pdev->dev, pr, NULL);
 | |
| 	if (rv) {
 | |
| 		dev_err(&pdev->dev,
 | |
| 			"Unable to add hard-code properties: %d\n", rv);
 | |
| 		goto err;
 | |
| 	}
 | |
| 
 | |
| 	rv = platform_device_add(pdev);
 | |
| 	if (rv) {
 | |
| 		dev_err(&pdev->dev,
 | |
| 			"Unable to add hard-code device: %d\n", rv);
 | |
| 		goto err;
 | |
| 	}
 | |
| 	return pdev;
 | |
| 
 | |
| err:
 | |
| 	platform_device_put(pdev);
 | |
| 	return NULL;
 | |
| }
 | |
| EXPORT_SYMBOL(ipmi_platform_add);
 |