android_kernel_samsung_sm8650/drivers/samsung/bsp/param/sec_param.c
2024-10-20 20:09:27 +02:00

186 lines
4.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* COPYRIGHT(C) 2011-2023 Samsung Electronics Co., Ltd. All Right Reserved.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ":%s() " fmt, __func__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/samsung/builder_pattern.h>
#include <linux/samsung/bsp/sec_param.h>
struct sec_param_drvdata {
struct builder bd;
struct sec_param_operations *ops;
};
static struct sec_param_drvdata *sec_param;
static __always_inline bool __param_is_probed(void)
{
return !!sec_param;
}
static bool __param_get(size_t index, void *value)
{
struct sec_param_operations *ops = sec_param->ops;
if (!ops || !ops->read)
return false;
return ops->read(index, value);
}
bool sec_param_get(size_t index, void *value)
{
if (!__param_is_probed())
return false;
return __param_get(index, value);
}
EXPORT_SYMBOL_GPL(sec_param_get);
static bool __param_set(size_t index, const void *value)
{
struct sec_param_operations *ops = sec_param->ops;
if (!ops || !ops->write)
return false;
return ops->write(index, value);
}
bool sec_param_set(size_t index, const void *value)
{
if (!__param_is_probed())
return false;
return __param_set(index, value);
}
EXPORT_SYMBOL_GPL(sec_param_set);
int sec_param_register_operations(struct sec_param_operations *ops)
{
if (!__param_is_probed())
return -EBUSY;
if (sec_param->ops) {
dev_warn(sec_param->bd.dev, "ops is already set (%p)\n",
sec_param->ops);
return -EPERM;
}
sec_param->ops = ops;
return 0;
}
EXPORT_SYMBOL_GPL(sec_param_register_operations);
void sec_param_unregister_operations(struct sec_param_operations *ops)
{
if (ops != sec_param->ops) {
dev_warn(sec_param->bd.dev,
"%p is not a registered ops.\n", ops);
return;
}
sec_param->ops = NULL;
}
EXPORT_SYMBOL_GPL(sec_param_unregister_operations);
static noinline int __param_probe_epilog(struct builder *bd)
{
struct sec_param_drvdata *drvdata =
container_of(bd, struct sec_param_drvdata, bd);
struct device *dev = bd->dev;
dev_set_drvdata(dev, drvdata);
sec_param = drvdata;
return 0;
}
static noinline void __param_remove_prolog(struct builder *bd)
{
/* FIXME: This is not a graceful exit. */
sec_param = NULL;
}
static const struct dev_builder __param_dev_builder[] = {
DEVICE_BUILDER(__param_probe_epilog, __param_remove_prolog),
};
static int __param_probe(struct platform_device *pdev,
const struct dev_builder *builder, ssize_t n)
{
struct device *dev = &pdev->dev;
struct sec_param_drvdata *drvdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->bd.dev = dev;
return sec_director_probe_dev(&drvdata->bd, builder, n);
}
static int __param_remove(struct platform_device *pdev,
const struct dev_builder *builder, ssize_t n)
{
struct sec_param_drvdata *drvdata = platform_get_drvdata(pdev);
sec_director_destruct_dev(&drvdata->bd, builder, n, n);
return 0;
}
static int sec_param_probe(struct platform_device *pdev)
{
return __param_probe(pdev, __param_dev_builder,
ARRAY_SIZE(__param_dev_builder));
}
static int sec_param_remove(struct platform_device *pdev)
{
return __param_remove(pdev, __param_dev_builder,
ARRAY_SIZE(__param_dev_builder));
}
static const struct of_device_id sec_param_match_table[] = {
{ .compatible = "samsung,param" },
{},
};
MODULE_DEVICE_TABLE(of, sec_param_match_table);
static struct platform_driver sec_param_driver = {
.driver = {
.name = "sec,param",
.of_match_table = of_match_ptr(sec_param_match_table),
},
.probe = sec_param_probe,
.remove = sec_param_remove,
};
static int __init sec_param_init(void)
{
return platform_driver_register(&sec_param_driver);
}
module_init(sec_param_init);
static void __exit sec_param_exit(void)
{
platform_driver_unregister(&sec_param_driver);
}
module_exit(sec_param_exit);
MODULE_AUTHOR("Samsung Electronics");
MODULE_DESCRIPTION("SEC PARAM driver");
MODULE_LICENSE("GPL v2");