Loading Documentation/devicetree/bindings/input/misc/mma8x5x.txt +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ Optional properties: - interrupt-parent : parent of interrupt. - interrupts : sensor signal interrupt to indicate new data ready or a motion is detected. - fsl,use-interrupt : to enable interrupt mode. - fsl,irq-gpio : First irq gpio which is to provide interrupts to host, same as "interrupts" node. It will also contain active low or active high information. Loading @@ -36,4 +37,5 @@ Example: vio-supply = <&pm8110_l14>; fsl,sensors-position = <5>; fsl,irq-gpio = <&msmgpio 0x81 0x02>; fsl,use-interrupt; }; No newline at end of file arch/arm/mach-msm/board-8610-gpiomux.c +14 −1 Original line number Diff line number Diff line /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -450,6 +450,12 @@ static struct gpiomux_setting cam_settings[] = { }, }; static struct gpiomux_setting accel_interrupt_config = { .func = GPIOMUX_FUNC_GPIO, .drv = GPIOMUX_DRV_6MA, .pull = GPIOMUX_PULL_DOWN, }; static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = { { .gpio = 8, /* CAM1_STANDBY_N */ Loading @@ -458,6 +464,13 @@ static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = { [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1], }, }, { .gpio = 81, /*ACCEL_INT1 */ .settings = { [GPIOMUX_ACTIVE] = &accel_interrupt_config, [GPIOMUX_SUSPENDED] = &accel_interrupt_config, }, }, }; static struct msm_gpiomux_config msm_sensor_configs[] __initdata = { Loading drivers/input/misc/mma8x5x.c +312 −57 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <linux/sensors.h> #include <linux/regulator/consumer.h> #include <linux/of_gpio.h> #include <linux/irq.h> #define ACCEL_INPUT_DEV_NAME "accelerometer" #define MMA8451_ID 0x1A Loading @@ -41,7 +42,7 @@ /* Polling delay in msecs */ #define POLL_INTERVAL_MIN 1 #define POLL_INTERVAL_MAX 10000 #define POLL_INTERVAL 100 #define POLL_INTERVAL 100 /* msecs */ /* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */ #define POLL_STOP_TIME 10000 Loading Loading @@ -74,6 +75,13 @@ static struct sensors_classdev sensors_cdev = { .sensors_poll_delay = NULL, }; #define MMA_WAKE_CFG 0x02 #define MMA_INT_EN_DRDY 0x01 #define MMA_INT_EN_FF_MT 0x04 #define MMA_INT_ROUTING_CFG 0x01 #define MMA_POWER_CFG_MASK 0xFE struct sensor_regulator { struct regulator *vreg; const char *name; Loading @@ -86,6 +94,23 @@ static struct sensor_regulator mma_vreg[] = { {NULL, "vio", 1800000, 1800000}, }; struct mma_odr_selection_table { u32 odr_cfg; u32 delay_bottom; u32 delay_top; }; static struct mma_odr_selection_table mma_odr_table[] = { {0x00, 0, 1500}, {0x08, 1501, 3500}, {0x10, 3501, 7500}, {0x18, 7501, 15000}, {0x20, 15001, 50000}, {0x28, 50001, 120000}, {0x30, 120001, 400000}, {0x38, 400001, 10000000}, }; /* register enum for mma8x5x registers */ enum { MMA8X5X_STATUS = 0x00, Loading Loading @@ -165,6 +190,7 @@ struct mma8x5x_data_axis { struct mma8x5x_data { struct i2c_client *client; struct input_polled_dev *poll_dev; struct input_dev *idev; struct mutex data_lock; struct sensors_classdev cdev; int active; Loading @@ -174,6 +200,7 @@ struct mma8x5x_data { int int_pin; u32 int_flags; int poll_delay; bool use_int; }; /* Addresses scanned */ static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END}; Loading Loading @@ -202,7 +229,7 @@ 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} }, }; static struct mma8x5x_data *drv_data; static int mma8x5x_config_regulator(struct i2c_client *client, bool on) { int rc = 0, i; Loading Loading @@ -348,6 +375,98 @@ err_out: return -EIO; } static int mma8x5x_delay2odr(u32 delay_ms) { int i; u32 delay_us; delay_us = delay_ms * 1000; for (i = 0; i < sizeof(mma_odr_table) / sizeof(struct mma_odr_selection_table); i++) { if ((delay_us <= mma_odr_table[i].delay_top) && (delay_us > mma_odr_table[i].delay_bottom)) break; } if (i < sizeof(mma_odr_table) / sizeof(struct mma_odr_selection_table)) return mma_odr_table[i].odr_cfg; else return -EINVAL; } static int mma8x5x_device_set_odr(struct i2c_client *client, u32 delay_ms) { int result; u8 val; result = mma8x5x_delay2odr(delay_ms); if (result < 0) goto out; val = (u8)result; result = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); if (result < 0) goto out; val = (u8)result | val; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, (val & MMA_POWER_CFG_MASK)); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4, MMA_INT_EN_DRDY); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5, MMA_INT_ROUTING_CFG); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val); if (result < 0) goto out; return 0; out: dev_err(&client->dev, "error when set ODR mma8x5x:(%d)", result); return result; } static int mma8x5x_device_int_init(struct i2c_client *client) { struct mma8x5x_data *pdata = i2c_get_clientdata(client); int result; int val; result = mma8x5x_device_set_odr(client, pdata->poll_delay); if (result < 0) goto out; val = MMA_WAKE_CFG; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG3, val); if (result < 0) goto out; val = MMA_INT_EN_DRDY; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4, val); if (result < 0) goto out; val = MMA_INT_ROUTING_CFG; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5, val); if (result < 0) goto out; return 0; out: dev_err(&client->dev, "error when int init mma8x5x:(%d)", result); return result; } static int mma8x5x_read_data(struct i2c_client *client, struct mma8x5x_data_axis *data) { Loading Loading @@ -396,6 +515,28 @@ static void mma8x5x_dev_poll(struct input_polled_dev *dev) mma8x5x_report_data(pdata); } static irqreturn_t mma8x5x_interrupt(int vec, void *data) { struct i2c_client *client = (struct i2c_client *)data; struct mma8x5x_data *pdata = i2c_get_clientdata(client); struct input_dev *idev = pdata->idev; struct mma8x5x_data_axis data_axis; mutex_lock(&pdata->data_lock); if (mma8x5x_read_data(pdata->client, &data_axis) != 0) goto out; mma8x5x_data_convert(pdata, &data_axis); input_report_abs(idev, ABS_X, data_axis.x); input_report_abs(idev, ABS_Y, data_axis.y); input_report_abs(idev, ABS_Z, data_axis.z); input_sync(idev); out: mutex_unlock(&pdata->data_lock); return IRQ_HANDLED; } static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev, unsigned int enable) { Loading @@ -416,6 +557,9 @@ static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev, if (ret) goto err_failed; ret = mma8x5x_device_set_odr(client, pdata->poll_delay); if (ret) goto err_failed; pdata->active &= ~MMA_SHUTTEDDOWN; } if (pdata->active == MMA_STANDBY) { Loading Loading @@ -472,12 +616,17 @@ err_failed: 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; struct mma8x5x_data *pdata = drv_data; struct i2c_client *client; u8 val; int enable; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } client = pdata->client; mutex_lock(&pdata->data_lock); val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); if ((val & 0x01) && pdata->active == MMA_ACTIVED) Loading @@ -492,11 +641,16 @@ 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 mma8x5x_data *pdata = drv_data; struct i2c_client *client; int ret; unsigned long enable; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } client = pdata->client; ret = kstrtoul(buf, 10, &enable); if (ret) return ret; Loading @@ -509,9 +663,13 @@ static ssize_t mma8x5x_enable_store(struct device *dev, 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); struct mma8x5x_data *pdata = drv_data; int position = 0; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } mutex_lock(&pdata->data_lock); position = pdata->position ; mutex_unlock(&pdata->data_lock); Loading @@ -522,10 +680,14 @@ 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); struct mma8x5x_data *pdata = drv_data; int position; int ret; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } ret = kstrtoint(buf, 10, &position); if (ret) return ret; Loading @@ -540,11 +702,21 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev, { struct mma8x5x_data *pdata = container_of(sensors_cdev, struct mma8x5x_data, cdev); int ret; if (pdata->use_int) { mutex_lock(&pdata->data_lock); pdata->poll_delay = delay_ms; ret = mma8x5x_device_set_odr(pdata->client, delay_ms); mutex_unlock(&pdata->data_lock); if (ret < 0) return ret; } else { mutex_lock(&pdata->data_lock); pdata->poll_delay = delay_ms; pdata->poll_dev->poll_interval = pdata->poll_delay; mutex_unlock(&pdata->data_lock); } return 0; } Loading @@ -552,8 +724,13 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev, static ssize_t mma8x5x_poll_delay_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 mma8x5x_data *pdata = drv_data; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } return snprintf(buf, PAGE_SIZE, "%d\n", pdata->poll_delay); } Loading @@ -561,19 +738,23 @@ static ssize_t mma8x5x_poll_delay_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 interval; struct mma8x5x_data *pdata = drv_data; int delay; int ret; ret = kstrtoint(buf, 10, &interval); if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } ret = kstrtoint(buf, 10, &delay); if (ret) return ret; if (interval <= POLL_INTERVAL_MIN) interval = POLL_INTERVAL_MIN; if (interval > POLL_INTERVAL_MAX) interval = POLL_INTERVAL_MAX; if (delay <= POLL_INTERVAL_MIN) delay = POLL_INTERVAL_MIN; if (delay > POLL_INTERVAL_MAX) delay = POLL_INTERVAL_MAX; mma8x5x_poll_delay_set(&pdata->cdev, interval); mma8x5x_poll_delay_set(&pdata->cdev, delay); return count; } Loading Loading @@ -632,6 +813,8 @@ static int mma8x5x_parse_dt(struct device *dev, struct mma8x5x_data *data) return rc; } data->use_int = of_property_read_bool(np, "fsl,use-interrupt"); return 0; } Loading Loading @@ -676,7 +859,7 @@ static int mma8x5x_probe(struct i2c_client *client, if (client->dev.of_node) { result = mma8x5x_parse_dt(&client->dev, pdata); if (result) return result; goto err_parse_dt; } else { pdata->position = CONFIG_SENSORS_MMA_POSITION; pdata->int_pin = -1; Loading @@ -684,15 +867,69 @@ static int mma8x5x_probe(struct i2c_client *client, } /* Initialize the MMA8X5X chip */ drv_data = pdata; pdata->client = client; pdata->chip_id = chip_id; pdata->mode = MODE_2G; pdata->poll_delay = POLL_INTERVAL; pdata->poll_delay = POLL_STOP_TIME; pdata->poll_dev = NULL; mutex_init(&pdata->data_lock); i2c_set_clientdata(client, pdata); /* Initialize the MMA8X5X chip */ mma8x5x_device_init(client); if (pdata->use_int) { if (pdata->int_pin >= 0) client->irq = gpio_to_irq(pdata->int_pin); if (gpio_is_valid(pdata->int_pin)) { result = gpio_request(pdata->int_pin, "mma8x5x_irq_gpio"); if (result) { dev_err(&client->dev, "irq gpio(%d) request failed", pdata->int_pin); goto err_request_gpio; } result = gpio_direction_input(pdata->int_pin); if (result) { dev_err(&client->dev, "set_direction for irq gpio failed\n"); goto err_set_direction; } } idev = input_allocate_device(); if (!idev) { result = -ENOMEM; dev_err(&client->dev, "alloc input device failed!\n"); goto err_alloc_poll_device; } input_set_drvdata(idev, pdata); idev->name = ACCEL_INPUT_DEV_NAME; 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); result = input_register_device(idev); if (result) { dev_err(&client->dev, "register input device failed!\n"); goto err_register_device; } pdata->idev = idev; device_init_wakeup(&client->dev, true); enable_irq_wake(client->irq); result = request_threaded_irq(client->irq, NULL, mma8x5x_interrupt, IRQ_TYPE_EDGE_RISING | IRQF_ONESHOT | IRQF_NO_SUSPEND, ACCEL_INPUT_DEV_NAME, (void *)client); if (result) { dev_err(&client->dev, "Could not allocate irq(%d) !\n", client->irq); goto err_register_irq; } mma8x5x_device_int_init(client); } else { /* create the input poll device */ poll_dev = input_allocate_polled_device(); if (!poll_dev) { Loading @@ -700,6 +937,8 @@ static int mma8x5x_probe(struct i2c_client *client, dev_err(&client->dev, "alloc poll device failed!\n"); goto err_alloc_poll_device; } pdata->poll_dev = poll_dev; pdata->idev = NULL; poll_dev->poll = mma8x5x_dev_poll; poll_dev->poll_interval = POLL_STOP_TIME; poll_dev->poll_interval_min = POLL_INTERVAL_MIN; Loading @@ -713,11 +952,11 @@ static int mma8x5x_probe(struct i2c_client *client, 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; goto err_register_device; } } result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group); if (result) { Loading @@ -727,7 +966,7 @@ static int mma8x5x_probe(struct i2c_client *client, } pdata->cdev = sensors_cdev; pdata->cdev.min_delay = POLL_INTERVAL_MIN * 1000; pdata->cdev.delay_msec = poll_dev->poll_interval; pdata->cdev.delay_msec = pdata->poll_delay; pdata->cdev.sensors_enable = mma8x5x_enable_set; pdata->cdev.sensors_poll_delay = mma8x5x_poll_delay_set; result = sensors_classdev_register(&client->dev, &pdata->cdev); Loading @@ -745,9 +984,20 @@ err_create_class_sysfs: sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group); err_create_sysfs: input_unregister_polled_device(pdata->poll_dev); err_register_polled_device: input_free_polled_device(poll_dev); err_register_irq: if (pdata->use_int) device_init_wakeup(&client->dev, false); err_register_device: if (pdata->use_int) input_free_device(idev); else input_free_polled_device(pdata->poll_dev); err_alloc_poll_device: err_set_direction: if (gpio_is_valid(pdata->int_pin) && pdata->use_int) gpio_free(pdata->int_pin); err_request_gpio: err_parse_dt: kfree(pdata); err_out: mma8x5x_config_regulator(client, 0); Loading @@ -773,6 +1023,9 @@ 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->use_int && pdata->active == MMA_ACTIVED) return 0; if (pdata->active == MMA_ACTIVED) mma8x5x_device_stop(client); if (pdata->active & MMA_SHUTTEDDOWN) Loading @@ -789,6 +1042,8 @@ static int mma8x5x_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct mma8x5x_data *pdata = i2c_get_clientdata(client); if (pdata->use_int && pdata->active == MMA_ACTIVED) return 0; /* No need to power on while device is shutdowned from standby state */ if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY)) return 0; Loading Loading
Documentation/devicetree/bindings/input/misc/mma8x5x.txt +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ Optional properties: - interrupt-parent : parent of interrupt. - interrupts : sensor signal interrupt to indicate new data ready or a motion is detected. - fsl,use-interrupt : to enable interrupt mode. - fsl,irq-gpio : First irq gpio which is to provide interrupts to host, same as "interrupts" node. It will also contain active low or active high information. Loading @@ -36,4 +37,5 @@ Example: vio-supply = <&pm8110_l14>; fsl,sensors-position = <5>; fsl,irq-gpio = <&msmgpio 0x81 0x02>; fsl,use-interrupt; }; No newline at end of file
arch/arm/mach-msm/board-8610-gpiomux.c +14 −1 Original line number Diff line number Diff line /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -450,6 +450,12 @@ static struct gpiomux_setting cam_settings[] = { }, }; static struct gpiomux_setting accel_interrupt_config = { .func = GPIOMUX_FUNC_GPIO, .drv = GPIOMUX_DRV_6MA, .pull = GPIOMUX_PULL_DOWN, }; static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = { { .gpio = 8, /* CAM1_STANDBY_N */ Loading @@ -458,6 +464,13 @@ static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = { [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1], }, }, { .gpio = 81, /*ACCEL_INT1 */ .settings = { [GPIOMUX_ACTIVE] = &accel_interrupt_config, [GPIOMUX_SUSPENDED] = &accel_interrupt_config, }, }, }; static struct msm_gpiomux_config msm_sensor_configs[] __initdata = { Loading
drivers/input/misc/mma8x5x.c +312 −57 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <linux/sensors.h> #include <linux/regulator/consumer.h> #include <linux/of_gpio.h> #include <linux/irq.h> #define ACCEL_INPUT_DEV_NAME "accelerometer" #define MMA8451_ID 0x1A Loading @@ -41,7 +42,7 @@ /* Polling delay in msecs */ #define POLL_INTERVAL_MIN 1 #define POLL_INTERVAL_MAX 10000 #define POLL_INTERVAL 100 #define POLL_INTERVAL 100 /* msecs */ /* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */ #define POLL_STOP_TIME 10000 Loading Loading @@ -74,6 +75,13 @@ static struct sensors_classdev sensors_cdev = { .sensors_poll_delay = NULL, }; #define MMA_WAKE_CFG 0x02 #define MMA_INT_EN_DRDY 0x01 #define MMA_INT_EN_FF_MT 0x04 #define MMA_INT_ROUTING_CFG 0x01 #define MMA_POWER_CFG_MASK 0xFE struct sensor_regulator { struct regulator *vreg; const char *name; Loading @@ -86,6 +94,23 @@ static struct sensor_regulator mma_vreg[] = { {NULL, "vio", 1800000, 1800000}, }; struct mma_odr_selection_table { u32 odr_cfg; u32 delay_bottom; u32 delay_top; }; static struct mma_odr_selection_table mma_odr_table[] = { {0x00, 0, 1500}, {0x08, 1501, 3500}, {0x10, 3501, 7500}, {0x18, 7501, 15000}, {0x20, 15001, 50000}, {0x28, 50001, 120000}, {0x30, 120001, 400000}, {0x38, 400001, 10000000}, }; /* register enum for mma8x5x registers */ enum { MMA8X5X_STATUS = 0x00, Loading Loading @@ -165,6 +190,7 @@ struct mma8x5x_data_axis { struct mma8x5x_data { struct i2c_client *client; struct input_polled_dev *poll_dev; struct input_dev *idev; struct mutex data_lock; struct sensors_classdev cdev; int active; Loading @@ -174,6 +200,7 @@ struct mma8x5x_data { int int_pin; u32 int_flags; int poll_delay; bool use_int; }; /* Addresses scanned */ static const unsigned short normal_i2c[] = {0x1c, 0x1d, I2C_CLIENT_END}; Loading Loading @@ -202,7 +229,7 @@ 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} }, }; static struct mma8x5x_data *drv_data; static int mma8x5x_config_regulator(struct i2c_client *client, bool on) { int rc = 0, i; Loading Loading @@ -348,6 +375,98 @@ err_out: return -EIO; } static int mma8x5x_delay2odr(u32 delay_ms) { int i; u32 delay_us; delay_us = delay_ms * 1000; for (i = 0; i < sizeof(mma_odr_table) / sizeof(struct mma_odr_selection_table); i++) { if ((delay_us <= mma_odr_table[i].delay_top) && (delay_us > mma_odr_table[i].delay_bottom)) break; } if (i < sizeof(mma_odr_table) / sizeof(struct mma_odr_selection_table)) return mma_odr_table[i].odr_cfg; else return -EINVAL; } static int mma8x5x_device_set_odr(struct i2c_client *client, u32 delay_ms) { int result; u8 val; result = mma8x5x_delay2odr(delay_ms); if (result < 0) goto out; val = (u8)result; result = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); if (result < 0) goto out; val = (u8)result | val; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, (val & MMA_POWER_CFG_MASK)); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4, MMA_INT_EN_DRDY); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5, MMA_INT_ROUTING_CFG); if (result < 0) goto out; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val); if (result < 0) goto out; return 0; out: dev_err(&client->dev, "error when set ODR mma8x5x:(%d)", result); return result; } static int mma8x5x_device_int_init(struct i2c_client *client) { struct mma8x5x_data *pdata = i2c_get_clientdata(client); int result; int val; result = mma8x5x_device_set_odr(client, pdata->poll_delay); if (result < 0) goto out; val = MMA_WAKE_CFG; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG3, val); if (result < 0) goto out; val = MMA_INT_EN_DRDY; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG4, val); if (result < 0) goto out; val = MMA_INT_ROUTING_CFG; result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG5, val); if (result < 0) goto out; return 0; out: dev_err(&client->dev, "error when int init mma8x5x:(%d)", result); return result; } static int mma8x5x_read_data(struct i2c_client *client, struct mma8x5x_data_axis *data) { Loading Loading @@ -396,6 +515,28 @@ static void mma8x5x_dev_poll(struct input_polled_dev *dev) mma8x5x_report_data(pdata); } static irqreturn_t mma8x5x_interrupt(int vec, void *data) { struct i2c_client *client = (struct i2c_client *)data; struct mma8x5x_data *pdata = i2c_get_clientdata(client); struct input_dev *idev = pdata->idev; struct mma8x5x_data_axis data_axis; mutex_lock(&pdata->data_lock); if (mma8x5x_read_data(pdata->client, &data_axis) != 0) goto out; mma8x5x_data_convert(pdata, &data_axis); input_report_abs(idev, ABS_X, data_axis.x); input_report_abs(idev, ABS_Y, data_axis.y); input_report_abs(idev, ABS_Z, data_axis.z); input_sync(idev); out: mutex_unlock(&pdata->data_lock); return IRQ_HANDLED; } static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev, unsigned int enable) { Loading @@ -416,6 +557,9 @@ static int mma8x5x_enable_set(struct sensors_classdev *sensors_cdev, if (ret) goto err_failed; ret = mma8x5x_device_set_odr(client, pdata->poll_delay); if (ret) goto err_failed; pdata->active &= ~MMA_SHUTTEDDOWN; } if (pdata->active == MMA_STANDBY) { Loading Loading @@ -472,12 +616,17 @@ err_failed: 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; struct mma8x5x_data *pdata = drv_data; struct i2c_client *client; u8 val; int enable; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } client = pdata->client; mutex_lock(&pdata->data_lock); val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1); if ((val & 0x01) && pdata->active == MMA_ACTIVED) Loading @@ -492,11 +641,16 @@ 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 mma8x5x_data *pdata = drv_data; struct i2c_client *client; int ret; unsigned long enable; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } client = pdata->client; ret = kstrtoul(buf, 10, &enable); if (ret) return ret; Loading @@ -509,9 +663,13 @@ static ssize_t mma8x5x_enable_store(struct device *dev, 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); struct mma8x5x_data *pdata = drv_data; int position = 0; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } mutex_lock(&pdata->data_lock); position = pdata->position ; mutex_unlock(&pdata->data_lock); Loading @@ -522,10 +680,14 @@ 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); struct mma8x5x_data *pdata = drv_data; int position; int ret; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } ret = kstrtoint(buf, 10, &position); if (ret) return ret; Loading @@ -540,11 +702,21 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev, { struct mma8x5x_data *pdata = container_of(sensors_cdev, struct mma8x5x_data, cdev); int ret; if (pdata->use_int) { mutex_lock(&pdata->data_lock); pdata->poll_delay = delay_ms; ret = mma8x5x_device_set_odr(pdata->client, delay_ms); mutex_unlock(&pdata->data_lock); if (ret < 0) return ret; } else { mutex_lock(&pdata->data_lock); pdata->poll_delay = delay_ms; pdata->poll_dev->poll_interval = pdata->poll_delay; mutex_unlock(&pdata->data_lock); } return 0; } Loading @@ -552,8 +724,13 @@ static int mma8x5x_poll_delay_set(struct sensors_classdev *sensors_cdev, static ssize_t mma8x5x_poll_delay_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 mma8x5x_data *pdata = drv_data; if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } return snprintf(buf, PAGE_SIZE, "%d\n", pdata->poll_delay); } Loading @@ -561,19 +738,23 @@ static ssize_t mma8x5x_poll_delay_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 interval; struct mma8x5x_data *pdata = drv_data; int delay; int ret; ret = kstrtoint(buf, 10, &interval); if (!pdata) { dev_err(dev, "Invalid driver private data!"); return -EINVAL; } ret = kstrtoint(buf, 10, &delay); if (ret) return ret; if (interval <= POLL_INTERVAL_MIN) interval = POLL_INTERVAL_MIN; if (interval > POLL_INTERVAL_MAX) interval = POLL_INTERVAL_MAX; if (delay <= POLL_INTERVAL_MIN) delay = POLL_INTERVAL_MIN; if (delay > POLL_INTERVAL_MAX) delay = POLL_INTERVAL_MAX; mma8x5x_poll_delay_set(&pdata->cdev, interval); mma8x5x_poll_delay_set(&pdata->cdev, delay); return count; } Loading Loading @@ -632,6 +813,8 @@ static int mma8x5x_parse_dt(struct device *dev, struct mma8x5x_data *data) return rc; } data->use_int = of_property_read_bool(np, "fsl,use-interrupt"); return 0; } Loading Loading @@ -676,7 +859,7 @@ static int mma8x5x_probe(struct i2c_client *client, if (client->dev.of_node) { result = mma8x5x_parse_dt(&client->dev, pdata); if (result) return result; goto err_parse_dt; } else { pdata->position = CONFIG_SENSORS_MMA_POSITION; pdata->int_pin = -1; Loading @@ -684,15 +867,69 @@ static int mma8x5x_probe(struct i2c_client *client, } /* Initialize the MMA8X5X chip */ drv_data = pdata; pdata->client = client; pdata->chip_id = chip_id; pdata->mode = MODE_2G; pdata->poll_delay = POLL_INTERVAL; pdata->poll_delay = POLL_STOP_TIME; pdata->poll_dev = NULL; mutex_init(&pdata->data_lock); i2c_set_clientdata(client, pdata); /* Initialize the MMA8X5X chip */ mma8x5x_device_init(client); if (pdata->use_int) { if (pdata->int_pin >= 0) client->irq = gpio_to_irq(pdata->int_pin); if (gpio_is_valid(pdata->int_pin)) { result = gpio_request(pdata->int_pin, "mma8x5x_irq_gpio"); if (result) { dev_err(&client->dev, "irq gpio(%d) request failed", pdata->int_pin); goto err_request_gpio; } result = gpio_direction_input(pdata->int_pin); if (result) { dev_err(&client->dev, "set_direction for irq gpio failed\n"); goto err_set_direction; } } idev = input_allocate_device(); if (!idev) { result = -ENOMEM; dev_err(&client->dev, "alloc input device failed!\n"); goto err_alloc_poll_device; } input_set_drvdata(idev, pdata); idev->name = ACCEL_INPUT_DEV_NAME; 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); result = input_register_device(idev); if (result) { dev_err(&client->dev, "register input device failed!\n"); goto err_register_device; } pdata->idev = idev; device_init_wakeup(&client->dev, true); enable_irq_wake(client->irq); result = request_threaded_irq(client->irq, NULL, mma8x5x_interrupt, IRQ_TYPE_EDGE_RISING | IRQF_ONESHOT | IRQF_NO_SUSPEND, ACCEL_INPUT_DEV_NAME, (void *)client); if (result) { dev_err(&client->dev, "Could not allocate irq(%d) !\n", client->irq); goto err_register_irq; } mma8x5x_device_int_init(client); } else { /* create the input poll device */ poll_dev = input_allocate_polled_device(); if (!poll_dev) { Loading @@ -700,6 +937,8 @@ static int mma8x5x_probe(struct i2c_client *client, dev_err(&client->dev, "alloc poll device failed!\n"); goto err_alloc_poll_device; } pdata->poll_dev = poll_dev; pdata->idev = NULL; poll_dev->poll = mma8x5x_dev_poll; poll_dev->poll_interval = POLL_STOP_TIME; poll_dev->poll_interval_min = POLL_INTERVAL_MIN; Loading @@ -713,11 +952,11 @@ static int mma8x5x_probe(struct i2c_client *client, 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; goto err_register_device; } } result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group); if (result) { Loading @@ -727,7 +966,7 @@ static int mma8x5x_probe(struct i2c_client *client, } pdata->cdev = sensors_cdev; pdata->cdev.min_delay = POLL_INTERVAL_MIN * 1000; pdata->cdev.delay_msec = poll_dev->poll_interval; pdata->cdev.delay_msec = pdata->poll_delay; pdata->cdev.sensors_enable = mma8x5x_enable_set; pdata->cdev.sensors_poll_delay = mma8x5x_poll_delay_set; result = sensors_classdev_register(&client->dev, &pdata->cdev); Loading @@ -745,9 +984,20 @@ err_create_class_sysfs: sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group); err_create_sysfs: input_unregister_polled_device(pdata->poll_dev); err_register_polled_device: input_free_polled_device(poll_dev); err_register_irq: if (pdata->use_int) device_init_wakeup(&client->dev, false); err_register_device: if (pdata->use_int) input_free_device(idev); else input_free_polled_device(pdata->poll_dev); err_alloc_poll_device: err_set_direction: if (gpio_is_valid(pdata->int_pin) && pdata->use_int) gpio_free(pdata->int_pin); err_request_gpio: err_parse_dt: kfree(pdata); err_out: mma8x5x_config_regulator(client, 0); Loading @@ -773,6 +1023,9 @@ 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->use_int && pdata->active == MMA_ACTIVED) return 0; if (pdata->active == MMA_ACTIVED) mma8x5x_device_stop(client); if (pdata->active & MMA_SHUTTEDDOWN) Loading @@ -789,6 +1042,8 @@ static int mma8x5x_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct mma8x5x_data *pdata = i2c_get_clientdata(client); if (pdata->use_int && pdata->active == MMA_ACTIVED) return 0; /* No need to power on while device is shutdowned from standby state */ if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY)) return 0; Loading