cam_cpas_intf.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021, 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-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. /* SFE Paths */
  91. case CAM_AXI_PATH_DATA_SFE_NRDI:
  92. return "SFE_NRDI";
  93. case CAM_AXI_PATH_DATA_SFE_RDI0:
  94. return "SFE_RDI0";
  95. case CAM_AXI_PATH_DATA_SFE_RDI1:
  96. return "SFE_RDI1";
  97. case CAM_AXI_PATH_DATA_SFE_RDI2:
  98. return "SFE_RDI2";
  99. case CAM_AXI_PATH_DATA_SFE_RDI3:
  100. return "SFE_RDI3";
  101. case CAM_AXI_PATH_DATA_SFE_RDI4:
  102. return "SFE_RDI4";
  103. case CAM_AXI_PATH_DATA_SFE_STATS:
  104. return "SFE_STATS";
  105. /* Common Paths */
  106. case CAM_AXI_PATH_DATA_ALL:
  107. return "DATA_ALL";
  108. default:
  109. return "IFE_PATH_INVALID";
  110. }
  111. }
  112. EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string);
  113. const char *cam_cpas_axi_util_trans_type_to_string(
  114. uint32_t transac_type)
  115. {
  116. switch (transac_type) {
  117. case CAM_AXI_TRANSACTION_READ:
  118. return "TRANSAC_READ";
  119. case CAM_AXI_TRANSACTION_WRITE:
  120. return "TRANSAC_WRITE";
  121. default:
  122. return "TRANSAC_INVALID";
  123. }
  124. }
  125. EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
  126. bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
  127. uint32_t *fuse_val)
  128. {
  129. struct cam_hw_info *cpas_hw = NULL;
  130. struct cam_cpas_private_soc *soc_private = NULL;
  131. bool supported = true;
  132. int32_t i;
  133. if (!CAM_CPAS_INTF_INITIALIZED()) {
  134. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  135. return false;
  136. }
  137. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  138. soc_private =
  139. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  140. if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
  141. CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
  142. return false;
  143. }
  144. for (i = 0; i < soc_private->num_feature_info; i++)
  145. if (soc_private->feature_info[i].feature == flag)
  146. break;
  147. if (i == soc_private->num_feature_info) {
  148. CAM_INFO(CAM_CPAS, "Feature not found, no of featues: %d",
  149. soc_private->num_feature_info);
  150. goto end;
  151. }
  152. if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE
  153. || (soc_private->feature_info[i].type ==
  154. CAM_CPAS_FEATURE_TYPE_ENABLE)) {
  155. if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map)
  156. supported = soc_private->feature_info[i].enable;
  157. else
  158. supported = !soc_private->feature_info[i].enable;
  159. } else {
  160. if (!fuse_val) {
  161. CAM_ERR(CAM_CPAS,
  162. "Invalid arg fuse_val");
  163. } else {
  164. *fuse_val = soc_private->feature_info[i].value;
  165. }
  166. }
  167. end:
  168. return supported;
  169. }
  170. EXPORT_SYMBOL(cam_cpas_is_feature_supported);
  171. int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
  172. {
  173. struct cam_hw_info *cpas_hw = NULL;
  174. if (!CAM_CPAS_INTF_INITIALIZED()) {
  175. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  176. return -ENODEV;
  177. }
  178. if (!hw_version) {
  179. CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version);
  180. return -EINVAL;
  181. }
  182. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  183. *hw_version = cpas_hw->soc_info.hw_version;
  184. if (*hw_version == CAM_CPAS_TITAN_NONE) {
  185. CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d",
  186. *hw_version);
  187. }
  188. return 0;
  189. }
  190. int cam_cpas_get_hw_info(uint32_t *camera_family,
  191. struct cam_hw_version *camera_version,
  192. struct cam_hw_version *cpas_version,
  193. uint32_t *cam_caps,
  194. struct cam_cpas_fuse_info *cam_fuse_info)
  195. {
  196. if (!CAM_CPAS_INTF_INITIALIZED()) {
  197. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  198. return -ENODEV;
  199. }
  200. if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
  201. CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
  202. camera_family, camera_version, cpas_version, cam_caps);
  203. return -EINVAL;
  204. }
  205. *camera_family = g_cpas_intf->hw_caps.camera_family;
  206. *camera_version = g_cpas_intf->hw_caps.camera_version;
  207. *cpas_version = g_cpas_intf->hw_caps.cpas_version;
  208. *cam_caps = g_cpas_intf->hw_caps.camera_capability;
  209. if (cam_fuse_info)
  210. *cam_fuse_info = g_cpas_intf->hw_caps.fuse_info;
  211. CAM_DBG(CAM_CPAS, "Family %d, version %d.%d cam_caps %d",
  212. *camera_family, camera_version->major,
  213. camera_version->minor, *cam_caps);
  214. return 0;
  215. }
  216. EXPORT_SYMBOL(cam_cpas_get_hw_info);
  217. int cam_cpas_reg_write(uint32_t client_handle,
  218. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  219. uint32_t value)
  220. {
  221. int rc;
  222. if (!CAM_CPAS_INTF_INITIALIZED()) {
  223. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  224. return -ENODEV;
  225. }
  226. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  227. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write;
  228. cmd_reg_write.client_handle = client_handle;
  229. cmd_reg_write.reg_base = reg_base;
  230. cmd_reg_write.offset = offset;
  231. cmd_reg_write.value = value;
  232. cmd_reg_write.mb = mb;
  233. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  234. g_cpas_intf->hw_intf->hw_priv,
  235. CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write,
  236. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  237. if (rc)
  238. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  239. } else {
  240. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  241. rc = -EINVAL;
  242. }
  243. return rc;
  244. }
  245. EXPORT_SYMBOL(cam_cpas_reg_write);
  246. int cam_cpas_reg_read(uint32_t client_handle,
  247. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  248. uint32_t *value)
  249. {
  250. int rc;
  251. if (!CAM_CPAS_INTF_INITIALIZED()) {
  252. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  253. return -ENODEV;
  254. }
  255. if (!value) {
  256. CAM_ERR(CAM_CPAS, "Invalid arg value");
  257. return -EINVAL;
  258. }
  259. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  260. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read;
  261. cmd_reg_read.client_handle = client_handle;
  262. cmd_reg_read.reg_base = reg_base;
  263. cmd_reg_read.offset = offset;
  264. cmd_reg_read.mb = mb;
  265. cmd_reg_read.value = 0;
  266. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  267. g_cpas_intf->hw_intf->hw_priv,
  268. CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read,
  269. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  270. if (rc) {
  271. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  272. return rc;
  273. }
  274. *value = cmd_reg_read.value;
  275. } else {
  276. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  277. rc = -EINVAL;
  278. }
  279. return rc;
  280. }
  281. EXPORT_SYMBOL(cam_cpas_reg_read);
  282. int cam_cpas_update_axi_vote(uint32_t client_handle,
  283. struct cam_axi_vote *axi_vote)
  284. {
  285. int rc;
  286. if (!CAM_CPAS_INTF_INITIALIZED()) {
  287. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  288. return -ENODEV;
  289. }
  290. if (!axi_vote) {
  291. CAM_ERR(CAM_CPAS, "NULL axi vote");
  292. return -EINVAL;
  293. }
  294. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  295. struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote;
  296. cmd_axi_vote.client_handle = client_handle;
  297. cmd_axi_vote.axi_vote = axi_vote;
  298. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  299. g_cpas_intf->hw_intf->hw_priv,
  300. CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote,
  301. sizeof(struct cam_cpas_hw_cmd_axi_vote));
  302. if (rc)
  303. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  304. } else {
  305. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  306. rc = -EINVAL;
  307. }
  308. return rc;
  309. }
  310. EXPORT_SYMBOL(cam_cpas_update_axi_vote);
  311. int cam_cpas_update_ahb_vote(uint32_t client_handle,
  312. struct cam_ahb_vote *ahb_vote)
  313. {
  314. int rc;
  315. if (!CAM_CPAS_INTF_INITIALIZED()) {
  316. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  317. return -ENODEV;
  318. }
  319. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  320. struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote;
  321. cmd_ahb_vote.client_handle = client_handle;
  322. cmd_ahb_vote.ahb_vote = ahb_vote;
  323. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  324. g_cpas_intf->hw_intf->hw_priv,
  325. CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote,
  326. sizeof(struct cam_cpas_hw_cmd_ahb_vote));
  327. if (rc)
  328. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  329. } else {
  330. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  331. rc = -EINVAL;
  332. }
  333. return rc;
  334. }
  335. EXPORT_SYMBOL(cam_cpas_update_ahb_vote);
  336. int cam_cpas_stop(uint32_t client_handle)
  337. {
  338. int rc;
  339. if (!CAM_CPAS_INTF_INITIALIZED()) {
  340. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  341. return -ENODEV;
  342. }
  343. if (g_cpas_intf->hw_intf->hw_ops.stop) {
  344. struct cam_cpas_hw_cmd_stop cmd_hw_stop;
  345. cmd_hw_stop.client_handle = client_handle;
  346. rc = g_cpas_intf->hw_intf->hw_ops.stop(
  347. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop,
  348. sizeof(struct cam_cpas_hw_cmd_stop));
  349. if (rc)
  350. CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc);
  351. } else {
  352. CAM_ERR(CAM_CPAS, "Invalid stop ops");
  353. rc = -EINVAL;
  354. }
  355. return rc;
  356. }
  357. EXPORT_SYMBOL(cam_cpas_stop);
  358. int cam_cpas_start(uint32_t client_handle,
  359. struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote)
  360. {
  361. int rc;
  362. if (!CAM_CPAS_INTF_INITIALIZED()) {
  363. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  364. return -ENODEV;
  365. }
  366. if (!axi_vote) {
  367. CAM_ERR(CAM_CPAS, "NULL axi vote");
  368. return -EINVAL;
  369. }
  370. if (g_cpas_intf->hw_intf->hw_ops.start) {
  371. struct cam_cpas_hw_cmd_start cmd_hw_start;
  372. cmd_hw_start.client_handle = client_handle;
  373. cmd_hw_start.ahb_vote = ahb_vote;
  374. cmd_hw_start.axi_vote = axi_vote;
  375. rc = g_cpas_intf->hw_intf->hw_ops.start(
  376. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start,
  377. sizeof(struct cam_cpas_hw_cmd_start));
  378. if (rc)
  379. CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc);
  380. } else {
  381. CAM_ERR(CAM_CPAS, "Invalid start ops");
  382. rc = -EINVAL;
  383. }
  384. return rc;
  385. }
  386. EXPORT_SYMBOL(cam_cpas_start);
  387. void cam_cpas_log_votes(void)
  388. {
  389. uint32_t dummy_args;
  390. int rc;
  391. if (!CAM_CPAS_INTF_INITIALIZED()) {
  392. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  393. return;
  394. }
  395. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  396. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  397. g_cpas_intf->hw_intf->hw_priv,
  398. CAM_CPAS_HW_CMD_LOG_VOTE, &dummy_args,
  399. sizeof(dummy_args));
  400. if (rc)
  401. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  402. } else {
  403. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  404. }
  405. }
  406. EXPORT_SYMBOL(cam_cpas_log_votes);
  407. int cam_cpas_select_qos_settings(uint32_t selection_mask)
  408. {
  409. int rc = 0;
  410. if (!CAM_CPAS_INTF_INITIALIZED()) {
  411. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  412. return -EBADR;
  413. }
  414. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  415. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  416. g_cpas_intf->hw_intf->hw_priv,
  417. CAM_CPAS_HW_CMD_SELECT_QOS, &selection_mask,
  418. sizeof(selection_mask));
  419. if (rc)
  420. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  421. } else {
  422. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  423. rc = -EBADR;
  424. }
  425. return rc;
  426. }
  427. EXPORT_SYMBOL(cam_cpas_select_qos_settings);
  428. int cam_cpas_notify_event(const char *identifier_string,
  429. int32_t identifier_value)
  430. {
  431. int rc = 0;
  432. if (!CAM_CPAS_INTF_INITIALIZED()) {
  433. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  434. return -EBADR;
  435. }
  436. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  437. struct cam_cpas_hw_cmd_notify_event event = { 0 };
  438. event.identifier_string = identifier_string;
  439. event.identifier_value = identifier_value;
  440. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  441. g_cpas_intf->hw_intf->hw_priv,
  442. CAM_CPAS_HW_CMD_LOG_EVENT, &event,
  443. sizeof(event));
  444. if (rc)
  445. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  446. } else {
  447. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  448. rc = -EBADR;
  449. }
  450. return rc;
  451. }
  452. EXPORT_SYMBOL(cam_cpas_notify_event);
  453. int cam_cpas_unregister_client(uint32_t client_handle)
  454. {
  455. int rc;
  456. if (!CAM_CPAS_INTF_INITIALIZED()) {
  457. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  458. return -ENODEV;
  459. }
  460. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  461. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  462. g_cpas_intf->hw_intf->hw_priv,
  463. CAM_CPAS_HW_CMD_UNREGISTER_CLIENT,
  464. &client_handle, sizeof(uint32_t));
  465. if (rc)
  466. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  467. } else {
  468. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  469. rc = -EINVAL;
  470. }
  471. return rc;
  472. }
  473. EXPORT_SYMBOL(cam_cpas_unregister_client);
  474. int cam_cpas_register_client(
  475. struct cam_cpas_register_params *register_params)
  476. {
  477. int rc;
  478. if (!CAM_CPAS_INTF_INITIALIZED()) {
  479. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  480. return -ENODEV;
  481. }
  482. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  483. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  484. g_cpas_intf->hw_intf->hw_priv,
  485. CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params,
  486. sizeof(struct cam_cpas_register_params));
  487. if (rc)
  488. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  489. } else {
  490. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  491. rc = -EINVAL;
  492. }
  493. return rc;
  494. }
  495. EXPORT_SYMBOL(cam_cpas_register_client);
  496. int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
  497. struct cam_control *cmd)
  498. {
  499. int rc = 0;
  500. if (!cmd) {
  501. CAM_ERR(CAM_CPAS, "Invalid input cmd");
  502. return -EINVAL;
  503. }
  504. switch (cmd->op_code) {
  505. case CAM_QUERY_CAP: {
  506. struct cam_cpas_query_cap query;
  507. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  508. sizeof(query));
  509. if (rc) {
  510. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  511. rc);
  512. break;
  513. }
  514. rc = cam_cpas_get_hw_info(&query.camera_family,
  515. &query.camera_version, &query.cpas_version,
  516. &query.reserved, NULL);
  517. if (rc)
  518. break;
  519. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  520. sizeof(query));
  521. if (rc)
  522. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  523. break;
  524. }
  525. case CAM_QUERY_CAP_V2: {
  526. struct cam_cpas_query_cap_v2 query;
  527. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  528. sizeof(query));
  529. if (rc) {
  530. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  531. rc);
  532. break;
  533. }
  534. rc = cam_cpas_get_hw_info(&query.camera_family,
  535. &query.camera_version, &query.cpas_version,
  536. &query.reserved,
  537. &query.fuse_info);
  538. if (rc)
  539. break;
  540. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  541. sizeof(query));
  542. if (rc)
  543. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  544. break;
  545. }
  546. case CAM_SD_SHUTDOWN:
  547. break;
  548. default:
  549. CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code);
  550. rc = -EINVAL;
  551. break;
  552. }
  553. return rc;
  554. }
  555. static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
  556. struct v4l2_subdev_fh *fh)
  557. {
  558. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  559. if (!cpas_intf || !cpas_intf->probe_done) {
  560. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  561. return -ENODEV;
  562. }
  563. mutex_lock(&cpas_intf->intf_lock);
  564. cpas_intf->open_cnt++;
  565. CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt);
  566. mutex_unlock(&cpas_intf->intf_lock);
  567. return 0;
  568. }
  569. static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
  570. struct v4l2_subdev_fh *fh)
  571. {
  572. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  573. if (!cpas_intf || !cpas_intf->probe_done) {
  574. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  575. return -ENODEV;
  576. }
  577. mutex_lock(&cpas_intf->intf_lock);
  578. cpas_intf->open_cnt--;
  579. CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
  580. mutex_unlock(&cpas_intf->intf_lock);
  581. return 0;
  582. }
  583. static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
  584. unsigned int cmd, void *arg)
  585. {
  586. int32_t rc;
  587. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  588. if (!cpas_intf || !cpas_intf->probe_done) {
  589. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  590. return -ENODEV;
  591. }
  592. switch (cmd) {
  593. case VIDIOC_CAM_CONTROL:
  594. rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
  595. break;
  596. default:
  597. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  598. rc = -EINVAL;
  599. break;
  600. }
  601. return rc;
  602. }
  603. #ifdef CONFIG_COMPAT
  604. static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
  605. unsigned int cmd, unsigned long arg)
  606. {
  607. struct cam_control cmd_data;
  608. int32_t rc;
  609. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  610. if (!cpas_intf || !cpas_intf->probe_done) {
  611. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  612. return -ENODEV;
  613. }
  614. if (copy_from_user(&cmd_data, (void __user *)arg,
  615. sizeof(cmd_data))) {
  616. CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu",
  617. (void __user *)arg, sizeof(cmd_data));
  618. return -EFAULT;
  619. }
  620. switch (cmd) {
  621. case VIDIOC_CAM_CONTROL:
  622. rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
  623. break;
  624. default:
  625. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  626. rc = -EINVAL;
  627. break;
  628. }
  629. if (!rc) {
  630. if (copy_to_user((void __user *)arg, &cmd_data,
  631. sizeof(cmd_data))) {
  632. CAM_ERR(CAM_CPAS,
  633. "Failed to copy to user_ptr=%pK size=%zu",
  634. (void __user *)arg, sizeof(cmd_data));
  635. rc = -EFAULT;
  636. }
  637. }
  638. return rc;
  639. }
  640. #endif
  641. static struct v4l2_subdev_core_ops cpas_subdev_core_ops = {
  642. .ioctl = cam_cpas_subdev_ioctl,
  643. #ifdef CONFIG_COMPAT
  644. .compat_ioctl32 = cam_cpas_subdev_compat_ioctl,
  645. #endif
  646. };
  647. static const struct v4l2_subdev_ops cpas_subdev_ops = {
  648. .core = &cpas_subdev_core_ops,
  649. };
  650. static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = {
  651. .open = cam_cpas_subdev_open,
  652. .close = cam_cpas_subdev_close,
  653. };
  654. static int cam_cpas_subdev_register(struct platform_device *pdev)
  655. {
  656. int rc;
  657. struct cam_subdev *subdev;
  658. if (!g_cpas_intf)
  659. return -EINVAL;
  660. subdev = &g_cpas_intf->subdev;
  661. subdev->name = CAM_CPAS_DEV_NAME;
  662. subdev->pdev = pdev;
  663. subdev->ops = &cpas_subdev_ops;
  664. subdev->internal_ops = &cpas_subdev_intern_ops;
  665. subdev->token = g_cpas_intf;
  666. subdev->sd_flags =
  667. V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
  668. subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
  669. rc = cam_register_subdev(subdev);
  670. if (rc) {
  671. CAM_ERR(CAM_CPAS, "failed register subdev: %s!",
  672. CAM_CPAS_DEV_NAME);
  673. return rc;
  674. }
  675. platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf);
  676. return rc;
  677. }
  678. static int cam_cpas_dev_component_bind(struct device *dev,
  679. struct device *master_dev, void *data)
  680. {
  681. struct cam_cpas_hw_caps *hw_caps;
  682. struct cam_hw_intf *hw_intf;
  683. int rc;
  684. struct platform_device *pdev = to_platform_device(dev);
  685. if (g_cpas_intf) {
  686. CAM_ERR(CAM_CPAS, "cpas component already binded");
  687. return -EALREADY;
  688. }
  689. g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL);
  690. if (!g_cpas_intf)
  691. return -ENOMEM;
  692. mutex_init(&g_cpas_intf->intf_lock);
  693. g_cpas_intf->pdev = pdev;
  694. rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf);
  695. if (rc || (g_cpas_intf->hw_intf == NULL)) {
  696. CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc);
  697. goto error_destroy_mem;
  698. }
  699. hw_intf = g_cpas_intf->hw_intf;
  700. hw_caps = &g_cpas_intf->hw_caps;
  701. if (hw_intf->hw_ops.get_hw_caps) {
  702. rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv,
  703. hw_caps, sizeof(struct cam_cpas_hw_caps));
  704. if (rc) {
  705. CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc);
  706. goto error_hw_remove;
  707. }
  708. } else {
  709. CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops");
  710. goto error_hw_remove;
  711. }
  712. rc = cam_cpas_subdev_register(pdev);
  713. if (rc)
  714. goto error_hw_remove;
  715. g_cpas_intf->probe_done = true;
  716. CAM_DBG(CAM_CPAS,
  717. "Component bound successfully %d, %d.%d.%d, %d.%d.%d, 0x%x",
  718. hw_caps->camera_family, hw_caps->camera_version.major,
  719. hw_caps->camera_version.minor, hw_caps->camera_version.incr,
  720. hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
  721. hw_caps->cpas_version.incr, hw_caps->camera_capability);
  722. return rc;
  723. error_hw_remove:
  724. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  725. error_destroy_mem:
  726. mutex_destroy(&g_cpas_intf->intf_lock);
  727. kfree(g_cpas_intf);
  728. g_cpas_intf = NULL;
  729. CAM_ERR(CAM_CPAS, "CPAS component bind failed");
  730. return rc;
  731. }
  732. static void cam_cpas_dev_component_unbind(struct device *dev,
  733. struct device *master_dev, void *data)
  734. {
  735. if (!CAM_CPAS_INTF_INITIALIZED()) {
  736. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  737. return;
  738. }
  739. mutex_lock(&g_cpas_intf->intf_lock);
  740. g_cpas_intf->probe_done = false;
  741. cam_unregister_subdev(&g_cpas_intf->subdev);
  742. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  743. mutex_unlock(&g_cpas_intf->intf_lock);
  744. mutex_destroy(&g_cpas_intf->intf_lock);
  745. kfree(g_cpas_intf);
  746. g_cpas_intf = NULL;
  747. }
  748. const static struct component_ops cam_cpas_dev_component_ops = {
  749. .bind = cam_cpas_dev_component_bind,
  750. .unbind = cam_cpas_dev_component_unbind,
  751. };
  752. static int cam_cpas_dev_probe(struct platform_device *pdev)
  753. {
  754. int rc = 0;
  755. CAM_DBG(CAM_CPAS, "Adding CPAS INTF component");
  756. rc = component_add(&pdev->dev, &cam_cpas_dev_component_ops);
  757. if (rc)
  758. CAM_ERR(CAM_CPAS, "failed to add component rc: %d", rc);
  759. return rc;
  760. }
  761. static int cam_cpas_dev_remove(struct platform_device *pdev)
  762. {
  763. component_del(&pdev->dev, &cam_cpas_dev_component_ops);
  764. return 0;
  765. }
  766. static const struct of_device_id cam_cpas_dt_match[] = {
  767. {.compatible = "qcom,cam-cpas"},
  768. {}
  769. };
  770. struct platform_driver cam_cpas_driver = {
  771. .probe = cam_cpas_dev_probe,
  772. .remove = cam_cpas_dev_remove,
  773. .driver = {
  774. .name = CAM_CPAS_DEV_NAME,
  775. .owner = THIS_MODULE,
  776. .of_match_table = cam_cpas_dt_match,
  777. .suppress_bind_attrs = true,
  778. },
  779. };
  780. int cam_cpas_dev_init_module(void)
  781. {
  782. return platform_driver_register(&cam_cpas_driver);
  783. }
  784. void cam_cpas_dev_exit_module(void)
  785. {
  786. platform_driver_unregister(&cam_cpas_driver);
  787. }
  788. MODULE_DESCRIPTION("MSM CPAS driver");
  789. MODULE_LICENSE("GPL v2");