Commit | Line | Data |
---|---|---|
3cd83bac CM |
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; | |
d7323638 | 15 | unsigned int num_r = 1, size = 0, pidx = 0; |
3cd83bac CM |
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 | ||
d7323638 CM |
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; | |
3cd83bac | 34 | |
d7323638 CM |
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 | } | |
3cd83bac | 39 | |
3cd83bac CM |
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: | |
c053c4eb | 105 | rv = device_create_managed_software_node(&pdev->dev, pr, NULL); |
3cd83bac CM |
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); |