return false;
}
+static inline int is_output_whisper_emu(struct cpcap_audio_state *state)
+{
+ if (state->codec_primary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO
+ || state->codec_secondary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO
+ || state->stdac_primary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO
+ || state->stdac_secondary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO
+ || state->ext_primary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO
+ || state->ext_secondary_speaker == CPCAP_AUDIO_OUT_EMU_STEREO) {
+ pr_debug("%s() returning TRUE\n", __func__);
+ return 1;
+ }
+
+ pr_debug("%s() returning FALSE\n", __func__);
+ return 0;
+}
+
static inline bool is_speaker_turning_off(struct cpcap_audio_state *state,
struct cpcap_audio_state *prev)
{
value |= CPCAP_BIT_ALEFT_HS_CDC_SW;
break;
+ case CPCAP_AUDIO_OUT_EMU_STEREO:
+ if (balance != CPCAP_AUDIO_BALANCE_R_ONLY)
+ value |= CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW;
+ if (balance != CPCAP_AUDIO_BALANCE_L_ONLY)
+ value |= CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW;
+ break;
+
case CPCAP_AUDIO_OUT_LINEOUT:
value |= CPCAP_BIT_A4_LINEOUT_R_CDC_SW |
CPCAP_BIT_A4_LINEOUT_L_CDC_SW;
value |= CPCAP_BIT_ARIGHT_HS_DAC_SW;
break;
+ case CPCAP_AUDIO_OUT_EMU_STEREO:
+ if (balance != CPCAP_AUDIO_BALANCE_R_ONLY)
+ value |= CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW;
+ if (balance != CPCAP_AUDIO_BALANCE_L_ONLY)
+ value |= CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW;
+ break;
+
case CPCAP_AUDIO_OUT_LOUDSPEAKER:
value |= CPCAP_BIT_A2_LDSP_L_DAC_SW | CPCAP_BIT_MONO_DAC0 |
CPCAP_BIT_MONO_DAC1;
CPCAP_BIT_PGA_EXT_L_EN;
break;
+ case CPCAP_AUDIO_OUT_EMU_STEREO:
+ if (balance != CPCAP_AUDIO_BALANCE_R_ONLY)
+ value |= CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW;
+ if (balance != CPCAP_AUDIO_BALANCE_L_ONLY)
+ value |= CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW;
+ break;
+
case CPCAP_AUDIO_OUT_LOUDSPEAKER:
value = CPCAP_BIT_A2_LDSP_L_EXT_SW | CPCAP_BIT_PGA_EXT_L_EN;
break;
static bool cpcap_audio_set_bits_for_speaker(int speaker, int balance,
unsigned short int *message)
{
- pr_debug("%s() called with speaker = %d\n", __func__,
- speaker);
-
/* Get the data required to enable each possible path */
switch (speaker) {
case CPCAP_AUDIO_OUT_HANDSET:
(*message) |= CPCAP_BIT_HS_R_EN;
break;
+ case CPCAP_AUDIO_OUT_EMU_STEREO:
+ if (balance != CPCAP_AUDIO_BALANCE_R_ONLY)
+ (*message) |= CPCAP_BIT_EMU_SPKR_R_EN;
+ if (balance != CPCAP_AUDIO_BALANCE_L_ONLY)
+ (*message) |= CPCAP_BIT_EMU_SPKR_L_EN;
+ break;
+
case CPCAP_AUDIO_OUT_LOUDSPEAKER:
(*message) |= CPCAP_BIT_A2_LDSP_L_EN;
break;
previous_power = power;
}
+static void cpcap_activate_whisper_emu_audio(struct cpcap_audio_state *state)
+{
+ struct cpcap_regacc reg_changes;
+
+ pr_debug("%s() called\n", __func__);
+
+ if (is_output_whisper_emu(state)) {
+ reg_changes.mask |= CPCAP_BIT_DIG_AUD_IN;
+ reg_changes.value = 0;
+ logged_cpcap_write(state->cpcap, CPCAP_REG_CDI,
+ reg_changes.value, reg_changes.mask);
+ }
+}
+
void cpcap_audio_state_dump(struct cpcap_audio_state *state)
{
pr_info("mode = %d", state->mode);
printk(KERN_INFO "0x20C[524] = %x\n", reg_val);
cpcap_regacc_read(state->cpcap, CPCAP_REG_A2LA, ®_val);
printk(KERN_INFO "0x20D[525] = %x\n", reg_val);
+ cpcap_regacc_read(state->cpcap, CPCAP_REG_USBC2, ®_val);
+ printk(KERN_INFO "0x381[897] = %x\n", reg_val);
}
static inline bool should_power_on(struct cpcap_audio_state *state)
cpcap_audio_configure_aud_mute(state, prev);
+ cpcap_activate_whisper_emu_audio(state);
+
if (!power_on)
cpcap_audio_configure_power(0);
NO_DOCK,
DESK_DOCK,
CAR_DOCK,
- MOBILE_DOCK,
- HD_DOCK,
+ LE_DOCK,
+ HE_DOCK,
};
struct cpcap_whisper_data {
struct switch_dev asdev; /* Audio switch */
struct switch_dev csdev; /* Invalid charger switch */
char dock_id[CPCAP_WHISPER_ID_SIZE];
+ char dock_prop[CPCAP_WHISPER_PROP_SIZE];
struct otg_transceiver *otg;
};
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");
+ case LE_DOCK:
+ return sprintf(buf, "LE\n");
+ case HE_DOCK:
+ return sprintf(buf, "HE\n");
}
return -EINVAL;
}
static DEVICE_ATTR(dock_addr, S_IRUGO | S_IWUSR, dock_id_show, NULL);
+static ssize_t dock_prop_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct switch_dev *dsdev = dev_get_drvdata(dev);
+ struct cpcap_whisper_data *data =
+ container_of(dsdev, struct cpcap_whisper_data, dsdev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", data->dock_prop);
+}
+static DEVICE_ATTR(dock_prop, S_IRUGO | S_IWUSR, dock_prop_show, NULL);
+
static void vusb_enable(struct cpcap_whisper_data *data)
{
if (!data->is_vusb_enabled) {
switch_set_state(&di->asdev, 0);
switch_set_state(&di->csdev, 0);
memset(di->dock_id, 0, CPCAP_WHISPER_ID_SIZE);
+ memset(di->dock_prop, 0, CPCAP_WHISPER_PROP_SIZE);
}
}
case SAMPLE_1:
get_sense(data);
data->state = SAMPLE_2;
- queue_delayed_work(data->wq, &data->work, msecs_to_jiffies(100));
+ queue_delayed_work(data->wq, &data->work,
+ msecs_to_jiffies(100));
break;
case SAMPLE_2:
} else
data->state = IDENTIFY;
- queue_delayed_work(data->wq, &data->work, msecs_to_jiffies(100));
+ queue_delayed_work(data->wq, &data->work,
+ msecs_to_jiffies(100));
break;
case IDENTIFY:
/* Special handling of USB undetect. */
data->state = USB;
- } else if ((data->sense & SENSE_USB_HOST_MASK) == SENSE_USB_HOST) {
+ } else if ((data->sense & SENSE_USB_HOST_MASK) ==
+ SENSE_USB_HOST) {
whisper_notify(data, CPCAP_ACCY_USB_HOST);
data->state = USB_POWER;
queue_delayed_work(di->wq, &(di->work), 0);
}
-int cpcap_accy_whisper(struct cpcap_device *cpcap, unsigned int cmd,
- char *dock_id)
+int cpcap_accy_whisper(struct cpcap_device *cpcap,
+ struct cpcap_whisper_request *req)
{
struct cpcap_whisper_data *di = cpcap->accydata;
int retval = -EAGAIN;
/* Can only change settings if not debouncing and whisper device
* is present. */
if (di->state == WHISPER) {
- if (cmd & CPCAP_WHISPER_ENABLE_UART)
+ if (req->cmd & CPCAP_WHISPER_ENABLE_UART)
value = CPCAP_BIT_EMUMODE0;
retval = cpcap_regacc_write(cpcap, CPCAP_REG_USBC2, value,
(CPCAP_BIT_EMUMODE2 |
CPCAP_BIT_EMUMODE1 |
CPCAP_BIT_EMUMODE0));
- value = (cmd & CPCAP_WHISPER_MODE_PU) ? CPCAP_BIT_ID100KPU : 0;
+ value = (req->cmd & CPCAP_WHISPER_MODE_PU) ?
+ CPCAP_BIT_ID100KPU : 0;
retval |= cpcap_regacc_write(cpcap, CPCAP_REG_USBC1,
value, CPCAP_BIT_ID100KPU);
if (value) {
}
/* Report dock type to system. */
- dock = (cmd & CPCAP_WHISPER_ACCY_MASK) >>
+ dock = (req->cmd & CPCAP_WHISPER_ACCY_MASK) >>
CPCAP_WHISPER_ACCY_SHFT;
- if (dock && (strlen(dock_id) < CPCAP_WHISPER_ID_SIZE))
- strncpy(di->dock_id, dock_id, CPCAP_WHISPER_ID_SIZE);
+ if (dock && (strlen(req->dock_id) < CPCAP_WHISPER_ID_SIZE))
+ strncpy(di->dock_id, req->dock_id,
+ CPCAP_WHISPER_ID_SIZE);
+ if (dock && (strlen(req->dock_prop) < CPCAP_WHISPER_PROP_SIZE))
+ strncpy(di->dock_prop, req->dock_prop,
+ CPCAP_WHISPER_PROP_SIZE);
switch_set_state(&di->dsdev, dock);
whisper_audio_check(di);
} else if (di->state == WHISPER_SMART) {
/* Report dock type to system. */
- dock = (cmd & CPCAP_WHISPER_ACCY_MASK) >>
+ dock = (req->cmd & CPCAP_WHISPER_ACCY_MASK) >>
CPCAP_WHISPER_ACCY_SHFT;
- if (dock && (strlen(dock_id) < CPCAP_WHISPER_ID_SIZE))
- strncpy(di->dock_id, dock_id, CPCAP_WHISPER_ID_SIZE);
+ if (dock && (strlen(req->dock_id) < CPCAP_WHISPER_ID_SIZE))
+ strncpy(di->dock_id, req->dock_id,
+ CPCAP_WHISPER_ID_SIZE);
+ if (dock && (strlen(req->dock_prop) < CPCAP_WHISPER_PROP_SIZE))
+ strncpy(di->dock_prop, req->dock_prop,
+ CPCAP_WHISPER_PROP_SIZE);
switch_set_state(&di->dsdev, dock);
retval = 0;
}
if (!switch_get_state(&whisper_di->dsdev))
return;
- state = ((state > 0) ? 1 : 0);
+ state = ((state > 0) ? 2 : 0);
switch_set_state(&whisper_di->asdev, state);
pr_info("%s: Audio cable %s present\n", __func__,
switch_dev_register(&data->dsdev);
retval = device_create_file(data->dsdev.dev, &dev_attr_dock_addr);
if (retval < 0) {
- dev_err(&pdev->dev, "Failed to create device file\n");
+ dev_err(&pdev->dev, "Failed to create dock_addr file\n");
goto free_mem;
}
+ retval = device_create_file(data->dsdev.dev, &dev_attr_dock_prop);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "Failed to create dock_prop file\n");
+ goto free_dock_id;
+ }
platform_set_drvdata(pdev, data);
dev_err(&pdev->dev,
"Could not get regulator for cpcap_whisper\n");
retval = PTR_ERR(data->regulator);
- goto free_dock_id;
+ goto free_dock_prop;
}
regulator_set_voltage(data->regulator, 3300000, 3300000);
cpcap_irq_free(data->cpcap, CPCAP_IRQ_IDFLOAT);
cpcap_irq_free(data->cpcap, CPCAP_IRQ_CHRG_DET);
regulator_put(data->regulator);
+free_dock_prop:
+ device_remove_file(data->dsdev.dev, &dev_attr_dock_prop);
free_dock_id:
device_remove_file(data->dsdev.dev, &dev_attr_dock_addr);
free_mem:
cancel_delayed_work_sync(&data->work);
destroy_workqueue(data->wq);
+ device_remove_file(data->dsdev.dev, &dev_attr_dock_prop);
device_remove_file(data->dsdev.dev, &dev_attr_dock_addr);
switch_dev_unregister(&data->wsdev);
switch_dev_unregister(&data->dsdev);