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);
|