From e3fc887ca40cf997ad84b3b601a34ee033d0e230 Mon Sep 17 00:00:00 2001 From: Bekir Date: Sun, 22 Dec 2019 17:38:30 +0200 Subject: [PATCH 1/4] mpu6050-interrupt: Add base driver Signed-off-by: Bekir --- mpu6050/mpu6050-interrupt/Makefile | 32 +++ mpu6050/mpu6050-interrupt/mpu6050-regs.h | 33 +++ mpu6050/mpu6050-interrupt/mpu6050.c | 296 +++++++++++++++++++++++ 3 files changed, 361 insertions(+) create mode 100644 mpu6050/mpu6050-interrupt/Makefile create mode 100644 mpu6050/mpu6050-interrupt/mpu6050-regs.h create mode 100644 mpu6050/mpu6050-interrupt/mpu6050.c diff --git a/mpu6050/mpu6050-interrupt/Makefile b/mpu6050/mpu6050-interrupt/Makefile new file mode 100644 index 0000000..c2abd90 --- /dev/null +++ b/mpu6050/mpu6050-interrupt/Makefile @@ -0,0 +1,32 @@ +# +# mpu6050 accelerometer & gyroscope +# +ifneq ($(KERNELRELEASE),) + +obj-m := mpu6050.o + +else + + +ifeq ($(KERNELDIR),) +ifeq ($(BBB_KERNEL),) + $(error Path to kernel tree - KERNELDIR or BBB_KERNEL variable is not defined!) +endif +endif + +KERNELDIR ?= $(BBB_KERNEL) + +export ARCH = arm +export CROSS_COMPILE ?= arm-linux-gnueabihf- + + +.PHONY: all clean + +all: + $(MAKE) -C $(KERNELDIR) M=$(CURDIR) modules + +clean: + $(MAKE) -C $(KERNELDIR) M=$(CURDIR) clean + + +endif diff --git a/mpu6050/mpu6050-interrupt/mpu6050-regs.h b/mpu6050/mpu6050-interrupt/mpu6050-regs.h new file mode 100644 index 0000000..9d51680 --- /dev/null +++ b/mpu6050/mpu6050-interrupt/mpu6050-regs.h @@ -0,0 +1,33 @@ +#ifndef _MPU6050_REGS_H +#define _MPU6050_REGS_H + +/* Registed addresses */ +#define REG_CONFIG 0x1A +#define REG_GYRO_CONFIG 0x1B +#define REG_ACCEL_CONFIG 0x1C +#define REG_FIFO_EN 0x23 +#define REG_INT_PIN_CFG 0x37 +#define REG_INT_ENABLE 0x38 +#define REG_ACCEL_XOUT_H 0x3B +#define REG_ACCEL_XOUT_L 0x3C +#define REG_ACCEL_YOUT_H 0x3D +#define REG_ACCEL_YOUT_L 0x3E +#define REG_ACCEL_ZOUT_H 0x3F +#define REG_ACCEL_ZOUT_L 0x40 +#define REG_TEMP_OUT_H 0x41 +#define REG_TEMP_OUT_L 0x42 +#define REG_GYRO_XOUT_H 0x43 +#define REG_GYRO_XOUT_L 0x44 +#define REG_GYRO_YOUT_H 0x45 +#define REG_GYRO_YOUT_L 0x46 +#define REG_GYRO_ZOUT_H 0x47 +#define REG_GYRO_ZOUT_L 0x48 +#define REG_USER_CTRL 0x6A +#define REG_PWR_MGMT_1 0x6B +#define REG_PWR_MGMT_2 0x6C +#define REG_WHO_AM_I 0x75 + +/* Register values */ +#define MPU6050_WHO_AM_I 0x68 + +#endif /* _MPU6050_REGS_H */ diff --git a/mpu6050/mpu6050-interrupt/mpu6050.c b/mpu6050/mpu6050-interrupt/mpu6050.c new file mode 100644 index 0000000..b6ef64b --- /dev/null +++ b/mpu6050/mpu6050-interrupt/mpu6050.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include + +#include "mpu6050-regs.h" + + +struct mpu6050_data { + struct i2c_client *drv_client; + int accel_values[3]; + int gyro_values[3]; + int temperature; +}; + +static struct mpu6050_data g_mpu6050_data; + +static int mpu6050_read_data(void) +{ + int temp; + struct i2c_client *drv_client = g_mpu6050_data.drv_client; + + if (drv_client == 0) + return -ENODEV; + + /* accel */ + g_mpu6050_data.accel_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_XOUT_H)); + g_mpu6050_data.accel_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_YOUT_H)); + g_mpu6050_data.accel_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_ZOUT_H)); + /* gyro */ + g_mpu6050_data.gyro_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_XOUT_H)); + g_mpu6050_data.gyro_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_YOUT_H)); + g_mpu6050_data.gyro_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_ZOUT_H)); + /* Temperature in degrees C = + * (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 + */ + temp = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_TEMP_OUT_H)); + g_mpu6050_data.temperature = (temp + 12420 + 170) / 340; + + dev_info(&drv_client->dev, "sensor data read:\n"); + dev_info(&drv_client->dev, "ACCEL[X,Y,Z] = [%d, %d, %d]\n", + g_mpu6050_data.accel_values[0], + g_mpu6050_data.accel_values[1], + g_mpu6050_data.accel_values[2]); + dev_info(&drv_client->dev, "GYRO[X,Y,Z] = [%d, %d, %d]\n", + g_mpu6050_data.gyro_values[0], + g_mpu6050_data.gyro_values[1], + g_mpu6050_data.gyro_values[2]); + dev_info(&drv_client->dev, "TEMP = %d\n", + g_mpu6050_data.temperature); + + return 0; +} + +static int mpu6050_probe(struct i2c_client *drv_client, + const struct i2c_device_id *id) +{ + int ret; + + dev_info(&drv_client->dev, + "i2c client address is 0x%X\n", drv_client->addr); + + /* Read who_am_i register */ + ret = i2c_smbus_read_byte_data(drv_client, REG_WHO_AM_I); + if (IS_ERR_VALUE(ret)) { + dev_err(&drv_client->dev, + "i2c_smbus_read_byte_data() failed with error: %d\n", + ret); + return ret; + } + if (ret != MPU6050_WHO_AM_I) { + dev_err(&drv_client->dev, + "wrong i2c device found: expected 0x%X, found 0x%X\n", + MPU6050_WHO_AM_I, ret); + return -1; + } + dev_info(&drv_client->dev, + "i2c mpu6050 device found, WHO_AM_I register value = 0x%X\n", + ret); + + /* Setup the device */ + /* No error handling here! */ + i2c_smbus_write_byte_data(drv_client, REG_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_GYRO_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_ACCEL_CONFIG, 0); + i2c_smbus_write_byte_data(drv_client, REG_FIFO_EN, 0); + i2c_smbus_write_byte_data(drv_client, REG_INT_PIN_CFG, 0); + i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 0); + i2c_smbus_write_byte_data(drv_client, REG_USER_CTRL, 0); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_2, 0); + + g_mpu6050_data.drv_client = drv_client; + + dev_info(&drv_client->dev, "i2c driver probed\n"); + return 0; +} + +static int mpu6050_remove(struct i2c_client *drv_client) +{ + g_mpu6050_data.drv_client = 0; + + dev_info(&drv_client->dev, "i2c driver removed\n"); + return 0; +} + +static const struct i2c_device_id mpu6050_idtable[] = { + { "mpu6050", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpu6050_idtable); + +static struct i2c_driver mpu6050_i2c_driver = { + .driver = { + .name = "gl_mpu6050", + }, + + .probe = mpu6050_probe, + .remove = mpu6050_remove, + .id_table = mpu6050_idtable, +}; + +static ssize_t accel_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); + return strlen(buf); +} + +static ssize_t accel_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); + return strlen(buf); +} + +static ssize_t accel_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); + return strlen(buf); +} + +static ssize_t gyro_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); + return strlen(buf); +} + +static ssize_t gyro_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); + return strlen(buf); +} + +static ssize_t gyro_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); + return strlen(buf); +} + +static ssize_t temp_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + mpu6050_read_data(); + + sprintf(buf, "%d\n", g_mpu6050_data.temperature); + return strlen(buf); +} + +CLASS_ATTR(accel_x, 0444, &accel_x_show, NULL); +CLASS_ATTR(accel_y, 0444, &accel_y_show, NULL); +CLASS_ATTR(accel_z, 0444, &accel_z_show, NULL); +CLASS_ATTR(gyro_x, 0444, &gyro_x_show, NULL); +CLASS_ATTR(gyro_y, 0444, &gyro_y_show, NULL); +CLASS_ATTR(gyro_z, 0444, &gyro_z_show, NULL); +CLASS_ATTR(temperature, 0444, &temp_show, NULL); + +static struct class *attr_class; + +static int mpu6050_init(void) +{ + int ret; + + /* Create i2c driver */ + ret = i2c_add_driver(&mpu6050_i2c_driver); + if (ret) { + pr_err("mpu6050: failed to add new i2c driver: %d\n", ret); + return ret; + } + pr_info("mpu6050: i2c driver created\n"); + + /* Create class */ + attr_class = class_create(THIS_MODULE, "mpu6050"); + if (IS_ERR(attr_class)) { + ret = PTR_ERR(attr_class); + pr_err("mpu6050: failed to create sysfs class: %d\n", ret); + return ret; + } + pr_info("mpu6050: sysfs class created\n"); + + /* Create accel_x */ + ret = class_create_file(attr_class, &class_attr_accel_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_x: %d\n", ret); + return ret; + } + /* Create accel_y */ + ret = class_create_file(attr_class, &class_attr_accel_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_y: %d\n", ret); + return ret; + } + /* Create accel_z */ + ret = class_create_file(attr_class, &class_attr_accel_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_z: %d\n", ret); + return ret; + } + /* Create gyro_x */ + ret = class_create_file(attr_class, &class_attr_gyro_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_x: %d\n", ret); + return ret; + } + /* Create gyro_y */ + ret = class_create_file(attr_class, &class_attr_gyro_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_y: %d\n", ret); + return ret; + } + /* Create gyro_z */ + ret = class_create_file(attr_class, &class_attr_gyro_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_z: %d\n", ret); + return ret; + } + /* Create temperature */ + ret = class_create_file(attr_class, &class_attr_temperature); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute temperature: %d\n", ret); + return ret; + } + + pr_info("mpu6050: sysfs class attributes created\n"); + + pr_info("mpu6050: module loaded\n"); + return 0; +} + +static void mpu6050_exit(void) +{ + if (attr_class) { + class_remove_file(attr_class, &class_attr_accel_x); + class_remove_file(attr_class, &class_attr_accel_y); + class_remove_file(attr_class, &class_attr_accel_z); + class_remove_file(attr_class, &class_attr_gyro_x); + class_remove_file(attr_class, &class_attr_gyro_y); + class_remove_file(attr_class, &class_attr_gyro_z); + class_remove_file(attr_class, &class_attr_temperature); + pr_info("mpu6050: sysfs class attributes removed\n"); + + class_destroy(attr_class); + pr_info("mpu6050: sysfs class destroyed\n"); + } + + i2c_del_driver(&mpu6050_i2c_driver); + pr_info("mpu6050: i2c driver deleted\n"); + + pr_info("mpu6050: module exited\n"); +} + +module_init(mpu6050_init); +module_exit(mpu6050_exit); + +MODULE_AUTHOR("Andriy.Khulap "); +MODULE_DESCRIPTION("mpu6050 I2C acc&gyro"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); From 66abafaf1d4d1f9483eab394171c587aed25d950 Mon Sep 17 00:00:00 2001 From: Bekir Date: Sun, 22 Dec 2019 17:53:06 +0200 Subject: [PATCH 2/4] mpu6050-interrupt: Add work queue Signed-off-by: Bekir --- mpu6050/mpu6050-interrupt/Makefile | 34 +--- .../sun8i-h3-i2c-mpu6050.dts | 32 ++++ .../device_tree_overlay/sun8i-h3-mpu6050.dtbo | Bin 0 -> 944 bytes mpu6050/mpu6050-interrupt/logs/dmesg_1 | 169 ++++++++++++++++++ mpu6050/mpu6050-interrupt/logs/log_1 | 34 ++++ mpu6050/mpu6050-interrupt/mpu6050.c | 159 +++++++++------- 6 files changed, 332 insertions(+), 96 deletions(-) create mode 100644 mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-i2c-mpu6050.dts create mode 100644 mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-mpu6050.dtbo create mode 100644 mpu6050/mpu6050-interrupt/logs/dmesg_1 create mode 100644 mpu6050/mpu6050-interrupt/logs/log_1 diff --git a/mpu6050/mpu6050-interrupt/Makefile b/mpu6050/mpu6050-interrupt/Makefile index c2abd90..036d870 100644 --- a/mpu6050/mpu6050-interrupt/Makefile +++ b/mpu6050/mpu6050-interrupt/Makefile @@ -1,32 +1,12 @@ -# -# mpu6050 accelerometer & gyroscope -# -ifneq ($(KERNELRELEASE),) +obj-m +=mpu6050.o -obj-m := mpu6050.o +KERNEL_DIR := /home/bekir/Work/LinuxKernelCamp/linux/linux-stable -else - - -ifeq ($(KERNELDIR),) -ifeq ($(BBB_KERNEL),) - $(error Path to kernel tree - KERNELDIR or BBB_KERNEL variable is not defined!) -endif -endif - -KERNELDIR ?= $(BBB_KERNEL) - -export ARCH = arm -export CROSS_COMPILE ?= arm-linux-gnueabihf- - - -.PHONY: all clean +COMPILE_FLAGS += CROSS_COMPILE=arm-linux-gnueabihf- CROSS=arm-linux-gnueabihf- ARCH=arm all: - $(MAKE) -C $(KERNELDIR) M=$(CURDIR) modules - + make -C $(KERNEL_DIR) M=$(PWD) $(COMPILE_FLAGS) modules clean: - $(MAKE) -C $(KERNELDIR) M=$(CURDIR) clean - - -endif + make -C $(KERNEL_DIR) M=$(PWD) $(COMPILE_FLAGS) clean +install: + make -C $(KERNEL_DIR) M=$(PWD) modules_install INSTALL_MOD_PATH=$(PWD)/build_modules diff --git a/mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-i2c-mpu6050.dts b/mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-i2c-mpu6050.dts new file mode 100644 index 0000000..19991ec --- /dev/null +++ b/mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-i2c-mpu6050.dts @@ -0,0 +1,32 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "allwinner,sun8i-h3"; + + fragment@0 { + target = <&i2c0>; + __overlay__ { + mpu6050@68 { + compatible = "gl,mpu6050"; + reg = <0x68>; + interrupt-parent = <&pio>; + interrupts = <0 1 2>; + interrupt-names = "mpu6050_interrupt"; + pinctrl-names = "default"; + pinctrl-0 = <&mpu6050_int_pin>; + status = "okay"; + }; + }; + }; + + fragment@1 { + target = <&pio>; + __overlay__ { + mpu6050_int_pin: mpu6050-int-pin { + pins = "PA1"; + function = "gpio_in"; + }; + }; + }; +}; diff --git a/mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-mpu6050.dtbo b/mpu6050/mpu6050-interrupt/device_tree_overlay/sun8i-h3-mpu6050.dtbo new file mode 100644 index 0000000000000000000000000000000000000000..ccb9058cc7541f313655f4e12f48b079b822cfb7 GIT binary patch literal 944 zcma)4OHRWu5Ow)TAVA_HShJ%GqNYVus4HO0hBceWElz6T*pcHsFA7}aml zB2uU27DaiUc=my5D?TcDsc#!N0mw-23P5@48I)v!)J|BNB@Rg#?Qa0r_afw(%CnTC zf87GaL-9IrXCC+*o{YFFG-vMTdsY8mXZE1QOQfczs)yfR8w{ zIN?r?m0-mYnH3RRmfR%LX6b1jiirq = 50 +[64540.232674] gl,mpu6050 0-0068: i2c driver probed +[64540.232860] mpu6050: i2c driver created +[64540.232894] mpu6050: sysfs class created +[64540.232917] mpu6050: sysfs class attributes created +[64540.232920] mpu6050: module loaded +[64540.238057] delay work is active +[64540.341532] delay work is active +[64540.539109] delay work is active +[64540.736682] delay work is active +[64540.934228] delay work is active +[64541.131820] delay work is active +[64541.329375] delay work is active +[64541.526948] delay work is active +[64541.724534] delay work is active +[64541.922121] delay work is active +[64542.119695] delay work is active +[64542.317296] delay work is active +[64542.514872] delay work is active +[64542.712443] delay work is active +[64542.910016] delay work is active +[64543.107613] delay work is active +[64543.305199] delay work is active +[64543.502754] delay work is active +[64543.700330] delay work is active +[64543.897923] delay work is active +[64544.095535] delay work is active +[64544.293126] delay work is active +[64544.490698] delay work is active +[64544.688283] delay work is active +[64544.885856] delay work is active +[64545.083444] delay work is active +[64545.281029] delay work is active +[64545.478616] delay work is active +[64545.676190] delay work is active +[64545.873753] delay work is active +[64546.071346] delay work is active +[64546.268906] delay work is active +[64546.466484] delay work is active +[64546.664071] delay work is active +[64546.861660] delay work is active +[64547.059235] delay work is active +[64547.256832] delay work is active +[64547.454423] delay work is active +[64547.652001] delay work is active +[64547.849581] delay work is active +[64548.047165] delay work is active +[64548.244734] delay work is active +[64548.442345] delay work is active +[64548.639912] delay work is active +[64548.837507] delay work is active +[64549.035122] delay work is active +[64549.232713] delay work is active +[64549.430313] delay work is active +[64549.627873] delay work is active +[64549.825462] delay work is active +[64550.023069] delay work is active +[64550.220635] delay work is active +[64550.418248] delay work is active +[64550.615841] delay work is active +[64550.813434] delay work is active +[64551.011046] delay work is active +[64551.208624] delay work is active +[64551.406214] delay work is active +[64551.603811] delay work is active +[64551.801398] delay work is active +[64551.998996] delay work is active +[64552.196594] delay work is active +[64552.394191] delay work is active +[64552.591788] delay work is active +[64552.789371] delay work is active +[64552.986928] delay work is active +[64553.184559] delay work is active +[64553.382173] delay work is active +[64553.579734] delay work is active +[64553.777320] delay work is active +[64553.974937] delay work is active +[64554.172494] delay work is active +[64554.370087] delay work is active +[64554.567685] delay work is active +[64554.765266] delay work is active +[64554.962865] delay work is active +[64555.160481] delay work is active +[64555.358060] delay work is active +[64555.555653] delay work is active +[64555.753228] delay work is active +[64555.950812] delay work is active +[64556.148388] delay work is active +[64556.345981] delay work is active +[64556.543588] delay work is active +[64556.741227] delay work is active +[64556.938752] delay work is active +[64557.136314] delay work is active +[64557.333927] delay work is active +[64557.531480] delay work is active +[64557.729082] delay work is active +[64557.926683] delay work is active +[64558.124231] delay work is active +[64558.321833] delay work is active +[64558.519400] delay work is active +[64558.717007] delay work is active +[64558.914584] delay work is active +[64559.112184] delay work is active +[64559.309772] delay work is active +[64559.507335] delay work is active +[64559.704934] delay work is active +[64559.902516] delay work is active +[64560.100088] delay work is active +[64560.297684] delay work is active +[64560.495255] delay work is active +[64560.692834] delay work is active +[64560.890449] delay work is active +[64561.087979] delay work is active +[64561.285612] delay work is active +[64561.483165] delay work is active +[64561.680778] delay work is active +[64561.878368] delay work is active +[64562.075920] delay work is active +[64562.273525] delay work is active +[64562.471115] delay work is active +[64562.668697] delay work is active +[64562.866240] delay work is active +[64563.063837] delay work is active +[64563.261407] delay work is active +[64563.459011] delay work is active +[64563.656608] delay work is active +[64563.854199] delay work is active +[64564.051783] delay work is active +[64564.249343] delay work is active +[64564.446934] delay work is active +[64564.644533] delay work is active +[64564.842086] delay work is active +[64565.039667] delay work is active +[64565.237258] delay work is active +[64565.434843] delay work is active +[64565.632429] delay work is active +[64565.829998] delay work is active +[64566.027605] delay work is active +[64566.225173] delay work is active +[64566.422753] delay work is active +[64566.620340] delay work is active +[64566.817888] delay work is active +[64567.015486] delay work is active +[64567.213045] delay work is active +[64567.410636] delay work is active +[64567.608217] delay work is active +[64567.805784] delay work is active +[64568.003335] delay work is active +[64568.200916] delay work is active +[64568.398496] delay work is active +[64568.596090] delay work is active +[64568.793649] delay work is active +[64568.991248] delay work is active +[64569.188806] delay work is active +[64569.386375] delay work is active +[64569.583980] delay work is active +[64569.781564] delay work is active +[64569.979155] delay work is active +[64570.176721] delay work is active +[64570.374306] delay work is active +[64570.421589] mpu6050: sysfs class attributes removed +[64570.421670] mpu6050: sysfs class destroyed +[64570.421863] gl,mpu6050 0-0068: i2c driver removed +[64570.421991] mpu6050: i2c driver deleted +[64570.421995] mpu6050: module exited + diff --git a/mpu6050/mpu6050-interrupt/logs/log_1 b/mpu6050/mpu6050-interrupt/logs/log_1 new file mode 100644 index 0000000..1f1f078 --- /dev/null +++ b/mpu6050/mpu6050-interrupt/logs/log_1 @@ -0,0 +1,34 @@ + ___ ____ _ ___ + / _ \| _ \(_) / _ \ _ __ ___ +| | | | |_) | | | | | | '_ \ / _ \ +| |_| | __/| | | |_| | | | | __/ + \___/|_| |_| \___/|_| |_|\___| + +Welcome to Armbian Bionic with Linux 5.3.7-dirty + +System load: 0.00 0.00 0.00 Up time: 17:54 hours +Memory usage: 9 % of 498MB IP: 192.168.100.2 +Usage of /: 13% of 7.3G + +[ General system configuration (beta): armbian-config ] + +Last login: Fri Dec 13 03:10:59 2019 + +root@orangepione:~# insmod ./mpu6050.ko^C +root@orangepione:~# cd /home/bekir/ +root@orangepione:/home/bekir# insmod ./mpu6050_delay_work.ko +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +25.128 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +25.112 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +25.128 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_x +-5864 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_y +-5908 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_z +14868 +root@orangepione:/home/bekir# rmmod mpu6050_delay_work +root@orangepione:/home/bekir# + diff --git a/mpu6050/mpu6050-interrupt/mpu6050.c b/mpu6050/mpu6050-interrupt/mpu6050.c index b6ef64b..4fdba88 100644 --- a/mpu6050/mpu6050-interrupt/mpu6050.c +++ b/mpu6050/mpu6050-interrupt/mpu6050.c @@ -4,12 +4,25 @@ #include #include #include +#include +#include +#include -#include "mpu6050-regs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpu6050-regs.h" struct mpu6050_data { struct i2c_client *drv_client; + struct workqueue_struct *queue; + struct work_struct work; int accel_values[3]; int gyro_values[3]; int temperature; @@ -17,43 +30,41 @@ struct mpu6050_data { static struct mpu6050_data g_mpu6050_data; -static int mpu6050_read_data(void) +static int mpu6050_read_data(int reg, int *value) { - int temp; struct i2c_client *drv_client = g_mpu6050_data.drv_client; if (drv_client == 0) return -ENODEV; - /* accel */ - g_mpu6050_data.accel_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_XOUT_H)); - g_mpu6050_data.accel_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_YOUT_H)); - g_mpu6050_data.accel_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_ACCEL_ZOUT_H)); - /* gyro */ - g_mpu6050_data.gyro_values[0] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_XOUT_H)); - g_mpu6050_data.gyro_values[1] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_YOUT_H)); - g_mpu6050_data.gyro_values[2] = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_GYRO_ZOUT_H)); - /* Temperature in degrees C = - * (TEMP_OUT Register Value as a signed quantity)/340 + 36.53 - */ - temp = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, REG_TEMP_OUT_H)); - g_mpu6050_data.temperature = (temp + 12420 + 170) / 340; - - dev_info(&drv_client->dev, "sensor data read:\n"); - dev_info(&drv_client->dev, "ACCEL[X,Y,Z] = [%d, %d, %d]\n", - g_mpu6050_data.accel_values[0], - g_mpu6050_data.accel_values[1], - g_mpu6050_data.accel_values[2]); - dev_info(&drv_client->dev, "GYRO[X,Y,Z] = [%d, %d, %d]\n", - g_mpu6050_data.gyro_values[0], - g_mpu6050_data.gyro_values[1], - g_mpu6050_data.gyro_values[2]); - dev_info(&drv_client->dev, "TEMP = %d\n", - g_mpu6050_data.temperature); + *value = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, reg)); return 0; } +static irqreturn_t interrupt_handler(int irq, void *dev) +{ + queue_work(g_mpu6050_data.queue, &g_mpu6050_data.work); + return IRQ_HANDLED; +} + +static void work_func(struct work_struct *work) +{ + int temp; + + mpu6050_read_data(REG_ACCEL_XOUT_H, &g_mpu6050_data.accel_values[0]); + mpu6050_read_data(REG_ACCEL_YOUT_H, &g_mpu6050_data.accel_values[1]); + mpu6050_read_data(REG_ACCEL_ZOUT_H, &g_mpu6050_data.accel_values[2]); + mpu6050_read_data(REG_GYRO_XOUT_H, &g_mpu6050_data.gyro_values[0]); + mpu6050_read_data(REG_GYRO_YOUT_H, &g_mpu6050_data.gyro_values[1]); + mpu6050_read_data(REG_GYRO_ZOUT_H, &g_mpu6050_data.gyro_values[2]); + + mpu6050_read_data(REG_TEMP_OUT_H, &temp); + g_mpu6050_data.temperature = (temp + 12420); + + pr_info("delay work is active\n"); +} + static int mpu6050_probe(struct i2c_client *drv_client, const struct i2c_device_id *id) { @@ -82,26 +93,42 @@ static int mpu6050_probe(struct i2c_client *drv_client, /* Setup the device */ /* No error handling here! */ - i2c_smbus_write_byte_data(drv_client, REG_CONFIG, 0); - i2c_smbus_write_byte_data(drv_client, REG_GYRO_CONFIG, 0); - i2c_smbus_write_byte_data(drv_client, REG_ACCEL_CONFIG, 0); - i2c_smbus_write_byte_data(drv_client, REG_FIFO_EN, 0); - i2c_smbus_write_byte_data(drv_client, REG_INT_PIN_CFG, 0); - i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 0); - i2c_smbus_write_byte_data(drv_client, REG_USER_CTRL, 0); - i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0); - i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_2, 0); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0x80); + msleep(100); + i2c_smbus_write_byte_data(drv_client, REG_SMPRT_DIV, 0xFF); + i2c_smbus_write_byte_data(drv_client, REG_INT_PIN_CFG, 0x90); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0x20); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_2, 0x40); + i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 1); g_mpu6050_data.drv_client = drv_client; + g_mpu6050_data.queue = create_singlethread_workqueue("mpu6050_work_queue"); + INIT_WORK(&g_mpu6050_data.work, work_func); + + if (request_irq(drv_client->irq, interrupt_handler, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + "mpu6050", (void *)drv_client)) { + + dev_info(&drv_client->dev, "interrupt is not registered\n"); + return -EINVAL; + + } + dev_info(&drv_client->dev, "drv_client->irq = %d\n", drv_client->irq); dev_info(&drv_client->dev, "i2c driver probed\n"); + return 0; } static int mpu6050_remove(struct i2c_client *drv_client) { + + free_irq(drv_client->irq, (void *)drv_client); g_mpu6050_data.drv_client = 0; + flush_workqueue(g_mpu6050_data.queue); + destroy_workqueue(g_mpu6050_data.queue); + dev_info(&drv_client->dev, "i2c driver removed\n"); return 0; } @@ -114,7 +141,7 @@ MODULE_DEVICE_TABLE(i2c, mpu6050_idtable); static struct i2c_driver mpu6050_i2c_driver = { .driver = { - .name = "gl_mpu6050", + .name = "gl,mpu6050", }, .probe = mpu6050_probe, @@ -125,8 +152,6 @@ static struct i2c_driver mpu6050_i2c_driver = { static ssize_t accel_x_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); return strlen(buf); } @@ -134,8 +159,6 @@ static ssize_t accel_x_show(struct class *class, static ssize_t accel_y_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); return strlen(buf); } @@ -143,8 +166,6 @@ static ssize_t accel_y_show(struct class *class, static ssize_t accel_z_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); return strlen(buf); } @@ -152,8 +173,6 @@ static ssize_t accel_z_show(struct class *class, static ssize_t gyro_x_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); return strlen(buf); } @@ -161,8 +180,6 @@ static ssize_t gyro_x_show(struct class *class, static ssize_t gyro_y_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); return strlen(buf); } @@ -170,8 +187,6 @@ static ssize_t gyro_y_show(struct class *class, static ssize_t gyro_z_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); return strlen(buf); } @@ -179,19 +194,18 @@ static ssize_t gyro_z_show(struct class *class, static ssize_t temp_show(struct class *class, struct class_attribute *attr, char *buf) { - mpu6050_read_data(); - - sprintf(buf, "%d\n", g_mpu6050_data.temperature); + sprintf(buf, "%i.%03i\n", g_mpu6050_data.temperature / 340, + g_mpu6050_data.temperature % 340); return strlen(buf); } -CLASS_ATTR(accel_x, 0444, &accel_x_show, NULL); -CLASS_ATTR(accel_y, 0444, &accel_y_show, NULL); -CLASS_ATTR(accel_z, 0444, &accel_z_show, NULL); -CLASS_ATTR(gyro_x, 0444, &gyro_x_show, NULL); -CLASS_ATTR(gyro_y, 0444, &gyro_y_show, NULL); -CLASS_ATTR(gyro_z, 0444, &gyro_z_show, NULL); -CLASS_ATTR(temperature, 0444, &temp_show, NULL); +CLASS_ATTR_RO(accel_x); +CLASS_ATTR_RO(accel_y); +CLASS_ATTR_RO(accel_z); +CLASS_ATTR_RO(gyro_x); +CLASS_ATTR_RO(gyro_y); +CLASS_ATTR_RO(gyro_z); +CLASS_ATTR_RO(temp); static struct class *attr_class; @@ -219,43 +233,50 @@ static int mpu6050_init(void) /* Create accel_x */ ret = class_create_file(attr_class, &class_attr_accel_x); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute accel_x: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute accel_x:%d\n", + ret); return ret; } /* Create accel_y */ ret = class_create_file(attr_class, &class_attr_accel_y); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute accel_y: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute accel_y:%d\n", + ret); return ret; } /* Create accel_z */ ret = class_create_file(attr_class, &class_attr_accel_z); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute accel_z: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute accel_z:%d\n", + ret); return ret; } /* Create gyro_x */ ret = class_create_file(attr_class, &class_attr_gyro_x); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute gyro_x: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute gyro_x:%d\n", + ret); return ret; } /* Create gyro_y */ ret = class_create_file(attr_class, &class_attr_gyro_y); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute gyro_y: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute gyro_y:%d\n", + ret); return ret; } /* Create gyro_z */ ret = class_create_file(attr_class, &class_attr_gyro_z); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute gyro_z: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute gyro_z:%d\n", + ret); return ret; } /* Create temperature */ - ret = class_create_file(attr_class, &class_attr_temperature); + ret = class_create_file(attr_class, &class_attr_temp); if (ret) { - pr_err("mpu6050: failed to create sysfs class attribute temperature: %d\n", ret); + pr_err("mpu6050: failed to create sysfs class attribute temperature:%d\n", + ret); return ret; } @@ -274,7 +295,7 @@ static void mpu6050_exit(void) class_remove_file(attr_class, &class_attr_gyro_x); class_remove_file(attr_class, &class_attr_gyro_y); class_remove_file(attr_class, &class_attr_gyro_z); - class_remove_file(attr_class, &class_attr_temperature); + class_remove_file(attr_class, &class_attr_temp); pr_info("mpu6050: sysfs class attributes removed\n"); class_destroy(attr_class); From a68fbef5b7b7d9e49f7f1c0f183a54b1a445b882 Mon Sep 17 00:00:00 2001 From: Bekir Date: Sun, 22 Dec 2019 17:59:16 +0200 Subject: [PATCH 3/4] mpu6050-interrupt: Add thread interrupt Signed-off-by: Bekir --- mpu6050/mpu6050-interrupt/Makefile | 1 + mpu6050/mpu6050-interrupt/logs/dmesg_2 | 123 +++++++ mpu6050/mpu6050-interrupt/logs/log_2 | 15 + mpu6050/mpu6050-interrupt/mpu6050_interrupt.c | 309 ++++++++++++++++++ 4 files changed, 448 insertions(+) create mode 100644 mpu6050/mpu6050-interrupt/logs/dmesg_2 create mode 100644 mpu6050/mpu6050-interrupt/logs/log_2 create mode 100644 mpu6050/mpu6050-interrupt/mpu6050_interrupt.c diff --git a/mpu6050/mpu6050-interrupt/Makefile b/mpu6050/mpu6050-interrupt/Makefile index 036d870..d8d77c5 100644 --- a/mpu6050/mpu6050-interrupt/Makefile +++ b/mpu6050/mpu6050-interrupt/Makefile @@ -1,3 +1,4 @@ +obj-m += mpu6050_interrupt.o obj-m +=mpu6050.o KERNEL_DIR := /home/bekir/Work/LinuxKernelCamp/linux/linux-stable diff --git a/mpu6050/mpu6050-interrupt/logs/dmesg_2 b/mpu6050/mpu6050-interrupt/logs/dmesg_2 new file mode 100644 index 0000000..ae9fbf9 --- /dev/null +++ b/mpu6050/mpu6050-interrupt/logs/dmesg_2 @@ -0,0 +1,123 @@ +root@orangepione:~# dmesg -w +[65178.875001] gl,mpu6050 0-0068: i2c client address is 0x68 +[65178.875452] gl,mpu6050 0-0068: i2c mpu6050 device found, WHO_AM_I register value = 0x68 +[65178.992653] gl,mpu6050 0-0068: drv_client->irq = 50 +[65178.992665] gl,mpu6050 0-0068: i2c driver probed +[65178.992849] mpu6050: i2c driver created +[65178.992887] mpu6050: sysfs class created +[65178.992908] mpu6050: sysfs class attributes created +[65178.992911] mpu6050: module loaded +[65178.996524] irq 50 was generated +[65179.101599] irq 50 was generated +[65179.299310] irq 50 was generated +[65179.497022] irq 50 was generated +[65179.694747] irq 50 was generated +[65179.892443] irq 50 was generated +[65180.090175] irq 50 was generated +[65180.287890] irq 50 was generated +[65180.485590] irq 50 was generated +[65180.683301] irq 50 was generated +[65180.881039] irq 50 was generated +[65181.078747] irq 50 was generated +[65181.276467] irq 50 was generated +[65181.474186] irq 50 was generated +[65181.671877] irq 50 was generated +[65181.869598] irq 50 was generated +[65182.067307] irq 50 was generated +[65182.265019] irq 50 was generated +[65182.462752] irq 50 was generated +[65182.660462] irq 50 was generated +[65182.858172] irq 50 was generated +[65183.055887] irq 50 was generated +[65183.253604] irq 50 was generated +[65183.451342] irq 50 was generated +[65183.649027] irq 50 was generated +[65183.846759] irq 50 was generated +[65184.044501] irq 50 was generated +[65184.242192] irq 50 was generated +[65184.439910] irq 50 was generated +[65184.637604] irq 50 was generated +[65184.835305] irq 50 was generated +[65185.033026] irq 50 was generated +[65185.230743] irq 50 was generated +[65185.428455] irq 50 was generated +[65185.626175] irq 50 was generated +[65185.823879] irq 50 was generated +[65186.021607] irq 50 was generated +[65186.219325] irq 50 was generated +[65186.417016] irq 50 was generated +[65186.614726] irq 50 was generated +[65186.812447] irq 50 was generated +[65187.010160] irq 50 was generated +[65187.207883] irq 50 was generated +[65187.405595] irq 50 was generated +[65187.603309] irq 50 was generated +[65187.801017] irq 50 was generated +[65187.998717] irq 50 was generated +[65188.196446] irq 50 was generated +[65188.394142] irq 50 was generated +[65188.591845] irq 50 was generated +[65188.789561] irq 50 was generated +[65188.987281] irq 50 was generated +[65189.184998] irq 50 was generated +[65189.382702] irq 50 was generated +[65189.580406] irq 50 was generated +[65189.778119] irq 50 was generated +[65189.975857] irq 50 was generated +[65190.173560] irq 50 was generated +[65190.371301] irq 50 was generated +[65190.569018] irq 50 was generated +[65190.766736] irq 50 was generated +[65190.964461] irq 50 was generated +[65191.162220] irq 50 was generated +[65191.359907] irq 50 was generated +[65191.557638] irq 50 was generated +[65191.755335] irq 50 was generated +[65191.953031] irq 50 was generated +[65192.150748] irq 50 was generated +[65192.348482] irq 50 was generated +[65192.546206] irq 50 was generated +[65192.743913] irq 50 was generated +[65192.941626] irq 50 was generated +[65193.139310] irq 50 was generated +[65193.337050] irq 50 was generated +[65193.534797] irq 50 was generated +[65193.732507] irq 50 was generated +[65193.930195] irq 50 was generated +[65194.127919] irq 50 was generated +[65194.325624] irq 50 was generated +[65194.523371] irq 50 was generated +[65194.721098] irq 50 was generated +[65194.918809] irq 50 was generated +[65195.116512] irq 50 was generated +[65195.314200] irq 50 was generated +[65195.511935] irq 50 was generated +[65195.709659] irq 50 was generated +[65195.907348] irq 50 was generated +[65196.105072] irq 50 was generated +[65196.302814] irq 50 was generated +[65196.500524] irq 50 was generated +[65196.698233] irq 50 was generated +[65196.895955] irq 50 was generated +[65197.093680] irq 50 was generated +[65197.291427] irq 50 was generated +[65197.489140] irq 50 was generated +[65197.686849] irq 50 was generated +[65197.884599] irq 50 was generated +[65198.082325] irq 50 was generated +[65198.280022] irq 50 was generated +[65198.477759] irq 50 was generated +[65198.675486] irq 50 was generated +[65198.873205] irq 50 was generated +[65199.070924] irq 50 was generated +[65199.268645] irq 50 was generated +[65199.466356] irq 50 was generated +[65199.664083] irq 50 was generated +[65199.861094] mpu6050: sysfs class attributes removed +[65199.861180] mpu6050: sysfs class destroyed +[65199.861994] irq 50 was generated +[65199.862050] gl,mpu6050 0-0068: i2c driver removed +[65199.862200] mpu6050: i2c driver deleted +[65199.862204] mpu6050: module exited + + diff --git a/mpu6050/mpu6050-interrupt/logs/log_2 b/mpu6050/mpu6050-interrupt/logs/log_2 new file mode 100644 index 0000000..8c2593a --- /dev/null +++ b/mpu6050/mpu6050-interrupt/logs/log_2 @@ -0,0 +1,15 @@ +root@orangepione:/home/bekir# insmod ./mpu6050_interrupt.ko +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_x +-5776 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_y +-5840 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/accel_z +14896 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +24.260 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +24.308 +root@orangepione:/home/bekir# cat /sys/class/mpu6050/temp +24.276 +root@orangepione:/home/bekir# rmmod mpu6050_interrupt +root@orangepione:/home/bekir# diff --git a/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c b/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c new file mode 100644 index 0000000..4ebc60e --- /dev/null +++ b/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mpu6050-regs.h" + +struct mpu6050_data { + struct i2c_client *drv_client; + int accel_values[3]; + int gyro_values[3]; + int temperature; +}; + +static struct mpu6050_data g_mpu6050_data; + +static int mpu6050_read_data(int reg, int *value) +{ + struct i2c_client *drv_client = g_mpu6050_data.drv_client; + + if (drv_client == 0) + return -ENODEV; + + *value = (s16)((u16)i2c_smbus_read_word_swapped(drv_client, reg)); + + return 0; +} + +static irqreturn_t interrupt_handler(int irq, void *dev) +{ + return IRQ_WAKE_THREAD; +} + +static irqreturn_t interrupt_thread(int irq, void *dev_id) +{ + int temp; + + mpu6050_read_data(REG_ACCEL_XOUT_H, &g_mpu6050_data.accel_values[0]); + mpu6050_read_data(REG_ACCEL_YOUT_H, &g_mpu6050_data.accel_values[1]); + mpu6050_read_data(REG_ACCEL_ZOUT_H, &g_mpu6050_data.accel_values[2]); + mpu6050_read_data(REG_GYRO_XOUT_H, &g_mpu6050_data.gyro_values[0]); + mpu6050_read_data(REG_GYRO_YOUT_H, &g_mpu6050_data.gyro_values[1]); + mpu6050_read_data(REG_GYRO_ZOUT_H, &g_mpu6050_data.gyro_values[2]); + + mpu6050_read_data(REG_TEMP_OUT_H, &temp); + g_mpu6050_data.temperature = (temp + 12420); + + pr_info("irq %d was generated\n", ((struct i2c_client *)dev_id)->irq); + + return IRQ_HANDLED; +} + +static int mpu6050_probe(struct i2c_client *drv_client, + const struct i2c_device_id *id) +{ + int ret; + + dev_info(&drv_client->dev, + "i2c client address is 0x%X\n", drv_client->addr); + + /* Read who_am_i register */ + ret = i2c_smbus_read_byte_data(drv_client, REG_WHO_AM_I); + if (IS_ERR_VALUE(ret)) { + dev_err(&drv_client->dev, + "i2c_smbus_read_byte_data() failed with error: %d\n", + ret); + return ret; + } + if (ret != MPU6050_WHO_AM_I) { + dev_err(&drv_client->dev, + "wrong i2c device found: expected 0x%X, found 0x%X\n", + MPU6050_WHO_AM_I, ret); + return -1; + } + dev_info(&drv_client->dev, + "i2c mpu6050 device found, WHO_AM_I register value = 0x%X\n", + ret); + + /* Setup the device */ + /* No error handling here! */ + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0x80); + msleep(100); + i2c_smbus_write_byte_data(drv_client, REG_SMPRT_DIV, 0xFF); + i2c_smbus_write_byte_data(drv_client, REG_INT_PIN_CFG, 0x90); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_1, 0x20); + i2c_smbus_write_byte_data(drv_client, REG_PWR_MGMT_2, 0x40); + i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 1); + + g_mpu6050_data.drv_client = drv_client; + + if (request_threaded_irq(drv_client->irq, interrupt_handler, + interrupt_thread, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + "mpu6050", (void *)drv_client)) { + + dev_info(&drv_client->dev, "interrupt is not registered\n"); + return -EINVAL; + + } + dev_info(&drv_client->dev, "drv_client->irq = %d\n", drv_client->irq); + dev_info(&drv_client->dev, "i2c driver probed\n"); + + return 0; +} + +static int mpu6050_remove(struct i2c_client *drv_client) +{ + + free_irq(drv_client->irq, (void *)drv_client); + g_mpu6050_data.drv_client = 0; + + dev_info(&drv_client->dev, "i2c driver removed\n"); + return 0; +} + +static const struct i2c_device_id mpu6050_idtable[] = { + { "mpu6050", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mpu6050_idtable); + +static struct i2c_driver mpu6050_i2c_driver = { + .driver = { + .name = "gl,mpu6050", + }, + + .probe = mpu6050_probe, + .remove = mpu6050_remove, + .id_table = mpu6050_idtable, +}; + +static ssize_t accel_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); + return strlen(buf); +} + +static ssize_t accel_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); + return strlen(buf); +} + +static ssize_t accel_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); + return strlen(buf); +} + +static ssize_t gyro_x_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); + return strlen(buf); +} + +static ssize_t gyro_y_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); + return strlen(buf); +} + +static ssize_t gyro_z_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); + return strlen(buf); +} + +static ssize_t temp_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + sprintf(buf, "%i.%03i\n", g_mpu6050_data.temperature / 340, + g_mpu6050_data.temperature % 340); + return strlen(buf); +} + +CLASS_ATTR_RO(accel_x); +CLASS_ATTR_RO(accel_y); +CLASS_ATTR_RO(accel_z); +CLASS_ATTR_RO(gyro_x); +CLASS_ATTR_RO(gyro_y); +CLASS_ATTR_RO(gyro_z); +CLASS_ATTR_RO(temp); + +static struct class *attr_class; + +static int mpu6050_init(void) +{ + int ret; + + /* Create i2c driver */ + ret = i2c_add_driver(&mpu6050_i2c_driver); + if (ret) { + pr_err("mpu6050: failed to add new i2c driver: %d\n", ret); + return ret; + } + pr_info("mpu6050: i2c driver created\n"); + + /* Create class */ + attr_class = class_create(THIS_MODULE, "mpu6050"); + if (IS_ERR(attr_class)) { + ret = PTR_ERR(attr_class); + pr_err("mpu6050: failed to create sysfs class: %d\n", ret); + return ret; + } + pr_info("mpu6050: sysfs class created\n"); + + /* Create accel_x */ + ret = class_create_file(attr_class, &class_attr_accel_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_x:%d\n", + ret); + return ret; + } + /* Create accel_y */ + ret = class_create_file(attr_class, &class_attr_accel_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_y:%d\n", + ret); + return ret; + } + /* Create accel_z */ + ret = class_create_file(attr_class, &class_attr_accel_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute accel_z:%d\n", + ret); + return ret; + } + /* Create gyro_x */ + ret = class_create_file(attr_class, &class_attr_gyro_x); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_x:%d\n", + ret); + return ret; + } + /* Create gyro_y */ + ret = class_create_file(attr_class, &class_attr_gyro_y); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_y:%d\n", + ret); + return ret; + } + /* Create gyro_z */ + ret = class_create_file(attr_class, &class_attr_gyro_z); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute gyro_z:%d\n", + ret); + return ret; + } + /* Create temperature */ + ret = class_create_file(attr_class, &class_attr_temp); + if (ret) { + pr_err("mpu6050: failed to create sysfs class attribute temperature:%d\n", + ret); + return ret; + } + + pr_info("mpu6050: sysfs class attributes created\n"); + + pr_info("mpu6050: module loaded\n"); + return 0; +} + +static void mpu6050_exit(void) +{ + if (attr_class) { + class_remove_file(attr_class, &class_attr_accel_x); + class_remove_file(attr_class, &class_attr_accel_y); + class_remove_file(attr_class, &class_attr_accel_z); + class_remove_file(attr_class, &class_attr_gyro_x); + class_remove_file(attr_class, &class_attr_gyro_y); + class_remove_file(attr_class, &class_attr_gyro_z); + class_remove_file(attr_class, &class_attr_temp); + pr_info("mpu6050: sysfs class attributes removed\n"); + + class_destroy(attr_class); + pr_info("mpu6050: sysfs class destroyed\n"); + } + + i2c_del_driver(&mpu6050_i2c_driver); + pr_info("mpu6050: i2c driver deleted\n"); + + pr_info("mpu6050: module exited\n"); +} + +module_init(mpu6050_init); +module_exit(mpu6050_exit); + +MODULE_AUTHOR("Andriy.Khulap "); +MODULE_DESCRIPTION("mpu6050 I2C acc&gyro"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); From 426624e056fc64cdff46111f1e788ca8f2545949 Mon Sep 17 00:00:00 2001 From: Bekir Date: Thu, 26 Dec 2019 19:43:10 +0200 Subject: [PATCH 4/4] mpu6050-interrupt: Add synchronization to module Signed-off-by: Bekir --- mpu6050/mpu6050-interrupt/mpu6050.c | 24 +++++++++++++++++++ mpu6050/mpu6050-interrupt/mpu6050_interrupt.c | 20 ++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/mpu6050/mpu6050-interrupt/mpu6050.c b/mpu6050/mpu6050-interrupt/mpu6050.c index 4fdba88..b4c2a78 100644 --- a/mpu6050/mpu6050-interrupt/mpu6050.c +++ b/mpu6050/mpu6050-interrupt/mpu6050.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -23,6 +25,8 @@ struct mpu6050_data { struct i2c_client *drv_client; struct workqueue_struct *queue; struct work_struct work; + struct mutex mutex_sysfs; + struct spinlock spinlock_irq; int accel_values[3]; int gyro_values[3]; int temperature; @@ -44,7 +48,9 @@ static int mpu6050_read_data(int reg, int *value) static irqreturn_t interrupt_handler(int irq, void *dev) { + spin_lock(&g_mpu6050_data.spinlock_irq); queue_work(g_mpu6050_data.queue, &g_mpu6050_data.work); + spin_unlock(&g_mpu6050_data.spinlock_irq); return IRQ_HANDLED; } @@ -52,6 +58,7 @@ static void work_func(struct work_struct *work) { int temp; + mutex_lock(&g_mpu6050_data.mutex_sysfs); mpu6050_read_data(REG_ACCEL_XOUT_H, &g_mpu6050_data.accel_values[0]); mpu6050_read_data(REG_ACCEL_YOUT_H, &g_mpu6050_data.accel_values[1]); mpu6050_read_data(REG_ACCEL_ZOUT_H, &g_mpu6050_data.accel_values[2]); @@ -63,6 +70,7 @@ static void work_func(struct work_struct *work) g_mpu6050_data.temperature = (temp + 12420); pr_info("delay work is active\n"); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); } static int mpu6050_probe(struct i2c_client *drv_client, @@ -102,6 +110,8 @@ static int mpu6050_probe(struct i2c_client *drv_client, i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 1); g_mpu6050_data.drv_client = drv_client; + mutex_init(&g_mpu6050_data.mutex_sysfs); + spin_lock_init(&g_mpu6050_data.spinlock_irq); g_mpu6050_data.queue = create_singlethread_workqueue("mpu6050_work_queue"); INIT_WORK(&g_mpu6050_data.work, work_func); @@ -152,50 +162,64 @@ static struct i2c_driver mpu6050_i2c_driver = { static ssize_t accel_x_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t accel_y_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t accel_z_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_x_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_y_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_z_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t temp_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%i.%03i\n", g_mpu6050_data.temperature / 340, g_mpu6050_data.temperature % 340); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } diff --git a/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c b/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c index 4ebc60e..60d4203 100644 --- a/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c +++ b/mpu6050/mpu6050-interrupt/mpu6050_interrupt.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -20,6 +22,7 @@ struct mpu6050_data { struct i2c_client *drv_client; + struct mutex mutex_sysfs; int accel_values[3]; int gyro_values[3]; int temperature; @@ -48,6 +51,7 @@ static irqreturn_t interrupt_thread(int irq, void *dev_id) { int temp; + mutex_lock(&g_mpu6050_data.mutex_sysfs); mpu6050_read_data(REG_ACCEL_XOUT_H, &g_mpu6050_data.accel_values[0]); mpu6050_read_data(REG_ACCEL_YOUT_H, &g_mpu6050_data.accel_values[1]); mpu6050_read_data(REG_ACCEL_ZOUT_H, &g_mpu6050_data.accel_values[2]); @@ -59,6 +63,7 @@ static irqreturn_t interrupt_thread(int irq, void *dev_id) g_mpu6050_data.temperature = (temp + 12420); pr_info("irq %d was generated\n", ((struct i2c_client *)dev_id)->irq); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return IRQ_HANDLED; } @@ -100,6 +105,7 @@ static int mpu6050_probe(struct i2c_client *drv_client, i2c_smbus_write_byte_data(drv_client, REG_INT_ENABLE, 1); g_mpu6050_data.drv_client = drv_client; + mutex_init(&g_mpu6050_data.mutex_sysfs); if (request_threaded_irq(drv_client->irq, interrupt_handler, interrupt_thread, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, @@ -144,50 +150,64 @@ static struct i2c_driver mpu6050_i2c_driver = { static ssize_t accel_x_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[0]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t accel_y_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[1]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t accel_z_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.accel_values[2]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_x_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[0]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_y_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[1]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t gyro_z_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%d\n", g_mpu6050_data.gyro_values[2]); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); } static ssize_t temp_show(struct class *class, struct class_attribute *attr, char *buf) { + mutex_lock(&g_mpu6050_data.mutex_sysfs); sprintf(buf, "%i.%03i\n", g_mpu6050_data.temperature / 340, g_mpu6050_data.temperature % 340); + mutex_unlock(&g_mpu6050_data.mutex_sysfs); return strlen(buf); }