cam_cpas_intf.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/of.h>
  6. #include <linux/module.h>
  7. #include <linux/kernel.h>
  8. #include <linux/platform_device.h>
  9. #include <media/v4l2-event.h>
  10. #include <media/v4l2-ioctl.h>
  11. #include <media/v4l2-subdev.h>
  12. #include <media/cam_cpas.h>
  13. #include <media/cam_req_mgr.h>
  14. #include <dt-bindings/msm/msm-camera.h>
  15. #include "cam_subdev.h"
  16. #include "cam_cpas_hw_intf.h"
  17. #include "cam_cpas_soc.h"
  18. #include "camera_main.h"
  19. #define CAM_CPAS_DEV_NAME "cam-cpas"
  20. #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
  21. /**
  22. * struct cam_cpas_intf : CPAS interface
  23. *
  24. * @pdev: Platform device
  25. * @subdev: Subdev info
  26. * @hw_intf: CPAS HW interface
  27. * @hw_caps: CPAS HW capabilities
  28. * @intf_lock: CPAS interface mutex
  29. * @open_cnt: CPAS subdev open count
  30. * @probe_done: Whether CPAS prove completed
  31. *
  32. */
  33. struct cam_cpas_intf {
  34. struct platform_device *pdev;
  35. struct cam_subdev subdev;
  36. struct cam_hw_intf *hw_intf;
  37. struct cam_cpas_hw_caps hw_caps;
  38. struct mutex intf_lock;
  39. uint32_t open_cnt;
  40. bool probe_done;
  41. };
  42. static struct cam_cpas_intf *g_cpas_intf;
  43. const char *cam_cpas_axi_util_path_type_to_string(
  44. uint32_t path_data_type)
  45. {
  46. switch (path_data_type) {
  47. /* IFE Paths */
  48. case CAM_AXI_PATH_DATA_IFE_LINEAR:
  49. return "IFE_LINEAR";
  50. case CAM_AXI_PATH_DATA_IFE_VID:
  51. return "IFE_VID";
  52. case CAM_AXI_PATH_DATA_IFE_DISP:
  53. return "IFE_DISP";
  54. case CAM_AXI_PATH_DATA_IFE_STATS:
  55. return "IFE_STATS";
  56. case CAM_AXI_PATH_DATA_IFE_RDI0:
  57. return "IFE_RDI0";
  58. case CAM_AXI_PATH_DATA_IFE_RDI1:
  59. return "IFE_RDI1";
  60. case CAM_AXI_PATH_DATA_IFE_RDI2:
  61. return "IFE_RDI2";
  62. case CAM_AXI_PATH_DATA_IFE_RDI3:
  63. return "IFE_RDI3";
  64. case CAM_AXI_PATH_DATA_IFE_PDAF:
  65. return "IFE_PDAF";
  66. case CAM_AXI_PATH_DATA_IFE_PIXEL_RAW:
  67. return "IFE_PIXEL_RAW";
  68. /* IPE Paths */
  69. case CAM_AXI_PATH_DATA_IPE_RD_IN:
  70. return "IPE_RD_IN";
  71. case CAM_AXI_PATH_DATA_IPE_RD_REF:
  72. return "IPE_RD_REF";
  73. case CAM_AXI_PATH_DATA_IPE_WR_VID:
  74. return "IPE_WR_VID";
  75. case CAM_AXI_PATH_DATA_IPE_WR_DISP:
  76. return "IPE_WR_DISP";
  77. case CAM_AXI_PATH_DATA_IPE_WR_REF:
  78. return "IPE_WR_REF";
  79. /* OPE Paths */
  80. case CAM_AXI_PATH_DATA_OPE_RD_IN:
  81. return "OPE_RD_IN";
  82. case CAM_AXI_PATH_DATA_OPE_RD_REF:
  83. return "OPE_RD_REF";
  84. case CAM_AXI_PATH_DATA_OPE_WR_VID:
  85. return "OPE_WR_VID";
  86. case CAM_AXI_PATH_DATA_OPE_WR_DISP:
  87. return "OPE_WR_DISP";
  88. case CAM_AXI_PATH_DATA_OPE_WR_REF:
  89. return "OPE_WR_REF";
  90. /* Common Paths */
  91. case CAM_AXI_PATH_DATA_ALL:
  92. return "DATA_ALL";
  93. default:
  94. return "IFE_PATH_INVALID";
  95. }
  96. }
  97. EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string);
  98. const char *cam_cpas_axi_util_trans_type_to_string(
  99. uint32_t transac_type)
  100. {
  101. switch (transac_type) {
  102. case CAM_AXI_TRANSACTION_READ:
  103. return "TRANSAC_READ";
  104. case CAM_AXI_TRANSACTION_WRITE:
  105. return "TRANSAC_WRITE";
  106. default:
  107. return "TRANSAC_INVALID";
  108. }
  109. }
  110. EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
  111. int cam_cpas_is_feature_supported(uint32_t flag)
  112. {
  113. struct cam_hw_info *cpas_hw = NULL;
  114. struct cam_cpas_private_soc *soc_private = NULL;
  115. uint32_t feature_mask;
  116. if (!CAM_CPAS_INTF_INITIALIZED()) {
  117. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  118. return -ENODEV;
  119. }
  120. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  121. soc_private =
  122. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  123. feature_mask = soc_private->feature_mask;
  124. if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
  125. CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
  126. return -EINVAL;
  127. }
  128. return feature_mask & flag ? 1 : 0;
  129. }
  130. EXPORT_SYMBOL(cam_cpas_is_feature_supported);
  131. int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
  132. {
  133. struct cam_hw_info *cpas_hw = NULL;
  134. if (!CAM_CPAS_INTF_INITIALIZED()) {
  135. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  136. return -ENODEV;
  137. }
  138. if (!hw_version) {
  139. CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version);
  140. return -EINVAL;
  141. }
  142. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  143. *hw_version = cpas_hw->soc_info.hw_version;
  144. if (*hw_version == CAM_CPAS_TITAN_NONE) {
  145. CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d",
  146. *hw_version);
  147. }
  148. return 0;
  149. }
  150. int cam_cpas_get_hw_info(uint32_t *camera_family,
  151. struct cam_hw_version *camera_version,
  152. struct cam_hw_version *cpas_version,
  153. uint32_t *cam_caps)
  154. {
  155. if (!CAM_CPAS_INTF_INITIALIZED()) {
  156. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  157. return -ENODEV;
  158. }
  159. if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
  160. CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
  161. camera_family, camera_version, cpas_version, cam_caps);
  162. return -EINVAL;
  163. }
  164. *camera_family = g_cpas_intf->hw_caps.camera_family;
  165. *camera_version = g_cpas_intf->hw_caps.camera_version;
  166. *cpas_version = g_cpas_intf->hw_caps.cpas_version;
  167. *cam_caps = g_cpas_intf->hw_caps.camera_capability;
  168. return 0;
  169. }
  170. EXPORT_SYMBOL(cam_cpas_get_hw_info);
  171. int cam_cpas_reg_write(uint32_t client_handle,
  172. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  173. uint32_t value)
  174. {
  175. int rc;
  176. if (!CAM_CPAS_INTF_INITIALIZED()) {
  177. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  178. return -ENODEV;
  179. }
  180. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  181. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write;
  182. cmd_reg_write.client_handle = client_handle;
  183. cmd_reg_write.reg_base = reg_base;
  184. cmd_reg_write.offset = offset;
  185. cmd_reg_write.value = value;
  186. cmd_reg_write.mb = mb;
  187. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  188. g_cpas_intf->hw_intf->hw_priv,
  189. CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write,
  190. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  191. if (rc)
  192. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  193. } else {
  194. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  195. rc = -EINVAL;
  196. }
  197. return rc;
  198. }
  199. EXPORT_SYMBOL(cam_cpas_reg_write);
  200. int cam_cpas_reg_read(uint32_t client_handle,
  201. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  202. uint32_t *value)
  203. {
  204. int rc;
  205. if (!CAM_CPAS_INTF_INITIALIZED()) {
  206. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  207. return -ENODEV;
  208. }
  209. if (!value) {
  210. CAM_ERR(CAM_CPAS, "Invalid arg value");
  211. return -EINVAL;
  212. }
  213. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  214. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read;
  215. cmd_reg_read.client_handle = client_handle;
  216. cmd_reg_read.reg_base = reg_base;
  217. cmd_reg_read.offset = offset;
  218. cmd_reg_read.mb = mb;
  219. cmd_reg_read.value = 0;
  220. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  221. g_cpas_intf->hw_intf->hw_priv,
  222. CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read,
  223. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  224. if (rc) {
  225. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  226. return rc;
  227. }
  228. *value = cmd_reg_read.value;
  229. } else {
  230. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  231. rc = -EINVAL;
  232. }
  233. return rc;
  234. }
  235. EXPORT_SYMBOL(cam_cpas_reg_read);
  236. int cam_cpas_update_axi_vote(uint32_t client_handle,
  237. struct cam_axi_vote *axi_vote)
  238. {
  239. int rc;
  240. if (!CAM_CPAS_INTF_INITIALIZED()) {
  241. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  242. return -ENODEV;
  243. }
  244. if (!axi_vote) {
  245. CAM_ERR(CAM_CPAS, "NULL axi vote");
  246. return -EINVAL;
  247. }
  248. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  249. struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote;
  250. cmd_axi_vote.client_handle = client_handle;
  251. cmd_axi_vote.axi_vote = axi_vote;
  252. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  253. g_cpas_intf->hw_intf->hw_priv,
  254. CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote,
  255. sizeof(struct cam_cpas_hw_cmd_axi_vote));
  256. if (rc)
  257. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  258. } else {
  259. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  260. rc = -EINVAL;
  261. }
  262. return rc;
  263. }
  264. EXPORT_SYMBOL(cam_cpas_update_axi_vote);
  265. int cam_cpas_update_ahb_vote(uint32_t client_handle,
  266. struct cam_ahb_vote *ahb_vote)
  267. {
  268. int rc;
  269. if (!CAM_CPAS_INTF_INITIALIZED()) {
  270. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  271. return -ENODEV;
  272. }
  273. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  274. struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote;
  275. cmd_ahb_vote.client_handle = client_handle;
  276. cmd_ahb_vote.ahb_vote = ahb_vote;
  277. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  278. g_cpas_intf->hw_intf->hw_priv,
  279. CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote,
  280. sizeof(struct cam_cpas_hw_cmd_ahb_vote));
  281. if (rc)
  282. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  283. } else {
  284. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  285. rc = -EINVAL;
  286. }
  287. return rc;
  288. }
  289. EXPORT_SYMBOL(cam_cpas_update_ahb_vote);
  290. int cam_cpas_stop(uint32_t client_handle)
  291. {
  292. int rc;
  293. if (!CAM_CPAS_INTF_INITIALIZED()) {
  294. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  295. return -ENODEV;
  296. }
  297. if (g_cpas_intf->hw_intf->hw_ops.stop) {
  298. struct cam_cpas_hw_cmd_stop cmd_hw_stop;
  299. cmd_hw_stop.client_handle = client_handle;
  300. rc = g_cpas_intf->hw_intf->hw_ops.stop(
  301. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop,
  302. sizeof(struct cam_cpas_hw_cmd_stop));
  303. if (rc)
  304. CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc);
  305. } else {
  306. CAM_ERR(CAM_CPAS, "Invalid stop ops");
  307. rc = -EINVAL;
  308. }
  309. return rc;
  310. }
  311. EXPORT_SYMBOL(cam_cpas_stop);
  312. int cam_cpas_start(uint32_t client_handle,
  313. struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote)
  314. {
  315. int rc;
  316. if (!CAM_CPAS_INTF_INITIALIZED()) {
  317. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  318. return -ENODEV;
  319. }
  320. if (!axi_vote) {
  321. CAM_ERR(CAM_CPAS, "NULL axi vote");
  322. return -EINVAL;
  323. }
  324. if (g_cpas_intf->hw_intf->hw_ops.start) {
  325. struct cam_cpas_hw_cmd_start cmd_hw_start;
  326. cmd_hw_start.client_handle = client_handle;
  327. cmd_hw_start.ahb_vote = ahb_vote;
  328. cmd_hw_start.axi_vote = axi_vote;
  329. rc = g_cpas_intf->hw_intf->hw_ops.start(
  330. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start,
  331. sizeof(struct cam_cpas_hw_cmd_start));
  332. if (rc)
  333. CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc);
  334. } else {
  335. CAM_ERR(CAM_CPAS, "Invalid start ops");
  336. rc = -EINVAL;
  337. }
  338. return rc;
  339. }
  340. EXPORT_SYMBOL(cam_cpas_start);
  341. void cam_cpas_log_votes(void)
  342. {
  343. uint32_t dummy_args;
  344. int rc;
  345. if (!CAM_CPAS_INTF_INITIALIZED()) {
  346. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  347. return;
  348. }
  349. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  350. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  351. g_cpas_intf->hw_intf->hw_priv,
  352. CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args,
  353. sizeof(dummy_args));
  354. if (rc)
  355. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  356. } else {
  357. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  358. }
  359. }
  360. EXPORT_SYMBOL(cam_cpas_log_votes);
  361. int cam_cpas_select_qos_settings(uint32_t selection_mask)
  362. {
  363. int rc = 0;
  364. if (!CAM_CPAS_INTF_INITIALIZED()) {
  365. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  366. return -EBADR;
  367. }
  368. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  369. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  370. g_cpas_intf->hw_intf->hw_priv,
  371. CAM_CPAS_HW_CMD_SELECT_QOS, &selection_mask,
  372. sizeof(selection_mask));
  373. if (rc)
  374. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  375. } else {
  376. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  377. rc = -EBADR;
  378. }
  379. return rc;
  380. }
  381. EXPORT_SYMBOL(cam_cpas_select_qos_settings);
  382. int cam_cpas_unregister_client(uint32_t client_handle)
  383. {
  384. int rc;
  385. if (!CAM_CPAS_INTF_INITIALIZED()) {
  386. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  387. return -ENODEV;
  388. }
  389. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  390. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  391. g_cpas_intf->hw_intf->hw_priv,
  392. CAM_CPAS_HW_CMD_UNREGISTER_CLIENT,
  393. &client_handle, sizeof(uint32_t));
  394. if (rc)
  395. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  396. } else {
  397. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  398. rc = -EINVAL;
  399. }
  400. return rc;
  401. }
  402. EXPORT_SYMBOL(cam_cpas_unregister_client);
  403. int cam_cpas_register_client(
  404. struct cam_cpas_register_params *register_params)
  405. {
  406. int rc;
  407. if (!CAM_CPAS_INTF_INITIALIZED()) {
  408. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  409. return -ENODEV;
  410. }
  411. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  412. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  413. g_cpas_intf->hw_intf->hw_priv,
  414. CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params,
  415. sizeof(struct cam_cpas_register_params));
  416. if (rc)
  417. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  418. } else {
  419. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  420. rc = -EINVAL;
  421. }
  422. return rc;
  423. }
  424. EXPORT_SYMBOL(cam_cpas_register_client);
  425. int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
  426. struct cam_control *cmd)
  427. {
  428. int rc = 0;
  429. if (!cmd) {
  430. CAM_ERR(CAM_CPAS, "Invalid input cmd");
  431. return -EINVAL;
  432. }
  433. switch (cmd->op_code) {
  434. case CAM_QUERY_CAP: {
  435. struct cam_cpas_query_cap query;
  436. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  437. sizeof(query));
  438. if (rc) {
  439. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  440. rc);
  441. break;
  442. }
  443. rc = cam_cpas_get_hw_info(&query.camera_family,
  444. &query.camera_version, &query.cpas_version,
  445. &query.reserved);
  446. if (rc)
  447. break;
  448. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  449. sizeof(query));
  450. if (rc)
  451. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  452. break;
  453. }
  454. case CAM_SD_SHUTDOWN:
  455. break;
  456. default:
  457. CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code);
  458. rc = -EINVAL;
  459. break;
  460. }
  461. return rc;
  462. }
  463. static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
  464. struct v4l2_subdev_fh *fh)
  465. {
  466. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  467. if (!cpas_intf || !cpas_intf->probe_done) {
  468. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  469. return -ENODEV;
  470. }
  471. mutex_lock(&cpas_intf->intf_lock);
  472. cpas_intf->open_cnt++;
  473. CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt);
  474. mutex_unlock(&cpas_intf->intf_lock);
  475. return 0;
  476. }
  477. static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
  478. struct v4l2_subdev_fh *fh)
  479. {
  480. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  481. if (!cpas_intf || !cpas_intf->probe_done) {
  482. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  483. return -ENODEV;
  484. }
  485. mutex_lock(&cpas_intf->intf_lock);
  486. cpas_intf->open_cnt--;
  487. CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
  488. mutex_unlock(&cpas_intf->intf_lock);
  489. return 0;
  490. }
  491. static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
  492. unsigned int cmd, void *arg)
  493. {
  494. int32_t rc;
  495. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  496. if (!cpas_intf || !cpas_intf->probe_done) {
  497. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  498. return -ENODEV;
  499. }
  500. switch (cmd) {
  501. case VIDIOC_CAM_CONTROL:
  502. rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
  503. break;
  504. default:
  505. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  506. rc = -EINVAL;
  507. break;
  508. }
  509. return rc;
  510. }
  511. #ifdef CONFIG_COMPAT
  512. static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
  513. unsigned int cmd, unsigned long arg)
  514. {
  515. struct cam_control cmd_data;
  516. int32_t rc;
  517. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  518. if (!cpas_intf || !cpas_intf->probe_done) {
  519. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  520. return -ENODEV;
  521. }
  522. if (copy_from_user(&cmd_data, (void __user *)arg,
  523. sizeof(cmd_data))) {
  524. CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu",
  525. (void __user *)arg, sizeof(cmd_data));
  526. return -EFAULT;
  527. }
  528. switch (cmd) {
  529. case VIDIOC_CAM_CONTROL:
  530. rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
  531. break;
  532. default:
  533. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  534. rc = -EINVAL;
  535. break;
  536. }
  537. if (!rc) {
  538. if (copy_to_user((void __user *)arg, &cmd_data,
  539. sizeof(cmd_data))) {
  540. CAM_ERR(CAM_CPAS,
  541. "Failed to copy to user_ptr=%pK size=%zu",
  542. (void __user *)arg, sizeof(cmd_data));
  543. rc = -EFAULT;
  544. }
  545. }
  546. return rc;
  547. }
  548. #endif
  549. static struct v4l2_subdev_core_ops cpas_subdev_core_ops = {
  550. .ioctl = cam_cpas_subdev_ioctl,
  551. #ifdef CONFIG_COMPAT
  552. .compat_ioctl32 = cam_cpas_subdev_compat_ioctl,
  553. #endif
  554. };
  555. static const struct v4l2_subdev_ops cpas_subdev_ops = {
  556. .core = &cpas_subdev_core_ops,
  557. };
  558. static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = {
  559. .open = cam_cpas_subdev_open,
  560. .close = cam_cpas_subdev_close,
  561. };
  562. static int cam_cpas_subdev_register(struct platform_device *pdev)
  563. {
  564. int rc;
  565. struct cam_subdev *subdev;
  566. if (!g_cpas_intf)
  567. return -EINVAL;
  568. subdev = &g_cpas_intf->subdev;
  569. subdev->name = CAM_CPAS_DEV_NAME;
  570. subdev->pdev = pdev;
  571. subdev->ops = &cpas_subdev_ops;
  572. subdev->internal_ops = &cpas_subdev_intern_ops;
  573. subdev->token = g_cpas_intf;
  574. subdev->sd_flags =
  575. V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
  576. subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
  577. rc = cam_register_subdev(subdev);
  578. if (rc) {
  579. CAM_ERR(CAM_CPAS, "failed register subdev: %s!",
  580. CAM_CPAS_DEV_NAME);
  581. return rc;
  582. }
  583. platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf);
  584. return rc;
  585. }
  586. static int cam_cpas_dev_component_bind(struct device *dev,
  587. struct device *master_dev, void *data)
  588. {
  589. struct cam_cpas_hw_caps *hw_caps;
  590. struct cam_hw_intf *hw_intf;
  591. int rc;
  592. struct platform_device *pdev = to_platform_device(dev);
  593. if (g_cpas_intf) {
  594. CAM_ERR(CAM_CPAS, "cpas component already binded");
  595. return -EALREADY;
  596. }
  597. g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL);
  598. if (!g_cpas_intf)
  599. return -ENOMEM;
  600. mutex_init(&g_cpas_intf->intf_lock);
  601. g_cpas_intf->pdev = pdev;
  602. rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf);
  603. if (rc || (g_cpas_intf->hw_intf == NULL)) {
  604. CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc);
  605. goto error_destroy_mem;
  606. }
  607. hw_intf = g_cpas_intf->hw_intf;
  608. hw_caps = &g_cpas_intf->hw_caps;
  609. if (hw_intf->hw_ops.get_hw_caps) {
  610. rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv,
  611. hw_caps, sizeof(struct cam_cpas_hw_caps));
  612. if (rc) {
  613. CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc);
  614. goto error_hw_remove;
  615. }
  616. } else {
  617. CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops");
  618. goto error_hw_remove;
  619. }
  620. rc = cam_cpas_subdev_register(pdev);
  621. if (rc)
  622. goto error_hw_remove;
  623. g_cpas_intf->probe_done = true;
  624. CAM_DBG(CAM_CPAS,
  625. "Component bound successfully %d, %d.%d.%d, %d.%d.%d, 0x%x",
  626. hw_caps->camera_family, hw_caps->camera_version.major,
  627. hw_caps->camera_version.minor, hw_caps->camera_version.incr,
  628. hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
  629. hw_caps->cpas_version.incr, hw_caps->camera_capability);
  630. return rc;
  631. error_hw_remove:
  632. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  633. error_destroy_mem:
  634. mutex_destroy(&g_cpas_intf->intf_lock);
  635. kfree(g_cpas_intf);
  636. g_cpas_intf = NULL;
  637. CAM_ERR(CAM_CPAS, "CPAS component bind failed");
  638. return rc;
  639. }
  640. static void cam_cpas_dev_component_unbind(struct device *dev,
  641. struct device *master_dev, void *data)
  642. {
  643. if (!CAM_CPAS_INTF_INITIALIZED()) {
  644. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  645. return;
  646. }
  647. mutex_lock(&g_cpas_intf->intf_lock);
  648. g_cpas_intf->probe_done = false;
  649. cam_unregister_subdev(&g_cpas_intf->subdev);
  650. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  651. mutex_unlock(&g_cpas_intf->intf_lock);
  652. mutex_destroy(&g_cpas_intf->intf_lock);
  653. kfree(g_cpas_intf);
  654. g_cpas_intf = NULL;
  655. }
  656. const static struct component_ops cam_cpas_dev_component_ops = {
  657. .bind = cam_cpas_dev_component_bind,
  658. .unbind = cam_cpas_dev_component_unbind,
  659. };
  660. static int cam_cpas_dev_probe(struct platform_device *pdev)
  661. {
  662. int rc = 0;
  663. CAM_DBG(CAM_CPAS, "Adding CPAS INTF component");
  664. rc = component_add(&pdev->dev, &cam_cpas_dev_component_ops);
  665. if (rc)
  666. CAM_ERR(CAM_CPAS, "failed to add component rc: %d", rc);
  667. return rc;
  668. }
  669. static int cam_cpas_dev_remove(struct platform_device *pdev)
  670. {
  671. component_del(&pdev->dev, &cam_cpas_dev_component_ops);
  672. return 0;
  673. }
  674. static const struct of_device_id cam_cpas_dt_match[] = {
  675. {.compatible = "qcom,cam-cpas"},
  676. {}
  677. };
  678. struct platform_driver cam_cpas_driver = {
  679. .probe = cam_cpas_dev_probe,
  680. .remove = cam_cpas_dev_remove,
  681. .driver = {
  682. .name = CAM_CPAS_DEV_NAME,
  683. .owner = THIS_MODULE,
  684. .of_match_table = cam_cpas_dt_match,
  685. .suppress_bind_attrs = true,
  686. },
  687. };
  688. int cam_cpas_dev_init_module(void)
  689. {
  690. return platform_driver_register(&cam_cpas_driver);
  691. }
  692. void cam_cpas_dev_exit_module(void)
  693. {
  694. platform_driver_unregister(&cam_cpas_driver);
  695. }
  696. MODULE_DESCRIPTION("MSM CPAS driver");
  697. MODULE_LICENSE("GPL v2");