1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
| #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/cdev.h> #include <linux/property.h> #include <linux/gpio/consumer.h> #include <linux/device.h>
#define DEVICE_NAME "my_i2c_device" #define CLASS_NAME "my_i2c_class"
static int major; static struct class *i2c_class = NULL; static struct device *i2c_device = NULL; static struct i2c_client *global_client = NULL;
static int my_i2c_read(struct i2c_client *client, char *buf, int count) { struct i2c_msg msgs[1]; msgs[0].addr = client->addr; msgs[0].flags = I2C_M_RD; msgs[0].len = count; msgs[0].buf = buf; return (i2c_transfer(client->adapter, msgs, 1) == 1) ? 0 : -EIO; }
static int my_i2c_write(struct i2c_client *client, const char *buf, int count) { struct i2c_msg msgs[1]; msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = count; msgs[0].buf = (char *)buf; return (i2c_transfer(client->adapter, msgs, 1) == 1) ? 0 : -EIO; }
static ssize_t dev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { char kbuf[64]; int ret; if (count > 64) count = 64; ret = my_i2c_read(global_client, kbuf, count); if (ret < 0) return ret; if (copy_to_user(buf, kbuf, count)) return -EFAULT; return count; }
static ssize_t dev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { char kbuf[64]; if (count > 64) count = 64; if (copy_from_user(kbuf, buf, count)) return -EFAULT; if (my_i2c_write(global_client, kbuf, count) < 0) return -EIO; return count; }
static struct file_operations fops = { .owner = THIS_MODULE, .read = dev_read, .write = dev_write, };
static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; u32 val32, array[4]; const char *str; bool gesture_enabled;
global_client = client;
if (!device_property_read_u32(dev, "max-x", &val32)) dev_info(dev, "DTS Max X: %u\n", val32);
if (!device_property_read_string(dev, "vendor-name", &str)) dev_info(dev, "DTS Vendor: %s\n", str);
gesture_enabled = device_property_read_bool(dev, "enable-gesture"); dev_info(dev, "DTS Gesture: %s\n", gesture_enabled ? "Yes" : "No");
if (!device_property_read_u32_array(dev, "touch-thresholds", array, 4)) dev_info(dev, "DTS Thresholds: %u, %u, %u, %u\n", array[0], array[1], array[2], array[3]);
struct gpio_desc *ts_gpio = devm_gpiod_get_optional(dev, "touch", GPIOD_IN); if (!IS_ERR(ts_gpio) && ts_gpio) dev_info(dev, "DTS Touch GPIO obtained!\n");
if (client->irq > 0) dev_info(dev, "DTS IRQ Number: %d\n", client->irq);
major = register_chrdev(0, DEVICE_NAME, &fops); if (major < 0) return major;
i2c_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(i2c_class)) { unregister_chrdev(major, DEVICE_NAME); return PTR_ERR(i2c_class); }
i2c_device = device_create(i2c_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); if (IS_ERR(i2c_device)) { class_destroy(i2c_class); unregister_chrdev(major, DEVICE_NAME); return PTR_ERR(i2c_device); }
dev_info(dev, "Device /dev/%s created successfully\n", DEVICE_NAME); return 0; }
static void my_i2c_remove(struct i2c_client *client) { device_destroy(i2c_class, MKDEV(major, 0)); class_destroy(i2c_class); unregister_chrdev(major, DEVICE_NAME); dev_info(&client->dev, "I2C Device Removed\n"); }
static const struct of_device_id my_i2c_of_match[] = { { .compatible = "myvendor,mysensor" }, { } }; MODULE_DEVICE_TABLE(of, my_i2c_of_match);
static struct i2c_driver my_driver = { .driver = { .name = "my_custom_i2c_driver", .of_match_table = my_i2c_of_match, }, .probe = my_i2c_probe, .remove = my_i2c_remove, };
module_i2c_driver(my_driver);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jvle");
|