Moving to list based OPP layer and its new semantics.

diff --git a/arch/arm/plat-omap/include/plat/opp.h 
b/arch/arm/plat-omap/include/plat/opp.h
index 9f91ad3..38ba00f 100644
--- a/arch/arm/plat-omap/include/plat/opp.h
+++ b/arch/arm/plat-omap/include/plat/opp.h
@@ -2,9 +2,9 @@
  * OMAP OPP Interface
  *
  * Copyright (C) 2009 Texas Instruments Incorporated.
- *     Nishanth Menon
- * Copyright (C) 2009 Deep Root Systems, LLC.
- *     Kevin Hilman
+ * Romit Dasgupta <ro...@ti.com>
+ * Derived from the original series of patches by Nishanth Menon &
+ * Kevin Hilman.
  *
  * 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
@@ -13,223 +13,88 @@
 #ifndef __ASM_ARM_OMAP_OPP_H
 #define __ASM_ARM_OMAP_OPP_H
 
-extern struct omap_opp *mpu_opps;
-extern struct omap_opp *dsp_opps;
-extern struct omap_opp *l3_opps;
+#ifdef CONFIG_CPU_FREQ
+#include <linux/cpufreq.h>
+#endif
 
-struct omap_opp;
+#define OPP_ENABLED (1 << 0)
+#define OPP_DISABLED (1 << 1)
+#define OPP_H (1 << 2)
+#define OPP_L (1 << 3)
+#define OPP_EQ (1 << 4)
+#define OPP_ALL (OPP_ENABLED | OPP_DISABLED)
 
-/**
- * opp_get_voltage() - Gets the voltage corresponding to an opp
- * @opp:       opp for which voltage has to be returned for
- *
- * Return voltage in micro volt corresponding to the opp, else
- * return 0
+/*
+ * XXX: Pending documentation.
  */
-unsigned long opp_get_voltage(const struct omap_opp *opp);
 
-/**
- * opp_get_freq() - Gets the frequency corresponding to an opp
- * @opp:       opp for which frequency has to be returned for
- *
- * Return frequency in hertz corresponding to the opp, else
- * return 0
- */
-unsigned long opp_get_freq(const struct omap_opp *opp);
+struct omap_opp {
+       struct list_head opp_node;
+       unsigned int enabled:1;
+       unsigned long rate;
+       unsigned long uvolt;
+};
 
-/**
- * opp_get_opp_count() - Get number of opps enabled in the opp list
- * @num:       returns the number of opps
- * @oppl:      opp list
- *
- * This functions returns the number of opps if there are any OPPs enabled,
- * else returns corresponding error value.
- */
-int opp_get_opp_count(struct omap_opp *oppl);
+enum opp_t {
+       OPP_NONE = 0,
+       OPP_MPU,
+       OPP_L3,
+       OPP_DSP,
+};
 
-/**
- * opp_find_freq_exact() - search for an exact frequency
- * @oppl:      OPP list
- * @freq:      frequency to search for
- * @enabled:   enabled/disabled OPP to search for
- *
- * searches for the match in the opp list and returns handle to the matching
- * opp if found, else returns ERR_PTR in case of error and should be handled
- * using IS_ERR.
- *
- * Note enabled is a modifier for the search. if enabled=true, then the match 
is
- * for exact matching frequency and is enabled. if true, the match is for exact
- * frequency which is disabled.
- */
-struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
-                                    unsigned long freq, bool enabled);
+static inline long opp_to_volt(struct omap_opp *opp)
+{
+       return opp ? opp->uvolt : 0;
+}
 
-/* XXX This documentation needs fixing */
+static inline long opp_to_freq(struct omap_opp *opp)
+{
+       return opp ? opp->rate : 0;
+}
 
-/**
- * opp_find_freq_floor() - Search for an rounded freq
- * @oppl:      Starting list
- * @freq:      Start frequency
- *
- * Search for the lower *enabled* OPP from a starting freq
- * from a start opp list.
- *
- * Returns *opp and *freq is populated with the next match, else
- * returns NULL opp if found, else returns ERR_PTR in case of error.
- *
- * Example usages:
- *     * find match/next lowest available frequency
- *     freq = 350000;
- *     opp = opp_find_freq_floor(oppl, &freq)))
- *     if (IS_ERR(opp))
- *             pr_err ("unable to find a lower frequency\n");
- *     else
- *             pr_info("match freq = %ld\n", freq);
- *
- *     * print all supported frequencies in descending order *
- *     opp = oppl;
- *     freq = ULONG_MAX;
- *     while (!IS_ERR(opp = opp_find_freq_floor(opp, &freq)) {
- *             pr_info("freq = %ld\n", freq);
- *             freq--; * for next lower match *
- *     }
- *
- * NOTE: if we set freq as ULONG_MAX and search low, we get the
- * highest enabled frequency
- */
-struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl,
-                                    unsigned long *freq);
+static inline unsigned int opp_is_valid(struct omap_opp *opp)
+{
+       return opp ? opp->enabled : 0;
+}
 
-/* XXX This documentation needs fixing */
+extern struct omap_opp *find_opp_by_freq(enum opp_t, unsigned long,
+                                               unsigned long);
 
-/**
- * opp_find_freq_ceil() - Search for an rounded freq
- * @oppl:      Starting list
- * @freq:      Start frequency
- *
- * Search for the higher *enabled* OPP from a starting freq
- * from a start opp list.
- *
- * Returns *opp and *freq is populated with the next match, else
- * returns NULL opp if found, else returns ERR_PTR in case of error.
- *
- * Example usages:
- *     * find match/next highest available frequency
- *     freq = 350000;
- *     opp = opp_find_freq_ceil(oppl, &freq))
- *     if (IS_ERR(opp))
- *             pr_err ("unable to find a higher frequency\n");
- *     else
- *             pr_info("match freq = %ld\n", freq);
- *
- *     * print all supported frequencies in ascending order *
- *     opp = oppl;
- *     freq = 0;
- *     while (!IS_ERR(opp = opp_find_freq_ceil(opp, &freq)) {
- *             pr_info("freq = %ld\n", freq);
- *             freq++; * for next higher match *
- *     }
- */
-struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl, unsigned long 
*freq);
+extern unsigned int get_opp_count(enum opp_t, unsigned long);
 
+extern int opp_add(enum opp_t, struct omap_opp *, unsigned long);
+extern int opp_del(enum opp_t, struct omap_opp *);
 
-/**
- * struct omap_opp_def - OMAP OPP Definition
- * @enabled:   True/false - is this OPP enabled/disabled by default
- * @freq:      Frequency in hertz corresponding to this OPP
- * @u_volt:    Nominal voltage in microvolts corresponding to this OPP
- *
- * OMAP SOCs have a standard set of tuples consisting of frequency and voltage
- * pairs that the device will support per voltage domain. This is called
- * Operating Points or OPP. The actual definitions of OMAP Operating Points
- * varies over silicon within the same family of devices. For a specific
- * domain, you can have a set of {frequency, voltage} pairs and this is denoted
- * by an array of omap_opp_def. As the kernel boots and more information is
- * available, a set of these are activated based on the precise nature of
- * device the kernel boots up on. It is interesting to remember that each IP
- * which belongs to a voltage domain may define their own set of OPPs on top
- * of this - but this is handled by the appropriate driver.
- */
-struct omap_opp_def {
-       bool enabled;
-       unsigned long freq;
-       unsigned long u_volt;
-};
+extern int create_opp_list(enum opp_t, struct omap_opp *);
 
-/*
- * Initialization wrapper used to define an OPP
- * to point at the end of a terminator of a list of OPPs,
- * use OMAP_OPP_DEF(0, 0, 0)
- */
-#define OMAP_OPP_DEF(_enabled, _freq, _uv)     \
-{                                              \
-       .enabled        = _enabled,             \
-       .freq           = _freq,                \
-       .u_volt         = _uv,                  \
+static inline void opp_enable(struct omap_opp *opp)
+{
+       opp ? opp->enabled = 1 : 0;
+       return;
 }
 
-/**
- * opp_init_list() - Initialize an opp list from the opp definitions
- * @opp_defs:  Initial opp definitions to create the list.
- *
- * This function creates a list of opp definitions and returns a handle.
- * This list can be used to further validation/search/modifications. New
- * opp entries can be added to this list by using opp_add().
- *
- * In the case of error, ERR_PTR is returned to the caller and should be
- * appropriately handled with IS_ERR.
- */
-struct omap_opp __init *opp_init_list(const struct omap_opp_def *opp_defs);
-
-/**
- * opp_add()  - Add an OPP table from a table definitions
- * @oppl:      List to add the OPP to
- * @opp_def:   omap_opp_def to describe the OPP which we want to add to list.
- *
- * This function adds an opp definition to the opp list and returns
- * a handle representing the new OPP list. This handle is then used for further
- * validation, search, modification operations on the OPP list.
- *
- * This function returns the pointer to the allocated list through oppl if
- * success, else corresponding ERR_PTR value. Caller should NOT free the oppl.
- * opps_defs can be freed after use.
- *
- * NOTE: caller should assume that on success, oppl is probably populated with
- * a new handle and the new handle should be used for further referencing
- */
-struct omap_opp *opp_add(struct omap_opp *oppl,
-                        const struct omap_opp_def *opp_def);
+static inline void opp_disable(struct omap_opp *opp)
+{
+       opp ? opp->enabled = 0 : 0;
+       return;
+}
 
-/**
- * opp_enable() - Enable a specific OPP
- * @opp:       Pointer to opp
- *
- * Enables a provided opp. If the operation is valid, this returns 0, else the
- * corresponding error value.
- *
- * OPP used here is from the the opp_is_valid/opp_has_freq or other search
- * functions
- */
-int opp_enable(struct omap_opp *opp);
+extern void dump_list(enum opp_t);
 
-/**
- * opp_disable() - Disable a specific OPP
- * @opp:       Pointer to opp
- *
- * Disables a provided opp. If the operation is valid, this returns 0, else the
- * corresponding error value.
- *
- * OPP used here is from the the opp_is_valid/opp_has_freq or other search
- * functions
+/*
+ * Initialization wrapper used to define an OPP.
  */
-int opp_disable(struct omap_opp *opp);
 
-struct omap_opp * __deprecated opp_find_by_opp_id(struct omap_opp *opps,
-                                                 u8 opp_id);
-u8 __deprecated opp_get_opp_id(struct omap_opp *opp);
+#define OMAP_OPP_DEF(_enabled, _freq, _uv)             \
+{                                                      \
+       .enabled        = _enabled,                     \
+       .rate           = _freq,                        \
+       .uvolt          = _uv,                          \
+}
 
-void opp_init_cpufreq_table(struct omap_opp *opps,
-                           struct cpufreq_frequency_table **table);
 
+#ifdef CONFIG_CPU_FREQ
+extern void opp_init_cpufreq_table(struct cpufreq_frequency_table **);
+#endif
 
 #endif         /* __ASM_ARM_OMAP_OPP_H */
diff --git a/arch/arm/plat-omap/opp.c b/arch/arm/plat-omap/opp.c
index 4fe1933..afcd469 100644
--- a/arch/arm/plat-omap/opp.c
+++ b/arch/arm/plat-omap/opp.c
@@ -2,7 +2,9 @@
  * OMAP OPP Interface
  *
  * Copyright (C) 2009 Texas Instruments Incorporated.
- *     Nishanth Menon
+ * Romit Dasgupta <ro...@ti.com>
+ * Derived from the original series of patches by
+ * Nishanth Menon & Kevin Hilman.
  *
  * 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
@@ -11,318 +13,362 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
 #include <linux/cpufreq.h>
 
 #include <plat/opp_twl_tps.h>
 #include <plat/opp.h>
 
-/**
- * struct omap_opp - OMAP OPP description structure
- * @enabled:   true/false - marking this OPP as enabled/disabled
- * @rate:      Frequency in hertz
- * @opp_id:    (DEPRECATED) opp identifier
- * @u_volt:     minimum microvolts DC required for this OPP to function
- *
- * This structure stores the OPP information for a given domain.
- * Due to legacy reasons, this structure is currently exposed and
- * will soon be removed elsewhere and will only be used as a handle
- * from the OPP internal referencing mechanism
- */
-struct omap_opp {
-       bool enabled;
-       unsigned long rate;
-       unsigned long u_volt;
-       u8 opp_id;
+/* For 3xxx we have MPU, DSP & L3 OPPs */
+#ifdef CONFIG_ARCH_OMAP3
+#define NUM_OPP_TYPES 3
+#else
+#error "define the OPP types for OMAP type"
+#endif
+
+struct opp_list {
+       struct list_head opp_head;
+       struct mutex opp_mtx;
+       enum opp_t id;
 };
 
 /*
- * DEPRECATED: Meant to detect end of opp array
- * This is meant to help co-exist with current SRF etc
- * TODO: REMOVE!
+ * Will hold OPPs for MPU, L3, DSP etc.
+ * This has been statically allocated as OPP types
+ * are known for eachy platform. However individual OPPs
+ * can be dynamically introduced or revoked.
  */
-#define OPP_TERM(opp) (!(opp)->rate && !(opp)->u_volt && !(opp)->enabled)
+static struct opp_list opp_types[NUM_OPP_TYPES];
 
-unsigned long opp_get_voltage(const struct omap_opp *opp)
+static struct opp_list *get_slot(void)
 {
-       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return 0;
+       struct opp_list *arr = opp_types;
+       int i;
+
+       for (i = 0; i < NUM_OPP_TYPES; i++)
+               if (arr->id == OPP_NONE)
+                       break;
+               else
+                       arr++;
+
+       if (i == NUM_OPP_TYPES)
+               return NULL;
+       else {
+               INIT_LIST_HEAD(&arr->opp_head);
+               mutex_init(&arr->opp_mtx);
+               return arr;
        }
-       return opp->u_volt;
 }
 
-unsigned long opp_get_freq(const struct omap_opp *opp)
+static void put_slot(struct opp_list *arr)
 {
-       if (unlikely(!opp || IS_ERR(opp)) || !opp->enabled) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return 0;
-       }
-       return opp->rate;
+       arr->id = OPP_NONE;
 }
 
-/**
- * opp_find_by_opp_id - look up OPP by OPP ID (deprecated)
- * @opps: pointer to an array of struct omap_opp
- *
- * Returns the struct omap_opp pointer corresponding to the given OPP
- * ID @opp_id, or returns NULL on error.
- */
-struct omap_opp * __deprecated opp_find_by_opp_id(struct omap_opp *opps,
-                                                 u8 opp_id)
+static struct opp_list *exists(enum opp_t id)
 {
+       struct opp_list *arr = opp_types;
        int i = 0;
 
-       if (!opps || !opp_id)
+       if (!id)
                return NULL;
 
-       while (!OPP_TERM(&opps[i])) {
-               if (opps[i].enabled && (opps[i].opp_id == opp_id))
-                       return &opps[i];
-
-               i++;
+       for (i = 0; i < NUM_OPP_TYPES; i++) {
+               if (id == arr->id)
+                       return arr;
+               arr++;
        }
+       return NULL;
+}
+
+#define __OPP_NOLOCK (1 << 31)
 
+static struct omap_opp *_find_opp_by_freq_eq(struct list_head *head,
+                                               unsigned long freq)
+{
+       struct omap_opp *opp;
+
+       list_for_each_entry(opp, head, opp_node)
+               if (opp->rate == freq)
+                       return opp;
        return NULL;
 }
 
-u8 __deprecated opp_get_opp_id(struct omap_opp *opp)
+static struct omap_opp *_find_first_enabled_h(struct list_head *head,
+                                               struct omap_opp *opp)
 {
-       return opp->opp_id;
+       while (!opp->enabled && opp->opp_node.prev != head)
+               opp = list_entry(opp->opp_node.prev, struct omap_opp,
+                                       opp_node);
+
+       if (opp->opp_node.prev == head && !opp->enabled)
+               return NULL;
+       else
+               return opp;
 }
 
-int opp_get_opp_count(struct omap_opp *oppl)
+static struct omap_opp *_find_first_enabled_l(struct list_head *head,
+                                               struct omap_opp *opp)
 {
-       u8 n = 0;
+       while (!opp->enabled && opp->opp_node.next != head)
+               opp = list_entry(opp->opp_node.next, struct omap_opp,
+                                       opp_node);
 
-       if (unlikely(!oppl || IS_ERR(oppl))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return -EINVAL;
-       }
-       while (!OPP_TERM(oppl)) {
-               if (oppl->enabled)
-                       n++;
-               oppl++;
-       }
-       return n;
+       if (opp->opp_node.next == head && !opp->enabled)
+               return NULL;
+       else
+               return opp;
 }
 
-struct omap_opp *opp_find_freq_exact(struct omap_opp *oppl,
-                                    unsigned long freq, bool enabled)
+static struct omap_opp *_find_opp_by_freq_h(struct list_head *head,
+                                               unsigned long freq,
+                                               unsigned long flags)
 {
-       if (unlikely(!oppl || IS_ERR(oppl))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       struct omap_opp *opp = NULL;
 
-       while (!OPP_TERM(oppl)) {
-               if ((oppl->rate == freq) && (oppl->enabled == enabled))
+       list_for_each_entry(opp, head, opp_node)
+               if (opp->rate > freq) {
+                       if (opp->opp_node.prev == head)
+                               return NULL;
                        break;
-               oppl++;
-       }
+               }
+       opp = list_entry(opp->opp_node.prev, struct omap_opp, opp_node);
 
-       return OPP_TERM(oppl) ? ERR_PTR(-ENOENT) : oppl;
+       if (flags & OPP_ENABLED)
+               opp = _find_first_enabled_h(head, opp);
+
+       return opp;
 }
 
-struct omap_opp *opp_find_freq_ceil(struct omap_opp *oppl, unsigned long *freq)
+static struct omap_opp *_find_opp_by_freq_l(struct list_head *head,
+                                               unsigned long freq,
+                                               unsigned long flags)
 {
-       if (unlikely(!oppl || IS_ERR(oppl) || !freq || IS_ERR(freq))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       struct omap_opp *opp = NULL;
 
-       while (!OPP_TERM(oppl)) {
-               if (oppl->enabled && oppl->rate >= *freq)
+       list_for_each_entry_reverse(opp, head, opp_node)
+               if (opp->rate < freq) {
+                       if (opp->opp_node.next == head)
+                               return NULL;
                        break;
+               }
 
-               oppl++;
-       }
+       opp = list_entry(opp->opp_node.next, struct omap_opp, opp_node);
+
+       if (flags & OPP_ENABLED)
+               opp = _find_first_enabled_l(head, opp);
 
-       if (OPP_TERM(oppl))
-               return ERR_PTR(-ENOENT);
+       return opp;
+}
+
+struct omap_opp *_find_opp_by_freq(struct opp_list *oppl,
+                                       unsigned long freq,
+                                       unsigned long flags)
+{
+       struct omap_opp *opp = NULL;
 
-       *freq = oppl->rate;
+       if (!(flags & __OPP_NOLOCK))
+               mutex_lock(&oppl->opp_mtx);
 
-       return oppl;
+       if (list_empty(&oppl->opp_head))
+               goto unlock;
+
+       if (flags & OPP_EQ) {
+               opp = _find_opp_by_freq_eq(&oppl->opp_head, freq);
+               if ((flags & OPP_ENABLED) && !opp_is_valid(opp))
+                       opp = NULL;
+       } else if (flags & OPP_L) {
+               opp = _find_opp_by_freq_l(&oppl->opp_head, freq, flags);
+       } else if (flags & OPP_H)
+               opp = _find_opp_by_freq_h(&oppl->opp_head, freq, flags);
+
+unlock:
+       if (!(flags & __OPP_NOLOCK))
+               mutex_unlock(&oppl->opp_mtx);
+
+       return opp;
+}
+
+struct omap_opp *find_opp_by_freq(enum opp_t id, unsigned long freq,
+                                       unsigned long flags)
+{
+       struct opp_list *oppl;
+       oppl = exists(id);
+       BUG_ON(!oppl);
+       return _find_opp_by_freq(oppl, freq, flags);
 }
 
-struct omap_opp *opp_find_freq_floor(struct omap_opp *oppl, unsigned long 
*freq)
+static unsigned int _get_opp_count(struct opp_list *oppl, unsigned long flags)
 {
-       struct omap_opp *prev_opp = oppl;
+       struct omap_opp *opp;
+       unsigned int enabled = 0, total = 0;
+
+       mutex_lock(&oppl->opp_mtx);
 
-       if (unlikely(!oppl || IS_ERR(oppl) || !freq || IS_ERR(freq))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return ERR_PTR(-EINVAL);
+       list_for_each_entry(opp, &oppl->opp_head, opp_node) {
+               if (flags & OPP_ENABLED && opp->enabled)
+                       enabled++;
+               total++;
        }
 
-       while (!OPP_TERM(oppl)) {
-               if (oppl->enabled) {
-                       if (oppl->rate > *freq)
-                               break;
+       mutex_unlock(&oppl->opp_mtx);
 
-                       prev_opp = oppl;
-               }
+       if (flags & OPP_ENABLED)
+               return enabled;
+       else
+               return total;
+}
 
-               oppl++;
-       }
+unsigned int get_opp_count(enum opp_t id, unsigned long flags)
+{
+       struct opp_list *oppl;
 
-       if (prev_opp->rate > *freq)
-               return ERR_PTR(-ENOENT);
+       oppl = exists(id);
+       BUG_ON(!oppl);
+       return _get_opp_count(oppl, flags);
+}
 
-       *freq = prev_opp->rate;
+static int _opp_del(struct opp_list *oppl, struct omap_opp *opp)
+{
+       mutex_lock(&oppl->opp_mtx);
+       list_del(&opp->opp_node);
+       mutex_unlock(&oppl->opp_mtx);
+       kfree(opp);
 
-       return oppl;
+       return 0;
 }
 
-/* wrapper to reuse converting opp_def to opp struct */
-static void omap_opp_populate(struct omap_opp *opp,
-                             const struct omap_opp_def *opp_def)
+int opp_del(enum opp_t id, struct omap_opp *opp)
 {
-       opp->rate = opp_def->freq;
-       opp->enabled = opp_def->enabled;
-       opp->u_volt = opp_def->u_volt;
+       struct opp_list *oppl;
+
+       oppl = exists(id);
+       BUG_ON(!oppl || !opp);
+
+       return _opp_del(oppl, opp);
 }
 
-struct omap_opp *opp_add(struct omap_opp *oppl,
-                        const struct omap_opp_def *opp_def)
+static int _opp_add(struct opp_list *oppl, struct omap_opp *opp,
+                       unsigned long flags)
 {
-       struct omap_opp *opp, *oppt, *oppr;
-       u8 n, i, ins;
+       struct omap_opp *new_opp, *tmp;
 
-       if (unlikely(!oppl || IS_ERR(oppl) || !opp_def || IS_ERR(opp_def))) {
-               pr_err("%s: Invalid params being passed\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
+       new_opp = kzalloc(sizeof(struct omap_opp), flags);
+       if (!new_opp)
+               return -ENOMEM;
 
-       n = 0;
-       opp = oppl;
-       while (!OPP_TERM(opp)) {
-               n++;
-               opp++;
-       }
+       INIT_LIST_HEAD(&new_opp->opp_node);
+       new_opp->enabled = opp->enabled;
+       new_opp->rate = opp->rate;
+       new_opp->uvolt = opp->uvolt;
+
+       mutex_lock(&oppl->opp_mtx);
 
        /*
-        * Allocate enough entries to copy the original list, plus the new
-        * OPP, plus the concluding terminator
+        * List is always sorted w.r.t. frequency. No duplicates.
         */
-       oppr = kzalloc(sizeof(struct omap_opp) * (n + 2), GFP_KERNEL);
-       if (!oppr) {
-               pr_err("%s: No memory for new opp array\n", __func__);
-               return ERR_PTR(-ENOMEM);
-       }
 
-       /* Simple insertion sort */
-       opp = oppl;
-       oppt = oppr;
-       ins = 0;
-       i = 1;
-       do {
-               if (ins || opp->rate < opp_def->freq) {
-                       memcpy(oppt, opp, sizeof(struct omap_opp));
-                       opp++;
-               } else {
-                       omap_opp_populate(oppt, opp_def);
-                       ins++;
+       tmp = _find_opp_by_freq(oppl, opp->rate, OPP_H | __OPP_NOLOCK);
+
+       if (tmp) {
+               if (tmp->rate == opp->rate) {
+                       kfree(opp);
+                       mutex_unlock(&oppl->opp_mtx);
+                       return -EEXIST;
                }
-               oppt->opp_id = i;
-               oppt++;
-               i++;
-       } while (!OPP_TERM(opp));
+               __list_add(&new_opp->opp_node, &tmp->opp_node,
+                               tmp->opp_node.next);
+       } else
+               /*
+                * If this is the lowest frequency add it to the front of the
+                * list.
+                */
+               list_add(&new_opp->opp_node, &oppl->opp_head);
 
-       /* If nothing got inserted, this belongs to the end */
-       if (!ins) {
-               omap_opp_populate(oppt, opp_def);
-               oppt->opp_id = i;
-               oppt++;
-       }
+       mutex_unlock(&oppl->opp_mtx);
 
-       /* Terminator implicitly added by kzalloc() */
+       return 0;
+}
 
-       /* Free the old list */
-       kfree(oppl);
+int opp_add(enum opp_t id, struct omap_opp *opp, unsigned long flags)
+{
+       struct opp_list *oppl;
 
-       return oppr;
+       oppl = exists(id);
+       BUG_ON(!oppl || !opp);
+       return _opp_add(oppl, opp, flags);
 }
 
-struct omap_opp __init *opp_init_list(const struct omap_opp_def *opp_defs)
+static void __init destroy_opp_list(struct opp_list *oppl)
 {
-       struct omap_opp_def *t = (struct omap_opp_def *)opp_defs;
-       struct omap_opp *opp, *oppl;
-       u8 n = 0, i = 1;
+       struct omap_opp *opp;
 
-       if (unlikely(!opp_defs || IS_ERR(opp_defs))) {
-               pr_err("%s: Invalid params being passed\n", __func__);
-               return ERR_PTR(-EINVAL);
-       }
-       /* Grab a count */
-       while (t->enabled || t->freq || t->u_volt) {
-               n++;
-               t++;
-       }
+       mutex_lock(&oppl->opp_mtx);
+       list_for_each_entry(opp, &oppl->opp_head, opp_node);
+               kfree(opp);
+       mutex_unlock(&oppl->opp_mtx);
+       return;
+}
 
-       /*
-        * Allocate enough entries to copy the original list, plus the
-        * concluding terminator
-        */
-       oppl = kzalloc(sizeof(struct omap_opp) * (n + 1), GFP_KERNEL);
-       if (!oppl) {
-               pr_err("%s: No memory for opp array\n", __func__);
-               return ERR_PTR(-ENOMEM);
-       }
+int __init create_opp_list(enum opp_t id, struct omap_opp *oppdefs)
+{
+       int ret = 0, used_slot = 0;
+       struct opp_list *oppl;
 
-       opp = oppl;
-       while (n) {
-               omap_opp_populate(opp, opp_defs);
-               opp->opp_id = i;
-               n--;
-               opp++;
-               opp_defs++;
-               i++;
-       }
+       if (unlikely(!id))
+               return -EINVAL;
 
-       /* Terminator implicitly added by kzalloc() */
+       if (exists(id))
+               return -EEXIST;
 
-       return oppl;
-}
+       oppl = get_slot();
+       BUG_ON(!oppl);
+       oppl->id = id;
 
-int opp_enable(struct omap_opp *opp)
-{
-       if (unlikely(!opp || IS_ERR(opp))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return -EINVAL;
+       while (oppdefs->rate || oppdefs->uvolt) {
+               ret = _opp_add(oppl, oppdefs, GFP_KERNEL);
+               if (ret) {
+                       destroy_opp_list(oppl);
+                       put_slot(oppl);
+                       return ret;
+               }
+               oppdefs++;
+               used_slot = 1;
        }
-       opp->enabled = true;
-       return 0;
+
+       if (!used_slot)
+               put_slot(oppl);
+
+       return ret;
 }
 
-int opp_disable(struct omap_opp *opp)
+void dump_list(enum opp_t id)
 {
-       if (unlikely(!opp || IS_ERR(opp))) {
-               pr_err("%s: Invalid parameters being passed\n", __func__);
-               return -EINVAL;
-       }
-       opp->enabled = false;
-       return 0;
+       struct omap_opp *opp;
+       struct opp_list *oppl;
+
+       oppl = exists(id);
+       if (oppl)
+               list_for_each_entry(opp, &oppl->opp_head, opp_node)
+                       printk(KERN_DEBUG"For OPP list %d, opp:%lu\n", id,
+                                       opp_to_freq(opp));
+       return;
 }
 
 /* XXX document */
-void opp_init_cpufreq_table(struct omap_opp *opps,
-                           struct cpufreq_frequency_table **table)
+void opp_init_cpufreq_table(struct cpufreq_frequency_table **table)
 {
-       int i = 0, j;
-       int opp_num;
+       int i = 0, opp_num;
+       unsigned long freq = ULONG_MAX;
+       struct omap_opp *opp;
        struct cpufreq_frequency_table *freq_table;
 
-       if (!opps) {
-               pr_warning("%s: failed to initialize frequency"
-                               "table\n", __func__);
-               return;
-       }
-
-       opp_num = opp_get_opp_count(opps);
-       if (opp_num < 0) {
+       opp_num = get_opp_count(OPP_MPU, OPP_ENABLED);
+       if (!opp_num) {
                pr_err("%s: no opp table?\n", __func__);
                return;
        }
@@ -335,14 +381,17 @@ void opp_init_cpufreq_table(struct omap_opp *opps,
                return;
        }
 
-       for (j = opp_num; j >= 0; j--) {
-               struct omap_opp *opp = &opps[j];
+       opp = find_opp_by_freq(OPP_MPU, freq, OPP_H | OPP_ENABLED);
 
-               if (opp->enabled) {
-                       freq_table[i].index = i;
-                       freq_table[i].frequency = opp->rate / 1000;
-                       i++;
-               }
+       while (opp) {
+               freq_table[i].index = i;
+               freq_table[i].frequency = opp_to_freq(opp) / 1000;
+               i++;
+               /*
+                * search the next highest frequency.
+                */
+               freq = opp_to_freq(opp) - 1;
+               opp = find_opp_by_freq(OPP_MPU, freq, OPP_H | OPP_ENABLED);
        }
 
        freq_table[i].index = i;


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to