atmel-sama5d2-isc.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Microchip Image Sensor Controller (ISC) driver
  4. *
  5. * Copyright (C) 2016-2019 Microchip Technology, Inc.
  6. *
  7. * Author: Songjun Wu
  8. * Author: Eugen Hristev <eugen.hristev@microchip.com>
  9. *
  10. *
  11. * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
  12. *
  13. * ISC video pipeline integrates the following submodules:
  14. * PFE: Parallel Front End to sample the camera sensor input stream
  15. * WB: Programmable white balance in the Bayer domain
  16. * CFA: Color filter array interpolation module
  17. * CC: Programmable color correction
  18. * GAM: Gamma correction
  19. * CSC: Programmable color space conversion
  20. * CBC: Contrast and Brightness control
  21. * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
  22. * RLP: This module performs rounding, range limiting
  23. * and packing of the incoming data
  24. */
  25. #include <linux/clk.h>
  26. #include <linux/clkdev.h>
  27. #include <linux/clk-provider.h>
  28. #include <linux/delay.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/math64.h>
  31. #include <linux/module.h>
  32. #include <linux/of.h>
  33. #include <linux/of_graph.h>
  34. #include <linux/platform_device.h>
  35. #include <linux/pm_runtime.h>
  36. #include <linux/regmap.h>
  37. #include <linux/videodev2.h>
  38. #include <media/v4l2-ctrls.h>
  39. #include <media/v4l2-device.h>
  40. #include <media/v4l2-event.h>
  41. #include <media/v4l2-image-sizes.h>
  42. #include <media/v4l2-ioctl.h>
  43. #include <media/v4l2-fwnode.h>
  44. #include <media/v4l2-subdev.h>
  45. #include <media/videobuf2-dma-contig.h>
  46. #include "atmel-isc-regs.h"
  47. #include "atmel-isc.h"
  48. #define ISC_MAX_SUPPORT_WIDTH 2592
  49. #define ISC_MAX_SUPPORT_HEIGHT 1944
  50. #define ISC_CLK_MAX_DIV 255
  51. static int isc_parse_dt(struct device *dev, struct isc_device *isc)
  52. {
  53. struct device_node *np = dev->of_node;
  54. struct device_node *epn = NULL, *rem;
  55. struct isc_subdev_entity *subdev_entity;
  56. unsigned int flags;
  57. int ret;
  58. INIT_LIST_HEAD(&isc->subdev_entities);
  59. while (1) {
  60. struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
  61. epn = of_graph_get_next_endpoint(np, epn);
  62. if (!epn)
  63. return 0;
  64. rem = of_graph_get_remote_port_parent(epn);
  65. if (!rem) {
  66. dev_notice(dev, "Remote device at %pOF not found\n",
  67. epn);
  68. continue;
  69. }
  70. ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
  71. &v4l2_epn);
  72. if (ret) {
  73. of_node_put(rem);
  74. ret = -EINVAL;
  75. dev_err(dev, "Could not parse the endpoint\n");
  76. break;
  77. }
  78. subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
  79. GFP_KERNEL);
  80. if (!subdev_entity) {
  81. of_node_put(rem);
  82. ret = -ENOMEM;
  83. break;
  84. }
  85. /* asd will be freed by the subsystem once it's added to the
  86. * notifier list
  87. */
  88. subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd),
  89. GFP_KERNEL);
  90. if (!subdev_entity->asd) {
  91. of_node_put(rem);
  92. ret = -ENOMEM;
  93. break;
  94. }
  95. flags = v4l2_epn.bus.parallel.flags;
  96. if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
  97. subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
  98. if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
  99. subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
  100. if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
  101. subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
  102. if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
  103. subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
  104. ISC_PFE_CFG0_CCIR656;
  105. subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
  106. subdev_entity->asd->match.fwnode = of_fwnode_handle(rem);
  107. list_add_tail(&subdev_entity->list, &isc->subdev_entities);
  108. }
  109. of_node_put(epn);
  110. return ret;
  111. }
  112. static int atmel_isc_probe(struct platform_device *pdev)
  113. {
  114. struct device *dev = &pdev->dev;
  115. struct isc_device *isc;
  116. struct resource *res;
  117. void __iomem *io_base;
  118. struct isc_subdev_entity *subdev_entity;
  119. int irq;
  120. int ret;
  121. isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
  122. if (!isc)
  123. return -ENOMEM;
  124. platform_set_drvdata(pdev, isc);
  125. isc->dev = dev;
  126. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  127. io_base = devm_ioremap_resource(dev, res);
  128. if (IS_ERR(io_base))
  129. return PTR_ERR(io_base);
  130. isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
  131. if (IS_ERR(isc->regmap)) {
  132. ret = PTR_ERR(isc->regmap);
  133. dev_err(dev, "failed to init register map: %d\n", ret);
  134. return ret;
  135. }
  136. irq = platform_get_irq(pdev, 0);
  137. if (irq < 0)
  138. return irq;
  139. ret = devm_request_irq(dev, irq, isc_interrupt, 0,
  140. ATMEL_ISC_NAME, isc);
  141. if (ret < 0) {
  142. dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
  143. irq, ret);
  144. return ret;
  145. }
  146. ret = isc_pipeline_init(isc);
  147. if (ret)
  148. return ret;
  149. isc->hclock = devm_clk_get(dev, "hclock");
  150. if (IS_ERR(isc->hclock)) {
  151. ret = PTR_ERR(isc->hclock);
  152. dev_err(dev, "failed to get hclock: %d\n", ret);
  153. return ret;
  154. }
  155. ret = clk_prepare_enable(isc->hclock);
  156. if (ret) {
  157. dev_err(dev, "failed to enable hclock: %d\n", ret);
  158. return ret;
  159. }
  160. ret = isc_clk_init(isc);
  161. if (ret) {
  162. dev_err(dev, "failed to init isc clock: %d\n", ret);
  163. goto unprepare_hclk;
  164. }
  165. isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
  166. ret = clk_prepare_enable(isc->ispck);
  167. if (ret) {
  168. dev_err(dev, "failed to enable ispck: %d\n", ret);
  169. goto unprepare_hclk;
  170. }
  171. /* ispck should be greater or equal to hclock */
  172. ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
  173. if (ret) {
  174. dev_err(dev, "failed to set ispck rate: %d\n", ret);
  175. goto unprepare_clk;
  176. }
  177. ret = v4l2_device_register(dev, &isc->v4l2_dev);
  178. if (ret) {
  179. dev_err(dev, "unable to register v4l2 device.\n");
  180. goto unprepare_clk;
  181. }
  182. ret = isc_parse_dt(dev, isc);
  183. if (ret) {
  184. dev_err(dev, "fail to parse device tree\n");
  185. goto unregister_v4l2_device;
  186. }
  187. if (list_empty(&isc->subdev_entities)) {
  188. dev_err(dev, "no subdev found\n");
  189. ret = -ENODEV;
  190. goto unregister_v4l2_device;
  191. }
  192. list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
  193. v4l2_async_notifier_init(&subdev_entity->notifier);
  194. ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier,
  195. subdev_entity->asd);
  196. if (ret) {
  197. fwnode_handle_put(subdev_entity->asd->match.fwnode);
  198. kfree(subdev_entity->asd);
  199. goto cleanup_subdev;
  200. }
  201. subdev_entity->notifier.ops = &isc_async_ops;
  202. ret = v4l2_async_notifier_register(&isc->v4l2_dev,
  203. &subdev_entity->notifier);
  204. if (ret) {
  205. dev_err(dev, "fail to register async notifier\n");
  206. goto cleanup_subdev;
  207. }
  208. if (video_is_registered(&isc->video_dev))
  209. break;
  210. }
  211. pm_runtime_set_active(dev);
  212. pm_runtime_enable(dev);
  213. pm_request_idle(dev);
  214. return 0;
  215. cleanup_subdev:
  216. isc_subdev_cleanup(isc);
  217. unregister_v4l2_device:
  218. v4l2_device_unregister(&isc->v4l2_dev);
  219. unprepare_clk:
  220. clk_disable_unprepare(isc->ispck);
  221. unprepare_hclk:
  222. clk_disable_unprepare(isc->hclock);
  223. isc_clk_cleanup(isc);
  224. return ret;
  225. }
  226. static int atmel_isc_remove(struct platform_device *pdev)
  227. {
  228. struct isc_device *isc = platform_get_drvdata(pdev);
  229. pm_runtime_disable(&pdev->dev);
  230. isc_subdev_cleanup(isc);
  231. v4l2_device_unregister(&isc->v4l2_dev);
  232. clk_disable_unprepare(isc->ispck);
  233. clk_disable_unprepare(isc->hclock);
  234. isc_clk_cleanup(isc);
  235. return 0;
  236. }
  237. static int __maybe_unused isc_runtime_suspend(struct device *dev)
  238. {
  239. struct isc_device *isc = dev_get_drvdata(dev);
  240. clk_disable_unprepare(isc->ispck);
  241. clk_disable_unprepare(isc->hclock);
  242. return 0;
  243. }
  244. static int __maybe_unused isc_runtime_resume(struct device *dev)
  245. {
  246. struct isc_device *isc = dev_get_drvdata(dev);
  247. int ret;
  248. ret = clk_prepare_enable(isc->hclock);
  249. if (ret)
  250. return ret;
  251. ret = clk_prepare_enable(isc->ispck);
  252. if (ret)
  253. clk_disable_unprepare(isc->hclock);
  254. return ret;
  255. }
  256. static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
  257. SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
  258. };
  259. static const struct of_device_id atmel_isc_of_match[] = {
  260. { .compatible = "atmel,sama5d2-isc" },
  261. { }
  262. };
  263. MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
  264. static struct platform_driver atmel_isc_driver = {
  265. .probe = atmel_isc_probe,
  266. .remove = atmel_isc_remove,
  267. .driver = {
  268. .name = ATMEL_ISC_NAME,
  269. .pm = &atmel_isc_dev_pm_ops,
  270. .of_match_table = of_match_ptr(atmel_isc_of_match),
  271. },
  272. };
  273. module_platform_driver(atmel_isc_driver);
  274. MODULE_AUTHOR("Songjun Wu");
  275. MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
  276. MODULE_LICENSE("GPL v2");
  277. MODULE_SUPPORTED_DEVICE("video");