1313#include <linux/clk.h>
1414#include <linux/errno.h>
1515#include <linux/err.h>
16- #include <linux/slab.h>
1716#include <linux/device.h>
1817#include <linux/export.h>
1918#include <linux/pm_domain.h>
2019#include <linux/regulator/consumer.h>
20+ #include <linux/slab.h>
21+ #include <linux/xarray.h>
2122
2223#include "opp.h"
2324
@@ -36,6 +37,9 @@ DEFINE_MUTEX(opp_table_lock);
3637/* Flag indicating that opp_tables list is being updated at the moment */
3738static bool opp_tables_busy ;
3839
40+ /* OPP ID allocator */
41+ static DEFINE_XARRAY_ALLOC1 (opp_configs );
42+
3943static bool _find_opp_dev (const struct device * dev , struct opp_table * opp_table )
4044{
4145 struct opp_device * opp_dev ;
@@ -2497,6 +2501,229 @@ int devm_pm_opp_attach_genpd(struct device *dev, const char * const *names,
24972501}
24982502EXPORT_SYMBOL_GPL (devm_pm_opp_attach_genpd );
24992503
2504+ static void _opp_clear_config (struct opp_config_data * data )
2505+ {
2506+ if (data -> flags & OPP_CONFIG_GENPD )
2507+ dev_pm_opp_detach_genpd (data -> opp_table );
2508+ if (data -> flags & OPP_CONFIG_REGULATOR )
2509+ dev_pm_opp_put_regulators (data -> opp_table );
2510+ if (data -> flags & OPP_CONFIG_SUPPORTED_HW )
2511+ dev_pm_opp_put_supported_hw (data -> opp_table );
2512+ if (data -> flags & OPP_CONFIG_REGULATOR_HELPER )
2513+ dev_pm_opp_unregister_set_opp_helper (data -> opp_table );
2514+ if (data -> flags & OPP_CONFIG_PROP_NAME )
2515+ dev_pm_opp_put_prop_name (data -> opp_table );
2516+ if (data -> flags & OPP_CONFIG_CLK )
2517+ dev_pm_opp_put_clkname (data -> opp_table );
2518+
2519+ dev_pm_opp_put_opp_table (data -> opp_table );
2520+ kfree (data );
2521+ }
2522+
2523+ /**
2524+ * dev_pm_opp_set_config() - Set OPP configuration for the device.
2525+ * @dev: Device for which configuration is being set.
2526+ * @config: OPP configuration.
2527+ *
2528+ * This allows all device OPP configurations to be performed at once.
2529+ *
2530+ * This must be called before any OPPs are initialized for the device. This may
2531+ * be called multiple times for the same OPP table, for example once for each
2532+ * CPU that share the same table. This must be balanced by the same number of
2533+ * calls to dev_pm_opp_clear_config() in order to free the OPP table properly.
2534+ *
2535+ * This returns a token to the caller, which must be passed to
2536+ * dev_pm_opp_clear_config() to free the resources later. The value of the
2537+ * returned token will be >= 1 for success and negative for errors. The minimum
2538+ * value of 1 is chosen here to make it easy for callers to manage the resource.
2539+ */
2540+ int dev_pm_opp_set_config (struct device * dev , struct dev_pm_opp_config * config )
2541+ {
2542+ struct opp_table * opp_table , * err ;
2543+ struct opp_config_data * data ;
2544+ unsigned int id ;
2545+ int ret ;
2546+
2547+ data = kmalloc (sizeof (* data ), GFP_KERNEL );
2548+ if (!data )
2549+ return - ENOMEM ;
2550+
2551+ opp_table = _add_opp_table (dev , false);
2552+ if (IS_ERR (opp_table )) {
2553+ kfree (data );
2554+ return PTR_ERR (opp_table );
2555+ }
2556+
2557+ data -> opp_table = opp_table ;
2558+ data -> flags = 0 ;
2559+
2560+ /* This should be called before OPPs are initialized */
2561+ if (WARN_ON (!list_empty (& opp_table -> opp_list ))) {
2562+ ret = - EBUSY ;
2563+ goto err ;
2564+ }
2565+
2566+ /* Configure clocks */
2567+ if (config -> clk_names ) {
2568+ const char * const * temp = config -> clk_names ;
2569+ int count = 0 ;
2570+
2571+ /* Count number of clks */
2572+ while (* temp ++ )
2573+ count ++ ;
2574+
2575+ /*
2576+ * This is a special case where we have a single clock, whose
2577+ * connection id name is NULL, i.e. first two entries are NULL
2578+ * in the array.
2579+ */
2580+ if (!count && !config -> clk_names [1 ])
2581+ count = 1 ;
2582+
2583+ /* We support only one clock name for now */
2584+ if (count != 1 ) {
2585+ ret = - EINVAL ;
2586+ goto err ;
2587+ }
2588+
2589+ err = dev_pm_opp_set_clkname (dev , config -> clk_names [0 ]);
2590+ if (IS_ERR (err )) {
2591+ ret = PTR_ERR (err );
2592+ goto err ;
2593+ }
2594+
2595+ data -> flags |= OPP_CONFIG_CLK ;
2596+ }
2597+
2598+ /* Configure property names */
2599+ if (config -> prop_name ) {
2600+ err = dev_pm_opp_set_prop_name (dev , config -> prop_name );
2601+ if (IS_ERR (err )) {
2602+ ret = PTR_ERR (err );
2603+ goto err ;
2604+ }
2605+
2606+ data -> flags |= OPP_CONFIG_PROP_NAME ;
2607+ }
2608+
2609+ /* Configure opp helper */
2610+ if (config -> set_opp ) {
2611+ err = dev_pm_opp_register_set_opp_helper (dev , config -> set_opp );
2612+ if (IS_ERR (err )) {
2613+ ret = PTR_ERR (err );
2614+ goto err ;
2615+ }
2616+
2617+ data -> flags |= OPP_CONFIG_REGULATOR_HELPER ;
2618+ }
2619+
2620+ /* Configure supported hardware */
2621+ if (config -> supported_hw ) {
2622+ err = dev_pm_opp_set_supported_hw (dev , config -> supported_hw ,
2623+ config -> supported_hw_count );
2624+ if (IS_ERR (err )) {
2625+ ret = PTR_ERR (err );
2626+ goto err ;
2627+ }
2628+
2629+ data -> flags |= OPP_CONFIG_SUPPORTED_HW ;
2630+ }
2631+
2632+ /* Configure supplies */
2633+ if (config -> regulator_names ) {
2634+ err = dev_pm_opp_set_regulators (dev , config -> regulator_names );
2635+ if (IS_ERR (err )) {
2636+ ret = PTR_ERR (err );
2637+ goto err ;
2638+ }
2639+
2640+ data -> flags |= OPP_CONFIG_REGULATOR ;
2641+ }
2642+
2643+ /* Attach genpds */
2644+ if (config -> genpd_names ) {
2645+ err = dev_pm_opp_attach_genpd (dev , config -> genpd_names ,
2646+ config -> virt_devs );
2647+ if (IS_ERR (err )) {
2648+ ret = PTR_ERR (err );
2649+ goto err ;
2650+ }
2651+
2652+ data -> flags |= OPP_CONFIG_GENPD ;
2653+ }
2654+
2655+ ret = xa_alloc (& opp_configs , & id , data , XA_LIMIT (1 , INT_MAX ),
2656+ GFP_KERNEL );
2657+ if (ret )
2658+ goto err ;
2659+
2660+ return id ;
2661+
2662+ err :
2663+ _opp_clear_config (data );
2664+ return ret ;
2665+ }
2666+ EXPORT_SYMBOL_GPL (dev_pm_opp_set_config );
2667+
2668+ /**
2669+ * dev_pm_opp_clear_config() - Releases resources blocked for OPP configuration.
2670+ * @opp_table: OPP table returned from dev_pm_opp_set_config().
2671+ *
2672+ * This allows all device OPP configurations to be cleared at once. This must be
2673+ * called once for each call made to dev_pm_opp_set_config(), in order to free
2674+ * the OPPs properly.
2675+ *
2676+ * Currently the first call itself ends up freeing all the OPP configurations,
2677+ * while the later ones only drop the OPP table reference. This works well for
2678+ * now as we would never want to use an half initialized OPP table and want to
2679+ * remove the configurations together.
2680+ */
2681+ void dev_pm_opp_clear_config (int token )
2682+ {
2683+ struct opp_config_data * data ;
2684+
2685+ /*
2686+ * This lets the callers call this unconditionally and keep their code
2687+ * simple.
2688+ */
2689+ if (unlikely (token <= 0 ))
2690+ return ;
2691+
2692+ data = xa_erase (& opp_configs , token );
2693+ if (WARN_ON (!data ))
2694+ return ;
2695+
2696+ _opp_clear_config (data );
2697+ }
2698+ EXPORT_SYMBOL_GPL (dev_pm_opp_clear_config );
2699+
2700+ static void devm_pm_opp_config_release (void * token )
2701+ {
2702+ dev_pm_opp_clear_config ((unsigned long )token );
2703+ }
2704+
2705+ /**
2706+ * devm_pm_opp_set_config() - Set OPP configuration for the device.
2707+ * @dev: Device for which configuration is being set.
2708+ * @config: OPP configuration.
2709+ *
2710+ * This allows all device OPP configurations to be performed at once.
2711+ * This is a resource-managed variant of dev_pm_opp_set_config().
2712+ *
2713+ * Return: 0 on success and errorno otherwise.
2714+ */
2715+ int devm_pm_opp_set_config (struct device * dev , struct dev_pm_opp_config * config )
2716+ {
2717+ int token = dev_pm_opp_set_config (dev , config );
2718+
2719+ if (token < 0 )
2720+ return token ;
2721+
2722+ return devm_add_action_or_reset (dev , devm_pm_opp_config_release ,
2723+ (void * ) ((unsigned long ) token ));
2724+ }
2725+ EXPORT_SYMBOL_GPL (devm_pm_opp_set_config );
2726+
25002727/**
25012728 * dev_pm_opp_xlate_required_opp() - Find required OPP for @src_table OPP.
25022729 * @src_table: OPP table which has @dst_table as one of its required OPP table.
0 commit comments