125 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Add an IPMI platform device.5 */6 7#include <linux/platform_device.h>8#include "ipmi_plat_data.h"9#include "ipmi_si.h"10 11struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,12 struct ipmi_plat_data *p)13{14 struct platform_device *pdev;15 unsigned int num_r = 1, size = 0, pidx = 0;16 struct resource r[4];17 struct property_entry pr[6];18 u32 flags;19 int rv;20 21 memset(pr, 0, sizeof(pr));22 memset(r, 0, sizeof(r));23 24 if (p->iftype == IPMI_PLAT_IF_SI) {25 if (p->type == SI_BT)26 size = 3;27 else if (p->type != SI_TYPE_INVALID)28 size = 2;29 30 if (p->regsize == 0)31 p->regsize = DEFAULT_REGSIZE;32 if (p->regspacing == 0)33 p->regspacing = p->regsize;34 35 pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);36 } else if (p->iftype == IPMI_PLAT_IF_SSIF) {37 pr[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", p->addr);38 }39 40 if (p->slave_addr)41 pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);42 pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);43 if (p->regshift)44 pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);45 pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);46 /* Last entry must be left NULL to terminate it. */47 48 pdev = platform_device_alloc(name, inst);49 if (!pdev) {50 pr_err("Error allocating IPMI platform device %s.%d\n",51 name, inst);52 return NULL;53 }54 55 if (size == 0)56 /* An invalid or SSIF interface, no resources. */57 goto add_properties;58 59 /*60 * Register spacing is derived from the resources in61 * the IPMI platform code.62 */63 64 if (p->space == IPMI_IO_ADDR_SPACE)65 flags = IORESOURCE_IO;66 else67 flags = IORESOURCE_MEM;68 69 r[0].start = p->addr;70 r[0].end = r[0].start + p->regsize - 1;71 r[0].name = "IPMI Address 1";72 r[0].flags = flags;73 74 if (size > 1) {75 r[1].start = r[0].start + p->regspacing;76 r[1].end = r[1].start + p->regsize - 1;77 r[1].name = "IPMI Address 2";78 r[1].flags = flags;79 num_r++;80 }81 82 if (size > 2) {83 r[2].start = r[1].start + p->regspacing;84 r[2].end = r[2].start + p->regsize - 1;85 r[2].name = "IPMI Address 3";86 r[2].flags = flags;87 num_r++;88 }89 90 if (p->irq) {91 r[num_r].start = p->irq;92 r[num_r].end = p->irq;93 r[num_r].name = "IPMI IRQ";94 r[num_r].flags = IORESOURCE_IRQ;95 num_r++;96 }97 98 rv = platform_device_add_resources(pdev, r, num_r);99 if (rv) {100 dev_err(&pdev->dev,101 "Unable to add hard-code resources: %d\n", rv);102 goto err;103 }104 add_properties:105 rv = device_create_managed_software_node(&pdev->dev, pr, NULL);106 if (rv) {107 dev_err(&pdev->dev,108 "Unable to add hard-code properties: %d\n", rv);109 goto err;110 }111 112 rv = platform_device_add(pdev);113 if (rv) {114 dev_err(&pdev->dev,115 "Unable to add hard-code device: %d\n", rv);116 goto err;117 }118 return pdev;119 120err:121 platform_device_put(pdev);122 return NULL;123}124EXPORT_SYMBOL(ipmi_platform_add);125