2 * Copyright (C) 2013 Google, Inc.
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.
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.
15 #include <video/adf_client.h>
19 #include "adf_sysfs.h"
21 static struct class *adf_class;
23 static DEFINE_IDR(adf_minors);
25 #define dev_to_adf_interface(p) \
26 adf_obj_to_interface(container_of(p, struct adf_obj, dev))
28 static ssize_t dpms_state_show(struct device *dev,
29 struct device_attribute *attr, char *buf)
31 struct adf_interface *intf = dev_to_adf_interface(dev);
32 return scnprintf(buf, PAGE_SIZE, "%u\n",
33 adf_interface_dpms_state(intf));
36 static ssize_t dpms_state_store(struct device *dev,
37 struct device_attribute *attr, const char *buf, size_t count)
39 struct adf_interface *intf = dev_to_adf_interface(dev);
43 err = kstrtou8(buf, 0, &dpms_state);
47 err = adf_interface_blank(intf, dpms_state);
54 static ssize_t current_mode_show(struct device *dev,
55 struct device_attribute *attr, char *buf)
57 struct adf_interface *intf = dev_to_adf_interface(dev);
58 struct drm_mode_modeinfo mode;
60 adf_interface_current_mode(intf, &mode);
63 return scnprintf(buf, PAGE_SIZE, "%s\n", mode.name);
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" : "");
71 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
74 struct adf_interface *intf = dev_to_adf_interface(dev);
75 return scnprintf(buf, PAGE_SIZE, "%s\n",
76 adf_interface_type_str(intf));
79 static ssize_t vsync_timestamp_show(struct device *dev,
80 struct device_attribute *attr, char *buf)
82 struct adf_interface *intf = dev_to_adf_interface(dev);
86 read_lock_irqsave(&intf->vsync_lock, flags);
87 memcpy(×tamp, &intf->vsync_timestamp, sizeof(timestamp));
88 read_unlock_irqrestore(&intf->vsync_lock, flags);
90 return scnprintf(buf, PAGE_SIZE, "%llu\n", ktime_to_ns(timestamp));
93 static ssize_t hotplug_detect_show(struct device *dev,
94 struct device_attribute *attr, char *buf)
96 struct adf_interface *intf = dev_to_adf_interface(dev);
97 return scnprintf(buf, PAGE_SIZE, "%u\n", intf->hotplug_detect);
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),
105 __ATTR_RO(vsync_timestamp),
108 static char *adf_devnode(struct device *dev, umode_t *mode)
110 return kasprintf(GFP_KERNEL, "adf/%s", dev_name(dev));
113 int adf_obj_sysfs_init(struct adf_obj *obj, struct device *parent)
115 int ret = idr_alloc(&adf_minors, obj, 0, 0, GFP_KERNEL);
117 pr_err("%s: allocating adf minor failed: %d\n", __func__,
123 obj->dev.parent = parent;
124 obj->dev.class = adf_class;
125 obj->dev.devt = MKDEV(adf_major, obj->minor);
127 ret = device_register(&obj->dev);
129 pr_err("%s: registering adf object failed: %d\n", __func__,
131 goto err_device_register;
137 idr_remove(&adf_minors, obj->minor);
141 static char *adf_device_devnode(struct device *dev, umode_t *mode,
142 kuid_t *uid, kgid_t *gid)
144 struct adf_obj *obj = container_of(dev, struct adf_obj, dev);
145 return kasprintf(GFP_KERNEL, "adf/%s/device", obj->name);
148 static char *adf_interface_devnode(struct device *dev, umode_t *mode,
149 kuid_t *uid, kgid_t *gid)
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);
158 static char *adf_overlay_engine_devnode(struct device *dev, umode_t *mode,
159 kuid_t *uid, kgid_t *gid)
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);
168 static void adf_noop_release(struct device *dev)
172 static struct device_type adf_device_type = {
173 .name = "adf_device",
174 .devnode = adf_device_devnode,
175 .release = adf_noop_release,
178 static struct device_type adf_interface_type = {
179 .name = "adf_interface",
180 .devnode = adf_interface_devnode,
181 .release = adf_noop_release,
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,
190 int adf_device_sysfs_init(struct adf_device *dev)
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);
197 int adf_interface_sysfs_init(struct adf_interface *intf)
199 struct adf_device *parent = adf_interface_parent(intf);
203 intf->base.dev.type = &adf_interface_type;
204 dev_set_name(&intf->base.dev, "%s-interface%d", parent->base.name,
207 ret = adf_obj_sysfs_init(&intf->base, &parent->base.dev);
211 for (i = 0; i < ARRAY_SIZE(adf_interface_attrs); i++) {
212 ret = device_create_file(&intf->base.dev,
213 &adf_interface_attrs[i]);
215 dev_err(&intf->base.dev, "creating sysfs attribute %s failed: %d\n",
216 adf_interface_attrs[i].attr.name, ret);
224 for (j = 0; j < i; j++)
225 device_remove_file(&intf->base.dev, &adf_interface_attrs[j]);
229 int adf_overlay_engine_sysfs_init(struct adf_overlay_engine *eng)
231 struct adf_device *parent = adf_overlay_engine_parent(eng);
233 eng->base.dev.type = &adf_overlay_engine_type;
234 dev_set_name(&eng->base.dev, "%s-overlay-engine%d", parent->base.name,
237 return adf_obj_sysfs_init(&eng->base, &parent->base.dev);
240 struct adf_obj *adf_obj_sysfs_find(int minor)
242 return idr_find(&adf_minors, minor);
245 void adf_obj_sysfs_destroy(struct adf_obj *obj)
247 idr_remove(&adf_minors, obj->minor);
248 device_unregister(&obj->dev);
251 void adf_device_sysfs_destroy(struct adf_device *dev)
253 adf_obj_sysfs_destroy(&dev->base);
256 void adf_interface_sysfs_destroy(struct adf_interface *intf)
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);
265 void adf_overlay_engine_sysfs_destroy(struct adf_overlay_engine *eng)
267 adf_obj_sysfs_destroy(&eng->base);
270 int adf_sysfs_init(void)
275 class = class_create(THIS_MODULE, "adf");
277 ret = PTR_ERR(class);
278 pr_err("%s: creating class failed: %d\n", __func__, ret);
282 ret = register_chrdev(0, "adf", &adf_fops);
284 pr_err("%s: registering device failed: %d\n", __func__, ret);
288 class->devnode = adf_devnode;
294 class_destroy(adf_class);
298 void adf_sysfs_destroy(void)
300 idr_destroy(&adf_minors);
301 class_destroy(adf_class);