Hi, Some very basic incomplete sketch of how some of my ideas might look in code: /* * OMAP PM Core implementation by Eugeny S. Mints <eugeny.mints at gmail.com>, * modified by Dominik Brodowski. * * Copyright (C) 2006, Nomad Global Solutions, Inc. * Copyright (C) 2006 Dominik Brodowski * * Based on code by Todd Poynor, Matthew Locke, Dmitry Chigirev, and * Bishop Brock. * * Copyright (C) 2002, 2004 MontaVista Software <source at mvista.com>. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> /* Number of colums in operating points table */ #define OP_VALUES 4 /* GENERIC PART BEGINS HERE */ struct op_entry { unsigned int value[OP_VALUES]; struct op_entry *next; }; int pm_core_verify_value(unsigned int what, unsigned int value, struct op_entry *table, int set_other(unsigned int, unsigned int)) { int i, colum = -1; struct op_entry *table_entry = table->next; for (i=0; i<OP_VALUES; i++) { if (table->value[i] == what) colum = i; } if (colum == -1) return -EINVAL; while (table_entry) { /* very easy algorithm at first: use the first operating point which matches what we are looking for */ if (table_entry->value[colum] == value) goto found_it; table_entry = table_entry->next; }; return -EINVAL; found_it: for (i=0; i<OP_VALUES; i++) { if (i==colum) continue; /* FIXME: error handling */ set_other(table->value[i], table_entry->value[i]); } return 0; } /* GENERIC PART ENDS HERE */ /* dummy */ static int set_cpu_vltg(unsigned int value) { return 0; } static int set_dpll(unsigned int value) { return 0; } static int set_cpu_freq(unsigned int value) { return 0; } enum { CPU_VLTG = 0, DPLL = 1, CPU_FREQ = 2, OPPOINT_NR = 3, }; static int set_pm(unsigned int what, unsigned int value) { int ret = -ENODEV; /* FIXME pm_core_notify_prechange(what, value); */ switch (what) { case CPU_VLTG: /* FIXME: only set it if it is really different * from current level */ ret = set_cpu_vltg(value); break; case DPLL: ret = set_dpll(value); break; case CPU_FREQ: ret = set_cpu_freq(value); break; case OPPOINT_NR: /* ignore */ break; } /* FIXME if (!ret) pm_core_notify_postchange(what, value); else pm_core_notify_failed_change(what, value); */ return ret; } /* THE TABLE CONTAING PRE-DEFINED OPERATING POINTS */ /* FIXME: think of a better way to set up a static table */ struct op_entry omap_op_static_entry4 = { .value = {2, 3, 2, 4}, }; struct op_entry omap_op_static_entry3 = { .value = {1, 2, 2, 3}, .next = &omap_op_static_entry4, }; struct op_entry omap_op_static_entry2 = { .value = {2, 1, 1, 2}, .next = &omap_op_static_entry3, }; struct op_entry omap_op_static_entry1 = { .value = {1, 1, 1, 1}, .next = &omap_op_static_entry2, }; struct op_entry omap_op_table = { .value = {CPU_VLTG, DPLL, CPU_FREQ, OPPOINT_NR}, .next = &omap_op_static_entry1, }; /* function being called by external interface. You can add whatever userspace API on top of it you like -- configfs, sysfs, module parameter, syscall, ... */ int omap_set(unsigned int what, unsigned int value) { int ret; ret = pm_core_verify_value(what, value, &omap_op_table, set_pm); if (ret) return ret; return set_pm(what, value); } /* To set a specific operating point, let's say, oppoint 3, the yet-to-be-defined interface needs to call: omap_set(OPPOINT_NR, 3); Setting up a cpufreq interaction is quite easy, as it basically only needs to call omap_set(CPU_FREQ, validated_target_freq); You only need to make sure that you're not using in-kernel CPU frequency scaling parallel to setting oppoints. But such a validation should be trivial to add. */ IT COMPILES!!! SHIP IT! ;) Thanks, Dominik