static int tegra_devfreq_probe()

in tegra30-devfreq.c [824:929]


static int tegra_devfreq_probe(struct platform_device *pdev)
{
	u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
	struct tegra_devfreq_device *dev;
	struct tegra_devfreq *tegra;
	struct devfreq *devfreq;
	unsigned int i;
	long rate;
	int err;

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

	tegra->soc = of_device_get_match_data(&pdev->dev);

	tegra->regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(tegra->regs))
		return PTR_ERR(tegra->regs);

	tegra->reset = devm_reset_control_get(&pdev->dev, "actmon");
	if (IS_ERR(tegra->reset)) {
		dev_err(&pdev->dev, "Failed to get reset\n");
		return PTR_ERR(tegra->reset);
	}

	tegra->clock = devm_clk_get(&pdev->dev, "actmon");
	if (IS_ERR(tegra->clock)) {
		dev_err(&pdev->dev, "Failed to get actmon clock\n");
		return PTR_ERR(tegra->clock);
	}

	tegra->emc_clock = devm_clk_get(&pdev->dev, "emc");
	if (IS_ERR(tegra->emc_clock))
		return dev_err_probe(&pdev->dev, PTR_ERR(tegra->emc_clock),
				     "Failed to get emc clock\n");

	err = platform_get_irq(pdev, 0);
	if (err < 0)
		return err;

	tegra->irq = err;

	irq_set_status_flags(tegra->irq, IRQ_NOAUTOEN);

	err = devm_request_threaded_irq(&pdev->dev, tegra->irq, NULL,
					actmon_thread_isr, IRQF_ONESHOT,
					"tegra-devfreq", tegra);
	if (err) {
		dev_err(&pdev->dev, "Interrupt request failed: %d\n", err);
		return err;
	}

	err = devm_pm_opp_set_supported_hw(&pdev->dev, &hw_version, 1);
	if (err) {
		dev_err(&pdev->dev, "Failed to set supported HW: %d\n", err);
		return err;
	}

	err = devm_pm_opp_of_add_table_noclk(&pdev->dev, 0);
	if (err) {
		dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
		return err;
	}

	err = devm_tegra_devfreq_init_hw(&pdev->dev, tegra);
	if (err)
		return err;

	rate = clk_round_rate(tegra->emc_clock, ULONG_MAX);
	if (rate <= 0) {
		dev_err(&pdev->dev, "Failed to round clock rate: %ld\n", rate);
		return rate ?: -EINVAL;
	}

	tegra->max_freq = rate / KHZ;

	for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
		dev = tegra->devices + i;
		dev->config = tegra->soc->configs + i;
		dev->regs = tegra->regs + dev->config->offset;
	}

	platform_set_drvdata(pdev, tegra);

	tegra->clk_rate_change_nb.notifier_call = tegra_actmon_clk_notify_cb;
	tegra->cpu_rate_change_nb.notifier_call = tegra_actmon_cpu_notify_cb;

	INIT_DELAYED_WORK(&tegra->cpufreq_update_work,
			  tegra_actmon_delayed_update);

	err = devm_devfreq_add_governor(&pdev->dev, &tegra_devfreq_governor);
	if (err) {
		dev_err(&pdev->dev, "Failed to add governor: %d\n", err);
		return err;
	}

	tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock);

	devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
					  "tegra_actmon", NULL);
	if (IS_ERR(devfreq))
		return PTR_ERR(devfreq);

	return 0;
}