dwe_driver.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /****************************************************************************
  2. *
  3. * The MIT License (MIT)
  4. *
  5. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. *
  25. *****************************************************************************
  26. *
  27. * The GPL License (GPL)
  28. *
  29. * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd.
  30. *
  31. * This program is free software; you can redistribute it and/or
  32. * modify it under the terms of the GNU General Public License
  33. * as published by the Free Software Foundation; either version 2
  34. * of the License, or (at your option) any later version.
  35. *
  36. * This program is distributed in the hope that it will be useful,
  37. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. * GNU General Public License for more details.
  40. *
  41. * You should have received a copy of the GNU General Public License
  42. * along with this program;
  43. *
  44. *****************************************************************************
  45. *
  46. * Note: This software is released under dual MIT and GPL licenses. A
  47. * recipient may use this file under the terms of either the MIT license or
  48. * GPL License. If you wish to use only one license not the other, you can
  49. * indicate your decision by deleting one of the above license notices in your
  50. * version of this file.
  51. *
  52. *****************************************************************************/
  53. #include <linux/delay.h>
  54. #include <linux/clk.h>
  55. #include <linux/io.h>
  56. #include <linux/module.h>
  57. #include <linux/proc_fs.h>
  58. #include <linux/debugfs.h>
  59. #include <linux/of_device.h>
  60. #include <linux/sched_clock.h>
  61. #include <linux/videodev2.h>
  62. #include <media/v4l2-ctrls.h>
  63. #include <media/v4l2-subdev.h>
  64. #include <media/v4l2-device.h>
  65. #include <media/v4l2-ioctl.h>
  66. #include <media/v4l2-event.h>
  67. #include <media/media-entity.h>
  68. #include <uapi/linux/media-bus-format.h>
  69. #include <linux/pm_runtime.h>
  70. #include "dwe_driver.h"
  71. #include "dwe_ioctl.h"
  72. #define DEVICE_NAME "vvcam-dwe"
  73. int dwe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
  74. struct v4l2_event_subscription *sub)
  75. {
  76. return v4l2_event_subscribe(fh, sub, 2, NULL);
  77. }
  78. int dwe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
  79. struct v4l2_event_subscription *sub)
  80. {
  81. return v4l2_event_unsubscribe(fh, sub);
  82. }
  83. #ifdef CONFIG_COMPAT
  84. static long dwe_ioctl_compat(struct v4l2_subdev *sd,
  85. unsigned int cmd, void *arg)
  86. {
  87. struct dwe_device *dwe_dev = v4l2_get_subdevdata(sd);
  88. return dwe_priv_ioctl(&dwe_dev->ic_dev, cmd, arg);
  89. }
  90. long dwe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
  91. {
  92. return dwe_ioctl_compat(sd, cmd, arg);
  93. }
  94. #else /* CONFIG_COMPAT */
  95. long dwe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
  96. {
  97. struct dwe_device *dwe_dev = v4l2_get_subdevdata(sd);
  98. return dwe_priv_ioctl(&dwe_dev->ic_dev, cmd, arg);
  99. }
  100. #endif /* CONFIG_COMPAT */
  101. static int dwe_enable_clocks(struct dwe_device *dwe_dev)
  102. {
  103. int ret;
  104. ret = clk_prepare_enable(dwe_dev->clk_core);
  105. if (ret)
  106. return ret;
  107. ret = clk_prepare_enable(dwe_dev->clk_axi);
  108. if (ret)
  109. goto disable_clk_core;
  110. ret = clk_prepare_enable(dwe_dev->clk_ahb);
  111. if (ret)
  112. goto disable_clk_axi;
  113. return 0;
  114. disable_clk_axi:
  115. clk_disable_unprepare(dwe_dev->clk_axi);
  116. disable_clk_core:
  117. clk_disable_unprepare(dwe_dev->clk_core);
  118. return ret;
  119. }
  120. static void dwe_disable_clocks(struct dwe_device *dwe_dev)
  121. {
  122. clk_disable_unprepare(dwe_dev->clk_ahb);
  123. clk_disable_unprepare(dwe_dev->clk_axi);
  124. clk_disable_unprepare(dwe_dev->clk_core);
  125. }
  126. int dwe_set_stream(struct v4l2_subdev *sd, int enable)
  127. {
  128. return 0;
  129. }
  130. static struct v4l2_subdev_core_ops dwe_v4l2_subdev_core_ops = {
  131. .ioctl = dwe_ioctl,
  132. .subscribe_event = dwe_subscribe_event,
  133. .unsubscribe_event = dwe_unsubscribe_event,
  134. };
  135. static struct v4l2_subdev_video_ops dwe_v4l2_subdev_video_ops = {
  136. .s_stream = dwe_set_stream,
  137. };
  138. static struct v4l2_subdev_ops dwe_v4l2_subdev_ops = {
  139. .core = &dwe_v4l2_subdev_core_ops,
  140. .video = &dwe_v4l2_subdev_video_ops,
  141. };
  142. static int dwe_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
  143. {
  144. pm_runtime_get_sync(sd->dev);
  145. return 0;
  146. }
  147. static int dwe_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
  148. {
  149. pm_runtime_put_sync(sd->dev);
  150. return 0;
  151. }
  152. static struct v4l2_subdev_internal_ops dwe_internal_ops = {
  153. .open = dwe_open,
  154. .close = dwe_close,
  155. };
  156. int dwe_hw_probe(struct platform_device *pdev)
  157. {
  158. struct device *dev = &pdev->dev;
  159. struct dwe_device *dwe_dev;
  160. struct resource *mem_res;
  161. int rc = 0;
  162. pr_info("enter %s\n", __func__);
  163. dwe_dev = kzalloc(sizeof(struct dwe_device), GFP_KERNEL);
  164. if (!dwe_dev) {
  165. rc = -ENOMEM;
  166. goto end;
  167. }
  168. dwe_dev->clk_core = devm_clk_get(dev, "core");
  169. if (IS_ERR(dwe_dev->clk_core)) {
  170. rc = PTR_ERR(dwe_dev->clk_core);
  171. dev_err(dev, "can't get core clock: %d\n", rc);
  172. return rc;
  173. }
  174. dwe_dev->clk_axi = devm_clk_get(dev, "axi");
  175. if (IS_ERR(dwe_dev->clk_axi)) {
  176. rc = PTR_ERR(dwe_dev->clk_axi);
  177. dev_err(dev, "can't get axi clock: %d\n", rc);
  178. return rc;
  179. }
  180. dwe_dev->clk_ahb = devm_clk_get(dev, "ahb");
  181. if (IS_ERR(dwe_dev->clk_ahb)) {
  182. rc = PTR_ERR(dwe_dev->clk_ahb);
  183. dev_err(dev, "can't get ahb clock: %d\n", rc);
  184. return rc;
  185. }
  186. dwe_dev->sd.internal_ops = &dwe_internal_ops;
  187. v4l2_subdev_init(&dwe_dev->sd, &dwe_v4l2_subdev_ops);
  188. snprintf(dwe_dev->sd.name, sizeof(dwe_dev->sd.name), DEVICE_NAME);
  189. dwe_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
  190. dwe_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
  191. dwe_dev->sd.owner = THIS_MODULE;
  192. dwe_dev->sd.dev = &pdev->dev;
  193. v4l2_set_subdevdata(&dwe_dev->sd, dwe_dev);
  194. dwe_dev->vd = kzalloc(sizeof(*dwe_dev->vd), GFP_KERNEL);
  195. if (WARN_ON(!dwe_dev->vd)) {
  196. rc = -ENOMEM;
  197. goto end;
  198. }
  199. rc = v4l2_device_register(&(pdev->dev), dwe_dev->vd);
  200. if (WARN_ON(rc < 0))
  201. goto end;
  202. rc = v4l2_device_register_subdev(dwe_dev->vd, &dwe_dev->sd);
  203. if (rc) {
  204. pr_err("failed to register subdev %d\n", rc);
  205. goto end;
  206. }
  207. mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  208. dwe_dev->ic_dev.base = devm_ioremap_resource(&pdev->dev, mem_res);
  209. if (IS_ERR(dwe_dev->ic_dev.base)) {
  210. pr_err("failed to get ioremap resource.\n");
  211. goto end;
  212. }
  213. #ifdef DWE_REG_RESET
  214. dwe_dev->ic_dev.reset = ioremap(DWE_REG_RESET, 4);
  215. #endif
  216. platform_set_drvdata(pdev, dwe_dev);
  217. rc = v4l2_device_register_subdev_nodes(dwe_dev->vd);
  218. pm_runtime_enable(&pdev->dev);
  219. pr_info("vvcam dewarp driver probed\n");
  220. return 0;
  221. end:
  222. return rc;
  223. }
  224. int dwe_hw_remove(struct platform_device *pdev)
  225. {
  226. struct dwe_device *dwe = platform_get_drvdata(pdev);
  227. pr_info("enter %s\n", __func__);
  228. if (!dwe)
  229. return -1;
  230. pm_runtime_disable(&pdev->dev);
  231. v4l2_device_unregister_subdev(&dwe->sd);
  232. v4l2_device_disconnect(dwe->vd);
  233. v4l2_device_put(dwe->vd);
  234. #ifdef DWE_REG_RESET
  235. iounmap(dwe->ic_dev.reset);
  236. #endif
  237. kfree(dwe);
  238. pr_info("vvcam dewarp driver removed\n");
  239. return 0;
  240. }
  241. static int dwe_system_suspend(struct device *dev)
  242. {
  243. return pm_runtime_force_suspend(dev);
  244. }
  245. static int dwe_system_resume(struct device *dev)
  246. {
  247. int ret;
  248. ret = pm_runtime_force_resume(dev);
  249. if (ret < 0) {
  250. dev_err(dev, "force resume %s failed!\n", dev_name(dev));
  251. return ret;
  252. }
  253. return 0;
  254. }
  255. static int dwe_runtime_suspend(struct device *dev)
  256. {
  257. struct dwe_device *dwe_dev = dev_get_drvdata(dev);
  258. dwe_disable_clocks(dwe_dev);
  259. return 0;
  260. }
  261. static int dwe_runtime_resume(struct device *dev)
  262. {
  263. struct dwe_device *dwe_dev = dev_get_drvdata(dev);
  264. dwe_enable_clocks(dwe_dev);
  265. return 0;
  266. }
  267. static const struct dev_pm_ops dwe_pm_ops = {
  268. SET_SYSTEM_SLEEP_PM_OPS(dwe_system_suspend, dwe_system_resume)
  269. SET_RUNTIME_PM_OPS(dwe_runtime_suspend, dwe_runtime_resume, NULL)
  270. };
  271. static const struct of_device_id dwe_of_match[] = {
  272. {.compatible = DWE_COMPAT_NAME,},
  273. { /* sentinel */ },
  274. };
  275. MODULE_DEVICE_TABLE(of, dwe_of_match);
  276. static struct platform_driver viv_dwe_driver = {
  277. .probe = dwe_hw_probe,
  278. .remove = dwe_hw_remove,
  279. .driver = {
  280. .name = DWE_DEVICE_NAME,
  281. .owner = THIS_MODULE,
  282. .of_match_table = dwe_of_match,
  283. .pm = &dwe_pm_ops,
  284. }
  285. };
  286. static int __init viv_dwe_init_module(void)
  287. {
  288. int ret = 0;
  289. pr_info("enter %s\n", __func__);
  290. ret = platform_driver_register(&viv_dwe_driver);
  291. if (ret)
  292. pr_err("register platform driver failed.\n");
  293. return ret;
  294. }
  295. static void __exit viv_dwe_exit_module(void)
  296. {
  297. pr_info("enter %s\n", __func__);
  298. platform_driver_unregister(&viv_dwe_driver);
  299. }
  300. module_init(viv_dwe_init_module);
  301. module_exit(viv_dwe_exit_module);
  302. MODULE_AUTHOR("zhiye.yin@verisilicon.com");
  303. MODULE_LICENSE("GPL");
  304. MODULE_ALIAS("Dewarp");
  305. MODULE_VERSION("1.0");