unsigned long rpres_get_max_freq(struct rpres *obj) { struct platform_device *pdev = obj->pdev; struct opp *opp; unsigned long maxfreq = ULONG_MAX; rcu_read_lock(); opp = opp_find_freq_floor(&pdev->dev, &maxfreq); if (IS_ERR(opp)) maxfreq = 0; rcu_read_unlock(); return maxfreq; }
struct opp *step_down(struct busfreq_data *data, int step) { int i; struct opp *opp = data->curr_opp; unsigned long newfreq; if (data->min_opp == data->curr_opp) return data->curr_opp; for (i = 0; i < step; i++) { newfreq = opp_get_freq(opp) - 1; opp = opp_find_freq_floor(data->dev, &newfreq); if (opp == data->min_opp) break; } return opp; }
int g3_display_probe(struct platform_device *pdev){ struct g3_display_data *data; struct device *dev = &pdev->dev; int ret = 0; struct opp *opp; int i; data = kzalloc(sizeof(struct g3_display_data), GFP_KERNEL); if(!data){ dev_err(dev, "cannot_allocate memory.\n"); return -ENOMEM; } data->dev = dev; mutex_init(&data->lock); /* register opp entries */ for(i=0; i<_LV_END_; i++){ ret = opp_add(dev, g3_display_opp_table[i].freq, g3_display_opp_table[i].volt); if(ret){ dev_err(dev, "cannot add opp entries.\n"); goto err_alloc_mem; } } /* find opp entry with init frequency */ opp = opp_find_freq_floor(dev, &g3_display_profile.initial_freq); if(IS_ERR(opp)){ dev_err(dev, "invalid initial frequency %lu.\n", g3_display_profile.initial_freq); ret = PTR_ERR(opp); goto err_alloc_mem; } data->curr_opp = opp; /* initialize qos */ // TODO /* register g3_display to devfreq framework */ data->devfreq = devfreq_add_device(dev, &g3_display_profile, "simple_ondemand", &g3_display_ondemand_data); if(IS_ERR(data->devfreq)){ ret = PTR_ERR(data->devfreq); dev_err(dev, "failed to add devfreq: %d\n", ret); goto err_alloc_mem; } devfreq_register_opp_notifier(dev, data->devfreq); /* register g3_display as client to pm notifier */ memset(&data->nb_pm, 0, sizeof(data->nb_pm)); data->nb_pm.notifier_call = g3_display_pm_notifier_callback; ret = register_pm_notifier(&data->nb_pm); if(ret < 0){ dev_err(dev, "failed to get pm notifier: %d\n", ret); goto err_add_devfreq; } platform_set_drvdata(pdev, data); return 0; err_add_devfreq: devfreq_remove_device(data->devfreq); err_alloc_mem: kfree(data); return ret; }
int exynos5250_init(struct device *dev, struct busfreq_data *data) { unsigned int i, tmp; unsigned long maxfreq = ULONG_MAX; unsigned long minfreq = 0; unsigned long cdrexfreq; unsigned long lrbusfreq; struct clk *clk; int ret; /* Enable pause function for DREX2 DVFS */ drex2_pause_ctrl = __raw_readl(EXYNOS5_DREX2_PAUSE); drex2_pause_ctrl |= DMC_PAUSE_ENABLE; __raw_writel(drex2_pause_ctrl, EXYNOS5_DREX2_PAUSE); clk = clk_get(NULL, "mclk_cdrex"); if (IS_ERR(clk)) { dev_err(dev, "Fail to get mclk_cdrex clock"); ret = PTR_ERR(clk); return ret; } cdrexfreq = clk_get_rate(clk) / 1000; clk_put(clk); clk = clk_get(NULL, "aclk_266"); if (IS_ERR(clk)) { dev_err(dev, "Fail to get aclk_266 clock"); ret = PTR_ERR(clk); return ret; } lrbusfreq = clk_get_rate(clk) / 1000; clk_put(clk); if (cdrexfreq == 800000) { clkdiv_cdrex = clkdiv_cdrex_for800; exynos5_busfreq_table_mif = exynos5_busfreq_table_for800; exynos5_mif_volt = exynos5_mif_volt_for800; } else if (cdrexfreq == 666857) { clkdiv_cdrex = clkdiv_cdrex_for667; exynos5_busfreq_table_mif = exynos5_busfreq_table_for667; exynos5_mif_volt = exynos5_mif_volt_for667; } else if (cdrexfreq == 533000) { clkdiv_cdrex = clkdiv_cdrex_for533; exynos5_busfreq_table_mif = exynos5_busfreq_table_for533; exynos5_mif_volt = exynos5_mif_volt_for533; } else if (cdrexfreq == 400000) { clkdiv_cdrex = clkdiv_cdrex_for400; exynos5_busfreq_table_mif = exynos5_busfreq_table_for400; exynos5_mif_volt = exynos5_mif_volt_for400; } else { dev_err(dev, "Don't support cdrex table\n"); return -EINVAL; } tmp = __raw_readl(EXYNOS5_CLKDIV_LEX); for (i = LV_0; i < LV_INT_END; i++) { tmp &= ~(EXYNOS5_CLKDIV_LEX_ATCLK_LEX_MASK | EXYNOS5_CLKDIV_LEX_PCLK_LEX_MASK); tmp |= ((clkdiv_lex[i][0] << EXYNOS5_CLKDIV_LEX_ATCLK_LEX_SHIFT) | (clkdiv_lex[i][1] << EXYNOS5_CLKDIV_LEX_PCLK_LEX_SHIFT)); data->lex_divtable[i] = tmp; } tmp = __raw_readl(EXYNOS5_CLKDIV_R0X); for (i = LV_0; i < LV_INT_END; i++) { tmp &= ~EXYNOS5_CLKDIV_R0X_PCLK_R0X_MASK; tmp |= (clkdiv_r0x[i][0] << EXYNOS5_CLKDIV_R0X_PCLK_R0X_SHIFT); data->r0x_divtable[i] = tmp; } tmp = __raw_readl(EXYNOS5_CLKDIV_R1X); for (i = LV_0; i < LV_INT_END; i++) { tmp &= ~EXYNOS5_CLKDIV_R1X_PCLK_R1X_MASK; tmp |= (clkdiv_r1x[i][0] << EXYNOS5_CLKDIV_R1X_PCLK_R1X_SHIFT); data->r1x_divtable[i] = tmp; } tmp = __raw_readl(EXYNOS5_CLKDIV_CDREX); if (samsung_rev() < EXYNOS5250_REV_1_0) { for (i = LV_0; i < LV_MIF_END; i++) { tmp &= ~(EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_MASK | EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_CLK400_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_C2C200_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_MASK); tmp |= ((clkdiv_cdrex[i][0] << EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_SHIFT) | (clkdiv_cdrex[i][1] << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_SHIFT) | (clkdiv_cdrex[i][2] << EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_SHIFT) | (clkdiv_cdrex[i][3] << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_SHIFT) | (clkdiv_cdrex[i][4] << EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_SHIFT) | (clkdiv_cdrex[i][5] << EXYNOS5_CLKDIV_CDREX_ACLK_CLK400_SHIFT) | (clkdiv_cdrex[i][6] << EXYNOS5_CLKDIV_CDREX_ACLK_C2C200_SHIFT) | (clkdiv_cdrex[i][8] << EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_SHIFT)); data->cdrex_divtable[i] = tmp; } } else { for (i = LV_0; i < LV_MIF_END; i++) { tmp &= ~(EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_MASK | EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_MASK | EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_MASK); tmp |= ((clkdiv_cdrex[i][0] << EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_SHIFT) | (clkdiv_cdrex[i][1] << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_SHIFT) | (clkdiv_cdrex[i][2] << EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_SHIFT) | (clkdiv_cdrex[i][3] << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_SHIFT) | (clkdiv_cdrex[i][4] << EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_SHIFT) | (clkdiv_cdrex[i][8] << EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_SHIFT)); data->cdrex_divtable[i] = tmp; } } if (samsung_rev() < EXYNOS5250_REV_1_0) { tmp = __raw_readl(EXYNOS5_CLKDIV_CDREX2); for (i = LV_0; i < LV_MIF_END; i++) { tmp &= ~EXYNOS5_CLKDIV_CDREX2_MCLK_EFPHY_MASK; tmp |= clkdiv_cdrex[i][7] << EXYNOS5_CLKDIV_CDREX2_MCLK_EFPHY_SHIFT; data->cdrex2_divtable[i] = tmp; } } exynos5250_set_bus_volt(); data->dev[PPMU_MIF] = dev; data->dev[PPMU_INT] = &busfreq_for_int; for (i = LV_0; i < LV_MIF_END; i++) { ret = opp_add(data->dev[PPMU_MIF], exynos5_busfreq_table_mif[i].mem_clk, exynos5_busfreq_table_mif[i].volt); if (ret) { dev_err(dev, "Fail to add opp entries.\n"); return ret; } } #if defined(CONFIG_DP_60HZ_P11) || defined(CONFIG_DP_60HZ_P10) if (cdrexfreq == 666857) { opp_disable(data->dev[PPMU_MIF], 334000); opp_disable(data->dev[PPMU_MIF], 110000); } else if (cdrexfreq == 533000) { opp_disable(data->dev[PPMU_MIF], 267000); opp_disable(data->dev[PPMU_MIF], 107000); } else if (cdrexfreq == 400000) { opp_disable(data->dev[PPMU_MIF], 267000); opp_disable(data->dev[PPMU_MIF], 100000); } #endif for (i = LV_0; i < LV_INT_END; i++) { ret = opp_add(data->dev[PPMU_INT], exynos5_busfreq_table_int[i].mem_clk, exynos5_busfreq_table_int[i].volt); if (ret) { dev_err(dev, "Fail to add opp entries.\n"); return ret; } } data->target = exynos5250_target; data->get_table_index = exynos5250_get_table_index; data->monitor = exynos5250_monitor; data->busfreq_suspend = exynos5250_suspend; data->busfreq_resume = exynos5250_resume; data->sampling_rate = usecs_to_jiffies(100000); data->table[PPMU_MIF] = exynos5_busfreq_table_mif; data->table[PPMU_INT] = exynos5_busfreq_table_int; /* Find max frequency for mif */ data->max_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_floor(data->dev[PPMU_MIF], &maxfreq)); data->min_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_MIF], &minfreq)); data->curr_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_MIF], &cdrexfreq)); /* Find max frequency for int */ maxfreq = ULONG_MAX; minfreq = 0; data->max_freq[PPMU_INT] = opp_get_freq(opp_find_freq_floor(data->dev[PPMU_INT], &maxfreq)); data->min_freq[PPMU_INT] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_INT], &minfreq)); data->curr_freq[PPMU_INT] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_INT], &lrbusfreq)); data->vdd_reg[PPMU_INT] = regulator_get(NULL, "vdd_int"); if (IS_ERR(data->vdd_reg[PPMU_INT])) { pr_err("failed to get resource %s\n", "vdd_int"); return -ENODEV; } data->vdd_reg[PPMU_MIF] = regulator_get(NULL, "vdd_mif"); if (IS_ERR(data->vdd_reg[PPMU_MIF])) { pr_err("failed to get resource %s\n", "vdd_mif"); regulator_put(data->vdd_reg[PPMU_INT]); return -ENODEV; } data->busfreq_early_suspend_handler.suspend = &busfreq_early_suspend; data->busfreq_early_suspend_handler.resume = &busfreq_late_resume; data->busfreq_early_suspend_handler.suspend = &busfreq_early_suspend; data->busfreq_early_suspend_handler.resume = &busfreq_late_resume; /* Request min 300MHz for MIF and 150MHz for INT*/ dev_lock(dev, dev, 300150); register_early_suspend(&data->busfreq_early_suspend_handler); tmp = __raw_readl(EXYNOS5_ABBG_INT_CONTROL); tmp &= ~(0x1f | (1 << 31) | (1 << 7)); tmp |= ((8 + INT_RBB) | (1 << 31) | (1 << 7)); __raw_writel(tmp, EXYNOS5_ABBG_INT_CONTROL); return 0; }
int exynos5250_init(struct device *dev, struct busfreq_data *data) { unsigned int i; unsigned long maxfreq = ULONG_MAX; unsigned long minfreq = 0; unsigned long cdrexfreq; unsigned long lrbusfreq; struct clk *clk; int ret; /* Enable pause function for DREX2 DVFS */ dmc_pause_ctrl = __raw_readl(EXYNOS5_DMC_PAUSE_CTRL); dmc_pause_ctrl |= DMC_PAUSE_ENABLE; __raw_writel(dmc_pause_ctrl, EXYNOS5_DMC_PAUSE_CTRL); clk = clk_get(NULL, "mout_cdrex"); if (IS_ERR(clk)) { dev_err(dev, "Fail to get mclk_cdrex clock"); ret = PTR_ERR(clk); return ret; } cdrexfreq = clk_get_rate(clk) / 1000; clk_put(clk); clk = clk_get(NULL, "aclk_266"); if (IS_ERR(clk)) { dev_err(dev, "Fail to get aclk_266 clock"); ret = PTR_ERR(clk); return ret; } lrbusfreq = clk_get_rate(clk) / 1000; clk_put(clk); if (cdrexfreq == 800000) { clkdiv_cdrex = clkdiv_cdrex_for800; exynos5_busfreq_table_mif = exynos5_busfreq_table_for800; exynos5_mif_volt = exynos5_mif_volt_for800; } else if (cdrexfreq == 666857) { clkdiv_cdrex = clkdiv_cdrex_for667; exynos5_busfreq_table_mif = exynos5_busfreq_table_for667; exynos5_mif_volt = exynos5_mif_volt_for667; } else if (cdrexfreq == 533000) { clkdiv_cdrex = clkdiv_cdrex_for533; exynos5_busfreq_table_mif = exynos5_busfreq_table_for533; exynos5_mif_volt = exynos5_mif_volt_for533; } else if (cdrexfreq == 400000) { clkdiv_cdrex = clkdiv_cdrex_for400; exynos5_busfreq_table_mif = exynos5_busfreq_table_for400; exynos5_mif_volt = exynos5_mif_volt_for400; } else { dev_err(dev, "Don't support cdrex table\n"); return -EINVAL; } exynos5250_set_bus_volt(); data->dev[PPMU_MIF] = dev; data->dev[PPMU_INT] = &busfreq_for_int; for (i = LV_0; i < LV_MIF_END; i++) { ret = opp_add(data->dev[PPMU_MIF], exynos5_busfreq_table_mif[i].mem_clk, exynos5_busfreq_table_mif[i].volt); if (ret) { dev_err(dev, "Fail to add opp entries.\n"); return ret; } } opp_disable(data->dev[PPMU_MIF], 107000); for (i = LV_0; i < LV_INT_END; i++) { ret = opp_add(data->dev[PPMU_INT], exynos5_busfreq_table_int[i].mem_clk, exynos5_busfreq_table_int[i].volt); if (ret) { dev_err(dev, "Fail to add opp entries.\n"); return ret; } } data->target = exynos5250_target; data->get_table_index = exynos5250_get_table_index; data->monitor = exynos5250_monitor; data->busfreq_suspend = exynos5250_suspend; data->busfreq_resume = exynos5250_resume; data->sampling_rate = usecs_to_jiffies(100000); data->table[PPMU_MIF] = exynos5_busfreq_table_mif; data->table[PPMU_INT] = exynos5_busfreq_table_int; /* Find max frequency for mif */ data->max_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_floor(data->dev[PPMU_MIF], &maxfreq)); data->min_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_MIF], &minfreq)); data->curr_freq[PPMU_MIF] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_MIF], &cdrexfreq)); /* Find max frequency for int */ maxfreq = ULONG_MAX; minfreq = 0; data->max_freq[PPMU_INT] = opp_get_freq(opp_find_freq_floor(data->dev[PPMU_INT], &maxfreq)); data->min_freq[PPMU_INT] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_INT], &minfreq)); data->curr_freq[PPMU_INT] = opp_get_freq(opp_find_freq_ceil(data->dev[PPMU_INT], &lrbusfreq)); data->vdd_reg[PPMU_INT] = regulator_get(NULL, "vdd_int"); if (IS_ERR(data->vdd_reg[PPMU_INT])) { pr_err("failed to get resource %s\n", "vdd_int"); return -ENODEV; } data->vdd_reg[PPMU_MIF] = regulator_get(NULL, "vdd_mif"); if (IS_ERR(data->vdd_reg[PPMU_MIF])) { pr_err("failed to get resource %s\n", "vdd_mif"); regulator_put(data->vdd_reg[PPMU_INT]); return -ENODEV; } data->busfreq_early_suspend_handler.suspend = &busfreq_early_suspend; data->busfreq_early_suspend_handler.resume = &busfreq_late_resume; /* Request min 300MHz */ dev_lock(dev, dev, 300000); register_early_suspend(&data->busfreq_early_suspend_handler); tmp = __raw_readl(EXYNOS5_ABBG_INT_CONTROL); tmp &= ~(0x1f | (1 << 31) | (1 << 7)); tmp |= ((8 + INT_RBB) | (1 << 31) | (1 << 7)); __raw_writel(tmp, EXYNOS5_ABBG_INT_CONTROL); return 0; }
/* * This API is to be called during init to set the various voltage * domains to the voltage as per the opp table. Typically we boot up * at the nominal voltage. So this function finds out the rate of * the clock associated with the voltage domain, finds out the correct * opp entry and sets the voltage domain to the voltage specified * in the opp entry */ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, const char *oh_name) { struct voltagedomain *voltdm; struct clk *clk; struct opp *opp; struct device *dev; unsigned long freq_cur, freq_valid, bootup_volt; int ret = -EINVAL; dev = omap_device_get_by_hwmod_name(oh_name); if (IS_ERR(dev)) { pr_err("%s: Unable to get dev pointer for hwmod %s\n", __func__, oh_name); goto exit; } voltdm = voltdm_lookup(vdd_name); if (IS_ERR(voltdm)) { pr_err("%s: unable to get vdd pointer for vdd_%s\n", __func__, vdd_name); goto exit; } clk = clk_get(NULL, clk_name); if (IS_ERR(clk)) { pr_err("%s: unable to get clk %s\n", __func__, clk_name); goto exit; } freq_cur = clk->rate; freq_valid = freq_cur; rcu_read_lock(); opp = opp_find_freq_ceil(dev, &freq_valid); if (IS_ERR(opp)) { opp = opp_find_freq_floor(dev, &freq_valid); if (IS_ERR(opp)) { rcu_read_unlock(); pr_err("%s: no boot OPP match for %ld on vdd_%s\n", __func__, freq_cur, vdd_name); ret = -ENOENT; goto exit_ck; } } bootup_volt = opp_get_voltage(opp); rcu_read_unlock(); if (!bootup_volt) { pr_err("%s: unable to find voltage corresponding " "to the bootup OPP for vdd_%s\n", __func__, vdd_name); ret = -ENOENT; goto exit_ck; } /* * Frequency and Voltage have to be sequenced: if we move from * a lower frequency to higher frequency, raise voltage, followed by * frequency, and vice versa. we assume that the voltage at boot * is the required voltage for the frequency it was set for. * NOTE: * we can check the frequency, but there is numerous ways to set * voltage. We play the safe path and just set the voltage. */ if (freq_cur < freq_valid) { ret = voltdm_scale(voltdm, bootup_volt); if (ret) { pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", __func__, vdd_name, freq_valid, bootup_volt, vdd_name); goto exit_ck; } } /* Set freq only if there is a difference in freq */ if (freq_valid != freq_cur) { ret = clk_set_rate(clk, freq_valid); if (ret) { pr_err("%s: Fail set clk-%s(f=%ld v=%ld)on vdd%s\n", __func__, clk_name, freq_valid, bootup_volt, vdd_name); goto exit_ck; } } if (freq_cur >= freq_valid) { ret = voltdm_scale(voltdm, bootup_volt); if (ret) { pr_err("%s: Fail set voltage-%s(f=%ld v=%ld)on vdd%s\n", __func__, clk_name, freq_valid, bootup_volt, vdd_name); goto exit_ck; } } ret = 0; exit_ck: clk_put(clk); if (!ret) return 0; exit: pr_err("%s: unable to set vdd_%s\n", __func__, vdd_name); return -EINVAL; }
int exynos4210_init(struct device *dev, struct busfreq_data *data) { unsigned int i; unsigned int tmp; unsigned long maxfreq = UINT_MAX; int ret; tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0); for (i = 0; i < LV_END; i++) { tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK | EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK | EXYNOS4_CLKDIV_DMC0_DPHY_MASK | EXYNOS4_CLKDIV_DMC0_DMC_MASK | EXYNOS4_CLKDIV_DMC0_DMCD_MASK | EXYNOS4_CLKDIV_DMC0_DMCP_MASK | EXYNOS4_CLKDIV_DMC0_COPY2_MASK | EXYNOS4_CLKDIV_DMC0_CORETI_MASK); tmp |= ((clkdiv_dmc0[i][0] << EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) | (clkdiv_dmc0[i][1] << EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) | (clkdiv_dmc0[i][2] << EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) | (clkdiv_dmc0[i][3] << EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) | (clkdiv_dmc0[i][4] << EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) | (clkdiv_dmc0[i][5] << EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) | (clkdiv_dmc0[i][6] << EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) | (clkdiv_dmc0[i][7] << EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT)); exynos4_busfreq_table[i].clk_dmc0div = tmp; } tmp = __raw_readl(EXYNOS4_CLKDIV_TOP); for (i = 0; i < LV_END; i++) { tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK | EXYNOS4_CLKDIV_TOP_ACLK100_MASK | EXYNOS4_CLKDIV_TOP_ACLK160_MASK | EXYNOS4_CLKDIV_TOP_ACLK133_MASK | EXYNOS4_CLKDIV_TOP_ONENAND_MASK); tmp |= ((clkdiv_top[i][0] << EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) | (clkdiv_top[i][1] << EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) | (clkdiv_top[i][2] << EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) | (clkdiv_top[i][3] << EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) | (clkdiv_top[i][4] << EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT)); exynos4_busfreq_table[i].clk_topdiv = tmp; } exynos4210_set_bus_volt(); for (i = 0; i < LV_END; i++) { ret = opp_add(dev, exynos4_busfreq_table[i].mem_clk, exynos4_busfreq_table[i].volt); if (ret) { dev_err(dev, "Fail to add opp entries.\n"); return ret; } } data->table = exynos4_busfreq_table; data->table_size = LV_END; /* Find max frequency */ data->max_opp = opp_find_freq_floor(dev, &maxfreq); data->vdd_int = regulator_get(NULL, "vdd_int"); if (IS_ERR(data->vdd_int)) { pr_err("failed to get resource %s\n", "vdd_int"); return -ENODEV; } data->vdd_mif = ERR_PTR(-ENODEV); return 0; }
/** * omap_device_set_rate - Set a new rate at which the device is to operate * @req_dev : pointer to the device requesting the scaling. * @dev : pointer to the device that is to be scaled * @rate : the rnew rate for the device. * * This API gets the device opp table associated with this device and * tries putting the device to the requested rate and the voltage domain * associated with the device to the voltage corresponding to the * requested rate. Since multiple devices can be assocciated with a * voltage domain this API finds out the possible voltage the * voltage domain can enter and then decides on the final device * rate. Return 0 on success else the error value */ int omap_device_set_rate(struct device *req_dev, struct device *dev, unsigned long rate) { struct omap_opp *opp; unsigned long volt, freq, min_freq, max_freq, flags; struct voltagedomain *voltdm; struct platform_device *pdev; struct omap_device *od; int ret; pdev = container_of(dev, struct platform_device, dev); od = _find_by_pdev(pdev); /* if in low power DPLL cascading mode, bail out early */ if (cpu_is_omap44xx()) { read_lock_irqsave(&dpll_cascading_lock, flags); if (in_dpll_cascading) { ret = -EINVAL; goto out; } } /* * Figure out if the desired frquency lies between the * maximum and minimum possible for the particular device */ min_freq = 0; if (IS_ERR(opp_find_freq_ceil(dev, &min_freq))) { dev_err(dev, "%s: Unable to find lowest opp\n", __func__); ret = -ENODEV; goto out; } max_freq = ULONG_MAX; if (IS_ERR(opp_find_freq_floor(dev, &max_freq))) { dev_err(dev, "%s: Unable to find highest opp\n", __func__); ret = -ENODEV; goto out; } if (rate < min_freq) freq = min_freq; else if (rate > max_freq) freq = max_freq; else freq = rate; /* Get the possible rate from the opp layer */ opp = opp_find_freq_ceil(dev, &freq); if (IS_ERR(opp)) { dev_dbg(dev, "%s: Unable to find OPP for freq%ld\n", __func__, rate); ret = -ENODEV; goto out; } if (unlikely(freq != rate)) dev_dbg(dev, "%s: Available freq %ld != dpll freq %ld.\n", __func__, freq, rate); /* Get the voltage corresponding to the requested frequency */ volt = opp_get_voltage(opp); /* * Call into the voltage layer to get the final voltage possible * for the voltage domain associated with the device. */ voltdm = od->hwmods[0]->voltdm; ret = omap_voltage_add_userreq(voltdm, req_dev, &volt); if (ret) { dev_err(dev, "%s: Unable to get the final volt for scaling\n", __func__); goto out; } /* Do the actual scaling */ ret = omap_voltage_scale(voltdm); out: if (cpu_is_omap44xx()) read_unlock_irqrestore(&dpll_cascading_lock, flags); return ret; }
/** * omap_device_scale() - Set a new rate at which the device is to operate * @req_dev: pointer to the device requesting the scaling. * @dev: pointer to the device that is to be scaled * @rate: the rnew rate for the device. * * This API gets the device opp table associated with this device and * tries putting the device to the requested rate and the voltage domain * associated with the device to the voltage corresponding to the * requested rate. Since multiple devices can be assocciated with a * voltage domain this API finds out the possible voltage the * voltage domain can enter and then decides on the final device * rate. Return 0 on success else the error value */ int omap_device_scale(struct device *req_dev, struct device *dev, unsigned long rate) { struct opp *opp; unsigned long volt, freq, min_freq, max_freq; struct voltagedomain *voltdm; struct platform_device *pdev; struct omap_device *od; int ret; pdev = container_of(dev, struct platform_device, dev); od = _find_by_pdev(pdev); /* * Figure out if the desired frquency lies between the * maximum and minimum possible for the particular device */ min_freq = 0; if (IS_ERR(opp_find_freq_ceil(dev, &min_freq))) { dev_err(dev, "%s: Unable to find lowest opp\n", __func__); return -ENODEV; } max_freq = ULONG_MAX; if (IS_ERR(opp_find_freq_floor(dev, &max_freq))) { dev_err(dev, "%s: Unable to find highest opp\n", __func__); return -ENODEV; } if (rate < min_freq) freq = min_freq; else if (rate > max_freq) freq = max_freq; else freq = rate; opp = opp_find_freq_ceil(dev, &freq); if (IS_ERR(opp)) { dev_err(dev, "%s: Unable to find OPP for freq%ld\n", __func__, rate); return -ENODEV; } /* Get the voltage corresponding to the requested frequency */ volt = opp_get_voltage(opp); /* * Call into the voltage layer to get the final voltage possible * for the voltage domain associated with the device. */ voltdm = od->hwmods[0]->voltdm; ret = omap_voltage_add_request(voltdm, req_dev, &volt); if (ret) { dev_err(dev, "%s: Unable to get the final volt for scaling\n", __func__); return ret; } /* Do the actual scaling */ return omap_voltage_scale(voltdm, volt); }