Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 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); |