cam_cpas_intf.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/of.h>
  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/platform_device.h>
  10. #include <media/v4l2-event.h>
  11. #include <media/v4l2-ioctl.h>
  12. #include <media/v4l2-subdev.h>
  13. #include <media/cam_cpas.h>
  14. #include <media/cam_req_mgr.h>
  15. #include <dt-bindings/msm-camera.h>
  16. #include "cam_subdev.h"
  17. #include "cam_cpas_hw_intf.h"
  18. #include "cam_cpas_soc.h"
  19. #include "camera_main.h"
  20. #define CAM_CPAS_DEV_NAME "cam-cpas"
  21. #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
  22. /**
  23. * struct cam_cpas_intf : CPAS interface
  24. *
  25. * @pdev: Platform device
  26. * @subdev: Subdev info
  27. * @hw_intf: CPAS HW interface
  28. * @hw_caps: CPAS HW capabilities
  29. * @intf_lock: CPAS interface mutex
  30. * @open_cnt: CPAS subdev open count
  31. * @probe_done: Whether CPAS prove completed
  32. *
  33. */
  34. struct cam_cpas_intf {
  35. struct platform_device *pdev;
  36. struct cam_subdev subdev;
  37. struct cam_hw_intf *hw_intf;
  38. struct cam_cpas_hw_caps hw_caps;
  39. struct mutex intf_lock;
  40. uint32_t open_cnt;
  41. bool probe_done;
  42. };
  43. static struct cam_cpas_intf *g_cpas_intf;
  44. const char *cam_cpas_axi_util_path_type_to_string(
  45. uint32_t path_data_type)
  46. {
  47. switch (path_data_type) {
  48. /* IFE Paths */
  49. case CAM_AXI_PATH_DATA_IFE_LINEAR:
  50. return "IFE_LINEAR";
  51. case CAM_AXI_PATH_DATA_IFE_VID:
  52. return "IFE_VID";
  53. case CAM_AXI_PATH_DATA_IFE_DISP:
  54. return "IFE_DISP";
  55. case CAM_AXI_PATH_DATA_IFE_STATS:
  56. return "IFE_STATS";
  57. case CAM_AXI_PATH_DATA_IFE_RDI0:
  58. return "IFE_RDI0";
  59. case CAM_AXI_PATH_DATA_IFE_RDI1:
  60. return "IFE_RDI1";
  61. case CAM_AXI_PATH_DATA_IFE_RDI2:
  62. return "IFE_RDI2";
  63. case CAM_AXI_PATH_DATA_IFE_RDI3:
  64. return "IFE_RDI3";
  65. case CAM_AXI_PATH_DATA_IFE_PDAF:
  66. return "IFE_PDAF";
  67. case CAM_AXI_PATH_DATA_IFE_PIXEL_RAW:
  68. return "IFE_PIXEL_RAW";
  69. /* IPE Paths */
  70. case CAM_AXI_PATH_DATA_IPE_RD_IN:
  71. return "IPE_RD_IN";
  72. case CAM_AXI_PATH_DATA_IPE_RD_REF:
  73. return "IPE_RD_REF";
  74. case CAM_AXI_PATH_DATA_IPE_WR_VID:
  75. return "IPE_WR_VID";
  76. case CAM_AXI_PATH_DATA_IPE_WR_DISP:
  77. return "IPE_WR_DISP";
  78. case CAM_AXI_PATH_DATA_IPE_WR_REF:
  79. return "IPE_WR_REF";
  80. case CAM_AXI_PATH_DATA_IPE_WR_APP:
  81. return "IPE_WR_APP";
  82. /* OPE Paths */
  83. case CAM_AXI_PATH_DATA_OPE_RD_IN:
  84. return "OPE_RD_IN";
  85. case CAM_AXI_PATH_DATA_OPE_RD_REF:
  86. return "OPE_RD_REF";
  87. case CAM_AXI_PATH_DATA_OPE_WR_VID:
  88. return "OPE_WR_VID";
  89. case CAM_AXI_PATH_DATA_OPE_WR_DISP:
  90. return "OPE_WR_DISP";
  91. case CAM_AXI_PATH_DATA_OPE_WR_REF:
  92. return "OPE_WR_REF";
  93. /* SFE Paths */
  94. case CAM_AXI_PATH_DATA_SFE_NRDI:
  95. return "SFE_NRDI";
  96. case CAM_AXI_PATH_DATA_SFE_RDI0:
  97. return "SFE_RDI0";
  98. case CAM_AXI_PATH_DATA_SFE_RDI1:
  99. return "SFE_RDI1";
  100. case CAM_AXI_PATH_DATA_SFE_RDI2:
  101. return "SFE_RDI2";
  102. case CAM_AXI_PATH_DATA_SFE_RDI3:
  103. return "SFE_RDI3";
  104. case CAM_AXI_PATH_DATA_SFE_RDI4:
  105. return "SFE_RDI4";
  106. case CAM_AXI_PATH_DATA_SFE_STATS:
  107. return "SFE_STATS";
  108. case CAM_AXI_PATH_DATA_CRE_RD_IN:
  109. return "CRE_RD_IN";
  110. case CAM_AXI_PATH_DATA_CRE_WR_OUT:
  111. return "CRE_WR_OUT";
  112. /* Common Paths */
  113. case CAM_AXI_PATH_DATA_ALL:
  114. return "DATA_ALL";
  115. default:
  116. return "IFE_PATH_INVALID";
  117. }
  118. }
  119. EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string);
  120. const char *cam_cpas_axi_util_trans_type_to_string(
  121. uint32_t transac_type)
  122. {
  123. switch (transac_type) {
  124. case CAM_AXI_TRANSACTION_READ:
  125. return "TRANSAC_READ";
  126. case CAM_AXI_TRANSACTION_WRITE:
  127. return "TRANSAC_WRITE";
  128. default:
  129. return "TRANSAC_INVALID";
  130. }
  131. }
  132. EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string);
  133. const char *cam_cpas_axi_util_drv_vote_lvl_to_string(
  134. uint32_t vote_lvl)
  135. {
  136. switch (vote_lvl) {
  137. case CAM_CPAS_VOTE_LEVEL_LOW:
  138. return "VOTE_LVL_LOW";
  139. case CAM_CPAS_VOTE_LEVEL_HIGH:
  140. return "VOTE_LVL_HIGH";
  141. default:
  142. return "VOTE_LVL_INVALID";
  143. }
  144. }
  145. EXPORT_SYMBOL(cam_cpas_axi_util_drv_vote_lvl_to_string);
  146. int cam_cpas_query_drv_enable(bool *is_drv_enabled)
  147. {
  148. struct cam_hw_info *cpas_hw = NULL;
  149. struct cam_cpas_private_soc *soc_private = NULL;
  150. if (!CAM_CPAS_INTF_INITIALIZED()) {
  151. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  152. return -ENODEV;
  153. }
  154. if (!is_drv_enabled) {
  155. CAM_ERR(CAM_CPAS, "invalid input %pK", is_drv_enabled);
  156. return -EINVAL;
  157. }
  158. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  159. soc_private = (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
  160. *is_drv_enabled = soc_private->enable_cam_ddr_drv;
  161. return 0;
  162. }
  163. EXPORT_SYMBOL(cam_cpas_query_drv_enable);
  164. int cam_cpas_csid_process_resume(uint32_t csid_idx)
  165. {
  166. int rc;
  167. if (!CAM_CPAS_INTF_INITIALIZED()) {
  168. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  169. return -ENODEV;
  170. }
  171. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  172. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  173. g_cpas_intf->hw_intf->hw_priv,
  174. CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME, &csid_idx,
  175. sizeof(uint32_t));
  176. if (rc)
  177. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  178. } else {
  179. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  180. rc = -EINVAL;
  181. }
  182. return rc;
  183. }
  184. EXPORT_SYMBOL(cam_cpas_csid_process_resume);
  185. int cam_cpas_csid_input_core_info_update(int csid_idx, int sfe_idx, bool set_port)
  186. {
  187. int rc;
  188. if (!CAM_CPAS_INTF_INITIALIZED()) {
  189. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  190. return -ENODEV;
  191. }
  192. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  193. struct cam_cpas_hw_cmd_csid_input_core_info_update core_info_update;
  194. core_info_update.csid_idx = csid_idx;
  195. core_info_update.sfe_idx = sfe_idx;
  196. core_info_update.set_port = set_port;
  197. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  198. g_cpas_intf->hw_intf->hw_priv,
  199. CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE, &core_info_update,
  200. sizeof(core_info_update));
  201. if (rc)
  202. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  203. } else {
  204. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  205. rc = -EINVAL;
  206. }
  207. return rc;
  208. }
  209. EXPORT_SYMBOL(cam_cpas_csid_input_core_info_update);
  210. int cam_cpas_dump_camnoc_buff_fill_info(uint32_t client_handle)
  211. {
  212. int rc;
  213. if (!CAM_CPAS_INTF_INITIALIZED()) {
  214. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  215. return -ENODEV;
  216. }
  217. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  218. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  219. g_cpas_intf->hw_intf->hw_priv,
  220. CAM_CPAS_HW_CMD_DUMP_BUFF_FILL_INFO, &client_handle,
  221. sizeof(uint32_t));
  222. if (rc)
  223. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  224. } else {
  225. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  226. rc = -EINVAL;
  227. }
  228. return rc;
  229. }
  230. EXPORT_SYMBOL(cam_cpas_dump_camnoc_buff_fill_info);
  231. bool cam_cpas_is_feature_supported(uint32_t flag, uint32_t hw_map,
  232. uint32_t *fuse_val)
  233. {
  234. struct cam_hw_info *cpas_hw = NULL;
  235. struct cam_cpas_private_soc *soc_private = NULL;
  236. bool supported = true;
  237. int32_t i;
  238. if (!CAM_CPAS_INTF_INITIALIZED()) {
  239. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  240. return false;
  241. }
  242. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  243. soc_private =
  244. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  245. if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) {
  246. CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag);
  247. return false;
  248. }
  249. for (i = 0; i < soc_private->num_feature_info; i++)
  250. if (soc_private->feature_info[i].feature == flag)
  251. break;
  252. if (i == soc_private->num_feature_info)
  253. goto end;
  254. if (soc_private->feature_info[i].type == CAM_CPAS_FEATURE_TYPE_DISABLE
  255. || (soc_private->feature_info[i].type ==
  256. CAM_CPAS_FEATURE_TYPE_ENABLE)) {
  257. if ((soc_private->feature_info[i].hw_map & hw_map) == hw_map)
  258. supported = soc_private->feature_info[i].enable;
  259. } else {
  260. if (!fuse_val) {
  261. CAM_ERR(CAM_CPAS,
  262. "Invalid arg fuse_val");
  263. } else {
  264. *fuse_val = soc_private->feature_info[i].value;
  265. }
  266. }
  267. end:
  268. return supported;
  269. }
  270. EXPORT_SYMBOL(cam_cpas_is_feature_supported);
  271. int cam_cpas_get_cpas_hw_version(uint32_t *hw_version)
  272. {
  273. struct cam_hw_info *cpas_hw = NULL;
  274. if (!CAM_CPAS_INTF_INITIALIZED()) {
  275. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  276. return -ENODEV;
  277. }
  278. if (!hw_version) {
  279. CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version);
  280. return -EINVAL;
  281. }
  282. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  283. *hw_version = cpas_hw->soc_info.hw_version;
  284. if (*hw_version == CAM_CPAS_TITAN_NONE) {
  285. CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d",
  286. *hw_version);
  287. }
  288. return 0;
  289. }
  290. int cam_cpas_get_hw_info(uint32_t *camera_family,
  291. struct cam_hw_version *camera_version,
  292. struct cam_hw_version *cpas_version,
  293. uint32_t *cam_caps,
  294. struct cam_cpas_fuse_info *cam_fuse_info,
  295. struct cam_cpas_domain_id_caps *domain_id_info)
  296. {
  297. struct cam_hw_info *cpas_hw;
  298. struct cam_cpas_private_soc *soc_private;
  299. struct cam_cpas_domain_id_info cpas_domain_id;
  300. int i;
  301. if (!CAM_CPAS_INTF_INITIALIZED()) {
  302. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  303. return -ENODEV;
  304. }
  305. if (!camera_family || !camera_version || !cpas_version || !cam_caps) {
  306. CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK",
  307. camera_family, camera_version, cpas_version, cam_caps);
  308. return -EINVAL;
  309. }
  310. cpas_hw = g_cpas_intf->hw_intf->hw_priv;
  311. soc_private = (struct cam_cpas_private_soc *)
  312. cpas_hw->soc_info.soc_private;
  313. *camera_family = g_cpas_intf->hw_caps.camera_family;
  314. *camera_version = g_cpas_intf->hw_caps.camera_version;
  315. *cpas_version = g_cpas_intf->hw_caps.cpas_version;
  316. *cam_caps = g_cpas_intf->hw_caps.camera_capability;
  317. if (cam_fuse_info)
  318. *cam_fuse_info = g_cpas_intf->hw_caps.fuse_info;
  319. if (domain_id_info) {
  320. cpas_domain_id = soc_private->domain_id_info;
  321. if (!soc_private->domain_id_info.domain_id_supported) {
  322. domain_id_info->num_mapping = 0;
  323. domain_id_info->is_supported = 0;
  324. } else {
  325. domain_id_info->is_supported = 1;
  326. domain_id_info->num_mapping =
  327. soc_private->domain_id_info.num_domain_ids;
  328. for (i = 0; i < domain_id_info->num_mapping; i++) {
  329. domain_id_info->entries[i].domain_type =
  330. cpas_domain_id.domain_id_entries[i].domain_type;
  331. domain_id_info->entries[i].mapping_id =
  332. cpas_domain_id.domain_id_entries[i].mapping_id;
  333. }
  334. }
  335. }
  336. CAM_DBG(CAM_CPAS, "Family %d, version %d.%d cam_caps %d, domain_id: %s",
  337. CAM_BOOL_TO_YESNO(soc_private->domain_id_info.domain_id_supported),
  338. *camera_family, camera_version->major,
  339. camera_version->minor, *cam_caps);
  340. return 0;
  341. }
  342. EXPORT_SYMBOL(cam_cpas_get_hw_info);
  343. int cam_cpas_reg_write(uint32_t client_handle,
  344. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  345. uint32_t value)
  346. {
  347. int rc;
  348. if (!CAM_CPAS_INTF_INITIALIZED()) {
  349. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  350. return -ENODEV;
  351. }
  352. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  353. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write;
  354. cmd_reg_write.client_handle = client_handle;
  355. cmd_reg_write.reg_base = reg_base;
  356. cmd_reg_write.offset = offset;
  357. cmd_reg_write.value = value;
  358. cmd_reg_write.mb = mb;
  359. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  360. g_cpas_intf->hw_intf->hw_priv,
  361. CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write,
  362. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  363. if (rc)
  364. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  365. } else {
  366. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  367. rc = -EINVAL;
  368. }
  369. return rc;
  370. }
  371. EXPORT_SYMBOL(cam_cpas_reg_write);
  372. int cam_cpas_reg_read(uint32_t client_handle,
  373. enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb,
  374. uint32_t *value)
  375. {
  376. int rc;
  377. if (!CAM_CPAS_INTF_INITIALIZED()) {
  378. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  379. return -ENODEV;
  380. }
  381. if (!value) {
  382. CAM_ERR(CAM_CPAS, "Invalid arg value");
  383. return -EINVAL;
  384. }
  385. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  386. struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read;
  387. cmd_reg_read.client_handle = client_handle;
  388. cmd_reg_read.reg_base = reg_base;
  389. cmd_reg_read.offset = offset;
  390. cmd_reg_read.mb = mb;
  391. cmd_reg_read.value = 0;
  392. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  393. g_cpas_intf->hw_intf->hw_priv,
  394. CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read,
  395. sizeof(struct cam_cpas_hw_cmd_reg_read_write));
  396. if (rc) {
  397. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  398. return rc;
  399. }
  400. *value = cmd_reg_read.value;
  401. } else {
  402. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  403. rc = -EINVAL;
  404. }
  405. return rc;
  406. }
  407. EXPORT_SYMBOL(cam_cpas_reg_read);
  408. int cam_cpas_update_axi_vote(uint32_t client_handle,
  409. struct cam_axi_vote *axi_vote)
  410. {
  411. int rc;
  412. if (!CAM_CPAS_INTF_INITIALIZED()) {
  413. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  414. return -ENODEV;
  415. }
  416. if (!axi_vote) {
  417. CAM_ERR(CAM_CPAS, "NULL axi vote");
  418. return -EINVAL;
  419. }
  420. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  421. struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote;
  422. cmd_axi_vote.client_handle = client_handle;
  423. cmd_axi_vote.axi_vote = axi_vote;
  424. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  425. g_cpas_intf->hw_intf->hw_priv,
  426. CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote,
  427. sizeof(struct cam_cpas_hw_cmd_axi_vote));
  428. if (rc)
  429. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  430. } else {
  431. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  432. rc = -EINVAL;
  433. }
  434. return rc;
  435. }
  436. EXPORT_SYMBOL(cam_cpas_update_axi_vote);
  437. int cam_cpas_update_ahb_vote(uint32_t client_handle,
  438. struct cam_ahb_vote *ahb_vote)
  439. {
  440. int rc;
  441. if (!CAM_CPAS_INTF_INITIALIZED()) {
  442. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  443. return -ENODEV;
  444. }
  445. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  446. struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote;
  447. cmd_ahb_vote.client_handle = client_handle;
  448. cmd_ahb_vote.ahb_vote = ahb_vote;
  449. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  450. g_cpas_intf->hw_intf->hw_priv,
  451. CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote,
  452. sizeof(struct cam_cpas_hw_cmd_ahb_vote));
  453. if (rc)
  454. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  455. } else {
  456. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  457. rc = -EINVAL;
  458. }
  459. return rc;
  460. }
  461. EXPORT_SYMBOL(cam_cpas_update_ahb_vote);
  462. int cam_cpas_stop(uint32_t client_handle)
  463. {
  464. int rc;
  465. if (!CAM_CPAS_INTF_INITIALIZED()) {
  466. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  467. return -ENODEV;
  468. }
  469. if (g_cpas_intf->hw_intf->hw_ops.stop) {
  470. struct cam_cpas_hw_cmd_stop cmd_hw_stop;
  471. cmd_hw_stop.client_handle = client_handle;
  472. rc = g_cpas_intf->hw_intf->hw_ops.stop(
  473. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop,
  474. sizeof(struct cam_cpas_hw_cmd_stop));
  475. if (rc)
  476. CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc);
  477. } else {
  478. CAM_ERR(CAM_CPAS, "Invalid stop ops");
  479. rc = -EINVAL;
  480. }
  481. return rc;
  482. }
  483. EXPORT_SYMBOL(cam_cpas_stop);
  484. int cam_cpas_start(uint32_t client_handle,
  485. struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote)
  486. {
  487. int rc;
  488. if (!CAM_CPAS_INTF_INITIALIZED()) {
  489. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  490. return -ENODEV;
  491. }
  492. if (!axi_vote) {
  493. CAM_ERR(CAM_CPAS, "NULL axi vote");
  494. return -EINVAL;
  495. }
  496. if (g_cpas_intf->hw_intf->hw_ops.start) {
  497. struct cam_cpas_hw_cmd_start cmd_hw_start;
  498. cmd_hw_start.client_handle = client_handle;
  499. cmd_hw_start.ahb_vote = ahb_vote;
  500. cmd_hw_start.axi_vote = axi_vote;
  501. rc = g_cpas_intf->hw_intf->hw_ops.start(
  502. g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start,
  503. sizeof(struct cam_cpas_hw_cmd_start));
  504. if (rc)
  505. CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc);
  506. } else {
  507. CAM_ERR(CAM_CPAS, "Invalid start ops");
  508. rc = -EINVAL;
  509. }
  510. return rc;
  511. }
  512. EXPORT_SYMBOL(cam_cpas_start);
  513. void cam_cpas_log_votes(bool ddr_only)
  514. {
  515. int rc;
  516. if (!CAM_CPAS_INTF_INITIALIZED()) {
  517. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  518. return;
  519. }
  520. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  521. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  522. g_cpas_intf->hw_intf->hw_priv,
  523. CAM_CPAS_HW_CMD_LOG_VOTE, &ddr_only,
  524. sizeof(ddr_only));
  525. if (rc)
  526. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  527. } else {
  528. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  529. }
  530. }
  531. EXPORT_SYMBOL(cam_cpas_log_votes);
  532. int cam_cpas_select_qos_settings(uint32_t selection_mask)
  533. {
  534. int rc = 0;
  535. if (!CAM_CPAS_INTF_INITIALIZED()) {
  536. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  537. return -EBADR;
  538. }
  539. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  540. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  541. g_cpas_intf->hw_intf->hw_priv,
  542. CAM_CPAS_HW_CMD_SELECT_QOS, &selection_mask,
  543. sizeof(selection_mask));
  544. if (rc)
  545. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  546. } else {
  547. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  548. rc = -EBADR;
  549. }
  550. return rc;
  551. }
  552. EXPORT_SYMBOL(cam_cpas_select_qos_settings);
  553. int cam_cpas_notify_event(const char *identifier_string,
  554. int32_t identifier_value)
  555. {
  556. int rc = 0;
  557. if (!CAM_CPAS_INTF_INITIALIZED()) {
  558. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  559. return -EBADR;
  560. }
  561. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  562. struct cam_cpas_hw_cmd_notify_event event = { 0 };
  563. event.identifier_string = identifier_string;
  564. event.identifier_value = identifier_value;
  565. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  566. g_cpas_intf->hw_intf->hw_priv,
  567. CAM_CPAS_HW_CMD_LOG_EVENT, &event,
  568. sizeof(event));
  569. if (rc)
  570. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  571. } else {
  572. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  573. rc = -EBADR;
  574. }
  575. return rc;
  576. }
  577. EXPORT_SYMBOL(cam_cpas_notify_event);
  578. int cam_cpas_unregister_client(uint32_t client_handle)
  579. {
  580. int rc;
  581. if (!CAM_CPAS_INTF_INITIALIZED()) {
  582. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  583. return -ENODEV;
  584. }
  585. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  586. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  587. g_cpas_intf->hw_intf->hw_priv,
  588. CAM_CPAS_HW_CMD_UNREGISTER_CLIENT,
  589. &client_handle, sizeof(uint32_t));
  590. if (rc)
  591. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  592. } else {
  593. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  594. rc = -EINVAL;
  595. }
  596. return rc;
  597. }
  598. EXPORT_SYMBOL(cam_cpas_unregister_client);
  599. int cam_cpas_register_client(
  600. struct cam_cpas_register_params *register_params)
  601. {
  602. int rc;
  603. if (!CAM_CPAS_INTF_INITIALIZED()) {
  604. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  605. return -ENODEV;
  606. }
  607. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  608. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  609. g_cpas_intf->hw_intf->hw_priv,
  610. CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params,
  611. sizeof(struct cam_cpas_register_params));
  612. if (rc)
  613. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  614. } else {
  615. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  616. rc = -EINVAL;
  617. }
  618. return rc;
  619. }
  620. EXPORT_SYMBOL(cam_cpas_register_client);
  621. int cam_cpas_get_scid(
  622. enum cam_sys_cache_config_types type)
  623. {
  624. int rc;
  625. if (!CAM_CPAS_INTF_INITIALIZED()) {
  626. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  627. return -ENODEV;
  628. }
  629. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  630. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  631. g_cpas_intf->hw_intf->hw_priv,
  632. CAM_CPAS_HW_CMD_GET_SCID, &type,
  633. sizeof(type));
  634. } else {
  635. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  636. rc = -EINVAL;
  637. }
  638. return rc;
  639. }
  640. EXPORT_SYMBOL(cam_cpas_get_scid);
  641. int cam_cpas_activate_llcc(
  642. enum cam_sys_cache_config_types type)
  643. {
  644. int rc;
  645. if (!CAM_CPAS_INTF_INITIALIZED()) {
  646. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  647. return -ENODEV;
  648. }
  649. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  650. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  651. g_cpas_intf->hw_intf->hw_priv,
  652. CAM_CPAS_HW_CMD_ACTIVATE_LLC, &type,
  653. sizeof(type));
  654. if (rc)
  655. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  656. } else {
  657. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  658. rc = -EINVAL;
  659. }
  660. return rc;
  661. }
  662. EXPORT_SYMBOL(cam_cpas_activate_llcc);
  663. int cam_cpas_deactivate_llcc(
  664. enum cam_sys_cache_config_types type)
  665. {
  666. int rc;
  667. if (!CAM_CPAS_INTF_INITIALIZED()) {
  668. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  669. return -ENODEV;
  670. }
  671. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  672. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  673. g_cpas_intf->hw_intf->hw_priv,
  674. CAM_CPAS_HW_CMD_DEACTIVATE_LLC, &type,
  675. sizeof(type));
  676. if (rc)
  677. CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc);
  678. } else {
  679. CAM_ERR(CAM_CPAS, "Invalid process_cmd ops");
  680. rc = -EINVAL;
  681. }
  682. return rc;
  683. }
  684. EXPORT_SYMBOL(cam_cpas_deactivate_llcc);
  685. bool cam_cpas_query_domain_id_security_support(void)
  686. {
  687. struct cam_hw_info *cpas_hw = NULL;
  688. struct cam_cpas_private_soc *soc_private = NULL;
  689. if (!CAM_CPAS_INTF_INITIALIZED()) {
  690. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  691. return false;
  692. }
  693. cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv;
  694. soc_private =
  695. (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private;
  696. return soc_private->domain_id_info.domain_id_supported;
  697. }
  698. EXPORT_SYMBOL(cam_cpas_query_domain_id_security_support);
  699. int cam_cpas_enable_clks_for_domain_id(bool enable)
  700. {
  701. int rc = 0;
  702. if (!CAM_CPAS_INTF_INITIALIZED()) {
  703. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  704. return -ENODEV;
  705. }
  706. if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
  707. rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
  708. g_cpas_intf->hw_intf->hw_priv,
  709. CAM_CPAS_HW_CMD_ENABLE_DISABLE_DOMAIN_ID_CLK, &enable,
  710. sizeof(enable));
  711. }
  712. return rc;
  713. }
  714. EXPORT_SYMBOL(cam_cpas_enable_clks_for_domain_id);
  715. int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
  716. struct cam_control *cmd)
  717. {
  718. int rc = 0;
  719. if (!cmd) {
  720. CAM_ERR(CAM_CPAS, "Invalid input cmd");
  721. return -EINVAL;
  722. }
  723. switch (cmd->op_code) {
  724. case CAM_QUERY_CAP: {
  725. struct cam_cpas_query_cap query;
  726. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  727. sizeof(query));
  728. if (rc) {
  729. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  730. rc);
  731. break;
  732. }
  733. rc = cam_cpas_get_hw_info(&query.camera_family,
  734. &query.camera_version, &query.cpas_version,
  735. &query.reserved, NULL, NULL);
  736. if (rc)
  737. break;
  738. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  739. sizeof(query));
  740. if (rc)
  741. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  742. break;
  743. }
  744. case CAM_QUERY_CAP_V2: {
  745. struct cam_cpas_query_cap_v2 query;
  746. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  747. sizeof(query));
  748. if (rc) {
  749. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  750. rc);
  751. break;
  752. }
  753. rc = cam_cpas_get_hw_info(&query.camera_family,
  754. &query.camera_version, &query.cpas_version,
  755. &query.reserved,
  756. &query.fuse_info, NULL);
  757. if (rc)
  758. break;
  759. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  760. sizeof(query));
  761. if (rc)
  762. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  763. break;
  764. }
  765. case CAM_QUERY_CAP_V3: {
  766. struct cam_cpas_query_cap_v3 query;
  767. rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle),
  768. sizeof(query));
  769. if (rc) {
  770. CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d",
  771. rc);
  772. break;
  773. }
  774. rc = cam_cpas_get_hw_info(&query.camera_family,
  775. &query.camera_version, &query.cpas_version,
  776. &query.camera_caps, &query.fuse_info,
  777. &query.domain_id_info);
  778. if (rc)
  779. break;
  780. rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query,
  781. sizeof(query));
  782. if (rc)
  783. CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc);
  784. break;
  785. }
  786. case CAM_SD_SHUTDOWN:
  787. break;
  788. default:
  789. CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code);
  790. rc = -EINVAL;
  791. break;
  792. }
  793. return rc;
  794. }
  795. static int cam_cpas_subdev_open(struct v4l2_subdev *sd,
  796. struct v4l2_subdev_fh *fh)
  797. {
  798. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  799. if (!cpas_intf || !cpas_intf->probe_done) {
  800. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  801. return -ENODEV;
  802. }
  803. mutex_lock(&cpas_intf->intf_lock);
  804. cpas_intf->open_cnt++;
  805. CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt);
  806. mutex_unlock(&cpas_intf->intf_lock);
  807. return 0;
  808. }
  809. static int __cam_cpas_subdev_close(struct v4l2_subdev *sd,
  810. struct v4l2_subdev_fh *fh)
  811. {
  812. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  813. if (!cpas_intf || !cpas_intf->probe_done) {
  814. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  815. return -ENODEV;
  816. }
  817. mutex_lock(&cpas_intf->intf_lock);
  818. if (cpas_intf->open_cnt <= 0) {
  819. CAM_WARN(CAM_CPAS, "device already closed, open_cnt: %d", cpas_intf->open_cnt);
  820. mutex_unlock(&cpas_intf->intf_lock);
  821. return 0;
  822. }
  823. cpas_intf->open_cnt--;
  824. CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt);
  825. mutex_unlock(&cpas_intf->intf_lock);
  826. return 0;
  827. }
  828. static int cam_cpas_subdev_close(struct v4l2_subdev *sd,
  829. struct v4l2_subdev_fh *fh)
  830. {
  831. bool crm_active = cam_req_mgr_is_open();
  832. if (crm_active) {
  833. CAM_DBG(CAM_CPAS, "CRM is ACTIVE, close should be from CRM");
  834. return 0;
  835. }
  836. return __cam_cpas_subdev_close(sd, fh);
  837. }
  838. static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd,
  839. unsigned int cmd, void *arg)
  840. {
  841. int32_t rc;
  842. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  843. if (!cpas_intf || !cpas_intf->probe_done) {
  844. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  845. return -ENODEV;
  846. }
  847. switch (cmd) {
  848. case VIDIOC_CAM_CONTROL:
  849. rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
  850. break;
  851. case CAM_SD_SHUTDOWN:
  852. rc = __cam_cpas_subdev_close(sd, NULL);
  853. break;
  854. default:
  855. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  856. rc = -EINVAL;
  857. break;
  858. }
  859. return rc;
  860. }
  861. #ifdef CONFIG_COMPAT
  862. static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
  863. unsigned int cmd, unsigned long arg)
  864. {
  865. struct cam_control cmd_data;
  866. int32_t rc;
  867. struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
  868. if (!cpas_intf || !cpas_intf->probe_done) {
  869. CAM_ERR(CAM_CPAS, "CPAS not initialized");
  870. return -ENODEV;
  871. }
  872. if (copy_from_user(&cmd_data, (void __user *)arg,
  873. sizeof(cmd_data))) {
  874. CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu",
  875. (void __user *)arg, sizeof(cmd_data));
  876. return -EFAULT;
  877. }
  878. switch (cmd) {
  879. case VIDIOC_CAM_CONTROL:
  880. rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
  881. break;
  882. default:
  883. CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd);
  884. rc = -EINVAL;
  885. break;
  886. }
  887. if (!rc) {
  888. if (copy_to_user((void __user *)arg, &cmd_data,
  889. sizeof(cmd_data))) {
  890. CAM_ERR(CAM_CPAS,
  891. "Failed to copy to user_ptr=%pK size=%zu",
  892. (void __user *)arg, sizeof(cmd_data));
  893. rc = -EFAULT;
  894. }
  895. }
  896. return rc;
  897. }
  898. #endif
  899. static struct v4l2_subdev_core_ops cpas_subdev_core_ops = {
  900. .ioctl = cam_cpas_subdev_ioctl,
  901. #ifdef CONFIG_COMPAT
  902. .compat_ioctl32 = cam_cpas_subdev_compat_ioctl,
  903. #endif
  904. };
  905. static const struct v4l2_subdev_ops cpas_subdev_ops = {
  906. .core = &cpas_subdev_core_ops,
  907. };
  908. static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = {
  909. .open = cam_cpas_subdev_open,
  910. .close = cam_cpas_subdev_close,
  911. };
  912. static int cam_cpas_subdev_register(struct platform_device *pdev)
  913. {
  914. int rc;
  915. struct cam_subdev *subdev;
  916. if (!g_cpas_intf)
  917. return -EINVAL;
  918. subdev = &g_cpas_intf->subdev;
  919. subdev->name = CAM_CPAS_DEV_NAME;
  920. subdev->pdev = pdev;
  921. subdev->ops = &cpas_subdev_ops;
  922. subdev->internal_ops = &cpas_subdev_intern_ops;
  923. subdev->token = g_cpas_intf;
  924. subdev->sd_flags =
  925. V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
  926. subdev->ent_function = CAM_CPAS_DEVICE_TYPE;
  927. subdev->close_seq_prior = CAM_SD_CLOSE_LOW_PRIORITY;
  928. rc = cam_register_subdev(subdev);
  929. if (rc) {
  930. CAM_ERR(CAM_CPAS, "failed register subdev: %s!",
  931. CAM_CPAS_DEV_NAME);
  932. return rc;
  933. }
  934. platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf);
  935. return rc;
  936. }
  937. static int cam_cpas_dev_component_bind(struct device *dev,
  938. struct device *master_dev, void *data)
  939. {
  940. struct cam_cpas_hw_caps *hw_caps;
  941. struct cam_hw_intf *hw_intf;
  942. int rc;
  943. struct platform_device *pdev = to_platform_device(dev);
  944. if (g_cpas_intf) {
  945. CAM_ERR(CAM_CPAS, "cpas component already binded");
  946. return -EALREADY;
  947. }
  948. g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL);
  949. if (!g_cpas_intf)
  950. return -ENOMEM;
  951. mutex_init(&g_cpas_intf->intf_lock);
  952. g_cpas_intf->pdev = pdev;
  953. rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf);
  954. if (rc || (g_cpas_intf->hw_intf == NULL)) {
  955. CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc);
  956. goto error_destroy_mem;
  957. }
  958. hw_intf = g_cpas_intf->hw_intf;
  959. hw_caps = &g_cpas_intf->hw_caps;
  960. if (hw_intf->hw_ops.get_hw_caps) {
  961. rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv,
  962. hw_caps, sizeof(struct cam_cpas_hw_caps));
  963. if (rc) {
  964. CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc);
  965. goto error_hw_remove;
  966. }
  967. } else {
  968. CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops");
  969. goto error_hw_remove;
  970. }
  971. rc = cam_cpas_subdev_register(pdev);
  972. if (rc)
  973. goto error_hw_remove;
  974. g_cpas_intf->probe_done = true;
  975. CAM_DBG(CAM_CPAS,
  976. "Component bound successfully %d, %d.%d.%d, %d.%d.%d, 0x%x",
  977. hw_caps->camera_family, hw_caps->camera_version.major,
  978. hw_caps->camera_version.minor, hw_caps->camera_version.incr,
  979. hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
  980. hw_caps->cpas_version.incr, hw_caps->camera_capability);
  981. return rc;
  982. error_hw_remove:
  983. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  984. error_destroy_mem:
  985. mutex_destroy(&g_cpas_intf->intf_lock);
  986. kfree(g_cpas_intf);
  987. g_cpas_intf = NULL;
  988. CAM_ERR(CAM_CPAS, "CPAS component bind failed");
  989. return rc;
  990. }
  991. static void cam_cpas_dev_component_unbind(struct device *dev,
  992. struct device *master_dev, void *data)
  993. {
  994. if (!CAM_CPAS_INTF_INITIALIZED()) {
  995. CAM_ERR(CAM_CPAS, "cpas intf not initialized");
  996. return;
  997. }
  998. mutex_lock(&g_cpas_intf->intf_lock);
  999. g_cpas_intf->probe_done = false;
  1000. cam_unregister_subdev(&g_cpas_intf->subdev);
  1001. cam_cpas_hw_remove(g_cpas_intf->hw_intf);
  1002. mutex_unlock(&g_cpas_intf->intf_lock);
  1003. mutex_destroy(&g_cpas_intf->intf_lock);
  1004. kfree(g_cpas_intf);
  1005. g_cpas_intf = NULL;
  1006. }
  1007. const static struct component_ops cam_cpas_dev_component_ops = {
  1008. .bind = cam_cpas_dev_component_bind,
  1009. .unbind = cam_cpas_dev_component_unbind,
  1010. };
  1011. static int cam_cpas_dev_probe(struct platform_device *pdev)
  1012. {
  1013. int rc = 0;
  1014. CAM_DBG(CAM_CPAS, "Adding CPAS INTF component");
  1015. rc = component_add(&pdev->dev, &cam_cpas_dev_component_ops);
  1016. if (rc)
  1017. CAM_ERR(CAM_CPAS, "failed to add component rc: %d", rc);
  1018. return rc;
  1019. }
  1020. static int cam_cpas_dev_remove(struct platform_device *pdev)
  1021. {
  1022. component_del(&pdev->dev, &cam_cpas_dev_component_ops);
  1023. return 0;
  1024. }
  1025. static const struct of_device_id cam_cpas_dt_match[] = {
  1026. {.compatible = "qcom,cam-cpas"},
  1027. {}
  1028. };
  1029. struct platform_driver cam_cpas_driver = {
  1030. .probe = cam_cpas_dev_probe,
  1031. .remove = cam_cpas_dev_remove,
  1032. .driver = {
  1033. .name = CAM_CPAS_DEV_NAME,
  1034. .owner = THIS_MODULE,
  1035. .of_match_table = cam_cpas_dt_match,
  1036. .suppress_bind_attrs = true,
  1037. },
  1038. };
  1039. int cam_cpas_dev_init_module(void)
  1040. {
  1041. return platform_driver_register(&cam_cpas_driver);
  1042. }
  1043. void cam_cpas_dev_exit_module(void)
  1044. {
  1045. platform_driver_unregister(&cam_cpas_driver);
  1046. }
  1047. MODULE_DESCRIPTION("MSM CPAS driver");
  1048. MODULE_LICENSE("GPL v2");