int mv_switch_port_based_vlan_set(unsigned int ports_mask, int set_cpu_port) { unsigned int p, pl; unsigned char cnt; GT_LPORT port_list[MAX_SWITCH_PORTS]; for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(ports_mask, p) && (set_cpu_port || (p != qd_cpu_port))) { SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("port based vlan, port %d: ", p)); for (pl = 0, cnt = 0; pl < qd_dev->numOfPorts; pl++) { if (MV_BIT_CHECK(ports_mask, pl) && (pl != p)) { SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("%d ", pl)); port_list[cnt] = pl; cnt++; } } if (gvlnSetPortVlanPorts(qd_dev, p, port_list, cnt) != GT_OK) { printk(KERN_ERR "gvlnSetPortVlanPorts failed\n"); return -1; } SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("\n")); } } return 0; }
int mv_switch_all_multicasts_del(int db_num) { GT_STATUS status = GT_OK; GT_ATU_ENTRY atu_entry; GT_U8 mc_mac[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; GT_U8 bc_mac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; memcpy(atu_entry.macAddr.arEther, &mc_mac, 6); atu_entry.DBNum = db_num; while ((status = gfdbGetAtuEntryNext(qd_dev, &atu_entry)) == GT_OK) { /* we don't want to delete the broadcast entry which is the last one */ if (memcmp(atu_entry.macAddr.arEther, &bc_mac, 6) == 0) break; SWITCH_DBG(SWITCH_DBG_MCAST, ("Deleting ATU Entry: db = %d, MAC = %02X:%02X:%02X:%02X:%02X:%02X\n", atu_entry.DBNum, atu_entry.macAddr.arEther[0], atu_entry.macAddr.arEther[1], atu_entry.macAddr.arEther[2], atu_entry.macAddr.arEther[3], atu_entry.macAddr.arEther[4], atu_entry.macAddr.arEther[5])); if (gfdbDelAtuEntry(qd_dev, &atu_entry) != GT_OK) { printk(KERN_ERR "gfdbDelAtuEntry failed\n"); return -1; } memcpy(atu_entry.macAddr.arEther, &mc_mac, 6); atu_entry.DBNum = db_num; } return 0; }
static void earphone_switch_work(struct work_struct *work) { struct gpio_switch_data *switch_data = container_of(work, struct gpio_switch_data, work); SWITCH_DBG("te:%d\n", switch_data->state); //pr_err("*********************/*************switch_data->state:%d\n",switch_data->state); down(&switch_data->sem); switch_set_state(&switch_data->sdev, switch_data->state); up(&switch_data->sem); if (((&switch_data->timer) != NULL)&&(switch_data->state!=1)&&(switch_data->state!=2)) { SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); del_timer(&switch_data->timer); } #if 0 hmic_wr_prcm_control(PAEN_HP_CTRL, 0x1, HPPAEN, 0x0); usleep_range(50,100); hmic_wr_prcm_control(PAEN_HP_CTRL, 0x1, HPPAEN, 0x1); #endif }
int mv_switch_vlan_in_vtu_set(unsigned short vlan_id, unsigned short db_num, unsigned int ports_mask) { GT_VTU_ENTRY vtu_entry; unsigned int p; memset(&vtu_entry, 0, sizeof(GT_VTU_ENTRY)); vtu_entry.sid = 1; vtu_entry.vid = vlan_id; vtu_entry.DBNum = db_num; vtu_entry.vidPriOverride = GT_FALSE; vtu_entry.vidPriority = 0; vtu_entry.vidExInfo.useVIDFPri = GT_FALSE; vtu_entry.vidExInfo.vidFPri = 0; vtu_entry.vidExInfo.useVIDQPri = GT_FALSE; vtu_entry.vidExInfo.vidQPri = 0; vtu_entry.vidExInfo.vidNRateLimit = GT_FALSE; SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("vtu entry: vid=0x%x, port ", vtu_entry.vid)); for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(ports_mask, p)) { SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("%d ", p)); vtu_entry.vtuData.memberTagP[p] = MEMBER_EGRESS_UNMODIFIED; } else { vtu_entry.vtuData.memberTagP[p] = NOT_A_MEMBER; } vtu_entry.vtuData.portStateP[p] = 0; } if (gvtuAddEntry(qd_dev, &vtu_entry) != GT_OK) { printk(KERN_ERR "gvtuAddEntry failed\n"); return -1; } SWITCH_DBG(SWITCH_DBG_LOAD | SWITCH_DBG_MCAST | SWITCH_DBG_VLAN, ("\n")); return 0; }
int mv_switch_init(int mtu, unsigned int switch_ports_mask) { unsigned int p; unsigned char cnt; GT_LPORT port_list[MAX_SWITCH_PORTS]; if (qd_dev == NULL) { printk(KERN_ERR "%s: qd_dev not initialized, call mv_switch_load() first\n", __func__); return -1; } /* general Switch initialization - relevant for all Switch devices */ /* disable all ports */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) if (gstpSetPortState(qd_dev, p, GT_PORT_DISABLE) != GT_OK) { printk(KERN_ERR "gstpSetPortState failed\n"); return -1; } } /* flush All counters for all ports */ if (gstatsFlushAll(qd_dev) != GT_OK) printk(KERN_ERR "gstatsFlushAll failed\n"); /* set all ports not to unmodify the vlan tag on egress */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) { if (gprtSetEgressMode(qd_dev, p, GT_UNMODIFY_EGRESS) != GT_OK) { printk(KERN_ERR "gprtSetEgressMode GT_UNMODIFY_EGRESS failed\n"); return -1; } } } /* initializes the PVT Table (cross-chip port based VLAN) to all one's (initial state) */ if (gpvtInitialize(qd_dev) != GT_OK) { printk(KERN_ERR "gpvtInitialize failed\n"); return -1; } /* set all ports to work in Normal mode */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) { if (gprtSetFrameMode(qd_dev, p, GT_FRAME_MODE_NORMAL) != GT_OK) { printk(KERN_ERR "gprtSetFrameMode GT_FRAME_MODE_NORMAL failed\n"); return -1; } } } /* set priorities rules */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) { /* default port priority to queue zero */ if (gcosSetPortDefaultTc(qd_dev, p, 0) != GT_OK) printk(KERN_ERR "gcosSetPortDefaultTc failed (port %d)\n", p); /* enable IP TOS Prio */ if (gqosIpPrioMapEn(qd_dev, p, GT_TRUE) != GT_OK) printk(KERN_ERR "gqosIpPrioMapEn failed (port %d)\n", p); /* set IP QoS */ if (gqosSetPrioMapRule(qd_dev, p, GT_FALSE) != GT_OK) printk(KERN_ERR "gqosSetPrioMapRule failed (port %d)\n", p); /* disable Vlan QoS Prio */ if (gqosUserPrioMapEn(qd_dev, p, GT_FALSE) != GT_OK) printk(KERN_ERR "gqosUserPrioMapEn failed (port %d)\n", p); } } /* specific Switch initialization according to Switch ID */ switch (qd_dev->deviceId) { case GT_88E6161: case GT_88E6165: case GT_88E6171: case GT_88E6351: case GT_88E6172: case GT_88E6176: /* set Header Mode in all ports to False */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) { if (gprtSetHeaderMode(qd_dev, p, GT_FALSE) != GT_OK) { printk(KERN_ERR "gprtSetHeaderMode GT_FALSE failed\n"); return -1; } } } if (gprtSetHeaderMode(qd_dev, qd_cpu_port, GT_TRUE) != GT_OK) { printk(KERN_ERR "gprtSetHeaderMode GT_TRUE failed\n"); return -1; } mv_switch_jumbo_mode_set(mtu); break; default: printk(KERN_ERR "Unsupported Switch. Switch ID is 0x%X.\n", qd_dev->deviceId); return -1; } /* The switch CPU port is not part of the VLAN, but rather connected by tunneling to each */ /* of the VLAN's ports. Our MAC addr will be added during start operation to the VLAN DB */ /* at switch level to forward packets with this DA to CPU port. */ SWITCH_DBG(SWITCH_DBG_LOAD, ("Enabling Tunneling on ports: ")); for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p) && (p != qd_cpu_port)) { if (gprtSetVlanTunnel(qd_dev, p, GT_TRUE) != GT_OK) { printk(KERN_ERR "gprtSetVlanTunnel failed (port %d)\n", p); return -1; } else { SWITCH_DBG(SWITCH_DBG_LOAD, ("%d ", p)); } } } SWITCH_DBG(SWITCH_DBG_LOAD, ("\n")); /* set cpu-port with port-based vlan to all other ports */ SWITCH_DBG(SWITCH_DBG_LOAD, ("cpu port-based vlan:")); for (p = 0, cnt = 0; p < qd_dev->numOfPorts; p++) { if (p != qd_cpu_port) { SWITCH_DBG(SWITCH_DBG_LOAD, ("%d ", p)); port_list[cnt] = p; cnt++; } } SWITCH_DBG(SWITCH_DBG_LOAD, ("\n")); if (gvlnSetPortVlanPorts(qd_dev, qd_cpu_port, port_list, cnt) != GT_OK) { printk(KERN_ERR "gvlnSetPortVlanPorts failed\n"); return -1; } if (gfdbFlush(qd_dev, GT_FLUSH_ALL) != GT_OK) printk(KERN_ERR "gfdbFlush failed\n"); mv_switch_link_detection_init(); /* Configure Ethernet related LEDs, currently according to Switch ID */ switch (qd_dev->deviceId) { case GT_88E6161: case GT_88E6165: case GT_88E6171: case GT_88E6351: case GT_88E6172: case GT_88E6176: break; /* do nothing */ default: for (p = 0; p < qd_dev->numOfPorts; p++) { if ((p != qd_cpu_port) && ((p))) { if (gprtSetPhyReg(qd_dev, p, 22, 0x1FFA)) { /* Configure Register 22 LED0 to 0xA for Link/Act */ printk(KERN_ERR "gprtSetPhyReg failed (port=%d)\n", p); } } } break; } /* enable all relevant ports (ports connected to the MAC or external ports) */ for (p = 0; p < qd_dev->numOfPorts; p++) { if (MV_BIT_CHECK(switch_ports_mask, p)) { if ((mvBoardSwitchPortMap(MV_SWITCH_DEF_INDEX, p) != -1) || (mvBoardSwitchConnectedPortGet(MV_ETH_PORT_0) == p) || (mvBoardSwitchConnectedPortGet(MV_ETH_PORT_1) == p)) { if (gstpSetPortState(qd_dev, p, GT_PORT_FORWARDING) != GT_OK) { printk(KERN_ERR "gstpSetPortState failed\n"); return -1; } } } } #ifdef SWITCH_DEBUG /* for debug: */ mv_switch_status_print(); #endif return 0; }
static void switch_resume_events(struct work_struct *work) { int tmp = 0,tmp1 = 0; int headphone_mute_used = 0; script_item_u val; script_item_value_type_e type; struct gpio_switch_data *switch_data = container_of(work, struct gpio_switch_data, resume_work); if (switch_data == NULL) { SWITCH_DBG("%s, %d, switch_data is NULL\n", __func__, __LINE__); return; } /*fix the resume blaze blaze noise*/ hmic_wr_prcm_control(ADDA_APT2, 0x1, PA_SLOPE_SELECT, 0x1); //hmic_wr_control(SUN6I_ADDAC_TUNE, 0x1, PA_SLOPE_SECECT, 0x1); //hmic_wr_control(SUN6I_PA_CTRL, 0x1, HPPAEN, 0x1); hmic_wr_prcm_control(PAEN_HP_CTRL, 0x1, HPPAEN, 0x1); msleep(450); type = script_get_item("audio0", "headphone_mute_used", &val); if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { pr_err("[audiocodec] headphone_mute_used type err!\n"); } headphone_mute_used = val.val; if (headphone_mute_used) { gpio_set_value(item_mute.gpio.gpio, 1); } msleep(200); /*audio codec hardware bug. the HBIASADCEN bit must be enable in init*/ #ifdef CONFIG_ARCH_SUN8IW5 hmic_wr_prcm_control(MIC1G_MICBIAS_CTRL, 0x1, HMICBIAS_MODE, 0x1); #else/*CONFIG_ARCH_SUN8IW8*/ hmic_wr_prcm_control(MIC1G_MICBIAS_CTRL, 0x1, HMICADCEN, 0x1); #endif //hmic_wr_prcm_control(MIC1G_MICBIAS_CTRL, 0x1, HMICBIAS_MODE, 0x1); hmic_wr_prcm_control(MIC1G_MICBIAS_CTRL, 0x1, HMICBIASEN, 0x1); SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); msleep(200); tmp = hmic_rdreg(SUNXI_HMIC_DATA); tmp1 =(tmp&0x1f); switch_data->mode = HEADPHONE_IDLE; switch_data->sdev.state = -1; switch_data->check_three_count = 0; switch_data->check_four_count = 0; switch_data->check_plugout_count = 0; switch_data->check_debounce_count = 0; switch_data->check_hook_count = 0; SWITCH_DBG("%s,line:%d,headphone_state:%d, tmp:%x\n", __func__, __LINE__, headphone_state, tmp); #if 0 if ( (tmp & (0x1<<20)) || (headphone_state ==1 && tmp == 0) ) { //plug out SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, (tmp&0x1f)); /*if the irq is hmic earphone pull out, when the irq coming, clean the pending bit*/ hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_OUT_IRQ_PEND, 0x1); switch_data->state = 0; headphone_state = 0; // schedule_work(&switch_data->work); down(&switch_data->sem); switch_set_state(&switch_data->sdev, switch_data->state); up(&switch_data->sem); } else if ((tmp1>0x0) && (tmp1<0xb)) { switch_data->mode = FOUR_HEADPHONE_PLUGIN; if (((&switch_data->timer) != NULL)) { del_timer(&switch_data->timer); } init_timer(&switch_data->timer); switch_data->timer.function = earphone_switch_timer_poll; switch_data->timer.data = (unsigned long)switch_data; mod_timer(&switch_data->timer, jiffies + HZ/8 ); SWITCH_DBG("%s,line:%d,headphone_state:%d, tmp1:%x\n", __func__, __LINE__, headphone_state, tmp1); } else if (tmp1>=0xb) { switch_data->mode = THREE_HEADPHONE_PLUGIN; SWITCH_DBG("%s,line:%d,headphone_state:%d, tmp1:%x\n", __func__, __LINE__, headphone_state, tmp1); } #endif }
static irqreturn_t audio_hmic_irq(int irq, void *dev_id) { int tmp = 0; int debounce_ave; struct gpio_switch_data *switch_data = (struct gpio_switch_data *)dev_id; if (switch_data == NULL) { return IRQ_NONE; } /*mute headphone pa*/ hmic_wr_prcm_control(DAC_PA_SRC, 0x1, 2, 0x0); hmic_wr_prcm_control(DAC_PA_SRC, 0x1, 3, 0x0); tmp = hmic_rdreg(SUNXI_HMIC_DATA); if ((0x1<<HMIC_DATA_IRQ_PEND)&tmp) { SWITCH_DBG("hd:%x\n", (tmp&0x1f)); } /*����Ľڶ����γ������У����������ڶ���״̬ ���ڼ������һ�������γ�״̬����ʱ�����¼�⣬��ֹhook������*/ if ((0x1<<HMIC_EARPHONE_OUT_IRQ_PEND)&tmp) { SWITCH_DBG("po, (tmp&0x1f):%x\n", (tmp&0x1f)); switch_data->reset_flag = 1; } tmp = tmp&0x1f; if (!headphone_direct_used) { if ((switch_data->state == -1)||(tmp >= 1)) { SWITCH_DBG("h-1\n"); /*�ɼ����ݣ��˲��ж�*/ if (switch_data->check_debounce_count <= HEADSET_DEBOUNCE) { debounce_val[switch_data->check_debounce_count] = tmp; SWITCH_DBG("h-2, debounce_val[%d]:%x\n", switch_data->check_debounce_count, debounce_val[switch_data->check_debounce_count]); switch_data->check_debounce_count++; } else { switch_data->check_debounce_count = 0; SWITCH_DBG("h-3\n"); } if ((debounce_val[0]==debounce_val[1])&&(debounce_val[1]==debounce_val[2])&&(debounce_val[2]==debounce_val[3])) { debounce_ave = (int)((debounce_val[0] + debounce_val[1] + debounce_val[2] + debounce_val[3])/4); SWITCH_DBG("h-4,debounce_ave:%d,%d\n", debounce_ave,16/4); if (debounce_ave >= 1) { SWITCH_DBG("h-5\n"); /*�������жϹرգ��������жϣ����²ɼ������ж��Ƿ������ζ������Ķζ���*/ hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x0); /*23*/ if (((&switch_data->timer) != NULL)) { del_timer(&switch_data->timer); } switch_data->reset_flag = 0; switch_data->check_four_count = 0; switch_data->check_plugout_count = 0; switch_data->check_three_count = 0; switch_data->check_debounce_count = 0; init_timer(&switch_data->timer); switch_data->timer.function = earphone_switch_timer_poll; switch_data->timer.data = (unsigned long)switch_data; mod_timer(&switch_data->timer, jiffies + HZ/20 ); } debounce_val[0] = 0; debounce_val[1] = 0; debounce_val[2] = 0; debounce_val[3] = 0; } else { SWITCH_DBG("h-6, switch_data->state:%d,debounce_val[0]:%d, debounce_val[1]:%d, debounce_val[2]:%d, debounce_val[3]:%d\n", switch_data->state, debounce_val[0], debounce_val[1], debounce_val[2], debounce_val[3]); /*�ɼ��������У�����0data���ж��Ƿ��Ƕ����γ�״̬*/ if ((debounce_val[0]==0)||(debounce_val[1]==0)||(debounce_val[2]==0)||(debounce_val[3]==0)) { if (((&switch_data->timer) != NULL)) { del_timer(&switch_data->timer); } init_timer(&switch_data->timer); switch_data->timer.function = earphone_switch_timer_poll; switch_data->timer.data = (unsigned long)switch_data; mod_timer(&switch_data->timer, jiffies + HZ/20 ); } else { /*�����ж��������жϣ����²ɼ��ж�*/ hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_DIRQ, 0x1); /*23*/ } } } else { SWITCH_DBG("h-7\n"); /*�������жϣ��ж��Ƿ��Ƕ����γ�״̬*/ if (((&switch_data->timer) != NULL)) { del_timer(&switch_data->timer); } debounce_val[0] = 0; debounce_val[1] = 0; debounce_val[2] = 0; debounce_val[3] = 0; switch_data->mode = HEADPHONE_IDLE; switch_data->state = 0; switch_data->check_four_count = 0; switch_data->check_plugout_count = 0; switch_data->check_three_count = 0; switch_data->check_debounce_count = 0; switch_data->check_hook_count = 0; init_timer(&switch_data->timer); switch_data->timer.function = earphone_switch_timer_poll; switch_data->timer.data = (unsigned long)switch_data; mod_timer(&switch_data->timer, jiffies + HZ/20 ); } } else { /*headphone_direct_used == 1*/ #if 0 if (tmp > 0) { SWITCH_DBG("headphone three or four HP,HMIC_DAT= %d\n",(tmp&0x1f)); switch_data->state = 2; headphone_state = 1; } else { SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, (tmp&0x1f)); /*if the irq is hmic earphone pull out, when the irq coming, clean the pending bit*/ headphone_state = 0; switch_data->state = 0; } schedule_work(&switch_data->work); #endif if (((&switch_data->timer) != NULL)) { del_timer(&switch_data->timer); } //switch_data->mode = HEADPHONE_IDLE; switch_data->state = 0; switch_data->check_three_count = 0; switch_data->check_plugout_count = 0; init_timer(&switch_data->timer); switch_data->timer.function = earphone_switch_timer_poll; switch_data->timer.data = (unsigned long)switch_data; mod_timer(&switch_data->timer, jiffies + HZ/8 ); } if (((&switch_data->mute_timer) != NULL)) { del_timer(&switch_data->mute_timer); } init_timer(&switch_data->mute_timer); switch_data->mute_timer.function = earphone_open_mute; switch_data->mute_timer.data = (unsigned long)switch_data; if (headphone_direct_used) { mod_timer(&switch_data->mute_timer, jiffies + HZ); } else{ mod_timer(&switch_data->mute_timer, jiffies + (HZ+HZ/2)); } hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_DOWN_IRQ_PEND, 0x1); hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_IN_IRQ_PEND, 0x1); hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_UP_IRQ_PEND, 0x1); hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_OUT_IRQ_PEND, 0x1); hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_DATA_IRQ_PEND, 0x1); return IRQ_HANDLED; }
static void earphone_switch_timer_poll(unsigned long data) { int tmp = 0; struct gpio_switch_data *switch_data =(struct gpio_switch_data *)data; tmp = hmic_rdreg(SUNXI_HMIC_DATA); tmp &= 0x1f; SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, tmp); if (!headphone_direct_used) { if (((tmp >= 0xb) && (switch_data->mode != FOUR_HEADPHONE_PLUGIN) && (switch_data->state != 2) && (switch_data->reset_flag == 0))&&(switch_data->mode!=HOOK_CHCCK_DOWN)) { SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, tmp); if ((switch_data->check_three_count > CIRCLE_COUNT) && (switch_data->state != 2)) { /*it means the three sections earphone has plun in*/ switch_data->mode = THREE_HEADPHONE_PLUGIN; switch_data->state = 2; schedule_work(&switch_data->work); SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); switch_data->check_three_count = 0; hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x0); /*23*/ } /*check again to reduce the disturb from earphone plug in unstable*/ switch_data->check_three_count++; switch_data->check_four_count = 0; switch_data->check_plugout_count = 0; switch_data->check_debounce_count = 0; if (((&switch_data->timer) != NULL)) { SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); if (switch_data->state == 2) { mod_timer(&switch_data->timer, jiffies + HZ/20); } else { mod_timer(&switch_data->timer, jiffies + HZ/5); } } headphone_state = 1; } else if ((tmp>=0x1 && tmp<0xb) && (switch_data->mode != THREE_HEADPHONE_PLUGIN) && (switch_data->state != 1) && (switch_data->reset_flag == 0)) { SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, tmp); if ((switch_data->check_four_count > CIRCLE_COUNT) && (switch_data->state != 1)) { /*it means the four sections earphone has plun in*/ switch_data->mode = FOUR_HEADPHONE_PLUGIN; switch_data->state = 1; schedule_work(&switch_data->work); SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); switch_data->check_four_count = 0; } switch_data->check_four_count++; switch_data->check_three_count = 0; switch_data->check_plugout_count = 0; switch_data->check_debounce_count = 0; switch_data->check_hook_count = 0; if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/20); } headphone_state = 1; SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); } else if ((tmp>=0xb) && (switch_data->mode == FOUR_HEADPHONE_PLUGIN) && (switch_data->state == 1) && (switch_data->reset_flag == 0)) { SWITCH_DBG("%s,line:%d,switch_data->reset_flag:%d,tmp:%x\n", __func__, __LINE__, switch_data->reset_flag, tmp); //spin_lock(&switch_data->lock); if ((tmp >= 0x10)&&(switch_data->reset_flag==0)) { SWITCH_DBG("H_SCH\n"); //schedule_work(&switch_data->hook_work); //queue_work(switch_hook_queue, &switch_data->hook_work); //switch_data->check_hook_count = 0; switch_data->mode = HOOK_CHCCK_DOWN; hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x1); /*23*/ } else if ((tmp == 0xf)&&(switch_data->reset_flag==0)) { input_report_key(switch_data->key, KEY_VOLUMEUP, 1); input_sync(switch_data->key); input_report_key(switch_data->key, KEY_VOLUMEUP, 0); input_sync(switch_data->key); // hmic_wr_control(SUN6I_HMIC_CTL, 0x1, HMIC_DIRQ, 0x1); /*23*/ } else if ((tmp == 0xe)&&(switch_data->reset_flag==0)) { input_report_key(switch_data->key, KEY_VOLUMEDOWN, 1); input_sync(switch_data->key); input_report_key(switch_data->key, KEY_VOLUMEDOWN, 0); input_sync(switch_data->key); // hmic_wr_control(SUN6I_HMIC_CTL, 0x1, HMIC_DIRQ, 0x1); /*23*/ } //spin_unlock(&switch_data->lock); //switch_data->check_hook_count++; if (tmp >= 0x10) { if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/10); } } else { if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/20); } } headphone_state = 1; } else if ((tmp<0xb&&tmp>0) && (switch_data->mode == FOUR_HEADPHONE_PLUGIN) && (switch_data->state == 1) && (switch_data->reset_flag == 0)) { SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, tmp); /*hook up*/ input_report_key(switch_data->key, KEY_HEADSETHOOK, 0); input_sync(switch_data->key); if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/5); } headphone_state = 1; switch_data->check_hook_count = 0; } else if (switch_data->mode == HOOK_CHCCK_DOWN) { if ((switch_data->reset_flag == 0)&&(switch_data->check_hook_count > 1)) { SWITCH_DBG("vol%s,line:%d,switch_data->reset_flag:%d,tmp:%x\n", __func__, __LINE__, switch_data->reset_flag, tmp); /*hook down*/ input_report_key(switch_data->key, KEY_HEADSETHOOK, 1); input_sync(switch_data->key); switch_data->mode = FOUR_HEADPHONE_PLUGIN; } switch_data->check_hook_count++; if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/5); } headphone_state = 1; } else { SWITCH_DBG("%s,line:%d,switch_data->state:%d, switch_data->reset_flag:%d, tmp:%x\n", __func__, __LINE__, switch_data->state, switch_data->reset_flag, tmp); if (switch_data->check_plugout_count > CIRCLE_COUNT) { if (tmp>=0x1) { switch_data->reset_flag = 0; headphone_state = 1; } else { switch_data->state = 0; headphone_state = 0; schedule_work(&switch_data->work); } SWITCH_DBG("%s,line:%d,switch_data->state:%d,switch_data->reset_flag:%d, tmp:%x\n", __func__, __LINE__, switch_data->state, switch_data->reset_flag, tmp); switch_data->check_plugout_count = 0; hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x0); /*23*/ } switch_data->check_plugout_count++; switch_data->mode = HEADPHONE_IDLE; //switch_data->state = 0; switch_data->check_four_count = 0; switch_data->check_three_count = 0; switch_data->check_debounce_count = 0; if (((&switch_data->timer) != NULL)) { mod_timer(&switch_data->timer, jiffies + HZ/20); } } }else{ if (tmp > 1) { if (switch_data->check_three_count > (CIRCLE_COUNT-1)) { /*it means the three sections earphone has plun in*/ switch_data->state = 2; schedule_work(&switch_data->work); SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); switch_data->check_three_count = 0; //hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x0); /*23*/ } switch_data->check_three_count++; switch_data->check_plugout_count = 0; SWITCH_DBG("headphone three or four HP,HMIC_DAT= %d\n",(tmp&0x1f)); } else { if (switch_data->check_plugout_count > CIRCLE_COUNT) { /*it means the three sections earphone has plun in*/ switch_data->state = 0; schedule_work(&switch_data->work); SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); switch_data->check_plugout_count = 0; //hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x0); /*23*/ } switch_data->check_three_count = 0; switch_data->check_plugout_count++; SWITCH_DBG("%s,line:%d,tmp:%x\n", __func__, __LINE__, (tmp&0x1f)); /*if the irq is hmic earphone pull out, when the irq coming, clean the pending bit*/ } if (((&switch_data->timer) != NULL)) { SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); mod_timer(&switch_data->timer, jiffies + HZ/8); } } }
static void earphone_open_mute(unsigned long data) { SWITCH_DBG("%s,line:%d\n", __func__, __LINE__); hmic_wr_prcm_control(DAC_PA_SRC, 0x1, 2, 0x1); hmic_wr_prcm_control(DAC_PA_SRC, 0x1, 3, 0x1); }