@@ -476,6 +476,16 @@ static unsigned long _read_bw(struct dev_pm_opp *opp, int index)
476476 return opp -> bandwidth [index ].peak ;
477477}
478478
479+ static unsigned long _read_opp_key (struct dev_pm_opp * opp , int index ,
480+ struct dev_pm_opp_key * key )
481+ {
482+ key -> bw = opp -> bandwidth ? opp -> bandwidth [index ].peak : 0 ;
483+ key -> freq = opp -> rates [index ];
484+ key -> level = opp -> level ;
485+
486+ return true;
487+ }
488+
479489/* Generic comparison helpers */
480490static bool _compare_exact (struct dev_pm_opp * * opp , struct dev_pm_opp * temp_opp ,
481491 unsigned long opp_key , unsigned long key )
@@ -509,6 +519,22 @@ static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
509519 return false;
510520}
511521
522+ static bool _compare_opp_key_exact (struct dev_pm_opp * * opp ,
523+ struct dev_pm_opp * temp_opp , struct dev_pm_opp_key * opp_key ,
524+ struct dev_pm_opp_key * key )
525+ {
526+ bool level_match = (key -> level == OPP_LEVEL_UNSET || opp_key -> level == key -> level );
527+ bool freq_match = (key -> freq == 0 || opp_key -> freq == key -> freq );
528+ bool bw_match = (key -> bw == 0 || opp_key -> bw == key -> bw );
529+
530+ if (freq_match && level_match && bw_match ) {
531+ * opp = temp_opp ;
532+ return true;
533+ }
534+
535+ return false;
536+ }
537+
512538/* Generic key finding helpers */
513539static struct dev_pm_opp * _opp_table_find_key (struct opp_table * opp_table ,
514540 unsigned long * key , int index , bool available ,
@@ -541,6 +567,37 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
541567 return opp ;
542568}
543569
570+ static struct dev_pm_opp * _opp_table_find_opp_key (struct opp_table * opp_table ,
571+ struct dev_pm_opp_key * key , bool available ,
572+ unsigned long (* read )(struct dev_pm_opp * opp , int index ,
573+ struct dev_pm_opp_key * key ),
574+ bool (* compare )(struct dev_pm_opp * * opp , struct dev_pm_opp * temp_opp ,
575+ struct dev_pm_opp_key * opp_key , struct dev_pm_opp_key * key ),
576+ bool (* assert )(struct opp_table * opp_table , unsigned int index ))
577+ {
578+ struct dev_pm_opp * temp_opp , * opp = ERR_PTR (- ERANGE );
579+ struct dev_pm_opp_key temp_key ;
580+
581+ /* Assert that the requirement is met */
582+ if (!assert (opp_table , 0 ))
583+ return ERR_PTR (- EINVAL );
584+
585+ guard (mutex )(& opp_table -> lock );
586+
587+ list_for_each_entry (temp_opp , & opp_table -> opp_list , node ) {
588+ if (temp_opp -> available == available ) {
589+ read (temp_opp , 0 , & temp_key );
590+ if (compare (& opp , temp_opp , & temp_key , key )) {
591+ /* Increment the reference count of OPP */
592+ dev_pm_opp_get (opp );
593+ break ;
594+ }
595+ }
596+ }
597+
598+ return opp ;
599+ }
600+
544601static struct dev_pm_opp *
545602_find_key (struct device * dev , unsigned long * key , int index , bool available ,
546603 unsigned long (* read )(struct dev_pm_opp * opp , int index ),
@@ -632,6 +689,48 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
632689}
633690EXPORT_SYMBOL_GPL (dev_pm_opp_find_freq_exact );
634691
692+ /**
693+ * dev_pm_opp_find_key_exact() - Search for an OPP with exact key set
694+ * @dev: Device for which the OPP is being searched
695+ * @key: OPP key set to match
696+ * @available: true/false - match for available OPP
697+ *
698+ * Search for an exact match of the key set in the OPP table.
699+ *
700+ * Return: A matching opp on success, else ERR_PTR in case of error.
701+ * Possible error values:
702+ * EINVAL: for bad pointers
703+ * ERANGE: no match found for search
704+ * ENODEV: if device not found in list of registered devices
705+ *
706+ * Note: 'available' is a modifier for the search. If 'available' == true,
707+ * then the match is for exact matching key and is available in the stored
708+ * OPP table. If false, the match is for exact key which is not available.
709+ *
710+ * This provides a mechanism to enable an OPP which is not available currently
711+ * or the opposite as well.
712+ *
713+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
714+ * use.
715+ */
716+ struct dev_pm_opp * dev_pm_opp_find_key_exact (struct device * dev ,
717+ struct dev_pm_opp_key * key ,
718+ bool available )
719+ {
720+ struct opp_table * opp_table __free (put_opp_table ) = _find_opp_table (dev );
721+
722+ if (IS_ERR (opp_table )) {
723+ dev_err (dev , "%s: OPP table not found (%ld)\n" , __func__ ,
724+ PTR_ERR (opp_table ));
725+ return ERR_CAST (opp_table );
726+ }
727+
728+ return _opp_table_find_opp_key (opp_table , key , available ,
729+ _read_opp_key , _compare_opp_key_exact ,
730+ assert_single_clk );
731+ }
732+ EXPORT_SYMBOL_GPL (dev_pm_opp_find_key_exact );
733+
635734/**
636735 * dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
637736 * clock corresponding to the index
0 commit comments