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 11 struct 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, 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->type == SI_BT) 25 size = 3; 26 else if (p->type == SI_TYPE_INVALID) 27 size = 0; 28 else 29 size = 2; 30 31 if (p->regsize == 0) 32 p->regsize = DEFAULT_REGSIZE; 33 if (p->regspacing == 0) 34 p->regspacing = p->regsize; 35 36 pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type); 37 if (p->slave_addr) 38 pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr); 39 pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source); 40 if (p->regshift) 41 pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift); 42 pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize); 43 /* Last entry must be left NULL to terminate it. */ 44 45 pdev = platform_device_alloc(name, inst); 46 if (!pdev) { 47 pr_err("Error allocating IPMI platform device %s.%d\n", 48 name, inst); 49 return NULL; 50 } 51 52 if (size == 0) 53 /* An invalid or SSIF interface, no resources. */ 54 goto add_properties; 55 56 /* 57 * Register spacing is derived from the resources in 58 * the IPMI platform code. 59 */ 60 61 if (p->space == IPMI_IO_ADDR_SPACE) 62 flags = IORESOURCE_IO; 63 else 64 flags = IORESOURCE_MEM; 65 66 r[0].start = p->addr; 67 r[0].end = r[0].start + p->regsize - 1; 68 r[0].name = "IPMI Address 1"; 69 r[0].flags = flags; 70 71 if (size > 1) { 72 r[1].start = r[0].start + p->regspacing; 73 r[1].end = r[1].start + p->regsize - 1; 74 r[1].name = "IPMI Address 2"; 75 r[1].flags = flags; 76 num_r++; 77 } 78 79 if (size > 2) { 80 r[2].start = r[1].start + p->regspacing; 81 r[2].end = r[2].start + p->regsize - 1; 82 r[2].name = "IPMI Address 3"; 83 r[2].flags = flags; 84 num_r++; 85 } 86 87 if (p->irq) { 88 r[num_r].start = p->irq; 89 r[num_r].end = p->irq; 90 r[num_r].name = "IPMI IRQ"; 91 r[num_r].flags = IORESOURCE_IRQ; 92 num_r++; 93 } 94 95 rv = platform_device_add_resources(pdev, r, num_r); 96 if (rv) { 97 dev_err(&pdev->dev, 98 "Unable to add hard-code resources: %d\n", rv); 99 goto err; 100 } 101 add_properties: 102 rv = platform_device_add_properties(pdev, pr); 103 if (rv) { 104 dev_err(&pdev->dev, 105 "Unable to add hard-code properties: %d\n", rv); 106 goto err; 107 } 108 109 rv = platform_device_add(pdev); 110 if (rv) { 111 dev_err(&pdev->dev, 112 "Unable to add hard-code device: %d\n", rv); 113 goto err; 114 } 115 return pdev; 116 117 err: 118 platform_device_put(pdev); 119 return NULL; 120 } 121 EXPORT_SYMBOL(ipmi_platform_add); 122