Loading drivers/clk/Makefile +1 −1 Original line number Diff line number Diff line # common clock types obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o Loading drivers/clk/clk-bulk.c 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * Copyright 2017 NXP * * Dong Aisheng <aisheng.dong@nxp.com> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> #include <linux/device.h> #include <linux/export.h> void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) { while (--num_clks >= 0) { clk_put(clks[num_clks].clk); clks[num_clks].clk = NULL; } } EXPORT_SYMBOL_GPL(clk_bulk_put); int __must_check clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) clks[i].clk = NULL; for (i = 0; i < num_clks; i++) { clks[i].clk = clk_get(dev, clks[i].id); if (IS_ERR(clks[i].clk)) { ret = PTR_ERR(clks[i].clk); dev_err(dev, "Failed to get clk '%s': %d\n", clks[i].id, ret); clks[i].clk = NULL; goto err; } } return 0; err: clk_bulk_put(i, clks); return ret; } EXPORT_SYMBOL(clk_bulk_get); #ifdef CONFIG_HAVE_CLK_PREPARE /** * clk_bulk_unprepare - undo preparation of a set of clock sources * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being unprepared * * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable. * Returns 0 on success, -EERROR otherwise. */ void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks) { while (--num_clks >= 0) clk_unprepare(clks[num_clks].clk); } EXPORT_SYMBOL_GPL(clk_bulk_unprepare); /** * clk_bulk_prepare - prepare a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being prepared * * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable. * Returns 0 on success, -EERROR otherwise. */ int __must_check clk_bulk_prepare(int num_clks, const struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) { ret = clk_prepare(clks[i].clk); if (ret) { pr_err("Failed to prepare clk '%s': %d\n", clks[i].id, ret); goto err; } } return 0; err: clk_bulk_unprepare(i, clks); return ret; } #endif /* CONFIG_HAVE_CLK_PREPARE */ /** * clk_bulk_disable - gate a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being gated * * clk_bulk_disable must not sleep, which differentiates it from * clk_bulk_unprepare. clk_bulk_disable must be called before * clk_bulk_unprepare. */ void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks) { while (--num_clks >= 0) clk_disable(clks[num_clks].clk); } EXPORT_SYMBOL_GPL(clk_bulk_disable); /** * clk_bulk_enable - ungate a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being ungated * * clk_bulk_enable must not sleep * Returns 0 on success, -EERROR otherwise. */ int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) { ret = clk_enable(clks[i].clk); if (ret) { pr_err("Failed to enable clk '%s': %d\n", clks[i].id, ret); goto err; } } return 0; err: clk_bulk_disable(i, clks); return ret; } EXPORT_SYMBOL_GPL(clk_bulk_enable); drivers/clk/clk-devres.c +36 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,42 @@ struct clk *devm_clk_get(struct device *dev, const char *id) } EXPORT_SYMBOL(devm_clk_get); struct clk_bulk_devres { struct clk_bulk_data *clks; int num_clks; }; static void devm_clk_bulk_release(struct device *dev, void *res) { struct clk_bulk_devres *devres = res; clk_bulk_put(devres->num_clks, devres->clks); } int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { struct clk_bulk_devres *devres; int ret; devres = devres_alloc(devm_clk_bulk_release, sizeof(*devres), GFP_KERNEL); if (!devres) return -ENOMEM; ret = clk_bulk_get(dev, num_clks, clks); if (!ret) { devres->clks = clks; devres->num_clks = num_clks; devres_add(dev, devres); } else { devres_free(devres); } return ret; } EXPORT_SYMBOL_GPL(devm_clk_bulk_get); static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk **c = res; Loading include/linux/clk.h +132 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,21 @@ struct clk_notifier_data { unsigned long new_rate; }; /** * struct clk_bulk_data - Data used for bulk clk operations. * * @id: clock consumer ID * @clk: struct clk * to store the associated clock * * The CLK APIs provide a series of clk_bulk_() API calls as * a convenience to consumers which require multiple clks. This * structure is used to manage data for these calls. */ struct clk_bulk_data { const char *id; struct clk *clk; }; #ifdef CONFIG_COMMON_CLK /** Loading Loading @@ -185,12 +200,20 @@ static inline bool clk_is_match(const struct clk *p, const struct clk *q) */ #ifdef CONFIG_HAVE_CLK_PREPARE int clk_prepare(struct clk *clk); int __must_check clk_bulk_prepare(int num_clks, const struct clk_bulk_data *clks); #else static inline int clk_prepare(struct clk *clk) { might_sleep(); return 0; } static inline int clk_bulk_prepare(int num_clks, struct clk_bulk_data *clks) { might_sleep(); return 0; } #endif /** Loading @@ -204,11 +227,16 @@ static inline int clk_prepare(struct clk *clk) */ #ifdef CONFIG_HAVE_CLK_PREPARE void clk_unprepare(struct clk *clk); void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks); #else static inline void clk_unprepare(struct clk *clk) { might_sleep(); } static inline void clk_bulk_unprepare(int num_clks, struct clk_bulk_data *clks) { might_sleep(); } #endif #ifdef CONFIG_HAVE_CLK Loading @@ -229,6 +257,44 @@ static inline void clk_unprepare(struct clk *clk) */ struct clk *clk_get(struct device *dev, const char *id); /** * clk_bulk_get - lookup and obtain a number of references to clock producer. * @dev: device for clock "consumer" * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * This helper function allows drivers to get several clk consumers in one * operation. If any of the clk cannot be acquired then any clks * that were obtained will be freed before returning to the caller. * * Returns 0 if all clocks specified in clk_bulk_data table are obtained * successfully, or valid IS_ERR() condition containing errno. * The implementation uses @dev and @clk_bulk_data.id to determine the * clock consumer, and thereby the clock producer. * The clock returned is stored in each @clk_bulk_data.clk field. * * Drivers must assume that the clock source is not enabled. * * clk_bulk_get should not be called from within interrupt context. */ int __must_check clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks); /** * devm_clk_bulk_get - managed get multiple clk consumers * @dev: device for clock "consumer" * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Return 0 on success, an errno on failure. * * This helper function allows drivers to get several clk * consumers in one operation with management, the clks will * automatically be freed when the device is unbound. */ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks); /** * devm_clk_get - lookup and obtain a managed reference to a clock producer. * @dev: device for clock "consumer" Loading Loading @@ -278,6 +344,18 @@ struct clk *devm_get_clk_from_child(struct device *dev, */ int clk_enable(struct clk *clk); /** * clk_bulk_enable - inform the system when the set of clks should be running. * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * May be called from atomic contexts. * * Returns success (0) or negative errno. */ int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks); /** * clk_disable - inform the system when the clock source is no longer required. * @clk: clock source Loading @@ -294,6 +372,24 @@ int clk_enable(struct clk *clk); */ void clk_disable(struct clk *clk); /** * clk_bulk_disable - inform the system when the set of clks is no * longer required. * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Inform the system that a set of clks is no longer required by * a driver and may be shut down. * * May be called from atomic contexts. * * Implementation detail: if the set of clks is shared between * multiple drivers, clk_bulk_enable() calls must be balanced by the * same number of clk_bulk_disable() calls for the clock source to be * disabled. */ void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); /** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. Loading @@ -313,6 +409,19 @@ unsigned long clk_get_rate(struct clk *clk); */ void clk_put(struct clk *clk); /** * clk_bulk_put - "free" the clock source * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Note: drivers must ensure that all clk_bulk_enable calls made on this * clock source are balanced by clk_bulk_disable calls prior to calling * this function. * * clk_bulk_put should not be called from within interrupt context. */ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks); /** * devm_clk_put - "free" a managed clock source * @dev: device used to acquire the clock Loading Loading @@ -445,11 +554,23 @@ static inline struct clk *clk_get(struct device *dev, const char *id) return NULL; } static inline int clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { return 0; } static inline struct clk *devm_clk_get(struct device *dev, const char *id) { return NULL; } static inline int devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { return 0; } static inline struct clk *devm_get_clk_from_child(struct device *dev, struct device_node *np, const char *con_id) { Loading @@ -458,6 +579,8 @@ static inline struct clk *devm_get_clk_from_child(struct device *dev, static inline void clk_put(struct clk *clk) {} static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {} static inline void devm_clk_put(struct device *dev, struct clk *clk) {} static inline int clk_enable(struct clk *clk) Loading @@ -465,8 +588,17 @@ static inline int clk_enable(struct clk *clk) return 0; } static inline int clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) { return 0; } static inline void clk_disable(struct clk *clk) {} static inline void clk_bulk_disable(int num_clks, struct clk_bulk_data *clks) {} static inline unsigned long clk_get_rate(struct clk *clk) { return 0; Loading Loading
drivers/clk/Makefile +1 −1 Original line number Diff line number Diff line # common clock types obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o Loading
drivers/clk/clk-bulk.c 0 → 100644 +157 −0 Original line number Diff line number Diff line /* * Copyright 2017 NXP * * Dong Aisheng <aisheng.dong@nxp.com> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <linux/clk.h> #include <linux/device.h> #include <linux/export.h> void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) { while (--num_clks >= 0) { clk_put(clks[num_clks].clk); clks[num_clks].clk = NULL; } } EXPORT_SYMBOL_GPL(clk_bulk_put); int __must_check clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) clks[i].clk = NULL; for (i = 0; i < num_clks; i++) { clks[i].clk = clk_get(dev, clks[i].id); if (IS_ERR(clks[i].clk)) { ret = PTR_ERR(clks[i].clk); dev_err(dev, "Failed to get clk '%s': %d\n", clks[i].id, ret); clks[i].clk = NULL; goto err; } } return 0; err: clk_bulk_put(i, clks); return ret; } EXPORT_SYMBOL(clk_bulk_get); #ifdef CONFIG_HAVE_CLK_PREPARE /** * clk_bulk_unprepare - undo preparation of a set of clock sources * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being unprepared * * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable. * Returns 0 on success, -EERROR otherwise. */ void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks) { while (--num_clks >= 0) clk_unprepare(clks[num_clks].clk); } EXPORT_SYMBOL_GPL(clk_bulk_unprepare); /** * clk_bulk_prepare - prepare a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being prepared * * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable. * Returns 0 on success, -EERROR otherwise. */ int __must_check clk_bulk_prepare(int num_clks, const struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) { ret = clk_prepare(clks[i].clk); if (ret) { pr_err("Failed to prepare clk '%s': %d\n", clks[i].id, ret); goto err; } } return 0; err: clk_bulk_unprepare(i, clks); return ret; } #endif /* CONFIG_HAVE_CLK_PREPARE */ /** * clk_bulk_disable - gate a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being gated * * clk_bulk_disable must not sleep, which differentiates it from * clk_bulk_unprepare. clk_bulk_disable must be called before * clk_bulk_unprepare. */ void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks) { while (--num_clks >= 0) clk_disable(clks[num_clks].clk); } EXPORT_SYMBOL_GPL(clk_bulk_disable); /** * clk_bulk_enable - ungate a set of clocks * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table being ungated * * clk_bulk_enable must not sleep * Returns 0 on success, -EERROR otherwise. */ int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks) { int ret; int i; for (i = 0; i < num_clks; i++) { ret = clk_enable(clks[i].clk); if (ret) { pr_err("Failed to enable clk '%s': %d\n", clks[i].id, ret); goto err; } } return 0; err: clk_bulk_disable(i, clks); return ret; } EXPORT_SYMBOL_GPL(clk_bulk_enable);
drivers/clk/clk-devres.c +36 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,42 @@ struct clk *devm_clk_get(struct device *dev, const char *id) } EXPORT_SYMBOL(devm_clk_get); struct clk_bulk_devres { struct clk_bulk_data *clks; int num_clks; }; static void devm_clk_bulk_release(struct device *dev, void *res) { struct clk_bulk_devres *devres = res; clk_bulk_put(devres->num_clks, devres->clks); } int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { struct clk_bulk_devres *devres; int ret; devres = devres_alloc(devm_clk_bulk_release, sizeof(*devres), GFP_KERNEL); if (!devres) return -ENOMEM; ret = clk_bulk_get(dev, num_clks, clks); if (!ret) { devres->clks = clks; devres->num_clks = num_clks; devres_add(dev, devres); } else { devres_free(devres); } return ret; } EXPORT_SYMBOL_GPL(devm_clk_bulk_get); static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk **c = res; Loading
include/linux/clk.h +132 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,21 @@ struct clk_notifier_data { unsigned long new_rate; }; /** * struct clk_bulk_data - Data used for bulk clk operations. * * @id: clock consumer ID * @clk: struct clk * to store the associated clock * * The CLK APIs provide a series of clk_bulk_() API calls as * a convenience to consumers which require multiple clks. This * structure is used to manage data for these calls. */ struct clk_bulk_data { const char *id; struct clk *clk; }; #ifdef CONFIG_COMMON_CLK /** Loading Loading @@ -185,12 +200,20 @@ static inline bool clk_is_match(const struct clk *p, const struct clk *q) */ #ifdef CONFIG_HAVE_CLK_PREPARE int clk_prepare(struct clk *clk); int __must_check clk_bulk_prepare(int num_clks, const struct clk_bulk_data *clks); #else static inline int clk_prepare(struct clk *clk) { might_sleep(); return 0; } static inline int clk_bulk_prepare(int num_clks, struct clk_bulk_data *clks) { might_sleep(); return 0; } #endif /** Loading @@ -204,11 +227,16 @@ static inline int clk_prepare(struct clk *clk) */ #ifdef CONFIG_HAVE_CLK_PREPARE void clk_unprepare(struct clk *clk); void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks); #else static inline void clk_unprepare(struct clk *clk) { might_sleep(); } static inline void clk_bulk_unprepare(int num_clks, struct clk_bulk_data *clks) { might_sleep(); } #endif #ifdef CONFIG_HAVE_CLK Loading @@ -229,6 +257,44 @@ static inline void clk_unprepare(struct clk *clk) */ struct clk *clk_get(struct device *dev, const char *id); /** * clk_bulk_get - lookup and obtain a number of references to clock producer. * @dev: device for clock "consumer" * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * This helper function allows drivers to get several clk consumers in one * operation. If any of the clk cannot be acquired then any clks * that were obtained will be freed before returning to the caller. * * Returns 0 if all clocks specified in clk_bulk_data table are obtained * successfully, or valid IS_ERR() condition containing errno. * The implementation uses @dev and @clk_bulk_data.id to determine the * clock consumer, and thereby the clock producer. * The clock returned is stored in each @clk_bulk_data.clk field. * * Drivers must assume that the clock source is not enabled. * * clk_bulk_get should not be called from within interrupt context. */ int __must_check clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks); /** * devm_clk_bulk_get - managed get multiple clk consumers * @dev: device for clock "consumer" * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Return 0 on success, an errno on failure. * * This helper function allows drivers to get several clk * consumers in one operation with management, the clks will * automatically be freed when the device is unbound. */ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks); /** * devm_clk_get - lookup and obtain a managed reference to a clock producer. * @dev: device for clock "consumer" Loading Loading @@ -278,6 +344,18 @@ struct clk *devm_get_clk_from_child(struct device *dev, */ int clk_enable(struct clk *clk); /** * clk_bulk_enable - inform the system when the set of clks should be running. * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * May be called from atomic contexts. * * Returns success (0) or negative errno. */ int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks); /** * clk_disable - inform the system when the clock source is no longer required. * @clk: clock source Loading @@ -294,6 +372,24 @@ int clk_enable(struct clk *clk); */ void clk_disable(struct clk *clk); /** * clk_bulk_disable - inform the system when the set of clks is no * longer required. * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Inform the system that a set of clks is no longer required by * a driver and may be shut down. * * May be called from atomic contexts. * * Implementation detail: if the set of clks is shared between * multiple drivers, clk_bulk_enable() calls must be balanced by the * same number of clk_bulk_disable() calls for the clock source to be * disabled. */ void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks); /** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. Loading @@ -313,6 +409,19 @@ unsigned long clk_get_rate(struct clk *clk); */ void clk_put(struct clk *clk); /** * clk_bulk_put - "free" the clock source * @num_clks: the number of clk_bulk_data * @clks: the clk_bulk_data table of consumer * * Note: drivers must ensure that all clk_bulk_enable calls made on this * clock source are balanced by clk_bulk_disable calls prior to calling * this function. * * clk_bulk_put should not be called from within interrupt context. */ void clk_bulk_put(int num_clks, struct clk_bulk_data *clks); /** * devm_clk_put - "free" a managed clock source * @dev: device used to acquire the clock Loading Loading @@ -445,11 +554,23 @@ static inline struct clk *clk_get(struct device *dev, const char *id) return NULL; } static inline int clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { return 0; } static inline struct clk *devm_clk_get(struct device *dev, const char *id) { return NULL; } static inline int devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks) { return 0; } static inline struct clk *devm_get_clk_from_child(struct device *dev, struct device_node *np, const char *con_id) { Loading @@ -458,6 +579,8 @@ static inline struct clk *devm_get_clk_from_child(struct device *dev, static inline void clk_put(struct clk *clk) {} static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {} static inline void devm_clk_put(struct device *dev, struct clk *clk) {} static inline int clk_enable(struct clk *clk) Loading @@ -465,8 +588,17 @@ static inline int clk_enable(struct clk *clk) return 0; } static inline int clk_bulk_enable(int num_clks, struct clk_bulk_data *clks) { return 0; } static inline void clk_disable(struct clk *clk) {} static inline void clk_bulk_disable(int num_clks, struct clk_bulk_data *clks) {} static inline unsigned long clk_get_rate(struct clk *clk) { return 0; Loading