diff options
author | guoyin.chen <guoyin.chen@freescale.com> | 2013-06-18 18:25:32 +0800 |
---|---|---|
committer | guoyin.chen <guoyin.chen@freescale.com> | 2013-06-26 17:14:15 +0800 |
commit | 42dac4e485bb620ac7f57544e347820599024388 (patch) | |
tree | 67b7db0b3edbaeb5bc8fc63b30b729bc7b25f9b1 | |
parent | 0f2d6ad7875b8cf1efc2d1f41b865ec5251770f1 (diff) |
ENGR00268599-1 Integrate Fsl_Sensor_Android_v4.0 update for sensor driver
Update sensor driver from Fsl_Sensor_Android_v4.0 release
Signed-off-by: guoyin.chen <guoyin.chen@freescale.com>
-rwxr-xr-x | drivers/hwmon/Kconfig | 16 | ||||
-rwxr-xr-x | drivers/hwmon/Makefile | 3 | ||||
-rwxr-xr-x | drivers/hwmon/mag3110.c | 481 | ||||
-rw-r--r-- | drivers/hwmon/mma8x5x.c | 561 | ||||
-rw-r--r-- | drivers/hwmon/mxc_mma8450.c | 392 | ||||
-rw-r--r-- | drivers/hwmon/mxc_mma8451.c | 521 |
6 files changed, 837 insertions, 1137 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b42baef3dcd0..3fdc73765c9f 100755 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1419,14 +1419,12 @@ config SENSORS_MAG3110 This driver can also be built as a module. If so, the module will be called mag3110. -config MXC_MMA8450 - tristate "MMA8450 device driver" - depends on I2C - default y - -config MXC_MMA8451 - tristate "MMA8451 device driver" - depends on I2C - default y +config SENSORS_MMA8X5X + tristate "MMA8451/MMA8452/MMA8453/MMA8652/MMA8653 device driver" + depends on I2C && SYSFS + default n + help + If you say yes here you get support for the Freescale + MMA8451/MMA8452/MMA8453/MMA8652/MMA8653 sensors. endif # HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index fc6e6b43a287..71e7a24ef8db 100755 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -120,8 +120,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o -obj-$(CONFIG_MXC_MMA8450) += mxc_mma8450.o -obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o +obj-$(CONFIG_SENSORS_MMA8X5X) += mma8x5x.o obj-$(CONFIG_SENSORS_DA9052) += da9052-adc.o obj-$(CONFIG_SENSORS_IMX_AHCI) += imx_ahci_hwmon.o diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c index f17212553355..67681e2a25d1 100755 --- a/drivers/hwmon/mag3110.c +++ b/drivers/hwmon/mag3110.c @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,21 +31,26 @@ #include <linux/wait.h> #include <linux/workqueue.h> +#define ABS_STATUS ABS_WHEEL + #define MAG3110_DRV_NAME "mag3110" -#define MAG3110_ID 0xC4 -#define MAG3110_XYZ_DATA_LEN 6 -#define MAG3110_STATUS_ZYXDR 0x08 +#define MAG3110_ID 0xC4 +#define MAG3110_XYZ_DATA_LEN 6 +#define MAG3110_STATUS_ZYXDR 0x08 #define MAG3110_AC_MASK (0x01) #define MAG3110_AC_OFFSET 0 #define MAG3110_DR_MODE_MASK (0x7 << 5) #define MAG3110_DR_MODE_OFFSET 5 -#define MAG3110_IRQ_USED 1 +#define MAG3110_IRQ_USED 1 + +#define POLL_INTERVAL_MAX 500 +#define POLL_INTERVAL_MIN 1 +#define POLL_INTERVAL 100 +/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */ +#define POLL_STOP_TIME 200 -#define POLL_INTERVAL_MIN 100 -#define POLL_INTERVAL_MAX 1000 -#define POLL_INTERVAL 500 -#define INT_TIMEOUT 1000 +#define INT_TIMEOUT 1000 /* register enum for mag3110 registers */ enum { MAG3110_DR_STATUS = 0x00, @@ -73,57 +78,61 @@ enum { MAG_STANDBY, MAG_ACTIVED }; +struct mag3110_data_axis { + short x; + short y; + short z; +}; + struct mag3110_data { struct i2c_client *client; struct input_polled_dev *poll_dev; - struct device *hwmon_dev; + /* mag3110 calibrated data report input dev */ + struct input_dev *cal_input; + struct mutex data_lock; wait_queue_head_t waitq; bool data_ready; u8 ctl_reg1; int active; int position; }; -static short MAGHAL[8][3][3] = { - {{ 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, - {{ 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} }, - {{ 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} }, - {{-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} }, +static short mag3110_position_setting[8][3][3] = { + { { 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, -1 } }, + { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 } }, + { { 0, 1, 0 }, { -1, 0, 0 }, { 0, 0, -1 } }, + { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } }, - {{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} }, - {{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} }, - {{ 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, - {{-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} }, + { { 0, -1, 0 }, { -1, 0, 0 }, { 0, 0, 1 } }, + { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }, + { { 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 } }, + { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } }, }; -static struct mag3110_data *mag3110_pdata; /*! * This function do one mag3110 register read. */ -static DEFINE_MUTEX(mag3110_lock); -static int mag3110_adjust_position(short *x, short *y, short *z) +static int mag3110_data_convert(int position, + struct mag3110_data_axis *axis_data) { short rawdata[3], data[3]; int i, j; - int position = mag3110_pdata->position; + if (position < 0 || position > 7) position = 0; - - rawdata[0] = *x; - rawdata[1] = *y; - rawdata[2] = *z; - + rawdata[0] = axis_data->x; + rawdata[1] = axis_data->y; + rawdata[2] = axis_data->z; for (i = 0; i < 3; i++) { data[i] = 0; for (j = 0; j < 3; j++) - data[i] += rawdata[j] * MAGHAL[position][i][j]; + data[i] += rawdata[j] * mag3110_position_setting[position][i][j]; } - *x = data[0]; - *y = data[1]; - *z = data[2]; + axis_data->x = data[0]; + axis_data->y = data[1]; + axis_data->z = data[2]; return 0; } - static int mag3110_read_reg(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -146,10 +155,10 @@ static int mag3110_write_reg(struct i2c_client *client, u8 reg, char value) * This function do multiple mag3110 registers read. */ static int mag3110_read_block_data(struct i2c_client *client, u8 reg, - int count, u8 *addr) + int count, u8 *addr) { if (i2c_smbus_read_i2c_block_data - (client, reg, count, addr) < count) { + (client, reg, count, addr) < count) { dev_err(&client->dev, "i2c block read failed\n"); return -1; } @@ -177,157 +186,198 @@ static int mag3110_init_client(struct i2c_client *client) } /*************************************************************** - * - * read sensor data from mag3110 - * - ***************************************************************/ -static int mag3110_read_data(short *x, short *y, short *z) +* +* read sensor data from mag3110 +* +***************************************************************/ +static int mag3110_read_data(struct i2c_client *client, + struct mag3110_data_axis *pdata) { - struct mag3110_data *data; + struct mag3110_data *mag = i2c_get_clientdata(client); u8 tmp_data[MAG3110_XYZ_DATA_LEN]; -#if !MAG3110_IRQ_USED - int retry = 3; - int result; -#endif - if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) + if (!mag || mag->active == MAG_STANDBY) return -EINVAL; - - data = mag3110_pdata; #if MAG3110_IRQ_USED if (!wait_event_interruptible_timeout - (data->waitq, data->data_ready != 0, - msecs_to_jiffies(INT_TIMEOUT))) { - dev_dbg(&data->client->dev, "interrupt not received\n"); + (mag->waitq, mag->data_ready != 0, + msecs_to_jiffies(INT_TIMEOUT))) { + dev_dbg(&mag->client->dev, "interrupt not received\n"); return -ETIME; } -#else - do { - msleep(1); - result = i2c_smbus_read_byte_data(data->client, - MAG3110_DR_STATUS); - retry--; - } while (!(result & MAG3110_STATUS_ZYXDR) && retry > 0); - /* Clear data_ready flag after data is read out */ - if (retry == 0) { - printk(KERN_DEBUG "magd wait data ready timeout....\n"); - return -EINVAL; - } #endif - - data->data_ready = 0; - - if (mag3110_read_block_data(data->client, - MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, tmp_data) < 0) + mag->data_ready = 0; + if (mag3110_read_block_data(client, + MAG3110_OUT_X_MSB, + MAG3110_XYZ_DATA_LEN, tmp_data) < 0) return -1; - - *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; - *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; - *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + pdata->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + pdata->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + pdata->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; return 0; } -static void report_abs(void) +static void mag3110_report_data(struct mag3110_data *mag) { - struct input_dev *idev; - short x, y, z; - mutex_lock(&mag3110_lock); - if (mag3110_read_data(&x, &y, &z) != 0) + struct input_polled_dev *poll_dev = mag->poll_dev; + struct input_dev *idev = poll_dev->input; + struct mag3110_data_axis data; + + mutex_lock(&mag->data_lock); + if (mag3110_read_data(mag->client, &data) != 0) { + poll_dev->poll_interval = POLL_STOP_TIME; goto out; - mag3110_adjust_position(&x, &y, &z); - idev = mag3110_pdata->poll_dev->input; - input_report_abs(idev, ABS_X, x); - input_report_abs(idev, ABS_Y, y); - input_report_abs(idev, ABS_Z, z); + } else if (poll_dev->poll_interval == POLL_STOP_TIME) + poll_dev->poll_interval = POLL_INTERVAL; + mag3110_data_convert(mag->position, &data); + idev = mag->poll_dev->input; + input_report_abs(idev, ABS_X, data.x); + input_report_abs(idev, ABS_Y, data.y); + input_report_abs(idev, ABS_Z, data.z); input_sync(idev); out: - mutex_unlock(&mag3110_lock); + mutex_unlock(&mag->data_lock); } static void mag3110_dev_poll(struct input_polled_dev *dev) { - report_abs(); + struct mag3110_data * mag = (struct mag3110_data *)dev->private; + + mag3110_report_data(mag); } #if MAG3110_IRQ_USED -static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) +static irqreturn_t mag3110_irq_handler(int irq, void *dev) { - mag3110_pdata->data_ready = 1; - wake_up_interruptible(&mag3110_pdata->waitq); + struct mag3110_data *mag = (struct mag3110_data *)dev; + + mag->data_ready = 1; + wake_up_interruptible(&mag->waitq); return IRQ_HANDLED; } #endif +static int mag3110_reigister_caldata_input(struct mag3110_data *mag) +{ + struct input_dev *idev; + struct i2c_client *client = mag->client; + int ret; + + idev = input_allocate_device(); + if (!idev) { + dev_err(&client->dev, "alloc calibrated data device error\n"); + return -EINVAL; + } + idev->name = "eCompass"; + idev->id.bustype = BUS_I2C; + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0); + input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0); + input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0); + input_set_abs_params(idev, ABS_RX, 0, 36000, 0, 0); + input_set_abs_params(idev, ABS_RY, -18000, 18000, 0, 0); + input_set_abs_params(idev, ABS_RZ, -9000, 9000, 0, 0); + input_set_abs_params(idev, ABS_STATUS, 0, 3, 0, 0); + ret = input_register_device(idev); + if (ret) { + dev_err(&client->dev, "register poll device failed!\n"); + return -EINVAL; + } + mag->cal_input = idev; + return 0; +} +static int mag3110_unreigister_caldata_input(struct mag3110_data *mag) +{ + struct input_dev *idev = mag->cal_input; + + if (idev) { + input_unregister_device(idev); + input_free_device(idev); + } + mag->cal_input = NULL; + return 0; +} static ssize_t mag3110_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { - struct i2c_client *client; + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); + struct i2c_client *client = mag->client; int val; - mutex_lock(&mag3110_lock); - client = mag3110_pdata->client; - val = mag3110_read_reg(client, MAG3110_CTRL_REG1) & MAG3110_AC_MASK; - mutex_unlock(&mag3110_lock); + mutex_lock(&mag->data_lock); + val = mag3110_read_reg(client, MAG3110_CTRL_REG1); + val &= MAG3110_AC_MASK; + mutex_unlock(&mag->data_lock); return sprintf(buf, "%d\n", val); } static ssize_t mag3110_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - struct i2c_client *client; + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); + struct i2c_client *client = mag->client; int reg, ret, enable; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; enable = simple_strtoul(buf, NULL, 10); - mutex_lock(&mag3110_lock); - client = mag3110_pdata->client; + mutex_lock(&mag->data_lock); + client = mag->client; reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); - if (enable && mag3110_pdata->active == MAG_STANDBY) { + if (enable && mag->active == MAG_STANDBY) { reg |= MAG3110_AC_MASK; ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); if (!ret) - mag3110_pdata->active = MAG_ACTIVED; - } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) { + mag->active = MAG_ACTIVED; + printk(KERN_INFO"mag3110 set active\n"); + } else if (!enable && mag->active == MAG_ACTIVED) { reg &= ~MAG3110_AC_MASK; ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); if (!ret) - mag3110_pdata->active = MAG_STANDBY; + mag->active = MAG_STANDBY; + printk(KERN_INFO"mag3110 set inactive\n"); + } - if (mag3110_pdata->active == MAG_ACTIVED) { + if (mag->active == MAG_ACTIVED) { msleep(100); /* Read out MSB data to clear interrupt flag automatically */ mag3110_read_block_data(client, MAG3110_OUT_X_MSB, - MAG3110_XYZ_DATA_LEN, tmp_data); + MAG3110_XYZ_DATA_LEN, tmp_data); } - mutex_unlock(&mag3110_lock); + mutex_unlock(&mag->data_lock); return count; } static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, - mag3110_enable_show, mag3110_enable_store); + mag3110_enable_show, mag3110_enable_store); static ssize_t mag3110_dr_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { - struct i2c_client *client; + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); + struct i2c_client *client = mag->client; int val; - client = mag3110_pdata->client; + client = mag->client; val = (mag3110_read_reg(client, MAG3110_CTRL_REG1) - & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET; + & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET; return sprintf(buf, "%d\n", val); } static ssize_t mag3110_dr_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - struct i2c_client *client ; + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); + struct i2c_client *client = mag->client; int reg, ret; unsigned long val; @@ -335,9 +385,9 @@ static ssize_t mag3110_dr_mode_store(struct device *dev, if ((strict_strtoul(buf, 10, &val) < 0) || (val > 7)) return -EINVAL; - client = mag3110_pdata->client; + client = mag->client; reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) & - ~MAG3110_DR_MODE_MASK; + ~MAG3110_DR_MODE_MASK; reg |= (val << MAG3110_DR_MODE_OFFSET); /* MAG3110_CTRL_REG1 bit 5-7: data rate mode */ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); @@ -348,32 +398,36 @@ static ssize_t mag3110_dr_mode_store(struct device *dev, } static DEVICE_ATTR(dr_mode, S_IWUSR | S_IRUGO, - mag3110_dr_mode_show, mag3110_dr_mode_store); + mag3110_dr_mode_show, mag3110_dr_mode_store); static ssize_t mag3110_position_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); int val; - mutex_lock(&mag3110_lock); - val = mag3110_pdata->position; - mutex_unlock(&mag3110_lock); + + mutex_lock(&mag->data_lock); + val = mag->position; + mutex_unlock(&mag->data_lock); return sprintf(buf, "%d\n", val); } - static ssize_t mag3110_position_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mag3110_data *mag = (struct mag3110_data *)(poll_dev->private); int position; + position = simple_strtoul(buf, NULL, 10); - mutex_lock(&mag3110_lock); - mag3110_pdata->position = position; - mutex_unlock(&mag3110_lock); + mutex_lock(&mag->data_lock); + mag->position = position; + mutex_unlock(&mag->data_lock); return count; } - static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, - mag3110_position_show, mag3110_position_store); + mag3110_position_show, mag3110_position_store); static struct attribute *mag3110_attributes[] = { &dev_attr_enable.attr, @@ -383,22 +437,22 @@ static struct attribute *mag3110_attributes[] = { }; static const struct attribute_group mag3110_attr_group = { - .attrs = mag3110_attributes, + .attrs = mag3110_attributes, }; static int __devinit mag3110_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct i2c_adapter *adapter; struct input_dev *idev; - struct mag3110_data *data; + struct mag3110_data *mag; int ret = 0; adapter = to_i2c_adapter(client->dev.parent); if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; dev_info(&client->dev, "check mag3110 chip ID\n"); @@ -406,106 +460,104 @@ static int __devinit mag3110_probe(struct i2c_client *client, if (MAG3110_ID != ret) { dev_err(&client->dev, - "read chip ID 0x%x is not equal to 0x%x!\n", - ret, MAG3110_ID); + "read chip ID 0x%x is not equal to 0x%x!\n", ret, + MAG3110_ID); return -EINVAL; } - data = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL); - if (!data) + mag = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL); + if (!mag) return -ENOMEM; - data->client = client; - i2c_set_clientdata(client, data); + mag->client = client; + mag->active = MAG_STANDBY; + mag->position = *(int *)client->dev.platform_data; + mutex_init(&mag->data_lock); + i2c_set_clientdata(client, mag); /* Init queue */ - init_waitqueue_head(&data->waitq); - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - dev_err(&client->dev, "hwmon register failed!\n"); - ret = PTR_ERR(data->hwmon_dev); - goto error_rm_dev_sysfs; - } + init_waitqueue_head(&mag->waitq); /*input poll device register */ - data->poll_dev = input_allocate_polled_device(); - if (!data->poll_dev) { + mag->poll_dev = input_allocate_polled_device(); + if (!mag->poll_dev) { dev_err(&client->dev, "alloc poll device failed!\n"); ret = -ENOMEM; - goto error_rm_hwmon_dev; + goto error_alloc_poll_dev; } - data->poll_dev->poll = mag3110_dev_poll; - data->poll_dev->poll_interval = POLL_INTERVAL; - data->poll_dev->poll_interval_min = POLL_INTERVAL_MIN; - data->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; - idev = data->poll_dev->input; - idev->name = MAG3110_DRV_NAME; + mag->poll_dev->poll = mag3110_dev_poll; + mag->poll_dev->poll_interval = POLL_STOP_TIME; + mag->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; + mag->poll_dev->poll_interval_min = POLL_INTERVAL_MIN; + mag->poll_dev->private = mag; + idev = mag->poll_dev->input; + idev->name = "FreescaleMagnetometer"; idev->id.bustype = BUS_I2C; idev->evbit[0] = BIT_MASK(EV_ABS); - input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0); - input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0); - input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0); - ret = input_register_polled_device(data->poll_dev); + input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0); + ret = input_register_polled_device(mag->poll_dev); if (ret) { dev_err(&client->dev, "register poll device failed!\n"); - goto error_free_poll_dev; + goto error_reg_poll_dev; + } + ret = mag3110_reigister_caldata_input(mag); + if (ret < 0) { + dev_err(&client->dev, + "failed to register calibrated input device!\n"); + goto erorr_reg_caldev; } - /*create device group in sysfs as user interface */ ret = sysfs_create_group(&idev->dev.kobj, &mag3110_attr_group); if (ret) { - dev_err(&client->dev, "create device file failed!\n"); + dev_err(&client->dev, "create sysfs device file failed!\n"); ret = -EINVAL; - goto error_rm_poll_dev; + goto error_reg_sysfs; } + /* set irq type to edge rising */ #if MAG3110_IRQ_USED ret = request_irq(client->irq, mag3110_irq_handler, - IRQF_TRIGGER_RISING, client->dev.driver->name, idev); + IRQF_TRIGGER_RISING, client->dev.driver->name, mag); if (ret < 0) { dev_err(&client->dev, "failed to register irq %d!\n", - client->irq); - goto error_rm_dev_sysfs; + client->irq); + goto error_reg_irq; } #endif /* Initialize mag3110 chip */ + mag3110_init_client(client); - mag3110_pdata = data; - mag3110_pdata->active = MAG_STANDBY; - mag3110_pdata->position = *(int *)client->dev.platform_data; dev_info(&client->dev, "mag3110 is probed\n"); return 0; -error_rm_dev_sysfs: +#if MAG3110_IRQ_USED +error_reg_irq: sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); -error_rm_poll_dev: - input_unregister_polled_device(data->poll_dev); -error_free_poll_dev: - input_free_polled_device(data->poll_dev); -error_rm_hwmon_dev: - hwmon_device_unregister(data->hwmon_dev); - - kfree(data); - mag3110_pdata = NULL; - +#endif +error_reg_sysfs: + mag3110_unreigister_caldata_input(mag); +erorr_reg_caldev: + input_unregister_polled_device(mag->poll_dev); +error_reg_poll_dev: + input_free_polled_device(mag->poll_dev); +error_alloc_poll_dev: + kfree(mag); return ret; } static int __devexit mag3110_remove(struct i2c_client *client) { - struct mag3110_data *data; + struct mag3110_data *mag = i2c_get_clientdata(client); int ret; - data = i2c_get_clientdata(client); - - data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); + mag->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, - data->ctl_reg1 & ~MAG3110_AC_MASK); - - free_irq(client->irq, data); - input_unregister_polled_device(data->poll_dev); - input_free_polled_device(data->poll_dev); - hwmon_device_unregister(data->hwmon_dev); + mag->ctl_reg1 & ~MAG3110_AC_MASK); + free_irq(client->irq, mag); + input_unregister_polled_device(mag->poll_dev); + input_free_polled_device(mag->poll_dev); sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); - kfree(data); - mag3110_pdata = NULL; + mag3110_unreigister_caldata_input(mag); + kfree(mag); + mag = NULL; return ret; } @@ -513,12 +565,13 @@ static int __devexit mag3110_remove(struct i2c_client *client) #ifdef CONFIG_PM static int mag3110_suspend(struct i2c_client *client, pm_message_t mesg) { + struct mag3110_data *mag = i2c_get_clientdata(client); int ret = 0; - struct mag3110_data *data = i2c_get_clientdata(client); - if (data->active == MAG_ACTIVED) { - data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); + + if (mag->active == MAG_ACTIVED) { + mag->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, - data->ctl_reg1 & ~MAG3110_AC_MASK); + mag->ctl_reg1 & ~MAG3110_AC_MASK); } return ret; } @@ -527,15 +580,17 @@ static int mag3110_resume(struct i2c_client *client) { int ret = 0; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; - struct mag3110_data *data = i2c_get_clientdata(client); - if (data->active == MAG_ACTIVED) { + struct mag3110_data *mag = i2c_get_clientdata(client); + + if (mag->active == MAG_ACTIVED) { ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, - data->ctl_reg1); + mag->ctl_reg1); - if (data->ctl_reg1 & MAG3110_AC_MASK) { - /* Read out MSB data to clear interrupt automatically*/ + if (mag->ctl_reg1 & MAG3110_AC_MASK) { + /* Read out MSB data to clear */ + /* interrupt flag automatically */ mag3110_read_block_data(client, MAG3110_OUT_X_MSB, - MAG3110_XYZ_DATA_LEN, tmp_data); + MAG3110_XYZ_DATA_LEN, tmp_data); } } return ret; @@ -544,22 +599,22 @@ static int mag3110_resume(struct i2c_client *client) #else #define mag3110_suspend NULL #define mag3110_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM */ static const struct i2c_device_id mag3110_id[] = { - {MAG3110_DRV_NAME, 0}, + { MAG3110_DRV_NAME, 0 }, {} }; MODULE_DEVICE_TABLE(i2c, mag3110_id); static struct i2c_driver mag3110_driver = { - .driver = {.name = MAG3110_DRV_NAME, - .owner = THIS_MODULE,}, - .suspend = mag3110_suspend, - .resume = mag3110_resume, - .probe = mag3110_probe, - .remove = __devexit_p(mag3110_remove), - .id_table = mag3110_id, + .driver = { .name = MAG3110_DRV_NAME, + .owner = THIS_MODULE, }, + .suspend = mag3110_suspend, + .resume = mag3110_resume, + .probe = mag3110_probe, + .remove = __devexit_p(mag3110_remove), + .id_table = mag3110_id, }; static int __init mag3110_init(void) diff --git a/drivers/hwmon/mma8x5x.c b/drivers/hwmon/mma8x5x.c new file mode 100644 index 000000000000..ba00053ac447 --- /dev/null +++ b/drivers/hwmon/mma8x5x.c @@ -0,0 +1,561 @@ +/* + * mma8x5x.c - Linux kernel modules for 3-Axis Orientation/Motion + * Detection Sensor MMA8451/MMA8452/MMA8453/MMA8652/MMA8653 + * + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. 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 as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/pm.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/input-polldev.h> + + +#define MMA8X5X_I2C_ADDR 0x1D +#define MMA8451_ID 0x1A +#define MMA8452_ID 0x2A +#define MMA8453_ID 0x3A +#define MMA8652_ID 0x4A +#define MMA8653_ID 0x5A + + +#define POLL_INTERVAL_MIN 1 +#define POLL_INTERVAL_MAX 500 +#define POLL_INTERVAL 100 /* msecs */ + +/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */ +#define POLL_STOP_TIME 200 +#define INPUT_FUZZ 32 +#define INPUT_FLAT 32 +#define MODE_CHANGE_DELAY_MS 100 + +#define MMA8X5X_STATUS_ZYXDR 0x08 +#define MMA8X5X_BUF_SIZE 6 + +/* register enum for mma8x5x registers */ +enum { + MMA8X5X_STATUS = 0x00, + MMA8X5X_OUT_X_MSB, + MMA8X5X_OUT_X_LSB, + MMA8X5X_OUT_Y_MSB, + MMA8X5X_OUT_Y_LSB, + MMA8X5X_OUT_Z_MSB, + MMA8X5X_OUT_Z_LSB, + + MMA8X5X_F_SETUP = 0x09, + MMA8X5X_TRIG_CFG, + MMA8X5X_SYSMOD, + MMA8X5X_INT_SOURCE, + MMA8X5X_WHO_AM_I, + MMA8X5X_XYZ_DATA_CFG, + MMA8X5X_HP_FILTER_CUTOFF, + + MMA8X5X_PL_STATUS, + MMA8X5X_PL_CFG, + MMA8X5X_PL_COUNT, + MMA8X5X_PL_BF_ZCOMP, + MMA8X5X_P_L_THS_REG, + + MMA8X5X_FF_MT_CFG, + MMA8X5X_FF_MT_SRC, + MMA8X5X_FF_MT_THS, + MMA8X5X_FF_MT_COUNT, + + MMA8X5X_TRANSIENT_CFG = 0x1D, + MMA8X5X_TRANSIENT_SRC, + MMA8X5X_TRANSIENT_THS, + MMA8X5X_TRANSIENT_COUNT, + + MMA8X5X_PULSE_CFG, + MMA8X5X_PULSE_SRC, + MMA8X5X_PULSE_THSX, + MMA8X5X_PULSE_THSY, + MMA8X5X_PULSE_THSZ, + MMA8X5X_PULSE_TMLT, + MMA8X5X_PULSE_LTCY, + MMA8X5X_PULSE_WIND, + + MMA8X5X_ASLP_COUNT, + MMA8X5X_CTRL_REG1, + MMA8X5X_CTRL_REG2, + MMA8X5X_CTRL_REG3, + MMA8X5X_CTRL_REG4, + MMA8X5X_CTRL_REG5, + + MMA8X5X_OFF_X, + MMA8X5X_OFF_Y, + MMA8X5X_OFF_Z, + + MMA8X5X_REG_END, +}; + +/* The sensitivity is represented in counts/g. In 2g mode the + sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512 + counts/g and in 8g mode the sensitivity is 256 counts/g. + */ +enum { + MODE_2G = 0, + MODE_4G, + MODE_8G, +}; + +enum { + MMA_STANDBY = 0, + MMA_ACTIVED, +}; +struct mma8x5x_data_axis { + short x; + short y; + short z; +}; +struct mma8x5x_data { + struct i2c_client *client; + struct input_polled_dev *poll_dev; + struct mutex data_lock; + int active; + int position; + u8 chip_id; + int mode; +}; +/* Addresses scanned */ +static const unsigned short normal_i2c[] = { 0x1c, 0x1d, I2C_CLIENT_END }; + +static int mma8x5x_chip_id[] = { + MMA8451_ID, + MMA8452_ID, + MMA8453_ID, + MMA8652_ID, + MMA8653_ID, +}; +static char *mma8x5x_names[] = { + "mma8451", + "mma8452", + "mma8453", + "mma8652", + "mma8653", +}; +static int mma8x5x_position_setting[8][3][3] = { + { { 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 } }, + { { -1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } }, + { { 0, 1, 0 }, { -1, 0, 0 }, { 0, 0, 1 } }, + { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }, + + { { 0, -1, 0 }, { -1, 0, 0 }, { 0, 0, -1 } }, + { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } }, + { { 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, -1 } }, + { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, -1 } }, +}; + +static int mma8x5x_data_convert(struct mma8x5x_data *pdata, + struct mma8x5x_data_axis *axis_data) +{ + short rawdata[3], data[3]; + int i, j; + int position = pdata->position; + + if (position < 0 || position > 7) + position = 0; + rawdata[0] = axis_data->x; + rawdata[1] = axis_data->y; + rawdata[2] = axis_data->z; + for (i = 0; i < 3; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += rawdata[j] * mma8x5x_position_setting[position][i][j]; + } + axis_data->x = data[0]; + axis_data->y = data[1]; + axis_data->z = data[2]; + return 0; +} +static int mma8x5x_check_id(int id) +{ + int i = 0; + + for (i = 0; i < sizeof(mma8x5x_chip_id) / sizeof(mma8x5x_chip_id[0]); i++) + if (id == mma8x5x_chip_id[i]) + return 1; + return 0; +} +static char *mma8x5x_id2name(u8 id) +{ + return mma8x5x_names[(id >> 4) - 1]; +} +static int mma8x5x_device_init(struct i2c_client *client) +{ + int result; + struct mma8x5x_data *pdata = i2c_get_clientdata(client); + + result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0); + if (result < 0) + goto out; + + result = i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG, + pdata->mode); + if (result < 0) + goto out; + pdata->active = MMA_STANDBY; + msleep(MODE_CHANGE_DELAY_MS); + return 0; +out: + dev_err(&client->dev, "error when init mma8x5x:(%d)", result); + return result; +} +static int mma8x5x_device_stop(struct i2c_client *client) +{ + u8 val; + + val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); + i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val & 0xfe); + return 0; +} + +static int mma8x5x_read_data(struct i2c_client *client, + struct mma8x5x_data_axis *data) +{ + u8 tmp_data[MMA8X5X_BUF_SIZE]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, + MMA8X5X_OUT_X_MSB, + MMA8X5X_BUF_SIZE, tmp_data); + if (ret < MMA8X5X_BUF_SIZE) { + dev_err(&client->dev, "i2c block read failed\n"); + return -EIO; + } + data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; + data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; + data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; + return 0; +} + +static void mma8x5x_report_data(struct mma8x5x_data *pdata) +{ + struct input_polled_dev *poll_dev = pdata->poll_dev; + struct mma8x5x_data_axis data; + + mutex_lock(&pdata->data_lock); + if (pdata->active == MMA_STANDBY) { + /* if standby ,set as 10s to slow the poll */ + poll_dev->poll_interval = POLL_STOP_TIME; + goto out; + } else if (poll_dev->poll_interval == POLL_STOP_TIME) + poll_dev->poll_interval = POLL_INTERVAL; + if (mma8x5x_read_data(pdata->client, &data) != 0) + goto out; + mma8x5x_data_convert(pdata, &data); + input_report_abs(poll_dev->input, ABS_X, data.x); + input_report_abs(poll_dev->input, ABS_Y, data.y); + input_report_abs(poll_dev->input, ABS_Z, data.z); + input_sync(poll_dev->input); +out: + mutex_unlock(&pdata->data_lock); +} + +static void mma8x5x_dev_poll(struct input_polled_dev *dev) +{ + struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private; + + mma8x5x_report_data(pdata); +} + +static ssize_t mma8x5x_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private); + struct i2c_client *client = pdata->client; + u8 val; + int enable; + + mutex_lock(&pdata->data_lock); + val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); + if ((val & 0x01) && pdata->active == MMA_ACTIVED) + enable = 1; + else + enable = 0; + mutex_unlock(&pdata->data_lock); + return sprintf(buf, "%d\n", enable); +} + +static ssize_t mma8x5x_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private); + struct i2c_client *client = pdata->client; + int ret; + unsigned long enable; + u8 val = 0; + + enable = simple_strtoul(buf, NULL, 10); + mutex_lock(&pdata->data_lock); + enable = (enable > 0) ? 1 : 0; + if (enable && pdata->active == MMA_STANDBY) { + val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); + ret = i2c_smbus_write_byte_data(client, + MMA8X5X_CTRL_REG1, val | 0x01); + if (!ret) { + pdata->active = MMA_ACTIVED; + printk(KERN_INFO"mma enable setting active \n"); + } + } else if (enable == 0 && pdata->active == MMA_ACTIVED) { + val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); + ret = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val & 0xFE); + if (!ret) { + pdata->active = MMA_STANDBY; + printk(KERN_INFO"mma enable setting inactive \n"); + } + } + mutex_unlock(&pdata->data_lock); + return count; +} +static ssize_t mma8x5x_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private); + int position = 0; + + mutex_lock(&pdata->data_lock); + position = pdata->position; + mutex_unlock(&pdata->data_lock); + return sprintf(buf, "%d\n", position); +} + +static ssize_t mma8x5x_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_polled_dev *poll_dev = dev_get_drvdata(dev); + struct mma8x5x_data *pdata = (struct mma8x5x_data *)(poll_dev->private); + int position; + + position = simple_strtoul(buf, NULL, 10); + mutex_lock(&pdata->data_lock); + pdata->position = position; + mutex_unlock(&pdata->data_lock); + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, + mma8x5x_enable_show, mma8x5x_enable_store); +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, + mma8x5x_position_show, mma8x5x_position_store); + +static struct attribute *mma8x5x_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_position.attr, + NULL +}; + +static const struct attribute_group mma8x5x_attr_group = { + .attrs = mma8x5x_attributes, +}; +static int mma8x5x_detect(struct i2c_client *client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + int chip_id; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -ENODEV; + chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I); + if (!mma8x5x_check_id(chip_id)) + return -ENODEV; + printk(KERN_INFO "check %s i2c address 0x%x \n", + mma8x5x_id2name(chip_id), client->addr); + strlcpy(info->type, "mma8x5x", I2C_NAME_SIZE); + return 0; +} +static int __devinit mma8x5x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int result, chip_id; + struct input_dev *idev; + struct mma8x5x_data *pdata; + struct i2c_adapter *adapter; + struct input_polled_dev *poll_dev; + + adapter = to_i2c_adapter(client->dev.parent); + result = i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA); + if (!result) + goto err_out; + + chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I); + + if (!mma8x5x_check_id(chip_id)) { + dev_err(&client->dev, + "read chip ID 0x%x is not equal to 0x%x,0x%x,0x%x,0x%x,0x%x!\n", + chip_id, MMA8451_ID, MMA8452_ID, + MMA8453_ID, MMA8652_ID, MMA8653_ID); + result = -EINVAL; + goto err_out; + } + pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL); + if (!pdata) { + result = -ENOMEM; + dev_err(&client->dev, "alloc data memory error!\n"); + goto err_out; + } + /* Initialize the MMA8X5X chip */ + pdata->client = client; + pdata->chip_id = chip_id; + pdata->mode = MODE_2G; + pdata->position = *(int *)client->dev.platform_data; + mutex_init(&pdata->data_lock); + i2c_set_clientdata(client, pdata); + mma8x5x_device_init(client); + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + result = -ENOMEM; + dev_err(&client->dev, "alloc poll device failed!\n"); + goto err_alloc_poll_device; + } + poll_dev->poll = mma8x5x_dev_poll; + poll_dev->poll_interval = POLL_STOP_TIME; + poll_dev->poll_interval_min = POLL_INTERVAL_MIN; + poll_dev->poll_interval_max = POLL_INTERVAL_MAX; + poll_dev->private = pdata; + idev = poll_dev->input; + idev->name = "FreescaleAccelerometer"; + idev->uniq = mma8x5x_id2name(pdata->chip_id); + idev->id.bustype = BUS_I2C; + idev->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0); + input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0); + pdata->poll_dev = poll_dev; + result = input_register_polled_device(pdata->poll_dev); + if (result) { + dev_err(&client->dev, "register poll device failed!\n"); + goto err_register_polled_device; + } + result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group); + if (result) { + dev_err(&client->dev, "create device file failed!\n"); + result = -EINVAL; + goto err_create_sysfs; + } + printk(KERN_INFO"mma8x5x device driver probe successfully\n"); + return 0; +err_create_sysfs: + input_unregister_polled_device(pdata->poll_dev); +err_register_polled_device: + input_free_polled_device(poll_dev); +err_alloc_poll_device: + kfree(pdata); +err_out: + return result; +} +static int __devexit mma8x5x_remove(struct i2c_client *client) +{ + struct mma8x5x_data *pdata = i2c_get_clientdata(client); + struct input_polled_dev *poll_dev = pdata->poll_dev; + + mma8x5x_device_stop(client); + if (pdata) { + input_unregister_polled_device(poll_dev); + input_free_polled_device(poll_dev); + kfree(pdata); + } + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mma8x5x_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mma8x5x_data *pdata = i2c_get_clientdata(client); + + if (pdata->active == MMA_ACTIVED) + mma8x5x_device_stop(client); + return 0; +} + +static int mma8x5x_resume(struct device *dev) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + struct mma8x5x_data *pdata = i2c_get_clientdata(client); + + if (pdata->active == MMA_ACTIVED) { + val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); + i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val | 0x01); + } + return 0; + +} +#endif + +static const struct i2c_device_id mma8x5x_id[] = { + { "mma8x5x", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mma8x5x_id); + +static SIMPLE_DEV_PM_OPS(mma8x5x_pm_ops, mma8x5x_suspend, mma8x5x_resume); +static struct i2c_driver mma8x5x_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "mma8x5x", + .owner = THIS_MODULE, + .pm = &mma8x5x_pm_ops, + }, + .probe = mma8x5x_probe, + .remove = __devexit_p(mma8x5x_remove), + .id_table = mma8x5x_id, + .detect = mma8x5x_detect, + .address_list = normal_i2c, +}; + +static int __init mma8x5x_init(void) +{ + /* register driver */ + int res; + + res = i2c_add_driver(&mma8x5x_driver); + if (res < 0) { + printk(KERN_INFO "add mma8x5x i2c driver failed\n"); + return -ENODEV; + } + return res; +} + +static void __exit mma8x5x_exit(void) +{ + i2c_del_driver(&mma8x5x_driver); +} + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MMA8X5X 3-Axis Orientation/Motion Detection Sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(mma8x5x_init); +module_exit(mma8x5x_exit); diff --git a/drivers/hwmon/mxc_mma8450.c b/drivers/hwmon/mxc_mma8450.c deleted file mode 100644 index 214df139a866..000000000000 --- a/drivers/hwmon/mxc_mma8450.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * mma8450.c - Linux kernel modules for 3-Axis Orientation/Motion - * Detection Sensor - * - * Copyright (C) 2011 Freescale Semiconductor, Inc. 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/hwmon-sysfs.h> -#include <linux/err.h> -#include <linux/hwmon.h> -#include <linux/input-polldev.h> - -/* - * Defines - */ -#define assert(expr)\ - if (!(expr)) {\ - printk(KERN_ERR "Assertion failed! %s,%d,%s,%s\n",\ - __FILE__, __LINE__, __func__, #expr);\ - } - -#define MMA8450_DRV_NAME "mma8450" -#define MMA8450_I2C_ADDR 0x1C -#define MMA8450_ID 0xC6 -#define MMA8450_STATUS 0x00 - -#define MODE_CHANGE_DELAY_MS 100 -#define POLL_INTERVAL_MAX 500 -#define POLL_INTERVAL 100 -#define INPUT_FUZZ 32 -#define INPUT_FLAT 32 - -/* register enum for mma8450 registers */ -enum { - MMA8450_STATUS1 = 0x00, - MMA8450_OUT_X8, - MMA8450_OUT_Y8, - MMA8450_OUT_Z8, - - MMA8450_STATUS2, - MMA8450_OUT_X_LSB, - MMA8450_OUT_X_MSB, - MMA8450_OUT_Y_LSB, - MMA8450_OUT_Y_MSB, - MMA8450_OUT_Z_LSB, - MMA8450_OUT_Z_MSB, - - MMA8450_STATUS3, - MMA8450_OUT_X_DELTA, - MMA8450_OUT_Y_DELTA, - MMA8450_OUT_Z_DELTA, - - MMA8450_WHO_AM_I, - - MMA8450_F_STATUS, - MMA8450_F_8DATA, - MMA8450_F_12DATA, - MMA8450_F_SETUP, - - MMA8450_SYSMOD, - MMA8450_INT_SOURCE, - MMA8450_XYZ_DATA_CFG, - MMA8450_HP_FILTER_CUTOFF, - - MMA8450_PL_STATUS, - MMA8450_PL_PRE_STATUS, - MMA8450_PL_CFG, - MMA8450_PL_COUNT, - MMA8450_PL_BF_ZCOMP, - MMA8450_PL_P_L_THS_REG1, - MMA8450_PL_P_L_THS_REG2, - MMA8450_PL_P_L_THS_REG3, - MMA8450_PL_L_P_THS_REG1, - MMA8450_PL_L_P_THS_REG2, - MMA8450_PL_L_P_THS_REG3, - - MMA8450_FF_MT_CFG_1, - MMA8450_FF_MT_SRC_1, - MMA8450_FF_MT_THS_1, - MMA8450_FF_MT_COUNT_1, - MMA8450_FF_MT_CFG_2, - MMA8450_FF_MT_SRC_2, - MMA8450_FF_MT_THS_2, - MMA8450_FF_MT_COUNT_2, - - MMA8450_TRANSIENT_CFG, - MMA8450_TRANSIENT_SRC, - MMA8450_TRANSIENT_THS, - MMA8450_TRANSIENT_COUNT, - - MMA8450_PULSE_CFG, - MMA8450_PULSE_SRC, - MMA8450_PULSE_THSX, - MMA8450_PULSE_THSY, - MMA8450_PULSE_THSZ, - MMA8450_PULSE_TMLT, - MMA8450_PULSE_LTCY, - MMA8450_PULSE_WIND, - - MMA8450_ASLP_COUNT, - MMA8450_CTRL_REG1, - MMA8450_CTRL_REG2, - MMA8450_CTRL_REG3, - MMA8450_CTRL_REG4, - MMA8450_CTRL_REG5, - - MMA8450_OFF_X, - MMA8450_OFF_Y, - MMA8450_OFF_Z, - - MMA8450_REG_END, -}; - -enum { - MODE_STANDBY, - MODE_2G, - MODE_4G, - MODE_8G, -}; - -/* mma8450 status */ -struct mma8450_status { - u8 mode; - u8 ctl_reg2; - u8 ctl_reg1; -}; - -static struct mma8450_status mma_status = { - .mode = 0, - .ctl_reg2 = 0, - .ctl_reg1 = 0 -}; - -static struct device *hwmon_dev; -static struct i2c_client *mma8450_i2c_client; -static struct input_polled_dev *mma8450_idev; - -/* - * Initialization function - */ -static int mma8450_init_client(struct i2c_client *client) -{ - int result; - - mma_status.mode = MODE_2G; - - result = i2c_smbus_write_byte_data(client, MMA8450_XYZ_DATA_CFG, 0x07); - assert(result == 0); - - result = - i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1, - mma_status.mode); - assert(result == 0); - - mdelay(MODE_CHANGE_DELAY_MS); - - return result; -} - -/* - * read sensor data from mma8450 - */ -static int mma8450_read_data(short *x, short *y, short *z) -{ - u8 tmp_data[7]; - - if (i2c_smbus_read_i2c_block_data - (mma8450_i2c_client, MMA8450_OUT_X_LSB, 7, tmp_data) < 7) { - dev_err(&mma8450_i2c_client->dev, "i2c block read failed\n"); - return -3; - } - - *x = ((tmp_data[1] << 8) & 0xff00) | ((tmp_data[0] << 4) & 0x00f0); - *y = ((tmp_data[3] << 8) & 0xff00) | ((tmp_data[2] << 4) & 0x00f0); - *z = ((tmp_data[5] << 8) & 0xff00) | ((tmp_data[4] << 4) & 0x00f0); - - *x = (short)(*x) >> 4; - *y = (short)(*y) >> 4; - *z = (short)(*z) >> 4; - - if (mma_status.mode == MODE_4G) { - (*x) = (*x) << 1; - (*y) = (*y) << 1; - (*z) = (*z) << 1; - } else if (mma_status.mode == MODE_8G) { - (*x) = (*x) << 2; - (*y) = (*y) << 2; - (*z) = (*z) << 2; - } - - return 0; -} - -static void report_abs(void) -{ - short x, y, z; - int result; - - do { - result = - i2c_smbus_read_byte_data(mma8450_i2c_client, - MMA8450_STATUS3); - } while (!(result & 0x08)); /* wait for new data */ - - if (mma8450_read_data(&x, &y, &z) != 0) - return; - - input_report_abs(mma8450_idev->input, ABS_X, x); - input_report_abs(mma8450_idev->input, ABS_Y, y); - input_report_abs(mma8450_idev->input, ABS_Z, z); - input_sync(mma8450_idev->input); -} - -static void mma8450_dev_poll(struct input_polled_dev *dev) -{ - report_abs(); -} - -/* - * I2C init/probing/exit functions - */ -static int __devinit mma8450_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int result; - struct i2c_adapter *adapter; - struct input_dev *idev; - - mma8450_i2c_client = client; - adapter = to_i2c_adapter(client->dev.parent); - - result = i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA); - assert(result); - - printk(KERN_INFO "check mma8450 chip ID\n"); - result = i2c_smbus_read_byte_data(client, MMA8450_WHO_AM_I); - - if (MMA8450_ID != (result)) { - dev_err(&client->dev, - "read chip ID 0x%x is not equal to 0x%x!\n", result, - MMA8450_ID); - printk(KERN_INFO "read chip ID failed\n"); - result = -EINVAL; - goto err_detach_client; - } - - /* Initialize the MMA8450 chip */ - result = mma8450_init_client(client); - assert(result == 0); - - hwmon_dev = hwmon_device_register(&client->dev); - assert(!(IS_ERR(hwmon_dev))); - - dev_info(&client->dev, "build time %s %s\n", __DATE__, __TIME__); - - /*input poll device register */ - mma8450_idev = input_allocate_polled_device(); - if (!mma8450_idev) { - dev_err(&client->dev, "alloc poll device failed!\n"); - result = -ENOMEM; - return result; - } - mma8450_idev->poll = mma8450_dev_poll; - mma8450_idev->poll_interval = POLL_INTERVAL; - mma8450_idev->poll_interval_max = POLL_INTERVAL_MAX; - idev = mma8450_idev->input; - idev->name = MMA8450_DRV_NAME; - idev->id.bustype = BUS_I2C; - idev->evbit[0] = BIT_MASK(EV_ABS); - - input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - result = input_register_polled_device(mma8450_idev); - if (result) { - dev_err(&client->dev, "register poll device failed!\n"); - return result; - } - - return result; - -err_detach_client: - return result; -} - -static int __devexit mma8450_remove(struct i2c_client *client) -{ - int result; - mma_status.ctl_reg1 = - i2c_smbus_read_byte_data(client, MMA8450_CTRL_REG1); - result = - i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1, - mma_status.ctl_reg1 & 0xFC); - assert(result == 0); - - hwmon_device_unregister(hwmon_dev); - - return result; -} - -static int mma8450_suspend(struct i2c_client *client, pm_message_t mesg) -{ - int result; - mma_status.ctl_reg1 = - i2c_smbus_read_byte_data(client, MMA8450_CTRL_REG1); - result = - i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1, - mma_status.ctl_reg1 & 0xFC); - assert(result == 0); - return result; -} - -static int mma8450_resume(struct i2c_client *client) -{ - int result; - result = - i2c_smbus_write_byte_data(client, MMA8450_CTRL_REG1, - mma_status.mode); - assert(result == 0); - return result; -} - -static const struct i2c_device_id mma8450_id[] = { - {MMA8450_DRV_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, mma8450_id); - -static struct i2c_driver mma8450_driver = { - .driver = { - .name = MMA8450_DRV_NAME, - .owner = THIS_MODULE, - }, - .suspend = mma8450_suspend, - .resume = mma8450_resume, - .probe = mma8450_probe, - .remove = __devexit_p(mma8450_remove), - .id_table = mma8450_id, -}; - -static int __init mma8450_init(void) -{ - /* register driver */ - int res; - - res = i2c_add_driver(&mma8450_driver); - if (res < 0) { - printk(KERN_INFO "add mma8450 i2c driver failed\n"); - return -ENODEV; - } - printk(KERN_INFO "add mma8450 i2c driver\n"); - - return res; -} - -static void __exit mma8450_exit(void) -{ - printk(KERN_INFO "remove mma8450 i2c driver.\n"); - i2c_del_driver(&mma8450_driver); -} - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MMA8450 3-Axis Orientation/Motion Detection Sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(mma8450_init); -module_exit(mma8450_exit); diff --git a/drivers/hwmon/mxc_mma8451.c b/drivers/hwmon/mxc_mma8451.c deleted file mode 100644 index d144cbcbacdb..000000000000 --- a/drivers/hwmon/mxc_mma8451.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion - * Detection Sensor - * - * Copyright (C) 2012 Freescale Semiconductor, Inc. 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 as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/pm.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/hwmon-sysfs.h> -#include <linux/err.h> -#include <linux/hwmon.h> -#include <linux/input-polldev.h> - -#define MMA8451_DRV_NAME "mma8451" -#define MMA8451_I2C_ADDR 0x1C -#define MMA8451_ID 0x1A -#define MMA8452_ID 0x2A -#define MMA8453_ID 0x3A - -#define POLL_INTERVAL_MIN 20 -#define POLL_INTERVAL_MAX 1000 -#define POLL_INTERVAL 500 -#define INPUT_FUZZ 128 -#define INPUT_FLAT 128 -#define MODE_CHANGE_DELAY_MS 100 - -#define MMA8451_STATUS_ZYXDR 0x08 -#define MMA8451_BUF_SIZE 6 - -#define DR_1_25MS 0 -#define DR_2_5MS 1 -#define DR_5_0MS 2 -#define DR_10_0MS 3 -#define DR_20_0MS 4 -#define DR_80_0MS 5 -#define DR_160_0MS 6 -#define DR_640_0MS 7 - -/* register enum for mma8451 registers */ -enum { - MMA8451_STATUS = 0x00, - MMA8451_OUT_X_MSB, - MMA8451_OUT_X_LSB, - MMA8451_OUT_Y_MSB, - MMA8451_OUT_Y_LSB, - MMA8451_OUT_Z_MSB, - MMA8451_OUT_Z_LSB, - - MMA8451_F_SETUP = 0x09, - MMA8451_TRIG_CFG, - MMA8451_SYSMOD, - MMA8451_INT_SOURCE, - MMA8451_WHO_AM_I, - MMA8451_XYZ_DATA_CFG, - MMA8451_HP_FILTER_CUTOFF, - - MMA8451_PL_STATUS, - MMA8451_PL_CFG, - MMA8451_PL_COUNT, - MMA8451_PL_BF_ZCOMP, - MMA8451_P_L_THS_REG, - - MMA8451_FF_MT_CFG, - MMA8451_FF_MT_SRC, - MMA8451_FF_MT_THS, - MMA8451_FF_MT_COUNT, - - MMA8451_TRANSIENT_CFG = 0x1D, - MMA8451_TRANSIENT_SRC, - MMA8451_TRANSIENT_THS, - MMA8451_TRANSIENT_COUNT, - - MMA8451_PULSE_CFG, - MMA8451_PULSE_SRC, - MMA8451_PULSE_THSX, - MMA8451_PULSE_THSY, - MMA8451_PULSE_THSZ, - MMA8451_PULSE_TMLT, - MMA8451_PULSE_LTCY, - MMA8451_PULSE_WIND, - - MMA8451_ASLP_COUNT, - MMA8451_CTRL_REG1, - MMA8451_CTRL_REG2, - MMA8451_CTRL_REG3, - MMA8451_CTRL_REG4, - MMA8451_CTRL_REG5, - - MMA8451_OFF_X, - MMA8451_OFF_Y, - MMA8451_OFF_Z, - - MMA8451_REG_END, -}; - -/* The sensitivity is represented in counts/g. In 2g mode the - sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512 - counts/g and in 8g mode the sensitivity is 256 counts/g. - */ -enum { - MODE_2G = 0, - MODE_4G, - MODE_8G, -}; - -enum { - MMA_STANDBY = 0, - MMA_ACTIVED, -}; - -/* mma8451 status */ -struct mma8451_status { - u8 mode; - u8 ctl_reg1; - int active; - int position; -}; - -static struct mma8451_status mma_status; -static struct input_polled_dev *mma8451_idev; -static struct device *hwmon_dev; -static struct i2c_client *mma8451_i2c_client; - -static int senstive_mode = MODE_2G; -static int ACCHAL[8][3][3] = { - {{ 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} }, - {{-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} }, - {{ 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, - {{ 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} }, - - {{ 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, - {{-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} }, - {{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} }, - {{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} }, -}; - -static DEFINE_MUTEX(mma8451_lock); -static int mma8451_adjust_position(short *x, short *y, short *z) -{ - short rawdata[3], data[3]; - int i, j; - int position = mma_status.position; - if (position < 0 || position > 7) - position = 0; - - rawdata[0] = *x; - rawdata[1] = *y; - rawdata[2] = *z; - - for (i = 0; i < 3 ; i++) { - data[i] = 0; - for (j = 0; j < 3; j++) - data[i] += rawdata[j] * ACCHAL[position][i][j]; - } - *x = data[0]; - *y = data[1]; - *z = data[2]; - return 0; -} - -static int mma8451_change_mode(struct i2c_client *client, int mode) -{ - int result; - - /* Put sensor into Standby Mode by clearing the Active bit */ - mma_status.ctl_reg1 = 0x00; - result = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1); - if (result < 0) - goto out; - - /* Write the 2g dynamic range value */ - mma_status.mode = mode; - result = i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG, - mma_status.mode); - if (result < 0) - goto out; - - /* Set the Active bit and Data rate in CTRL Reg 1 */ - mma_status.active = MMA_STANDBY; - - mdelay(MODE_CHANGE_DELAY_MS); - - return 0; -out: - dev_err(&client->dev, "error when init mma8451:(%d)", result); - return result; -} - -static int mma8451_read_data(short *x, short *y, short *z) -{ - u8 tmp_data[MMA8451_BUF_SIZE]; - int ret; - - /* Read 14-bit XYZ results using 6 byte */ - ret = i2c_smbus_read_i2c_block_data(mma8451_i2c_client, - MMA8451_OUT_X_MSB, MMA8451_BUF_SIZE, tmp_data); - if (ret < MMA8451_BUF_SIZE) { - dev_err(&mma8451_i2c_client->dev, "i2c block read failed\n"); - return -EIO; - } - - /* Concatenate the MSB and LSB */ - *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; - *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; - *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; - return 0; -} - -static void report_abs(void) -{ - short x, y, z; - int result; - - mutex_lock(&mma8451_lock); - if (mma_status.active == MMA_STANDBY) - goto out; - /* Read Status register */ - result = i2c_smbus_read_byte_data(mma8451_i2c_client, MMA8451_STATUS); - - /* Check ZYXDR status bit for data available */ - if (!(result & MMA8451_STATUS_ZYXDR)) { - /* Data not ready */ - goto out; - } - - /* Read XYZ data */ - if (mma8451_read_data(&x, &y, &z) != 0) - goto out; - mma8451_adjust_position(&x, &y, &z); - /* Report XYZ data */ - input_report_abs(mma8451_idev->input, ABS_X, x); - input_report_abs(mma8451_idev->input, ABS_Y, y); - input_report_abs(mma8451_idev->input, ABS_Z, z); - input_sync(mma8451_idev->input); -out: - mutex_unlock(&mma8451_lock); -} - -static void mma8451_dev_poll(struct input_polled_dev *dev) -{ - report_abs(); -} - -static ssize_t mma8451_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct i2c_client *client; - u8 val; - int enable; - - mutex_lock(&mma8451_lock); - client = mma8451_i2c_client; - val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); - if ((val & 0x01) && mma_status.active == MMA_ACTIVED) - enable = 1; - else - enable = 0; - mutex_unlock(&mma8451_lock); - return sprintf(buf, "%d\n", enable); -} - -static ssize_t mma8451_enable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client; - int ret; - unsigned long enable; - u8 val = 0; - enable = simple_strtoul(buf, NULL, 10); - mutex_lock(&mma8451_lock); - client = mma8451_i2c_client; - enable = (enable > 0) ? 1 : 0; - - if (enable && mma_status.active == MMA_STANDBY) { - val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); - /* Set the Active bit and Data rate in CTRL Reg 1 */ - val |= (DR_20_0MS<<3); - val |= 1; - ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - val); - if (!ret) { - mma_status.active = MMA_ACTIVED; - printk(KERN_DEBUG "mma enable setting active\n"); - } - } else if (enable == 0 && mma_status.active == MMA_ACTIVED) { - val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); - ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - val & 0xFE); - if (!ret) { - mma_status.active = MMA_STANDBY; - printk(KERN_DEBUG "mma enable setting inactive\n"); - } - } - mutex_unlock(&mma8451_lock); - return count; -} -static ssize_t mma8451_position_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int position = 0; - mutex_lock(&mma8451_lock); - position = mma_status.position ; - mutex_unlock(&mma8451_lock); - return sprintf(buf, "%d\n", position); -} - -static ssize_t mma8451_position_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int position; - position = simple_strtoul(buf, NULL, 10); - mutex_lock(&mma8451_lock); - mma_status.position = position; - mutex_unlock(&mma8451_lock); - return count; -} - -static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, - mma8451_enable_show, mma8451_enable_store); -static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, - mma8451_position_show, mma8451_position_store); - -static struct attribute *mma8451_attributes[] = { - &dev_attr_enable.attr, - &dev_attr_position.attr, - NULL -}; - -static const struct attribute_group mma8451_attr_group = { - .attrs = mma8451_attributes, -}; - -static int __devinit mma8451_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int result, client_id; - struct input_dev *idev; - struct i2c_adapter *adapter; - - mma8451_i2c_client = client; - adapter = to_i2c_adapter(client->dev.parent); - result = i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA); - if (!result) - goto err_out; - - client_id = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I); - - if (client_id != MMA8451_ID && client_id != MMA8452_ID && - client_id != MMA8453_ID) { - dev_err(&client->dev, - "read chip ID 0x%x is not equal to 0x%x \ - or 0x%x!\n", result, MMA8451_ID, MMA8452_ID); - result = -EINVAL; - goto err_out; - } - - /* Initialize the MMA8451 chip */ - result = mma8451_change_mode(client, senstive_mode); - if (result) { - dev_err(&client->dev, - "error when init mma8451 chip:(%d)\n", result); - goto err_out; - } - - hwmon_dev = hwmon_device_register(&client->dev); - if (!hwmon_dev) { - result = -ENOMEM; - dev_err(&client->dev, - "error when register hwmon device\n"); - goto err_out; - } - - mma8451_idev = input_allocate_polled_device(); - if (!mma8451_idev) { - result = -ENOMEM; - dev_err(&client->dev, "alloc poll device failed!\n"); - goto err_alloc_poll_device; - } - mma8451_idev->poll = mma8451_dev_poll; - mma8451_idev->poll_interval = POLL_INTERVAL; - mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN; - mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX; - idev = mma8451_idev->input; - idev->name = "mma845x"; - idev->id.bustype = BUS_I2C; - idev->evbit[0] = BIT_MASK(EV_ABS); - - input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); - - result = input_register_polled_device(mma8451_idev); - if (result) { - dev_err(&client->dev, "register poll device failed!\n"); - goto err_register_polled_device; - } - result = sysfs_create_group(&idev->dev.kobj, &mma8451_attr_group); - if (result) { - dev_err(&client->dev, "create device file failed!\n"); - result = -EINVAL; - goto err_register_polled_device; - } - mma_status.position = *(int *)client->dev.platform_data; - return 0; -err_register_polled_device: - input_free_polled_device(mma8451_idev); -err_alloc_poll_device: - hwmon_device_unregister(&client->dev); -err_out: - return result; -} - -static int mma8451_stop_chip(struct i2c_client *client) -{ - int ret = 0; - if (mma_status.active == MMA_ACTIVED) { - mma_status.ctl_reg1 = i2c_smbus_read_byte_data(client, - MMA8451_CTRL_REG1); - ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1 & 0xFE); - } - return ret; -} - -static int __devexit mma8451_remove(struct i2c_client *client) -{ - int ret; - ret = mma8451_stop_chip(client); - hwmon_device_unregister(hwmon_dev); - - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int mma8451_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - return mma8451_stop_chip(client); -} - -static int mma8451_resume(struct device *dev) -{ - int ret = 0; - struct i2c_client *client = to_i2c_client(dev); - if (mma_status.active == MMA_ACTIVED) - ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1); - return ret; - -} -#endif - -static const struct i2c_device_id mma8451_id[] = { - {MMA8451_DRV_NAME, 0}, -}; -MODULE_DEVICE_TABLE(i2c, mma8451_id); - -static SIMPLE_DEV_PM_OPS(mma8451_pm_ops, mma8451_suspend, mma8451_resume); -static struct i2c_driver mma8451_driver = { - .driver = { - .name = MMA8451_DRV_NAME, - .owner = THIS_MODULE, - .pm = &mma8451_pm_ops, - }, - .probe = mma8451_probe, - .remove = __devexit_p(mma8451_remove), - .id_table = mma8451_id, -}; - -static int __init mma8451_init(void) -{ - /* register driver */ - int res; - - res = i2c_add_driver(&mma8451_driver); - if (res < 0) { - printk(KERN_INFO "add mma8451 i2c driver failed\n"); - return -ENODEV; - } - return res; -} - -static void __exit mma8451_exit(void) -{ - i2c_del_driver(&mma8451_driver); -} - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MMA8451 3-Axis Orientation/Motion Detection Sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(mma8451_init); -module_exit(mma8451_exit); |