diff options
author | Stephen Boyd <sboyd@kernel.org> | 2018-04-06 22:38:08 +0200 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-04-06 22:38:08 +0200 |
commit | b44c4ddf4a15c42a91a88aaa32b7d53cf43391cb (patch) | |
tree | 04dbcb069c73c3c1fd82d177c50f44fac75beff1 /drivers | |
parent | Merge branches 'clk-stratix10', 'clk-imx', 'clk-bcm', 'clk-cs2000' and 'clk-i... (diff) | |
parent | clk: davinci: add a reset lookup table for psc0 (diff) | |
download | linux-b44c4ddf4a15c42a91a88aaa32b7d53cf43391cb.tar.xz linux-b44c4ddf4a15c42a91a88aaa32b7d53cf43391cb.zip |
Merge branch 'clk-davinci' into clk-next
* clk-davinci:
clk: davinci: add a reset lookup table for psc0
reset: modify the way reset lookup works for board files
reset: add support for non-DT systems
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/davinci/psc-da850.c | 7 | ||||
-rw-r--r-- | drivers/clk/davinci/psc.c | 1 | ||||
-rw-r--r-- | drivers/reset/core.c | 96 |
3 files changed, 103 insertions, 1 deletions
diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c index ccc7eb17bf3a..d196dcbed560 100644 --- a/drivers/clk/davinci/psc-da850.c +++ b/drivers/clk/davinci/psc-da850.c @@ -6,6 +6,7 @@ */ #include <linux/clk-provider.h> +#include <linux/reset-controller.h> #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/init.h> @@ -66,8 +67,14 @@ LPSC_CLKDEV3(ecap_clkdev, "fck", "ecap.0", "fck", "ecap.1", "fck", "ecap.2"); +static struct reset_control_lookup da850_psc0_reset_lookup_table[] = { + RESET_LOOKUP("da850-psc0", 15, "davinci-rproc.0", NULL), +}; + static int da850_psc0_init(struct device *dev, void __iomem *base) { + reset_controller_add_lookup(da850_psc0_reset_lookup_table, + ARRAY_SIZE(da850_psc0_reset_lookup_table)); return davinci_psc_register_clocks(dev, da850_psc0_info, 16, base); } diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index ff6f4a038e04..ce170e600f09 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -425,6 +425,7 @@ __davinci_psc_register_clocks(struct device *dev, psc->rcdev.ops = &davinci_psc_reset_ops; psc->rcdev.owner = THIS_MODULE; + psc->rcdev.dev = dev; psc->rcdev.of_node = dev->of_node; psc->rcdev.of_reset_n_cells = 1; psc->rcdev.of_xlate = davinci_psc_reset_of_xlate; diff --git a/drivers/reset/core.c b/drivers/reset/core.c index da4292e9de97..6488292e129c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -23,6 +23,9 @@ static DEFINE_MUTEX(reset_list_mutex); static LIST_HEAD(reset_controller_list); +static DEFINE_MUTEX(reset_lookup_mutex); +static LIST_HEAD(reset_lookup_list); + /** * struct reset_control - a reset control * @rcdev: a pointer to the reset controller device @@ -148,6 +151,33 @@ int devm_reset_controller_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_reset_controller_register); +/** + * reset_controller_add_lookup - register a set of lookup entries + * @lookup: array of reset lookup entries + * @num_entries: number of entries in the lookup array + */ +void reset_controller_add_lookup(struct reset_control_lookup *lookup, + unsigned int num_entries) +{ + struct reset_control_lookup *entry; + unsigned int i; + + mutex_lock(&reset_lookup_mutex); + for (i = 0; i < num_entries; i++) { + entry = &lookup[i]; + + if (!entry->dev_id || !entry->provider) { + pr_warn("%s(): reset lookup entry badly specified, skipping\n", + __func__); + continue; + } + + list_add_tail(&entry->list, &reset_lookup_list); + } + mutex_unlock(&reset_lookup_mutex); +} +EXPORT_SYMBOL_GPL(reset_controller_add_lookup); + static inline struct reset_control_array * rstc_to_array(struct reset_control *rstc) { return container_of(rstc, struct reset_control_array, base); @@ -493,6 +523,70 @@ struct reset_control *__of_reset_control_get(struct device_node *node, } EXPORT_SYMBOL_GPL(__of_reset_control_get); +static struct reset_controller_dev * +__reset_controller_by_name(const char *name) +{ + struct reset_controller_dev *rcdev; + + lockdep_assert_held(&reset_list_mutex); + + list_for_each_entry(rcdev, &reset_controller_list, list) { + if (!rcdev->dev) + continue; + + if (!strcmp(name, dev_name(rcdev->dev))) + return rcdev; + } + + return NULL; +} + +static struct reset_control * +__reset_control_get_from_lookup(struct device *dev, const char *con_id, + bool shared, bool optional) +{ + const struct reset_control_lookup *lookup; + struct reset_controller_dev *rcdev; + const char *dev_id = dev_name(dev); + struct reset_control *rstc = NULL; + + if (!dev) + return ERR_PTR(-EINVAL); + + mutex_lock(&reset_lookup_mutex); + + list_for_each_entry(lookup, &reset_lookup_list, list) { + if (strcmp(lookup->dev_id, dev_id)) + continue; + + if ((!con_id && !lookup->con_id) || + ((con_id && lookup->con_id) && + !strcmp(con_id, lookup->con_id))) { + mutex_lock(&reset_list_mutex); + rcdev = __reset_controller_by_name(lookup->provider); + if (!rcdev) { + mutex_unlock(&reset_list_mutex); + mutex_unlock(&reset_lookup_mutex); + /* Reset provider may not be ready yet. */ + return ERR_PTR(-EPROBE_DEFER); + } + + rstc = __reset_control_get_internal(rcdev, + lookup->index, + shared); + mutex_unlock(&reset_list_mutex); + break; + } + } + + mutex_unlock(&reset_lookup_mutex); + + if (!rstc) + return optional ? NULL : ERR_PTR(-ENOENT); + + return rstc; +} + struct reset_control *__reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional) { @@ -500,7 +594,7 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id, return __of_reset_control_get(dev->of_node, id, index, shared, optional); - return optional ? NULL : ERR_PTR(-EINVAL); + return __reset_control_get_from_lookup(dev, id, shared, optional); } EXPORT_SYMBOL_GPL(__reset_control_get); |