mtk_extd_mgr.c 13 KB

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