add es8323 codec for pcm modem
[firefly-linux-kernel-4.4.55.git] / drivers / misc / modem_sound.c
1 #include <linux/input.h>\r
2 #include <linux/module.h>\r
3 #include <linux/init.h>\r
4 #include <linux/interrupt.h>\r
5 #include <linux/kernel.h>\r
6 #include <linux/fcntl.h>\r
7 #include <linux/delay.h>\r
8 #include <linux/device.h>\r
9 #include <linux/miscdevice.h>\r
10 #include <asm/types.h>\r
11 #include <mach/gpio.h>\r
12 #include <mach/iomux.h>\r
13 #include <linux/platform_device.h>\r
14 #include <asm/uaccess.h>\r
15 #include <linux/wait.h>\r
16 #include "modem_sound.h"\r
17 #if 0\r
18 #define DBG(x...)       printk(KERN_INFO x)\r
19 #else\r
20 #define DBG(x...)\r
21 #endif\r
22 #define ENABLE             1\r
23 #define DISABLE            0\r
24 \r
25 static struct modem_sound_data *modem_sound;\r
26 int (*set_codec_for_pcm_modem)(int cmd) = NULL; /* Set the codec used only for PCM modem */\r
27 void (*set_codec_spk)(int on) = NULL;\r
28 #if defined(CONFIG_SND_RK_SOC_RK2928)|| defined(CONFIG_SND_RK29_SOC_RK610)\r
29 extern void call_set_spk(int on);\r
30 #endif\r
31 #ifdef CONFIG_SND_SOC_ES8323_PCM\r
32 extern int set_es8323(int cmd);\r
33 #endif\r
34 \r
35 #define HP_MIC 0\r
36 #define MAIN_MIC 1\r
37 #if defined(CONFIG_MODEM_MIC_SWITCH)\r
38 extern void Modem_Mic_switch(int value);\r
39 extern void Modem_Mic_release(void);\r
40 void Modem_Sound_Mic_switch(int value)\r
41 {\r
42         Modem_Mic_switch(value);\r
43 }\r
44 void Modem_Sound_Mic_release()\r
45 {\r
46         Modem_Mic_release();\r
47 }\r
48 #else\r
49 void Modem_Sound_Mic_switch(int value)\r
50 {\r
51 }\r
52 void Modem_Sound_Mic_release()\r
53 {\r
54 }\r
55 #endif\r
56 \r
57 int modem_sound_spkctl(int status)\r
58 {\r
59         if(status == ENABLE)\r
60                 gpio_direction_output(modem_sound->spkctl_io,GPIO_HIGH);//modem_sound->spkctl_io? GPIO_HIGH:GPIO_LOW);\r
61         else \r
62                 gpio_direction_output(modem_sound->spkctl_io,GPIO_LOW); //modem_sound->spkctl_io? GPIO_LOW:GPIO_HIGH);\r
63                         \r
64         return 0;\r
65 }\r
66 \r
67 static void modem_sound_delay_power_downup(struct work_struct *work)\r
68 {\r
69         struct modem_sound_data *pdata = container_of(work, struct modem_sound_data, work);\r
70         if (pdata == NULL) {\r
71                 printk("%s: pdata = NULL\n", __func__);\r
72                 return;\r
73         }\r
74 \r
75         down(&pdata->power_sem);\r
76         up(&pdata->power_sem);\r
77 }\r
78 \r
79 static int modem_sound_open(struct inode *inode, struct file *filp)\r
80 {\r
81     DBG("modem_sound_open\n");\r
82 \r
83         return 0;\r
84 }\r
85 \r
86 static ssize_t modem_sound_read(struct file *filp, char __user *ptr, size_t size, loff_t *pos)\r
87 {\r
88         if (ptr == NULL)\r
89                 printk("%s: user space address is NULL\n", __func__);\r
90         return sizeof(int);\r
91 }\r
92 \r
93 static long modem_sound_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
94 {\r
95         int ret = 0, codec_pcm_cmd = -1, codec_cmd = -1, modem_spk_enable = -1;\r
96         struct modem_sound_data *pdata = modem_sound;\r
97 \r
98         DBG("modem_sound_ioctl: cmd = %d arg = %ld\n",cmd, arg);\r
99 \r
100         ret = down_interruptible(&pdata->power_sem);\r
101         if (ret < 0) {\r
102                 printk("%s: down power_sem error ret = %d\n", __func__, ret);\r
103                 return ret;\r
104         }\r
105 \r
106         switch (cmd){\r
107                 case IOCTL_MODEM_EAR_PHOEN:\r
108                         DBG("modem_sound_ioctl: MODEM_EAR_PHONE\n");\r
109                         Modem_Sound_Mic_switch(MAIN_MIC);\r
110                         codec_cmd = 3;\r
111                         codec_pcm_cmd = RCV;\r
112                         modem_spk_enable = DISABLE;\r
113                         break;\r
114                 case IOCTL_MODEM_SPK_PHONE:\r
115                         DBG("modem_sound_ioctl: MODEM_SPK_PHONE\n");\r
116                         Modem_Sound_Mic_switch(MAIN_MIC);\r
117                         codec_cmd = 1;\r
118                         codec_pcm_cmd = SPK_PATH;\r
119                         modem_spk_enable = ENABLE;\r
120                         break;\r
121                 case IOCTL_MODEM_HP_WITHMIC_PHONE:\r
122                         DBG("modem_sound_ioctl: MODEM_HP_WITHMIC_PHONE\n");\r
123                         Modem_Sound_Mic_switch(HP_MIC);\r
124                         codec_cmd = 2;\r
125                         codec_pcm_cmd = HP_PATH;\r
126                         modem_spk_enable = DISABLE;\r
127                         break;\r
128                 case IOCTL_MODEM_BT_PHONE:\r
129                         codec_cmd = 3;\r
130                         codec_pcm_cmd = BT;\r
131                         modem_spk_enable = DISABLE;\r
132                         DBG("modem_sound_ioctl: MODEM_BT_PHONE\n");\r
133                         break;\r
134                 case IOCTL_MODEM_STOP_PHONE:\r
135                         DBG("modem_sound_ioctl: MODEM_STOP_PHONE\n");\r
136                         Modem_Sound_Mic_release();\r
137                         codec_cmd = 0;\r
138                         codec_pcm_cmd = OFF;\r
139                         modem_spk_enable = ENABLE;\r
140                         break;\r
141                 case IOCTL_MODEM_HP_NOMIC_PHONE:\r
142                         DBG("modem_sound_ioctl: MODEM_HP_NOMIC_PHONE\n");\r
143                         Modem_Sound_Mic_switch(MAIN_MIC);\r
144                         codec_cmd = 2;\r
145                         codec_pcm_cmd = HP_NO_MIC;\r
146                         modem_spk_enable = DISABLE;\r
147                         break;\r
148                 default:\r
149                         printk("unknown ioctl cmd!\n");\r
150                         ret = -EINVAL;\r
151                         break;\r
152         }\r
153 \r
154         if (set_codec_spk == NULL || set_codec_for_pcm_modem == NULL)\r
155                 printk("modem_sound_ioctl(), %s %s\n",\r
156                         set_codec_for_pcm_modem ? "" : "set_codec_for_pcm_modem is NULL",\r
157                         set_codec_spk ? "" : "set_codec_spk is NULL");\r
158 \r
159         if (ret >= 0) {\r
160                 // close codec firstly for pop noise\r
161                 if (codec_cmd == 0 && set_codec_spk)\r
162                         set_codec_spk(codec_cmd);\r
163 \r
164                 if (set_codec_for_pcm_modem)\r
165                         set_codec_for_pcm_modem(codec_pcm_cmd);\r
166 \r
167                 modem_sound_spkctl(modem_spk_enable);\r
168 \r
169                 // open codec lastly for pop noise\r
170                 if (codec_cmd != 0 && set_codec_spk)\r
171                         set_codec_spk(codec_cmd);\r
172         }\r
173 \r
174         up(&pdata->power_sem);\r
175 \r
176         return ret;\r
177 }\r
178 \r
179 static int modem_sound_release(struct inode *inode, struct file *filp)\r
180 {\r
181     DBG("modem_sound_release\n");\r
182     \r
183         return 0;\r
184 }\r
185 \r
186 static struct file_operations modem_sound_fops = {\r
187         .owner   = THIS_MODULE,\r
188         .open    = modem_sound_open,\r
189         .read    = modem_sound_read,\r
190         .unlocked_ioctl   = modem_sound_ioctl,\r
191         .release = modem_sound_release,\r
192 };\r
193 \r
194 static struct miscdevice modem_sound_dev = \r
195 {\r
196     .minor = MISC_DYNAMIC_MINOR,\r
197     .name = "modem_sound",\r
198     .fops = &modem_sound_fops,\r
199 };\r
200 \r
201 static int modem_sound_probe(struct platform_device *pdev)\r
202 {\r
203         int ret = 0;\r
204         struct modem_sound_data *pdata = pdev->dev.platform_data;\r
205         if(!pdata)\r
206                 return -1;\r
207 \r
208         ret = misc_register(&modem_sound_dev);\r
209         if (ret < 0){\r
210                 printk("modem register err!\n");\r
211                 return ret;\r
212         }\r
213         \r
214         sema_init(&pdata->power_sem,1);\r
215         pdata->wq = create_freezable_workqueue("modem_sound");\r
216         INIT_WORK(&pdata->work, modem_sound_delay_power_downup);\r
217         modem_sound = pdata;\r
218         printk("%s:modem sound initialized\n",__FUNCTION__);\r
219 \r
220 #if defined(CONFIG_SND_RK_SOC_RK2928)|| defined(CONFIG_SND_RK29_SOC_RK610)\r
221         set_codec_spk = call_set_spk;\r
222 #endif\r
223 #ifdef CONFIG_SND_SOC_ES8323_PCM\r
224         set_codec_for_pcm_modem = set_es8323;\r
225 #endif\r
226 \r
227         return ret;\r
228 }\r
229 \r
230 static int modem_sound_suspend(struct platform_device *pdev,  pm_message_t state)\r
231 {\r
232         struct modem_sound_data *pdata = pdev->dev.platform_data;\r
233 \r
234         if(!pdata) {\r
235                 printk("%s: pdata = NULL ...... \n", __func__);\r
236                 return -1;\r
237         }\r
238         printk("%s\n",__FUNCTION__);\r
239         return 0;       \r
240 }\r
241 \r
242 static int modem_sound_resume(struct platform_device *pdev)\r
243 {\r
244         struct modem_sound_data *pdata = pdev->dev.platform_data;\r
245 \r
246         if(!pdata) {\r
247                 printk("%s: pdata = NULL ...... \n", __func__);\r
248                 return -1;\r
249         }\r
250         printk("%s\n",__FUNCTION__);\r
251         return 0;\r
252 }\r
253 \r
254 static int modem_sound_remove(struct platform_device *pdev)\r
255 {\r
256         struct modem_sound_data *pdata = pdev->dev.platform_data;\r
257         if(!pdata)\r
258                 return -1;\r
259 \r
260         misc_deregister(&modem_sound_dev);\r
261 \r
262         return 0;\r
263 }\r
264 \r
265 static struct platform_driver modem_sound_driver = {\r
266         .probe  = modem_sound_probe,\r
267         .remove = modem_sound_remove,\r
268         .suspend        = modem_sound_suspend,\r
269         .resume         = modem_sound_resume,\r
270         .driver = {\r
271                 .name   = "modem_sound",\r
272                 .owner  = THIS_MODULE,\r
273         },\r
274 };\r
275 \r
276 static int __init modem_sound_init(void)\r
277 {\r
278         return platform_driver_register(&modem_sound_driver);\r
279 }\r
280 \r
281 static void __exit modem_sound_exit(void)\r
282 {\r
283         platform_driver_unregister(&modem_sound_driver);\r
284 }\r
285 \r
286 module_init(modem_sound_init);\r
287 module_exit(modem_sound_exit);\r
288 MODULE_DESCRIPTION ("modem sound driver");\r
289 MODULE_LICENSE("GPL");\r
290 \r