mtk_extd_mgr.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. /*****************************************************************************/
  2. /*****************************************************************************/
  3. #include <linux/mm.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/device.h>
  7. #include <linux/platform_device.h>
  8. /*#include <linux/rtpm_prio.h>*/
  9. #include <linux/miscdevice.h>
  10. #include <linux/fs.h>
  11. #include <linux/file.h>
  12. #include <linux/cdev.h>
  13. #include <linux/module.h>
  14. #include <linux/list.h>
  15. #include <linux/switch.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/atomic.h>
  18. /*#include "mach/mt_typedefs.h"*/
  19. #include <linux/types.h>
  20. #include "extd_log.h"
  21. #include "extd_utils.h"
  22. #include "extd_factory.h"
  23. #include "mtk_extd_mgr.h"
  24. /*#include <linux/earlysuspend.h>*/
  25. #include <linux/suspend.h>
  26. #ifdef CONFIG_PM_AUTOSLEEP
  27. #include <linux/fb.h>
  28. #include <linux/notifier.h>
  29. #include "mt8193_ckgen.h"
  30. #endif
  31. #define EXTD_DEVNAME "hdmitx"
  32. #define EXTD_DEV_ID(id) (((id)>>16)&0x0ff)
  33. #define EXTD_DEV_PARAM(id) ((id)&0x0ff)
  34. static dev_t extd_devno;
  35. static struct cdev *extd_cdev;
  36. static struct class *extd_class;
  37. static const struct EXTD_DRIVER *extd_driver[DEV_MAX_NUM - 1];
  38. static const struct EXTD_DRIVER *extd_factory_driver[DEV_MAX_NUM - 1];
  39. static void external_display_enable(unsigned long param)
  40. {
  41. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  42. int enable = EXTD_DEV_PARAM(param);
  43. if (device_id >= DEV_MAX_NUM) {
  44. EXT_MGR_ERR("external_display_enable, device id is invalid!");
  45. return;
  46. }
  47. if (extd_driver[device_id] && extd_driver[device_id]->enable)
  48. extd_driver[device_id]->enable(enable);
  49. }
  50. static void external_display_power_enable(unsigned long param)
  51. {
  52. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  53. int enable = EXTD_DEV_PARAM(param);
  54. if (device_id >= DEV_MAX_NUM) {
  55. EXT_MGR_ERR("external_display_power_enable, device id is invalid!");
  56. return;
  57. }
  58. if (extd_driver[device_id] && extd_driver[device_id]->power_enable)
  59. extd_driver[device_id]->power_enable(enable);
  60. }
  61. /*
  62. static void external_display_force_disable(unsigned long param)
  63. {
  64. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  65. if (device_id >= DEV_MAX_NUM) {
  66. EXT_MGR_ERR("external_display_force_disable, device id is invalid!");
  67. return;
  68. }
  69. return;
  70. }
  71. */
  72. static void external_display_set_resolution(unsigned long param)
  73. {
  74. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  75. int res = EXTD_DEV_PARAM(param);
  76. if (device_id >= DEV_MAX_NUM) {
  77. EXT_MGR_ERR("external_display_set_resolution, device id is invalid!");
  78. return;
  79. }
  80. if (extd_driver[device_id] && extd_driver[device_id]->set_resolution)
  81. extd_driver[device_id]->set_resolution(res);
  82. }
  83. static int external_display_get_dev_info(unsigned long param, void *info)
  84. {
  85. int ret = 0;
  86. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  87. if (device_id >= DEV_MAX_NUM) {
  88. EXT_MGR_ERR("external_display_get_dev_info, device id is invalid!");
  89. return ret;
  90. }
  91. if (extd_driver[device_id] && extd_driver[device_id]->get_dev_info)
  92. ret = extd_driver[device_id]->get_dev_info(AP_GET_INFO, info);
  93. return ret;
  94. }
  95. static int external_display_get_capability(unsigned long param, void *info)
  96. {
  97. int ret = 0;
  98. enum EXTD_DEV_ID device_id = EXTD_DEV_ID(param);
  99. device_id = DEV_MHL;
  100. if (device_id >= DEV_MAX_NUM) {
  101. EXT_MGR_ERR("external_display_get_capability, device id is invalid!");
  102. return ret;
  103. }
  104. if (extd_driver[device_id] && extd_driver[device_id]->get_capability)
  105. ret = extd_driver[device_id]->get_capability(info);
  106. return ret;
  107. }
  108. static long mtk_extd_mgr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  109. {
  110. void __user *argp = (void __user *)arg;
  111. int r = 0;
  112. EXT_MGR_LOG("[EXTD]ioctl= %s(%d), arg = %lu\n", _extd_ioctl_spy(cmd), cmd & 0xff, arg);
  113. switch (cmd) {
  114. case MTK_HDMI_AUDIO_VIDEO_ENABLE:
  115. {
  116. /* 0xXY
  117. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  118. * the device id:
  119. * X = 0 - mhl
  120. * X = 1 - wifi display
  121. */
  122. external_display_enable(arg);
  123. break;
  124. }
  125. case MTK_HDMI_POWER_ENABLE:
  126. {
  127. /* 0xXY
  128. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  129. * the device id:
  130. * X = 0 - mhl
  131. * X = 1 - wifi display
  132. */
  133. external_display_power_enable(arg);
  134. break;
  135. }
  136. case MTK_HDMI_VIDEO_CONFIG:
  137. {
  138. /* 0xXY
  139. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  140. * the device id:
  141. * X = 0 - mhl
  142. * X = 1 - wifi display
  143. */
  144. external_display_set_resolution(arg);
  145. break;
  146. }
  147. case MTK_HDMI_FORCE_FULLSCREEN_ON:
  148. /* case MTK_HDMI_FORCE_CLOSE: */
  149. {
  150. /* 0xXY
  151. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  152. * the device id:
  153. * X = 0 - mhl
  154. * X = 1 - wifi display
  155. */
  156. arg = arg | 0x1;
  157. external_display_power_enable(arg);
  158. break;
  159. }
  160. case MTK_HDMI_FORCE_FULLSCREEN_OFF:
  161. /* case MTK_HDMI_FORCE_OPEN: */
  162. {
  163. /* 0xXY
  164. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  165. * the device id:
  166. * X = 0 - mhl
  167. * X = 1 - wifi display
  168. */
  169. arg = arg & 0x0FF0000;
  170. external_display_power_enable(arg);
  171. break;
  172. }
  173. case MTK_HDMI_GET_DEV_INFO:
  174. {
  175. /* 0xXY
  176. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  177. * the device id:
  178. * X = 0 - mhl
  179. * X = 1 - wifi display
  180. */
  181. r = external_display_get_dev_info(*((unsigned long *)argp), argp);
  182. break;
  183. }
  184. case MTK_HDMI_USBOTG_STATUS:
  185. {
  186. /* hdmi_set_USBOTG_status(arg); */
  187. break;
  188. }
  189. case MTK_HDMI_AUDIO_ENABLE:
  190. {
  191. EXT_MGR_LOG("[EXTD]hdmi_set_audio_enable, arg = %lu\n", arg);
  192. if (extd_driver[DEV_MHL] && extd_driver[DEV_MHL]->set_audio_enable)
  193. r = extd_driver[DEV_MHL]->set_audio_enable((arg & 0x0FF));
  194. break;
  195. }
  196. case MTK_HDMI_VIDEO_ENABLE:
  197. {
  198. break;
  199. }
  200. case MTK_HDMI_AUDIO_CONFIG:
  201. {
  202. break;
  203. }
  204. case MTK_HDMI_IS_FORCE_AWAKE:
  205. {
  206. /* r = hdmi_is_force_awake(argp); */
  207. break;
  208. }
  209. case MTK_HDMI_GET_EDID:
  210. {
  211. if (extd_driver[DEV_MHL] && extd_driver[DEV_MHL]->get_edid)
  212. r = extd_driver[DEV_MHL]->get_edid(argp);
  213. break;
  214. }
  215. case MTK_HDMI_GET_CAPABILITY:
  216. {
  217. /* 0xXY
  218. * the low 16 bits(Y) are for disable and enable, and the high 16 bits(X) are for device id
  219. * the device id:
  220. * X = 0 - mhl
  221. * X = 1 - wifi display
  222. */
  223. r = external_display_get_capability(*((unsigned long *)argp), argp);
  224. break;
  225. }
  226. case MTK_HDMI_SCREEN_CAPTURE:
  227. {
  228. /* no actions */
  229. break;
  230. }
  231. case MTK_HDMI_FACTORY_CHIP_INIT:
  232. {
  233. if (extd_factory_driver[DEV_MHL] && extd_factory_driver[DEV_MHL]->factory_mode_test)
  234. r = extd_factory_driver[DEV_MHL]->factory_mode_test(STEP1_CHIP_INIT, NULL);
  235. break;
  236. }
  237. case MTK_HDMI_FACTORY_JUDGE_CALLBACK:
  238. {
  239. if (extd_factory_driver[DEV_MHL] && extd_factory_driver[DEV_MHL]->factory_mode_test)
  240. r = extd_factory_driver[DEV_MHL]->factory_mode_test(STEP2_JUDGE_CALLBACK, argp);
  241. break;
  242. }
  243. case MTK_HDMI_FACTORY_START_DPI_AND_CONFIG:
  244. {
  245. if (extd_factory_driver[DEV_MHL] && extd_factory_driver[DEV_MHL]->factory_mode_test)
  246. r = extd_factory_driver[DEV_MHL]->factory_mode_test(STEP3_START_DPI_AND_CONFIG,
  247. (void *)arg);
  248. break;
  249. }
  250. case MTK_HDMI_FACTORY_DPI_STOP_AND_POWER_OFF:
  251. {
  252. /* /r = hdmi_factory_mode_test(STEP4_DPI_STOP_AND_POWER_OFF, NULL); */
  253. break;
  254. }
  255. case MTK_HDMI_FAKE_PLUG_IN:
  256. {
  257. int connect = arg & 0x0FF;
  258. if (extd_driver[DEV_MHL] && extd_driver[DEV_MHL]->fake_connect)
  259. extd_driver[DEV_MHL]->fake_connect(connect);
  260. break;
  261. }
  262. default:
  263. {
  264. EXT_MGR_ERR("[EXTD]ioctl(%d) arguments is not support\n", cmd & 0x0ff);
  265. r = -EFAULT;
  266. break;
  267. }
  268. }
  269. EXT_MGR_LOG("[EXTD]ioctl = %s(%d) done\n", _extd_ioctl_spy(cmd), cmd & 0x0ff);
  270. return r;
  271. }
  272. static int mtk_extd_mgr_open(struct inode *inode, struct file *file)
  273. {
  274. EXT_MGR_FUNC();
  275. return 0;
  276. }
  277. static int mtk_extd_mgr_release(struct inode *inode, struct file *file)
  278. {
  279. EXT_MGR_FUNC();
  280. return 0;
  281. }
  282. #ifdef CONFIG_COMPAT
  283. static long mtk_extd_mgr_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  284. {
  285. long ret = -ENOIOCTLCMD;
  286. switch (cmd) {
  287. /* add cases here for 32bit/64bit conversion */
  288. /* ... */
  289. default:
  290. ret = mtk_extd_mgr_ioctl(file, cmd, arg);
  291. }
  292. return ret;
  293. }
  294. #endif
  295. const struct file_operations external_display_fops = {
  296. .owner = THIS_MODULE,
  297. .unlocked_ioctl = mtk_extd_mgr_ioctl,
  298. #ifdef CONFIG_COMPAT
  299. .compat_ioctl = mtk_extd_mgr_compat_ioctl,
  300. #endif
  301. .open = mtk_extd_mgr_open,
  302. .release = mtk_extd_mgr_release,
  303. };
  304. static const struct of_device_id extd_of_ids[] = {
  305. {.compatible = "mediatek,hdmitx",},
  306. {}
  307. };
  308. struct device *ext_dev_context;
  309. static int mtk_extd_mgr_probe(struct platform_device *pdev)
  310. {
  311. int ret = 0;
  312. int i = 0;
  313. struct class_device *class_dev = NULL;
  314. EXT_MGR_FUNC();
  315. /* Allocate device number for hdmi driver */
  316. ret = alloc_chrdev_region(&extd_devno, 0, 1, EXTD_DEVNAME);
  317. if (ret) {
  318. EXT_MGR_LOG("alloc_chrdev_region fail\n");
  319. return -1;
  320. }
  321. /* For character driver register to system, device number binded to file operations */
  322. extd_cdev = cdev_alloc();
  323. extd_cdev->owner = THIS_MODULE;
  324. extd_cdev->ops = &external_display_fops;
  325. ret = cdev_add(extd_cdev, extd_devno, 1);
  326. /* For device number binded to device name(hdmitx), one class is corresponeded to one node */
  327. extd_class = class_create(THIS_MODULE, EXTD_DEVNAME);
  328. /* mknod /dev/hdmitx */
  329. class_dev = (struct class_device *)device_create(extd_class, NULL, extd_devno, NULL, EXTD_DEVNAME);
  330. ext_dev_context = (struct device *)&(pdev->dev);
  331. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  332. if (extd_driver[i]->post_init != 0)
  333. extd_driver[i]->post_init();
  334. }
  335. EXT_MGR_LOG("[%s] out\n", __func__);
  336. return 0;
  337. }
  338. static int mtk_extd_mgr_remove(struct platform_device *pdev)
  339. {
  340. EXT_MGR_FUNC();
  341. return 0;
  342. }
  343. #ifdef CONFIG_PM
  344. int extd_pm_suspend(struct device *device)
  345. {
  346. EXT_MGR_FUNC();
  347. return 0;
  348. }
  349. int extd_pm_resume(struct device *device)
  350. {
  351. EXT_MGR_FUNC();
  352. return 0;
  353. }
  354. const struct dev_pm_ops extd_pm_ops = {
  355. .suspend = extd_pm_suspend,
  356. .resume = extd_pm_resume,
  357. };
  358. #endif
  359. static struct platform_driver external_display_driver = {
  360. .probe = mtk_extd_mgr_probe,
  361. .remove = mtk_extd_mgr_remove,
  362. .driver = {
  363. .name = EXTD_DEVNAME,
  364. #ifdef CONFIG_PM
  365. .pm = &extd_pm_ops,
  366. #endif
  367. .of_match_table = extd_of_ids,
  368. }
  369. };
  370. #ifdef CONFIG_HAS_EARLYSUSPEND
  371. static void extd_early_suspend(struct early_suspend *h)
  372. {
  373. EXT_MGR_FUNC();
  374. int i = 0;
  375. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  376. if (i != DEV_EINK && extd_driver[i]->power_enable)
  377. extd_driver[i]->power_enable(0);
  378. }
  379. }
  380. static void extd_late_resume(struct early_suspend *h)
  381. {
  382. EXT_MGR_FUNC();
  383. int i = 0;
  384. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  385. if (i != DEV_EINK && extd_driver[i]->power_enable)
  386. extd_driver[i]->power_enable(1);
  387. }
  388. }
  389. static struct early_suspend extd_early_suspend_handler = {
  390. .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1,
  391. .suspend = extd_early_suspend,
  392. .resume = extd_late_resume,
  393. };
  394. #endif
  395. #if defined(CONFIG_PM_AUTOSLEEP)
  396. static void extd_hdmi_early_suspend(void)
  397. {
  398. int i = 0;
  399. EXT_MGR_FUNC();
  400. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  401. if (i != DEV_EINK && extd_driver[i]->power_enable)
  402. extd_driver[i]->power_enable(0);
  403. }
  404. mt8193_ckgen_early_suspend();
  405. }
  406. static void extd_hdmi_late_resume(void)
  407. {
  408. int i = 0;
  409. EXT_MGR_FUNC();
  410. mt8193_ckgen_late_resume();
  411. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  412. if (i != DEV_EINK && extd_driver[i]->power_enable)
  413. extd_driver[i]->power_enable(1);
  414. }
  415. }
  416. static int extd_hdmi_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *fb_evdata)
  417. {
  418. struct fb_event *evdata = fb_evdata;
  419. int blank;
  420. if (event != FB_EVENT_BLANK)
  421. return 0;
  422. blank = *(int *)evdata->data;
  423. switch (blank) {
  424. case FB_BLANK_UNBLANK:
  425. case FB_BLANK_NORMAL:
  426. extd_hdmi_late_resume();
  427. break;
  428. case FB_BLANK_VSYNC_SUSPEND:
  429. case FB_BLANK_HSYNC_SUSPEND:
  430. break;
  431. case FB_BLANK_POWERDOWN:
  432. extd_hdmi_early_suspend();
  433. break;
  434. default:
  435. return -EINVAL;
  436. }
  437. return 0;
  438. }
  439. static struct notifier_block extd_hdmi_fb_notif = {
  440. .notifier_call = extd_hdmi_fb_notifier_callback,
  441. };
  442. #endif
  443. static int __init mtk_extd_mgr_init(void)
  444. {
  445. int i = 0;
  446. #ifdef CONFIG_PM_AUTOSLEEP
  447. int ret = 0;
  448. #endif
  449. EXT_MGR_FUNC();
  450. extd_driver[DEV_MHL] = EXTD_HDMI_Driver();
  451. extd_driver[DEV_EINK] = EXTD_EPD_Driver();
  452. extd_factory_driver[DEV_MHL] = EXTD_Factory_HDMI_Driver();
  453. for (i = DEV_MHL; i < DEV_MAX_NUM - 1; i++) {
  454. if (extd_driver[i]->init)
  455. extd_driver[i]->init();
  456. }
  457. if (platform_driver_register(&external_display_driver)) {
  458. EXT_MGR_ERR("[EXTD]failed to register mtkfb driver\n");
  459. return -1;
  460. }
  461. #ifdef CONFIG_HAS_EARLYSUSPEND
  462. register_early_suspend(&extd_early_suspend_handler);
  463. #endif
  464. #ifdef CONFIG_PM_AUTOSLEEP
  465. ret = fb_register_client(&extd_hdmi_fb_notif);
  466. if (ret) {
  467. pr_err("fail to register extd_hdmi_fb notifier, ret=%d\n", ret);
  468. return ret;
  469. }
  470. #endif
  471. return 0;
  472. }
  473. static void __exit mtk_extd_mgr_exit(void)
  474. {
  475. device_destroy(extd_class, extd_devno);
  476. class_destroy(extd_class);
  477. cdev_del(extd_cdev);
  478. unregister_chrdev_region(extd_devno, 1);
  479. }
  480. module_init(mtk_extd_mgr_init);
  481. module_exit(mtk_extd_mgr_exit);
  482. MODULE_AUTHOR("www.mediatek.com>");
  483. MODULE_DESCRIPTION("External Display Driver");
  484. MODULE_LICENSE("GPL");