Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/greybus/bundle.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Greybus bundles
4
*
5
* Copyright 2014-2015 Google Inc.
6
* Copyright 2014-2015 Linaro Ltd.
7
*/
8
9
#include <linux/greybus.h>
10
#include "greybus_trace.h"
11
12
static ssize_t bundle_class_show(struct device *dev,
13
struct device_attribute *attr, char *buf)
14
{
15
struct gb_bundle *bundle = to_gb_bundle(dev);
16
17
return sprintf(buf, "0x%02x\n", bundle->class);
18
}
19
static DEVICE_ATTR_RO(bundle_class);
20
21
static ssize_t bundle_id_show(struct device *dev,
22
struct device_attribute *attr, char *buf)
23
{
24
struct gb_bundle *bundle = to_gb_bundle(dev);
25
26
return sprintf(buf, "%u\n", bundle->id);
27
}
28
static DEVICE_ATTR_RO(bundle_id);
29
30
static ssize_t state_show(struct device *dev, struct device_attribute *attr,
31
char *buf)
32
{
33
struct gb_bundle *bundle = to_gb_bundle(dev);
34
35
if (!bundle->state)
36
return sprintf(buf, "\n");
37
38
return sprintf(buf, "%s\n", bundle->state);
39
}
40
41
static ssize_t state_store(struct device *dev, struct device_attribute *attr,
42
const char *buf, size_t size)
43
{
44
struct gb_bundle *bundle = to_gb_bundle(dev);
45
46
kfree(bundle->state);
47
bundle->state = kstrdup(buf, GFP_KERNEL);
48
if (!bundle->state)
49
return -ENOMEM;
50
51
/* Tell userspace that the file contents changed */
52
sysfs_notify(&bundle->dev.kobj, NULL, "state");
53
54
return size;
55
}
56
static DEVICE_ATTR_RW(state);
57
58
static struct attribute *bundle_attrs[] = {
59
&dev_attr_bundle_class.attr,
60
&dev_attr_bundle_id.attr,
61
&dev_attr_state.attr,
62
NULL,
63
};
64
65
ATTRIBUTE_GROUPS(bundle);
66
67
static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
68
u8 bundle_id)
69
{
70
struct gb_bundle *bundle;
71
72
list_for_each_entry(bundle, &intf->bundles, links) {
73
if (bundle->id == bundle_id)
74
return bundle;
75
}
76
77
return NULL;
78
}
79
80
static void gb_bundle_release(struct device *dev)
81
{
82
struct gb_bundle *bundle = to_gb_bundle(dev);
83
84
trace_gb_bundle_release(bundle);
85
86
kfree(bundle->state);
87
kfree(bundle->cport_desc);
88
kfree(bundle);
89
}
90
91
#ifdef CONFIG_PM
92
static void gb_bundle_disable_all_connections(struct gb_bundle *bundle)
93
{
94
struct gb_connection *connection;
95
96
list_for_each_entry(connection, &bundle->connections, bundle_links)
97
gb_connection_disable(connection);
98
}
99
100
static void gb_bundle_enable_all_connections(struct gb_bundle *bundle)
101
{
102
struct gb_connection *connection;
103
104
list_for_each_entry(connection, &bundle->connections, bundle_links)
105
gb_connection_enable(connection);
106
}
107
108
static int gb_bundle_suspend(struct device *dev)
109
{
110
struct gb_bundle *bundle = to_gb_bundle(dev);
111
const struct dev_pm_ops *pm = dev->driver->pm;
112
int ret;
113
114
if (pm && pm->runtime_suspend) {
115
ret = pm->runtime_suspend(&bundle->dev);
116
if (ret)
117
return ret;
118
} else {
119
gb_bundle_disable_all_connections(bundle);
120
}
121
122
ret = gb_control_bundle_suspend(bundle->intf->control, bundle->id);
123
if (ret) {
124
if (pm && pm->runtime_resume)
125
ret = pm->runtime_resume(dev);
126
else
127
gb_bundle_enable_all_connections(bundle);
128
129
return ret;
130
}
131
132
return 0;
133
}
134
135
static int gb_bundle_resume(struct device *dev)
136
{
137
struct gb_bundle *bundle = to_gb_bundle(dev);
138
const struct dev_pm_ops *pm = dev->driver->pm;
139
int ret;
140
141
ret = gb_control_bundle_resume(bundle->intf->control, bundle->id);
142
if (ret)
143
return ret;
144
145
if (pm && pm->runtime_resume) {
146
ret = pm->runtime_resume(dev);
147
if (ret)
148
return ret;
149
} else {
150
gb_bundle_enable_all_connections(bundle);
151
}
152
153
return 0;
154
}
155
156
static int gb_bundle_idle(struct device *dev)
157
{
158
pm_runtime_mark_last_busy(dev);
159
pm_request_autosuspend(dev);
160
161
return 0;
162
}
163
#endif
164
165
static const struct dev_pm_ops gb_bundle_pm_ops = {
166
SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle)
167
};
168
169
const struct device_type greybus_bundle_type = {
170
.name = "greybus_bundle",
171
.release = gb_bundle_release,
172
.pm = &gb_bundle_pm_ops,
173
};
174
175
/*
176
* Create a gb_bundle structure to represent a discovered
177
* bundle. Returns a pointer to the new bundle or a null
178
* pointer if a failure occurs due to memory exhaustion.
179
*/
180
struct gb_bundle *gb_bundle_create(struct gb_interface *intf, u8 bundle_id,
181
u8 class)
182
{
183
struct gb_bundle *bundle;
184
185
if (bundle_id == BUNDLE_ID_NONE) {
186
dev_err(&intf->dev, "can't use bundle id %u\n", bundle_id);
187
return NULL;
188
}
189
190
/*
191
* Reject any attempt to reuse a bundle id. We initialize
192
* these serially, so there's no need to worry about keeping
193
* the interface bundle list locked here.
194
*/
195
if (gb_bundle_find(intf, bundle_id)) {
196
dev_err(&intf->dev, "duplicate bundle id %u\n", bundle_id);
197
return NULL;
198
}
199
200
bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
201
if (!bundle)
202
return NULL;
203
204
bundle->intf = intf;
205
bundle->id = bundle_id;
206
bundle->class = class;
207
INIT_LIST_HEAD(&bundle->connections);
208
209
bundle->dev.parent = &intf->dev;
210
bundle->dev.bus = &greybus_bus_type;
211
bundle->dev.type = &greybus_bundle_type;
212
bundle->dev.groups = bundle_groups;
213
bundle->dev.dma_mask = intf->dev.dma_mask;
214
device_initialize(&bundle->dev);
215
dev_set_name(&bundle->dev, "%s.%d", dev_name(&intf->dev), bundle_id);
216
217
list_add(&bundle->links, &intf->bundles);
218
219
trace_gb_bundle_create(bundle);
220
221
return bundle;
222
}
223
224
int gb_bundle_add(struct gb_bundle *bundle)
225
{
226
int ret;
227
228
ret = device_add(&bundle->dev);
229
if (ret) {
230
dev_err(&bundle->dev, "failed to register bundle: %d\n", ret);
231
return ret;
232
}
233
234
trace_gb_bundle_add(bundle);
235
236
return 0;
237
}
238
239
/*
240
* Tear down a previously set up bundle.
241
*/
242
void gb_bundle_destroy(struct gb_bundle *bundle)
243
{
244
trace_gb_bundle_destroy(bundle);
245
246
if (device_is_registered(&bundle->dev))
247
device_del(&bundle->dev);
248
249
list_del(&bundle->links);
250
251
put_device(&bundle->dev);
252
}
253
254