0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define DSS_SUBSYS_NAME "DISPLAY"
0011
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/sysfs.h>
0016
0017 #include <video/omapfb_dss.h>
0018 #include "dss.h"
0019
0020 static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
0021 {
0022 return sysfs_emit(buf, "%s\n",
0023 dssdev->name ?
0024 dssdev->name : "");
0025 }
0026
0027 static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
0028 {
0029 return sysfs_emit(buf, "%d\n",
0030 omapdss_device_is_enabled(dssdev));
0031 }
0032
0033 static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
0034 const char *buf, size_t size)
0035 {
0036 int r;
0037 bool enable;
0038
0039 r = strtobool(buf, &enable);
0040 if (r)
0041 return r;
0042
0043 if (enable == omapdss_device_is_enabled(dssdev))
0044 return size;
0045
0046 if (omapdss_device_is_connected(dssdev) == false)
0047 return -ENODEV;
0048
0049 if (enable) {
0050 r = dssdev->driver->enable(dssdev);
0051 if (r)
0052 return r;
0053 } else {
0054 dssdev->driver->disable(dssdev);
0055 }
0056
0057 return size;
0058 }
0059
0060 static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
0061 {
0062 return sysfs_emit(buf, "%d\n",
0063 dssdev->driver->get_te ?
0064 dssdev->driver->get_te(dssdev) : 0);
0065 }
0066
0067 static ssize_t display_tear_store(struct omap_dss_device *dssdev,
0068 const char *buf, size_t size)
0069 {
0070 int r;
0071 bool te;
0072
0073 if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
0074 return -ENOENT;
0075
0076 r = strtobool(buf, &te);
0077 if (r)
0078 return r;
0079
0080 r = dssdev->driver->enable_te(dssdev, te);
0081 if (r)
0082 return r;
0083
0084 return size;
0085 }
0086
0087 static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
0088 {
0089 struct omap_video_timings t;
0090
0091 if (!dssdev->driver->get_timings)
0092 return -ENOENT;
0093
0094 dssdev->driver->get_timings(dssdev, &t);
0095
0096 return sysfs_emit(buf, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
0097 t.pixelclock,
0098 t.x_res, t.hfp, t.hbp, t.hsw,
0099 t.y_res, t.vfp, t.vbp, t.vsw);
0100 }
0101
0102 static ssize_t display_timings_store(struct omap_dss_device *dssdev,
0103 const char *buf, size_t size)
0104 {
0105 struct omap_video_timings t = dssdev->panel.timings;
0106 int r, found;
0107
0108 if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
0109 return -ENOENT;
0110
0111 found = 0;
0112 #ifdef CONFIG_FB_OMAP2_DSS_VENC
0113 if (strncmp("pal", buf, 3) == 0) {
0114 t = omap_dss_pal_timings;
0115 found = 1;
0116 } else if (strncmp("ntsc", buf, 4) == 0) {
0117 t = omap_dss_ntsc_timings;
0118 found = 1;
0119 }
0120 #endif
0121 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
0122 &t.pixelclock,
0123 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
0124 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
0125 return -EINVAL;
0126
0127 r = dssdev->driver->check_timings(dssdev, &t);
0128 if (r)
0129 return r;
0130
0131 dssdev->driver->disable(dssdev);
0132 dssdev->driver->set_timings(dssdev, &t);
0133 r = dssdev->driver->enable(dssdev);
0134 if (r)
0135 return r;
0136
0137 return size;
0138 }
0139
0140 static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
0141 {
0142 int rotate;
0143 if (!dssdev->driver->get_rotate)
0144 return -ENOENT;
0145 rotate = dssdev->driver->get_rotate(dssdev);
0146 return sysfs_emit(buf, "%u\n", rotate);
0147 }
0148
0149 static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
0150 const char *buf, size_t size)
0151 {
0152 int rot, r;
0153
0154 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
0155 return -ENOENT;
0156
0157 r = kstrtoint(buf, 0, &rot);
0158 if (r)
0159 return r;
0160
0161 r = dssdev->driver->set_rotate(dssdev, rot);
0162 if (r)
0163 return r;
0164
0165 return size;
0166 }
0167
0168 static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
0169 {
0170 int mirror;
0171 if (!dssdev->driver->get_mirror)
0172 return -ENOENT;
0173 mirror = dssdev->driver->get_mirror(dssdev);
0174 return sysfs_emit(buf, "%u\n", mirror);
0175 }
0176
0177 static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
0178 const char *buf, size_t size)
0179 {
0180 int r;
0181 bool mirror;
0182
0183 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
0184 return -ENOENT;
0185
0186 r = strtobool(buf, &mirror);
0187 if (r)
0188 return r;
0189
0190 r = dssdev->driver->set_mirror(dssdev, mirror);
0191 if (r)
0192 return r;
0193
0194 return size;
0195 }
0196
0197 static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
0198 {
0199 unsigned int wss;
0200
0201 if (!dssdev->driver->get_wss)
0202 return -ENOENT;
0203
0204 wss = dssdev->driver->get_wss(dssdev);
0205
0206 return sysfs_emit(buf, "0x%05x\n", wss);
0207 }
0208
0209 static ssize_t display_wss_store(struct omap_dss_device *dssdev,
0210 const char *buf, size_t size)
0211 {
0212 u32 wss;
0213 int r;
0214
0215 if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
0216 return -ENOENT;
0217
0218 r = kstrtou32(buf, 0, &wss);
0219 if (r)
0220 return r;
0221
0222 if (wss > 0xfffff)
0223 return -EINVAL;
0224
0225 r = dssdev->driver->set_wss(dssdev, wss);
0226 if (r)
0227 return r;
0228
0229 return size;
0230 }
0231
0232 struct display_attribute {
0233 struct attribute attr;
0234 ssize_t (*show)(struct omap_dss_device *, char *);
0235 ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
0236 };
0237
0238 #define DISPLAY_ATTR(_name, _mode, _show, _store) \
0239 struct display_attribute display_attr_##_name = \
0240 __ATTR(_name, _mode, _show, _store)
0241
0242 static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
0243 static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
0244 static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
0245 display_enabled_show, display_enabled_store);
0246 static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
0247 display_tear_show, display_tear_store);
0248 static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
0249 display_timings_show, display_timings_store);
0250 static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
0251 display_rotate_show, display_rotate_store);
0252 static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
0253 display_mirror_show, display_mirror_store);
0254 static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
0255 display_wss_show, display_wss_store);
0256
0257 static struct attribute *display_sysfs_attrs[] = {
0258 &display_attr_name.attr,
0259 &display_attr_display_name.attr,
0260 &display_attr_enabled.attr,
0261 &display_attr_tear_elim.attr,
0262 &display_attr_timings.attr,
0263 &display_attr_rotate.attr,
0264 &display_attr_mirror.attr,
0265 &display_attr_wss.attr,
0266 NULL
0267 };
0268 ATTRIBUTE_GROUPS(display_sysfs);
0269
0270 static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
0271 char *buf)
0272 {
0273 struct omap_dss_device *dssdev;
0274 struct display_attribute *display_attr;
0275
0276 dssdev = container_of(kobj, struct omap_dss_device, kobj);
0277 display_attr = container_of(attr, struct display_attribute, attr);
0278
0279 if (!display_attr->show)
0280 return -ENOENT;
0281
0282 return display_attr->show(dssdev, buf);
0283 }
0284
0285 static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
0286 const char *buf, size_t size)
0287 {
0288 struct omap_dss_device *dssdev;
0289 struct display_attribute *display_attr;
0290
0291 dssdev = container_of(kobj, struct omap_dss_device, kobj);
0292 display_attr = container_of(attr, struct display_attribute, attr);
0293
0294 if (!display_attr->store)
0295 return -ENOENT;
0296
0297 return display_attr->store(dssdev, buf, size);
0298 }
0299
0300 static const struct sysfs_ops display_sysfs_ops = {
0301 .show = display_attr_show,
0302 .store = display_attr_store,
0303 };
0304
0305 static struct kobj_type display_ktype = {
0306 .sysfs_ops = &display_sysfs_ops,
0307 .default_groups = display_sysfs_groups,
0308 };
0309
0310 int display_init_sysfs(struct platform_device *pdev)
0311 {
0312 struct omap_dss_device *dssdev = NULL;
0313 int r;
0314
0315 for_each_dss_dev(dssdev) {
0316 r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
0317 &pdev->dev.kobj, "%s", dssdev->alias);
0318 if (r) {
0319 DSSERR("failed to create sysfs files\n");
0320 omap_dss_put_device(dssdev);
0321 goto err;
0322 }
0323 }
0324
0325 return 0;
0326
0327 err:
0328 display_uninit_sysfs(pdev);
0329
0330 return r;
0331 }
0332
0333 void display_uninit_sysfs(struct platform_device *pdev)
0334 {
0335 struct omap_dss_device *dssdev = NULL;
0336
0337 for_each_dss_dev(dssdev) {
0338 if (kobject_name(&dssdev->kobj) == NULL)
0339 continue;
0340
0341 kobject_del(&dssdev->kobj);
0342 kobject_put(&dssdev->kobj);
0343
0344 memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
0345 }
0346 }