Advertisement
GeeckoDev

ms5xxx kernel driver

Jul 8th, 2014
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.51 KB | None | 0 0
  1. /*
  2.  * Driver for AMSYS MS5611 barometer sensor chips
  3.  *
  4.  * MS5611:
  5.  * High Precision Pressure Sensor Module with I2C Interface
  6.  * Datasheet: http://www.amsys-sensor.com/products/ms5611.htm
  7.  *
  8.  * Copyright (C) 2014 Clément Guérin <clement.guerin@ciblenetworks.fr>
  9.  * Copyright (C) 2012-2013 Olaf Lüke <olaf@tinkerforge.com>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; version 2 of the License.
  14.  */
  15.  
  16. #include <linux/module.h>
  17. #include <linux/init.h>
  18. #include <linux/slab.h>
  19. #include <linux/jiffies.h>
  20. #include <linux/i2c.h>
  21. #include <linux/hwmon.h>
  22. #include <linux/hwmon-sysfs.h>
  23. #include <linux/err.h>
  24. #include <linux/mutex.h>
  25. #include <linux/delay.h>
  26.  
  27. /* Command definitions */
  28. #define MS5611_CMD_RESET        0x1E
  29. #define MS5611_CMD_D1           0x40
  30. #define MS5611_CMD_D2           0x50
  31. #define MS5611_CMD_ADC_READ     0x00
  32.  
  33. /* Over Sampling Ratio definitions */
  34. #define MS561101BA_OSR_256      0x00
  35. #define MS561101BA_OSR_512      0x02
  36. #define MS561101BA_OSR_1024     0x04
  37. #define MS561101BA_OSR_2048     0x06
  38. #define MS561101BA_OSR_4096     0x08
  39. #define MS561101BA_OSR          MS561101BA_OSR_4096
  40.  
  41. /* PROM definitions */
  42. #define MS5611_PROM_ADDR        0xA0
  43. #define MS5611_PROM_COUNT       8
  44. #define MS5611_PROM_SIZE        2
  45.  
  46. enum ms5xxx_ids { ms5611 };
  47.  
  48. struct ms5xxx_data {
  49.     struct device *hwmon_dev;
  50.     struct mutex update_lock;
  51.     u16 prom[MS5611_PROM_COUNT];
  52.     u8 prom_valid;
  53.     u32 last_adc;
  54. };
  55.  
  56. /* Send command */
  57. static struct ms5xxx_data *ms5xxx_cmd(struct device *dev, u8 cmd)
  58. {
  59.     struct i2c_client *client = to_i2c_client(dev);
  60.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  61.  
  62.     mutex_lock(&data->update_lock);
  63.  
  64.     i2c_smbus_write_byte(client, cmd);
  65.  
  66.     mutex_unlock(&data->update_lock);
  67.  
  68.     return data;
  69. }
  70.  
  71. /* Read calibration data */
  72. static struct ms5xxx_data *ms5xxx_read_prom(struct device *dev)
  73. {
  74.     struct i2c_client *client = to_i2c_client(dev);
  75.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  76.     u8 bytes[MS5611_PROM_SIZE];
  77.     u8 i;
  78.  
  79.     mutex_lock(&data->update_lock);
  80.  
  81.     for (i = 0; i < MS5611_PROM_COUNT; i++) {
  82.         u8 cmd = MS5611_PROM_ADDR + i * MS5611_PROM_SIZE;
  83.         i2c_smbus_read_i2c_block_data(client, cmd, MS5611_PROM_SIZE, bytes);
  84.         data->prom[i] = (bytes[0] << 8) | bytes[1];
  85.     }
  86.  
  87.     mutex_unlock(&data->update_lock);
  88.  
  89.     return data;
  90. }
  91.  
  92. /* Validate calibration data */
  93. static struct ms5xxx_data *ms5xxx_validate_prom(struct device *dev)
  94. {
  95.     struct i2c_client *client = to_i2c_client(dev);
  96.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  97.     u16 reminder = 0;
  98.     u16 backup = data->prom[7];
  99.     u8 i, k;
  100.  
  101.     data->prom[7] = 0xFF00 & data->prom[7];
  102.  
  103.     for (i = 0; i < 2 * MS5611_PROM_COUNT; i++) {
  104.         if (i % 2 == 1) {
  105.             reminder ^= data->prom[i >> 1] & 0x00FF;
  106.         } else {
  107.             reminder ^= data->prom[i >> 1] >> 8;
  108.         }
  109.  
  110.         for (k = 8; k > 0; k--) {
  111.             if (reminder & 0x8000) {
  112.                 reminder = (reminder << 1) ^ 0x3000;
  113.             } else {
  114.                 reminder = reminder << 1;
  115.             }
  116.         }
  117.     }
  118.  
  119.     reminder = 0x000F & (reminder >> 12);
  120.     data->prom[7] = backup;
  121.     data->prom_valid = (reminder == (data->prom[7] & 0x000F));
  122.  
  123.     return data;
  124. }
  125.  
  126. /* Read sensor data */
  127. static struct ms5xxx_data *ms5xxx_read_adc(struct device *dev)
  128. {
  129.     struct i2c_client *client = to_i2c_client(dev);
  130.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  131.     u8 bytes[3];
  132.  
  133.     mutex_lock(&data->update_lock);
  134.  
  135.     i2c_smbus_read_i2c_block_data(client, MS5611_CMD_ADC_READ, 3, bytes);
  136.     data->last_adc = (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
  137.  
  138.     mutex_unlock(&data->update_lock);
  139.  
  140.     return data;
  141. }
  142.  
  143. static ssize_t show_prom(struct device *dev, struct device_attribute *da,
  144.     char *buf)
  145. {
  146.     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  147.     struct i2c_client *client = to_i2c_client(dev);
  148.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  149.  
  150.     return sprintf(buf, "%d\n", data->prom[attr->index]);
  151. }
  152.  
  153. static ssize_t show_prom_valid(struct device *dev, struct device_attribute *da,
  154.     char *buf)
  155. {
  156.     struct i2c_client *client = to_i2c_client(dev);
  157.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  158.  
  159.     return sprintf(buf, "%d\n", data->prom_valid);
  160. }
  161.  
  162. static ssize_t show_raw_pres(struct device *dev, struct device_attribute *da,
  163.     char *buf)
  164. {
  165.     struct i2c_client *client = to_i2c_client(dev);
  166.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  167.  
  168.     ms5xxx_cmd(dev, MS5611_CMD_D1 | MS561101BA_OSR);
  169.     msleep(10);
  170.     ms5xxx_read_adc(dev);
  171.  
  172.     return sprintf(buf, "%d\n", data->last_adc);
  173. }
  174.  
  175. static ssize_t show_raw_temp(struct device *dev, struct device_attribute *da,
  176.     char *buf)
  177. {
  178.     struct i2c_client *client = to_i2c_client(dev);
  179.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  180.     s32 dt, temp;
  181.  
  182.     ms5xxx_cmd(dev, MS5611_CMD_D2 | MS561101BA_OSR);
  183.     msleep(10);
  184.     ms5xxx_read_adc(dev);
  185.  
  186.     dt = (s32)data->last_adc - ((s32)data->prom[5] << 8);
  187.     temp = 2000 + (((s64)dt * (s64)data->prom[6]) >> 23);
  188.  
  189.     return sprintf(buf, "%d\n", temp);
  190. }
  191.  
  192. static SENSOR_DEVICE_ATTR(prom0, S_IRUGO, show_prom, NULL, 0);
  193. static SENSOR_DEVICE_ATTR(prom1, S_IRUGO, show_prom, NULL, 1);
  194. static SENSOR_DEVICE_ATTR(prom2, S_IRUGO, show_prom, NULL, 2);
  195. static SENSOR_DEVICE_ATTR(prom3, S_IRUGO, show_prom, NULL, 3);
  196. static SENSOR_DEVICE_ATTR(prom4, S_IRUGO, show_prom, NULL, 4);
  197. static SENSOR_DEVICE_ATTR(prom5, S_IRUGO, show_prom, NULL, 5);
  198. static SENSOR_DEVICE_ATTR(prom6, S_IRUGO, show_prom, NULL, 6);
  199. static SENSOR_DEVICE_ATTR(prom7, S_IRUGO, show_prom, NULL, 7);
  200. static SENSOR_DEVICE_ATTR(prom_valid, S_IRUGO, show_prom_valid, NULL, 0);
  201. static SENSOR_DEVICE_ATTR(raw_pres, S_IRUGO, show_raw_pres, NULL, 0);
  202. static SENSOR_DEVICE_ATTR(temp, S_IRUGO, show_raw_temp, NULL, 0);
  203.  
  204. static struct attribute *ms5xxx_attributes[] = {
  205.     &sensor_dev_attr_prom0.dev_attr.attr,
  206.     &sensor_dev_attr_prom1.dev_attr.attr,
  207.     &sensor_dev_attr_prom2.dev_attr.attr,
  208.     &sensor_dev_attr_prom3.dev_attr.attr,
  209.     &sensor_dev_attr_prom4.dev_attr.attr,
  210.     &sensor_dev_attr_prom5.dev_attr.attr,
  211.     &sensor_dev_attr_prom6.dev_attr.attr,
  212.     &sensor_dev_attr_prom7.dev_attr.attr,
  213.     &sensor_dev_attr_prom_valid.dev_attr.attr,
  214.     &sensor_dev_attr_raw_pres.dev_attr.attr,
  215.     &sensor_dev_attr_temp.dev_attr.attr,
  216.     NULL
  217. };
  218.  
  219. static const struct attribute_group ms5xxx_group = {
  220.     .attrs = ms5xxx_attributes,
  221. };
  222.  
  223.  
  224. static int ms5xxx_probe(struct i2c_client *client,
  225.             const struct i2c_device_id *id)
  226. {
  227.     struct ms5xxx_data *data;
  228.     int err;
  229.  
  230.     data = kzalloc(sizeof(struct ms5xxx_data), GFP_KERNEL);
  231.     if (!data) {
  232.         err = -ENOMEM;
  233.         goto exit;
  234.     }
  235.  
  236.     i2c_set_clientdata(client, data);
  237.     mutex_init(&data->update_lock);
  238.  
  239.     /* Register sysfs hooks */
  240.     err = sysfs_create_group(&client->dev.kobj, &ms5xxx_group);
  241.     if (err)
  242.         goto exit_free;
  243.  
  244.     data->hwmon_dev = hwmon_device_register(&client->dev);
  245.     if (IS_ERR(data->hwmon_dev)) {
  246.         err = PTR_ERR(data->hwmon_dev);
  247.         goto exit_remove;
  248.     }
  249.  
  250.     ms5xxx_cmd(&client->dev, MS5611_CMD_RESET);
  251.     msleep(5);
  252.     ms5xxx_read_prom(&client->dev);
  253.     ms5xxx_validate_prom(&client->dev);
  254.  
  255.     return 0;
  256.  
  257. exit_remove:
  258.     sysfs_remove_group(&client->dev.kobj, &ms5xxx_group);
  259. exit_free:
  260.     kfree(data);
  261. exit:
  262.     return err;
  263. }
  264.  
  265. static const struct i2c_device_id ms5xxx_id[] = {
  266.     { "ms5611", ms5611 },
  267.     { }
  268. };
  269. MODULE_DEVICE_TABLE(i2c, ms5xxx_id);
  270.  
  271. static struct i2c_driver ms5xxx_driver = {
  272.     .driver = {
  273.         .name   = "ms5xxx",
  274.     },
  275.     .probe      = ms5xxx_probe,
  276.     .id_table   = ms5xxx_id,
  277. };
  278.  
  279. module_i2c_driver(ms5xxx_driver);
  280.  
  281. MODULE_AUTHOR("Clément Guérin <clement.guerin@ciblenetworks.fr>");
  282. MODULE_DESCRIPTION("ms5xxx driver");
  283. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement