#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(¶meter, buf, sizeof(parameter))) { return -EFAULT; } parameter.value = HDMI_ReadI2C_Byte(parameter.address); if (copy_to_user(buf, ¶meter, 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(¶meter, 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 ");