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 = 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 in 61 * the IPMI platform code. 62 */ 63 64 if (p->space == IPMI_IO_ADDR_SPACE) 65 flags = IORESOURCE_IO; 66 else 67 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 120 err: 121 platform_device_put(pdev); 122 return NULL; 123 } 124 EXPORT_SYMBOL(ipmi_platform_add); 125