linuxOS_D21X/source/linux-5.10/drivers/video/lt8911exb/LontiumDrv.c
2026-04-02 19:23:55 +08:00

284 lines
5.7 KiB
C
Executable File

#include "include/include.h"
struct _lt8911exb *lt8911exb;
static struct task_struct *kthread_obj;
atomic_t thread_should_stop = ATOMIC_INIT(0);
char *ChipName = "lt8911exb"; //Define Lontium Chip Name
static int major = 0;
static struct cdev chip_cdev;
static struct class *chip_class;
static int chip_open(struct inode *inode, struct file *filp)
{
printk("chip open\n");
return 0;
}
static int chip_close (struct inode *node, struct file *file)
{
printk("chip close\n");
return 0;
}
static ssize_t chip_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
Chip_Control_Args parameter;
if (copy_from_user(&parameter, buf, sizeof(parameter))) {
return -EFAULT;
}
parameter.value = HDMI_ReadI2C_Byte(parameter.address);
if (copy_to_user(buf, &parameter, sizeof(parameter))) {
return -EFAULT;
}
return sizeof(parameter);
}
static ssize_t chip_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
Chip_Control_Args parameter;
if (copy_from_user(&parameter, buf, sizeof(parameter))) {
return -EFAULT;
}
HDMI_WriteI2C_Byte(parameter.address, parameter.value);
return sizeof(parameter);
}
static struct file_operations chip_drv = {
.owner = THIS_MODULE,
.open = chip_open,
.release = chip_close,
.read = chip_read,
.write = chip_write,
};
static int chip_dev_init(void)
{
int ret;
dev_t devid;
ret = alloc_chrdev_region(&devid, 0, 1, ChipName);
if (ret < 0) {
return ret;
}
major = MAJOR(devid);
cdev_init(&chip_cdev, &chip_drv);
cdev_add(&chip_cdev, devid, 1);
chip_class = class_create(THIS_MODULE, "chip_class");
if (IS_ERR(chip_class)) {
unregister_chrdev(major, ChipName);
return -1;
}
device_create(chip_class, NULL, MKDEV(major, 0), NULL, ChipName); /* /dev/ChipName */
return 0;
}
static void chip_dev_exit(void)
{
device_destroy(chip_class, MKDEV(major, 0));
class_destroy(chip_class);
cdev_del(&chip_cdev);
unregister_chrdev_region(MKDEV(major,0), 1);
}
static const struct regmap_range chip_ranges[] = {
{ .range_min = 0, .range_max = 0xffff },
};
static const struct regmap_access_table chip_table = {
.yes_ranges = chip_ranges,
.n_yes_ranges = ARRAY_SIZE(chip_ranges),
};
static const struct regmap_config chip_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &chip_table,
.cache_type = REGCACHE_NONE,
};
/*
* devm_gpiod_get_optional - If this fails, NULL is returned and no error pointer.
*
* devm_gpiod_get - If this fails, an error pointer is returned, usually ERR_PTR(-ENOENT).
*
* The devm_gpiod_get function is recommended for practical use.
*/
static int chip_parse_dts(struct device *dev)
{
//Gets the handle to power gpio in dts
lt8911exb->power_gpio=devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(lt8911exb->power_gpio)) {
dev_err(dev, "Failed to get power GPIO\n");
return PTR_ERR(lt8911exb->power_gpio);
}
//Gets the handle to reset gpio in dts
lt8911exb->reset_gpio=devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(lt8911exb->reset_gpio)) {
dev_err(dev, "Failed to get reset GPIO\n");
return PTR_ERR(lt8911exb->reset_gpio);
}
// Additional GPIO pins can be added here if needed
return 0;
}
static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
chip_dev_init();
lt8911exb = devm_kzalloc(&client->dev, sizeof(*lt8911exb), GFP_KERNEL);
if (lt8911exb == NULL)
return -ENOMEM;
lt8911exb->trans_i2c = client;
lt8911exb->dev = &client->dev;
lt8911exb->chip_regmap = devm_regmap_init_i2c(client, &chip_regmap_config);
if (IS_ERR(lt8911exb->chip_regmap)) {
dev_err(&client->dev, "Failed to initialize regmap\n");
return PTR_ERR(lt8911exb->chip_regmap);
}
ret = chip_parse_dts(lt8911exb->dev);
if (ret<0){
dev_err(&client->dev, "Failed to parse device tree\n");
return ret;
}
i2c_set_clientdata(client, lt8911exb);
kthread_obj = kthread_run(LT8911EXB_Main, NULL, "LT8911EXB_kthread");
if (IS_ERR(kthread_obj)) {
kthread_obj = NULL;
chip_dev_exit();
dev_err(&client->dev, "Failed to create kernel thread\n");
return PTR_ERR(kthread_obj);
}
return 0;
}
static int chip_remove(struct i2c_client *client)
{
if (kthread_obj) {
atomic_set(&thread_should_stop, 1);
kthread_stop(kthread_obj);
kthread_obj = NULL;
}
chip_dev_exit();
printk("driver removed\n");
return 0;
}
static int chip_suspend(struct device *dev)
{
//power off
atomic_set(&thread_should_stop, 1);
kthread_stop(kthread_obj);
msleep(5);
gpiod_set_value(lt8911exb->power_gpio,0);
printk(KERN_INFO "lt8911exb Suspend");
return 0;
}
static int chip_resume(struct device *dev)
{
//power on
gpiod_set_value(lt8911exb->power_gpio,1);
msleep(5);
atomic_set(&thread_should_stop, 0);
kthread_obj = kthread_run(LT8911EXB_Main, NULL, "LT8911EXB_kthread");
printk(KERN_INFO "lt8911exb Resume");
return 0;
}
static const struct dev_pm_ops chip_pm_ops = {
.suspend = chip_suspend,
.resume = chip_resume,
};
static const struct i2c_device_id chip_ids[] = {
{"lt8911exb", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, chip_ids);
static const struct of_device_id chip_id_table[] = {
{.compatible = "lontium,lt8911exb"},
{ }
};
MODULE_DEVICE_TABLE(of, chip_id_table);
static struct i2c_driver chip_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "lt8911exb",
.pm = &chip_pm_ops,
.of_match_table = chip_id_table,
},
.probe = chip_probe,
.remove = chip_remove,
.id_table = chip_ids,
};
module_i2c_driver(chip_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LT8911EXB driver");
MODULE_AUTHOR("Tony <syyang@lontium.com>");