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;
}