1 /* drivers/i2c/chips/a2220.c - a2220 voice processor driver
3 * Copyright (C) 2009 HTC Corporation.
5 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/err.h>
21 #include <linux/module.h>
22 #include <linux/interrupt.h>
23 #include <linux/i2c.h>
24 #include <linux/slab.h>
25 #include <linux/irq.h>
26 #include <linux/miscdevice.h>
27 #include <linux/gpio.h>
28 #include <linux/uaccess.h>
29 #include <linux/delay.h>
30 #include <linux/input.h>
31 #include <linux/workqueue.h>
32 #include <linux/freezer.h>
33 #include <linux/a2220.h>
34 #include <linux/a2220_fw.h>
35 #include <linux/kthread.h>
36 #include <linux/clk.h>
38 #include <mach/iomap.h>
42 #define PMC_CLK_OUT 0x1a8
43 #define CLK3_SRC_SEL (0x3 << 22)
44 #define CLK3_FORCE_EN (0x1 << 18)
46 #define MODULE_NAME "audience_a2220"
48 #define ENABLE_DIAG_IOCTLS (0)
49 #define WAKEUP_GPIO_NUM_HERCULES_REV01 33
50 #define WAKEUP_GPIO_NUM_CELOX_ATT_REV05 33
52 /* MAGIC NUMBERS! Fixme */
54 #define AUDIO_LD0_EN 60
55 #define AMP_SHUTDOWN_N 139
57 static struct i2c_client *this_client;
58 static struct a2220_platform_data *pdata;
59 static struct task_struct *task;
60 static int execute_cmdmsg(unsigned int);
62 static struct mutex a2220_lock;
63 static int a2220_opened;
64 static int a2220_suspended;
65 static int control_a2220_clk = 0;
66 struct clk *extern3_clk;
67 static unsigned int a2220_NS_state = A2220_NS_STATE_AUTO;
68 static int a2220_current_config = A2220_PATH_SUSPEND;
69 static int a2220_param_ID;
73 unsigned int img_size;
76 struct vp_ctxt the_vp;
78 unsigned int get_hw_rev(void)
83 static int a2220_i2c_read(char *rxData, int length)
86 struct i2c_msg msgs[] = {
88 .addr = this_client->addr,
95 rc = i2c_transfer(this_client->adapter, msgs, 1);
97 printk(KERN_ERR "%s: transfer error %d\n", __func__, rc);
103 for (i = 0; i < length; i++)
104 pr_info("%s: rx[%d] = %2x\n", __func__, i, rxData[i]);
111 static int a2220_i2c_write(char *txData, int length)
114 struct i2c_msg msg[] = {
116 .addr = this_client->addr,
123 rc = i2c_transfer(this_client->adapter, msg, 1);
125 printk(KERN_ERR "%s: transfer error %d\n", __func__, rc);
131 for (i = 0; i < length; i++)
132 pr_info("%s: tx[%d] = %2x\n", __func__, i, txData[i]);
139 static int a2220_open(struct inode *inode, struct file *file)
142 struct vp_ctxt *vp = &the_vp;
144 mutex_lock(&a2220_lock);
147 printk(KERN_ERR "%s: busy\n", __func__);
152 file->private_data = vp;
156 mutex_unlock(&a2220_lock);
160 static int a2220_release(struct inode *inode, struct file *file)
162 mutex_lock(&a2220_lock);
164 mutex_unlock(&a2220_lock);
169 #ifdef AUDIENCE_BYPASS /*(+)dragonball Multimedia mode */
170 #define A100_msg_mutimedia1 0x801C0000 /*VoiceProcessingOn, 0x0000:off */
171 #define A100_msg_mutimedia2 0x8026001F /*SelectRouting, 0x001A:(26) */
172 #define A100_msg_mutimedia3 0x800C0B03 /* ; PCM B Din delay 1bit */
173 #define A100_msg_mutimedia4 0x800D0001
174 #define A100_msg_mutimedia5 0x800C0A03 /* ; PCM A Din delay 1bit */
175 #define A100_msg_mutimedia6 0x800D0001
178 static void a2220_i2c_sw_reset(unsigned int reset_cmd)
181 unsigned char msgbuf[4];
183 msgbuf[0] = (reset_cmd >> 24) & 0xFF;
184 msgbuf[1] = (reset_cmd >> 16) & 0xFF;
185 msgbuf[2] = (reset_cmd >> 8) & 0xFF;
186 msgbuf[3] = reset_cmd & 0xFF;
188 pr_info("%s: %08x\n", __func__, reset_cmd);
190 rc = a2220_i2c_write(msgbuf, 4);
195 static ssize_t a2220_hw_reset(struct a2220img *img)
197 struct a2220img *vp = img;
200 int retry = RETRY_CNT;
201 unsigned char *index;
205 /* Reset A2220 chip */
206 if (pdata->gpio_a2220_reset)
207 gpio_set_value(pdata->gpio_a2220_reset, 0);
209 gpio_set_value(VP_RESET, 1);
211 /* Enable A2220 clock */
212 if (control_a2220_clk)
213 gpio_set_value(pdata->gpio_a2220_clk, 1);
216 /* Take out of reset */
217 if (pdata->gpio_a2220_reset)
218 gpio_set_value(pdata->gpio_a2220_reset, 1);
220 gpio_set_value(VP_RESET, 0);
222 msleep(50); /* Delay before send I2C command */
224 /* Boot Cmd to A2220 */
225 buf[0] = A2220_msg_BOOT >> 8;
226 buf[1] = A2220_msg_BOOT & 0xff;
228 rc = a2220_i2c_write(buf, 2);
230 printk(KERN_ERR "%s: set boot mode error (%d retries left)\n",
236 rc = a2220_i2c_read(buf, 1);
239 printk(KERN_ERR "%s: boot mode ack error (%d retries left)\n",
244 remaining = vp->img_size / 32;
247 for (; remaining; remaining--, index += 32) {
248 rc = a2220_i2c_write(index, 32);
253 if (rc >= 0 && vp->img_size % 32)
254 rc = a2220_i2c_write(index, vp->img_size % 32);
257 printk(KERN_ERR "%s: fw load error %d (%d retries left)\n",
258 __func__, rc, retry);
262 msleep(20); /* Delay time before issue a Sync Cmd */
264 for (i = 0; i < 10; i++)
267 rc = execute_cmdmsg(A100_msg_Sync);
269 printk(KERN_ERR "%s: sync command error %d (%d retries left)\n",
270 __func__, rc, retry);
281 #ifdef CONFIG_USA_MODEL_SGH_I717
282 static int hpt_longCmd_execute(unsigned char *i2c_cmds, int size)
287 /* unsigned int sw_reset = 0; */
291 pMsg = (unsigned char *)&msg;
293 for (i = 0; i < size; i += 4) {
294 pMsg[3] = i2c_cmds[i];
295 pMsg[2] = i2c_cmds[i + 1];
296 pMsg[1] = i2c_cmds[i + 2];
297 pMsg[0] = i2c_cmds[i + 3];
300 rc = execute_cmdmsg(msg);
301 } while ((rc < 0) && --retry);
308 static int a2220_set_boot_mode()
311 int retry = RETRY_CNT;
317 /* Reset A2220 chip */
318 gpio_set_value(VP_RESET, 1);
320 /* Enable A2220 clock */
321 if (control_a2220_clk)
322 gpio_set_value(pdata->gpio_a2220_clk, 1);
325 /* Take out of reset */
326 gpio_set_value(VP_RESET, 0);
328 msleep(150); /* Delay before send I2C command */
330 /* Boot Cmd to A2220 */
331 buf[0] = A2220_msg_BOOT >> 8;
332 buf[1] = A2220_msg_BOOT & 0xff;
333 rc = a2220_i2c_write(buf, 2);
335 printk(KERN_ERR "%s: write error (%d retries left)\n",
344 rc = a2220_i2c_read(buf, 1);
347 printk(KERN_ERR "%s: ack error (%d retries left)\n",
356 static ssize_t a2220_bootup_init(struct a2220img *pImg)
358 struct a2220img *vp = pImg;
361 int retry = RETRY_CNT;
362 unsigned char *index;
368 remaining = vp->img_size / 32;
370 pr_info("%s: starting to load image (%d passes)...\n",
371 __func__, remaining + !!(vp->img_size % 32));
373 for (; remaining; remaining--, index += 32) {
374 rc = a2220_i2c_write(index, 32);
379 if (rc >= 0 && vp->img_size % 32)
380 rc = a2220_i2c_write(index, vp->img_size % 32);
383 printk(KERN_ERR "%s: fw load error %d (%d retries left)\n",
384 __func__, rc, retry);
388 msleep(150); /* Delay time before issue a Sync Cmd */
390 rc = execute_cmdmsg(A100_msg_Sync);
392 printk(KERN_ERR "%s: sync command error %d (%d retries left)\n",
393 __func__, rc, retry);
401 rc = execute_cmdmsg(A100_msg_ReadPortA);
403 printk(KERN_ERR "%s: suspend error\n", __func__);
405 rc = execute_cmdmsg(A100_msg_PortD_C_PASS);
407 printk(KERN_ERR "%s: suspend error\n", __func__);
409 rc = execute_cmdmsg(A100_msg_PortB_A_PASS);
411 printk(KERN_ERR "%s: suspend error\n", __func__);
414 rc = execute_cmdmsg(A100_msg_Sleep);
416 printk(KERN_ERR "%s: suspend error\n", __func__);
420 if (control_a2220_clk)
421 clk_disable(extern3_clk);
427 static ssize_t chk_wakeup_a2220(void)
429 int i, rc = 0, retry = 4;
431 if (a2220_suspended == 1) {
432 /* Enable A2220 clock */
433 if (control_a2220_clk) {
434 gpio_set_value(pdata->gpio_a2220_clk, 1);
438 if (pdata->gpio_a2220_wakeup) {
440 "%s : chk_wakeup_a2220 --> get_hw_rev of Target = %d\n",
441 __func__, get_hw_rev());
442 #ifdef CONFIG_USA_MODEL_SGH_T989
443 if (get_hw_rev() >= 0x05)
444 gpio_set_value(WAKEUP_GPIO_NUM_HERCULES_REV01,
447 gpio_set_value(pdata->gpio_a2220_wakeup, 0);
448 #elif CONFIG_USA_MODEL_SGH_I727
449 qweqwewq if (get_hw_rev() >= 0x05)
450 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05,
453 gpio_set_value(pdata->gpio_a2220_wakeup, 0);
454 #elif CONFIG_USA_MODEL_SGH_I717
455 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 0);
457 gpio_set_value(pdata->gpio_a2220_wakeup, 0);
460 #ifdef CONFIG_USA_MODEL_SGH_I717
461 for (i = 0; i < 5; i++)
468 rc = execute_cmdmsg(A100_msg_Sync);
469 } while ((rc < 0) && --retry);
471 /* Audience not responding to execute_cmdmsg ,
472 * doing HW reset of the chipset */
473 if ((retry == 0) && (rc < 0)) {
475 img.buf = a2220_firmware_buf;
476 img.img_size = sizeof(a2220_firmware_buf);
477 rc = a2220_hw_reset(&img); /* Call if the Audience
478 chipset is not responding after retrying 12 times */
481 printk(MODULE_NAME "%s :: Audience HW Reset Failed\n",
484 #ifdef CONFIG_USA_MODEL_SGH_I717
485 rc = hpt_longCmd_execute(hpt_init_macro,
486 sizeof(hpt_init_macro));
488 printk(MODULE_NAME "%s: htp init error\n", __func__);
491 if (pdata->gpio_a2220_wakeup) {
492 #ifdef CONFIG_USA_MODEL_SGH_T989
493 if (get_hw_rev() >= 0x05)
494 gpio_set_value(WAKEUP_GPIO_NUM_HERCULES_REV01,
497 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
498 #elif CONFIG_USA_MODEL_SGH_I727
499 if (get_hw_rev() >= 0x05)
500 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05,
503 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
504 #elif CONFIG_USA_MODEL_SGH_I717
505 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 1);
507 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
512 printk(KERN_ERR "%s: failed (%d)\n", __func__, rc);
513 goto wakeup_sync_err;
522 /* Filter commands according to noise suppression state forced by
523 * A2220_SET_NS_STATE ioctl.
525 * For this function to operate properly, all configurations must include
526 * both A100_msg_Bypass and Mic_Config commands even if default values
527 * are selected or if Mic_Config is useless because VP is off
529 int a2220_filter_vp_cmd(int cmd, int mode)
531 int msg = (cmd >> 16) & 0xFFFF;
532 int filtered_cmd = cmd;
534 if (a2220_NS_state == A2220_NS_STATE_AUTO)
538 case A100_msg_Bypass:
539 if (a2220_NS_state == A2220_NS_STATE_OFF)
540 filtered_cmd = A2220_msg_VP_OFF;
542 filtered_cmd = A2220_msg_VP_ON;
544 case A100_msg_SetAlgorithmParmID:
545 a2220_param_ID = cmd & 0xFFFF;
547 case A100_msg_SetAlgorithmParm:
548 if (a2220_param_ID == Mic_Config) {
549 if (a2220_NS_state == A2220_NS_STATE_CT)
550 filtered_cmd = (msg << 16);
551 else if (a2220_NS_state == A2220_NS_STATE_FT)
552 filtered_cmd = (msg << 16) | 0x0002;
556 if (mode == A2220_CONFIG_VP)
561 pr_info("%s: %x filtered = %x, a2220_NS_state %d, mode %d\n", __func__,
562 cmd, filtered_cmd, a2220_NS_state, mode);
567 int a2220_set_config(char newid, int mode)
569 int i = 0, rc = 0, size = 0;
571 unsigned int sw_reset = 0;
572 unsigned char *i2c_cmds;
576 if ((a2220_suspended) && (newid == A2220_PATH_SUSPEND))
579 #if defined(CONFIG_USA_MODEL_SGH_T989) || defined(CONFIG_USA_MODEL_SGH_I727)\
580 || defined(CONFIG_USA_MODEL_SGH_I717)
581 if (a2220_current_config == newid) {
582 printk(KERN_DEBUG "already configured this path!!!\n");
587 rc = chk_wakeup_a2220();
591 sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE);
594 case A2220_PATH_INCALL_RECEIVER_NSON:
595 i2c_cmds = phonecall_receiver_nson;
596 size = sizeof(phonecall_receiver_nson);
599 case A2220_PATH_INCALL_RECEIVER_NSOFF:
600 i2c_cmds = phonecall_receiver_nsoff;
601 size = sizeof(phonecall_receiver_nsoff);
604 /* (+) ysseo 20110420 : to use a2220 bypass mode */
605 #ifdef AUDIENCE_BYPASS /*(+)dragonball Multimedia bypass mode */
606 case A2220_PATH_BYPASS_MULTIMEDIA:
607 printk(KERN_DEBUG "%s : setting A2220_PATH_BYPASS_MULTIMEDIA\n",
609 i2c_cmds = bypass_multimedia;
610 size = sizeof(bypass_multimedia);
613 case A2220_PATH_INCALL_HEADSET:
614 i2c_cmds = phonecall_headset;
615 size = sizeof(phonecall_headset);
617 case A2220_PATH_INCALL_SPEAKER:
618 i2c_cmds = phonecall_speaker;
619 size = sizeof(phonecall_speaker);
621 case A2220_PATH_INCALL_BT:
622 i2c_cmds = phonecall_bt;
623 size = sizeof(phonecall_bt);
625 case A2220_PATH_INCALL_TTY:
626 i2c_cmds = phonecall_tty;
627 size = sizeof(phonecall_tty);
629 case A2220_PATH_VR_NO_NS_RECEIVER:
630 i2c_cmds = vr_no_ns_receiver;
631 size = sizeof(vr_no_ns_receiver);
633 case A2220_PATH_VR_NO_NS_HEADSET:
634 i2c_cmds = vr_no_ns_headset;
635 size = sizeof(vr_no_ns_headset);
637 case A2220_PATH_VR_NO_NS_SPEAKER:
638 i2c_cmds = vr_no_ns_speaker;
639 size = sizeof(vr_no_ns_speaker);
641 case A2220_PATH_VR_NO_NS_BT:
642 i2c_cmds = vr_no_ns_bt;
643 size = sizeof(vr_no_ns_bt);
645 case A2220_PATH_VR_NS_RECEIVER:
646 i2c_cmds = vr_ns_receiver;
647 size = sizeof(vr_ns_receiver);
649 case A2220_PATH_VR_NS_HEADSET:
650 i2c_cmds = vr_ns_headset;
651 size = sizeof(vr_ns_headset);
653 case A2220_PATH_VR_NS_SPEAKER:
654 i2c_cmds = vr_ns_speaker;
655 size = sizeof(vr_ns_speaker);
657 case A2220_PATH_VR_NS_BT:
659 size = sizeof(vr_ns_bt);
661 case A2220_PATH_RECORD_RECEIVER:
662 i2c_cmds = INT_MIC_recording_receiver;
663 size = sizeof(INT_MIC_recording_receiver);
665 case A2220_PATH_RECORD_HEADSET:
666 i2c_cmds = EXT_MIC_recording;
667 size = sizeof(EXT_MIC_recording);
669 case A2220_PATH_RECORD_SPEAKER:
670 i2c_cmds = INT_MIC_recording_speaker;
671 size = sizeof(INT_MIC_recording_speaker);
673 case A2220_PATH_RECORD_BT:
674 i2c_cmds = phonecall_bt;
675 size = sizeof(phonecall_bt);
677 case A2220_PATH_SUSPEND:
678 i2c_cmds = (unsigned char *)suspend_mode;
679 size = sizeof(suspend_mode);
681 case A2220_PATH_CAMCORDER:
682 i2c_cmds = BACK_MIC_recording;
683 size = sizeof(BACK_MIC_recording);
686 printk(KERN_ERR "%s: invalid cmd %d\n", __func__, newid);
692 a2220_current_config = newid;
695 pr_info("%s: change to mode %d\n", __func__, newid);
696 pr_info("%s: block write start (size = %d)\n", __func__, size);
697 for (i = 1; i <= size; i++) {
698 pr_info("%x ", *(i2c_cmds + i - 1));
706 pMsg = (unsigned char *)&msg;
708 for (i = 0; i < size; i += 4) {
709 pMsg[3] = i2c_cmds[i];
710 pMsg[2] = i2c_cmds[i + 1];
711 pMsg[1] = i2c_cmds[i + 2];
712 pMsg[0] = i2c_cmds[i + 3];
715 rc = execute_cmdmsg(msg);
716 } while ((rc < 0) && --retry);
718 /* Audience not responding to execute_cmdmsg ,
719 * doing HW reset of the chipset */
720 if ((retry == 0) && (rc < 0)) {
722 img.buf = a2220_firmware_buf;
723 img.img_size = sizeof(a2220_firmware_buf);
724 rc = a2220_hw_reset(&img); /* Call if the Audience
725 chipset is not responding after retrying 12 times */
728 "%s :: Audience HW Reset Failed\n",
737 rc = a2220_i2c_write(i2c_cmds, size);
739 printk(KERN_ERR "A2220 CMD block write error!\n");
740 a2220_i2c_sw_reset(sw_reset);
743 pr_info("%s: block write end\n", __func__);
745 /* Don't need to get Ack after sending out a suspend command */
746 if (*i2c_cmds == 0x80 && *(i2c_cmds + 1) == 0x10
747 && *(i2c_cmds + 2) == 0x00 && *(i2c_cmds + 3) == 0x01) {
749 /* Disable A2220 clock */
751 if (control_a2220_clk)
752 gpio_set_value(pdata->gpio_a2220_clk, 0);
756 memset(ack_buf, 0, sizeof(ack_buf));
758 pr_info("%s: CMD ACK block read start\n", __func__);
759 rc = a2220_i2c_read(ack_buf, size);
761 printk(KERN_ERR "%s: CMD ACK block read error\n", __func__);
762 a2220_i2c_sw_reset(sw_reset);
765 pr_info("%s: CMD ACK block read end\n", __func__);
767 for (i = 1; i <= size; i++) {
768 pr_info("%x ", ack_buf[i - 1]);
774 number_of_cmd_sets = size / 4;
776 if (*index == 0x00) {
777 rd_retry_cnt = POLLING_RETRY_CNT;
779 if (rd_retry_cnt--) {
780 memset(rdbuf, 0, sizeof(rdbuf));
781 rc = a2220_i2c_read(rdbuf, 4);
785 for (i = 0; i < sizeof(rdbuf); i++)
786 pr_info("0x%x\n", rdbuf[i]);
787 pr_info("-----------------\n");
789 if (rdbuf[0] == 0x00) {
794 printk(KERN_ERR "%s: CMD ACK Not Ready\n",
798 } else if (*index == 0xff) { /* illegal cmd */
800 } else if (*index == 0x80) {
803 } while (--number_of_cmd_sets);
811 int execute_cmdmsg(unsigned int msg)
814 int retries, pass = 0;
815 unsigned char msgbuf[4];
816 unsigned char chkbuf[4];
817 unsigned int sw_reset = 0;
819 sw_reset = ((A100_msg_Reset << 16) | RESET_IMMEDIATE);
821 msgbuf[0] = (msg >> 24) & 0xFF;
822 msgbuf[1] = (msg >> 16) & 0xFF;
823 msgbuf[2] = (msg >> 8) & 0xFF;
824 msgbuf[3] = msg & 0xFF;
827 printk(KERN_DEBUG "%s : execute_cmdmsg :: %x %x %x %x\n",
828 __func__, msgbuf[0], msgbuf[1], msgbuf[2], msgbuf[3]);
830 memcpy(chkbuf, msgbuf, 4);
832 rc = a2220_i2c_write(msgbuf, 4);
834 a2220_i2c_sw_reset(sw_reset);
836 if (msg == A100_msg_Sleep) {
838 "%s : execute_cmdmsg ...go to suspend first\n",
840 a2220_suspended = 1;/*(+)dragonball test for audience */
847 /* We don't need to get Ack after sending out a suspend command */
848 if (msg == A100_msg_Sleep) {
849 printk(MODULE_NAME "%s : ...go to suspend first\n", __func__);
850 a2220_suspended = 1; /*(+)dragonball test for audience */
855 retries = POLLING_RETRY_CNT;
858 memset(msgbuf, 0, sizeof(msgbuf));
859 rc = a2220_i2c_read(msgbuf, 4);
861 printk(KERN_ERR "%s: ...........ack-read error %d (%d retries)\n",
862 __func__, rc, retries);
866 if (msgbuf[0] == 0x80 && msgbuf[1] == chkbuf[1]) {
869 } else if (msgbuf[0] == 0xff && msgbuf[1] == 0xff) {
870 printk(KERN_ERR "%s: illegal cmd %08x\n",
874 } else if (msgbuf[0] == 0x00 && msgbuf[1] == 0x00) {
875 pr_info("%s: not ready (%d retries)\n", __func__,
879 pr_info("%s: cmd/ack mismatch: (%d retries left)\n",
882 pr_info("%s: msgbuf[0] = %x\n", __func__, msgbuf[0]);
883 pr_info("%s: msgbuf[1] = %x\n", __func__, msgbuf[1]);
884 pr_info("%s: msgbuf[2] = %x\n", __func__, msgbuf[2]);
885 pr_info("%s: msgbuf[3] = %x\n", __func__, msgbuf[3]);
889 msleep(20); /* use polling */
893 printk(KERN_ERR "%s: failed execute cmd %08x (%d)\n",
895 a2220_i2c_sw_reset(sw_reset);
901 #if ENABLE_DIAG_IOCTLS
902 static int a2220_set_mic_state(char miccase)
905 unsigned int cmd_msg = 0;
908 case 1: /* Mic-1 ON / Mic-2 OFF */
909 cmd_msg = 0x80260007;
911 case 2: /* Mic-1 OFF / Mic-2 ON */
912 cmd_msg = 0x80260015;
914 case 3: /* both ON */
915 cmd_msg = 0x80260001;
917 case 4: /* both OFF */
918 cmd_msg = 0x80260006;
921 pr_info("%s: invalid input %d\n", __func__, miccase);
925 rc = execute_cmdmsg(cmd_msg);
929 static int exe_cmd_in_file(unsigned char *incmd)
933 unsigned int cmd_msg = 0;
934 unsigned char tmp = 0;
936 for (i = 0; i < 4; i++) {
938 cmd_msg |= (unsigned int)tmp;
940 cmd_msg = cmd_msg << 8;
942 rc = execute_cmdmsg(cmd_msg);
944 printk(KERN_ERR "%s: cmd %08x error %d\n",
945 __func__, cmd_msg, rc);
948 #endif /* ENABLE_DIAG_IOCTLS */
950 /* Thread does the init process of Audience Chip */
951 static int a2220_init_thread(void *data)
955 img.buf = a2220_firmware_buf;
956 img.img_size = sizeof(a2220_firmware_buf);
957 rc = a2220_bootup_init(&img);
962 a2220_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
965 void __user *argp = (void __user *)arg;
968 #if ENABLE_DIAG_IOCTLS
973 unsigned int ns_state;
976 case A2220_BOOTUP_INIT:
977 img.buf = a2220_firmware_buf;
978 img.img_size = sizeof(a2220_firmware_buf);
979 printk(MODULE_NAME "%s : a2220_firmware_buf = %d\n", __func__,
980 sizeof(a2220_firmware_buf));
982 kthread_run(a2220_init_thread, NULL, "a2220_init_thread");
988 case A2220_SET_CONFIG:
989 rc = a2220_set_config(arg, A2220_CONFIG_FULL);
991 printk(KERN_ERR "%s: A2220_SET_CONFIG (%lu) error %d!\n",
994 case A2220_SET_NS_STATE:
995 if (copy_from_user(&ns_state, argp, sizeof(ns_state)))
997 pr_info("%s: set noise suppression %d\n", __func__, ns_state);
998 if (ns_state < 0 || ns_state >= A2220_NS_NUM_STATES)
1000 a2220_NS_state = ns_state;
1001 if (!a2220_suspended)
1002 a2220_set_config(a2220_current_config, A2220_CONFIG_VP);
1004 #if ENABLE_DIAG_IOCTLS
1005 case A2220_SET_MIC_ONOFF:
1006 rc = chk_wakeup_a2220();
1009 if (copy_from_user(&mic_cases, argp, sizeof(mic_cases)))
1011 rc = a2220_set_mic_state(mic_cases);
1013 printk(KERN_ERR "%s: A2220_SET_MIC_ONOFF %d error %d!\n",
1014 __func__, mic_cases, rc);
1016 case A2220_SET_MICSEL_ONOFF:
1017 rc = chk_wakeup_a2220();
1020 if (copy_from_user(&mic_sel, argp, sizeof(mic_sel)))
1024 case A2220_READ_DATA:
1025 rc = chk_wakeup_a2220();
1028 rc = a2220_i2c_read(msg, 4);
1029 if (copy_to_user(argp, &msg, 4))
1032 case A2220_WRITE_MSG:
1033 rc = chk_wakeup_a2220();
1036 if (copy_from_user(msg, argp, sizeof(msg)))
1038 rc = a2220_i2c_write(msg, 4);
1040 case A2220_SYNC_CMD:
1041 rc = chk_wakeup_a2220();
1048 rc = a2220_i2c_write(msg, 4);
1050 case A2220_SET_CMD_FILE:
1051 rc = chk_wakeup_a2220();
1054 if (copy_from_user(msg, argp, sizeof(msg)))
1056 rc = exe_cmd_in_file(msg);
1058 #endif /* ENABLE_DIAG_IOCTLS */
1060 printk(KERN_ERR "%s: invalid command %d\n",
1061 __func__, _IOC_NR(cmd));
1069 int a2220_ioctl2(unsigned int cmd, unsigned long arg)
1071 a2220_ioctl(NULL, NULL, cmd, arg);
1074 EXPORT_SYMBOL(a2220_ioctl2);
1076 int a2220_port_path_change(unsigned int msg)
1079 case A100_msg_PortC_D_PASS:
1080 case A100_msg_PortD_C_PASS:
1081 case A100_msg_PortB_A_PASS:
1082 case A100_msg_PortA_B_PASS:
1083 case A100_msg_PortC_A_PASS:
1084 case A100_msg_PortA_C_PASS:
1087 printk(KERN_ERR "Not support [0x%X] for port change\n", msg);
1090 /* Default set to PORTD -> PORTC and
1091 PORTB -> PORTA in pass through) */
1092 /* return execute_cmdmsg(msg); */
1095 EXPORT_SYMBOL(a2220_port_path_change);
1097 static const struct file_operations a2220_fops = {
1098 .owner = THIS_MODULE,
1100 .release = a2220_release,
1101 /* .ioctl = a2220_ioctl, */
1104 static struct miscdevice a2220_device = {
1105 .minor = MISC_DYNAMIC_MINOR,
1106 .name = "audience_a2220",
1107 .fops = &a2220_fops,
1110 static int a2220_probe(struct i2c_client *client,
1111 const struct i2c_device_id *id)
1115 void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
1117 extern3_clk = clk_get_sys("extern3", NULL);
1118 if (IS_ERR(extern3_clk)) {
1119 printk(KERN_ERR "%s: Can't retrieve extern3\n", __func__);
1120 goto err_clk_get_failed;
1123 ret = clk_enable(extern3_clk);
1125 printk(KERN_ERR "Can't enable clk extern3");
1126 goto err_clk_enable_failed;
1129 control_a2220_clk = 1;
1130 /* disable master enable in PMC */
1131 val = readl(pmc_base + PMC_CLK_OUT);
1132 val |= CLK3_SRC_SEL;
1134 writel(val, pmc_base + PMC_CLK_OUT);
1136 val = readl(pmc_base + PMC_CLK_OUT);
1137 val |= CLK3_FORCE_EN;
1138 writel(val, pmc_base + PMC_CLK_OUT);
1140 pdata = client->dev.platform_data;
1142 if (pdata == NULL) {
1143 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
1144 printk(KERN_ERR "%s : a2220_probe - pdata NULL so allocating ...\n",
1146 if (pdata == NULL) {
1148 printk(KERN_ERR "%s: platform data is NULL\n",
1151 goto err_alloc_data_failed;
1155 #ifdef CONFIG_USA_MODEL_SGH_T989
1156 if (get_hw_rev() >= 0x05)
1157 gpio_tlmm_config(GPIO_CFG(33, 0, GPIO_CFG_OUTPUT,
1158 GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
1159 GPIO_CFG_ENABLE);/* 2MIC_PWDN */
1161 gpio_tlmm_config(GPIO_CFG(34, 0, GPIO_CFG_OUTPUT,
1162 GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
1163 GPIO_CFG_ENABLE);/* 2MIC_PWDN */
1164 #elif CONFIG_USA_MODEL_SGH_I727
1165 if (get_hw_rev() >= 0x05) {
1166 printk(KERN_DEBUG " %s : GPIO 33\n", __func__);
1167 gpio_tlmm_config(GPIO_CFG(33, 0, GPIO_CFG_OUTPUT,
1168 GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
1169 GPIO_CFG_ENABLE);/* 2MIC_PWDN */
1171 printk(KERN_DEBUG "%s : get_hw_rev() == %d\n",
1172 __func__, get_hw_rev());
1174 gpio_tlmm_config(GPIO_CFG(34, 0, GPIO_CFG_OUTPUT,
1175 GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
1176 GPIO_CFG_ENABLE);/* 2MIC_PWDN */
1178 #elif CONFIG_USA_MODEL_SGH_I717
1181 gpio_tlmm_config(GPIO_CFG(34, 0, GPIO_CFG_OUTPUT,
1182 GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
1183 GPIO_CFG_ENABLE); /* 2MIC_PWDN */
1186 #if !defined(CONFIG_USA_MODEL_SGH_I727) && !defined(CONFIG_USA_MODEL_SGH_T989)\
1187 && !defined(CONFIG_USA_MODEL_SGH_I717) /*qup_a2220 */
1188 gpio_tlmm_config(GPIO_CFG(35, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
1189 GPIO_CFG_2MA), GPIO_CFG_ENABLE);/* 2MIC_SDA_1.8V */
1190 gpio_tlmm_config(GPIO_CFG(36, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
1191 GPIO_CFG_2MA), GPIO_CFG_ENABLE);/* 2MIC_SCL_1.8V */
1195 gpio_set_value(VP_RESET, 1);
1196 gpio_set_value(AUDIO_LD0_EN, 0);
1198 this_client = client;
1200 gpio_set_value(VP_RESET, 0);
1202 if (pdata->gpio_a2220_clk) {
1203 rc = gpio_request(pdata->gpio_a2220_clk, "a2220");
1205 control_a2220_clk = 0;
1206 goto chk_gpio_micsel;
1208 control_a2220_clk = 1;
1210 rc = gpio_direction_output(pdata->gpio_a2220_clk, 1);
1212 printk(KERN_ERR "%s: request clk gpio direction failed\n",
1214 goto err_free_gpio_clk;
1218 if (pdata->gpio_a2220_micsel) {
1219 rc = gpio_request(pdata->gpio_a2220_micsel, "a2220");
1221 printk(KERN_ERR "%s: gpio request mic_sel pin failed\n",
1223 goto err_free_gpio_micsel;
1226 rc = gpio_direction_output(pdata->gpio_a2220_micsel, 1);
1228 printk(KERN_ERR "%s: request mic_sel gpio direction failed\n",
1230 goto err_free_gpio_micsel;
1234 if (pdata->gpio_a2220_wakeup) {
1235 #ifdef CONFIG_USA_MODEL_SGH_T989
1236 if (get_hw_rev() >= 0x05)
1237 rc = gpio_request(WAKEUP_GPIO_NUM_HERCULES_REV01,
1240 rc = gpio_request(pdata->gpio_a2220_wakeup, "a2220");
1241 #elif CONFIG_USA_MODEL_SGH_I727
1242 if (get_hw_rev() >= 0x05)
1243 rc = gpio_request(WAKEUP_GPIO_NUM_CELOX_ATT_REV05,
1246 rc = gpio_request(pdata->gpio_a2220_wakeup, "a2220");
1247 #elif CONFIG_USA_MODEL_SGH_I717
1248 rc = gpio_request(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, "a2220");
1250 rc = gpio_request(pdata->gpio_a2220_wakeup, "a2220");
1253 printk(KERN_ERR "%s: gpio request wakeup pin failed\n",
1257 #ifdef CONFIG_USA_MODEL_SGH_T989
1258 if (get_hw_rev() >= 0x05)
1259 rc = gpio_direction_output
1260 (WAKEUP_GPIO_NUM_HERCULES_REV01, 1);
1262 rc = gpio_direction_output(pdata->gpio_a2220_wakeup, 1);
1263 #elif CONFIG_USA_MODEL_SGH_I727
1264 if (get_hw_rev() >= 0x05)
1265 rc = gpio_direction_output
1266 (WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 1);
1268 rc = gpio_direction_output(pdata->gpio_a2220_wakeup, 1);
1269 #elif CONFIG_USA_MODEL_SGH_I717
1270 rc = gpio_direction_output(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 1);
1272 rc = gpio_direction_output(pdata->gpio_a2220_wakeup, 1);
1277 printk(KERN_ERR "%s: request wakeup gpio direction failed\n",
1283 if (pdata->gpio_a2220_reset) {
1284 rc = gpio_request(pdata->gpio_a2220_reset, "a2220");
1286 printk(KERN_ERR "%s: gpio request reset pin failed\n",
1291 rc = gpio_direction_output(pdata->gpio_a2220_reset, 1);
1293 printk(KERN_ERR "%s: request reset gpio direction failed\n",
1295 goto err_free_gpio_all;
1299 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
1300 printk(KERN_ERR "%s: i2c check functionality error\n",
1303 goto err_free_gpio_all;
1306 if (control_a2220_clk)
1307 gpio_set_value(pdata->gpio_a2220_clk, 1);
1308 if (pdata->gpio_a2220_micsel)
1309 gpio_set_value(pdata->gpio_a2220_micsel, 0);
1311 if (pdata->gpio_a2220_wakeup) {
1312 #ifdef CONFIG_USA_MODEL_SGH_T989
1313 if (get_hw_rev() >= 0x05)
1314 gpio_set_value(WAKEUP_GPIO_NUM_HERCULES_REV01, 1);
1316 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
1317 #elif CONFIG_USA_MODEL_SGH_I727
1318 if (get_hw_rev() >= 0x05)
1319 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 1);
1321 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
1322 #elif CONFIG_USA_MODEL_SGH_I717
1323 gpio_set_value(WAKEUP_GPIO_NUM_CELOX_ATT_REV05, 1);
1325 gpio_set_value(pdata->gpio_a2220_wakeup, 1);
1329 if (pdata->gpio_a2220_reset)
1330 gpio_set_value(pdata->gpio_a2220_reset, 1);
1332 if (pdata->gpio_a2220_audience_chip_sel)
1333 gpio_set_value(pdata->gpio_a2220_audience_chip_sel, 1);
1335 rc = misc_register(&a2220_device);
1337 printk(KERN_ERR "%s: a2220_device register failed\n", __func__);
1338 goto err_free_gpio_all;
1342 rc = a2220_set_boot_mode();
1344 printk(KERN_ERR "%s: failed %d\n", __func__, rc);
1345 goto err_free_gpio_all;
1348 /* A2220 firmware download start .. */
1349 a2220_ioctl2(A2220_BOOTUP_INIT, 0);
1354 if (pdata->gpio_a2220_reset)
1355 gpio_free(pdata->gpio_a2220_reset);
1357 if (pdata->gpio_a2220_wakeup) {
1358 #ifdef CONFIG_USA_MODEL_SGH_T989
1359 if (get_hw_rev() >= 0x05)
1360 gpio_free(WAKEUP_GPIO_NUM_HERCULES_REV01);
1362 gpio_free(pdata->gpio_a2220_wakeup);
1363 #elif CONFIG_USA_MODEL_SGH_I727
1364 if (get_hw_rev() >= 0x05)
1365 gpio_free(WAKEUP_GPIO_NUM_CELOX_ATT_REV05);
1367 gpio_free(pdata->gpio_a2220_wakeup);
1368 #elif CONFIG_USA_MODEL_SGH_I717
1369 gpio_free(WAKEUP_GPIO_NUM_CELOX_ATT_REV05);
1371 gpio_free(pdata->gpio_a2220_wakeup);
1374 err_free_gpio_micsel:
1375 if (pdata->gpio_a2220_micsel)
1376 gpio_free(pdata->gpio_a2220_micsel);
1378 if (pdata->gpio_a2220_clk)
1379 gpio_free(pdata->gpio_a2220_clk);
1380 err_alloc_data_failed:
1381 clk_disable(extern3_clk);
1382 err_clk_enable_failed:
1383 clk_put(extern3_clk);
1389 static int a2220_remove(struct i2c_client *client)
1391 struct a2220_platform_data *p1026data = i2c_get_clientdata(client);
1397 static int a2220_suspend(struct i2c_client *client, pm_message_t mesg)
1402 static int a2220_resume(struct i2c_client *client)
1407 static const struct i2c_device_id a2220_id[] = {
1408 {"audience_a2220", 0},
1412 MODULE_DEVICE_TABLE(i2c, a2220_id);
1414 static struct i2c_driver a2220_driver = {
1415 .probe = a2220_probe,
1416 .remove = a2220_remove,
1417 .suspend = a2220_suspend,
1418 .resume = a2220_resume,
1419 .id_table = a2220_id,
1421 .name = "audience_a2220",
1426 static int __init a2220_init(void)
1428 #ifdef CONFIG_BATTERY_SEC
1429 if (is_lpcharging_state()) {
1430 pr_info("%s : LPM Charging Mode! return 0\n", __func__);
1434 mutex_init(&a2220_lock);
1436 return i2c_add_driver(&a2220_driver);
1439 static void __exit a2220_exit(void)
1441 i2c_del_driver(&a2220_driver);
1444 module_init(a2220_init);
1445 module_exit(a2220_exit);
1447 MODULE_DESCRIPTION("A2220 voice processor driver");
1448 MODULE_LICENSE("GPL");