From ee3524207f41baad4db947d185ea916f8e899c34 Mon Sep 17 00:00:00 2001
From: Greg Meiste <w30289@motorola.com>
Date: Wed, 26 May 2010 16:18:47 -0500
Subject: [PATCH] mfd: cpcap-whisper: Changes for version 0.4

Whisper detection changes for version 0.4, enabling Whisper proto board
to be detected.  Now reporting dock type to system.

Change-Id: I22e9704a33afc0afcd02eb68fcb40c87b9b3e3fc
Signed-off-by: Greg Meiste <w30289@motorola.com>
---
 drivers/mfd/cpcap-whisper.c | 49 +++++++++++++++++++++++++++++++------
 include/linux/spi/cpcap.h   |  7 ++++--
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/drivers/mfd/cpcap-whisper.c b/drivers/mfd/cpcap-whisper.c
index 68bd873d4c17..094790d44f0a 100644
--- a/drivers/mfd/cpcap-whisper.c
+++ b/drivers/mfd/cpcap-whisper.c
@@ -47,7 +47,7 @@
 			     CPCAP_BIT_VBUSVLD_S   | \
 			     CPCAP_BIT_SESSVLD_S)
 
-#define SENSE_WHISPER_PPD   (CPCAP_BIT_SE1_S)
+#define SENSE_WHISPER_PPD   (0)
 
 /* TODO: Update with appropriate value. */
 #define ADC_AUDIO_THRES     0x12C
@@ -57,6 +57,7 @@ enum cpcap_det_state {
 	SAMPLE_1,
 	SAMPLE_2,
 	IDENTIFY,
+	IDENTIFY_WHISPER,
 	WHISPER,
 };
 
@@ -73,6 +74,8 @@ enum {
 	NO_DOCK,
 	DESK_DOCK,
 	CAR_DOCK,
+	MOBILE_DOCK,
+	HD_DOCK,
 };
 
 struct cpcap_whisper_data {
@@ -102,6 +105,10 @@ static ssize_t print_name(struct switch_dev *dsdev, char *buf)
 		return sprintf(buf, "DESK\n");
 	case CAR_DOCK:
 		return sprintf(buf, "CAR\n");
+	case MOBILE_DOCK:
+		return sprintf(buf, "MOBILE\n");
+	case HD_DOCK:
+		return sprintf(buf, "HD\n");
 	}
 
 	return -EINVAL;
@@ -187,7 +194,7 @@ static int configure_hardware(struct cpcap_whisper_data *data,
 	case CPCAP_ACCY_USB:
 		retval |= cpcap_regacc_write(data->cpcap, CPCAP_REG_USBC1, 0,
 					     CPCAP_BIT_VBUSPD);
-		gpio_set_value(data->pdata->gpio, 1);
+		gpio_set_value(data->pdata->data_gpio, 1);
 		/* TODO: Does this driver enable "reverse mode" for hosts? */
 		break;
 
@@ -202,11 +209,11 @@ static int configure_hardware(struct cpcap_whisper_data *data,
 					      CPCAP_BIT_EMUMODE2 |
 					      CPCAP_BIT_EMUMODE1 |
 					      CPCAP_BIT_EMUMODE0));
-		/* TODO: Need to turn on "reverse mode" for PPD's */
 		break;
 
 	case CPCAP_ACCY_UNKNOWN:
-		gpio_set_value(data->pdata->gpio, 0);
+		gpio_set_value(data->pdata->pwr_gpio, 0);
+		gpio_set_value(data->pdata->data_gpio, 0);
 		retval |= cpcap_regacc_write(data->cpcap, CPCAP_REG_USBC1, 0,
 					     (CPCAP_BIT_VBUSPD |
 					      CPCAP_BIT_ID100KPU));
@@ -214,11 +221,11 @@ static int configure_hardware(struct cpcap_whisper_data *data,
 					     (CPCAP_BIT_EMUMODE2 |
 					      CPCAP_BIT_EMUMODE1 |
 					      CPCAP_BIT_EMUMODE0));
-		/* TODO: Need to turn off "reverse mode" */
 		break;
 
 	case CPCAP_ACCY_NONE:
 	default:
+		gpio_set_value(data->pdata->pwr_gpio, 0);
 		retval |= cpcap_regacc_write(data->cpcap, CPCAP_REG_USBC1,
 					     CPCAP_BIT_VBUSPD,
 					     CPCAP_BIT_VBUSPD);
@@ -347,6 +354,28 @@ static void whisper_det_work(struct work_struct *work)
 
 			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDFLOAT);
 		} else if (data->sense == SENSE_WHISPER_PPD) {
+			gpio_set_value(data->pdata->pwr_gpio, 1);
+
+			/* Extra identification step for Whisper. */
+			data->state = IDENTIFY_WHISPER;
+			schedule_delayed_work(&data->work,
+					      msecs_to_jiffies(47));
+		} else {
+			whisper_notify(data, CPCAP_ACCY_NONE);
+
+			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_CHRG_DET);
+			cpcap_irq_unmask(data->cpcap, CPCAP_IRQ_IDFLOAT);
+		}
+		break;
+
+	case IDENTIFY_WHISPER:
+		get_sense(data);
+		data->state = CONFIG;
+
+		if (whisper_debug)
+			pr_info("%s: sense=0x%04x\n", __func__, data->sense);
+
+		if (data->sense & CPCAP_BIT_SE1_S) {
 			whisper_notify(data, CPCAP_ACCY_WHISPER);
 			whisper_audio_check(data);
 
@@ -406,6 +435,7 @@ int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned long cmd)
 	struct cpcap_whisper_data *di = cpcap->accydata;
 	int retval = -EAGAIN;
 	unsigned short value;
+	int dock;
 
 	if (!di)
 		return -ENODEV;
@@ -418,7 +448,12 @@ int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned long cmd)
 		retval = cpcap_regacc_write(cpcap, CPCAP_REG_USBC1,
 					    value, CPCAP_BIT_ID100KPU);
 
-		/* TODO: Report dock type to system. */
+		/* Report dock type to system. */
+		dock = (cmd & CPCAP_WHISPER_ACCY_MASK) >>
+			CPCAP_WHISPER_ACCY_SHFT;
+		switch_set_state(&di->dsdev, dock);
+
+		/* TODO: Report audio cable to system. */
 	}
 
 	return retval;
@@ -511,7 +546,7 @@ static int __exit cpcap_whisper_remove(struct platform_device *pdev)
 	switch_dev_unregister(&data->wsdev);
 	switch_dev_unregister(&data->dsdev);
 
-	gpio_set_value(data->pdata->gpio, 1);
+	gpio_set_value(data->pdata->data_gpio, 1);
 
 	vusb_disable(data);
 	regulator_put(data->regulator);
diff --git a/include/linux/spi/cpcap.h b/include/linux/spi/cpcap.h
index fc806858c318..5e0d2b9e048d 100644
--- a/include/linux/spi/cpcap.h
+++ b/include/linux/spi/cpcap.h
@@ -39,7 +39,9 @@
 #define CPCAP_IRQ_INT4_INDEX 48
 #define CPCAP_IRQ_INT5_INDEX 64
 
-#define CPCAP_WHISPER_MODE_PU 0x00000001
+#define CPCAP_WHISPER_MODE_PU   0x00000001
+#define CPCAP_WHISPER_ACCY_MASK 0xF1000000
+#define CPCAP_WHISPER_ACCY_SHFT 27
 
 enum cpcap_regulator_id {
 	CPCAP_SW5,
@@ -587,7 +589,8 @@ struct cpcap_platform_data {
 };
 
 struct cpcap_whisper_pdata {
-	unsigned int gpio;
+	unsigned int data_gpio;
+	unsigned int pwr_gpio;
 	unsigned char uartmux;
 };
 
-- 
2.34.1