Advertisement
GeeckoDev

ms5xxx 1.0

Jul 8th, 2014
206
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.40 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.     struct mutex adc_lock;
  52.     u8 prom_valid;
  53.     u16 prom[MS5611_PROM_COUNT];
  54.     u32 d1, d2;
  55.     s32 dt, temp, pres;
  56.     unsigned long last_updated_d1;
  57.     unsigned long last_updated_d2;
  58. };
  59.  
  60. /* Send command */
  61. static struct ms5xxx_data *ms5xxx_cmd(struct device *dev, u8 cmd)
  62. {
  63.     struct i2c_client *client = to_i2c_client(dev);
  64.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  65.  
  66.     mutex_lock(&data->update_lock);
  67.  
  68.     i2c_smbus_write_byte(client, cmd);
  69.  
  70.     mutex_unlock(&data->update_lock);
  71.  
  72.     return data;
  73. }
  74.  
  75. /* Read calibration data */
  76. static struct ms5xxx_data *ms5xxx_read_prom(struct device *dev)
  77. {
  78.     struct i2c_client *client = to_i2c_client(dev);
  79.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  80.     u8 bytes[MS5611_PROM_SIZE];
  81.     u8 i;
  82.  
  83.     mutex_lock(&data->update_lock);
  84.  
  85.     for (i = 0; i < MS5611_PROM_COUNT; i++) {
  86.         u8 cmd = MS5611_PROM_ADDR + i * MS5611_PROM_SIZE;
  87.         i2c_smbus_read_i2c_block_data(client, cmd, MS5611_PROM_SIZE, bytes);
  88.         data->prom[i] = (bytes[0] << 8) | bytes[1];
  89.     }
  90.  
  91.     mutex_unlock(&data->update_lock);
  92.  
  93.     return data;
  94. }
  95.  
  96. /* Validate calibration data */
  97. static struct ms5xxx_data *ms5xxx_validate_prom(struct device *dev)
  98. {
  99.     struct i2c_client *client = to_i2c_client(dev);
  100.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  101.     u16 reminder = 0;
  102.     u16 backup = data->prom[7];
  103.     u8 i, k;
  104.  
  105.     data->prom[7] = 0xFF00 & data->prom[7];
  106.  
  107.     for (i = 0; i < 2 * MS5611_PROM_COUNT; i++) {
  108.         if (i % 2 == 1) {
  109.             reminder ^= data->prom[i >> 1] & 0x00FF;
  110.         } else {
  111.             reminder ^= data->prom[i >> 1] >> 8;
  112.         }
  113.  
  114.         for (k = 8; k > 0; k--) {
  115.             if (reminder & 0x8000) {
  116.                 reminder = (reminder << 1) ^ 0x3000;
  117.             } else {
  118.                 reminder = reminder << 1;
  119.             }
  120.         }
  121.     }
  122.  
  123.     reminder = 0x000F & (reminder >> 12);
  124.     data->prom[7] = backup;
  125.     data->prom_valid = (reminder == (data->prom[7] & 0x000F));
  126.  
  127.     return data;
  128. }
  129.  
  130. /* Read sensor data */
  131. static struct ms5xxx_data *ms5xxx_read_adc(struct device *dev, char n)
  132. {
  133.     struct i2c_client *client = to_i2c_client(dev);
  134.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  135.     u8 bytes[3];
  136.  
  137.     mutex_lock(&data->update_lock);
  138.  
  139.     i2c_smbus_read_i2c_block_data(client, MS5611_CMD_ADC_READ, 3, bytes);
  140.     if (n == 0)
  141.         data->d1 = (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
  142.     else
  143.         data->d2 = (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
  144.  
  145.     mutex_unlock(&data->update_lock);
  146.  
  147.     return data;
  148. }
  149.  
  150. /* Update pressure data */
  151. static struct ms5xxx_data *ms5xxx_update_pres(struct device *dev)
  152. {
  153.     struct i2c_client *client = to_i2c_client(dev);
  154.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  155.     s64 off, sens;
  156.  
  157.     if (time_after(jiffies, data->last_updated_d1 + HZ / 2)) {
  158.         /* Read D1 */
  159.         mutex_lock(&data->adc_lock);
  160.         ms5xxx_cmd(dev, MS5611_CMD_D1 | MS561101BA_OSR);
  161.         msleep(10);
  162.         ms5xxx_read_adc(dev, 0);
  163.         mutex_unlock(&data->adc_lock);
  164.  
  165.         /* Calculate pressure */
  166.         off = ((s64)data->prom[2] << 16) + (((s64)data->prom[4] * (s64)data->dt) >> 7);
  167.         sens = ((s64)data->prom[1] << 15) + (((s64)data->prom[3] * (s64)data->dt) >> 8);
  168.  
  169.         if (data->temp < 2000) {
  170.             s32 k = 5 * (data->temp - 2000) * (data->temp - 2000);
  171.  
  172.             off -= k >> 1;
  173.             sens -= k >> 2;
  174.  
  175.             if (data->temp < -1500) {
  176.                 s32 n = (data->temp + 1500) * (data->temp + 1500);
  177.  
  178.                 off -= 7 * n;
  179.                 sens -= (11 * n) >> 1;
  180.             }
  181.         }
  182.  
  183.         data->pres = (((((int64_t)data->d1 * sens) >> 21) - off) * 10) >> 15;
  184.  
  185.         data->last_updated_d1 = jiffies;
  186.     }
  187.  
  188.     return data;
  189. }
  190.  
  191. /* Update temperature data */
  192. static struct ms5xxx_data *ms5xxx_update_temp(struct device *dev)
  193. {
  194.     struct i2c_client *client = to_i2c_client(dev);
  195.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  196.  
  197.     if (time_after(jiffies, data->last_updated_d2 + HZ / 2)) {
  198.         /* Read D2 */
  199.         mutex_lock(&data->adc_lock);
  200.         ms5xxx_cmd(dev, MS5611_CMD_D2 | MS561101BA_OSR);
  201.         msleep(10);
  202.         ms5xxx_read_adc(dev, 1);
  203.         mutex_unlock(&data->adc_lock);
  204.  
  205.         /* Calculate temperature */
  206.         data->dt = (s32)data->d2 - ((s32)data->prom[5] << 8);
  207.         data->temp = 2000 + (((s64)data->dt * (s64)data->prom[6]) >> 23);
  208.  
  209.         if (data->temp < 2000) {
  210.             data->temp -= ((s64)data->dt * (s64)data->dt) >> 31;
  211.         }
  212.  
  213.         data->last_updated_d2 = jiffies;
  214.     }
  215.  
  216.     return data;
  217. }
  218.  
  219. static ssize_t show_prom(struct device *dev, struct device_attribute *da,
  220.     char *buf)
  221. {
  222.     struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  223.     struct i2c_client *client = to_i2c_client(dev);
  224.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  225.  
  226.     return sprintf(buf, "%d\n", data->prom[attr->index]);
  227. }
  228.  
  229. static ssize_t show_prom_valid(struct device *dev, struct device_attribute *da,
  230.     char *buf)
  231. {
  232.     struct i2c_client *client = to_i2c_client(dev);
  233.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  234.  
  235.     return sprintf(buf, "%d\n", data->prom_valid);
  236. }
  237.  
  238. static ssize_t show_pres(struct device *dev, struct device_attribute *da,
  239.     char *buf)
  240. {
  241.     struct ms5xxx_data *data = ms5xxx_update_temp(dev);
  242.  
  243.     ms5xxx_update_pres(dev);
  244.  
  245.     return sprintf(buf, "%d\n", data->pres);
  246. }
  247.  
  248. static ssize_t show_temp(struct device *dev, struct device_attribute *da,
  249.     char *buf)
  250. {
  251.     struct ms5xxx_data *data = ms5xxx_update_temp(dev);
  252.  
  253.     return sprintf(buf, "%d\n", data->temp);
  254. }
  255.  
  256. static SENSOR_DEVICE_ATTR(prom0, S_IRUGO, show_prom, NULL, 0);
  257. static SENSOR_DEVICE_ATTR(prom1, S_IRUGO, show_prom, NULL, 1);
  258. static SENSOR_DEVICE_ATTR(prom2, S_IRUGO, show_prom, NULL, 2);
  259. static SENSOR_DEVICE_ATTR(prom3, S_IRUGO, show_prom, NULL, 3);
  260. static SENSOR_DEVICE_ATTR(prom4, S_IRUGO, show_prom, NULL, 4);
  261. static SENSOR_DEVICE_ATTR(prom5, S_IRUGO, show_prom, NULL, 5);
  262. static SENSOR_DEVICE_ATTR(prom6, S_IRUGO, show_prom, NULL, 6);
  263. static SENSOR_DEVICE_ATTR(prom7, S_IRUGO, show_prom, NULL, 7);
  264. static SENSOR_DEVICE_ATTR(prom_valid, S_IRUGO, show_prom_valid, NULL, 0);
  265. static SENSOR_DEVICE_ATTR(pres, S_IRUGO, show_pres, NULL, 0);
  266. static SENSOR_DEVICE_ATTR(temp, S_IRUGO, show_temp, NULL, 0);
  267.  
  268. static struct attribute *ms5xxx_attributes[] = {
  269.     &sensor_dev_attr_prom0.dev_attr.attr,
  270.     &sensor_dev_attr_prom1.dev_attr.attr,
  271.     &sensor_dev_attr_prom2.dev_attr.attr,
  272.     &sensor_dev_attr_prom3.dev_attr.attr,
  273.     &sensor_dev_attr_prom4.dev_attr.attr,
  274.     &sensor_dev_attr_prom5.dev_attr.attr,
  275.     &sensor_dev_attr_prom6.dev_attr.attr,
  276.     &sensor_dev_attr_prom7.dev_attr.attr,
  277.     &sensor_dev_attr_prom_valid.dev_attr.attr,
  278.     &sensor_dev_attr_pres.dev_attr.attr,
  279.     &sensor_dev_attr_temp.dev_attr.attr,
  280.     NULL
  281. };
  282.  
  283. static const struct attribute_group ms5xxx_group = {
  284.     .attrs = ms5xxx_attributes,
  285. };
  286.  
  287.  
  288. static int ms5xxx_probe(struct i2c_client *client,
  289.             const struct i2c_device_id *id)
  290. {
  291.     struct ms5xxx_data *data;
  292.     int err;
  293.  
  294.     data = kzalloc(sizeof(struct ms5xxx_data), GFP_KERNEL);
  295.     if (!data) {
  296.         err = -ENOMEM;
  297.         goto exit;
  298.     }
  299.  
  300.     i2c_set_clientdata(client, data);
  301.     mutex_init(&data->update_lock);
  302.     mutex_init(&data->adc_lock);
  303.  
  304.     /* Register sysfs hooks */
  305.     err = sysfs_create_group(&client->dev.kobj, &ms5xxx_group);
  306.     if (err)
  307.         goto exit_free;
  308.  
  309.     data->hwmon_dev = hwmon_device_register(&client->dev);
  310.     if (IS_ERR(data->hwmon_dev)) {
  311.         err = PTR_ERR(data->hwmon_dev);
  312.         goto exit_remove;
  313.     }
  314.  
  315.     ms5xxx_cmd(&client->dev, MS5611_CMD_RESET);
  316.     msleep(5);
  317.     ms5xxx_read_prom(&client->dev);
  318.     ms5xxx_validate_prom(&client->dev);
  319.  
  320.     return 0;
  321.  
  322. exit_remove:
  323.     sysfs_remove_group(&client->dev.kobj, &ms5xxx_group);
  324. exit_free:
  325.     kfree(data);
  326. exit:
  327.     return err;
  328. }
  329.  
  330. static int ms5xxx_remove(struct i2c_client *client)
  331. {
  332.     struct ms5xxx_data *data = i2c_get_clientdata(client);
  333.  
  334.     hwmon_device_unregister(data->hwmon_dev);
  335.     sysfs_remove_group(&client->dev.kobj, &ms5xxx_group);
  336.     kfree(data);
  337.  
  338.     return 0;
  339. }
  340.  
  341. static const struct i2c_device_id ms5xxx_id[] = {
  342.     { "ms5611", ms5611 },
  343.     { }
  344. };
  345. MODULE_DEVICE_TABLE(i2c, ms5xxx_id);
  346.  
  347. static struct i2c_driver ms5xxx_driver = {
  348.     .driver = {
  349.         .name   = "ms5xxx",
  350.     },
  351.     .probe      = ms5xxx_probe,
  352.     .remove     = ms5xxx_remove,
  353.     .id_table   = ms5xxx_id,
  354. };
  355.  
  356. module_i2c_driver(ms5xxx_driver);
  357.  
  358. MODULE_AUTHOR("Clément Guérin <clement.guerin@ciblenetworks.fr>");
  359. MODULE_DESCRIPTION("ms5xxx driver");
  360. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement