mirror of
https://github.com/LuckfoxTECH/luckfox-pico.git
synced 2026-01-18 11:38:31 +01:00
update:add luckfox-pico Ultra support
This commit is contained in:
committed by
luckfox-eng33
parent
1e160dee55
commit
d3153ac97e
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
429
sysdrv/source/kernel/drivers/of/dtbocfg.c
Normal file
429
sysdrv/source/kernel/drivers/of/dtbocfg.c
Normal 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");
|
||||
Reference in New Issue
Block a user