From e22d9cc2d6b18e9dadf716bf320ac37a980ff91c Mon Sep 17 00:00:00 2001 From: Nitin Garg Date: Thu, 16 Feb 2012 18:18:08 -0600 Subject: ENGR00174723-2: Integrate the mag3110 and mxc_mma8451 Intergrate the mag3110 and mxc_mma8451 drivers released by sensor team. Signed-off-by: Nitin Garg --- drivers/hwmon/mag3110.c | 339 +++++++++++++++++++++++--------------------- drivers/hwmon/mxc_mma8451.c | 246 +++++++++++++++++++++++--------- 2 files changed, 359 insertions(+), 226 deletions(-) diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c index 7100474a9e19..36955f876b95 100644 --- a/drivers/hwmon/mag3110.c +++ b/drivers/hwmon/mag3110.c @@ -30,21 +30,21 @@ #include #include #include -#include #define MAG3110_DRV_NAME "mag3110" #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 0 #define POLL_INTERVAL_MAX 500 #define POLL_INTERVAL 100 -#define INT_TIMEOUT 1000 - +#define INT_TIMEOUT 1000 /* register enum for mag3110 registers */ enum { MAG3110_DR_STATUS = 0x00, @@ -68,22 +68,60 @@ enum { MAG3110_CTRL_REG1 = 0x10, MAG3110_CTRL_REG2, }; - +enum { + MAG_STANDBY, + MAG_ACTIVED +}; struct mag3110_data { struct i2c_client *client; struct input_polled_dev *poll_dev; struct device *hwmon_dev; wait_queue_head_t waitq; bool data_ready; - bool stop_polling; 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 struct mag3110_data *mag3110_pdata; + {{ 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) +{ + 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; + + for (i = 0; i < 3 ; i++) { + data[i] = 0; + for (j = 0; j < 3; j++) + data[i] += rawdata[j] * MAGHAL[position][i][j]; + } + *x = data[0]; + *y = data[1]; + *z = data[2]; + return 0; +} static int mag3110_read_reg(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -106,10 +144,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; } @@ -130,34 +168,48 @@ static int mag3110_init_client(struct i2c_client *client) /* set default data rate to 10HZ */ val = mag3110_read_reg(client, MAG3110_CTRL_REG1); - val |= (0x3 << MAG3110_DR_MODE_OFFSET); + val |= (0x0 << MAG3110_DR_MODE_OFFSET); ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, val); return ret; } /*************************************************************** -* -* read sensor data from mag3110 -* -***************************************************************/ + * + * read sensor data from mag3110 + * + ***************************************************************/ static int mag3110_read_data(short *x, short *y, short *z) { struct mag3110_data *data; + int retry = 3; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; - - if (!mag3110_pdata) + int result; + if (!mag3110_pdata || mag3110_pdata->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))) { + (data->waitq, data->data_ready != 0, + msecs_to_jiffies(INT_TIMEOUT))) { dev_dbg(&data->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, @@ -176,22 +228,25 @@ static void report_abs(void) struct input_dev *idev; short x, y, z; + mutex_lock(&mag3110_lock); if (mag3110_read_data(&x, &y, &z) != 0) - return; - + 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); input_sync(idev); +out: + mutex_unlock(&mag3110_lock); } static void mag3110_dev_poll(struct input_polled_dev *dev) { - if (!mag3110_pdata->stop_polling) - report_abs(); + report_abs(); } +#if MAG3110_IRQ_USED static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) { mag3110_pdata->data_ready = 1; @@ -199,74 +254,77 @@ static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } - +#endif 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 = to_i2c_client(dev); + struct i2c_client *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); 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; int reg, ret, enable; - unsigned long val; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; - if (strict_strtoul(buf, 10, &val) < 0) - return -EINVAL; - - enable = (val == 1) ? 1 : 0; - - client = to_i2c_client(dev); + enable = simple_strtoul(buf, NULL, 10); + mutex_lock(&mag3110_lock); + client = mag3110_pdata->client; reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); - if (enable) + if (enable && mag3110_pdata->active == MAG_STANDBY) { reg |= MAG3110_AC_MASK; - else + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); + if (!ret) + mag3110_pdata->active = MAG_ACTIVED; + printk(KERN_DEBUG "mag3110 set active\n"); + } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) { reg &= ~MAG3110_AC_MASK; + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); + if (!ret) + mag3110_pdata->active = MAG_STANDBY; + printk(KERN_DEBUG "mag3110 set inactive\n"); + } - /* MAG3110_CTRL_REG1 bit 0, 0: STANDBY mode; 1: ACTIVE mode */ - ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); - if (ret < 0) - return ret; - - if (enable) { + if (mag3110_pdata->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_read_block_data(client, MAG3110_OUT_X_MSB, + MAG3110_XYZ_DATA_LEN, tmp_data); } - + mutex_unlock(&mag3110_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 = to_i2c_client(dev); + struct i2c_client *client; int val; + client = mag3110_pdata->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 i2c_client *client ; int reg, ret; unsigned long val; @@ -274,8 +332,7 @@ static ssize_t mag3110_dr_mode_store(struct device *dev, if ((strict_strtoul(buf, 10, &val) < 0) || (val > 7)) return -EINVAL; - client = to_i2c_client(dev); - + client = mag3110_pdata->client; reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) & ~MAG3110_DR_MODE_MASK; reg |= (val << MAG3110_DR_MODE_OFFSET); @@ -288,11 +345,35 @@ 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) +{ + int val; + mutex_lock(&mag3110_lock); + val = mag3110_pdata->position; + mutex_unlock(&mag3110_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) +{ + int position; + position = simple_strtoul(buf, NULL, 10); + mutex_lock(&mag3110_lock); + mag3110_pdata->position = position; + mutex_unlock(&mag3110_lock); + return count; +} +static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, + mag3110_position_show, mag3110_position_store); static struct attribute *mag3110_attributes[] = { &dev_attr_enable.attr, &dev_attr_dr_mode.attr, + &dev_attr_position.attr, NULL }; @@ -301,7 +382,7 @@ static const struct attribute_group mag3110_attr_group = { }; 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; @@ -310,9 +391,9 @@ static int __devinit mag3110_probe(struct i2c_client *client, 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"); @@ -320,30 +401,19 @@ 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) return -ENOMEM; data->client = client; i2c_set_clientdata(client, data); - - /*create device group in sysfs as user interface */ - ret = sysfs_create_group(&client->dev.kobj, &mag3110_attr_group); - if (ret) { - dev_err(&client->dev, "create device file failed!\n"); - ret = -EINVAL; - goto error_kfree; - } - /* Init queue */ init_waitqueue_head(&data->waitq); data->hwmon_dev = hwmon_device_register(&client->dev); - data->stop_polling = false; if (IS_ERR(data->hwmon_dev)) { dev_err(&client->dev, "hwmon register failed!\n"); ret = PTR_ERR(data->hwmon_dev); @@ -364,7 +434,6 @@ static int __devinit mag3110_probe(struct i2c_client *client, idev->name = MAG3110_DRV_NAME; 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); @@ -374,58 +443,56 @@ static int __devinit mag3110_probe(struct i2c_client *client, goto error_free_poll_dev; } + /*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"); + ret = -EINVAL; + goto error_rm_poll_dev; + } /* 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, idev); if (ret < 0) { dev_err(&client->dev, "failed to register irq %d!\n", - client->irq); - goto error_rm_poll_dev; + client->irq); + goto error_rm_dev_sysfs; } - +#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: + 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); -error_rm_dev_sysfs: - sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); -error_kfree: + kfree(data); mag3110_pdata = NULL; return ret; } -static int mag3110_stop_chip(struct i2c_client *client) -{ - u8 tmp; - tmp = mag3110_read_reg(client, MAG3110_CTRL_REG1); - return mag3110_write_reg(client, - MAG3110_CTRL_REG1, - tmp & ~MAG3110_AC_MASK); -} - -static void mag3110_shutdown(struct i2c_client *client) -{ - mag3110_pdata->stop_polling = true; - mag3110_stop_chip(client); -} - static int __devexit mag3110_remove(struct i2c_client *client) { struct mag3110_data *data; int ret; data = i2c_get_clientdata(client); - ret = mag3110_stop_chip(client); + + data->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); @@ -440,30 +507,31 @@ static int __devexit mag3110_remove(struct i2c_client *client) #ifdef CONFIG_PM static int mag3110_suspend(struct i2c_client *client, pm_message_t mesg) { - int ret; + int ret = 0; struct mag3110_data *data = i2c_get_clientdata(client); - - data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); - ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, - data->ctl_reg1 & ~MAG3110_AC_MASK); + if (data->active == MAG_ACTIVED) { + data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, + data->ctl_reg1 & ~MAG3110_AC_MASK); + } return ret; } static int mag3110_resume(struct i2c_client *client) { - int ret; + int ret = 0; u8 tmp_data[MAG3110_XYZ_DATA_LEN]; struct mag3110_data *data = i2c_get_clientdata(client); + if (data->active == MAG_ACTIVED) { + ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, + data->ctl_reg1); - ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, - data->ctl_reg1); - - if (data->ctl_reg1 & MAG3110_AC_MASK) { - /* Read out MSB data to clear interrupt flag automatically */ - mag3110_read_block_data(client, MAG3110_OUT_X_MSB, + if (data->ctl_reg1 & MAG3110_AC_MASK) { + /* Read out MSB data to clear interrupt automatically*/ + mag3110_read_block_data(client, MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, tmp_data); + } } - return ret; } @@ -472,39 +540,6 @@ static int mag3110_resume(struct i2c_client *client) #define mag3110_resume NULL #endif /* CONFIG_PM */ -#ifdef CONFIG_HAS_EARLYSUSPEND -static void mag3110_early_suspend(struct early_suspend *h) -{ - struct i2c_client *client; - pm_message_t state = { .event = PM_EVENT_SUSPEND }; - - if (!mag3110_pdata) - return -EINVAL; - - client = mag3110_pdata->client; - mag3110_suspend(client, state); - dev_info(&client->dev, "mag3110 early_syspend\n"); -} - -static void mag3110_later_resume(struct early_suspend *h) -{ - struct i2c_client *client; - - if (!mag3110_pdata) - return -EINVAL; - - client = mag3110_pdata->client; - mag3110_resume(client); - dev_info(&client->dev, "mag3110 late_resume\n"); -} - -struct early_suspend mag3110_earlysuspend = { - .level = EARLY_SUSPEND_LEVEL_DISABLE_FB, - .suspend = mag3110_early_suspend, - .resume = mag3110_later_resume, -}; -#endif - static const struct i2c_device_id mag3110_id[] = { {MAG3110_DRV_NAME, 0}, {} @@ -513,33 +548,21 @@ static const struct i2c_device_id mag3110_id[] = { MODULE_DEVICE_TABLE(i2c, mag3110_id); static struct i2c_driver mag3110_driver = { .driver = {.name = MAG3110_DRV_NAME, - .owner = THIS_MODULE,}, -#ifndef CONFIG_HAS_EARLYSUSPEND + .owner = THIS_MODULE,}, .suspend = mag3110_suspend, .resume = mag3110_resume, -#endif .probe = mag3110_probe, .remove = __devexit_p(mag3110_remove), - .shutdown = mag3110_shutdown, .id_table = mag3110_id, }; static int __init mag3110_init(void) { - int ret; - ret = i2c_add_driver(&mag3110_driver); -#ifdef CONFIG_HAS_EARLYSUSPEND - if (!ret) - register_early_suspend(&mag3110_earlysuspend); -#endif - return ret; + return i2c_add_driver(&mag3110_driver); } static void __exit mag3110_exit(void) { -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&mag3110_earlysuspend); -#endif i2c_del_driver(&mag3110_driver); } diff --git a/drivers/hwmon/mxc_mma8451.c b/drivers/hwmon/mxc_mma8451.c index e61e5b4fd22a..d33449566639 100644 --- a/drivers/hwmon/mxc_mma8451.c +++ b/drivers/hwmon/mxc_mma8451.c @@ -36,13 +36,15 @@ #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 10 #define POLL_INTERVAL_MAX 500 #define POLL_INTERVAL 100 #define INPUT_FUZZ 32 #define INPUT_FLAT 32 -#define MODE_CHANGE_DELAY_MS 10 +#define MODE_CHANGE_DELAY_MS 100 #define MMA8451_STATUS_ZYXDR 0x08 #define MMA8451_BUF_SIZE 6 @@ -114,8 +116,8 @@ enum { }; /* 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. + 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, @@ -123,11 +125,17 @@ enum { MODE_8G, }; +enum { + MMA_STANDBY = 0, + MMA_ACTIVED, +}; + /* mma8451 status */ struct mma8451_status { u8 mode; u8 ctl_reg1; - bool stop_poll; + int active; + int position; }; static struct mma8451_status mma_status; @@ -136,7 +144,41 @@ 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) { @@ -145,22 +187,23 @@ static int mma8451_change_mode(struct i2c_client *client, int mode) /* 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); + 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); + mma_status.mode); if (result < 0) goto out; /* Set the Active bit and Data rate in CTRL Reg 1 */ - mma_status.ctl_reg1 |= 0x1; + mma_status.active = MMA_STANDBY; + mma_status.ctl_reg1 |= (DR_80_0MS<<3); result = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1); + mma_status.ctl_reg1); if (result < 0) goto out; @@ -179,7 +222,7 @@ static int mma8451_read_data(short *x, short *y, short *z) /* 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); + 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; @@ -189,22 +232,6 @@ static int mma8451_read_data(short *x, short *y, short *z) *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]; - - /* Drop the lower 2 bits as its 14-bit sample */ - *x = (short)(*x) >> 2; - *y = (short)(*y) >> 2; - *z = (short)(*z) >> 2; - - 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; } @@ -214,7 +241,8 @@ static void report_abs(void) 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); @@ -227,7 +255,7 @@ static void report_abs(void) /* 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); @@ -239,33 +267,118 @@ out: static void mma8451_dev_poll(struct input_polled_dev *dev) { - if (!mma_status.stop_poll) - report_abs(); + 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); + ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, + val|0x01); + 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) + const struct i2c_device_id *id) { - int result; + int result, client_id; struct input_dev *idev; struct i2c_adapter *adapter; mma8451_i2c_client = client; - mma_status.stop_poll = false; - adapter = to_i2c_adapter(client->dev.parent); result = i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA); + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA); if (!result) goto err_out; - result = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I); + client_id = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I); - if (result != MMA8451_ID) { + 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!\n", result, - MMA8451_ID); + "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; } @@ -274,7 +387,7 @@ static int __devinit mma8451_probe(struct i2c_client *client, result = mma8451_change_mode(client, senstive_mode); if (result) { dev_err(&client->dev, - "error when init mma8451 chip:(%d)\n", result); + "error when init mma8451 chip:(%d)\n", result); goto err_out; } @@ -282,7 +395,7 @@ static int __devinit mma8451_probe(struct i2c_client *client, if (!hwmon_dev) { result = -ENOMEM; dev_err(&client->dev, - "error when register hwmon device\n"); + "error when register hwmon device\n"); goto err_out; } @@ -310,7 +423,13 @@ static int __devinit mma8451_probe(struct i2c_client *client, 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); @@ -322,10 +441,14 @@ err_out: static int mma8451_stop_chip(struct i2c_client *client) { - mma_status.ctl_reg1 = i2c_smbus_read_byte_data(client, - MMA8451_CTRL_REG1); - return i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1 & 0xFE); + 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) @@ -337,21 +460,6 @@ static int __devexit mma8451_remove(struct i2c_client *client) return ret; } -void mma8451_shutdown(struct i2c_client *client) -{ - int ret; - - /* first, stop polling since this chip will pull sda low if - * reboot during poweroff/reboot, add stop function here to - * prevent this - */ - mma_status.stop_poll = true; - - ret = mma8451_stop_chip(client); - if (ret < 0) - dev_err(&client->dev, "stop chip failed:%d\n", ret); -} - #ifdef CONFIG_PM_SLEEP static int mma8451_suspend(struct device *dev) { @@ -362,10 +470,13 @@ static int mma8451_suspend(struct device *dev) 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; - return i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, - mma_status.ctl_reg1); } #endif @@ -377,13 +488,12 @@ 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, - }, + .name = MMA8451_DRV_NAME, + .owner = THIS_MODULE, + .pm = &mma8451_pm_ops, + }, .probe = mma8451_probe, .remove = __devexit_p(mma8451_remove), - .shutdown = mma8451_shutdown, .id_table = mma8451_id, }; -- cgit v1.2.3