// SPDX-License-Identifier: GPL-2.0-or-later /* * Generic Framer framework. * * Copyright 2023 CS GROUP France * * Author: Herve Codina <[email protected]> */ #include <linux/device.h> #include <linux/framer/framer.h> #include <linux/framer/framer-provider.h> #include <linux/idr.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> static void framer_release(struct device *dev); static const struct class framer_class = …; static DEFINE_MUTEX(framer_provider_mutex); static LIST_HEAD(framer_provider_list); static DEFINE_IDA(framer_ida); #define dev_to_framer(a) … int framer_pm_runtime_get(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); int framer_pm_runtime_get_sync(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); int framer_pm_runtime_put(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); int framer_pm_runtime_put_sync(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_init - framer internal initialization before framer operation * @framer: the framer returned by framer_get() * * Used to allow framer's driver to perform framer internal initialization, * such as PLL block powering, clock initialization or anything that's * is required by the framer to perform the start of operation. * Must be called before framer_power_on(). * * Return: %0 if successful, a negative error code otherwise */ int framer_init(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_exit - Framer internal un-initialization * @framer: the framer returned by framer_get() * * Must be called after framer_power_off(). */ int framer_exit(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_power_on - Enable the framer and enter proper operation * @framer: the framer returned by framer_get() * * Must be called after framer_init(). * * Return: %0 if successful, a negative error code otherwise */ int framer_power_on(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_power_off - Disable the framer. * @framer: the framer returned by framer_get() * * Must be called before framer_exit(). * * Return: %0 if successful, a negative error code otherwise */ int framer_power_off(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_get_status() - Gets the framer status * @framer: the framer returned by framer_get() * @status: the status to retrieve * * Used to get the framer status. framer_init() must have been called * on the framer. * * Return: %0 if successful, a negative error code otherwise */ int framer_get_status(struct framer *framer, struct framer_status *status) { … } EXPORT_SYMBOL_GPL(…); /** * framer_set_config() - Sets the framer configuration * @framer: the framer returned by framer_get() * @config: the configuration to set * * Used to set the framer configuration. framer_init() must have been called * on the framer. * * Return: %0 if successful, a negative error code otherwise */ int framer_set_config(struct framer *framer, const struct framer_config *config) { … } EXPORT_SYMBOL_GPL(…); /** * framer_get_config() - Gets the framer configuration * @framer: the framer returned by framer_get() * @config: the configuration to retrieve * * Used to get the framer configuration. framer_init() must have been called * on the framer. * * Return: %0 if successful, a negative error code otherwise */ int framer_get_config(struct framer *framer, struct framer_config *config) { … } EXPORT_SYMBOL_GPL(…); static void framer_polling_work(struct work_struct *work) { … } /** * framer_notifier_register() - Registers a notifier * @framer: the framer returned by framer_get() * @nb: the notifier block to register * * Used to register a notifier block on framer events. framer_init() must have * been called on the framer. * The available framer events are present in enum framer_events. * * Return: %0 if successful, a negative error code otherwise */ int framer_notifier_register(struct framer *framer, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); /** * framer_notifier_unregister() - Unregisters a notifier * @framer: the framer returned by framer_get() * @nb: the notifier block to unregister * * Used to unregister a notifier block. framer_init() must have * been called on the framer. * * Return: %0 if successful, a negative error code otherwise */ int framer_notifier_unregister(struct framer *framer, struct notifier_block *nb) { … } EXPORT_SYMBOL_GPL(…); static struct framer_provider *framer_provider_of_lookup(const struct device_node *node) { … } static struct framer *framer_of_get_from_provider(const struct of_phandle_args *args) { … } static struct framer *framer_of_get_byphandle(struct device_node *np, const char *propname, int index) { … } static struct framer *framer_of_get_byparent(struct device_node *np, int index) { … } /** * framer_get() - lookup and obtain a reference to a framer. * @dev: device that requests the framer * @con_id: name of the framer from device's point of view * * Returns the framer driver, after getting a refcount to it; or * -ENODEV if there is no such framer. The caller is responsible for * calling framer_put() to release that count. */ struct framer *framer_get(struct device *dev, const char *con_id) { … } EXPORT_SYMBOL_GPL(…); /** * framer_put() - release the framer * @dev: device that wants to release this framer * @framer: the framer returned by framer_get() * * Releases a refcount the caller received from framer_get(). */ void framer_put(struct device *dev, struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); static void devm_framer_put(struct device *dev, void *res) { … } /** * devm_framer_get() - lookup and obtain a reference to a framer. * @dev: device that requests this framer * @con_id: name of the framer from device's point of view * * Gets the framer using framer_get(), and associates a device with it using * devres. On driver detach, framer_put() function is invoked on the devres * data, then, devres data is freed. */ struct framer *devm_framer_get(struct device *dev, const char *con_id) { … } EXPORT_SYMBOL_GPL(…); /** * devm_framer_optional_get() - lookup and obtain a reference to an optional * framer. * @dev: device that requests this framer * @con_id: name of the framer from device's point of view * * Same as devm_framer_get() except that if the framer does not exist, it is not * considered an error and -ENODEV will not be returned. Instead the NULL framer * is returned. */ struct framer *devm_framer_optional_get(struct device *dev, const char *con_id) { … } EXPORT_SYMBOL_GPL(…); static void framer_notify_status_work(struct work_struct *work) { … } void framer_notify_status_change(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); /** * framer_create() - create a new framer * @dev: device that is creating the new framer * @node: device node of the framer. default to dev->of_node. * @ops: function pointers for performing framer operations * * Called to create a framer using framer framework. */ struct framer *framer_create(struct device *dev, struct device_node *node, const struct framer_ops *ops) { … } EXPORT_SYMBOL_GPL(…); /** * framer_destroy() - destroy the framer * @framer: the framer to be destroyed * * Called to destroy the framer. */ void framer_destroy(struct framer *framer) { … } EXPORT_SYMBOL_GPL(…); static void devm_framer_destroy(struct device *dev, void *res) { … } /** * devm_framer_create() - create a new framer * @dev: device that is creating the new framer * @node: device node of the framer * @ops: function pointers for performing framer operations * * Creates a new framer device adding it to the framer class. * While at that, it also associates the device with the framer using devres. * On driver detach, release function is invoked on the devres data, * then, devres data is freed. */ struct framer *devm_framer_create(struct device *dev, struct device_node *node, const struct framer_ops *ops) { … } EXPORT_SYMBOL_GPL(…); /** * framer_provider_simple_of_xlate() - returns the framer instance from framer provider * @dev: the framer provider device * @args: of_phandle_args (not used here) * * Intended to be used by framer provider for the common case where #framer-cells is * 0. For other cases where #framer-cells is greater than '0', the framer provider * should provide a custom of_xlate function that reads the *args* and returns * the appropriate framer. */ struct framer *framer_provider_simple_of_xlate(struct device *dev, const struct of_phandle_args *args) { … } EXPORT_SYMBOL_GPL(…); /** * __framer_provider_of_register() - create/register framer provider with the framework * @dev: struct device of the framer provider * @owner: the module owner containing of_xlate * @of_xlate: function pointer to obtain framer instance from framer provider * * Creates struct framer_provider from dev and of_xlate function pointer. * This is used in the case of dt boot for finding the framer instance from * framer provider. */ struct framer_provider * __framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, const struct of_phandle_args *args)) { … } EXPORT_SYMBOL_GPL(…); /** * framer_provider_of_unregister() - unregister framer provider from the framework * @framer_provider: framer provider returned by framer_provider_of_register() * * Removes the framer_provider created using framer_provider_of_register(). */ void framer_provider_of_unregister(struct framer_provider *framer_provider) { … } EXPORT_SYMBOL_GPL(…); static void devm_framer_provider_of_unregister(struct device *dev, void *res) { … } /** * __devm_framer_provider_of_register() - create/register framer provider with * the framework * @dev: struct device of the framer provider * @owner: the module owner containing of_xlate * @of_xlate: function pointer to obtain framer instance from framer provider * * Creates struct framer_provider from dev and of_xlate function pointer. * This is used in the case of dt boot for finding the framer instance from * framer provider. While at that, it also associates the device with the * framer provider using devres. On driver detach, release function is invoked * on the devres data, then, devres data is freed. */ struct framer_provider * __devm_framer_provider_of_register(struct device *dev, struct module *owner, struct framer *(*of_xlate)(struct device *dev, const struct of_phandle_args *args)) { … } EXPORT_SYMBOL_GPL(…); /** * framer_release() - release the framer * @dev: the dev member within framer * * When the last reference to the device is removed, it is called * from the embedded kobject as release method. */ static void framer_release(struct device *dev) { … } static int __init framer_core_init(void) { … } device_initcall(framer_core_init);