blob: dffb85ba759cef527353430c6f2caf246f4ca0dd [file] [log] [blame] [edit]
/**
* Copyright 2021 Google LLC.
*/
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include "ssr-core.h"
static struct class *ssr_class;
static DEFINE_IDA(ssr_instance_idr);
static ssize_t relay_open_store(struct device *dev, struct device_attribute *attr,
const char* buf, size_t count) {
struct ssr_data *data = dev_get_drvdata(dev);
return data->ops->relay_open_store(dev->parent, buf, count);
}
#define DEFINE_SSR_DEVICE_SHOW_FUNCTION(_name) \
ssize_t _name##_show(struct device *dev, struct device_attribute *attr, char* buf) { \
struct ssr_data *data = dev_get_drvdata(dev); \
return data->ops->_name##_show(dev->parent, buf); \
}
static DEFINE_SSR_DEVICE_SHOW_FUNCTION(relay_state);
static DEFINE_SSR_DEVICE_SHOW_FUNCTION(hv_vdd);
static DEFINE_SSR_DEVICE_SHOW_FUNCTION(acin1_vdd);
static DEFINE_SSR_DEVICE_SHOW_FUNCTION(acin2_vdd);
static DEVICE_ATTR_WO(relay_open);
static DEVICE_ATTR_RO(relay_state);
static DEVICE_ATTR_RO(hv_vdd);
static DEVICE_ATTR_RO(acin1_vdd);
static DEVICE_ATTR_RO(acin2_vdd);
static struct attribute *ssr_attrs[] = {
&dev_attr_relay_open.attr,
&dev_attr_relay_state.attr,
&dev_attr_hv_vdd.attr,
&dev_attr_acin1_vdd.attr,
&dev_attr_acin2_vdd.attr,
NULL,
};
ATTRIBUTE_GROUPS(ssr);
struct device *ssr_device_register(struct device *dev, const struct ssr_ops *ops) {
struct ssr_data *data;
struct device *new_dev;
int ret;
data = kmalloc(sizeof(struct ssr_data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err;
}
data->id = ida_alloc(&ssr_instance_idr, GFP_KERNEL);
if (data->id < 0) {
ret = data->id;
goto err_free_data;
}
data->ops = ops;
new_dev = device_create_with_groups(ssr_class, dev, 0, data,
ssr_groups, "ssr%d", data->id);
if (IS_ERR(new_dev)) {
ret = PTR_ERR(new_dev);
goto err_free_id;
}
return new_dev;
err_free_id:
ida_free(&ssr_instance_idr, data->id);
err_free_data:
kfree(data);
err:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(ssr_device_register);
void ssr_device_unregister(struct device *ssr_dev) {
struct ssr_data *data = dev_get_drvdata(ssr_dev);
ida_free(&ssr_instance_idr, data->id);
device_unregister(ssr_dev);
kfree(data);
}
EXPORT_SYMBOL_GPL(ssr_device_unregister);
int __init ssr_core_init(void) {
ssr_class = class_create(THIS_MODULE, "ssr");
if (IS_ERR(ssr_class)) {
pr_err("Failed to create ssr class %ld\n", PTR_ERR(ssr_class));
return PTR_ERR(ssr_class);
}
return 0;
}
void __exit ssr_core_exit(void) {
class_destroy(ssr_class);
ssr_class = NULL;
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SSR core module");
module_init(ssr_core_init);
module_exit(ssr_core_exit);