update:add luckfox-pico Ultra support

This commit is contained in:
luckfox-eng29
2024-03-16 17:03:10 +08:00
committed by luckfox-eng33
parent 1e160dee55
commit d3153ac97e
234 changed files with 89019 additions and 2435 deletions

View File

@@ -425,6 +425,11 @@ config TOUCHSCREEN_GSLX680_PAD
config TOUCHSCREEN_GT1X
tristate "GT1X touchscreens support"
config TOUCHSCREEN_GT9XX
tristate "GT9XX touchscreens support"
config TOUCHSCREEN_HIDEEP
tristate "HiDeep Touch IC"
depends on I2C

View File

@@ -52,6 +52,7 @@ gsl3673-ts-y := gsl3673.o gsl_point_id.o
obj-$(CONFIG_TOUCHSCREEN_GSLX680_PAD) += gslx680-pad.o
gslx680-pad-y := gslx680_pad.o gsl_point_id.o
obj-$(CONFIG_TOUCHSCREEN_GT1X) += gt1x/
obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o

View File

@@ -12,7 +12,7 @@
* Development of this driver has been sponsored by Glyn:
* http://www.glyn.com/Products/Displays
*/
#define DEBUG
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -832,8 +832,10 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
error = edt_ft5x06_ts_readwrite(client, 1, "\xBB",
EDT_NAME_LEN - 1, rdbuf);
if (error)
return error;
{
dev_dbg(&client->dev, "edt_ft5x06_ts_read_write xBB failed\n");
//return error;
}
/* Probe content for something consistent.
* M06 starts with a response byte, M12 gives the data directly.
* M09/Generic does not provide model number information.
@@ -881,15 +883,19 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
2, rdbuf);
if (error)
{
dev_dbg(&client->dev, "edt_ft5x06_ts_read_write XA6 failed\n");
return error;
}
strlcpy(fw_version, rdbuf, 2);
error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
1, rdbuf);
if (error)
{
dev_dbg(&client->dev, "edt_ft5x06_ts_read_write xA8 failed\n");
return error;
}
/* This "model identification" is not exact. Unfortunately
* not all firmwares for the ft5x06 put useful values in
* the identification registers.
@@ -917,7 +923,10 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
error = edt_ft5x06_ts_readwrite(client, 1, "\x53",
1, rdbuf);
if (error)
{
dev_dbg(&client->dev, "edt_ft5x06_ts_read_write x53 failed\n");
return error;
}
strlcpy(fw_version, rdbuf, 1);
snprintf(model_name, EDT_NAME_LEN,
"EVERVISION-FT5726NEi");
@@ -1155,7 +1164,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
}
if (tsdata->reset_gpio) {
usleep_range(5000, 6000);
//usleep_range(5000, 6000);
usleep_range(6000, 7000);
gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
msleep(300);
}
@@ -1174,7 +1184,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
return error;
dev_err(&client->dev, "error = %d\n",error);
// return error;
}
/*

View File

@@ -10,6 +10,7 @@
* 2010 - 2012 Goodix Technology.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/dmi.h>
@@ -962,6 +963,8 @@ static int goodix_read_version(struct goodix_ts_data *ts)
{
int error;
u8 buf[6];
//u8 reg_data[6];
//int i = 0;
char id_str[GOODIX_ID_MAX_LEN + 1];
error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
@@ -978,7 +981,6 @@ static int goodix_read_version(struct goodix_ts_data *ts)
dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id,
ts->version);
return 0;
}
@@ -1058,11 +1060,15 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
dev_dbg(&ts->client->dev, "(%d, %d, %d)", ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
/* Read configuration and apply touchscreen parameters */
goodix_read_config(ts);
dev_dbg(&ts->client->dev, "(%d, %d, %d)", ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
/* Try overriding touchscreen parameters via device properties */
touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
dev_dbg(&ts->client->dev, "(%d, %d, %d)", ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
dev_err(&ts->client->dev,
@@ -1127,9 +1133,17 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx)
{
struct goodix_ts_data *ts = ctx;
int error;
int i;
if (cfg) {
/* send device configuration to the firmware */
while(i < cfg->size)
{
dev_dbg(&ts->client->dev, "reg %d: %#x\n", i, cfg->data[i]);
i ++;
}
error = goodix_send_cfg(ts, cfg->data, cfg->size);
if (error)
goto err_release_cfg;
@@ -1229,8 +1243,11 @@ reset:
ts->chip = goodix_get_chip_data(ts->id);
ts->load_cfg_from_disk = 0;
if (ts->load_cfg_from_disk) {
/* update device config */
dev_dbg(&client->dev, "Configure from Disk\n");
ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
"goodix_%s_cfg.bin", ts->id);
if (!ts->cfg_name)
@@ -1248,6 +1265,7 @@ reset:
return 0;
} else {
dev_dbg(&client->dev, "Configure from Device\n");
error = goodix_configure_dev(ts);
if (error)
return error;

View File

@@ -3,4 +3,4 @@ obj-y += goodix_gt9xx.o
#goodix_gt9xx-y +=goodix_tool.o
goodix_gt9xx-y +=gt9xx.o
goodix_gt9xx-y +=gt9xx_update.o
#goodix_gt9xx-y +=gt9xx_update.o

View File

@@ -218,6 +218,7 @@ extern u16 total_len;
}
*/
/*
//WGJ10187_GT9271_Config_20140623_104014_0X41.cfg
#define CTP_CFG_GROUP1 {\
0x41,0x80,0x07,0xB0,0x04,0x0A,0x05,0x00,0x01,0x08,0x28,0x0F,0x50,0x32,0x03, \
@@ -234,6 +235,32 @@ extern u16 total_len;
0x23,0x24,0x25,0x26,0x27,0x28,0x29,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0xB5,0x01 \
}
*/
//FT040017_GT911_Config_20221026.cfg
#define CTP_CFG_GROUP1 { \
0x4F,0xE0,0x01,0xE0,0x01,0x05,0x35,0x00,0x01,0xC8, \
0x28,0x0F,0x50,0x3C,0x03,0x05,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x18,0x1A,0x1E,0x14,0x85,0x25,0x0A, \
0xEA,0xEC,0xB5,0x06,0x00,0x00,0x00,0x20,0x21,0x10, \
0x00,0x01,0x00,0x0F,0x00,0x2A,0x00,0x00,0x01,0x50, \
0x32,0xDC,0xFA,0x94,0xD0,0x02,0x08,0x00,0x00,0x04, \
0x80,0xDE,0x00,0x80,0xE4,0x00,0x80,0xEA,0x00,0x7F, \
0xF0,0x00,0x7F,0xF6,0x00,0x7F,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
0x00,0x00,0x14,0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06, \
0x04,0x02,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0x21,0x20,0x1F,0x1E,0x1D,0x00,0x02,0x04, \
0x06,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xAA,0x01 \
}
// TODO: define your config for Sensor_ID == 1 here, if needed
#define CTP_CFG_GROUP2 {\
@@ -391,7 +418,7 @@ extern u16 total_len;
}while (0)
//*****************************End of Part III********************************
#define TRUE 1
#define FALSE 0
//#define TRUE 1
//#define FALSE 0
#endif /* _GOODIX_GT9XX_H_ */

View File

@@ -2,6 +2,7 @@
#
# Makefile for the kernel mmc device drivers.
#
#subdir-ccflags-y := -DDEBUG
obj-$(CONFIG_MMC) += core/
obj-$(subst m,y,$(CONFIG_MMC)) += host/

View File

@@ -121,4 +121,11 @@ config OF_DMA_DEFAULT_COHERENT
# arches should select this if DMA is coherent by default for OF devices
bool
config OF_DTBO
bool "Device Tree DTBO"
select OF_DYNAMIC
select OF_FLATTREE
select OF_RESOLVE
help
Device Tree DTBO
endif # OF

View File

@@ -13,5 +13,6 @@ obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
obj-$(CONFIG_OF_NUMA) += of_numa.o
obj-$(CONFIG_OF_DTBO) += dtbocfg.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/

View File

@@ -0,0 +1,429 @@
/*********************************************************************************
*
* Copyright (C) 2016-2023 Ichiro Kawazome
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
********************************************************************************/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/configfs.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/limits.h>
#include <linux/file.h>
#include <linux/version.h>
#define DRIVER_NAME "dtbocfg"
#define DRIVER_VERSION "0.1.0"
/**
* Device Tree Overlay Item Structure
*/
struct dtbocfg_overlay_item {
struct config_item item;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0))
struct device_node* node;
#endif
int id;
void* dtbo;
int dtbo_size;
};
/**
* dtbocfg_overlay_create() - Create Device Tree Overlay
* @overlay: Pointer to Device Tree Overlay Item
* return Success(0) or Error Status.
*/
static int dtbocfg_overlay_item_create(struct dtbocfg_overlay_item *overlay)
{
int ret_val;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0))
{
int ovcs_id = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0))
ret_val = of_overlay_fdt_apply(overlay->dtbo,overlay->dtbo_size, &ovcs_id, NULL);
#else
ret_val = of_overlay_fdt_apply(overlay->dtbo,overlay->dtbo_size, &ovcs_id);
#endif
if (ret_val != 0) {
pr_err("%s: Failed to apply overlay (ret_val=%d)\n", __func__, ret_val);
goto failed;
}
overlay->id = ovcs_id;
pr_debug("%s: apply OK(id=%d)\n", __func__, ovcs_id);
}
#else
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
of_fdt_unflatten_tree(overlay->dtbo, NULL, &overlay->node);
#else
of_fdt_unflatten_tree(overlay->dtbo, &overlay->node);
#endif
if (overlay->node == NULL) {
pr_err("%s: failed to unflatten tree\n", __func__);
ret_val = -EINVAL;
goto failed;
}
pr_debug("%s: unflattened OK\n", __func__);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
{
int ovcs_id = 0;
ret_val = of_overlay_apply(overlay->node, &ovcs_id);
if (ret_val != 0) {
pr_err("%s: Failed to apply overlay (ret_val=%d)\n", __func__, ret_val);
goto failed;
}
overlay->id = ovcs_id;
pr_debug("%s: apply OK(id=%d)\n", __func__, ovcs_id);
}
#else
{
of_node_set_flag(overlay->node, OF_DETACHED);
ret_val = of_resolve_phandles(overlay->node);
if (ret_val != 0) {
pr_err("%s: Failed to resolve tree\n", __func__);
goto failed;
}
pr_debug("%s: resolved OK\n", __func__);
ret_val = of_overlay_create(overlay->node);
if (ret_val < 0) {
pr_err("%s: Failed to create overlay (ret_val=%d)\n", __func__, ret_val);
goto failed;
}
overlay->id = ret_val;
}
#endif
#endif
pr_debug("%s: create OK\n", __func__);
return 0;
failed:
return ret_val;
}
/**
* dtbocfg_overlay_item_release() - Relase Device Tree Overlay
* @overlay: Pointer to Device Tree Overlay Item
* return none
*/
static void dtbocfg_overlay_item_release(struct dtbocfg_overlay_item *overlay)
{
if (overlay->id >= 0) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
of_overlay_remove(&overlay->id);
#else
of_overlay_destroy(overlay->id);
#endif
overlay->id = -1;
}
}
/**
* container_of_dtbocfg_overlay_item() - Get Device Tree Overlay Item Pointer from Configuration Item
* @item: Pointer to Configuration Item
* return Pointer to Device Tree Overlay Item
*/
static inline struct dtbocfg_overlay_item* container_of_dtbocfg_overlay_item(struct config_item *item)
{
return item ? container_of(item, struct dtbocfg_overlay_item, item) : NULL;
}
/**
* dtbocfg_overlay_item_status_store() - Set Status Attibute
* @item: Pointer to Configuration Item
* @page: Pointer to Value Buffer
* @count: Size of Value Buffer Size
* return Stored Size or Error Status.
*/
static ssize_t dtbocfg_overlay_item_status_store(struct config_item *item, const char *buf, size_t count)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
ssize_t status;
unsigned long value;
if (0 != (status = kstrtoul(buf, 10, &value))) {
goto failed;
}
if (value == 0) {
if (overlay->id >= 0) {
dtbocfg_overlay_item_release(overlay);
}
} else {
if (overlay->id < 0) {
dtbocfg_overlay_item_create(overlay);
}
}
return count;
failed:
return -EPERM;
}
/**
* dtbocfg_overlay_item_status_show() - Show Status Attibute
* @item : Pointer to Configuration Item
* @page : Pointer to Value for Store
* return String Size or Error Status.
*/
static ssize_t dtbocfg_overlay_item_status_show(struct config_item *item, char *page)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
return sprintf(page, "%d\n", overlay->id >= 0 ? 1 : 0);
}
/**
* dtbocfg_overlay_item_dtbo_write() - Write Device Tree Blob to Configuration Item
* @item : Pointer to Configuration Item
* @page : Pointer to Value Buffer
* @count: Size of Value Buffer
* return Stored Size or Error Status.
*/
static ssize_t dtbocfg_overlay_item_dtbo_write(struct config_item *item, const void *buf, size_t count)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
if (overlay->dtbo_size > 0) {
if (overlay->id >= 0) {
return -EPERM;
}
kfree(overlay->dtbo);
overlay->dtbo = NULL;
overlay->dtbo_size = 0;
}
overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
if (overlay->dtbo == NULL) {
overlay->dtbo_size = 0;
return -ENOMEM;
} else {
overlay->dtbo_size = count;
return count;
}
}
/**
* dtbocfg_overlay_item_dtbo_read() - Read Device Tree Blob from Configuration Item
* @item : Pointer to Configuration Item
* @page : Pointer to Value for Store, or NULL to query the buffer size
* @size : Size of the supplied buffer
* return Read Size
*/
static ssize_t dtbocfg_overlay_item_dtbo_read(struct config_item *item, void *buf, size_t size)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
if (overlay->dtbo == NULL)
return 0;
if (buf != NULL)
memcpy(buf, overlay->dtbo, overlay->dtbo_size);
return overlay->dtbo_size;
}
/**
* Device Tree Blob Overlay Attribute Structure
*/
CONFIGFS_BIN_ATTR(dtbocfg_overlay_item_, dtbo, NULL, 1024 * 1024); // 1MiB should be way more than enough
CONFIGFS_ATTR(dtbocfg_overlay_item_, status);
static struct configfs_attribute *dtbocfg_overlay_attrs[] = {
&dtbocfg_overlay_item_attr_status,
NULL,
};
static struct configfs_bin_attribute *dtbocfg_overlay_bin_attrs[] = {
&dtbocfg_overlay_item_attr_dtbo,
NULL,
};
/**
* dtbocfg_overlay_release() - Release Device Tree Overlay Item
* @item : Pointer to Configuration Item
* Return None
*/
static void dtbocfg_overlay_release(struct config_item *item)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
pr_debug("%s\n", __func__);
dtbocfg_overlay_item_release(overlay);
if (overlay->dtbo) {
kfree(overlay->dtbo);
overlay->dtbo = NULL;
overlay->dtbo_size = 0;
}
kfree(overlay);
}
/**
* Device Tree Blob Overlay Item Structure
*/
static struct configfs_item_operations dtbocfg_overlay_item_ops = {
.release = dtbocfg_overlay_release,
};
static struct config_item_type dtbocfg_overlay_item_type = {
.ct_item_ops = &dtbocfg_overlay_item_ops,
.ct_attrs = dtbocfg_overlay_attrs,
.ct_bin_attrs = dtbocfg_overlay_bin_attrs,
.ct_owner = THIS_MODULE,
};
/**
* dtbocfg_overlay_group_make_item() - Make Device Tree Overlay Group Item
* @group: Pointer to Configuration Group
* @name : Pointer to Group Name
* Return Pointer to Device Tree Overlay Group Item
*/
static struct config_item *dtbocfg_overlay_group_make_item(struct config_group *group, const char *name)
{
struct dtbocfg_overlay_item *overlay;
pr_debug("%s\n", __func__);
overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
if (!overlay)
return ERR_PTR(-ENOMEM);
overlay->id = -1;
overlay->dtbo = NULL;
overlay->dtbo_size = 0;
config_item_init_type_name(&overlay->item, name, &dtbocfg_overlay_item_type);
return &overlay->item;
}
/**
* dtbocfg_overlay_group_drop_item() - Drop Device Tree Overlay Group Item
* @group: Pointer to Configuration Group
* @item : Pointer to Device Tree Overlay Group Item
*/
static void dtbocfg_overlay_group_drop_item(struct config_group *group, struct config_item *item)
{
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
pr_debug("%s\n", __func__);
config_item_put(&overlay->item);
}
/**
* Device Tree Blob Overlay Sub Group Structures
*/
static struct configfs_group_operations dtbocfg_overlays_ops = {
.make_item = dtbocfg_overlay_group_make_item,
.drop_item = dtbocfg_overlay_group_drop_item,
};
static struct config_item_type dtbocfg_overlays_type = {
.ct_group_ops = &dtbocfg_overlays_ops,
.ct_owner = THIS_MODULE,
};
static struct config_group dtbocfg_overlay_group;
/**
* Device Tree Blob Overlay Root Sub System Structures
*/
static struct configfs_group_operations dtbocfg_root_ops = {
/* empty - we don't allow anything to be created */
};
static struct config_item_type dtbocfg_root_type = {
.ct_group_ops = &dtbocfg_root_ops,
.ct_owner = THIS_MODULE,
};
static struct configfs_subsystem dtbocfg_root_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "device-tree",
.ci_type = &dtbocfg_root_type,
},
},
.su_mutex = __MUTEX_INITIALIZER(dtbocfg_root_subsys.su_mutex),
};
/**
* dtbocfg_module_init()
*/
static int __init dtbocfg_module_init(void)
{
int retval = 0;
pr_info(DRIVER_NAME ": " DRIVER_VERSION "\n");
config_group_init(&dtbocfg_root_subsys.su_group);
config_group_init_type_name(&dtbocfg_overlay_group, "overlays", &dtbocfg_overlays_type);
retval = configfs_register_subsystem(&dtbocfg_root_subsys);
if (retval != 0) {
pr_err( "%s: couldn't register subsys\n", __func__);
goto register_subsystem_failed;
}
retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group);
if (retval != 0) {
pr_err( "%s: couldn't register group\n", __func__);
goto register_group_failed;
}
pr_info(DRIVER_NAME ": OK\n");
return 0;
register_group_failed:
configfs_unregister_subsystem(&dtbocfg_root_subsys);
register_subsystem_failed:
return retval;
}
/**
* dtbocfg_module_exit()
*/
static void __exit dtbocfg_module_exit(void)
{
configfs_unregister_group(&dtbocfg_overlay_group);
configfs_unregister_subsystem(&dtbocfg_root_subsys);
}
module_init(dtbocfg_module_init);
module_exit(dtbocfg_module_exit);
MODULE_AUTHOR("ikwzm");
MODULE_DESCRIPTION("Device Tree Overlay Configuration File System");
MODULE_LICENSE("Dual BSD/GPL");