// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2024 Linaro Ltd.
*/
#include <linux/bug.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/pwrseq/consumer.h>
#include <linux/pwrseq/provider.h>
#include <linux/radix-tree.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
/*
* Power-sequencing framework for linux.
*
* This subsystem allows power sequence providers to register a set of targets
* that consumers may request and power-up/down.
*
* Glossary:
*
* Unit - a unit is a discreet chunk of a power sequence. For instance one unit
* may enable a set of regulators, another may enable a specific GPIO. Units
* can define dependencies in the form of other units that must be enabled
* before it itself can be.
*
* Target - a target is a set of units (composed of the "final" unit and its
* dependencies) that a consumer selects by its name when requesting a handle
* to the power sequencer. Via the dependency system, multiple targets may
* share the same parts of a power sequence but ignore parts that are
* irrelevant.
*
* Descriptor - a handle passed by the pwrseq core to every consumer that
* serves as the entry point to the provider layer. It ensures coherence
* between different users and keeps reference counting consistent.
*
* Each provider must define a .match() callback whose role is to determine
* whether a potential consumer is in fact associated with this sequencer.
* This allows creating abstraction layers on top of regular device-tree
* resources like regulators, clocks and other nodes connected to the consumer
* via phandle.
*/
static DEFINE_IDA(pwrseq_ida);
/*
* Protects the device list on the pwrseq bus from concurrent modifications
* but allows simultaneous read-only access.
*/
static DECLARE_RWSEM(pwrseq_sem);
/**
* struct pwrseq_unit - Private power-sequence unit data.
* @ref: Reference count for this object. When it goes to 0, the object is
* destroyed.
* @name: Name of this target.
* @list: Link to siblings on the list of all units of a single sequencer.
* @deps: List of units on which this unit depends.
* @enable: Callback running the part of the power-on sequence provided by
* this unit.
* @disable: Callback running the part of the power-off sequence provided
* by this unit.
* @enable_count: Current number of users that enabled this unit. May be the
* consumer of the power sequencer or other units that depend
* on this one.
*/
struct pwrseq_unit {
struct kref ref;
const char *name;
struct list_head list;
struct list_head deps;
pwrseq_power_state_func enable;
pwrseq_power_state_func disable;
unsigned int enable_count;
};
static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data)
{
struct pwrseq_unit *unit;
unit = kzalloc(sizeof(*unit), GFP_KERNEL);
if (!unit)
return NULL;
unit->name = kstrdup_const(data->name, GFP_KERNEL);
if (!unit->name) {
kfree(unit);
return NULL;
}
kref_init(&unit->ref);
INIT_LIST_HEAD(&unit->deps);
unit->enable = data->enable;
unit->disable = data->disable;
return unit;
}
static struct pwrseq_unit *pwrseq_unit_get(struct pwrseq_unit *unit)
{
kref_get(&unit->ref);
return unit;
}
static void pwrseq_unit_release(struct kref *ref);
static void pwrseq_unit_put(struct pwrseq_unit *unit)
{
kref_put(&unit->ref, pwrseq_unit_release);
}
/**
* struct pwrseq_unit_dep - Wrapper around a reference to the unit structure
* allowing to keep it on multiple dependency lists
* in different units.
* @list: Siblings on the list.
* @unit: Address of the referenced unit.
*/
struct pwrseq_unit_dep {
struct list_head list;
struct pwrseq_unit *unit;
};
static struct pwrseq_unit_dep *pwrseq_unit_dep_new(struct pwrseq_unit *unit)
{
struct pwrseq_unit_dep *dep;
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep)
return NULL;
dep->unit = unit;
return dep;
}
static void pwrseq_unit_dep_free(struct pwrseq_unit_dep *ref)
{
pwrseq_unit_put(ref->unit);
kfree(ref);
}
static void pwrseq_unit_free_deps(struct list_head *list)
{
struct pwrseq_unit_dep *dep, *next;
list_for_each_entry_safe(dep, next, list, list) {
list_del(&dep->list);
pwrseq_unit_dep_free(dep);
}
}
static void pwrseq_unit_release(struct kref *ref)
{
struct pwrseq_unit *unit = container_of(ref, struct pwrseq_unit, ref);
pwrseq_unit_free_deps(&unit->deps);
list_del(&unit->list);
kfree_const(unit->name);
kfree(unit);
}
/**
* struct pwrseq_target - Private power-sequence target data.
* @list: Siblings on the list of all targets exposed by a power sequencer.
* @name: Name of the target.
* @unit: Final unit for this target.
* @post_enable: Callback run after the target unit has been enabled, *after*
* the state lock has been released. It's useful for implementing
* boot-up delays without blocking other users from powering up
* using the same power sequencer.
*/
struct pwrseq_target {
struct list_head list;
const char *name;
struct pwrseq_unit *unit;
pwrseq_power_state_func post_enable;
};
static struct pwrseq_target *
pwrseq_target_new(const struct pwrseq_target_data *data)
{
struct pwrseq_target *target;
target = kzalloc(sizeof(*target), GFP_KERNEL);
if (!target)
return NULL;
target->name = kstrdup_const(data->name, GFP_KERNEL);
if (!target->name)