cam_cpas_intf.c 18 KB

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