Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ffe29d7 authored by Mike Turquette's avatar Mike Turquette
Browse files

Merge branch 'clk/clk-unregister' of git://linuxtv.org/snawrocki/samsung into clk-next-unregister

parents cdf64eee fcb0ee6a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,12 +14,14 @@

#include <linux/slab.h>

#ifndef CONFIG_COMMON_CLK
#ifdef CONFIG_HAVE_MACH_CLKDEV
#include <mach/clkdev.h>
#else
#define __clk_get(clk)	({ 1; })
#define __clk_put(clk)	do { } while (0)
#endif
#endif

static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
{
+2 −0
Original line number Diff line number Diff line
@@ -8,7 +8,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
	return kzalloc(size, GFP_KERNEL);
}

#ifndef CONFIG_COMMON_CLK
#define __clk_put(clk)
#define __clk_get(clk) ({ 1; })
#endif

#endif
+2 −0
Original line number Diff line number Diff line
@@ -14,8 +14,10 @@

#include <linux/slab.h>

#ifndef CONFIG_COMMON_CLK
#define __clk_get(clk)	({ 1; })
#define __clk_put(clk)	do { } while (0)
#endif

static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
{
+2 −0
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
		return kzalloc(size, GFP_KERNEL);
}

#ifndef CONFIG_COMMON_CLK
#define __clk_put(clk)
#define __clk_get(clk) ({ 1; })
#endif

#endif /* __CLKDEV_H__ */
+174 −11
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@
#include <linux/init.h>
#include <linux/sched.h>

#include "clk.h"

static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);

@@ -343,6 +345,21 @@ static int clk_debug_register(struct clk *clk)
	return ret;
}

 /**
 * clk_debug_unregister - remove a clk node from the debugfs clk tree
 * @clk: the clk being removed from the debugfs clk tree
 *
 * Dynamically removes a clk and all it's children clk nodes from the
 * debugfs clk tree if clk->dentry points to debugfs created by
 * clk_debug_register in __clk_init.
 *
 * Caller must hold prepare_lock.
 */
static void clk_debug_unregister(struct clk *clk)
{
	debugfs_remove_recursive(clk->dentry);
}

/**
 * clk_debug_reparent - reparent clk node in the debugfs clk tree
 * @clk: the clk being reparented
@@ -433,6 +450,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; }
static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
{
}
static inline void clk_debug_unregister(struct clk *clk)
{
}
#endif

/* caller must hold prepare_lock */
@@ -1776,6 +1796,7 @@ int __clk_init(struct device *dev, struct clk *clk)

	clk_debug_register(clk);

	kref_init(&clk->ref);
out:
	clk_prepare_unlock();

@@ -1811,6 +1832,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
	clk->flags = hw->init->flags;
	clk->parent_names = hw->init->parent_names;
	clk->num_parents = hw->init->num_parents;
	if (dev && dev->driver)
		clk->owner = dev->driver->owner;
	else
		clk->owner = NULL;

	ret = __clk_init(dev, clk);
	if (ret)
@@ -1831,6 +1856,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk)
		goto fail_name;
	}
	clk->ops = hw->init->ops;
	if (dev && dev->driver)
		clk->owner = dev->driver->owner;
	clk->hw = hw;
	clk->flags = hw->init->flags;
	clk->num_parents = hw->init->num_parents;
@@ -1905,13 +1932,104 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(clk_register);

/*
 * Free memory allocated for a clock.
 * Caller must hold prepare_lock.
 */
static void __clk_release(struct kref *ref)
{
	struct clk *clk = container_of(ref, struct clk, ref);
	int i = clk->num_parents;

	kfree(clk->parents);
	while (--i >= 0)
		kfree(clk->parent_names[i]);

	kfree(clk->parent_names);
	kfree(clk->name);
	kfree(clk);
}

/*
 * Empty clk_ops for unregistered clocks. These are used temporarily
 * after clk_unregister() was called on a clock and until last clock
 * consumer calls clk_put() and the struct clk object is freed.
 */
static int clk_nodrv_prepare_enable(struct clk_hw *hw)
{
	return -ENXIO;
}

static void clk_nodrv_disable_unprepare(struct clk_hw *hw)
{
	WARN_ON_ONCE(1);
}

static int clk_nodrv_set_rate(struct clk_hw *hw, unsigned long rate,
					unsigned long parent_rate)
{
	return -ENXIO;
}

static int clk_nodrv_set_parent(struct clk_hw *hw, u8 index)
{
	return -ENXIO;
}

static const struct clk_ops clk_nodrv_ops = {
	.enable		= clk_nodrv_prepare_enable,
	.disable	= clk_nodrv_disable_unprepare,
	.prepare	= clk_nodrv_prepare_enable,
	.unprepare	= clk_nodrv_disable_unprepare,
	.set_rate	= clk_nodrv_set_rate,
	.set_parent	= clk_nodrv_set_parent,
};

/**
 * clk_unregister - unregister a currently registered clock
 * @clk: clock to unregister
 *
 * Currently unimplemented.
 */
void clk_unregister(struct clk *clk) {}
void clk_unregister(struct clk *clk)
{
	unsigned long flags;

       if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
               return;

	clk_prepare_lock();

	if (clk->ops == &clk_nodrv_ops) {
		pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
		goto out;
	}
	/*
	 * Assign empty clock ops for consumers that might still hold
	 * a reference to this clock.
	 */
	flags = clk_enable_lock();
	clk->ops = &clk_nodrv_ops;
	clk_enable_unlock(flags);

	if (!hlist_empty(&clk->children)) {
		struct clk *child;

		/* Reparent all children to the orphan list. */
		hlist_for_each_entry(child, &clk->children, child_node)
			clk_set_parent(child, NULL);
	}

	clk_debug_unregister(clk);

	hlist_del_init(&clk->child_node);

	if (clk->prepare_count)
		pr_warn("%s: unregistering prepared clock: %s\n",
					__func__, clk->name);

	kref_put(&clk->ref, __clk_release);
out:
	clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unregister);

static void devm_clk_release(struct device *dev, void *res)
@@ -1971,6 +2089,31 @@ void devm_clk_unregister(struct device *dev, struct clk *clk)
}
EXPORT_SYMBOL_GPL(devm_clk_unregister);

/*
 * clkdev helpers
 */
int __clk_get(struct clk *clk)
{
	if (clk && !try_module_get(clk->owner))
		return 0;

	kref_get(&clk->ref);
	return 1;
}

void __clk_put(struct clk *clk)
{
	if (WARN_ON_ONCE(IS_ERR(clk)))
		return;

	clk_prepare_lock();
	kref_put(&clk->ref, __clk_release);
	clk_prepare_unlock();

	if (clk)
		module_put(clk->owner);
}

/***        clk rate change notifiers        ***/

/**
@@ -2111,7 +2254,18 @@ static const struct of_device_id __clk_of_table_sentinel
	__used __section(__clk_of_table_end);

static LIST_HEAD(of_clk_providers);
static DEFINE_MUTEX(of_clk_lock);
static DEFINE_MUTEX(of_clk_mutex);

/* of_clk_provider list locking helpers */
void of_clk_lock(void)
{
	mutex_lock(&of_clk_mutex);
}

void of_clk_unlock(void)
{
	mutex_unlock(&of_clk_mutex);
}

struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
				     void *data)
@@ -2155,9 +2309,9 @@ int of_clk_add_provider(struct device_node *np,
	cp->data = data;
	cp->get = clk_src_get;

	mutex_lock(&of_clk_lock);
	mutex_lock(&of_clk_mutex);
	list_add(&cp->link, &of_clk_providers);
	mutex_unlock(&of_clk_lock);
	mutex_unlock(&of_clk_mutex);
	pr_debug("Added clock from %s\n", np->full_name);

	return 0;
@@ -2172,7 +2326,7 @@ void of_clk_del_provider(struct device_node *np)
{
	struct of_clk_provider *cp;

	mutex_lock(&of_clk_lock);
	mutex_lock(&of_clk_mutex);
	list_for_each_entry(cp, &of_clk_providers, link) {
		if (cp->node == np) {
			list_del(&cp->link);
@@ -2181,24 +2335,33 @@ void of_clk_del_provider(struct device_node *np)
			break;
		}
	}
	mutex_unlock(&of_clk_lock);
	mutex_unlock(&of_clk_mutex);
}
EXPORT_SYMBOL_GPL(of_clk_del_provider);

struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
{
	struct of_clk_provider *provider;
	struct clk *clk = ERR_PTR(-ENOENT);

	/* Check if we have such a provider in our array */
	mutex_lock(&of_clk_lock);
	list_for_each_entry(provider, &of_clk_providers, link) {
		if (provider->node == clkspec->np)
			clk = provider->get(clkspec, provider->data);
		if (!IS_ERR(clk))
			break;
	}
	mutex_unlock(&of_clk_lock);

	return clk;
}

struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
{
	struct clk *clk;

	mutex_lock(&of_clk_mutex);
	clk = __of_clk_get_from_provider(clkspec);
	mutex_unlock(&of_clk_mutex);

	return clk;
}
Loading