/* Date: 2011/3/7 11:00:00 * Revision: 2.11 */ /* * This software program is licensed subject to the GNU General Public License * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html * (C) Copyright 2011 Bosch Sensortec GmbH * All Rights Reserved */ /* file BMA150.c brief This file contains all function implementations for the BMA150 in linux */ #include #include #include #include #include #include #include #include #include #define SENSOR_NAME "bma150" #define GRAVITY_EARTH 9806550 #define ABSMIN_2G (-GRAVITY_EARTH * 2) #define ABSMAX_2G (GRAVITY_EARTH * 2) #define BMA150_MAX_DELAY 200 #define BMA150_CHIP_ID 2 #define BMA150_RANGE_SET 0 #define BMA150_BW_SET 4 #define BMA150_CHIP_ID_REG 0x00 #define BMA150_X_AXIS_LSB_REG 0x02 #define BMA150_X_AXIS_MSB_REG 0x03 #define BMA150_Y_AXIS_LSB_REG 0x04 #define BMA150_Y_AXIS_MSB_REG 0x05 #define BMA150_Z_AXIS_LSB_REG 0x06 #define BMA150_Z_AXIS_MSB_REG 0x07 #define BMA150_STATUS_REG 0x09 #define BMA150_CTRL_REG 0x0a #define BMA150_CONF1_REG 0x0b #define BMA150_CUSTOMER1_REG 0x12 #define BMA150_CUSTOMER2_REG 0x13 #define BMA150_RANGE_BWIDTH_REG 0x14 #define BMA150_CONF2_REG 0x15 #define BMA150_OFFS_GAIN_X_REG 0x16 #define BMA150_OFFS_GAIN_Y_REG 0x17 #define BMA150_OFFS_GAIN_Z_REG 0x18 #define BMA150_OFFS_GAIN_T_REG 0x19 #define BMA150_OFFSET_X_REG 0x1a #define BMA150_OFFSET_Y_REG 0x1b #define BMA150_OFFSET_Z_REG 0x1c #define BMA150_OFFSET_T_REG 0x1d #define BMA150_CHIP_ID__POS 0 #define BMA150_CHIP_ID__MSK 0x07 #define BMA150_CHIP_ID__LEN 3 #define BMA150_CHIP_ID__REG BMA150_CHIP_ID_REG /* DATA REGISTERS */ #define BMA150_NEW_DATA_X__POS 0 #define BMA150_NEW_DATA_X__LEN 1 #define BMA150_NEW_DATA_X__MSK 0x01 #define BMA150_NEW_DATA_X__REG BMA150_X_AXIS_LSB_REG #define BMA150_ACC_X_LSB__POS 6 #define BMA150_ACC_X_LSB__LEN 2 #define BMA150_ACC_X_LSB__MSK 0xC0 #define BMA150_ACC_X_LSB__REG BMA150_X_AXIS_LSB_REG #define BMA150_ACC_X_MSB__POS 0 #define BMA150_ACC_X_MSB__LEN 8 #define BMA150_ACC_X_MSB__MSK 0xFF #define BMA150_ACC_X_MSB__REG BMA150_X_AXIS_MSB_REG #define BMA150_ACC_Y_LSB__POS 6 #define BMA150_ACC_Y_LSB__LEN 2 #define BMA150_ACC_Y_LSB__MSK 0xC0 #define BMA150_ACC_Y_LSB__REG BMA150_Y_AXIS_LSB_REG #define BMA150_ACC_Y_MSB__POS 0 #define BMA150_ACC_Y_MSB__LEN 8 #define BMA150_ACC_Y_MSB__MSK 0xFF #define BMA150_ACC_Y_MSB__REG BMA150_Y_AXIS_MSB_REG #define BMA150_ACC_Z_LSB__POS 6 #define BMA150_ACC_Z_LSB__LEN 2 #define BMA150_ACC_Z_LSB__MSK 0xC0 #define BMA150_ACC_Z_LSB__REG BMA150_Z_AXIS_LSB_REG #define BMA150_ACC_Z_MSB__POS 0 #define BMA150_ACC_Z_MSB__LEN 8 #define BMA150_ACC_Z_MSB__MSK 0xFF #define BMA150_ACC_Z_MSB__REG BMA150_Z_AXIS_MSB_REG /* CONTROL BITS */ #define BMA150_SLEEP__POS 0 #define BMA150_SLEEP__LEN 1 #define BMA150_SLEEP__MSK 0x01 #define BMA150_SLEEP__REG BMA150_CTRL_REG #define BMA150_SOFT_RESET__POS 1 #define BMA150_SOFT_RESET__LEN 1 #define BMA150_SOFT_RESET__MSK 0x02 #define BMA150_SOFT_RESET__REG BMA150_CTRL_REG #define BMA150_EE_W__POS 4 #define BMA150_EE_W__LEN 1 #define BMA150_EE_W__MSK 0x10 #define BMA150_EE_W__REG BMA150_CTRL_REG #define BMA150_UPDATE_IMAGE__POS 5 #define BMA150_UPDATE_IMAGE__LEN 1 #define BMA150_UPDATE_IMAGE__MSK 0x20 #define BMA150_UPDATE_IMAGE__REG BMA150_CTRL_REG #define BMA150_RESET_INT__POS 6 #define BMA150_RESET_INT__LEN 1 #define BMA150_RESET_INT__MSK 0x40 #define BMA150_RESET_INT__REG BMA150_CTRL_REG /* BANDWIDTH dependend definitions */ #define BMA150_BANDWIDTH__POS 0 #define BMA150_BANDWIDTH__LEN 3 #define BMA150_BANDWIDTH__MSK 0x07 #define BMA150_BANDWIDTH__REG BMA150_RANGE_BWIDTH_REG /* RANGE */ #define BMA150_RANGE__POS 3 #define BMA150_RANGE__LEN 2 #define BMA150_RANGE__MSK 0x18 #define BMA150_RANGE__REG BMA150_RANGE_BWIDTH_REG /* WAKE UP */ #define BMA150_WAKE_UP__POS 0 #define BMA150_WAKE_UP__LEN 1 #define BMA150_WAKE_UP__MSK 0x01 #define BMA150_WAKE_UP__REG BMA150_CONF2_REG #define BMA150_WAKE_UP_PAUSE__POS 1 #define BMA150_WAKE_UP_PAUSE__LEN 2 #define BMA150_WAKE_UP_PAUSE__MSK 0x06 #define BMA150_WAKE_UP_PAUSE__REG BMA150_CONF2_REG #define BMA150_GET_BITSLICE(regvar, bitname)\ ((regvar & bitname##__MSK) >> bitname##__POS) #define BMA150_SET_BITSLICE(regvar, bitname, val)\ ((regvar & ~bitname##__MSK) | ((val<>1)); comres += bma150_smbus_write_byte(client, BMA150_WAKE_UP__REG, &data1); comres += bma150_smbus_write_byte(client, BMA150_SLEEP__REG, &data2); mutex_lock(&bma150->mode_mutex); bma150->mode = (unsigned char) Mode; mutex_unlock(&bma150->mode_mutex); } else{ comres = -1; } } return comres; } static int bma150_set_range(struct i2c_client *client, unsigned char Range) { int comres = 0; unsigned char data = 0; if (client == NULL) { comres = -1; } else{ if (Range < 3) { comres = bma150_smbus_read_byte(client, BMA150_RANGE__REG, &data); data = BMA150_SET_BITSLICE(data, BMA150_RANGE, Range); comres += bma150_smbus_write_byte(client, BMA150_RANGE__REG, &data); } else{ comres = -1; } } return comres; } static int bma150_get_range(struct i2c_client *client, unsigned char *Range) { int comres = 0; unsigned char data; if (client == NULL) { comres = -1; } else{ comres = bma150_smbus_read_byte(client, BMA150_RANGE__REG, &data); *Range = BMA150_GET_BITSLICE(data, BMA150_RANGE); } return comres; } static int bma150_set_bandwidth(struct i2c_client *client, unsigned char BW) { int comres = 0; unsigned char data = 0; if (client == NULL) { comres = -1; } else{ if (BW < 8) { comres = bma150_smbus_read_byte(client, BMA150_BANDWIDTH__REG, &data); data = BMA150_SET_BITSLICE(data, BMA150_BANDWIDTH, BW); comres += bma150_smbus_write_byte(client, BMA150_BANDWIDTH__REG, &data); } else{ comres = -1; } } return comres; } static int bma150_get_bandwidth(struct i2c_client *client, unsigned char *BW) { int comres = 0; unsigned char data; if (client == NULL) { comres = -1; } else{ comres = bma150_smbus_read_byte(client, BMA150_BANDWIDTH__REG, &data); *BW = BMA150_GET_BITSLICE(data, BMA150_BANDWIDTH); } return comres; } static int bma150_read_accel_xyz(struct i2c_client *client, struct bma150acc *acc) { int comres; unsigned char data[6]; if (client == NULL) { comres = -1; } else{ comres = bma150_smbus_read_byte_block(client, BMA150_ACC_X_LSB__REG, &data[0], 6); acc->x = BMA150_GET_BITSLICE(data[0], BMA150_ACC_X_LSB) | (BMA150_GET_BITSLICE(data[1], BMA150_ACC_X_MSB)<< BMA150_ACC_X_LSB__LEN); acc->x = acc->x << (sizeof(short)*8-(BMA150_ACC_X_LSB__LEN+ BMA150_ACC_X_MSB__LEN)); acc->x = acc->x >> (sizeof(short)*8-(BMA150_ACC_X_LSB__LEN+ BMA150_ACC_X_MSB__LEN)); acc->y = BMA150_GET_BITSLICE(data[2], BMA150_ACC_Y_LSB) | (BMA150_GET_BITSLICE(data[3], BMA150_ACC_Y_MSB)<< BMA150_ACC_Y_LSB__LEN); acc->y = acc->y << (sizeof(short)*8-(BMA150_ACC_Y_LSB__LEN + BMA150_ACC_Y_MSB__LEN)); acc->y = acc->y >> (sizeof(short)*8-(BMA150_ACC_Y_LSB__LEN + BMA150_ACC_Y_MSB__LEN)); acc->z = BMA150_GET_BITSLICE(data[4], BMA150_ACC_Z_LSB); acc->z |= (BMA150_GET_BITSLICE(data[5], BMA150_ACC_Z_MSB)<< BMA150_ACC_Z_LSB__LEN); acc->z = acc->z << (sizeof(short)*8-(BMA150_ACC_Z_LSB__LEN+ BMA150_ACC_Z_MSB__LEN)); acc->z = acc->z >> (sizeof(short)*8-(BMA150_ACC_Z_LSB__LEN+ BMA150_ACC_Z_MSB__LEN)); } return comres; } static void bma150_work_func(struct work_struct *work) { struct bma150_data *bma150 = container_of((struct delayed_work *)work, struct bma150_data, work); static struct bma150acc acc; unsigned long delay = msecs_to_jiffies(atomic_read(&bma150->delay)); bma150_read_accel_xyz(bma150->bma150_client, &acc); input_report_abs(bma150->input, ABS_X, acc.x); input_report_abs(bma150->input, ABS_Y, acc.y); input_report_abs(bma150->input, ABS_Z, acc.z); input_sync(bma150->input); mutex_lock(&bma150->value_mutex); bma150->value = acc; mutex_unlock(&bma150->value_mutex); schedule_delayed_work(&bma150->work, delay); } static ssize_t bma150_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); mutex_lock(&bma150->mode_mutex); data = bma150->mode; mutex_unlock(&bma150->mode_mutex); return sprintf(buf, "%d\n", data); } static ssize_t bma150_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (bma150_set_mode(bma150->bma150_client, (unsigned char) data) < 0) return -EINVAL; return count; } static ssize_t bma150_range_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); if (bma150_get_range(bma150->bma150_client, &data) < 0) return sprintf(buf, "Read error\n"); return sprintf(buf, "%d\n", data); } static ssize_t bma150_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (bma150_set_range(bma150->bma150_client, (unsigned char) data) < 0) return -EINVAL; return count; } static ssize_t bma150_bandwidth_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned char data; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); if (bma150_get_bandwidth(bma150->bma150_client, &data) < 0) return sprintf(buf, "Read error\n"); return sprintf(buf, "%d\n", data); } static ssize_t bma150_bandwidth_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (bma150_set_bandwidth(bma150->bma150_client, (unsigned char) data) < 0) return -EINVAL; return count; } static ssize_t bma150_value_show(struct device *dev, struct device_attribute *attr, char *buf) { struct input_dev *input = to_input_dev(dev); struct bma150_data *bma150 = input_get_drvdata(input); struct bma150acc acc_value; mutex_lock(&bma150->value_mutex); acc_value = bma150->value; mutex_unlock(&bma150->value_mutex); return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y, acc_value.z); } static ssize_t bma150_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); return sprintf(buf, "%d\n", atomic_read(&bma150->delay)); } static ssize_t bma150_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long data; int error; struct i2c_client *client = to_i2c_client(dev); struct bma150_data *bma150 = i2c_get_clientdata(client); error = strict_strtoul(buf, 10, &data); if (error) return error; if (data > BMA150_MAX_DELAY) data = BMA150_MAX_DELAY; atomic_set(&bma150->delay, (unsigned int) data); return count; } static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP, bma150_range_show, bma150_range_store); static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP, bma150_bandwidth_show, bma150_bandwidth_store); static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP, bma150_mode_show, bma150_mode_store); static DEVICE_ATTR(value, S_IRUGO|S_IWUSR|S_IWGRP, bma150_value_show, NULL); static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, bma150_delay_show, bma150_delay_store); static struct attribute *bma150_attributes[] = { &dev_attr_range.attr, &dev_attr_bandwidth.attr, &dev_attr_mode.attr, &dev_attr_value.attr, &dev_attr_delay.attr, NULL }; static struct attribute_group bma150_attribute_group = { .attrs = bma150_attributes }; static int bma150_detect(struct i2c_client *client, struct i2c_board_info *info) { struct i2c_adapter *adapter = client->adapter; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE); return 0; } static int bma150_input_init(struct bma150_data *bma150) { struct input_dev *dev; int err; dev = input_allocate_device(); if (!dev) return -ENOMEM; dev->name = SENSOR_NAME; dev->id.bustype = BUS_I2C; input_set_capability(dev, EV_ABS, ABS_MISC); input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0); input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0); input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0); input_set_drvdata(dev, bma150); err = input_register_device(dev); if (err < 0) { input_free_device(dev); return err; } bma150->input = dev; return 0; } static void bma150_input_delete(struct bma150_data *bma150) { struct input_dev *dev = bma150->input; input_unregister_device(dev); input_free_device(dev); } static int bma150_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; int tempvalue; struct bma150_data *data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { printk(KERN_INFO "i2c_check_functionality error\n"); goto exit; } data = kzalloc(sizeof(struct bma150_data), GFP_KERNEL); if (!data) { err = -ENOMEM; goto exit; } i2c_set_clientdata(client, data); data->platform_data = client->dev.platform_data; if (data->platform_data->power_on) data->platform_data->power_on(); else printk(KERN_ERR "power_on function not defined!!\n"); tempvalue = 0; tempvalue = i2c_smbus_read_word_data(client, BMA150_CHIP_ID_REG); if ((tempvalue&0x00FF) == BMA150_CHIP_ID) { printk(KERN_INFO "Bosch Sensortec Device detected!\n" \ "BMA150 registered I2C driver!\n"); } else{ printk(KERN_INFO "Bosch Sensortec Device not found" \ "i2c error %d\n", tempvalue); err = -1; goto kfree_exit; } i2c_set_clientdata(client, data); data->bma150_client = client; mutex_init(&data->value_mutex); mutex_init(&data->mode_mutex); bma150_set_bandwidth(client, BMA150_BW_SET); bma150_set_range(client, BMA150_RANGE_SET); INIT_DELAYED_WORK(&data->work, bma150_work_func); atomic_set(&data->delay, BMA150_MAX_DELAY); err = bma150_input_init(data); if (err < 0) goto kfree_exit; err = sysfs_create_group(&data->input->dev.kobj, &bma150_attribute_group); if (err < 0) goto error_sysfs; schedule_delayed_work(&data->work, msecs_to_jiffies(atomic_read(&data->delay))); return 0; error_sysfs: bma150_input_delete(data); kfree_exit: kfree(data); exit: return err; } static int bma150_suspend(struct i2c_client *client, pm_message_t mesg) { struct bma150_data *data = i2c_get_clientdata(client); cancel_delayed_work_sync(&data->work); bma150_set_mode(client, BMA150_MODE_SLEEP); if ((data->platform_data) && (data->platform_data->power_off)) data->platform_data->power_off(); return 0; } static int bma150_resume(struct i2c_client *client) { struct bma150_data *data = i2c_get_clientdata(client); if ((data->platform_data) && (data->platform_data->power_on)) data->platform_data->power_on(); bma150_set_mode(client, BMA150_MODE_NORMAL); schedule_delayed_work(&data->work, msecs_to_jiffies(atomic_read(&data->delay))); return 0; } static int bma150_remove(struct i2c_client *client) { struct bma150_data *data = i2c_get_clientdata(client); if (data->platform_data->power_off) data->platform_data->power_off(); else printk(KERN_ERR "power_off function not defined!!\n"); sysfs_remove_group(&data->input->dev.kobj, &bma150_attribute_group); bma150_input_delete(data); free_irq(data->IRQ, data); kfree(data); return 0; } static const struct i2c_device_id bma150_id[] = { { SENSOR_NAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, bma150_id); static struct i2c_driver bma150_driver = { .driver = { .owner = THIS_MODULE, .name = SENSOR_NAME, }, .class = I2C_CLASS_HWMON, .id_table = bma150_id, .probe = bma150_probe, .remove = bma150_remove, .detect = bma150_detect, .suspend = bma150_suspend, .resume = bma150_resume, }; static int __init BMA150_init(void) { return i2c_add_driver(&bma150_driver); } static void __exit BMA150_exit(void) { i2c_del_driver(&bma150_driver); } MODULE_DESCRIPTION("BMA150 driver"); module_init(BMA150_init); module_exit(BMA150_exit);