/* * OMAP3/OMAP4 Voltage Management Routines * * Author: Thara Gopinath * * Copyright (C) 2007 Texas Instruments, Inc. * Rajendra Nayak * Lesly A M * * Copyright (C) 2008, 2011 Nokia Corporation * Kalle Jokiniemi * Paul Walmsley * * Copyright (C) 2010 Texas Instruments, Inc. * Thara Gopinath * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include "common.h" #include "prm-regbits-34xx.h" #include "prm-regbits-44xx.h" #include "prm44xx.h" #include "prcm44xx.h" #include "prminst44xx.h" #include "control.h" #include "voltage.h" #include "powerdomain.h" #include "vc.h" #include "vp.h" static LIST_HEAD(voltdm_list); /* Public functions */ /** * voltdm_get_voltage() - Gets the current non-auto-compensated voltage * @voltdm: pointer to the voltdm for which current voltage info is needed * * API to get the current non-auto-compensated voltage for a voltage domain. * Returns 0 in case of error else returns the current voltage. */ unsigned long voltdm_get_voltage(struct voltagedomain *voltdm) { if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return 0; } return voltdm->nominal_volt; } /** * voltdm_scale() - API to scale voltage of a particular voltage domain. * @voltdm: pointer to the voltage domain which is to be scaled. * @target_volt: The target voltage of the voltage domain * * This API should be called by the kernel to do the voltage scaling * for a particular voltage domain during DVFS. */ int voltdm_scale(struct voltagedomain *voltdm, unsigned long target_volt) { int ret, i; unsigned long volt = 0; if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return -EINVAL; } if (!voltdm->scale) { pr_err("%s: No voltage scale API registered for vdd_%s\n", __func__, voltdm->name); return -ENODATA; } /* Adjust voltage to the exact voltage from the OPP table */ for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) { if (voltdm->volt_data[i].volt_nominal >= target_volt) { volt = voltdm->volt_data[i].volt_nominal; break; } } if (!volt) { pr_warning("%s: not scaling. OPP voltage for %lu, not found.\n", __func__, target_volt); return -EINVAL; } ret = voltdm->scale(voltdm, volt); if (!ret) voltdm->nominal_volt = volt; return ret; } /** * voltdm_reset() - Resets the voltage of a particular voltage domain * to that of the current OPP. * @voltdm: pointer to the voltage domain whose voltage is to be reset. * * This API finds out the correct voltage the voltage domain is supposed * to be at and resets the voltage to that level. Should be used especially * while disabling any voltage compensation modules. */ void voltdm_reset(struct voltagedomain *voltdm) { unsigned long target_volt; if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return; } target_volt = voltdm_get_voltage(voltdm); if (!target_volt) { pr_err("%s: unable to find current voltage for vdd_%s\n", __func__, voltdm->name); return; } voltdm_scale(voltdm, target_volt); } /** * omap_voltage_get_volttable() - API to get the voltage table associated with a * particular voltage domain. * @voltdm: pointer to the VDD for which the voltage table is required * @volt_data: the voltage table for the particular vdd which is to be * populated by this API * * This API populates the voltage table associated with a VDD into the * passed parameter pointer. Returns the count of distinct voltages * supported by this vdd. * */ void omap_voltage_get_volttable(struct voltagedomain *voltdm, struct omap_volt_data **volt_data) { if (!voltdm || IS_ERR(voltdm)) { pr_warning("%s: VDD specified does not exist!\n", __func__); return; } *volt_data = voltdm->volt_data; }