Loading Documentation/driver-model/devres.txt +4 −0 Original line number Diff line number Diff line Loading @@ -276,3 +276,7 @@ REGULATOR devm_regulator_get() devm_regulator_put() devm_regulator_bulk_get() CLOCK devm_clk_get() devm_clk_put() drivers/clk/clkdev.c +132 −10 Original line number Diff line number Diff line Loading @@ -35,7 +35,12 @@ static DEFINE_MUTEX(clocks_mutex); static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { struct clk_lookup *p, *cl = NULL; int match, best = 0; int match, best_found = 0, best_possible = 0; if (dev_id) best_possible += 2; if (con_id) best_possible += 1; list_for_each_entry(p, &clocks, node) { match = 0; Loading @@ -50,10 +55,10 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) match += 1; } if (match > best) { if (match > best_found) { cl = p; if (match != 3) best = match; if (match != best_possible) best_found = match; else break; } Loading Loading @@ -89,6 +94,51 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); static void devm_clk_release(struct device *dev, void *res) { clk_put(*(struct clk **)res); } struct clk *devm_clk_get(struct device *dev, const char *id) { struct clk **ptr, *clk; ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); clk = clk_get(dev, id); if (!IS_ERR(clk)) { *ptr = clk; devres_add(dev, ptr); } else { devres_free(ptr); } return clk; } EXPORT_SYMBOL(devm_clk_get); static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk **c = res; if (!c || !*c) { WARN_ON(!c || !*c); return 0; } return *c == data; } void devm_clk_put(struct device *dev, struct clk *clk) { int ret; ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); WARN_ON(ret); } EXPORT_SYMBOL(devm_clk_put); void clkdev_add(struct clk_lookup *cl) { mutex_lock(&clocks_mutex); Loading Loading @@ -116,8 +166,9 @@ struct clk_lookup_alloc { char con_id[MAX_CON_ID]; }; struct clk_lookup * __init_refok clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) static struct clk_lookup * __init_refok vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, va_list ap) { struct clk_lookup_alloc *cla; Loading @@ -132,16 +183,25 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) } if (dev_fmt) { va_list ap; va_start(ap, dev_fmt); vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); cla->cl.dev_id = cla->dev_id; va_end(ap); } return &cla->cl; } struct clk_lookup * __init_refok clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup *cl; va_list ap; va_start(ap, dev_fmt); cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); va_end(ap); return cl; } EXPORT_SYMBOL(clkdev_alloc); int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, Loading Loading @@ -173,3 +233,65 @@ void clkdev_drop(struct clk_lookup *cl) kfree(cl); } EXPORT_SYMBOL(clkdev_drop); /** * clk_register_clkdev - register one clock lookup for a struct clk * @clk: struct clk to associate with all clk_lookups * @con_id: connection ID string on device * @dev_id: format string describing device name * * con_id or dev_id may be NULL as a wildcard, just as in the rest of * clkdev. * * To make things easier for mass registration, we detect error clks * from a previous clk_register() call, and return the error code for * those. This is to permit this function to be called immediately * after clk_register(). */ int clk_register_clkdev(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup *cl; va_list ap; if (IS_ERR(clk)) return PTR_ERR(clk); va_start(ap, dev_fmt); cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); va_end(ap); if (!cl) return -ENOMEM; clkdev_add(cl); return 0; } /** * clk_register_clkdevs - register a set of clk_lookup for a struct clk * @clk: struct clk to associate with all clk_lookups * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized * @num: number of clk_lookup structures to register * * To make things easier for mass registration, we detect error clks * from a previous clk_register() call, and return the error code for * those. This is to permit this function to be called immediately * after clk_register(). */ int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) { unsigned i; if (IS_ERR(clk)) return PTR_ERR(clk); for (i = 0; i < num; i++, cl++) { cl->clk = clk; clkdev_add(cl); } return 0; } EXPORT_SYMBOL(clk_register_clkdevs); include/linux/clk.h +32 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,26 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); */ struct clk *clk_get(struct device *dev, const char *id); /** * devm_clk_get - lookup and obtain a managed reference to a clock producer. * @dev: device for clock "consumer" * @id: clock comsumer ID * * Returns a struct clk corresponding to the clock producer, or * valid IS_ERR() condition containing errno. The implementation * uses @dev and @id to determine the clock consumer, and thereby * the clock producer. (IOW, @id may be identical strings, but * clk_get may return different clock producers depending on @dev.) * * Drivers must assume that the clock source is not enabled. * * devm_clk_get should not be called from within interrupt context. * * The clock will automatically be freed when the device is unbound * from the bus. */ struct clk *devm_clk_get(struct device *dev, const char *id); /** * clk_prepare - prepare a clock source * @clk: clock source Loading Loading @@ -206,6 +226,18 @@ unsigned long clk_get_rate(struct clk *clk); */ void clk_put(struct clk *clk); /** * devm_clk_put - "free" a managed clock source * @dev: device used to acuqire the clock * @clk: clock source acquired with devm_clk_get() * * Note: drivers must ensure that all clk_enable calls made on this * clock source are balanced by clk_disable calls prior to calling * this function. * * clk_put should not be called from within interrupt context. */ void devm_clk_put(struct device *dev, struct clk *clk); /* * The remaining APIs are optional for machine class support. Loading include/linux/clkdev.h +3 −0 Original line number Diff line number Diff line Loading @@ -40,4 +40,7 @@ void clkdev_drop(struct clk_lookup *cl); void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *, ...); int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); #endif Loading
Documentation/driver-model/devres.txt +4 −0 Original line number Diff line number Diff line Loading @@ -276,3 +276,7 @@ REGULATOR devm_regulator_get() devm_regulator_put() devm_regulator_bulk_get() CLOCK devm_clk_get() devm_clk_put()
drivers/clk/clkdev.c +132 −10 Original line number Diff line number Diff line Loading @@ -35,7 +35,12 @@ static DEFINE_MUTEX(clocks_mutex); static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { struct clk_lookup *p, *cl = NULL; int match, best = 0; int match, best_found = 0, best_possible = 0; if (dev_id) best_possible += 2; if (con_id) best_possible += 1; list_for_each_entry(p, &clocks, node) { match = 0; Loading @@ -50,10 +55,10 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) match += 1; } if (match > best) { if (match > best_found) { cl = p; if (match != 3) best = match; if (match != best_possible) best_found = match; else break; } Loading Loading @@ -89,6 +94,51 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); static void devm_clk_release(struct device *dev, void *res) { clk_put(*(struct clk **)res); } struct clk *devm_clk_get(struct device *dev, const char *id) { struct clk **ptr, *clk; ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); clk = clk_get(dev, id); if (!IS_ERR(clk)) { *ptr = clk; devres_add(dev, ptr); } else { devres_free(ptr); } return clk; } EXPORT_SYMBOL(devm_clk_get); static int devm_clk_match(struct device *dev, void *res, void *data) { struct clk **c = res; if (!c || !*c) { WARN_ON(!c || !*c); return 0; } return *c == data; } void devm_clk_put(struct device *dev, struct clk *clk) { int ret; ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); WARN_ON(ret); } EXPORT_SYMBOL(devm_clk_put); void clkdev_add(struct clk_lookup *cl) { mutex_lock(&clocks_mutex); Loading Loading @@ -116,8 +166,9 @@ struct clk_lookup_alloc { char con_id[MAX_CON_ID]; }; struct clk_lookup * __init_refok clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) static struct clk_lookup * __init_refok vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, va_list ap) { struct clk_lookup_alloc *cla; Loading @@ -132,16 +183,25 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) } if (dev_fmt) { va_list ap; va_start(ap, dev_fmt); vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); cla->cl.dev_id = cla->dev_id; va_end(ap); } return &cla->cl; } struct clk_lookup * __init_refok clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup *cl; va_list ap; va_start(ap, dev_fmt); cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); va_end(ap); return cl; } EXPORT_SYMBOL(clkdev_alloc); int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, Loading Loading @@ -173,3 +233,65 @@ void clkdev_drop(struct clk_lookup *cl) kfree(cl); } EXPORT_SYMBOL(clkdev_drop); /** * clk_register_clkdev - register one clock lookup for a struct clk * @clk: struct clk to associate with all clk_lookups * @con_id: connection ID string on device * @dev_id: format string describing device name * * con_id or dev_id may be NULL as a wildcard, just as in the rest of * clkdev. * * To make things easier for mass registration, we detect error clks * from a previous clk_register() call, and return the error code for * those. This is to permit this function to be called immediately * after clk_register(). */ int clk_register_clkdev(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup *cl; va_list ap; if (IS_ERR(clk)) return PTR_ERR(clk); va_start(ap, dev_fmt); cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); va_end(ap); if (!cl) return -ENOMEM; clkdev_add(cl); return 0; } /** * clk_register_clkdevs - register a set of clk_lookup for a struct clk * @clk: struct clk to associate with all clk_lookups * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized * @num: number of clk_lookup structures to register * * To make things easier for mass registration, we detect error clks * from a previous clk_register() call, and return the error code for * those. This is to permit this function to be called immediately * after clk_register(). */ int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) { unsigned i; if (IS_ERR(clk)) return PTR_ERR(clk); for (i = 0; i < num; i++, cl++) { cl->clk = clk; clkdev_add(cl); } return 0; } EXPORT_SYMBOL(clk_register_clkdevs);
include/linux/clk.h +32 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,26 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); */ struct clk *clk_get(struct device *dev, const char *id); /** * devm_clk_get - lookup and obtain a managed reference to a clock producer. * @dev: device for clock "consumer" * @id: clock comsumer ID * * Returns a struct clk corresponding to the clock producer, or * valid IS_ERR() condition containing errno. The implementation * uses @dev and @id to determine the clock consumer, and thereby * the clock producer. (IOW, @id may be identical strings, but * clk_get may return different clock producers depending on @dev.) * * Drivers must assume that the clock source is not enabled. * * devm_clk_get should not be called from within interrupt context. * * The clock will automatically be freed when the device is unbound * from the bus. */ struct clk *devm_clk_get(struct device *dev, const char *id); /** * clk_prepare - prepare a clock source * @clk: clock source Loading Loading @@ -206,6 +226,18 @@ unsigned long clk_get_rate(struct clk *clk); */ void clk_put(struct clk *clk); /** * devm_clk_put - "free" a managed clock source * @dev: device used to acuqire the clock * @clk: clock source acquired with devm_clk_get() * * Note: drivers must ensure that all clk_enable calls made on this * clock source are balanced by clk_disable calls prior to calling * this function. * * clk_put should not be called from within interrupt context. */ void devm_clk_put(struct device *dev, struct clk *clk); /* * The remaining APIs are optional for machine class support. Loading
include/linux/clkdev.h +3 −0 Original line number Diff line number Diff line Loading @@ -40,4 +40,7 @@ void clkdev_drop(struct clk_lookup *cl); void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *, ...); int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); #endif