forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
2.8 KiB
124 lines
2.8 KiB
// 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);
|
|
|