Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
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
}
Пример #4
0
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;
}
Пример #5
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;
}
Пример #6
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
}
Пример #7
0
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;
}
Пример #8
0
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);
			}

	}
}
Пример #9
0
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);
}