Esempio n. 1
0
static void key_handler(enum cpcap_irqs irq, void *data)
{
	struct cpcap_3mm5_data *data_3mm5 = data;

	if ((irq != CPCAP_IRQ_MB2) && (irq != CPCAP_IRQ_UC_PRIMACRO_5))
		return;

	if ((cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_HS, 1) == 1) ||
	    (switch_get_state(&data_3mm5->sdev) != HEADSET_WITH_MIC)) {
		hs_handler(CPCAP_IRQ_HS, data_3mm5);
		return;
	}

	if ((cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_MB2, 0) == 0) ||
	    (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_PTT, 0) == 0)) {
		send_key_event(data_3mm5, 1);

		/* If macro not available, only short presses are supported */
		if (!cpcap_uc_status(data_3mm5->cpcap, CPCAP_MACRO_5)) {
			send_key_event(data_3mm5, 0);

			/* Attempt to restart the macro for next time. */
			cpcap_uc_start(data_3mm5->cpcap, CPCAP_MACRO_5);
		}
	} else
		send_key_event(data_3mm5, 0);

	cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
	cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);
}
Esempio n. 2
0
static void mac13_work(struct work_struct *work)
{
	struct cpcap_3mm5_data *data_3mm5 =
		container_of(work, struct cpcap_3mm5_data, work.work);

	audio_low_power_set(data_3mm5, &data_3mm5->audio_low_pwr_mac13);
	cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_13);
}
Esempio n. 3
0
static void detection_work(struct work_struct *work)
{
	struct cpcap_usb_det_data *data =
		container_of(work, struct cpcap_usb_det_data, work.work);
#ifdef CONFIG_TTA_CHARGER
	static unsigned char first_time;
#endif

	printk(KERN_ERR "detection_work:data->state = %d\n", data->state);

	switch (data->state) {
	case CONFIG:
		vusb_enable(data);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_CHRG_DET);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_SE1);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_IDGND);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_VBUSVLD);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_DPI);
		cpcap_irq_mask(data->cpcap, CPCAP_IRQ_DMI);

		configure_hardware(data, CPCAP_ACCY_UNKNOWN);

		data->state = SAMPLE_1;
		schedule_delayed_work(&data->work, msecs_to_jiffies(11));
		break;

	case SAMPLE_1:
		get_sense(data);
#ifdef CONFIG_TTA_CHARGER
		if (!(data->sense_tta.gpio_val) &&
			(data->sense & CPCAP_BIT_SESSVLD_S)) {
			disable_tta();
			enable_tta();
		}
#endif
		data->state = SAMPLE_2;
		schedule_delayed_work(&data->work, msecs_to_jiffies(100));
		break;

	case SAMPLE_2:
		data->prev_sense = data->sense;
		get_sense(data);

		if (data->prev_sense != data->sense) {
			/* Stay in this state */
			data->state = SAMPLE_2;
			schedule_delayed_work(&data->work,
					      msecs_to_jiffies(100));
		} else if (!(data->sense & CPCAP_BIT_SE1_S) &&
			   (data->sense & CPCAP_BIT_ID_FLOAT_S) &&
			   !(data->sense & CPCAP_BIT_ID_GROUND_S) &&
			   !(data->sense & CPCAP_BIT_SESSVLD_S)) {
			data->state = IDENTIFY;
#ifdef CONFIG_TTA_CHARGER
			if (!(data->sense_tta.gpio_val))
				data->state = IDENTIFY_TTA;
#endif
			schedule_delayed_work(&data->work,
					      msecs_to_jiffies(100));
		} else {
			data->state = IDENTIFY;
#ifdef CONFIG_TTA_CHARGER
			if (!(data->sense & CPCAP_BIT_SESSVLD_S) &&
				!(data->sense_tta.gpio_val)) {
				data->state = IDENTIFY_TTA;
		}
#endif
			schedule_delayed_work(&data->work, 0);
		}
		break;
#ifdef CONFIG_TTA_CHARGER
	case IDENTIFY_TTA:
		configure_hardware(data, CPCAP_ACCY_TTA_CHARGER);
		data->state = IDENTIFY;
		schedule_delayed_work(&data->work, 0);
		break;
#endif
	case IDENTIFY:
		get_sense(data);
		data->state = CONFIG;

#ifdef CONFIG_TTA_CHARGER
		if ((data->sense_tta.dplus == data->sense_tta.dminus) &&
			!(data->sense_tta.gpio_val) &&
			!(data->sense & CPCAP_BIT_SESSVLD_S)) {
			notify_accy(data, CPCAP_ACCY_TTA_CHARGER);
			cpcap_irq_clear(data->cpcap, CPCAP_IRQ_DMI);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_DMI);
			data->state = TTA;
			disable_musb_int();

		} else if ((data->sense == SENSE_USB) ||
			(data->sense == SENSE_USB_FLASH)) {
			notify_accy(data, CPCAP_ACCY_USB);

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);

			/* Special handling of USB cable undetect. */
			data->state = USB;
		}
#else
		if ((data->sense == SENSE_USB) ||
		    (data->sense == SENSE_USB_FLASH)) {
			notify_accy(data, CPCAP_ACCY_USB);

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);

			/* Special handling of USB cable undetect. */
			data->state = USB;
		}
#endif
		else if (data->sense == SENSE_FACTORY) {
			notify_accy(data, CPCAP_ACCY_FACTORY);

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
#ifdef CONFIG_TTA_CHARGER
			disable_tta();
#endif
			/* Special handling of factory cable undetect. */
			data->state = FACTORY;
		} else if ((data->sense == SENSE_CHARGER_FLOAT) ||
			   (data->sense == SENSE_CHARGER)) {
			notify_accy(data, CPCAP_ACCY_CHARGER);

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);

			/* Special handling of charger undetect. */
			data->state = CHARGER;
		} else if ((data->sense & CPCAP_BIT_VBUSVLD_S) &&
				(data->usb_accy == CPCAP_ACCY_NONE)) {
			data->state = CONFIG;
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_DPI);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_DMI);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);

		} else {
			notify_accy(data, CPCAP_ACCY_NONE);

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);

			/* When a charger is unpowered by unplugging from the
			 * wall, VBUS voltage will drop below CHRG_DET (3.5V)
			 * until the ICHRG bits are cleared.  Once ICHRG is
			 * cleared, VBUS will rise above CHRG_DET, but below
			 * VBUSVLD (4.4V) briefly as it decays.  If the charger
			 * is re-powered while VBUS is within this window, the
			 * VBUSVLD interrupt is needed to trigger charger
			 * detection.
			 *
			 * VBUSVLD must be masked before going into suspend.
			 * See cpcap_usb_det_suspend() for details.
			 */
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_VBUSVLD);
#ifdef CONFIG_TTA_CHARGER
			disable_tta();
			enable_tta();
#endif
		}
		break;
#ifdef CONFIG_TTA_CHARGER
	case TTA:
		get_sense(data);

		if ((data->sense_tta.dplus != data->sense_tta.dminus) ||
			(data->sense_tta.gpio_val)) {
			cpcap_irq_mask(data->cpcap, CPCAP_IRQ_DMI);
			disable_tta();
			enable_tta();
			data->state = CONFIG;
			enable_musb_int();
			schedule_delayed_work(&data->work, 0);
		} else {
			data->state = TTA;
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_DMI);
		}
		break;
#endif
	case USB:
		get_sense(data);

		if ((data->sense & CPCAP_BIT_SE1_S) ||
			(data->sense & CPCAP_BIT_ID_GROUND_S) ||
			(!(data->sense & CPCAP_BIT_VBUSVLD_S))) {
				data->state = CONFIG;
				schedule_delayed_work(&data->work, 0);
		} else {
			data->state = USB;
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);
		}
		break;

	case FACTORY:
		get_sense(data);

		/* The removal of a factory cable can only be detected if a
		 * charger is attached.
		 */
		if (data->sense & CPCAP_BIT_SE1_S) {
#ifdef CONFIG_TTA_CHARGER
			enable_tta();
#endif
			data->state = CONFIG;
			schedule_delayed_work(&data->work, 0);
		} else {
			data->state = FACTORY;
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
		}
		break;

	case CHARGER:
		get_sense(data);

		/* If the battery voltage is above the set charge voltage in
		 * CPCAP and ICHRG is set, CHRGCURR1 will be 0.  Do not undetect
		 * charger in this case. */
		if (!(data->sense & CPCAP_BIT_SE1_S) ||
		    (!(data->sense & CPCAP_BIT_VBUSVLD_S) &&
		     !(data->sense & CPCAP_BIT_CHRGCURR1_S))) {
			data->state = CONFIG;
			schedule_delayed_work(&data->work, 0);
		} else {
			data->state = CHARGER;

			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_CURR1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_SE1);
			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDGND);
		}
		break;

	default:
		/* This shouldn't happen.  Need to reset state machine. */
		vusb_disable(data);
		data->state = CONFIG;
		schedule_delayed_work(&data->work, 0);
		break;
	}
#ifdef CONFIG_TTA_CHARGER
	temp_data = data;
	if (!first_time) {
		enable_musb_int();
		first_time = 1;
	}
#endif
}
Esempio n. 4
0
static void hs_handler(enum cpcap_irqs irq, void *data)
{
	struct cpcap_3mm5_data *data_3mm5 = data;
	int new_state = NO_DEVICE;

	if (irq != CPCAP_IRQ_HS)
		return;

	/* HS sense of 1 means no headset present, 0 means headset attached. */
	if (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_HS, 1) == 1) {
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_TXI, 0,
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN));
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_RXOA, 0,
				   CPCAP_BIT_ST_HS_CP_EN);
		audio_low_power_set(data_3mm5, &data_3mm5->audio_low_pwr_det);

		cpcap_irq_mask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_mask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_HS);

		send_key_event(data_3mm5, 0);

		/* Config mux switch to accy detection. */
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO2, 0,
				CPCAP_BIT_GPIO2DRV);
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO4, 0,
				CPCAP_BIT_GPIO4DRV);
		cpcap_uc_stop(data_3mm5->cpcap, CPCAP_MACRO_5);
	} else {
		/* Config mux switch to pass headset mic. */
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO2, 0,
					CPCAP_BIT_GPIO2DRV);
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO4,
					CPCAP_BIT_GPIO4DRV, CPCAP_BIT_GPIO4DRV);

		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_TXI,
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN),
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN));
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_RXOA,
				   CPCAP_BIT_ST_HS_CP_EN,
				   CPCAP_BIT_ST_HS_CP_EN);
		audio_low_power_clear(data_3mm5, &data_3mm5->audio_low_pwr_det);

		/* Give PTTS time to settle 10ms */
		msleep(11);

		if (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_PTT, 1) <= 0) {
			/* Headset without mic and MFB is detected. (May also
			 * be a headset with the MFB pressed.) */
			new_state = HEADSET_WITHOUT_MIC;
		} else {
			new_state = HEADSET_WITH_MIC;
			/* Config mux switch to pass headset mic. */
			cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO2, 0,
					CPCAP_BIT_GPIO2DRV);
			cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_GPIO4,
					CPCAP_BIT_GPIO4DRV, CPCAP_BIT_GPIO4DRV);
		}

		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_HS);
		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_uc_start(data_3mm5->cpcap, CPCAP_MACRO_5);
		headset_in_stamp = jiffies;
	}

	switch_set_state(&data_3mm5->sdev, new_state);
	if (data_3mm5->cpcap->h2w_new_state)
		data_3mm5->cpcap->h2w_new_state(new_state);

	dev_info(&data_3mm5->cpcap->spi->dev, "New headset state: %d\n",
		 new_state);
}
Esempio n. 5
0
static void hs_handler(enum cpcap_irqs irq, void *data)
{
	struct cpcap_3mm5_data *data_3mm5 = data;
	int new_state = NO_DEVICE;

	if (irq != CPCAP_IRQ_HS)
		return;

	/* HS sense of 1 means no headset present, 0 means headset attached. */
	if (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_HS, 1) == 1) {
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_TXI, 0,
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN));
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_RXOA, 0,
				   CPCAP_BIT_ST_HS_CP_EN);
		audio_low_power_set(data_3mm5, &data_3mm5->audio_low_pwr_det);

		cpcap_irq_mask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_mask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_HS);

		send_key_event(data_3mm5, 0);

		data_3mm5->unsupported_headset=0;

		cpcap_uc_stop(data_3mm5->cpcap, CPCAP_BANK_PRIMARY, CPCAP_MACRO_5);
	} else {
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_TXI,
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN),
				   (CPCAP_BIT_MB_ON2 | CPCAP_BIT_PTT_CMP_EN));
		cpcap_regacc_write(data_3mm5->cpcap, CPCAP_REG_RXOA,
				   CPCAP_BIT_ST_HS_CP_EN,
				   CPCAP_BIT_ST_HS_CP_EN);
		audio_low_power_clear(data_3mm5, &data_3mm5->audio_low_pwr_det);

		/* Give PTTS time to settle */
		mdelay(2);

		if (cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_PTT, 1) <= 0) {
			/* Headset without mic and MFB is detected. (May also
			 * be a headset with the MFB pressed.) */
			new_state = HEADSET_WITHOUT_MIC;
		} else {
		 if(cpcap_irq_sense(data_3mm5->cpcap, CPCAP_IRQ_MB2, 1) == 0) {
/*cvk011c: This is an Apple HS  and  its microphone will not work with CPCAP due to HW problem.
 Detect it as  HS without mic to avoid  problems with HS BTN detection and  MIC audio */
                		new_state = HEADSET_WITHOUT_MIC;
				dev_info(&data_3mm5->cpcap->spi->dev, "Unsupported headset detected\n");
				data_3mm5->unsupported_headset=1;
			}else
				new_state = HEADSET_WITH_MIC;
         	}

		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_clear(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_HS);
		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_MB2);
		cpcap_irq_unmask(data_3mm5->cpcap, CPCAP_IRQ_UC_PRIMACRO_5);

		cpcap_uc_start(data_3mm5->cpcap, CPCAP_BANK_PRIMARY, CPCAP_MACRO_5);
	}

	switch_set_state(&data_3mm5->sdev, new_state);
	if (data_3mm5->cpcap->h2w_new_state)
		data_3mm5->cpcap->h2w_new_state(new_state);

	dev_info(&data_3mm5->cpcap->spi->dev, "New headset state: %d\n",
		 new_state);
}