display-sysfs.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * Copyright (C) 2009 Nokia Corporation
  3. * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  4. *
  5. * Some code and ideas taken from drivers/video/omap/ driver
  6. * by Imre Deak.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License version 2 as published by
  10. * the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #define DSS_SUBSYS_NAME "DISPLAY"
  21. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/platform_device.h>
  24. #include <linux/sysfs.h>
  25. #include <video/omapdss.h>
  26. #include "dss.h"
  27. static ssize_t display_name_show(struct omap_dss_device *dssdev, char *buf)
  28. {
  29. return snprintf(buf, PAGE_SIZE, "%s\n",
  30. dssdev->name ?
  31. dssdev->name : "");
  32. }
  33. static ssize_t display_enabled_show(struct omap_dss_device *dssdev, char *buf)
  34. {
  35. return snprintf(buf, PAGE_SIZE, "%d\n",
  36. omapdss_device_is_enabled(dssdev));
  37. }
  38. static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
  39. const char *buf, size_t size)
  40. {
  41. int r;
  42. bool enable;
  43. r = strtobool(buf, &enable);
  44. if (r)
  45. return r;
  46. if (enable == omapdss_device_is_enabled(dssdev))
  47. return size;
  48. if (omapdss_device_is_connected(dssdev) == false)
  49. return -ENODEV;
  50. if (enable) {
  51. r = dssdev->driver->enable(dssdev);
  52. if (r)
  53. return r;
  54. } else {
  55. dssdev->driver->disable(dssdev);
  56. }
  57. return size;
  58. }
  59. static ssize_t display_tear_show(struct omap_dss_device *dssdev, char *buf)
  60. {
  61. return snprintf(buf, PAGE_SIZE, "%d\n",
  62. dssdev->driver->get_te ?
  63. dssdev->driver->get_te(dssdev) : 0);
  64. }
  65. static ssize_t display_tear_store(struct omap_dss_device *dssdev,
  66. const char *buf, size_t size)
  67. {
  68. int r;
  69. bool te;
  70. if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
  71. return -ENOENT;
  72. r = strtobool(buf, &te);
  73. if (r)
  74. return r;
  75. r = dssdev->driver->enable_te(dssdev, te);
  76. if (r)
  77. return r;
  78. return size;
  79. }
  80. static ssize_t display_timings_show(struct omap_dss_device *dssdev, char *buf)
  81. {
  82. struct omap_video_timings t;
  83. if (!dssdev->driver->get_timings)
  84. return -ENOENT;
  85. dssdev->driver->get_timings(dssdev, &t);
  86. return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
  87. t.pixelclock,
  88. t.x_res, t.hfp, t.hbp, t.hsw,
  89. t.y_res, t.vfp, t.vbp, t.vsw);
  90. }
  91. static ssize_t display_timings_store(struct omap_dss_device *dssdev,
  92. const char *buf, size_t size)
  93. {
  94. struct omap_video_timings t = dssdev->panel.timings;
  95. int r, found;
  96. if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
  97. return -ENOENT;
  98. found = 0;
  99. #ifdef CONFIG_OMAP2_DSS_VENC
  100. if (strncmp("pal", buf, 3) == 0) {
  101. t = omap_dss_pal_timings;
  102. found = 1;
  103. } else if (strncmp("ntsc", buf, 4) == 0) {
  104. t = omap_dss_ntsc_timings;
  105. found = 1;
  106. }
  107. #endif
  108. if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
  109. &t.pixelclock,
  110. &t.x_res, &t.hfp, &t.hbp, &t.hsw,
  111. &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
  112. return -EINVAL;
  113. r = dssdev->driver->check_timings(dssdev, &t);
  114. if (r)
  115. return r;
  116. dssdev->driver->disable(dssdev);
  117. dssdev->driver->set_timings(dssdev, &t);
  118. r = dssdev->driver->enable(dssdev);
  119. if (r)
  120. return r;
  121. return size;
  122. }
  123. static ssize_t display_rotate_show(struct omap_dss_device *dssdev, char *buf)
  124. {
  125. int rotate;
  126. if (!dssdev->driver->get_rotate)
  127. return -ENOENT;
  128. rotate = dssdev->driver->get_rotate(dssdev);
  129. return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
  130. }
  131. static ssize_t display_rotate_store(struct omap_dss_device *dssdev,
  132. const char *buf, size_t size)
  133. {
  134. int rot, r;
  135. if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
  136. return -ENOENT;
  137. r = kstrtoint(buf, 0, &rot);
  138. if (r)
  139. return r;
  140. r = dssdev->driver->set_rotate(dssdev, rot);
  141. if (r)
  142. return r;
  143. return size;
  144. }
  145. static ssize_t display_mirror_show(struct omap_dss_device *dssdev, char *buf)
  146. {
  147. int mirror;
  148. if (!dssdev->driver->get_mirror)
  149. return -ENOENT;
  150. mirror = dssdev->driver->get_mirror(dssdev);
  151. return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
  152. }
  153. static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
  154. const char *buf, size_t size)
  155. {
  156. int r;
  157. bool mirror;
  158. if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
  159. return -ENOENT;
  160. r = strtobool(buf, &mirror);
  161. if (r)
  162. return r;
  163. r = dssdev->driver->set_mirror(dssdev, mirror);
  164. if (r)
  165. return r;
  166. return size;
  167. }
  168. static ssize_t display_wss_show(struct omap_dss_device *dssdev, char *buf)
  169. {
  170. unsigned int wss;
  171. if (!dssdev->driver->get_wss)
  172. return -ENOENT;
  173. wss = dssdev->driver->get_wss(dssdev);
  174. return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
  175. }
  176. static ssize_t display_wss_store(struct omap_dss_device *dssdev,
  177. const char *buf, size_t size)
  178. {
  179. u32 wss;
  180. int r;
  181. if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
  182. return -ENOENT;
  183. r = kstrtou32(buf, 0, &wss);
  184. if (r)
  185. return r;
  186. if (wss > 0xfffff)
  187. return -EINVAL;
  188. r = dssdev->driver->set_wss(dssdev, wss);
  189. if (r)
  190. return r;
  191. return size;
  192. }
  193. struct display_attribute {
  194. struct attribute attr;
  195. ssize_t (*show)(struct omap_dss_device *, char *);
  196. ssize_t (*store)(struct omap_dss_device *, const char *, size_t);
  197. };
  198. #define DISPLAY_ATTR(_name, _mode, _show, _store) \
  199. struct display_attribute display_attr_##_name = \
  200. __ATTR(_name, _mode, _show, _store)
  201. static DISPLAY_ATTR(name, S_IRUGO, display_name_show, NULL);
  202. static DISPLAY_ATTR(display_name, S_IRUGO, display_name_show, NULL);
  203. static DISPLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
  204. display_enabled_show, display_enabled_store);
  205. static DISPLAY_ATTR(tear_elim, S_IRUGO|S_IWUSR,
  206. display_tear_show, display_tear_store);
  207. static DISPLAY_ATTR(timings, S_IRUGO|S_IWUSR,
  208. display_timings_show, display_timings_store);
  209. static DISPLAY_ATTR(rotate, S_IRUGO|S_IWUSR,
  210. display_rotate_show, display_rotate_store);
  211. static DISPLAY_ATTR(mirror, S_IRUGO|S_IWUSR,
  212. display_mirror_show, display_mirror_store);
  213. static DISPLAY_ATTR(wss, S_IRUGO|S_IWUSR,
  214. display_wss_show, display_wss_store);
  215. static struct attribute *display_sysfs_attrs[] = {
  216. &display_attr_name.attr,
  217. &display_attr_display_name.attr,
  218. &display_attr_enabled.attr,
  219. &display_attr_tear_elim.attr,
  220. &display_attr_timings.attr,
  221. &display_attr_rotate.attr,
  222. &display_attr_mirror.attr,
  223. &display_attr_wss.attr,
  224. NULL
  225. };
  226. static ssize_t display_attr_show(struct kobject *kobj, struct attribute *attr,
  227. char *buf)
  228. {
  229. struct omap_dss_device *dssdev;
  230. struct display_attribute *display_attr;
  231. dssdev = container_of(kobj, struct omap_dss_device, kobj);
  232. display_attr = container_of(attr, struct display_attribute, attr);
  233. if (!display_attr->show)
  234. return -ENOENT;
  235. return display_attr->show(dssdev, buf);
  236. }
  237. static ssize_t display_attr_store(struct kobject *kobj, struct attribute *attr,
  238. const char *buf, size_t size)
  239. {
  240. struct omap_dss_device *dssdev;
  241. struct display_attribute *display_attr;
  242. dssdev = container_of(kobj, struct omap_dss_device, kobj);
  243. display_attr = container_of(attr, struct display_attribute, attr);
  244. if (!display_attr->store)
  245. return -ENOENT;
  246. return display_attr->store(dssdev, buf, size);
  247. }
  248. static const struct sysfs_ops display_sysfs_ops = {
  249. .show = display_attr_show,
  250. .store = display_attr_store,
  251. };
  252. static struct kobj_type display_ktype = {
  253. .sysfs_ops = &display_sysfs_ops,
  254. .default_attrs = display_sysfs_attrs,
  255. };
  256. int display_init_sysfs(struct platform_device *pdev)
  257. {
  258. struct omap_dss_device *dssdev = NULL;
  259. int r;
  260. for_each_dss_dev(dssdev) {
  261. r = kobject_init_and_add(&dssdev->kobj, &display_ktype,
  262. &pdev->dev.kobj, "%s", dssdev->alias);
  263. if (r) {
  264. DSSERR("failed to create sysfs files\n");
  265. omap_dss_put_device(dssdev);
  266. goto err;
  267. }
  268. }
  269. return 0;
  270. err:
  271. display_uninit_sysfs(pdev);
  272. return r;
  273. }
  274. void display_uninit_sysfs(struct platform_device *pdev)
  275. {
  276. struct omap_dss_device *dssdev = NULL;
  277. for_each_dss_dev(dssdev) {
  278. if (kobject_name(&dssdev->kobj) == NULL)
  279. continue;
  280. kobject_del(&dssdev->kobj);
  281. kobject_put(&dssdev->kobj);
  282. memset(&dssdev->kobj, 0, sizeof(dssdev->kobj));
  283. }
  284. }