Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/ipmi/ipmi_plat_data.c
26282 views
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
126