Skip to content

Commit

Permalink
mpu6050: Add driver functionality
Browse files Browse the repository at this point in the history
This mpu6050 driver functionality consist of reading relevant values and
exporting them to the user space. Needed parameters are: accelerometer x,
y, z, gyroscope x, y, z and temperature (as an easiest check that device
is configured and operating properly).

First, the chip must be configured. This consist of programming all setup
registers with correct values. For example: clear power down, set prescalers,
configures fifos and so on.
Configuration is usually done in driver probe routine.

Second, reading values or performing needed actions can be done in a separate
theread inside driver, or in the workqueue. But this driver is supposed to
give values on demand so there is no need for that. All values are read at
once in a single function.

To export data to the user space was decided to use sysfs.
A class was created and 7 attributes for each parameter. Since all
parameters are read-only, all attributes have only show function and
their access rights are set to 0444.
So all _show() fuctions are almost the same: read all parameters first,
then return the needed one.

The summary how this driver works:
1. Create i2c device in module_init() and configure the chip from i2c_probe().
2. Create sysfs class and attributes for each parameter from module_init().
3. Read and return mpu6050 parameters in each sysfs_attribute_x_show().

Signed-off-by: Andriy.Khulap <[email protected]>
  • Loading branch information
an1kh committed Nov 9, 2017
1 parent 83e27dd commit 9a63b4c
Showing 1 changed file with 204 additions and 0 deletions.
204 changes: 204 additions & 0 deletions mpu6050/mpu6050.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,53 @@

#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)
{
Expand All @@ -33,12 +80,28 @@ static int mpu6050_probe(struct i2c_client *drv_client,
"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;
}
Expand All @@ -59,6 +122,79 @@ static struct i2c_driver mpu6050_i2c_driver = {
.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;
Expand All @@ -71,12 +207,80 @@ static int mpu6050_init(void)
}
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");

Expand Down

0 comments on commit 9a63b4c

Please sign in to comment.