/*
 * ACPI DSDT table doesn't have correct PCI interrupt routing information
 * for some devices, so here we have a kernel workaround to fix this issue.
 * The workaround can be easily removed by not appending "vlv2" paramerter
 * to kernel command line.
 */
static int __init vlv2_pci_irq_fixup(void)
{
	/* HACK: intel_mid_identify_cpu() is not set yet */

	/* More hack: do cpuid instruction. This will be done here (helper is_valleyview) for now
	 * as temp w/a until reworked function is provided from Bin Gao.
	 */
	if (is_valleyview()) {
		pr_info("VLV2: fix up PCI interrupt routing\n");
		pcibios_enable_irq = vlv2_pci_enable_irq;
	}

	return 0;
}
Beispiel #2
0
static int snd_cht_mc_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = snd_soc_cards[0].soc_card;
	struct snd_soc_acpi_mach *mach;
	struct cht_mc_private *drv;
	const char *i2c_name = NULL;
	bool found = false;
	bool is_bytcr = false;
	int dai_index = 0;
	int ret_val = 0;
	int i;

	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
	if (!drv)
		return -ENOMEM;

	mach = (&pdev->dev)->platform_data;

	for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
		if (acpi_dev_found(snd_soc_cards[i].codec_id) &&
			(!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) {
			dev_dbg(&pdev->dev,
				"found codec %s\n", snd_soc_cards[i].codec_id);
			card = snd_soc_cards[i].soc_card;
			drv->acpi_card = &snd_soc_cards[i];
			found = true;
			break;
		}
	}

	if (!found) {
		dev_err(&pdev->dev, "No matching HID found in supported list\n");
		return -ENODEV;
	}

	card->dev = &pdev->dev;
	sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id);

	/* set correct codec name */
	for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
		if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) {
			card->dai_link[i].codec_name = drv->codec_name;
			dai_index = i;
		}

	/* fixup codec name based on HID */
	i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1);
	if (i2c_name) {
		snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name),
			"%s%s", "i2c-", i2c_name);
		cht_dailink[dai_index].codec_name = cht_rt5645_codec_name;
	}

	/*
	 * swap SSP0 if bytcr is detected
	 * (will be overridden if DMI quirk is detected)
	 */
	if (is_valleyview()) {
		if (mach->mach_params.acpi_ipc_irq_index == 0)
			is_bytcr = true;
	}

	if (is_bytcr) {
		/*
		 * Baytrail CR platforms may have CHAN package in BIOS, try
		 * to find relevant routing quirk based as done on Windows
		 * platforms. We have to read the information directly from the
		 * BIOS, at this stage the card is not created and the links
		 * with the codec driver/pdata are non-existent
		 */

		struct acpi_chan_package chan_package;

		/* format specified: 2 64-bit integers */
		struct acpi_buffer format = {sizeof("NN"), "NN"};
		struct acpi_buffer state = {0, NULL};
		struct snd_soc_acpi_package_context pkg_ctx;
		bool pkg_found = false;

		state.length = sizeof(chan_package);
		state.pointer = &chan_package;

		pkg_ctx.name = "CHAN";
		pkg_ctx.length = 2;
		pkg_ctx.format = &format;
		pkg_ctx.state = &state;
		pkg_ctx.data_valid = false;

		pkg_found = snd_soc_acpi_find_package_from_hid(mach->id,
							       &pkg_ctx);
		if (pkg_found) {
			if (chan_package.aif_value == 1) {
				dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n");
				cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF1;
			} else  if (chan_package.aif_value == 2) {
				dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n");
				cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
			} else {
				dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n");
				pkg_found = false;
			}
		}

		if (!pkg_found) {
			/* no BIOS indications, assume SSP0-AIF2 connection */
			cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2;
		}
	}

	/* check quirks before creating card */
	dmi_check_system(cht_rt5645_quirk_table);
	log_quirks(&pdev->dev);

	if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) ||
		(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {

		/* fixup codec aif name */
		snprintf(cht_rt5645_codec_aif_name,
			sizeof(cht_rt5645_codec_aif_name),
			"%s", "rt5645-aif2");

		cht_dailink[dai_index].codec_dai_name =
			cht_rt5645_codec_aif_name;
	}

	if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) ||
		(cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) {

		/* fixup cpu dai name name */
		snprintf(cht_rt5645_cpu_dai_name,
			sizeof(cht_rt5645_cpu_dai_name),
			"%s", "ssp0-port");

		cht_dailink[dai_index].cpu_dai_name =
			cht_rt5645_cpu_dai_name;
	}

	drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
	if (IS_ERR(drv->mclk)) {
		dev_err(&pdev->dev,
			"Failed to get MCLK from pmc_plt_clk_3: %ld\n",
			PTR_ERR(drv->mclk));
		return PTR_ERR(drv->mclk);
	}

	snd_soc_card_set_drvdata(card, drv);
	ret_val = devm_snd_soc_register_card(&pdev->dev, card);
	if (ret_val) {
		dev_err(&pdev->dev,
			"snd_soc_register_card failed %d\n", ret_val);
		return ret_val;
	}
	platform_set_drvdata(pdev, card);
	return ret_val;
}