Merge branches 'pm-cpuidle', 'pm-core' and 'pm-sleep'
[linux-block.git] / drivers / video / fbdev / omap2 / omapfb / dss / display-sysfs.c
CommitLineData
caab277b 1// SPDX-License-Identifier: GPL-2.0-only
f76ee892
TV
2/*
3 * Copyright (C) 2009 Nokia Corporation
4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
5 *
6 * Some code and ideas taken from drivers/video/omap/ driver
7 * by Imre Deak.
f76ee892
TV
8 */
9
10#define DSS_SUBSYS_NAME "DISPLAY"
11
12#include <linux/kernel.h>
ee9fffdc 13#include <linux/kstrtox.h>
f76ee892
TV
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/sysfs.h>
17
62d9e44e 18#include <video/omapfb_dss.h>
f76ee892
TV
19#include "dss.h"
20
21static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
22{
cc83ff24 23 return sysfs_emit(buf, "%s\n",
f76ee892
TV
24 dssdev->name ?
25 dssdev->name : "");
26}
27
28static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
29{
cc83ff24 30 return sysfs_emit(buf, "%d\n",
f76ee892
TV
31 omapdss_device_is_enabled(dssdev));
32}
33
34static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
35 const char *buf, size_t size)
36{
37 int r;
38 bool enable;
39
ee9fffdc 40 r = kstrtobool(buf, &enable);
f76ee892
TV
41 if (r)
42 return r;
43
44 if (enable == omapdss_device_is_enabled(dssdev))
45 return size;
46
47 if (omapdss_device_is_connected(dssdev) == false)
48 return -ENODEV;
49
50 if (enable) {
51 r = dssdev->driver->enable(dssdev);
52 if (r)
53 return r;
54 } else {
55 dssdev->driver->disable(dssdev);
56 }
57
58 return size;
59}
60
61static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
62{
cc83ff24 63 return sysfs_emit(buf, "%d\n",
f76ee892
TV
64 dssdev->driver->get_te ?
65 dssdev->driver->get_te(dssdev) : 0);
66}
67
68static ssize_t display_tear_store(struct omap_dss_device *dssdev,
69 const char *buf, size_t size)
70{
71 int r;
72 bool te;
73
74 if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
75 return -ENOENT;
76
ee9fffdc 77 r = kstrtobool(buf, &te);
f76ee892
TV
78 if (r)
79 return r;
80
81 r = dssdev->driver->enable_te(dssdev, te);
82 if (r)
83 return r;
84
85 return size;
86}
87
88static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
89{
90 struct omap_video_timings t;
91
92 if (!dssdev->driver->get_timings)
93 return -ENOENT;
94
95 dssdev->driver->get_timings(dssdev, &t);
96
cc83ff24 97 return sysfs_emit(buf, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
f76ee892
TV
98 t.pixelclock,
99 t.x_res, t.hfp, t.hbp, t.hsw,
100 t.y_res, t.vfp, t.vbp, t.vsw);
101}
102
103static ssize_t display_timings_store(struct omap_dss_device *dssdev,
104 const char *buf, size_t size)
105{
106 struct omap_video_timings t = dssdev->panel.timings;
107 int r, found;
108
109 if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
110 return -ENOENT;
111
112 found = 0;
35b522cf 113#ifdef CONFIG_FB_OMAP2_DSS_VENC
f76ee892
TV
114 if (strncmp("pal", buf, 3) == 0) {
115 t = omap_dss_pal_timings;
116 found = 1;
117 } else if (strncmp("ntsc", buf, 4) == 0) {
118 t = omap_dss_ntsc_timings;
119 found = 1;
120 }
121#endif
122 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
123 &t.pixelclock,
124 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
125 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
126 return -EINVAL;
127
128 r = dssdev->driver->check_timings(dssdev, &t);
129 if (r)
130 return r;
131
132 dssdev->driver->disable(dssdev);
133 dssdev->driver->set_timings(dssdev, &t);
134 r = dssdev->driver->enable(dssdev);
135 if (r)
136 return r;
137
138 return size;
139}
140
141static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
142{
143 int rotate;
144 if (!dssdev->driver->get_rotate)
145 return -ENOENT;
146 rotate = dssdev->driver->get_rotate(dssdev);
cc83ff24 147 return sysfs_emit(buf, "%u\n", rotate);
f76ee892
TV
148}
149
150static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
151 const char *buf, size_t size)
152{
153 int rot, r;
154
155 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
156 return -ENOENT;
157
158 r = kstrtoint(buf, 0, &rot);
159 if (r)
160 return r;
161
162 r = dssdev->driver->set_rotate(dssdev, rot);
163 if (r)
164 return r;
165
166 return size;
167}
168
169static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
170{
171 int mirror;
172 if (!dssdev->driver->get_mirror)
173 return -ENOENT;
174 mirror = dssdev->driver->get_mirror(dssdev);
cc83ff24 175 return sysfs_emit(buf, "%u\n", mirror);
f76ee892
TV
176}
177
178static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
179 const char *buf, size_t size)
180{
181 int r;
182 bool mirror;
183
184 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
185 return -ENOENT;
186
ee9fffdc 187 r = kstrtobool(buf, &mirror);
f76ee892
TV
188 if (r)
189 return r;
190
191 r = dssdev->driver->set_mirror(dssdev, mirror);
192 if (r)
193 return r;
194
195 return size;
196}
197
198static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
199{
200 unsigned int wss;
201
202 if (!dssdev->driver->get_wss)
203 return -ENOENT;
204
205 wss = dssdev->driver->get_wss(dssdev);
206
cc83ff24 207 return sysfs_emit(buf, "0x%05x\n", wss);
f76ee892
TV
208}
209
210static ssize_t display_wss_store(struct omap_dss_device *dssdev,
211 const char *buf, size_t size)
212{
213 u32 wss;
214 int r;
215
216 if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
217 return -ENOENT;
218
219 r = kstrtou32(buf, 0, &wss);
220 if (r)
221 return r;
222
223 if (wss > 0xfffff)
224 return -EINVAL;
225
226 r = dssdev->driver->set_wss(dssdev, wss);
227 if (r)
228 return r;
229
230 return size;
231}
232
233struct display_attribute {
234 struct attribute attr;
235 ssize_t (*show)(struct omap_dss_device *, char *);
236 ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
237};
238
239#define DISPLAY_ATTR(_name, _mode, _show, _store) \
240 struct display_attribute display_attr_##_name = \
241 __ATTR(_name, _mode, _show, _store)
242
243static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
244static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
245static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
246 display_enabled_show, display_enabled_store);
247static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
248 display_tear_show, display_tear_store);
249static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
250 display_timings_show, display_timings_store);
251static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
252 display_rotate_show, display_rotate_store);
253static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
254 display_mirror_show, display_mirror_store);
255static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
256 display_wss_show, display_wss_store);
257
258static struct attribute *display_sysfs_attrs[] = {
259 &display_attr_name.attr,
260 &display_attr_display_name.attr,
261 &display_attr_enabled.attr,
262 &display_attr_tear_elim.attr,
263 &display_attr_timings.attr,
264 &display_attr_rotate.attr,
265 &display_attr_mirror.attr,
266 &display_attr_wss.attr,
267 NULL
268};
19d10a83 269ATTRIBUTE_GROUPS(display_sysfs);
f76ee892
TV
270
271static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
272 char *buf)
273{
274 struct omap_dss_device *dssdev;
275 struct display_attribute *display_attr;
276
277 dssdev = container_of(kobj, struct omap_dss_device, kobj);
278 display_attr = container_of(attr, struct display_attribute, attr);
279
280 if (!display_attr->show)
281 return -ENOENT;
282
283 return display_attr->show(dssdev, buf);
284}
285
286static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
287 const char *buf, size_t size)
288{
289 struct omap_dss_device *dssdev;
290 struct display_attribute *display_attr;
291
292 dssdev = container_of(kobj, struct omap_dss_device, kobj);
293 display_attr = container_of(attr, struct display_attribute, attr);
294
295 if (!display_attr->store)
296 return -ENOENT;
297
298 return display_attr->store(dssdev, buf, size);
299}
300
301static const struct sysfs_ops display_sysfs_ops = {
302 .show = display_attr_show,
303 .store = display_attr_store,
304};
305
306static struct kobj_type display_ktype = {
307 .sysfs_ops = &display_sysfs_ops,
19d10a83 308 .default_groups = display_sysfs_groups,
f76ee892
TV
309};
310
311int display_init_sysfs(struct platform_device *pdev)
312{
313 struct omap_dss_device *dssdev = NULL;
314 int r;
315
316 for_each_dss_dev(dssdev) {
317 r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
318 &pdev->dev.kobj, "%s", dssdev->alias);
319 if (r) {
320 DSSERR("failed to create sysfs files\n");
321 omap_dss_put_device(dssdev);
322 goto err;
323 }
324 }
325
326 return 0;
327
328err:
329 display_uninit_sysfs(pdev);
330
331 return r;
332}
333
334void display_uninit_sysfs(struct platform_device *pdev)
335{
336 struct omap_dss_device *dssdev = NULL;
337
338 for_each_dss_dev(dssdev) {
339 if (kobject_name(&dssdev->kobj) == NULL)
340 continue;
341
342 kobject_del(&dssdev->kobj);
343 kobject_put(&dssdev->kobj);
344
345 memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
346 }
347}