Beispiel #1
0
static int archos_omap4_twl6040_init(struct snd_soc_pcm_runtime *rtd)
{
    struct snd_soc_codec *codec = rtd->codec;
    struct twl6040 *twl6040 = codec->control_data;
    struct snd_soc_dapm_context *dapm = &codec->dapm;
    int hsotrim, left_offset, right_offset, mode, ret;


    /* Add specific controls */
    ret = snd_soc_add_controls(codec, archos_omap4_controls,
                               ARRAY_SIZE(archos_omap4_controls));
    if (ret)
        return ret;

    /* Add specific widgets */
    ret = snd_soc_dapm_new_controls(dapm, archos_omap4_twl6040_dapm_widgets,
                                    ARRAY_SIZE(archos_omap4_twl6040_dapm_widgets));
    if (ret)
        return ret;

    /* Set up specific audio path audio_map */
    snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));

    /* Connected pins */
    snd_soc_dapm_enable_pin(dapm, "Ext Mic");
    snd_soc_dapm_enable_pin(dapm, "Ext Spk");
    snd_soc_dapm_enable_pin(dapm, "AFML");
    snd_soc_dapm_enable_pin(dapm, "AFMR");
    snd_soc_dapm_enable_pin(dapm, "Headset Mic");
    snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");

    /* allow audio paths from the audio modem to run during suspend */
    snd_soc_dapm_ignore_suspend(dapm, "Ext Mic");
    snd_soc_dapm_ignore_suspend(dapm, "Ext Spk");
    snd_soc_dapm_ignore_suspend(dapm, "AFML");
    snd_soc_dapm_ignore_suspend(dapm, "AFMR");
    snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
    snd_soc_dapm_ignore_suspend(dapm, "Headset Stereophone");
    snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 0");
    snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 1");
    snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 2");

    ret = snd_soc_dapm_sync(dapm);
    if (ret)
        return ret;

    /* Headset jack detection */
    ret = snd_soc_jack_new(codec, "Headset Jack",
                           SND_JACK_HEADSET, &hs_jack);
    if (ret)
        return ret;

    ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
                                hs_jack_pins);

    twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);

    /* DC offset cancellation computation */
    hsotrim = snd_soc_read(codec, TWL6040_REG_HSOTRIM);
    right_offset = (hsotrim & TWL6040_HSRO) >> TWL6040_HSRO_OFFSET;
    left_offset = hsotrim & TWL6040_HSLO;

    if (twl6040_get_icrev(twl6040) < TWL6040_REV_1_3)
        /* For ES under ES_1.3 HS step is 2 mV */
        mode = 2;
    else
        /* For ES_1.3 HS step is 1 mV */
        mode = 1;

    abe_dsp_set_hs_offset(left_offset, right_offset, mode);

    /* don't wait before switching of HS power */
    rtd->pmdown_time = 0;

    return ret;
}
static int __devinit twl6040_probe(struct platform_device *pdev)
{
	struct twl4030_codec_data *pdata = pdev->dev.platform_data;
	struct twl6040 *twl6040;
	struct mfd_cell *cell = NULL;
	unsigned int naudint;
	int audpwron;
	int ret, children = 0;
	u8 accctl;

	if(!pdata) {
		dev_err(&pdev->dev, "Platform data is missing\n");
		return -EINVAL;
	}

	twl6040 = kzalloc(sizeof(struct twl6040), GFP_KERNEL);
	if (!twl6040)
		return -ENOMEM;

	platform_set_drvdata(pdev, twl6040);

	twl6040->dev = &pdev->dev;
	mutex_init(&twl6040->mutex);
	mutex_init(&twl6040->io_mutex);

	twl6040->icrev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
	if (twl6040->icrev < 0) {
		ret = twl6040->icrev;
		goto gpio1_err;
	}

	if (pdata && (twl6040_get_icrev(twl6040) > TWL6040_REV_1_0))
		audpwron = pdata->audpwron_gpio;
	else
		audpwron = -EINVAL;

	if (pdata)
		naudint = pdata->naudint_irq;
	else
		naudint = 0;

	twl6040->audpwron = audpwron;
	twl6040->powered = 0;
	twl6040->irq = naudint;
	twl6040->irq_base = pdata->irq_base;
	init_completion(&twl6040->ready);

	if (gpio_is_valid(audpwron)) {
		ret = gpio_request(audpwron, "audpwron");
		if (ret)
			goto gpio1_err;

		ret = gpio_direction_output(audpwron, 0);
		if (ret)
			goto gpio2_err;
	}

	if (naudint) {
		/* codec interrupt */
		ret = twl6040_irq_init(twl6040);
		if (ret)
			goto gpio2_err;

		ret = twl6040_request_irq(twl6040, TWL6040_IRQ_READY,
				  twl6040_naudint_handler, "twl6040_irq_ready",
				  twl6040);
		if (ret) {
			dev_err(twl6040->dev, "READY IRQ request failed: %d\n",
				ret);
			goto irq_err;
		}
	}

	/* dual-access registers controlled by I2C only */
	accctl = twl6040_reg_read(twl6040, TWL6040_REG_ACCCTL);
	twl6040_reg_write(twl6040, TWL6040_REG_ACCCTL, accctl | TWL6040_I2CSEL);

	if (pdata->get_ext_clk32k) {
		ret = pdata->get_ext_clk32k();
		if (ret) {
			dev_err(twl6040->dev,
				"failed to get external 32kHz clock %d\n",
				ret);
			goto clk32k_err;
		}
	}

	if (pdata->audio) {
		cell = &twl6040->cells[children];
		cell->name = "twl6040-codec";
		cell->platform_data = pdata->audio;
		cell->pdata_size = sizeof(*pdata->audio);
		children++;
	}

	if (pdata->vibra) {
		cell = &twl6040->cells[children];
		cell->name = "twl6040-vibra";
		cell->platform_data = pdata->vibra;
		cell->pdata_size = sizeof(*pdata->vibra);
		children++;
	}

	if (children) {
		ret = mfd_add_devices(&pdev->dev, pdev->id, twl6040->cells,
				      children, NULL, 0);
		if (ret)
			goto mfd_err;
	} else {
		dev_err(&pdev->dev, "No platform data found for children\n");
		ret = -ENODEV;
		goto mfd_err;
	}

	return 0;

mfd_err:
	if (pdata->put_ext_clk32k)
		pdata->put_ext_clk32k();
clk32k_err:
	if (naudint)
		twl6040_free_irq(twl6040, TWL6040_IRQ_READY, twl6040);
irq_err:
	if (naudint)
		twl6040_irq_exit(twl6040);
gpio2_err:
	if (gpio_is_valid(audpwron))
		gpio_free(audpwron);
gpio1_err:
	platform_set_drvdata(pdev, NULL);
	kfree(twl6040);
	return ret;
}