wcd-spi-ac.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/init.h>
  5. #include <linux/module.h>
  6. #include <linux/of.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/cdev.h>
  9. #include <linux/proc_fs.h>
  10. #include <linux/poll.h>
  11. #include <linux/slab.h>
  12. #include <linux/notifier.h>
  13. #include <audio/linux/wcd-spi-ac-params.h>
  14. #include <soc/wcd-spi-ac.h>
  15. #include <soc/qcom/msm_qmi_interface.h>
  16. #include "wcd_spi_ctl_v01.h"
  17. #define WCD_SPI_AC_PFS_ENTRY_MAX_LEN 16
  18. #define WCD_SPI_AC_WRITE_CMD_MIN_SIZE \
  19. (sizeof(struct wcd_spi_ac_write_cmd))
  20. #define WCD_SPI_AC_WRITE_CMD_MAX_SIZE \
  21. (WCD_SPI_AC_WRITE_CMD_MIN_SIZE + \
  22. (WCD_SPI_AC_MAX_BUFFERS * \
  23. sizeof(struct wcd_spi_ac_buf_data)))
  24. #define WCD_SPI_AC_MUTEX_LOCK(dev, lock) \
  25. { \
  26. dev_dbg(dev, "%s: mutex_lock(%s)\n", \
  27. __func__, __stringify_1(lock)); \
  28. mutex_lock(&lock); \
  29. }
  30. #define WCD_SPI_AC_MUTEX_UNLOCK(dev, lock) \
  31. { \
  32. dev_dbg(dev, "%s: mutex_unlock(%s)\n", \
  33. __func__, __stringify_1(lock)); \
  34. mutex_unlock(&lock); \
  35. }
  36. /*
  37. * All bits of status should be cleared for SPI access
  38. * to be released.
  39. */
  40. #define WCD_SPI_AC_STATUS_RELEASE_ACCESS 0x00
  41. #define WCD_SPI_AC_LOCAL_ACCESS 0x00
  42. #define WCD_SPI_AC_REMOTE_ACCESS 0x01
  43. #define WCD_SPI_CTL_INS_ID 0
  44. #define WCD_SPI_AC_QMI_TIMEOUT_MS 100
  45. struct wcd_spi_ac_priv {
  46. /* Pointer to device for this driver */
  47. struct device *dev;
  48. /* Pointer to parent's device */
  49. struct device *parent;
  50. /* char dev related */
  51. struct class *cls;
  52. struct device *chardev;
  53. struct cdev cdev;
  54. dev_t cdev_num;
  55. /* proc entry related */
  56. struct proc_dir_entry *pfs_root;
  57. struct proc_dir_entry *pfs_status;
  58. /* service status related */
  59. u8 svc_offline;
  60. u8 svc_offline_change;
  61. wait_queue_head_t svc_poll_wait;
  62. struct mutex status_lock;
  63. /* state maintenence related */
  64. u32 state;
  65. struct mutex state_lock;
  66. u8 current_access;
  67. /* qmi related */
  68. struct qmi_handle *qmi_hdl;
  69. struct work_struct svc_arr_work;
  70. struct work_struct svc_exit_work;
  71. struct notifier_block nb;
  72. struct mutex svc_lock;
  73. struct workqueue_struct *qmi_wq;
  74. struct work_struct recv_msg_work;
  75. };
  76. static void wcd_spi_ac_status_change(struct wcd_spi_ac_priv *ac,
  77. u8 online)
  78. {
  79. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
  80. ac->svc_offline = !online;
  81. /* Make sure the write is complete */
  82. wmb();
  83. xchg(&ac->svc_offline_change, 1);
  84. wake_up_interruptible(&ac->svc_poll_wait);
  85. dev_dbg(ac->dev,
  86. "%s request %u offline %u off_change %u\n",
  87. __func__, online, ac->svc_offline,
  88. ac->svc_offline_change);
  89. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
  90. }
  91. static int wcd_spi_ac_status_open(struct inode *inode,
  92. struct file *file)
  93. {
  94. struct wcd_spi_ac_priv *ac = PDE_DATA(inode);
  95. file->private_data = ac;
  96. return 0;
  97. }
  98. static ssize_t wcd_spi_ac_status_read(struct file *file,
  99. char __user *buffer,
  100. size_t count, loff_t *offset)
  101. {
  102. struct wcd_spi_ac_priv *ac;
  103. char buf[WCD_SPI_AC_PFS_ENTRY_MAX_LEN];
  104. int len, ret;
  105. u8 offline;
  106. ac = (struct wcd_spi_ac_priv *) file->private_data;
  107. if (!ac) {
  108. pr_err("%s: Invalid private data for status\n",
  109. __func__);
  110. return -EINVAL;
  111. }
  112. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
  113. offline = ac->svc_offline;
  114. /* Make sure the read is complete */
  115. rmb();
  116. dev_dbg(ac->dev, "%s: offline = %sline\n",
  117. __func__, offline ? "off" : "on");
  118. len = snprintf(buf, sizeof(buf), "%s\n",
  119. offline ? "OFFLINE" : "ONLINE");
  120. ret = simple_read_from_buffer(buffer, count, offset, buf, len);
  121. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
  122. return ret;
  123. }
  124. static unsigned int wcd_spi_ac_status_poll(struct file *file,
  125. poll_table *wait)
  126. {
  127. struct wcd_spi_ac_priv *ac;
  128. unsigned int ret = 0;
  129. ac = (struct wcd_spi_ac_priv *) file->private_data;
  130. if (!ac) {
  131. pr_err("%s: Invalid private data for status\n",
  132. __func__);
  133. return -EINVAL;
  134. }
  135. dev_dbg(ac->dev, "%s: Poll wait, svc = %s\n",
  136. __func__, ac->svc_offline ? "offline" : "online");
  137. poll_wait(file, &ac->svc_poll_wait, wait);
  138. dev_dbg(ac->dev, "%s: Woken up Poll wait, svc = %s\n",
  139. __func__, ac->svc_offline ? "offline" : "online");
  140. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
  141. if (xchg(&ac->svc_offline_change, 0))
  142. ret = POLLIN | POLLPRI | POLLRDNORM;
  143. dev_dbg(ac->dev, "%s: ret (%d) from poll_wait\n",
  144. __func__, ret);
  145. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
  146. return ret;
  147. }
  148. static const struct file_operations wcd_spi_ac_status_ops = {
  149. .owner = THIS_MODULE,
  150. .open = wcd_spi_ac_status_open,
  151. .read = wcd_spi_ac_status_read,
  152. .poll = wcd_spi_ac_status_poll,
  153. };
  154. static int wcd_spi_ac_procfs_init(struct wcd_spi_ac_priv *ac)
  155. {
  156. int ret = 0;
  157. ac->pfs_root = proc_mkdir(WCD_SPI_AC_PROCFS_DIR_NAME, NULL);
  158. if (!ac->pfs_root) {
  159. dev_err(ac->dev, "%s: proc_mkdir failed\n", __func__);
  160. return -EINVAL;
  161. }
  162. ac->pfs_status = proc_create_data(WCD_SPI_AC_PROCFS_STATE_NAME,
  163. 0444, ac->pfs_root,
  164. &wcd_spi_ac_status_ops,
  165. ac);
  166. if (!ac->pfs_status) {
  167. dev_err(ac->dev, "%s: proc_create_data failed\n",
  168. __func__);
  169. ret = -EINVAL;
  170. goto rmdir_root;
  171. }
  172. proc_set_size(ac->pfs_status, WCD_SPI_AC_PFS_ENTRY_MAX_LEN);
  173. return 0;
  174. rmdir_root:
  175. proc_remove(ac->pfs_root);
  176. return ret;
  177. }
  178. static void wcd_spi_ac_procfs_deinit(struct wcd_spi_ac_priv *ac)
  179. {
  180. proc_remove(ac->pfs_status);
  181. proc_remove(ac->pfs_root);
  182. }
  183. static int wcd_spi_ac_request_access(struct wcd_spi_ac_priv *ac,
  184. bool is_svc_locked)
  185. {
  186. struct wcd_spi_req_access_msg_v01 req;
  187. struct wcd_spi_req_access_resp_v01 rsp;
  188. struct msg_desc req_desc, rsp_desc;
  189. int ret = 0;
  190. dev_dbg(ac->dev, "%s: is_svc_locked = %s\n",
  191. __func__, is_svc_locked ? "true" : "false");
  192. memset(&req, 0, sizeof(req));
  193. memset(&rsp, 0, sizeof(rsp));
  194. req.reason_valid = 1;
  195. req.reason = ac->state & 0x03;
  196. req_desc.max_msg_len = WCD_SPI_REQ_ACCESS_MSG_V01_MAX_MSG_LEN;
  197. req_desc.msg_id = WCD_SPI_REQ_ACCESS_MSG_V01;
  198. req_desc.ei_array = wcd_spi_req_access_msg_v01_ei;
  199. rsp_desc.max_msg_len = WCD_SPI_REQ_ACCESS_RESP_V01_MAX_MSG_LEN;
  200. rsp_desc.msg_id = WCD_SPI_REQ_ACCESS_RESP_V01;
  201. rsp_desc.ei_array = wcd_spi_req_access_resp_v01_ei;
  202. if (!is_svc_locked)
  203. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
  204. ret = qmi_send_req_wait(ac->qmi_hdl,
  205. &req_desc, &req, sizeof(req),
  206. &rsp_desc, &rsp, sizeof(rsp),
  207. WCD_SPI_AC_QMI_TIMEOUT_MS);
  208. if (ret) {
  209. dev_err(ac->dev, "%s: msg send failed %d\n",
  210. __func__, ret);
  211. goto done;
  212. }
  213. if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
  214. ret = -EIO;
  215. dev_err(ac->dev, "%s: qmi resp error %d\n",
  216. __func__, rsp.resp.result);
  217. }
  218. done:
  219. if (!is_svc_locked)
  220. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
  221. return ret;
  222. }
  223. static int wcd_spi_ac_release_access(struct wcd_spi_ac_priv *ac,
  224. bool is_svc_locked)
  225. {
  226. struct wcd_spi_rel_access_msg_v01 req;
  227. struct wcd_spi_rel_access_resp_v01 rsp;
  228. struct msg_desc req_desc, rsp_desc;
  229. int ret = 0;
  230. dev_dbg(ac->dev, "%s: is_svc_locked = %s\n",
  231. __func__, is_svc_locked ? "true" : "false");
  232. memset(&req, 0, sizeof(req));
  233. memset(&rsp, 0, sizeof(rsp));
  234. req_desc.max_msg_len = WCD_SPI_REL_ACCESS_MSG_V01_MAX_MSG_LEN;
  235. req_desc.msg_id = WCD_SPI_REL_ACCESS_MSG_V01;
  236. req_desc.ei_array = wcd_spi_rel_access_msg_v01_ei;
  237. rsp_desc.max_msg_len = WCD_SPI_REL_ACCESS_RESP_V01_MAX_MSG_LEN;
  238. rsp_desc.msg_id = WCD_SPI_REL_ACCESS_RESP_V01;
  239. rsp_desc.ei_array = wcd_spi_rel_access_resp_v01_ei;
  240. if (!is_svc_locked)
  241. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
  242. ret = qmi_send_req_wait(ac->qmi_hdl,
  243. &req_desc, &req, sizeof(req),
  244. &rsp_desc, &rsp, sizeof(rsp),
  245. WCD_SPI_AC_QMI_TIMEOUT_MS);
  246. if (ret) {
  247. dev_err(ac->dev, "%s: msg send failed %d\n",
  248. __func__, ret);
  249. goto done;
  250. }
  251. if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
  252. ret = -EIO;
  253. dev_err(ac->dev, "%s: qmi resp error %d\n",
  254. __func__, rsp.resp.result);
  255. }
  256. done:
  257. if (!is_svc_locked)
  258. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
  259. return ret;
  260. }
  261. static int wcd_spi_ac_buf_msg(
  262. struct wcd_spi_ac_priv *ac,
  263. u8 *data, int data_sz)
  264. {
  265. struct wcd_spi_ac_buf_data *buf_data;
  266. struct wcd_spi_buff_msg_v01 req;
  267. struct wcd_spi_buff_resp_v01 rsp;
  268. struct msg_desc req_desc, rsp_desc;
  269. int ret = 0;
  270. memset(&req, 0, sizeof(req));
  271. memset(&rsp, 0, sizeof(rsp));
  272. buf_data = (struct wcd_spi_ac_buf_data *) data;
  273. memcpy(req.buff_addr_1, buf_data,
  274. sizeof(*buf_data));
  275. if (data_sz - sizeof(*buf_data) != 0) {
  276. req.buff_addr_2_valid = 1;
  277. buf_data++;
  278. memcpy(req.buff_addr_2, buf_data,
  279. sizeof(*buf_data));
  280. }
  281. req_desc.max_msg_len = WCD_SPI_BUFF_MSG_V01_MAX_MSG_LEN;
  282. req_desc.msg_id = WCD_SPI_BUFF_MSG_V01;
  283. req_desc.ei_array = wcd_spi_buff_msg_v01_ei;
  284. rsp_desc.max_msg_len = WCD_SPI_BUFF_RESP_V01_MAX_MSG_LEN;
  285. rsp_desc.msg_id = WCD_SPI_BUFF_RESP_V01;
  286. rsp_desc.ei_array = wcd_spi_buff_resp_v01_ei;
  287. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
  288. ret = qmi_send_req_wait(ac->qmi_hdl,
  289. &req_desc, &req, sizeof(req),
  290. &rsp_desc, &rsp, sizeof(rsp),
  291. WCD_SPI_AC_QMI_TIMEOUT_MS);
  292. if (ret) {
  293. dev_err(ac->dev, "%s: msg send failed %d\n",
  294. __func__, ret);
  295. goto done;
  296. }
  297. if (rsp.resp.result != QMI_RESULT_SUCCESS_V01) {
  298. ret = -EIO;
  299. dev_err(ac->dev, "%s: qmi resp error %d\n",
  300. __func__, rsp.resp.result);
  301. }
  302. done:
  303. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
  304. return ret;
  305. }
  306. /*
  307. * wcd_spi_ac_set_sync: Sets the current status of the SPI
  308. * bus and requests access if not
  309. * already accesible.
  310. * @ac: pointer to the drivers private data
  311. * @value: value to be set in the status mask
  312. * @is_svc_locked: flag to indicate if svc_lock is acquired by caller
  313. */
  314. static int wcd_spi_ac_set_sync(struct wcd_spi_ac_priv *ac,
  315. u32 value, bool is_svc_locked)
  316. {
  317. int ret = 0;
  318. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->state_lock);
  319. ac->state |= value;
  320. /* any non-zero state indicates us to request SPI access */
  321. wmb();
  322. dev_dbg(ac->dev, "%s: current state = 0x%x, current access 0x%x\n",
  323. __func__, ac->state, ac->current_access);
  324. if (ac->current_access == WCD_SPI_AC_REMOTE_ACCESS) {
  325. dev_dbg(ac->dev,
  326. "%s: requesting access, state = 0x%x\n",
  327. __func__, ac->state);
  328. ret = wcd_spi_ac_request_access(ac, is_svc_locked);
  329. if (!ret)
  330. ac->current_access = WCD_SPI_AC_LOCAL_ACCESS;
  331. }
  332. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->state_lock);
  333. return ret;
  334. }
  335. /*
  336. * wcd_spi_ac_clear_sync: Clears the current status of the SPI
  337. * bus and releases access if applicable
  338. * @ac: pointer to the drivers private data
  339. * @value: value to be cleared in the status mask
  340. * @is_svc_locked: flag to indicate if svc_lock is acquired by caller
  341. */
  342. static int wcd_spi_ac_clear_sync(struct wcd_spi_ac_priv *ac,
  343. u32 value, bool is_svc_locked)
  344. {
  345. int ret = 0;
  346. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->state_lock);
  347. ac->state &= ~(value);
  348. /* make sure value is written before read */
  349. wmb();
  350. dev_dbg(ac->dev, "%s: current state = 0x%x, current access 0x%x\n",
  351. __func__, ac->state, ac->current_access);
  352. /* state should be zero to release SPI access */
  353. if (!ac->state &&
  354. ac->current_access == WCD_SPI_AC_LOCAL_ACCESS) {
  355. dev_dbg(ac->dev,
  356. "%s: releasing access, state = 0x%x\n",
  357. __func__, ac->state);
  358. ret = wcd_spi_ac_release_access(ac, is_svc_locked);
  359. if (!ret)
  360. ac->current_access = WCD_SPI_AC_REMOTE_ACCESS;
  361. }
  362. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->state_lock);
  363. return ret;
  364. }
  365. /*
  366. * wcd_spi_access_ctl: API to request/release the access
  367. * to wcd-spi bus.
  368. * @dev: handle to the wcd-spi-ac device
  369. * @request: enum to indicate access request or access release
  370. * @reason: reason for request/release. Must be one of the
  371. * valid reasons.
  372. * Returns success if the access handover was sucessful,
  373. * negative error code otherwise.
  374. */
  375. int wcd_spi_access_ctl(struct device *dev,
  376. enum wcd_spi_acc_req request,
  377. u32 reason)
  378. {
  379. struct wcd_spi_ac_priv *ac;
  380. int ret = 0;
  381. if (!dev) {
  382. pr_err("%s: invalid device\n", __func__);
  383. return -EINVAL;
  384. }
  385. /* only data_transfer and remote_down are valid reasons */
  386. if (reason != WCD_SPI_AC_DATA_TRANSFER &&
  387. reason != WCD_SPI_AC_REMOTE_DOWN) {
  388. pr_err("%s: Invalid reason 0x%x\n",
  389. __func__, reason);
  390. return -EINVAL;
  391. }
  392. ac = (struct wcd_spi_ac_priv *) dev_get_drvdata(dev);
  393. if (!ac) {
  394. dev_err(dev, "%s: invalid driver data\n", __func__);
  395. return -EINVAL;
  396. }
  397. dev_dbg(dev, "%s: request = 0x%x, reason = 0x%x\n",
  398. __func__, request, reason);
  399. switch (request) {
  400. case WCD_SPI_ACCESS_REQUEST:
  401. ret = wcd_spi_ac_set_sync(ac, reason, false);
  402. if (ret)
  403. dev_err(dev, "%s: set_sync(0x%x) failed %d\n",
  404. __func__, reason, ret);
  405. break;
  406. case WCD_SPI_ACCESS_RELEASE:
  407. ret = wcd_spi_ac_clear_sync(ac, reason, false);
  408. if (ret)
  409. dev_err(dev, "%s: clear_sync(0x%x) failed %d\n",
  410. __func__, reason, ret);
  411. break;
  412. default:
  413. dev_err(dev, "%s: invalid request 0x%x\n",
  414. __func__, request);
  415. break;
  416. }
  417. return ret;
  418. }
  419. EXPORT_SYMBOL(wcd_spi_access_ctl);
  420. static int wcd_spi_ac_cdev_open(struct inode *inode,
  421. struct file *file)
  422. {
  423. struct wcd_spi_ac_priv *ac;
  424. int ret = 0;
  425. ac = container_of(inode->i_cdev, struct wcd_spi_ac_priv, cdev);
  426. if (!ac) {
  427. pr_err("%s: Invalid private data\n", __func__);
  428. return -EINVAL;
  429. }
  430. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->status_lock);
  431. if (ac->svc_offline) {
  432. dev_err(ac->dev, "%s: SVC is not online, cannot open driver\n",
  433. __func__);
  434. ret = -ENODEV;
  435. goto done;
  436. }
  437. file->private_data = ac;
  438. done:
  439. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->status_lock);
  440. return ret;
  441. }
  442. static ssize_t wcd_spi_ac_cdev_write(struct file *file,
  443. const char __user *buf,
  444. size_t count,
  445. loff_t *ppos)
  446. {
  447. struct wcd_spi_ac_priv *ac;
  448. struct wcd_spi_ac_write_cmd *cmd_buf;
  449. int ret = 0;
  450. int data_sz;
  451. ac = (struct wcd_spi_ac_priv *) file->private_data;
  452. if (!ac) {
  453. pr_err("%s: Invalid private data\n", __func__);
  454. return -EINVAL;
  455. }
  456. if (count < WCD_SPI_AC_WRITE_CMD_MIN_SIZE ||
  457. count > WCD_SPI_AC_WRITE_CMD_MAX_SIZE) {
  458. dev_err(ac->dev, "%s: Invalid write count %zd\n",
  459. __func__, count);
  460. return -EINVAL;
  461. }
  462. cmd_buf = kzalloc(count, GFP_KERNEL);
  463. if (!cmd_buf)
  464. return -ENOMEM;
  465. if (get_user(cmd_buf->cmd_type, buf)) {
  466. dev_err(ac->dev, "%s: get_user failed\n", __func__);
  467. ret = -EFAULT;
  468. goto free_cmd_buf;
  469. }
  470. dev_dbg(ac->dev, "%s: write cmd type 0x%x\n",
  471. __func__, cmd_buf->cmd_type);
  472. switch (cmd_buf->cmd_type) {
  473. case WCD_SPI_AC_CMD_CONC_BEGIN:
  474. ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_CONCURRENCY, false);
  475. if (ret) {
  476. dev_err(ac->dev, "%s: set_sync(CONC) fail %d\n",
  477. __func__, ret);
  478. goto free_cmd_buf;
  479. }
  480. break;
  481. case WCD_SPI_AC_CMD_CONC_END:
  482. ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_CONCURRENCY, false);
  483. if (ret) {
  484. dev_err(ac->dev, "%s: clear_sync(CONC) fail %d\n",
  485. __func__, ret);
  486. goto free_cmd_buf;
  487. }
  488. break;
  489. case WCD_SPI_AC_CMD_BUF_DATA:
  490. /* Read the buffer details and send to service */
  491. data_sz = count - sizeof(cmd_buf->cmd_type);
  492. if (!data_sz ||
  493. (data_sz % sizeof(struct wcd_spi_ac_buf_data))) {
  494. dev_err(ac->dev, "%s: size %d not multiple of %ld\n",
  495. __func__, data_sz,
  496. sizeof(struct wcd_spi_ac_buf_data));
  497. goto free_cmd_buf;
  498. }
  499. if (data_sz / sizeof(struct wcd_spi_ac_buf_data) >
  500. WCD_SPI_AC_MAX_BUFFERS) {
  501. dev_err(ac->dev, "%s: invalid size %d\n",
  502. __func__, data_sz);
  503. goto free_cmd_buf;
  504. }
  505. if (copy_from_user(cmd_buf->payload,
  506. buf + sizeof(cmd_buf->cmd_type),
  507. data_sz)) {
  508. dev_err(ac->dev, "%s: copy_from_user failed\n",
  509. __func__);
  510. ret = -EFAULT;
  511. goto free_cmd_buf;
  512. }
  513. ret = wcd_spi_ac_buf_msg(ac, cmd_buf->payload, data_sz);
  514. if (ret) {
  515. dev_err(ac->dev, "%s: _buf_msg failed %d\n",
  516. __func__, ret);
  517. goto free_cmd_buf;
  518. }
  519. ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_UNINITIALIZED,
  520. false);
  521. if (ret) {
  522. dev_err(ac->dev, "%s: clear_sync 0x%lx failed %d\n",
  523. __func__, WCD_SPI_AC_UNINITIALIZED, ret);
  524. goto free_cmd_buf;
  525. }
  526. break;
  527. default:
  528. dev_err(ac->dev, "%s: Invalid cmd_type 0x%x\n",
  529. __func__, cmd_buf->cmd_type);
  530. ret = -EINVAL;
  531. goto free_cmd_buf;
  532. }
  533. free_cmd_buf:
  534. kfree(cmd_buf);
  535. if (!ret)
  536. ret = count;
  537. return ret;
  538. }
  539. static int wcd_spi_ac_cdev_release(struct inode *inode,
  540. struct file *file)
  541. {
  542. struct wcd_spi_ac_priv *ac;
  543. int ret = 0;
  544. ac = (struct wcd_spi_ac_priv *) file->private_data;
  545. if (!ac) {
  546. pr_err("%s: Invalid private data\n", __func__);
  547. return -EINVAL;
  548. }
  549. ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_UNINITIALIZED, false);
  550. if (ret)
  551. dev_err(ac->dev, "%s: set_sync(UNINITIALIZED) failed %d\n",
  552. __func__, ret);
  553. return ret;
  554. }
  555. static const struct file_operations wcd_spi_ac_cdev_fops = {
  556. .owner = THIS_MODULE,
  557. .open = wcd_spi_ac_cdev_open,
  558. .write = wcd_spi_ac_cdev_write,
  559. .release = wcd_spi_ac_cdev_release,
  560. };
  561. static int wcd_spi_ac_reg_chardev(struct wcd_spi_ac_priv *ac)
  562. {
  563. int ret;
  564. ret = alloc_chrdev_region(&ac->cdev_num, 0, 1,
  565. WCD_SPI_AC_CLIENT_CDEV_NAME);
  566. if (ret) {
  567. dev_err(ac->dev, "%s: alloc_chrdev_region failed %d\n",
  568. __func__, ret);
  569. return ret;
  570. }
  571. ac->cls = class_create(THIS_MODULE, WCD_SPI_AC_CLIENT_CDEV_NAME);
  572. if (IS_ERR(ac->cls)) {
  573. ret = PTR_ERR(ac->cls);
  574. dev_err(ac->dev, "%s: class_create failed %d\n",
  575. __func__, ret);
  576. goto unregister_chrdev;
  577. }
  578. ac->chardev = device_create(ac->cls, NULL, ac->cdev_num,
  579. NULL, WCD_SPI_AC_CLIENT_CDEV_NAME);
  580. if (IS_ERR(ac->chardev)) {
  581. ret = PTR_ERR(ac->chardev);
  582. dev_err(ac->dev, "%s: device_create failed %d\n",
  583. __func__, ret);
  584. goto destroy_class;
  585. }
  586. cdev_init(&ac->cdev, &wcd_spi_ac_cdev_fops);
  587. ret = cdev_add(&ac->cdev, ac->cdev_num, 1);
  588. if (ret) {
  589. dev_err(ac->dev, "%s: cdev_add failed %d\n",
  590. __func__, ret);
  591. goto destroy_device;
  592. }
  593. return 0;
  594. destroy_device:
  595. device_destroy(ac->cls, ac->cdev_num);
  596. destroy_class:
  597. class_destroy(ac->cls);
  598. unregister_chrdev:
  599. unregister_chrdev_region(0, 1);
  600. return ret;
  601. }
  602. static int wcd_spi_ac_unreg_chardev(struct wcd_spi_ac_priv *ac)
  603. {
  604. cdev_del(&ac->cdev);
  605. device_destroy(ac->cls, ac->cdev_num);
  606. class_destroy(ac->cls);
  607. unregister_chrdev_region(0, 1);
  608. return 0;
  609. }
  610. static void wcd_spi_ac_recv_msg(struct work_struct *work)
  611. {
  612. struct wcd_spi_ac_priv *ac;
  613. int rc = 0;
  614. ac = container_of(work, struct wcd_spi_ac_priv,
  615. recv_msg_work);
  616. if (!ac) {
  617. pr_err("%s: Invalid private data\n", __func__);
  618. return;
  619. }
  620. do {
  621. dev_dbg(ac->dev, "%s: msg received, rc = %d\n",
  622. __func__, rc);
  623. } while ((rc = qmi_recv_msg(ac->qmi_hdl)) == 0);
  624. if (rc != -ENOMSG)
  625. dev_err(ac->dev, "%s: qmi_recv_msg failed %d\n",
  626. __func__, rc);
  627. }
  628. static void wcd_spi_ac_clnt_notify(struct qmi_handle *hdl,
  629. enum qmi_event_type event, void *priv_data)
  630. {
  631. struct wcd_spi_ac_priv *ac;
  632. if (!priv_data) {
  633. pr_err("%s: Invalid private data\n", __func__);
  634. return;
  635. }
  636. ac = (struct wcd_spi_ac_priv *) priv_data;
  637. switch (event) {
  638. case QMI_RECV_MSG:
  639. queue_work(ac->qmi_wq, &ac->recv_msg_work);
  640. break;
  641. default:
  642. break;
  643. }
  644. }
  645. static void wcd_spi_ac_svc_arrive(struct work_struct *work)
  646. {
  647. struct wcd_spi_ac_priv *ac;
  648. int ret;
  649. ac = container_of(work, struct wcd_spi_ac_priv,
  650. svc_arr_work);
  651. if (!ac) {
  652. pr_err("%s: Invalid private data\n",
  653. __func__);
  654. return;
  655. }
  656. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
  657. ac->qmi_hdl = qmi_handle_create(wcd_spi_ac_clnt_notify,
  658. ac);
  659. if (!ac->qmi_hdl) {
  660. dev_err(ac->dev, "%s: qmi_handle_create failed\n",
  661. __func__);
  662. goto done;
  663. }
  664. ret = qmi_connect_to_service(ac->qmi_hdl,
  665. WCD_SPI_CTL_SERVICE_ID_V01,
  666. WCD_SPI_CTL_SERVICE_VERS_V01,
  667. WCD_SPI_CTL_INS_ID);
  668. if (ret) {
  669. dev_err(ac->dev, "%s, cant connect to service, error %d\n",
  670. __func__, ret);
  671. qmi_handle_destroy(ac->qmi_hdl);
  672. ac->qmi_hdl = NULL;
  673. goto done;
  674. }
  675. /* Mark service as online */
  676. wcd_spi_ac_status_change(ac, 1);
  677. /*
  678. * update the state and clear the WCD_SPI_AC_SVC_OFFLINE
  679. * bit to indicate that the service is now online.
  680. */
  681. ret = wcd_spi_ac_clear_sync(ac, WCD_SPI_AC_SVC_OFFLINE, true);
  682. if (ret)
  683. dev_err(ac->dev, "%s: clear_sync(SVC_OFFLINE) failed %d\n",
  684. __func__, ret);
  685. done:
  686. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
  687. }
  688. static void wcd_spi_ac_svc_exit(struct work_struct *work)
  689. {
  690. struct wcd_spi_ac_priv *ac;
  691. int ret = 0;
  692. ac = container_of(work, struct wcd_spi_ac_priv,
  693. svc_exit_work);
  694. if (!ac) {
  695. pr_err("%s: Invalid private data\n",
  696. __func__);
  697. return;
  698. }
  699. WCD_SPI_AC_MUTEX_LOCK(ac->dev, ac->svc_lock);
  700. ret = wcd_spi_ac_set_sync(ac, WCD_SPI_AC_SVC_OFFLINE, true);
  701. if (ret)
  702. dev_err(ac->dev, "%s: set_sync(SVC_OFFLINE) failed %d\n",
  703. __func__, ret);
  704. qmi_handle_destroy(ac->qmi_hdl);
  705. ac->qmi_hdl = NULL;
  706. wcd_spi_ac_status_change(ac, 0);
  707. WCD_SPI_AC_MUTEX_UNLOCK(ac->dev, ac->svc_lock);
  708. }
  709. static int wcd_spi_ac_svc_event(struct notifier_block *this,
  710. unsigned long event,
  711. void *data)
  712. {
  713. struct wcd_spi_ac_priv *ac;
  714. ac = container_of(this, struct wcd_spi_ac_priv, nb);
  715. if (!ac) {
  716. pr_err("%s: Invalid private data\n", __func__);
  717. return -EINVAL;
  718. }
  719. dev_dbg(ac->dev, "%s: event = 0x%lx", __func__, event);
  720. switch (event) {
  721. case QMI_SERVER_ARRIVE:
  722. schedule_work(&ac->svc_arr_work);
  723. break;
  724. case QMI_SERVER_EXIT:
  725. schedule_work(&ac->svc_exit_work);
  726. break;
  727. default:
  728. dev_err(ac->dev, "%s unhandled event %ld\n",
  729. __func__, event);
  730. break;
  731. }
  732. return 0;
  733. }
  734. static int wcd_spi_ac_probe(struct platform_device *pdev)
  735. {
  736. struct wcd_spi_ac_priv *ac;
  737. struct device *parent = pdev->dev.parent;
  738. int ret = 0;
  739. ac = devm_kzalloc(&pdev->dev, sizeof(*ac),
  740. GFP_KERNEL);
  741. if (!ac)
  742. return -ENOMEM;
  743. ac->dev = &pdev->dev;
  744. ac->parent = parent;
  745. ret = wcd_spi_ac_reg_chardev(ac);
  746. if (ret)
  747. return ret;
  748. ret = wcd_spi_ac_procfs_init(ac);
  749. if (ret)
  750. goto unreg_chardev;
  751. mutex_init(&ac->status_lock);
  752. mutex_init(&ac->state_lock);
  753. mutex_init(&ac->svc_lock);
  754. init_waitqueue_head(&ac->svc_poll_wait);
  755. ac->svc_offline = 1;
  756. ac->state = (WCD_SPI_AC_SVC_OFFLINE |
  757. WCD_SPI_AC_UNINITIALIZED);
  758. ac->current_access = WCD_SPI_AC_LOCAL_ACCESS;
  759. ac->nb.notifier_call = wcd_spi_ac_svc_event;
  760. INIT_WORK(&ac->svc_arr_work, wcd_spi_ac_svc_arrive);
  761. INIT_WORK(&ac->svc_exit_work, wcd_spi_ac_svc_exit);
  762. INIT_WORK(&ac->recv_msg_work, wcd_spi_ac_recv_msg);
  763. ac->qmi_wq = create_singlethread_workqueue("qmi_wq");
  764. if (!ac->qmi_wq) {
  765. dev_err(&pdev->dev,
  766. "%s: create_singlethread_workqueue failed\n",
  767. __func__);
  768. goto deinit_procfs;
  769. }
  770. dev_set_drvdata(&pdev->dev, ac);
  771. ret = qmi_svc_event_notifier_register(
  772. WCD_SPI_CTL_SERVICE_ID_V01,
  773. WCD_SPI_CTL_SERVICE_VERS_V01,
  774. WCD_SPI_CTL_INS_ID,
  775. &ac->nb);
  776. if (ret) {
  777. dev_err(&pdev->dev,
  778. "%s: qmi_svc_event_notifier_register failed %d\n",
  779. __func__, ret);
  780. goto destroy_wq;
  781. }
  782. return 0;
  783. destroy_wq:
  784. destroy_workqueue(ac->qmi_wq);
  785. dev_set_drvdata(&pdev->dev, NULL);
  786. deinit_procfs:
  787. wcd_spi_ac_procfs_deinit(ac);
  788. mutex_destroy(&ac->status_lock);
  789. mutex_destroy(&ac->state_lock);
  790. mutex_destroy(&ac->svc_lock);
  791. unreg_chardev:
  792. wcd_spi_ac_unreg_chardev(ac);
  793. return ret;
  794. }
  795. static int wcd_spi_ac_remove(struct platform_device *pdev)
  796. {
  797. struct wcd_spi_ac_priv *ac;
  798. ac = dev_get_drvdata(&pdev->dev);
  799. qmi_svc_event_notifier_unregister(
  800. WCD_SPI_CTL_SERVICE_ID_V01,
  801. WCD_SPI_CTL_SERVICE_VERS_V01,
  802. WCD_SPI_CTL_INS_ID,
  803. &ac->nb);
  804. if (ac->qmi_wq)
  805. destroy_workqueue(ac->qmi_wq);
  806. wcd_spi_ac_unreg_chardev(ac);
  807. wcd_spi_ac_procfs_deinit(ac);
  808. mutex_destroy(&ac->status_lock);
  809. mutex_destroy(&ac->state_lock);
  810. mutex_destroy(&ac->svc_lock);
  811. return 0;
  812. }
  813. static const struct of_device_id wcd_spi_ac_of_match[] = {
  814. { .compatible = "qcom,wcd-spi-ac" },
  815. { },
  816. };
  817. MODULE_DEVICE_TABLE(of, wcd_spi_ac_of_match);
  818. static struct platform_driver wcd_spi_ac_driver = {
  819. .driver = {
  820. .name = "qcom,wcd-spi-ac",
  821. .of_match_table = wcd_spi_ac_of_match,
  822. .suppress_bind_attrs = true,
  823. },
  824. .probe = wcd_spi_ac_probe,
  825. .remove = wcd_spi_ac_remove,
  826. };
  827. module_platform_driver(wcd_spi_ac_driver);
  828. MODULE_DESCRIPTION("WCD SPI access control driver");
  829. MODULE_LICENSE("GPL v2");