Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / char / ipmi / ipmi_plat_data.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
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 = platform_device_add_properties(pdev, pr);
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);