076ccbd0cd888fca4d7a210489426f6f493a2c67
[firefly-linux-kernel-4.4.55.git] / drivers / video / adf / adf_sysfs.c
1 /*
2  * Copyright (C) 2013 Google, Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <video/adf_client.h>
16
17 #include "adf.h"
18 #include "adf_fops.h"
19 #include "adf_sysfs.h"
20
21 static struct class *adf_class;
22 static int adf_major;
23 static DEFINE_IDR(adf_minors);
24
25 #define dev_to_adf_interface(p) \
26         adf_obj_to_interface(container_of(p, struct adf_obj, dev))
27
28 static ssize_t dpms_state_show(struct device *dev,
29                 struct device_attribute *attr, char *buf)
30 {
31         struct adf_interface *intf = dev_to_adf_interface(dev);
32         return scnprintf(buf, PAGE_SIZE, "%u\n",
33                         adf_interface_dpms_state(intf));
34 }
35
36 static ssize_t dpms_state_store(struct device *dev,
37                 struct device_attribute *attr, const char *buf, size_t count)
38 {
39         struct adf_interface *intf = dev_to_adf_interface(dev);
40         u8 dpms_state;
41         int err;
42
43         err = kstrtou8(buf, 0, &dpms_state);
44         if (err < 0)
45                 return err;
46
47         err = adf_interface_blank(intf, dpms_state);
48         if (err < 0)
49                 return err;
50
51         return count;
52 }
53
54 static ssize_t current_mode_show(struct device *dev,
55                 struct device_attribute *attr, char *buf)
56 {
57         struct adf_interface *intf = dev_to_adf_interface(dev);
58         struct drm_mode_modeinfo mode;
59
60         adf_interface_current_mode(intf, &mode);
61
62         if (mode.name[0]) {
63                 return scnprintf(buf, PAGE_SIZE, "%s\n", mode.name);
64         } else {
65                 bool interlaced = !!(mode.flags & DRM_MODE_FLAG_INTERLACE);
66                 return scnprintf(buf, PAGE_SIZE, "%ux%u%s\n", mode.hdisplay,
67                                 mode.vdisplay, interlaced ? "i" : "");
68         }
69 }
70
71 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
72                         char *buf)
73 {
74         struct adf_interface *intf = dev_to_adf_interface(dev);
75         return scnprintf(buf, PAGE_SIZE, "%s\n",
76                         adf_interface_type_str(intf));
77 }
78
79 static ssize_t vsync_timestamp_show(struct device *dev,
80                 struct device_attribute *attr, char *buf)
81 {
82         struct adf_interface *intf = dev_to_adf_interface(dev);
83         ktime_t timestamp;
84         unsigned long flags;
85
86         read_lock_irqsave(&intf->vsync_lock, flags);
87         memcpy(&timestamp, &intf->vsync_timestamp, sizeof(timestamp));
88         read_unlock_irqrestore(&intf->vsync_lock, flags);
89
90         return scnprintf(buf, PAGE_SIZE, "%llu\n", ktime_to_ns(timestamp));
91 }
92
93 static ssize_t hotplug_detect_show(struct device *dev,
94                 struct device_attribute *attr, char *buf)
95 {
96         struct adf_interface *intf = dev_to_adf_interface(dev);
97         return scnprintf(buf, PAGE_SIZE, "%u\n", intf->hotplug_detect);
98 }
99
100 static struct device_attribute adf_interface_attrs[] = {
101         __ATTR(dpms_state, S_IRUGO|S_IWUSR, dpms_state_show, dpms_state_store),
102         __ATTR_RO(current_mode),
103         __ATTR_RO(hotplug_detect),
104         __ATTR_RO(type),
105         __ATTR_RO(vsync_timestamp),
106 };
107
108 static char *adf_devnode(struct device *dev, umode_t *mode)
109 {
110         return kasprintf(GFP_KERNEL, "adf/%s", dev_name(dev));
111 }
112
113 int adf_obj_sysfs_init(struct adf_obj *obj, struct device *parent)
114 {
115         int ret = idr_alloc(&adf_minors, obj, 0, 0, GFP_KERNEL);
116         if (ret < 0) {
117                 pr_err("%s: allocating adf minor failed: %d\n", __func__,
118                                 ret);
119                 return ret;
120         }
121
122         obj->minor = ret;
123         obj->dev.parent = parent;
124         obj->dev.class = adf_class;
125         obj->dev.devt = MKDEV(adf_major, obj->minor);
126
127         ret = device_register(&obj->dev);
128         if (ret < 0) {
129                 pr_err("%s: registering adf object failed: %d\n", __func__,
130                                 ret);
131                 goto err_device_register;
132         }
133
134         return 0;
135
136 err_device_register:
137         idr_remove(&adf_minors, obj->minor);
138         return ret;
139 }
140
141 static char *adf_device_devnode(struct device *dev, umode_t *mode,
142                 kuid_t *uid, kgid_t *gid)
143 {
144         struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
145         return kasprintf(GFP_KERNEL, "adf/%s/device", obj->name);
146 }
147
148 static char *adf_interface_devnode(struct device *dev, umode_t *mode,
149                 kuid_t *uid, kgid_t *gid)
150 {
151         struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
152         struct adf_interface *intf = adf_obj_to_interface(obj);
153         struct adf_device *parent = adf_interface_parent(intf);
154         return kasprintf(GFP_KERNEL, "adf/%s/interface%d",
155                         parent->base.name, intf->base.id);
156 }
157
158 static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
159                 kuid_t *uid, kgid_t *gid)
160 {
161         struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
162         struct adf_overlay_engine *eng = adf_obj_to_overlay_engine(obj);
163         struct adf_device *parent = adf_overlay_engine_parent(eng);
164         return kasprintf(GFP_KERNEL, "adf/%s/overlay-engine%d",
165                         parent->base.name, eng->base.id);
166 }
167
168 static void adf_noop_release(struct device *dev)
169 {
170 }
171
172 static struct device_type adf_device_type = {
173         .name = "adf_device",
174         .devnode = adf_device_devnode,
175         .release = adf_noop_release,
176 };
177
178 static struct device_type adf_interface_type = {
179         .name = "adf_interface",
180         .devnode = adf_interface_devnode,
181         .release = adf_noop_release,
182 };
183
184 static struct device_type adf_overlay_engine_type = {
185         .name = "adf_overlay_engine",
186         .devnode = adf_overlay_engine_devnode,
187         .release = adf_noop_release,
188 };
189
190 int adf_device_sysfs_init(struct adf_device *dev)
191 {
192         dev->base.dev.type = &adf_device_type;
193         dev_set_name(&dev->base.dev, "%s", dev->base.name);
194         return adf_obj_sysfs_init(&dev->base, dev->dev);
195 }
196
197 int adf_interface_sysfs_init(struct adf_interface *intf)
198 {
199         struct adf_device *parent = adf_interface_parent(intf);
200         size_t i, j;
201         int ret;
202
203         intf->base.dev.type = &adf_interface_type;
204         dev_set_name(&intf->base.dev, "%s-interface%d", parent->base.name,
205                         intf->base.id);
206
207         ret = adf_obj_sysfs_init(&intf->base, &parent->base.dev);
208         if (ret < 0)
209                 return ret;
210
211         for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++) {
212                 ret = device_create_file(&intf->base.dev,
213                                 &adf_interface_attrs[i]);
214                 if (ret < 0) {
215                         dev_err(&intf->base.dev, "creating sysfs attribute %s failed: %d\n",
216                                         adf_interface_attrs[i].attr.name, ret);
217                         goto err;
218                 }
219         }
220
221         return 0;
222
223 err:
224         for (j = 0; j < i; j++)
225                 device_remove_file(&intf->base.dev, &adf_interface_attrs[j]);
226         return ret;
227 }
228
229 int adf_overlay_engine_sysfs_init(struct adf_overlay_engine *eng)
230 {
231         struct adf_device *parent = adf_overlay_engine_parent(eng);
232
233         eng->base.dev.type = &adf_overlay_engine_type;
234         dev_set_name(&eng->base.dev, "%s-overlay-engine%d", parent->base.name,
235                         eng->base.id);
236
237         return adf_obj_sysfs_init(&eng->base, &parent->base.dev);
238 }
239
240 struct adf_obj *adf_obj_sysfs_find(int minor)
241 {
242         return idr_find(&adf_minors, minor);
243 }
244
245 void adf_obj_sysfs_destroy(struct adf_obj *obj)
246 {
247         idr_remove(&adf_minors, obj->minor);
248         device_unregister(&obj->dev);
249 }
250
251 void adf_device_sysfs_destroy(struct adf_device *dev)
252 {
253         adf_obj_sysfs_destroy(&dev->base);
254 }
255
256 void adf_interface_sysfs_destroy(struct adf_interface *intf)
257 {
258         size_t i;
259
260         for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++)
261                 device_remove_file(&intf->base.dev, &adf_interface_attrs[i]);
262         adf_obj_sysfs_destroy(&intf->base);
263 }
264
265 void adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine *eng)
266 {
267         adf_obj_sysfs_destroy(&eng->base);
268 }
269
270 int adf_sysfs_init(void)
271 {
272         struct class *class;
273         int ret;
274
275         class = class_create(THIS_MODULE, "adf");
276         if (IS_ERR(class)) {
277                 ret = PTR_ERR(class);
278                 pr_err("%s: creating class failed: %d\n", __func__, ret);
279                 return ret;
280         }
281
282         ret = register_chrdev(0, "adf", &adf_fops);
283         if (ret < 0) {
284                 pr_err("%s: registering device failed: %d\n", __func__, ret);
285                 goto err_chrdev;
286         }
287
288         class->devnode = adf_devnode;
289         adf_class = class;
290         adf_major = ret;
291         return 0;
292
293 err_chrdev:
294         class_destroy(adf_class);
295         return ret;
296 }
297
298 void adf_sysfs_destroy(void)
299 {
300         idr_destroy(&adf_minors);
301         class_destroy(adf_class);
302 }