1 /*
2 * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/miscdevice.h>
20 #include "securec.h"
21 #include "hi_osal.h"
22 #include "hidev.h"
23
24 static osal_semaphore g_hidev_pm_sem = {0};
25 static hi_u32 g_hidev_pm_cmd = -1;
26 static hi_s32 g_dbg_flag = 1;
27 #define hidev_dbg(params...) do { \
28 if (g_dbg_flag) { \
29 osal_printk(params); \
30 } \
31 } while (0)
32
hidev_open(hi_void * private_data)33 static hi_s32 hidev_open(hi_void *private_data)
34 {
35 hidev_dbg("Enter hidev_open\n");
36 return HI_SUCCESS;
37 }
38
hidev_release(hi_void * private_data)39 static hi_s32 hidev_release(hi_void *private_data)
40 {
41 hidev_dbg("Enter hidev_release\n");
42 return HI_SUCCESS;
43 }
44
hidev_get_pm_cmd(unsigned int cmd,hi_void * para,hi_void * private_data)45 static hi_s32 hidev_get_pm_cmd(unsigned int cmd, hi_void *para, hi_void *private_data)
46 {
47 struct hidev_pm_cmd *pm_cmd = para;
48 hi_s32 ret;
49
50 ret = osal_sem_down_interruptible(&g_hidev_pm_sem);
51 if (ret == 0) {
52 hidev_dbg("hidev get pm cmd %d.\n", g_hidev_pm_cmd);
53 }
54 pm_cmd->cmd = g_hidev_pm_cmd;
55 return ret;
56 }
57
hidev_free_block_mem(unsigned int cmd,hi_void * para,hi_void * private_data)58 static hi_s32 hidev_free_block_mem(unsigned int cmd, hi_void *para, hi_void *private_data)
59 {
60 struct hidev_block_mem *block_mem = para;
61 hidev_dbg("hidev_free_block_mem physaddr 0x%x, size %u.\n", block_mem->phys_addr, block_mem->size);
62 osal_blockmem_free(block_mem->phys_addr, block_mem->size);
63 return HI_SUCCESS;
64 }
65
hidev_pm_suspend(hi_void * private_data)66 static hi_s32 hidev_pm_suspend(hi_void *private_data)
67 {
68 /* userspace drv suspend called from userspace directly */
69 return HI_SUCCESS;
70 }
71
hidev_pm_resume(hi_void * private_data)72 static hi_s32 hidev_pm_resume(hi_void *private_data)
73 {
74 hi_s32 i;
75 g_hidev_pm_cmd = HIDEV_PM_RESUME;
76 hidev_dbg("hidev enter pm cmd %d.\n", g_hidev_pm_cmd);
77 osal_sem_up(&g_hidev_pm_sem);
78 return HI_SUCCESS;
79 }
80
hidev_pm_lowpower_enter(hi_void * private_data)81 static hi_s32 hidev_pm_lowpower_enter(hi_void *private_data)
82 {
83 g_hidev_pm_cmd = HIDEV_PM_LOWPOWER_ENTER;
84 hidev_dbg("hidev enter pm cmd %d.\n", g_hidev_pm_cmd);
85 osal_sem_up(&g_hidev_pm_sem);
86 return HI_SUCCESS;
87 }
88
hidev_pm_lowpower_exit(hi_void * private_data)89 static hi_s32 hidev_pm_lowpower_exit(hi_void *private_data)
90 {
91 g_hidev_pm_cmd = HIDEV_PM_LOWPOWER_EXIT;
92 hidev_dbg("hidev enter pm cmd %d.\n", g_hidev_pm_cmd);
93 osal_sem_up(&g_hidev_pm_sem);
94 return HI_SUCCESS;
95 }
96
hidev_pm_poweroff(hi_void * private_data)97 static hi_s32 hidev_pm_poweroff(hi_void *private_data)
98 {
99 g_hidev_pm_cmd = HIDEV_PM_POWEROFF;
100 hidev_dbg("hidev enter pm cmd %d.\n", g_hidev_pm_cmd);
101 osal_sem_up(&g_hidev_pm_sem);
102 return HI_SUCCESS;
103 }
104
105 static osal_pmops g_hidev_pmops = {
106 .pm_suspend = hidev_pm_suspend,
107 .pm_resume = hidev_pm_resume,
108 .pm_lowpower_enter = hidev_pm_lowpower_enter,
109 .pm_lowpower_exit = hidev_pm_lowpower_exit,
110 .pm_poweroff = hidev_pm_poweroff,
111 };
112
113 static osal_ioctl_cmd g_hidev_cmd[] = {
114 {HIDEV_GET_PM_CMD, hidev_get_pm_cmd},
115 {HIDEV_FREE_BLOCK_MEM, hidev_free_block_mem},
116 };
117
118 static osal_fileops g_hidev_fops = {
119 .open = hidev_open,
120 .release = hidev_release,
121 .cmd_list = g_hidev_cmd,
122 .cmd_cnt = sizeof(g_hidev_cmd) / sizeof(g_hidev_cmd[0]),
123 };
124
125 static osal_dev g_hidev_dev = {
126 .name = HIDEV_DEVICE_NAME,
127 .minor = MISC_DYNAMIC_MINOR,
128 .fops = &g_hidev_fops,
129 .pmops = &g_hidev_pmops,
130 };
131
hidev_init(hi_void)132 static hi_s32 hidev_init(hi_void)
133 {
134 if (osal_dev_register(&g_hidev_dev) != 0) {
135 osal_printk("hidev register %s failed.\n", g_hidev_dev.name);
136 return HI_FAILURE;
137 }
138
139 osal_sem_init(&g_hidev_pm_sem, 0);
140
141 hidev_dbg("hi_dev init ok.\n");
142 return HI_SUCCESS;
143 }
144
hidev_deinit(hi_void)145 static hi_void hidev_deinit(hi_void)
146 {
147 osal_dev_unregister(&g_hidev_dev);
148
149 osal_sem_destory(&g_hidev_pm_sem);
150
151 hidev_dbg("hi_dev deinit ok.\n");
152 }
153
hi_dev_module_init(hi_void)154 static hi_s32 hi_dev_module_init(hi_void)
155 {
156 hi_s32 ret;
157 ret = hidev_init();
158 return ret;
159 }
160
hi_dev_module_exit(hi_void)161 static hi_void hi_dev_module_exit(hi_void)
162 {
163 hidev_deinit();
164 return;
165 }
166
167 module_init(hi_dev_module_init);
168 module_exit(hi_dev_module_exit);
169