aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sensor/bmp180.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sensor/bmp180.c')
-rw-r--r--drivers/sensor/bmp180.c778
1 files changed, 778 insertions, 0 deletions
diff --git a/drivers/sensor/bmp180.c b/drivers/sensor/bmp180.c
new file mode 100644
index 0000000..21b5589
--- /dev/null
+++ b/drivers/sensor/bmp180.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sensor/sensors_core.h>
+
+#define BMP180_DRV_NAME "bmp180"
+#define DRIVER_VERSION "1.0"
+
+/* Register definitions */
+#define BMP180_TAKE_MEAS_REG 0xf4
+#define BMP180_READ_MEAS_REG_U 0xf6
+#define BMP180_READ_MEAS_REG_L 0xf7
+#define BMP180_READ_MEAS_REG_XL 0xf8
+
+/*
+ * Bytes defined by the spec to take measurements
+ * Temperature will take 4.5ms before EOC
+ */
+#define BMP180_MEAS_TEMP 0x2e
+/* 4.5ms wait for measurement */
+#define BMP180_MEAS_PRESS_OVERSAMP_0 0x34
+/* 7.5ms wait for measurement */
+#define BMP180_MEAS_PRESS_OVERSAMP_1 0x74
+/* 13.5ms wait for measurement */
+#define BMP180_MEAS_PRESS_OVERSAMP_2 0xb4
+/* 25.5ms wait for measurement */
+#define BMP180_MEAS_PRESS_OVERSAMP_3 0xf4
+
+/*
+ * EEPROM registers each is a two byte value so there is
+ * an upper byte and a lower byte
+ */
+#define BMP180_EEPROM_AC1_U 0xaa
+#define BMP180_EEPROM_AC1_L 0xab
+#define BMP180_EEPROM_AC2_U 0xac
+#define BMP180_EEPROM_AC2_L 0xad
+#define BMP180_EEPROM_AC3_U 0xae
+#define BMP180_EEPROM_AC3_L 0xaf
+#define BMP180_EEPROM_AC4_U 0xb0
+#define BMP180_EEPROM_AC4_L 0xb1
+#define BMP180_EEPROM_AC5_U 0xb2
+#define BMP180_EEPROM_AC5_L 0xb3
+#define BMP180_EEPROM_AC6_U 0xb4
+#define BMP180_EEPROM_AC6_L 0xb5
+#define BMP180_EEPROM_B1_U 0xb6
+#define BMP180_EEPROM_B1_L 0xb7
+#define BMP180_EEPROM_B2_U 0xb8
+#define BMP180_EEPROM_B2_L 0xb9
+#define BMP180_EEPROM_MB_U 0xba
+#define BMP180_EEPROM_MB_L 0xbb
+#define BMP180_EEPROM_MC_U 0xbc
+#define BMP180_EEPROM_MC_L 0xbd
+#define BMP180_EEPROM_MD_U 0xbe
+#define BMP180_EEPROM_MD_L 0xbf
+
+#define I2C_TRIES 5
+#define AUTO_INCREMENT 0x80
+
+#define DELAY_LOWBOUND (50 * NSEC_PER_MSEC)
+#define DELAY_UPBOUND (500 * NSEC_PER_MSEC)
+#define DELAY_DEFAULT (200 * NSEC_PER_MSEC)
+
+#define PRESSURE_MAX 125000
+#define PRESSURE_MIN 95000
+#define PRESSURE_FUZZ 5
+#define PRESSURE_FLAT 5
+
+#define FACTORY_TEST
+#ifdef FACTORY_TEST
+#define TEMP_MAX 3000
+#define TEMP_MIN -3000
+#define SEA_LEVEL_MAX 999999
+#define SEA_LEVEL_MIN -1
+#endif
+
+struct bmp180_eeprom_data {
+ s16 AC1, AC2, AC3;
+ u16 AC4, AC5, AC6;
+ s16 B1, B2;
+ s16 MB, MC, MD;
+};
+
+struct bmp180_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ struct workqueue_struct *wq;
+ struct work_struct work_pressure;
+ struct input_dev *input_dev;
+ struct hrtimer timer;
+#ifdef FACTORY_TEST
+ struct device *dev;
+#endif
+ ktime_t poll_delay;
+ u8 oversampling_rate;
+ struct bmp180_eeprom_data bmp180_eeprom_vals;
+ bool enabled;
+ bool on_before_suspend;
+};
+
+static int bmp180_i2c_read(struct i2c_client *client, u8 cmd,
+ u8 *buf, int len)
+{
+ int err;
+ int tries = 0;
+
+ do {
+ err = i2c_smbus_read_i2c_block_data(client, cmd, len, buf);
+ if (err == len)
+ return 0;
+ } while (++tries < I2C_TRIES);
+
+ return err;
+}
+
+static int bmp180_i2c_write(struct i2c_client *client, u8 cmd, u8 data)
+{
+ int err;
+ int tries = 0;
+
+ do {
+ err = i2c_smbus_write_byte_data(client, cmd, data);
+ if (!err)
+ return 0;
+ } while (++tries < I2C_TRIES);
+
+ return err;
+}
+
+static void bmp180_enable(struct bmp180_data *barom)
+{
+ pr_debug("%s: bmp180_enable\n", __func__);
+ if (!barom->enabled) {
+ barom->enabled = true;
+ pr_debug("%s: start timer\n", __func__);
+ hrtimer_start(&barom->timer, barom->poll_delay,
+ HRTIMER_MODE_REL);
+ }
+}
+
+static void bmp180_disable(struct bmp180_data *barom)
+{
+ pr_debug("%s: bmp180_disable\n", __func__);
+ if (barom->enabled) {
+ barom->enabled = false;
+ pr_debug("%s: stop timer\n", __func__);
+ hrtimer_cancel(&barom->timer);
+ cancel_work_sync(&barom->work_pressure);
+ }
+}
+
+static int bmp180_get_raw_temperature(struct bmp180_data *barom,
+ u16 *raw_temperature)
+{
+ int err;
+ u16 buf;
+
+ pr_debug("%s: read uncompensated temperature value\n", __func__);
+ err = bmp180_i2c_write(barom->client, BMP180_TAKE_MEAS_REG,
+ BMP180_MEAS_TEMP);
+ if (err) {
+ pr_err("%s: can't write BMP180_TAKE_MEAS_REG\n", __func__);
+ return err;
+ }
+
+ usleep_range(5000, 7000);
+
+ err = bmp180_i2c_read(barom->client, BMP180_READ_MEAS_REG_U,
+ (u8 *)&buf, 2);
+ if (err) {
+ pr_err("%s: Fail to read uncompensated temperature\n",
+ __func__);
+ return err;
+ }
+ *raw_temperature = be16_to_cpu(buf);
+ pr_debug("%s: uncompensated temperature: %d\n",
+ __func__, *raw_temperature);
+ return err;
+}
+
+static int bmp180_get_raw_pressure(struct bmp180_data *barom,
+ u32 *raw_pressure)
+{
+ int err;
+ u32 buf = 0;
+
+ pr_debug("%s: read uncompensated pressure value\n", __func__);
+
+ err = bmp180_i2c_write(barom->client, BMP180_TAKE_MEAS_REG,
+ BMP180_MEAS_PRESS_OVERSAMP_0 |
+ (barom->oversampling_rate << 6));
+ if (err) {
+ pr_err("%s: can't write BMP180_TAKE_MEAS_REG\n", __func__);
+ return err;
+ }
+
+ msleep(2+(3 << barom->oversampling_rate));
+
+ err = bmp180_i2c_read(barom->client, BMP180_READ_MEAS_REG_U,
+ ((u8 *)&buf)+1, 3);
+ if (err) {
+ pr_err("%s: Fail to read uncompensated pressure\n", __func__);
+ return err;
+ }
+
+ *raw_pressure = be32_to_cpu(buf);
+ *raw_pressure >>= (8 - barom->oversampling_rate);
+ pr_debug("%s: uncompensated pressure: %d\n",
+ __func__, *raw_pressure);
+
+ return err;
+}
+
+static void bmp180_get_pressure_data(struct work_struct *work)
+{
+ u16 raw_temperature;
+ u32 raw_pressure;
+ long x1, x2, x3, b3, b5, b6;
+ unsigned long b4, b7;
+ long p;
+ int pressure;
+
+ struct bmp180_data *barom =
+ container_of(work, struct bmp180_data, work_pressure);
+
+ if (bmp180_get_raw_temperature(barom, &raw_temperature)) {
+ pr_err("%s: can't read uncompensated temperature\n", __func__);
+ return;
+ }
+
+#ifdef FACTORY_TEST
+ x1 = ((raw_temperature - barom->bmp180_eeprom_vals.AC6)
+ * barom->bmp180_eeprom_vals.AC5) >> 15;
+ x2 = (barom->bmp180_eeprom_vals.MC << 11)
+ / (x1 + barom->bmp180_eeprom_vals.MD);
+ input_report_abs(barom->input_dev, ABS_MISC, (x1 + x2 + 8) >> 4);
+ input_sync(barom->input_dev);
+#endif
+
+ if (bmp180_get_raw_pressure(barom, &raw_pressure)) {
+ pr_err("%s: Fail to read uncompensated pressure\n", __func__);
+ return;
+ }
+
+ x1 = ((raw_temperature - barom->bmp180_eeprom_vals.AC6) *
+ barom->bmp180_eeprom_vals.AC5) >> 15;
+ x2 = (barom->bmp180_eeprom_vals.MC << 11) /
+ (x1 + barom->bmp180_eeprom_vals.MD);
+ b5 = x1 + x2;
+
+ b6 = (b5 - 4000);
+ x1 = (barom->bmp180_eeprom_vals.B2 * ((b6 * b6) >> 12)) >> 11;
+ x2 = (barom->bmp180_eeprom_vals.AC2 * b6) >> 11;
+ x3 = x1 + x2;
+ b3 = (((((long)barom->bmp180_eeprom_vals.AC1) * 4 +
+ x3) << barom->oversampling_rate) + 2) >> 2;
+ x1 = (barom->bmp180_eeprom_vals.AC3 * b6) >> 13;
+ x2 = (barom->bmp180_eeprom_vals.B1 * (b6 * b6 >> 12)) >> 16;
+ x3 = ((x1 + x2) + 2) >> 2;
+ b4 = (barom->bmp180_eeprom_vals.AC4 *
+ (unsigned long)(x3 + 32768)) >> 15;
+ b7 = ((unsigned long)raw_pressure - b3) *
+ (50000 >> barom->oversampling_rate);
+ if (b7 < 0x80000000)
+ p = (b7 * 2) / b4;
+ else
+ p = (b7 / b4) * 2;
+
+ x1 = (p >> 8) * (p >> 8);
+ x1 = (x1 * 3038) >> 16;
+ x2 = (-7357 * p) >> 16;
+ pressure = p + ((x1 + x2 + 3791) >> 4);
+ pr_debug("%s: calibrated pressure: %d\n",
+ __func__, pressure);
+
+ input_report_abs(barom->input_dev, ABS_PRESSURE, pressure);
+ input_sync(barom->input_dev);
+
+ return;
+}
+
+static int bmp180_input_init(struct bmp180_data *barom)
+{
+ int err;
+
+ pr_debug("%s: enter\n", __func__);
+ barom->input_dev = input_allocate_device();
+ if (!barom->input_dev) {
+ pr_err("%s: could not allocate input device\n", __func__);
+ return -ENOMEM;
+ }
+ input_set_drvdata(barom->input_dev, barom);
+ barom->input_dev->name = "barometer_sensor";
+ input_set_capability(barom->input_dev, EV_ABS, ABS_PRESSURE);
+
+ /* Need to define the correct min and max */
+ input_set_abs_params(barom->input_dev, ABS_PRESSURE,
+ PRESSURE_MIN, PRESSURE_MAX,
+ PRESSURE_FUZZ, PRESSURE_FLAT);
+
+#ifdef FACTORY_TEST
+ input_set_capability(barom->input_dev, EV_ABS, ABS_VOLUME);
+ input_set_capability(barom->input_dev, EV_ABS, ABS_MISC);
+ input_set_abs_params(barom->input_dev, ABS_VOLUME,
+ SEA_LEVEL_MIN, SEA_LEVEL_MAX, 0, 0);
+ input_set_abs_params(barom->input_dev, ABS_MISC,
+ TEMP_MIN, TEMP_MAX, 0, 0);
+#endif
+
+ pr_debug("%s: registering barometer input device\n", __func__);
+
+ err = input_register_device(barom->input_dev);
+ if (err) {
+ pr_err("%s: unable to register input polled device %s\n",
+ __func__, barom->input_dev->name);
+ goto err_register_device;
+ }
+
+ goto done;
+
+err_register_device:
+ input_free_device(barom->input_dev);
+done:
+ return err;
+}
+
+static void bmp180_input_cleanup(struct bmp180_data *barom)
+{
+ input_unregister_device(barom->input_dev);
+ input_free_device(barom->input_dev);
+}
+
+static int bmp180_read_store_eeprom_val(struct bmp180_data *barom)
+{
+ int err;
+ u16 buf[11];
+
+ err = bmp180_i2c_read(barom->client, BMP180_EEPROM_AC1_U,
+ (u8 *)buf, 22);
+ if (err) {
+ pr_err("%s: Cannot read EEPROM values\n", __func__);
+ return err;
+ }
+ barom->bmp180_eeprom_vals.AC1 = be16_to_cpu(buf[0]);
+ barom->bmp180_eeprom_vals.AC2 = be16_to_cpu(buf[1]);
+ barom->bmp180_eeprom_vals.AC3 = be16_to_cpu(buf[2]);
+ barom->bmp180_eeprom_vals.AC4 = be16_to_cpu(buf[3]);
+ barom->bmp180_eeprom_vals.AC5 = be16_to_cpu(buf[4]);
+ barom->bmp180_eeprom_vals.AC6 = be16_to_cpu(buf[5]);
+ barom->bmp180_eeprom_vals.B1 = be16_to_cpu(buf[6]);
+ barom->bmp180_eeprom_vals.B2 = be16_to_cpu(buf[7]);
+ barom->bmp180_eeprom_vals.MB = be16_to_cpu(buf[8]);
+ barom->bmp180_eeprom_vals.MC = be16_to_cpu(buf[9]);
+ barom->bmp180_eeprom_vals.MD = be16_to_cpu(buf[10]);
+ return 0;
+}
+
+static enum hrtimer_restart bmp180_timer_func(struct hrtimer *timer)
+{
+ struct bmp180_data *barom = container_of(timer,
+ struct bmp180_data, timer);
+
+ pr_debug("%s: start\n", __func__);
+ queue_work(barom->wq, &barom->work_pressure);
+ hrtimer_forward_now(&barom->timer, barom->poll_delay);
+ return HRTIMER_RESTART;
+}
+
+static ssize_t bmp180_poll_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld\n",
+ ktime_to_ns(barom->poll_delay));
+}
+
+static ssize_t bmp180_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int err;
+ int64_t new_delay;
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ err = strict_strtoll(buf, 10, &new_delay);
+ if (err < 0)
+ return err;
+
+ pr_debug("%s: new delay = %lldns, old delay = %lldns\n",
+ __func__, new_delay, ktime_to_ns(barom->poll_delay));
+
+ if (new_delay < DELAY_LOWBOUND || new_delay > DELAY_UPBOUND)
+ return -EINVAL;
+
+ mutex_lock(&barom->lock);
+ if (new_delay != ktime_to_ns(barom->poll_delay))
+ barom->poll_delay = ns_to_ktime(new_delay);
+
+ mutex_unlock(&barom->lock);
+
+ return size;
+}
+
+static ssize_t bmp180_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", barom->enabled);
+}
+
+static ssize_t bmp180_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ bool new_value;
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ pr_debug("%s: enable %s\n", __func__, buf);
+
+ if (sysfs_streq(buf, "1")) {
+ new_value = true;
+ } else if (sysfs_streq(buf, "0")) {
+ new_value = false;
+ } else {
+ pr_err("%s: invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: new_value = %d, old state = %d\n",
+ __func__, new_value, barom->enabled);
+
+ mutex_lock(&barom->lock);
+ if (new_value)
+ bmp180_enable(barom);
+ else
+ bmp180_disable(barom);
+
+ mutex_unlock(&barom->lock);
+
+ return size;
+}
+
+static ssize_t bmp180_oversampling_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", barom->oversampling_rate);
+}
+
+static ssize_t bmp180_oversampling_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+
+ unsigned long oversampling;
+ int success = strict_strtoul(buf, 10, &oversampling);
+ if (success == 0) {
+ if (oversampling > 3)
+ oversampling = 3;
+ barom->oversampling_rate = oversampling;
+ return count;
+ }
+ return success;
+}
+
+static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
+ bmp180_poll_delay_show, bmp180_poll_delay_store);
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
+ bmp180_enable_show, bmp180_enable_store);
+
+static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
+ bmp180_oversampling_show, bmp180_oversampling_store);
+
+static struct attribute *bmp180_sysfs_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+ &dev_attr_oversampling.attr,
+ NULL
+};
+
+static struct attribute_group bmp180_attribute_group = {
+ .attrs = bmp180_sysfs_attrs,
+};
+
+#ifdef FACTORY_TEST
+static ssize_t eeprom_check_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+ int val = -1;
+
+ if (barom->bmp180_eeprom_vals.AC1 == 0 ||
+ barom->bmp180_eeprom_vals.AC1 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.AC2 == 0 ||
+ barom->bmp180_eeprom_vals.AC2 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.AC3 == 0 ||
+ barom->bmp180_eeprom_vals.AC3 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.AC4 == 0 ||
+ barom->bmp180_eeprom_vals.AC4 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.AC5 == 0 ||
+ barom->bmp180_eeprom_vals.AC5 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.AC6 == 0 ||
+ barom->bmp180_eeprom_vals.AC6 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.B1 == 0 ||
+ barom->bmp180_eeprom_vals.B1 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.B2 == 0 ||
+ barom->bmp180_eeprom_vals.B2 == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.MB == 0 ||
+ barom->bmp180_eeprom_vals.MB == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.MC == 0 ||
+ barom->bmp180_eeprom_vals.MC == 0xFFFF)
+ goto done;
+ if (barom->bmp180_eeprom_vals.MC == 0 ||
+ barom->bmp180_eeprom_vals.MD == 0xFFFF)
+ goto done;
+
+ val = 1;
+
+done:
+ return sprintf(buf, "%d", val);
+}
+
+static ssize_t sea_level_pressure_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct bmp180_data *barom = dev_get_drvdata(dev);
+ int new_sea_level_pressure;
+
+ sscanf(buf, "%d", &new_sea_level_pressure);
+
+ input_report_abs(barom->input_dev, ABS_VOLUME, new_sea_level_pressure);
+ input_sync(barom->input_dev);
+
+ return size;
+}
+
+static DEVICE_ATTR(eeprom_check, S_IRUSR | S_IRGRP | S_IWGRP,
+ eeprom_check_show, NULL);
+
+static DEVICE_ATTR(sea_level_pressure, S_IRUGO | S_IWUSR | S_IWGRP,
+ NULL, sea_level_pressure_store);
+#endif
+
+static int __devinit bmp180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct bmp180_data *barom;
+
+ pr_debug("%s: enter\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("%s: client not i2c capable\n", __func__);
+ return -EIO;
+ }
+
+ barom = kzalloc(sizeof(*barom), GFP_KERNEL);
+ if (!barom) {
+ pr_err("%s: failed to allocate memory for module\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&barom->lock);
+ barom->client = client;
+
+ i2c_set_clientdata(client, barom);
+
+ err = bmp180_read_store_eeprom_val(barom);
+ if (err) {
+ pr_err("%s: Reading the EEPROM failed\n", __func__);
+ err = -ENODEV;
+ goto err_read_eeprom;
+ }
+
+ hrtimer_init(&barom->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ barom->poll_delay = ns_to_ktime(DELAY_DEFAULT);
+ barom->timer.function = bmp180_timer_func;
+
+ barom->wq = create_singlethread_workqueue("bmp180_wq");
+ if (!barom->wq) {
+ err = -ENOMEM;
+ pr_err("%s: could not create workqueue\n", __func__);
+ goto err_create_workqueue;
+ }
+
+ INIT_WORK(&barom->work_pressure, bmp180_get_pressure_data);
+
+ err = bmp180_input_init(barom);
+ if (err) {
+ pr_err("%s: could not create input device\n", __func__);
+ goto err_input_init;
+ }
+ err = sysfs_create_group(&barom->input_dev->dev.kobj,
+ &bmp180_attribute_group);
+ if (err) {
+ pr_err("%s: could not create sysfs group\n", __func__);
+ goto err_sysfs_create_group;
+ }
+
+#ifdef FACTORY_TEST
+ /* sysfs for factory test */
+ barom->dev = sensors_classdev_register("barometer_sensor");
+ if (IS_ERR(barom->dev)) {
+ err = PTR_ERR(barom->dev);
+ pr_err("%s: device_create failed[%d]\n", __func__, err);
+ goto err_device_create;
+ }
+
+ err = device_create_file(barom->dev, &dev_attr_sea_level_pressure);
+ if (err < 0) {
+ pr_err("%s: device_create_fil(sea_level_pressure) failed\n",
+ __func__);
+ goto err_device_create_file1;
+ }
+
+ err = device_create_file(barom->dev, &dev_attr_eeprom_check);
+ if (err < 0) {
+ pr_err("%s: device_create_file(eeprom_check) failed\n",
+ __func__);
+ goto err_device_create_file2;
+ }
+
+ dev_set_drvdata(barom->dev, barom);
+#endif
+ goto done;
+
+#ifdef FACTORY_TEST
+err_device_create_file2:
+ device_remove_file(barom->dev, &dev_attr_sea_level_pressure);
+err_device_create_file1:
+ sensors_classdev_unregister(barom->dev);
+err_device_create:
+ sysfs_remove_group(&barom->input_dev->dev.kobj,
+ &bmp180_attribute_group);
+#endif
+
+err_sysfs_create_group:
+ bmp180_input_cleanup(barom);
+err_input_init:
+ destroy_workqueue(barom->wq);
+err_create_workqueue:
+err_read_eeprom:
+ mutex_destroy(&barom->lock);
+ kfree(barom);
+done:
+ return err;
+}
+
+static int __devexit bmp180_remove(struct i2c_client *client)
+{
+ /* TO DO: revisit ordering here once _probe order is finalized */
+ struct bmp180_data *barom = i2c_get_clientdata(client);
+
+ pr_debug("%s: bmp180_remove +\n", __func__);
+ device_remove_file(barom->dev, &dev_attr_sea_level_pressure);
+ sensors_classdev_unregister(barom->dev);
+ sysfs_remove_group(&barom->input_dev->dev.kobj,
+ &bmp180_attribute_group);
+
+ bmp180_disable(barom);
+
+ bmp180_input_cleanup(barom);
+
+ destroy_workqueue(barom->wq);
+
+ mutex_destroy(&barom->lock);
+ kfree(barom);
+
+ pr_debug("%s: bmp180_remove -\n", __func__);
+ return 0;
+}
+
+static int bmp180_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bmp180_data *barom = i2c_get_clientdata(client);
+ pr_debug("%s: on_before_suspend %d\n",
+ __func__, barom->on_before_suspend);
+
+ if (barom->on_before_suspend)
+ bmp180_enable(barom);
+ return 0;
+}
+
+static int bmp180_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct bmp180_data *barom = i2c_get_clientdata(client);
+
+ barom->on_before_suspend = barom->enabled;
+ pr_debug("%s: on_before_suspend %d\n",
+ __func__, barom->on_before_suspend);
+ bmp180_disable(barom);
+ return 0;
+}
+
+static const struct i2c_device_id bmp180_id[] = {
+ {BMP180_DRV_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, bmp180_id);
+static const struct dev_pm_ops bmp180_pm_ops = {
+ .suspend = bmp180_suspend,
+ .resume = bmp180_resume,
+};
+
+static struct i2c_driver bmp180_driver = {
+ .driver = {
+ .name = BMP180_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &bmp180_pm_ops,
+ },
+ .probe = bmp180_probe,
+ .remove = __devexit_p(bmp180_remove),
+ .id_table = bmp180_id,
+};
+
+static int __init bmp180_init(void)
+{
+ pr_debug("%s: _init\n", __func__);
+ return i2c_add_driver(&bmp180_driver);
+}
+
+static void __exit bmp180_exit(void)
+{
+ pr_debug("%s: _exit +\n", __func__);
+ i2c_del_driver(&bmp180_driver);
+ pr_debug("%s: _exit -\n", __func__);
+ return;
+}
+
+MODULE_AUTHOR("Hyoung Wook Ham <hwham@sta.samsung.com>");
+MODULE_DESCRIPTION("BMP180 Pressure sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(bmp180_init);
+module_exit(bmp180_exit);