int max97236_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) { struct max97236_priv *max97236 = snd_soc_codec_get_drvdata(codec); unsigned int reg; int test_value; int ret = -1; /* dev_info(codec->dev, "%s enter\n", __func__); */ if (jack) { max97236->jack = jack; max97236->jack_state = M97236_JACK_STATE_NONE; regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); #ifdef M97236_JACK_SWITCH_NORMALLY_CLOSED test_value = 4; #else test_value = 0; #endif /* Overwrite above code using board id */ if (board_info.board_id == BOARD_E1690) { test_value = 0; } else { /* ERS */ test_value = 4; } if ((reg & M97236_JACKSW_MASK) == test_value) { schedule_delayed_work(&max97236->jack_work, msecs_to_jiffies(25)); } else { /* headset detect feature WJ 21/01/14 */ max97236->jack_state = SND_JACK_HEADSET; /* headset detect feature WJ 21/01/14 end*/ /* Clear any interrupts then enable jack detection */ regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, ®); #ifdef MAX97236_AUTOMODE1_JACK_DETECTION max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); #else regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); if (verbosity) pr_info("%s: M97236_STATE_FLOAT set\n", __func__); max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); #endif /* headset detect feature WJ 21/01/14*/ schedule_delayed_work(&max97236->jack_work, msecs_to_jiffies(25)); } ret = 0; } return ret; }
static void test_jack_presence(struct max97236_priv *max97236, int delay) { unsigned int reg; int test_value; regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); #ifdef M97236_JACK_SWITCH_NORMALLY_CLOSED test_value = 4; #else test_value = 0; #endif if ((reg & M97236_JACKSW_MASK) == test_value) { schedule_delayed_work(&max97236->jack_work, msecs_to_jiffies(delay)); } else { /* report there is no headset */ snd_soc_jack_report(max97236->jack, M97236_JACK_STATE_NONE, SND_JACK_HEADSET | SND_JACK_LINEOUT); /* Clear any interrupts then enable jack detection */ regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, ®); #ifdef MAX97236_AUTOMODE1_JACK_DETECTION max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); #else regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); #endif } }
static int test_jack_presence(struct max97236_priv *max97236, int delay) { unsigned int reg; int test_value; int ret = 0; regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); #ifdef M97236_JACK_SWITCH_NORMALLY_CLOSED test_value = 4; #else test_value = 0; #endif /* Overwrite above code using board id */ if (board_info.board_id == BOARD_E1690) { test_value = 0; } else { /* ERS */ test_value = 4; } if ((reg & M97236_JACKSW_MASK) == test_value) { schedule_delayed_work(&max97236->jack_work, msecs_to_jiffies(delay)); } else { ret = 1; /* Clear any interrupts then enable jack detection */ regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, ®); #ifdef MAX97236_AUTOMODE1_JACK_DETECTION max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); #else /* clear /FORCE bit to ensure hi-Z configures correctly */ regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_FORCEN_MASK); /* now set hi-Z */ regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); if (verbosity) pr_info("%s: M97236_STATE_FLOAT set\n", __func__); max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); #endif } return ret; }
static void max97236_jack_event(struct max97236_priv *max97236) { unsigned int status_reg[3]; regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); /* Key press or jack removal? */ if ((status_reg[0] & M97236_IMBH_MASK) || (status_reg[0] & M97236_IMCSW_MASK) || (status_reg[1] & M97236_IKEY_MASK)) { max97236_keypress(max97236, status_reg); } else { if (max97236_jacksw_active(max97236)) goto max97236_jack_event_10; regmap_update_bits(max97236->regmap, M97236_REG_07_LEFT_VOLUME, M97236_MUTEL_MASK, M97236_MUTEL_MASK); regmap_update_bits(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, M97236_MUTER_MASK, M97236_MUTER_MASK); regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, 0); status_reg[0] = 0; status_reg[1] = 0; status_reg[2] = 0; max97236_report_jack_state(max97236, status_reg); } max97236_jack_event_10: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); return; }
static void max97236_jack_event(struct max97236_priv *max97236) { unsigned int status_reg[3]; int count; regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); /* First check for a key press */ if (((status_reg[0] & M97236_IMBH_MASK) || (status_reg[0] & M97236_IMCSW_MASK) || (status_reg[1] & M97236_IKEY_MASK)) && (status_reg[0] & 0x80)) { max97236_keypress(max97236, status_reg); } else { if (max97236_jacksw_active(max97236)) goto max97236_jack_event_10; count = 30; do { msleep(20); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); } while (((status_reg[0] & 0x80) == 0x80) && --count); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); regmap_read(max97236->regmap, M97236_REG_02_STATUS3, &status_reg[2]); /* test for jack switch malfunction indication */ if ((status_reg[1] & M97236_IJACKSWINC_MASK) && (status_reg[0] & 0x80)) pr_err("JACKSWINC set\n"); max97236_report_jack_state(max97236, status_reg); if (max97236->jack_state == M97236_JACK_STATE_NONE) { regmap_update_bits(max97236->regmap, M97236_REG_07_LEFT_VOLUME, M97236_MUTEL_MASK, M97236_MUTEL_MASK); regmap_update_bits(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, M97236_MUTER_MASK, M97236_MUTER_MASK); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, 0); } } max97236_jack_event_10: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); return; }
static int max97236_soc_resume(struct snd_soc_codec *codec) { struct max97236_priv *max97236 = snd_soc_codec_get_drvdata(codec); struct snd_soc_card *card = codec->card; unsigned int reg, i; for (i = 0; i < card->num_links; i++) if (card->dai_link[i].ignore_suspend) return 0; /*max97236_reset(max97236);*/ max97236_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Clear any interrupts then enable jack detection */ regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, ®); #ifdef MAX97236_AUTOMODE1_JACK_DETECTION max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); #else max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); #endif max97236_mic_detect(codec, max97236->jack); if (gpio_is_valid(max97236->irq)) enable_irq(gpio_to_irq(max97236->irq)); regmap_read(max97236->regmap, M97236_REG_07_LEFT_VOLUME, ®); regmap_write(max97236->regmap, M97236_REG_07_LEFT_VOLUME, reg); regmap_read(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, ®); regmap_write(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, reg); return 0; }
static void max97236_jack_plugged(struct max97236_priv *max97236) { unsigned int status_reg[3]; int count; if (!max97236_jacksw_active(max97236)) goto max97236_jack_plugged_20; msleep(250); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, M97236_SHDNN_MASK); max97236_jack_plugged_10: max97236_reset(max97236); count = M97236_DEFAULT_JACK_DETECT_DELAY; do { msleep(20); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); } while (((status_reg[0] & M97236_DDONE_MASK) != M97236_DDONE_MASK) && --count); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); regmap_read(max97236->regmap, M97236_REG_02_STATUS3, &status_reg[2]); pr_info("%s: status 0x%02X, 0x%02X, count %d\n", __func__, status_reg[0], status_reg[1], count); max97236_report_jack_state(max97236, status_reg); if (!max97236_jacksw_active(max97236)) { goto max97236_jack_plugged_10; } if (max97236->jack_state == SND_JACK_HEADSET) max97236->ignore_int = 1; max97236_jack_plugged_20: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); }
static void max97236_jack_plugged(struct max97236_priv *max97236) { unsigned int status_reg[3] = {0, 0, 0}; int retries = M97236_DEFAULT_RETRIES; int force_value = 0; int count; wake_lock(&wakelock); /* Check for spurious interrupt */ if (!max97236_jacksw_active(max97236)) { max97236_jack_event(max97236); goto max97236_jack_plugged_30; } #if 1 /* Start debounce while periodically verifying jack presence */ for (count = 0; count < 24; count++) { msleep(40); if (!max97236_jacksw_active(max97236)) { max97236_jack_event(max97236); goto max97236_jack_plugged_30; } } #else msleep(750); #endif max97236_jack_plugged_10: if (!max97236_jacksw_active(max97236)) { max97236_jack_event(max97236); goto max97236_jack_plugged_30; } max97236_begin_detect(max97236); count = 10; do { msleep(20); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); } while (((status_reg[0] & 0x40) != 0x40) && --count); status_reg[0] = max97236_get_detect_result(max97236); max97236_translate_detected(status_reg, &force_value); if(retries<5 && status_reg[1] == 0xCC && status_reg[2] == 0xCC){ if (status_reg[0] & 0x08) { force_value = 0x02; status_reg[0] = 0x8c; status_reg[1] = 0x30; status_reg[2] = 0x03; }else{ force_value = 0x12; status_reg[0] = 0x84; status_reg[1] = 0x30; status_reg[2] = 0x03; } }else if(status_reg[1] == 0xCC && status_reg[2] == 0xCC){ status_reg[0] = 0x0; } if (status_reg[0] != 0) { regmap_write(max97236->regmap, M97236_REG_20_TEST_ENABLE_2, 0x00); regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, force_value); regmap_update_bits(max97236->regmap, M97236_REG_19_STATE_FORCING, 0x20, 0x00); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, M97236_SHDNN_MASK); } else { max97236_end_detect(max97236); if (--retries) goto max97236_jack_plugged_10; } max97236_jack_plugged_20: max97236_report_jack_state(max97236, status_reg); max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); if (max97236->jack_state == SND_JACK_HEADSET) max97236_ignore_key_ints(max97236); if ((max97236->jack_state == M97236_JACK_STATE_NONE) || (max97236->jack_state == M97236_JACK_STATE_UNKNOWN)) { if (verbosity) pr_info("%s: M97236_STATE_FLOAT set\n", __func__); regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); } else { if (!max97236_jacksw_active(max97236)) { status_reg[0] = 0; status_reg[1] = 0; goto max97236_jack_plugged_20; } } wake_unlock(&wakelock); return; max97236_jack_plugged_30: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); wake_unlock(&wakelock); }
static void max97236_jack_event(struct max97236_priv *max97236) { unsigned int status_reg[3]; int i; int test_value = 0; wake_lock(&wakelock_h); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); /* Overwrite above code using board id */ if (board_info.board_id == BOARD_E1690) { test_value = 0; } else { /* ERS */ test_value = 4; } /* Key press or jack removal? */ /* For Key press, it need make sure it is headset connected */ for (i = 0; i < 4; i++) { if ((status_reg[0] & M97236_JACKSW_MASK) == test_value) { break; } else { msleep(20); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, &status_reg[1]); } } if (((status_reg[0] & M97236_IMBH_MASK) || (status_reg[0] & M97236_IMCSW_MASK) || (status_reg[1] & M97236_IKEY_MASK)) && (status_reg[0] & M97236_JACKSW_MASK) == test_value) { /* headset detect feature WJ 21/01/14 */ if (max97236_jacksw_active(max97236)){ max97236_keypress(max97236, status_reg); }else{ regmap_update_bits(max97236->regmap, M97236_REG_07_LEFT_VOLUME, M97236_MUTEL_MASK, M97236_MUTEL_MASK); regmap_update_bits(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, M97236_MUTER_MASK, M97236_MUTER_MASK); regmap_write(max97236->regmap, M97236_REG_23_TEST_DATA_3, 0x00); regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, 0); status_reg[0] = 0; status_reg[1] = 0; status_reg[2] = 0; max97236_report_jack_state(max97236, status_reg); } /* headset detect feature WJ 21/01/14 end*/ } else { if (max97236_jacksw_active(max97236)) goto max97236_jack_event_10; regmap_update_bits(max97236->regmap, M97236_REG_07_LEFT_VOLUME, M97236_MUTEL_MASK, M97236_MUTEL_MASK); regmap_update_bits(max97236->regmap, M97236_REG_08_RIGHT_VOLUME, M97236_MUTER_MASK, M97236_MUTER_MASK); regmap_write(max97236->regmap, M97236_REG_23_TEST_DATA_3, 0x00); regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); if (verbosity) pr_info("%s: M97236_STATE_FLOAT set\n", __func__); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, 0); status_reg[0] = 0; status_reg[1] = 0; status_reg[2] = 0; max97236_report_jack_state(max97236, status_reg); } max97236_jack_event_10: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); wake_unlock(&wakelock_h); return; }
static int max97236_probe(struct snd_soc_codec *codec) { struct max97236_priv *max97236 = snd_soc_codec_get_drvdata(codec); unsigned int reg; int ret; #ifdef MAX97236_AUTOMODE1_JACK_DETECTION dev_info(codec->dev, "built on %s at %s, mode is DETECT1\n", __DATE__, __TIME__); #else dev_info(codec->dev, "built on %s at %s, mode is DETECT0\n", __DATE__, __TIME__); #endif dev_info(codec->dev, "build number %s\n", MAX97236_REVISION); max97236->codec = codec; codec->control_data = max97236->regmap; codec->dapm.idle_bias_off = 1; codec->cache_sync = 1; max97236->jack_state = M97236_JACK_STATE_UNKNOWN; clk_cdev1 = clk_get_sys("extern1", NULL); ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); goto err_access; } /* Disable all interrupts until we're ready to handle them */ regmap_write(max97236->regmap, M97236_REG_04_IRQ_MASK1, 0x00); regmap_write(max97236->regmap, M97236_REG_05_IRQ_MASK2, 0x00); regmap_write(max97236->regmap, M97236_REG_09_MICROPHONE, M97236_BIAS_MASK); regmap_write(max97236->regmap, M97236_REG_16_KEYSCAN_DELAY, 0x18); ret = regmap_read(max97236->regmap, M97236_REG_0B_REV_ID, ®); if (ret < 0) { dev_err(codec->dev, "Cannot read device version: %d\n", ret); goto err_access; } reg >>= M97236_ID_SHIFT; dev_info(codec->dev, "MAX97236 Vendor ID = 0x%02x\n", reg); if (reg == M97236_REVA) { max97236->devtype = MAX97236; } else { dev_err(codec->dev, "Unrecognized device 0x%02X\n", reg); ret = -1; goto err_access; } /* configure clock divider registers */ max97236_set_clk_dividers(max97236); dev_info(codec->dev, "gpio = %d\n", max97236->irq); /* Register for interrupts */ if (max97236->irq) { ret = gpio_request(max97236->irq, "max97236_hs_irq"); if (ret) dev_err(codec->dev, "failed to allocate gpio\n"); gpio_direction_input(max97236->irq); /* register an audio interrupt */ ret = request_threaded_irq(gpio_to_irq(max97236->irq), NULL, max97236_interrupt, IRQF_TRIGGER_FALLING, "max97236_interrupt", codec); if (ret) dev_err(codec->dev, "Failed to request IRQ: %d\n", ret); } max97236->ignore_int = 0; INIT_DELAYED_WORK(&max97236->jack_work, max97236_jack_work); wake_lock_init(&jack_key_lock , WAKE_LOCK_SUSPEND, "jack key wake lock" ); /* Clear any interrupts then enable jack detection */ regmap_read(max97236->regmap, M97236_REG_00_STATUS1, ®); regmap_read(max97236->regmap, M97236_REG_01_STATUS2, ®); #ifdef MAX97236_AUTOMODE1_JACK_DETECTION max97236_configure_for_detection(max97236, M97236_AUTO_MODE_1); #else max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); #endif max97236_handle_pdata(codec); max97236_add_widgets(codec); wake_lock_init(&wakelock, WAKE_LOCK_SUSPEND, "headset detect"); wake_lock_init(&wakelock_h, WAKE_LOCK_SUSPEND, "headset event detect"); err_access: return ret; }
static void max97236_jack_plugged(struct max97236_priv *max97236) { unsigned int status_reg[3] = {0, 0, 0}; int retries = M97236_DEFAULT_RETRIES; int test_number = 1; int force_value = 0; int count; /* Check for spurious interrupt */ if (!max97236_jacksw_active(max97236)) goto max97236_jack_plugged_30; /* Start debounce while periodically verifying jack presence */ for (count = 0; count < 24; count++) { msleep(20); if (!max97236_jacksw_active(max97236)) goto max97236_jack_plugged_30; } max97236_jack_plugged_10: if (!max97236_jacksw_active(max97236)) goto max97236_jack_plugged_30; max97236_begin_detect(max97236, test_number); count = 10; do { msleep(20); regmap_read(max97236->regmap, M97236_REG_00_STATUS1, &status_reg[0]); } while (((status_reg[0] & 0x40) != 0x40) && --count); status_reg[0] = max97236_get_detect_result(max97236); max97236_translate_detected(status_reg, &force_value); max97236_end_detect(max97236); if (status_reg[0] != 0) { regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, force_value); regmap_update_bits(max97236->regmap, M97236_REG_19_STATE_FORCING, 0x20, 0x00); regmap_update_bits(max97236->regmap, M97236_REG_1D_ENABLE_1, M97236_SHDNN_MASK, M97236_SHDNN_MASK); } else { if (--retries) { goto max97236_jack_plugged_10; } regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, force_value); regmap_update_bits(max97236->regmap, M97236_REG_19_STATE_FORCING, 0x20, 0x00); } max97236_jack_plugged_20: max97236_report_jack_state(max97236, status_reg); max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); if (max97236->jack_state == SND_JACK_HEADSET) #ifdef IGNORE_KEY_INT_FUNCTION_ENABLED max97236_ignore_key_ints(max97236); #else max97236->ignore_int = 1; #endif if ((max97236->jack_state == M97236_JACK_STATE_NONE) || (max97236->jack_state == M97236_JACK_STATE_UNKNOWN)) { regmap_write(max97236->regmap, M97236_REG_19_STATE_FORCING, M97236_STATE_FLOAT); } else { if (!max97236_jacksw_active(max97236)) { status_reg[0] = 0; status_reg[1] = 0; goto max97236_jack_plugged_20; } } return; max97236_jack_plugged_30: max97236_configure_for_detection(max97236, M97236_AUTO_MODE_0); }