Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2009 Nokia Corporation
0004  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
0005  *
0006  * Some code and ideas taken from drivers/video/omap/ driver
0007  * by Imre Deak.
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 }