rcar-core.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Driver for Renesas R-Car VIN
  3. *
  4. * Copyright (C) 2016 Renesas Electronics Corp.
  5. * Copyright (C) 2011-2013 Renesas Solutions Corp.
  6. * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
  7. * Copyright (C) 2008 Magnus Damm
  8. *
  9. * Based on the soc-camera rcar_vin driver
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License as published by the
  13. * Free Software Foundation; either version 2 of the License, or (at your
  14. * option) any later version.
  15. */
  16. #include <linux/module.h>
  17. #include <linux/of.h>
  18. #include <linux/of_device.h>
  19. #include <linux/of_graph.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/pm_runtime.h>
  22. #include <media/v4l2-of.h>
  23. #include "rcar-vin.h"
  24. /* -----------------------------------------------------------------------------
  25. * Async notifier
  26. */
  27. #define notifier_to_vin(n) container_of(n, struct rvin_dev, notifier)
  28. static bool rvin_mbus_supported(struct rvin_graph_entity *entity)
  29. {
  30. struct v4l2_subdev *sd = entity->subdev;
  31. struct v4l2_subdev_mbus_code_enum code = {
  32. .which = V4L2_SUBDEV_FORMAT_ACTIVE,
  33. };
  34. code.index = 0;
  35. while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) {
  36. code.index++;
  37. switch (code.code) {
  38. case MEDIA_BUS_FMT_YUYV8_1X16:
  39. case MEDIA_BUS_FMT_UYVY8_2X8:
  40. case MEDIA_BUS_FMT_UYVY10_2X10:
  41. case MEDIA_BUS_FMT_RGB888_1X24:
  42. entity->code = code.code;
  43. return true;
  44. default:
  45. break;
  46. }
  47. }
  48. return false;
  49. }
  50. static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)
  51. {
  52. struct rvin_dev *vin = notifier_to_vin(notifier);
  53. int ret;
  54. /* Verify subdevices mbus format */
  55. if (!rvin_mbus_supported(&vin->digital)) {
  56. vin_err(vin, "Unsupported media bus format for %s\n",
  57. vin->digital.subdev->name);
  58. return -EINVAL;
  59. }
  60. vin_dbg(vin, "Found media bus format for %s: %d\n",
  61. vin->digital.subdev->name, vin->digital.code);
  62. ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
  63. if (ret < 0) {
  64. vin_err(vin, "Failed to register subdev nodes\n");
  65. return ret;
  66. }
  67. return rvin_v4l2_probe(vin);
  68. }
  69. static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,
  70. struct v4l2_subdev *subdev,
  71. struct v4l2_async_subdev *asd)
  72. {
  73. struct rvin_dev *vin = notifier_to_vin(notifier);
  74. if (vin->digital.subdev == subdev) {
  75. vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
  76. rvin_v4l2_remove(vin);
  77. vin->digital.subdev = NULL;
  78. return;
  79. }
  80. vin_err(vin, "no entity for subdev %s to unbind\n", subdev->name);
  81. }
  82. static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
  83. struct v4l2_subdev *subdev,
  84. struct v4l2_async_subdev *asd)
  85. {
  86. struct rvin_dev *vin = notifier_to_vin(notifier);
  87. v4l2_set_subdev_hostdata(subdev, vin);
  88. if (vin->digital.asd.match.of.node == subdev->dev->of_node) {
  89. vin_dbg(vin, "bound digital subdev %s\n", subdev->name);
  90. vin->digital.subdev = subdev;
  91. return 0;
  92. }
  93. vin_err(vin, "no entity for subdev %s to bind\n", subdev->name);
  94. return -EINVAL;
  95. }
  96. static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
  97. struct device_node *ep,
  98. struct v4l2_mbus_config *mbus_cfg)
  99. {
  100. struct v4l2_of_endpoint v4l2_ep;
  101. int ret;
  102. ret = v4l2_of_parse_endpoint(ep, &v4l2_ep);
  103. if (ret) {
  104. vin_err(vin, "Could not parse v4l2 endpoint\n");
  105. return -EINVAL;
  106. }
  107. mbus_cfg->type = v4l2_ep.bus_type;
  108. switch (mbus_cfg->type) {
  109. case V4L2_MBUS_PARALLEL:
  110. vin_dbg(vin, "Found PARALLEL media bus\n");
  111. mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
  112. break;
  113. case V4L2_MBUS_BT656:
  114. vin_dbg(vin, "Found BT656 media bus\n");
  115. mbus_cfg->flags = 0;
  116. break;
  117. default:
  118. vin_err(vin, "Unknown media bus type\n");
  119. return -EINVAL;
  120. }
  121. return 0;
  122. }
  123. static int rvin_digital_graph_parse(struct rvin_dev *vin)
  124. {
  125. struct device_node *ep, *np;
  126. int ret;
  127. vin->digital.asd.match.of.node = NULL;
  128. vin->digital.subdev = NULL;
  129. /*
  130. * Port 0 id 0 is local digital input, try to get it.
  131. * Not all instances can or will have this, that is OK
  132. */
  133. ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
  134. if (!ep)
  135. return 0;
  136. np = of_graph_get_remote_port_parent(ep);
  137. if (!np) {
  138. vin_err(vin, "No remote parent for digital input\n");
  139. of_node_put(ep);
  140. return -EINVAL;
  141. }
  142. of_node_put(np);
  143. ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
  144. of_node_put(ep);
  145. if (ret)
  146. return ret;
  147. vin->digital.asd.match.of.node = np;
  148. vin->digital.asd.match_type = V4L2_ASYNC_MATCH_OF;
  149. return 0;
  150. }
  151. static int rvin_digital_graph_init(struct rvin_dev *vin)
  152. {
  153. struct v4l2_async_subdev **subdevs = NULL;
  154. int ret;
  155. ret = rvin_digital_graph_parse(vin);
  156. if (ret)
  157. return ret;
  158. if (!vin->digital.asd.match.of.node) {
  159. vin_dbg(vin, "No digital subdevice found\n");
  160. return -ENODEV;
  161. }
  162. /* Register the subdevices notifier. */
  163. subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
  164. if (subdevs == NULL)
  165. return -ENOMEM;
  166. subdevs[0] = &vin->digital.asd;
  167. vin_dbg(vin, "Found digital subdevice %s\n",
  168. of_node_full_name(subdevs[0]->match.of.node));
  169. vin->notifier.num_subdevs = 1;
  170. vin->notifier.subdevs = subdevs;
  171. vin->notifier.bound = rvin_digital_notify_bound;
  172. vin->notifier.unbind = rvin_digital_notify_unbind;
  173. vin->notifier.complete = rvin_digital_notify_complete;
  174. ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
  175. if (ret < 0) {
  176. vin_err(vin, "Notifier registration failed\n");
  177. return ret;
  178. }
  179. return 0;
  180. }
  181. /* -----------------------------------------------------------------------------
  182. * Platform Device Driver
  183. */
  184. static const struct of_device_id rvin_of_id_table[] = {
  185. { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 },
  186. { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 },
  187. { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 },
  188. { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 },
  189. { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 },
  190. { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 },
  191. { .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 },
  192. { },
  193. };
  194. MODULE_DEVICE_TABLE(of, rvin_of_id_table);
  195. static int rcar_vin_probe(struct platform_device *pdev)
  196. {
  197. const struct of_device_id *match;
  198. struct rvin_dev *vin;
  199. struct resource *mem;
  200. int irq, ret;
  201. vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL);
  202. if (!vin)
  203. return -ENOMEM;
  204. match = of_match_device(of_match_ptr(rvin_of_id_table), &pdev->dev);
  205. if (!match)
  206. return -ENODEV;
  207. vin->dev = &pdev->dev;
  208. vin->chip = (enum chip_id)match->data;
  209. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  210. if (mem == NULL)
  211. return -EINVAL;
  212. vin->base = devm_ioremap_resource(vin->dev, mem);
  213. if (IS_ERR(vin->base))
  214. return PTR_ERR(vin->base);
  215. irq = platform_get_irq(pdev, 0);
  216. if (irq < 0)
  217. return irq;
  218. ret = rvin_dma_probe(vin, irq);
  219. if (ret)
  220. return ret;
  221. ret = rvin_digital_graph_init(vin);
  222. if (ret < 0)
  223. goto error;
  224. pm_suspend_ignore_children(&pdev->dev, true);
  225. pm_runtime_enable(&pdev->dev);
  226. platform_set_drvdata(pdev, vin);
  227. return 0;
  228. error:
  229. rvin_dma_remove(vin);
  230. return ret;
  231. }
  232. static int rcar_vin_remove(struct platform_device *pdev)
  233. {
  234. struct rvin_dev *vin = platform_get_drvdata(pdev);
  235. pm_runtime_disable(&pdev->dev);
  236. v4l2_async_notifier_unregister(&vin->notifier);
  237. rvin_dma_remove(vin);
  238. return 0;
  239. }
  240. static struct platform_driver rcar_vin_driver = {
  241. .driver = {
  242. .name = "rcar-vin",
  243. .of_match_table = rvin_of_id_table,
  244. },
  245. .probe = rcar_vin_probe,
  246. .remove = rcar_vin_remove,
  247. };
  248. module_platform_driver(rcar_vin_driver);
  249. MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
  250. MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
  251. MODULE_LICENSE("GPL v2");