diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_plat_data.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_plat_data.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/char/ipmi/ipmi_plat_data.c b/drivers/char/ipmi/ipmi_plat_data.c new file mode 100644 index 000000000..747b51ae0 --- /dev/null +++ b/drivers/char/ipmi/ipmi_plat_data.c @@ -0,0 +1,124 @@ +// 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); |