0443-drm-panel-Add-support-for-the-Raspberry-Pi-7-Touchsc.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. From 4da2b00d471f7fca0d770551afafa95e85ec9b89 Mon Sep 17 00:00:00 2001
  2. From: Eric Anholt <eric@anholt.net>
  3. Date: Tue, 26 Apr 2016 13:46:13 -0700
  4. Subject: [PATCH] drm/panel: Add support for the Raspberry Pi 7" Touchscreen.
  5. Signed-off-by: Eric Anholt <eric@anholt.net>
  6. ---
  7. drivers/gpu/drm/panel/Kconfig | 9 +
  8. drivers/gpu/drm/panel/Makefile | 1 +
  9. .../gpu/drm/panel/panel-raspberrypi-touchscreen.c | 347 +++++++++++++++++++++
  10. 3 files changed, 357 insertions(+)
  11. create mode 100644 drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
  12. --- a/drivers/gpu/drm/panel/Kconfig
  13. +++ b/drivers/gpu/drm/panel/Kconfig
  14. @@ -31,6 +31,15 @@ config DRM_PANEL_LG_LG4573
  15. Say Y here if you want to enable support for LG4573 RGB panel.
  16. To compile this driver as a module, choose M here.
  17. +config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN
  18. + tristate "Raspberry Pi 7-inch touchscreen panel"
  19. + depends on DRM_MIPI_DSI
  20. + depends on BACKLIGHT_CLASS_DEVICE
  21. + help
  22. + Say Y here if you want to enable support for the Raspberry
  23. + Pi 7" Touchscreen. To compile this driver as a module,
  24. + choose M here.
  25. +
  26. config DRM_PANEL_SAMSUNG_S6E8AA0
  27. tristate "Samsung S6E8AA0 DSI video mode panel"
  28. depends on OF
  29. --- a/drivers/gpu/drm/panel/Makefile
  30. +++ b/drivers/gpu/drm/panel/Makefile
  31. @@ -1,5 +1,6 @@
  32. obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
  33. obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
  34. +obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
  35. obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
  36. obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
  37. obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
  38. --- /dev/null
  39. +++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
  40. @@ -0,0 +1,347 @@
  41. +/*
  42. + * Copyright © 2016 Broadcom Limited
  43. + *
  44. + * This program is free software; you can redistribute it and/or modify
  45. + * it under the terms of the GNU General Public License version 2 as
  46. + * published by the Free Software Foundation.
  47. + *
  48. + * Portions of this file (derived from panel-simple.c) are:
  49. + *
  50. + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
  51. + *
  52. + * Permission is hereby granted, free of charge, to any person obtaining a
  53. + * copy of this software and associated documentation files (the "Software"),
  54. + * to deal in the Software without restriction, including without limitation
  55. + * the rights to use, copy, modify, merge, publish, distribute, sub license,
  56. + * and/or sell copies of the Software, and to permit persons to whom the
  57. + * Software is furnished to do so, subject to the following conditions:
  58. + *
  59. + * The above copyright notice and this permission notice (including the
  60. + * next paragraph) shall be included in all copies or substantial portions
  61. + * of the Software.
  62. + *
  63. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  64. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  65. + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  66. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  67. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  68. + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  69. + * DEALINGS IN THE SOFTWARE.
  70. + */
  71. +
  72. +/**
  73. + * DOC: Raspberry Pi 7" touchscreen panel driver.
  74. + *
  75. + * The 7" touchscreen consists of a DPI LCD panel, a Toshiba
  76. + * TC358762XBG DSI-DPI bridge, and an I2C-connected Atmel ATTINY88-MUR
  77. + * controlling power management, the LCD PWM, and the touchscreen.
  78. + *
  79. + * This driver presents this device as a MIPI DSI panel to the DRM
  80. + * driver, and should expose the touchscreen as a HID device.
  81. + */
  82. +
  83. +#include <linux/backlight.h>
  84. +#include <linux/delay.h>
  85. +#include <linux/err.h>
  86. +#include <linux/fb.h>
  87. +#include <linux/gpio.h>
  88. +#include <linux/gpio/consumer.h>
  89. +#include <linux/i2c.h>
  90. +#include <linux/module.h>
  91. +#include <linux/of.h>
  92. +#include <linux/of_device.h>
  93. +#include <linux/of_graph.h>
  94. +#include <linux/pm.h>
  95. +
  96. +#include <drm/drm_panel.h>
  97. +#include <drm/drmP.h>
  98. +#include <drm/drm_crtc.h>
  99. +#include <drm/drm_mipi_dsi.h>
  100. +#include <drm/drm_panel.h>
  101. +
  102. +struct rpi_touchscreen {
  103. + struct drm_panel base;
  104. + struct mipi_dsi_device *dsi;
  105. + struct i2c_client *bridge_i2c;
  106. + struct backlight_device *backlight;
  107. +
  108. + bool prepared;
  109. + bool enabled;
  110. +
  111. + /* Version of the firmware on the bridge chip */
  112. + int atmel_ver;
  113. +};
  114. +
  115. +static const struct drm_display_mode rpi_touchscreen_modes[] = {
  116. + {
  117. + /* This is assuming that we'll be running the DSI PLL
  118. + * at 2Ghz / 3 (since we only get integer dividers),
  119. + * so a pixel clock of 2Ghz / 3 / 8.
  120. + */
  121. + .clock = 83333,
  122. + .hdisplay = 800,
  123. + .hsync_start = 800 + 61,
  124. + .hsync_end = 800 + 61 + 2,
  125. + .htotal = 800 + 61 + 2 + 44,
  126. + .vdisplay = 480,
  127. + .vsync_start = 480 + 7,
  128. + .vsync_end = 480 + 7 + 2,
  129. + .vtotal = 480 + 7 + 2 + 21,
  130. + .vrefresh = 60,
  131. + },
  132. +};
  133. +
  134. +static struct rpi_touchscreen *panel_to_ts(struct drm_panel *panel)
  135. +{
  136. + return container_of(panel, struct rpi_touchscreen, base);
  137. +}
  138. +
  139. +struct regdump {
  140. + const char *reg;
  141. + u32 offset;
  142. +};
  143. +
  144. +#define REGDUMP(reg) { #reg, reg }
  145. +
  146. +static int rpi_touchscreen_disable(struct drm_panel *panel)
  147. +{
  148. + struct rpi_touchscreen *ts = panel_to_ts(panel);
  149. + pr_err("disable\n");
  150. +
  151. + if (!ts->enabled)
  152. + return 0;
  153. +
  154. + if (ts->backlight) {
  155. + ts->backlight->props.power = FB_BLANK_POWERDOWN;
  156. + backlight_update_status(ts->backlight);
  157. + }
  158. +
  159. + ts->enabled = false;
  160. +
  161. + return 0;
  162. +}
  163. +
  164. +static int rpi_touchscreen_unprepare(struct drm_panel *panel)
  165. +{
  166. + struct rpi_touchscreen *ts = panel_to_ts(panel);
  167. +
  168. + if (!ts->prepared)
  169. + return 0;
  170. +
  171. + ts->prepared = false;
  172. +
  173. + return 0;
  174. +}
  175. +
  176. +static int rpi_touchscreen_prepare(struct drm_panel *panel)
  177. +{
  178. + struct rpi_touchscreen *ts = panel_to_ts(panel);
  179. +
  180. + if (ts->prepared)
  181. + return 0;
  182. +
  183. + ts->prepared = true;
  184. +
  185. + return 0;
  186. +}
  187. +
  188. +/*
  189. + * Powers on the panel once the DSI link is up.
  190. + *
  191. + * The TC358762 is run in PLLOFF mode, where it usees the MIPI DSI
  192. + * byte clock instead of an external reference clock. This means that
  193. + * we need the DSI host to be on and transmitting before we start
  194. + * talking to it.
  195. + */
  196. +static int rpi_touchscreen_enable(struct drm_panel *panel)
  197. +{
  198. + struct rpi_touchscreen *ts = panel_to_ts(panel);
  199. +
  200. + if (ts->enabled)
  201. + return 0;
  202. +
  203. + if (ts->backlight) {
  204. + ts->backlight->props.power = FB_BLANK_UNBLANK;
  205. + backlight_update_status(ts->backlight);
  206. + }
  207. +
  208. + ts->enabled = true;
  209. +
  210. + return 0;
  211. +}
  212. +
  213. +static int rpi_touchscreen_get_modes(struct drm_panel *panel)
  214. +{
  215. + struct drm_connector *connector = panel->connector;
  216. + struct drm_device *drm = panel->drm;
  217. + unsigned int i, num = 0;
  218. +
  219. + for (i = 0; i < ARRAY_SIZE(rpi_touchscreen_modes); i++) {
  220. + const struct drm_display_mode *m = &rpi_touchscreen_modes[i];
  221. + struct drm_display_mode *mode;
  222. +
  223. + mode = drm_mode_duplicate(drm, m);
  224. + if (!mode) {
  225. + dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
  226. + m->hdisplay, m->vdisplay, m->vrefresh);
  227. + continue;
  228. + }
  229. +
  230. + mode->type |= DRM_MODE_TYPE_DRIVER;
  231. +
  232. + if (i == 0)
  233. + mode->type |= DRM_MODE_TYPE_PREFERRED;
  234. +
  235. + drm_mode_set_name(mode);
  236. +
  237. + drm_mode_probed_add(connector, mode);
  238. + num++;
  239. + }
  240. +
  241. + connector->display_info.bpc = 8;
  242. + connector->display_info.width_mm = 217; /* XXX */
  243. + connector->display_info.height_mm = 136; /* XXX */
  244. +
  245. + return num;
  246. +}
  247. +
  248. +static int rpi_touchscreen_backlight_update(struct backlight_device *bl)
  249. +{
  250. + int brightness = bl->props.brightness;
  251. +
  252. + if (bl->props.power != FB_BLANK_UNBLANK ||
  253. + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
  254. + brightness = 0;
  255. +
  256. + return 0;
  257. +}
  258. +
  259. +static const struct backlight_ops rpi_touchscreen_backlight_ops = {
  260. + .update_status = rpi_touchscreen_backlight_update,
  261. +};
  262. +
  263. +static const struct drm_panel_funcs rpi_touchscreen_funcs = {
  264. + .disable = rpi_touchscreen_disable,
  265. + .unprepare = rpi_touchscreen_unprepare,
  266. + .prepare = rpi_touchscreen_prepare,
  267. + .enable = rpi_touchscreen_enable,
  268. + .get_modes = rpi_touchscreen_get_modes,
  269. +};
  270. +
  271. +static struct i2c_client *rpi_touchscreen_get_i2c(struct device *dev,
  272. + const char *name)
  273. +{
  274. + struct device_node *node;
  275. + struct i2c_client *client;
  276. +
  277. + node = of_parse_phandle(dev->of_node, name, 0);
  278. + if (!node)
  279. + return ERR_PTR(-ENODEV);
  280. +
  281. + client = of_find_i2c_device_by_node(node);
  282. +
  283. + of_node_put(node);
  284. +
  285. + return client;
  286. +}
  287. +
  288. +static int rpi_touchscreen_dsi_probe(struct mipi_dsi_device *dsi)
  289. +{
  290. + struct device *dev = &dsi->dev;
  291. + struct rpi_touchscreen *ts;
  292. + int ret;
  293. +
  294. + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
  295. + if (!ts)
  296. + return -ENOMEM;
  297. +
  298. + dev_set_drvdata(dev, ts);
  299. +
  300. + ts->dsi = dsi;
  301. + dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
  302. + MIPI_DSI_MODE_VIDEO_SYNC_PULSE);
  303. + dsi->format = MIPI_DSI_FMT_RGB888;
  304. + dsi->lanes = 1;
  305. +
  306. + ts->bridge_i2c =
  307. + rpi_touchscreen_get_i2c(dev, "raspberrypi,touchscreen-bridge");
  308. + if (!ts->bridge_i2c) {
  309. + ret = -EPROBE_DEFER;
  310. + return ret;
  311. + }
  312. +
  313. +#if 0
  314. + ts->backlight =
  315. + devm_backlight_device_register(dev,
  316. + "raspberrypi-touchscreen-backlight",
  317. + dev, ts,
  318. + &rpi_touchscreen_backlight_ops,
  319. + NULL);
  320. + if (IS_ERR(ts->backlight)) {
  321. + DRM_ERROR("failed to register backlight\n");
  322. + return PTR_ERR(ts->backlight);
  323. + }
  324. + ts->backlight->props.max_brightness = RPI_TOUCHSCREEN_MAX_BRIGHTNESS;
  325. + ts->backlight->props.brightness = RPI_TOUCHSCREEN_MAX_BRIGHTNESS;
  326. +#endif
  327. +
  328. + drm_panel_init(&ts->base);
  329. + ts->base.dev = dev;
  330. + ts->base.funcs = &rpi_touchscreen_funcs;
  331. +
  332. + ret = drm_panel_add(&ts->base);
  333. + if (ret < 0)
  334. + goto err_release_bridge;
  335. +
  336. + return mipi_dsi_attach(dsi);
  337. +
  338. +err_release_bridge:
  339. + put_device(&ts->bridge_i2c->dev);
  340. + return ret;
  341. +}
  342. +
  343. +static int rpi_touchscreen_dsi_remove(struct mipi_dsi_device *dsi)
  344. +{
  345. + struct device *dev = &dsi->dev;
  346. + struct rpi_touchscreen *ts = dev_get_drvdata(dev);
  347. + int ret;
  348. +
  349. + ret = mipi_dsi_detach(dsi);
  350. + if (ret < 0) {
  351. + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
  352. + return ret;
  353. + }
  354. +
  355. + drm_panel_detach(&ts->base);
  356. + drm_panel_remove(&ts->base);
  357. +
  358. + put_device(&ts->bridge_i2c->dev);
  359. +
  360. + return 0;
  361. +}
  362. +
  363. +static void rpi_touchscreen_dsi_shutdown(struct mipi_dsi_device *dsi)
  364. +{
  365. + /* XXX: poweroff */
  366. +}
  367. +
  368. +static const struct of_device_id rpi_touchscreen_of_match[] = {
  369. + { .compatible = "raspberrypi,touchscreen" },
  370. + { } /* sentinel */
  371. +};
  372. +MODULE_DEVICE_TABLE(of, rpi_touchscreen_of_match);
  373. +
  374. +static struct mipi_dsi_driver rpi_touchscreen_driver = {
  375. + .driver = {
  376. + .name = "raspberrypi-touchscreen",
  377. + .of_match_table = rpi_touchscreen_of_match,
  378. + },
  379. + .probe = rpi_touchscreen_dsi_probe,
  380. + .remove = rpi_touchscreen_dsi_remove,
  381. + .shutdown = rpi_touchscreen_dsi_shutdown,
  382. +};
  383. +module_mipi_dsi_driver(rpi_touchscreen_driver);
  384. +
  385. +MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
  386. +MODULE_DESCRIPTION("Raspberry Pi 7-inch touchscreen driver");
  387. +MODULE_LICENSE("GPL v2");