1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2009 Nokia Corporation
4 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 * Some code and ideas taken from drivers/video/omap/ driver
10 #define DSS_SUBSYS_NAME "DISPLAY"
12 #include <linux/kernel.h>
13 #include <linux/kstrtox.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/sysfs.h>
18 #include <video/omapfb_dss.h>
21 static ssize_t
display_name_show(struct omap_dss_device
*dssdev
, char *buf
)
23 return sysfs_emit(buf
, "%s\n",
28 static ssize_t
display_enabled_show(struct omap_dss_device
*dssdev
, char *buf
)
30 return sysfs_emit(buf
, "%d\n",
31 omapdss_device_is_enabled(dssdev
));
34 static ssize_t
display_enabled_store(struct omap_dss_device
*dssdev
,
35 const char *buf
, size_t size
)
40 r
= kstrtobool(buf
, &enable
);
44 if (enable
== omapdss_device_is_enabled(dssdev
))
47 if (omapdss_device_is_connected(dssdev
) == false)
51 r
= dssdev
->driver
->enable(dssdev
);
55 dssdev
->driver
->disable(dssdev
);
61 static ssize_t
display_tear_show(struct omap_dss_device
*dssdev
, char *buf
)
63 return sysfs_emit(buf
, "%d\n",
64 dssdev
->driver
->get_te
?
65 dssdev
->driver
->get_te(dssdev
) : 0);
68 static ssize_t
display_tear_store(struct omap_dss_device
*dssdev
,
69 const char *buf
, size_t size
)
74 if (!dssdev
->driver
->enable_te
|| !dssdev
->driver
->get_te
)
77 r
= kstrtobool(buf
, &te
);
81 r
= dssdev
->driver
->enable_te(dssdev
, te
);
88 static ssize_t
display_timings_show(struct omap_dss_device
*dssdev
, char *buf
)
90 struct omap_video_timings t
;
92 if (!dssdev
->driver
->get_timings
)
95 dssdev
->driver
->get_timings(dssdev
, &t
);
97 return sysfs_emit(buf
, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
99 t
.x_res
, t
.hfp
, t
.hbp
, t
.hsw
,
100 t
.y_res
, t
.vfp
, t
.vbp
, t
.vsw
);
103 static ssize_t
display_timings_store(struct omap_dss_device
*dssdev
,
104 const char *buf
, size_t size
)
106 struct omap_video_timings t
= dssdev
->panel
.timings
;
109 if (!dssdev
->driver
->set_timings
|| !dssdev
->driver
->check_timings
)
113 #ifdef CONFIG_FB_OMAP2_DSS_VENC
114 if (strncmp("pal", buf
, 3) == 0) {
115 t
= omap_dss_pal_timings
;
117 } else if (strncmp("ntsc", buf
, 4) == 0) {
118 t
= omap_dss_ntsc_timings
;
122 if (!found
&& sscanf(buf
, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
124 &t
.x_res
, &t
.hfp
, &t
.hbp
, &t
.hsw
,
125 &t
.y_res
, &t
.vfp
, &t
.vbp
, &t
.vsw
) != 9)
128 r
= dssdev
->driver
->check_timings(dssdev
, &t
);
132 dssdev
->driver
->disable(dssdev
);
133 dssdev
->driver
->set_timings(dssdev
, &t
);
134 r
= dssdev
->driver
->enable(dssdev
);
141 static ssize_t
display_rotate_show(struct omap_dss_device
*dssdev
, char *buf
)
144 if (!dssdev
->driver
->get_rotate
)
146 rotate
= dssdev
->driver
->get_rotate(dssdev
);
147 return sysfs_emit(buf
, "%u\n", rotate
);
150 static ssize_t
display_rotate_store(struct omap_dss_device
*dssdev
,
151 const char *buf
, size_t size
)
155 if (!dssdev
->driver
->set_rotate
|| !dssdev
->driver
->get_rotate
)
158 r
= kstrtoint(buf
, 0, &rot
);
162 r
= dssdev
->driver
->set_rotate(dssdev
, rot
);
169 static ssize_t
display_mirror_show(struct omap_dss_device
*dssdev
, char *buf
)
172 if (!dssdev
->driver
->get_mirror
)
174 mirror
= dssdev
->driver
->get_mirror(dssdev
);
175 return sysfs_emit(buf
, "%u\n", mirror
);
178 static ssize_t
display_mirror_store(struct omap_dss_device
*dssdev
,
179 const char *buf
, size_t size
)
184 if (!dssdev
->driver
->set_mirror
|| !dssdev
->driver
->get_mirror
)
187 r
= kstrtobool(buf
, &mirror
);
191 r
= dssdev
->driver
->set_mirror(dssdev
, mirror
);
198 static ssize_t
display_wss_show(struct omap_dss_device
*dssdev
, char *buf
)
202 if (!dssdev
->driver
->get_wss
)
205 wss
= dssdev
->driver
->get_wss(dssdev
);
207 return sysfs_emit(buf
, "0x%05x\n", wss
);
210 static ssize_t
display_wss_store(struct omap_dss_device
*dssdev
,
211 const char *buf
, size_t size
)
216 if (!dssdev
->driver
->get_wss
|| !dssdev
->driver
->set_wss
)
219 r
= kstrtou32(buf
, 0, &wss
);
226 r
= dssdev
->driver
->set_wss(dssdev
, wss
);
233 struct 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);
239 #define DISPLAY_ATTR(_name, _mode, _show, _store) \
240 struct display_attribute display_attr_##_name = \
241 __ATTR(_name, _mode, _show, _store)
243 static DISPLAY_ATTR(name
, S_IRUGO
, display_name_show
, NULL
);
244 static DISPLAY_ATTR(display_name
, S_IRUGO
, display_name_show
, NULL
);
245 static DISPLAY_ATTR(enabled
, S_IRUGO
|S_IWUSR
,
246 display_enabled_show
, display_enabled_store
);
247 static DISPLAY_ATTR(tear_elim
, S_IRUGO
|S_IWUSR
,
248 display_tear_show
, display_tear_store
);
249 static DISPLAY_ATTR(timings
, S_IRUGO
|S_IWUSR
,
250 display_timings_show
, display_timings_store
);
251 static DISPLAY_ATTR(rotate
, S_IRUGO
|S_IWUSR
,
252 display_rotate_show
, display_rotate_store
);
253 static DISPLAY_ATTR(mirror
, S_IRUGO
|S_IWUSR
,
254 display_mirror_show
, display_mirror_store
);
255 static DISPLAY_ATTR(wss
, S_IRUGO
|S_IWUSR
,
256 display_wss_show
, display_wss_store
);
258 static 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
,
269 ATTRIBUTE_GROUPS(display_sysfs
);
271 static ssize_t
display_attr_show(struct kobject
*kobj
, struct attribute
*attr
,
274 struct omap_dss_device
*dssdev
;
275 struct display_attribute
*display_attr
;
277 dssdev
= container_of(kobj
, struct omap_dss_device
, kobj
);
278 display_attr
= container_of(attr
, struct display_attribute
, attr
);
280 if (!display_attr
->show
)
283 return display_attr
->show(dssdev
, buf
);
286 static ssize_t
display_attr_store(struct kobject
*kobj
, struct attribute
*attr
,
287 const char *buf
, size_t size
)
289 struct omap_dss_device
*dssdev
;
290 struct display_attribute
*display_attr
;
292 dssdev
= container_of(kobj
, struct omap_dss_device
, kobj
);
293 display_attr
= container_of(attr
, struct display_attribute
, attr
);
295 if (!display_attr
->store
)
298 return display_attr
->store(dssdev
, buf
, size
);
301 static const struct sysfs_ops display_sysfs_ops
= {
302 .show
= display_attr_show
,
303 .store
= display_attr_store
,
306 static struct kobj_type display_ktype
= {
307 .sysfs_ops
= &display_sysfs_ops
,
308 .default_groups
= display_sysfs_groups
,
311 int display_init_sysfs(struct platform_device
*pdev
)
313 struct omap_dss_device
*dssdev
= NULL
;
316 for_each_dss_dev(dssdev
) {
317 r
= kobject_init_and_add(&dssdev
->kobj
, &display_ktype
,
318 &pdev
->dev
.kobj
, "%s", dssdev
->alias
);
320 DSSERR("failed to create sysfs files\n");
321 omap_dss_put_device(dssdev
);
329 display_uninit_sysfs(pdev
);
334 void display_uninit_sysfs(struct platform_device
*pdev
)
336 struct omap_dss_device
*dssdev
= NULL
;
338 for_each_dss_dev(dssdev
) {
339 if (kobject_name(&dssdev
->kobj
) == NULL
)
342 kobject_del(&dssdev
->kobj
);
343 kobject_put(&dssdev
->kobj
);
345 memset(&dssdev
->kobj
, 0, sizeof(dssdev
->kobj
));