lkml.org 
[lkml]   [2011]   [Oct]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
Date
SubjectRe: [PATCHv4 5/6] Input: add CMR3000 gyrsocope driver
Hello Grant

It is similar to the crm, because they came from the same
manufacturer and they share some commands, but that is all.

the crm is a gyroscope and the cma is an accelerometer. I tried to put
both drivers together and the result was a bit too messy, I think it
is easier to understand as two separate drivers, but if you believe
they have to live together and help me making it more understandable,
I have to problem in coding it.

Regards!

On Mon, Oct 24, 2011 at 23:40, Grant Likely <grant.likely@secretlab.ca> wrote:
> On Mon, Oct 24, 2011 at 10:21:15PM +0200, Ricardo Ribalda Delgado wrote:
>> Add support for CMR3000 Tri-axis accelerometer. CMR3000 supports both
>> I2C/SPI bus communication, currently the driver supports SPI
>> communication, since I have no hardware to test the I2C communication.
>
> How different is this driver from the cma3000?  Is it a cut and paste job?
>
> g.
>
>>
>> ---
>>
>> v4: Fixes suggested by Dmitry Torokhov
>>       -Do not release the input device until the irq has been released
>>
>> v3: Fixes suggested by Jonathan Cameron
>>       -Support DT
>>       -Cleaner spi read/write
>>
>> v2: Fixes suggested by Jonathan Cameron
>>       -Code Stype
>>       -Check pdata!=NULL
>>       -SPI align Cacheline
>>       -More clear based on
>>       -%s/set/write/
>>       -%s/accl/gyro/
>>       -remove READ/SET macros
>>
>> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
>> ---
>>  drivers/input/misc/Kconfig           |   24 ++
>>  drivers/input/misc/Makefile          |    2 +
>>  drivers/input/misc/cmr3000_d0x.c     |  426 ++++++++++++++++++++++++++++++++++
>>  drivers/input/misc/cmr3000_d0x.h     |   45 ++++
>>  drivers/input/misc/cmr3000_d0x_spi.c |  144 ++++++++++++
>>  include/linux/input/cmr3000.h        |   54 +++++
>>  6 files changed, 695 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/input/misc/cmr3000_d0x.c
>>  create mode 100644 drivers/input/misc/cmr3000_d0x.h
>>  create mode 100644 drivers/input/misc/cmr3000_d0x_spi.c
>>  create mode 100644 include/linux/input/cmr3000.h
>>
>> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
>> index b9f2e93..7c56f94 100644
>> --- a/drivers/input/misc/Kconfig
>> +++ b/drivers/input/misc/Kconfig
>> @@ -524,6 +524,30 @@ config INPUT_CMA3000_SPI
>>         To compile this driver as a module, choose M here: the
>>         module will be called cma3000_d0x_spi.
>>
>> +config INPUT_CMR3000
>> +     tristate "VTI CMR3000 Tri-axis gyroscope"
>> +     help
>> +       Say Y here if you want to use VTI CMR3000_D0x Gyroscope
>> +       driver
>> +
>> +       This driver currently only supports SPI interface to the
>> +       controller. Also select the SPI method.
>> +
>> +       If unsure, say N
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called cmr3000_d0x.
>> +
>> +config INPUT_CMR3000_SPI
>> +     tristate "Support SPI bus connection"
>> +     depends on INPUT_CMR3000 && SPI
>> +     help
>> +       Say Y here if you want to use VTI CMR3000_D0x Gyroscope
>> +       through SPI interface.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called cmr3000_d0x_spi.
>> +
>>  config INPUT_XEN_KBDDEV_FRONTEND
>>       tristate "Xen virtual keyboard and mouse support"
>>       depends on XEN_FBDEV_FRONTEND
>> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
>> index 7305f6f..c7fe09a 100644
>> --- a/drivers/input/misc/Makefile
>> +++ b/drivers/input/misc/Makefile
>> @@ -21,6 +21,8 @@ obj-$(CONFIG_INPUT_CM109)           += cm109.o
>>  obj-$(CONFIG_INPUT_CMA3000)          += cma3000_d0x.o
>>  obj-$(CONFIG_INPUT_CMA3000_I2C)              += cma3000_d0x_i2c.o
>>  obj-$(CONFIG_INPUT_CMA3000_SPI)              += cma3000_d0x_spi.o
>> +obj-$(CONFIG_INPUT_CMR3000)          += cmr3000_d0x.o
>> +obj-$(CONFIG_INPUT_CMR3000_SPI)              += cmr3000_d0x_spi.o
>>  obj-$(CONFIG_INPUT_COBALT_BTNS)              += cobalt_btns.o
>>  obj-$(CONFIG_INPUT_DM355EVM)         += dm355evm_keys.o
>>  obj-$(CONFIG_HP_SDC_RTC)             += hp_sdc_rtc.o
>> diff --git a/drivers/input/misc/cmr3000_d0x.c b/drivers/input/misc/cmr3000_d0x.c
>> new file mode 100644
>> index 0000000..d046149
>> --- /dev/null
>> +++ b/drivers/input/misc/cmr3000_d0x.c
>> @@ -0,0 +1,426 @@
>> +/*
>> + * VTI CMR3000_D0x Gyroscope driver
>> + *
>> + * Copyright (C) 2011 Qtechnology
>> + * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com>
>> + *
>> + * Based on:
>> + *   drivers/input/misc/cma3000_d0x.c by: Hemanth V
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/types.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/delay.h>
>> +#include <linux/slab.h>
>> +#include <linux/input.h>
>> +#include <linux/input/cmr3000.h>
>> +#include <linux/of.h>
>> +
>> +#include "cmr3000_d0x.h"
>> +
>> +#define CMR3000_REV         0x21
>> +
>> +#define CMR3000_WHOAMI      0x00
>> +#define CMR3000_REVID       0x01
>> +#define CMR3000_CTRL        0x02
>> +#define CMR3000_STATUS      0x03
>> +#define CMR3000_X_LSB       0x0C
>> +#define CMR3000_X_MSB       0x0D
>> +#define CMR3000_Y_LSB       0x0E
>> +#define CMR3000_Y_MSB       0x0F
>> +#define CMR3000_Z_LSB       0x10
>> +#define CMR3000_Z_MSB       0x11
>> +#define CMR3000_I2C_ADDR    0x22
>> +#define CMR3000_PDR         0x26
>> +
>> +#define CMR3000_IRQDIS     (1 << 0)
>> +#define CMR3000_MODEMASK   (3 << 1)
>> +#define CMR3000_BUSI2C     (0 << 4)
>> +#define CMR3000_BUSSPI     (1 << 4)
>> +#define CMR3000_INTLOW     (1 << 6)
>> +#define CMR3000_INTHIGH    (0 << 6)
>> +#define CMR3000_RST        (1 << 7)
>> +
>> +#define CMRMODE_SHIFT      1
>> +#define CMRIRQLEVEL_SHIFT  6
>> +
>> +#define CMR3000_STATUS_PERR    (1 << 0)
>> +#define CMR3000_STATUS_PORST   (1 << 3)
>> +
>> +/* Settling time delay in ms */
>> +#define CMR3000_SETDELAY    30
>> +
>> +/*
>> + * Bit weights mult/div in dps for bit 0, other bits need
>> + * multipy factor 2^n. 11th bit is the sign bit.
>> + */
>> +#define BIT_TO_DPS_MUL  3
>> +#define BIT_TO_DPS_DIV 32
>> +
>> +static struct cmr3000_platform_data cmr3000_default_pdata = {
>> +     .irq_level = CMR3000_INTHIGH,
>> +     .mode = CMRMODE_MEAS80,
>> +     .fuzz_x = 1,
>> +     .fuzz_y = 1,
>> +     .fuzz_z = 1,
>> +     .irqflags = 0,
>> +};
>> +
>> +struct cmr3000_gyro_data {
>> +     const struct cmr3000_bus_ops *bus_ops;
>> +     struct cmr3000_platform_data pdata;
>> +
>> +     struct device *dev;
>> +     struct input_dev *input_dev;
>> +
>> +     int irq_level;
>> +     u8 mode;
>> +
>> +     int bit_to_mg;
>> +     int irq;
>> +
>> +     struct mutex mutex;
>> +     bool opened;
>> +     bool suspended;
>> +};
>> +
>> +static void decode_dps(struct cmr3000_gyro_data *data, int *datax,
>> +                    int *datay, int *dataz)
>> +{
>> +     /* Data in 2's complement, convert to dps */
>> +     *datax = (((s16) ((*datax) << 2)) * BIT_TO_DPS_MUL) / BIT_TO_DPS_DIV;
>> +     *datay = (((s16) ((*datay) << 2)) * BIT_TO_DPS_MUL) / BIT_TO_DPS_DIV;
>> +     *dataz = (((s16) ((*dataz) << 2)) * BIT_TO_DPS_MUL) / BIT_TO_DPS_DIV;
>> +}
>> +
>> +static irqreturn_t cmr3000_thread_irq(int irq, void *dev_id)
>> +{
>> +     struct cmr3000_gyro_data *data = dev_id;
>> +     int datax, datay, dataz;
>> +     u8 mode, intr_status;
>> +
>> +     intr_status = data->bus_ops->read(data->dev, CMR3000_STATUS,
>> +                                                     "irq status");
>> +     intr_status = data->bus_ops->read(data->dev, CMR3000_CTRL,
>> +                                                     "control mode");
>> +     if (intr_status < 0)
>> +             return IRQ_NONE;
>> +
>> +     /* Interrupt not for this device */
>> +     if (intr_status & CMR3000_IRQDIS)
>> +             return IRQ_NONE;
>> +
>> +     mode = (intr_status & CMR3000_MODEMASK) >> CMRMODE_SHIFT;
>> +     if ((mode != CMRMODE_MEAS80)
>> +         && (mode != CMRMODE_MEAS20))
>> +             return IRQ_NONE;
>> +
>> +     datax = (data->bus_ops->read(data->dev, CMR3000_X_MSB, "X_MSB")) << 8;
>> +     datax |= data->bus_ops->read(data->dev, CMR3000_X_LSB, "X_LSB");
>> +     datay = (data->bus_ops->read(data->dev, CMR3000_Y_MSB, "Y_MSB")) << 8;
>> +     datay |= data->bus_ops->read(data->dev, CMR3000_Y_LSB, "Y_LSB");
>> +     dataz = (data->bus_ops->read(data->dev, CMR3000_Z_MSB, "Z_MSB")) << 8;
>> +     dataz |= data->bus_ops->read(data->dev, CMR3000_Z_LSB, "Z_LSB");
>> +
>> +     /* Device closed */
>> +     if ((data->mode != CMRMODE_MEAS80)
>> +         && (data->mode != CMRMODE_MEAS20))
>> +             return IRQ_NONE;
>> +
>> +     /* Decode register values to dps */
>> +     decode_dps(data, &datax, &datay, &dataz);
>> +
>> +     input_report_abs(data->input_dev, ABS_X, datax);
>> +     input_report_abs(data->input_dev, ABS_Y, datay);
>> +     input_report_abs(data->input_dev, ABS_Z, dataz);
>> +     input_sync(data->input_dev);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static int cmr3000_poweron(struct cmr3000_gyro_data *data)
>> +{
>> +     const struct cmr3000_platform_data *pdata = &data->pdata;
>> +     u8 ctrl;
>> +     int ret;
>> +
>> +     ctrl = pdata->irq_level << CMRIRQLEVEL_SHIFT;
>> +     ctrl |= data->mode << CMRMODE_SHIFT;
>> +     ctrl |= data->bus_ops->ctrl_mod;
>> +     ret = data->bus_ops->write(data->dev, CMR3000_CTRL, ctrl,
>> +                                                     "Mode setting");
>> +     if (ret < 0)
>> +             return -EIO;
>> +
>> +     msleep(CMR3000_SETDELAY);
>> +
>> +     return 0;
>> +}
>> +
>> +static int cmr3000_poweroff(struct cmr3000_gyro_data *data)
>> +{
>> +     int ret;
>> +     u8 ctrl = CMRMODE_POFF;
>> +
>> +     ctrl |= data->bus_ops->ctrl_mod;
>> +     ctrl |= CMR3000_IRQDIS;
>> +
>> +     ret = data->bus_ops->write(data->dev, CMR3000_CTRL, ctrl,
>> +                                                     "Mode setting");
>> +     msleep(CMR3000_SETDELAY);
>> +
>> +     return ret;
>> +}
>> +
>> +static int cmr3000_reset(struct cmr3000_gyro_data *data)
>> +{
>> +     int val;
>> +
>> +     /* Reset chip */
>> +     data->bus_ops->write(data->dev, CMR3000_CTRL, CMR3000_RST, "Reset");
>> +     mdelay(2);
>> +
>> +     /* Settling time delay */
>> +     val = data->bus_ops->read(data->dev, CMR3000_STATUS, "Status");
>> +     if (val < 0) {
>> +             dev_err(data->dev, "Reset failed\n");
>> +             return val;
>> +     }
>> +
>> +     if (val & CMR3000_STATUS_PERR) {
>> +             dev_err(data->dev, "Parity Error\n");
>> +             return -EIO;
>> +     }
>> +
>> +     return cmr3000_poweroff(data);
>> +}
>> +
>> +static int cmr3000_open(struct input_dev *input_dev)
>> +{
>> +     struct cmr3000_gyro_data *data = input_get_drvdata(input_dev);
>> +
>> +     mutex_lock(&data->mutex);
>> +
>> +     if (!data->suspended)
>> +             cmr3000_poweron(data);
>> +
>> +     data->opened = true;
>> +
>> +     mutex_unlock(&data->mutex);
>> +
>> +     return 0;
>> +}
>> +
>> +static void cmr3000_close(struct input_dev *input_dev)
>> +{
>> +     struct cmr3000_gyro_data *data = input_get_drvdata(input_dev);
>> +
>> +     mutex_lock(&data->mutex);
>> +
>> +     if (!data->suspended)
>> +             cmr3000_poweroff(data);
>> +
>> +     data->opened = false;
>> +
>> +     mutex_unlock(&data->mutex);
>> +}
>> +
>> +void cmr3000_suspend(struct cmr3000_gyro_data *data)
>> +{
>> +     mutex_lock(&data->mutex);
>> +
>> +     if (!data->suspended && data->opened)
>> +             cmr3000_poweroff(data);
>> +
>> +     data->suspended = true;
>> +
>> +     mutex_unlock(&data->mutex);
>> +}
>> +EXPORT_SYMBOL(cmr3000_suspend);
>> +
>> +void cmr3000_resume(struct cmr3000_gyro_data *data)
>> +{
>> +     mutex_lock(&data->mutex);
>> +
>> +     if (data->suspended && data->opened)
>> +             cmr3000_poweron(data);
>> +
>> +     data->suspended = false;
>> +
>> +     mutex_unlock(&data->mutex);
>> +}
>> +EXPORT_SYMBOL(cmr3000_resume);
>> +
>> +#ifdef CONFIG_OF
>> +void cmr3000_get_pdata_of(struct device *dev, struct cmr3000_gyro_data *data)
>> +{
>> +     const __be32 *property;
>> +     int len;
>> +
>> +     property = of_get_property(dev->of_node, "vti,irq_level", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.irq_level = be32_to_cpup(property);
>> +
>> +     property = of_get_property(dev->of_node, "vti,mode", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.mode = be32_to_cpup(property);
>> +
>> +     property = of_get_property(dev->of_node, "vti,fuzz_x", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.fuzz_x = be32_to_cpup(property);
>> +
>> +     property = of_get_property(dev->of_node, "vti,fuzz_y", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.fuzz_y = be32_to_cpup(property);
>> +
>> +     property = of_get_property(dev->of_node, "vti,fuzz_z", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.fuzz_z = be32_to_cpup(property);
>> +
>> +     property = of_get_property(dev->of_node, "vti,irqflags", &len);
>> +     if (property && len == sizeof(int))
>> +             data->pdata.irqflags = be32_to_cpup(property);
>> +
>> +     return;
>> +}
>> +#endif
>> +
>> +struct cmr3000_gyro_data *cmr3000_init(struct device *dev, int irq,
>> +                                    const struct cmr3000_bus_ops *bops)
>> +{
>> +     struct cmr3000_platform_data *pdata;
>> +     struct cmr3000_gyro_data *data;
>> +     struct input_dev *input_dev;
>> +     int rev;
>> +     int error;
>> +
>> +     /* if no IRQ return error */
>> +     if (irq == 0) {
>> +             error = -EINVAL;
>> +             goto err_out;
>> +     }
>> +
>> +     data = kzalloc(sizeof(struct cmr3000_gyro_data), GFP_KERNEL);
>> +     input_dev = input_allocate_device();
>> +     if (!data || !input_dev) {
>> +             error = -ENOMEM;
>> +             goto err_free_mem;
>> +     }
>> +
>> +     /*Init platform data*/
>> +     if (dev->platform_data != NULL) {
>> +             memcpy(&data->pdata, dev->platform_data, sizeof(data->pdata));
>> +     } else {
>> +             memcpy(&data->pdata, &cmr3000_default_pdata,
>> +                             sizeof(data->pdata));
>> +             #ifdef CONFIG_OF
>> +             if (dev->of_node != NULL)
>> +                     cmr3000_get_pdata_of(dev, data);
>> +              else
>> +             #endif
>> +             dev_info(dev, "platform data not found, using default\n");
>> +     }
>> +     pdata = &data->pdata;
>> +
>> +     data->dev = dev;
>> +     data->input_dev = input_dev;
>> +     data->bus_ops = bops;
>> +     data->irq = irq;
>> +     mutex_init(&data->mutex);
>> +
>> +     data->mode = pdata->mode;
>> +     if ((data->mode != CMRMODE_MEAS80)
>> +         && (data->mode != CMRMODE_MEAS20)) {
>> +             data->mode = CMRMODE_MEAS80;
>> +             dev_warn(dev, "Invalid mode specified, assuming 80Hz\n");
>> +     }
>> +
>> +     data->irq_level = pdata->irq_level;
>> +     if ((data->irq_level != CMR3000_INTLOW)
>> +         && (data->irq_level != CMR3000_INTHIGH)) {
>> +             data->irq_level = CMR3000_INTHIGH;
>> +             dev_warn(data->dev,
>> +                      "Invalid int level specified, assuming high\n");
>> +     }
>> +
>> +     input_dev->name = "cmr3000-gyroscope";
>> +     input_dev->id.bustype = bops->bustype;
>> +     input_dev->open = cmr3000_open;
>> +     input_dev->close = cmr3000_close;
>> +
>> +     __set_bit(EV_ABS, input_dev->evbit);
>> +
>> +     input_set_abs_params(input_dev, ABS_X,
>> +                          -CMRRANGE, CMRRANGE, pdata->fuzz_x, 0);
>> +     input_set_abs_params(input_dev, ABS_Y,
>> +                          -CMRRANGE, CMRRANGE, pdata->fuzz_y, 0);
>> +     input_set_abs_params(input_dev, ABS_Z,
>> +                          -CMRRANGE, CMRRANGE, pdata->fuzz_z, 0);
>> +
>> +     input_set_drvdata(input_dev, data);
>> +
>> +     error = cmr3000_reset(data);
>> +     if (error)
>> +             goto err_free_mem;
>> +
>> +     rev = data->bus_ops->read(data->dev, CMR3000_REVID, "Revid");
>> +     if (rev < 0) {
>> +             error = rev;
>> +             goto err_free_mem;
>> +     }
>> +     if (rev != CMR3000_REV) {
>> +             error = -EINVAL;
>> +             pr_err("CMR3000 Gyroscope: Unknown Revision %x\n", rev);
>> +             goto err_free_mem;
>> +     }
>> +     pr_info("CMR3000 Gyroscope: Revision %x\n", rev);
>> +
>> +     error = request_threaded_irq(irq, NULL, cmr3000_thread_irq,
>> +                                  pdata->irqflags | IRQF_ONESHOT,
>> +                                  "cmr3000_d0x", data);
>> +     if (error) {
>> +             dev_err(dev, "request_threaded_irq failed\n");
>> +             goto err_free_mem;
>> +     }
>> +
>> +     error = input_register_device(data->input_dev);
>> +     if (error) {
>> +             dev_err(dev, "Unable to register input device\n");
>> +             goto err_free_irq;
>> +     }
>> +
>> +     return data;
>> +
>> +err_free_irq:
>> +     free_irq(irq, data);
>> +err_free_mem:
>> +     input_free_device(input_dev);
>> +     kfree(data);
>> +err_out:
>> +     return ERR_PTR(error);
>> +}
>> +EXPORT_SYMBOL(cmr3000_init);
>> +
>> +void cmr3000_exit(struct cmr3000_gyro_data *data)
>> +{
>> +     free_irq(data->irq, data);
>> +     input_unregister_device(data->input_dev);
>> +     kfree(data);
>> +}
>> +EXPORT_SYMBOL(cmr3000_exit);
>> +
>> +MODULE_DESCRIPTION("CMR3000-D0x Gyroscope Driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
>> diff --git a/drivers/input/misc/cmr3000_d0x.h b/drivers/input/misc/cmr3000_d0x.h
>> new file mode 100644
>> index 0000000..3d0984a
>> --- /dev/null
>> +++ b/drivers/input/misc/cmr3000_d0x.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * VTI CMR3000_D0x Gyroscpe driver
>> + *
>> + * Copyright (C) 2011 Qtechnology
>> + * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com>
>> + *
>> + * Based on:
>> + *   drivers/input/misc/cma3000_d0x.h by Hemanth V
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef _INPUT_CMR3000_H
>> +#define _INPUT_CMR3000_H
>> +
>> +#include <linux/types.h>
>> +#include <linux/input.h>
>> +
>> +struct device;
>> +struct cmr3000_gyro_data;
>> +
>> +struct cmr3000_bus_ops {
>> +     u16 bustype;
>> +     u8 ctrl_mod;
>> +     int (*read) (struct device *, u8, char *);
>> +     int (*write) (struct device *, u8, u8, char *);
>> +};
>> +
>> +struct cmr3000_gyro_data *cmr3000_init(struct device *dev, int irq,
>> +                                    const struct cmr3000_bus_ops *bops);
>> +void cmr3000_exit(struct cmr3000_gyro_data *);
>> +void cmr3000_suspend(struct cmr3000_gyro_data *);
>> +void cmr3000_resume(struct cmr3000_gyro_data *);
>> +
>> +#endif
>> diff --git a/drivers/input/misc/cmr3000_d0x_spi.c b/drivers/input/misc/cmr3000_d0x_spi.c
>> new file mode 100644
>> index 0000000..7f27fa3
>> --- /dev/null
>> +++ b/drivers/input/misc/cmr3000_d0x_spi.c
>> @@ -0,0 +1,144 @@
>> +/*
>> + * Implements SPI interface for VTI CMR300_D0x Accelerometer driver
>> + *
>> + * Copyright (C) 2011 Qtechnology
>> + * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com.com>
>> + * Based on:
>> + *   drivers/input/misc/cma3000_d0x_i2c.c by Hemanth V
>> + *   drivers/input/mis/adxl34x-spi.c by Michael Hennerich
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/input/cmr3000.h>
>> +#include "cmr3000_d0x.h"
>> +
>> +static int cmr3000_spi_write(struct device *dev, u8 reg, u8 val, char *msg)
>> +{
>> +     struct spi_device *spi = to_spi_device(dev);
>> +     int ret;
>> +     u8 tmp[2];
>> +
>> +     tmp[0] = (reg << 2) | 2;
>> +     tmp[1] = val;
>> +
>> +     ret = spi_write_then_read(spi, tmp, sizeof(tmp), NULL, 0);
>> +     if (ret < 0) {
>> +             dev_err(dev, "%s failed (%s, %d)\n", __func__, msg, ret);
>> +             return ret;
>> +     }
>> +     return 0;
>> +}
>> +
>> +static int cmr3000_spi_read(struct device *dev, u8 reg, char *msg)
>> +{
>> +     struct spi_device *spi = to_spi_device(dev);
>> +     int ret;
>> +
>> +     ret = spi_w8r8(spi, reg << 2);
>> +     if (ret < 0)
>> +             dev_err(dev, "%s failed (%s, %d)\n", __func__, msg, ret);
>> +
>> +     return ret;
>> +}
>> +
>> +static const struct cmr3000_bus_ops cmr3000_spi_bops = {
>> +     .bustype = BUS_SPI,
>> +#define CMR3000_BUSSPI     (1 << 4)
>> +     .ctrl_mod = CMR3000_BUSSPI,
>> +     .read = cmr3000_spi_read,
>> +     .write = cmr3000_spi_write,
>> +};
>> +
>> +static int __devinit cmr3000_spi_probe(struct spi_device *spi)
>> +{
>> +     struct cmr3000_gyro_data *data;
>> +
>> +     data = cmr3000_init(&spi->dev, spi->irq, &cmr3000_spi_bops);
>> +     if (IS_ERR(data))
>> +             return PTR_ERR(data);
>> +
>> +     spi_set_drvdata(spi, data);
>> +
>> +     return 0;
>> +}
>> +
>> +static int __devexit cmr3000_spi_remove(struct spi_device *spi)
>> +{
>> +     struct cmr3000_gyro_data *data = dev_get_drvdata(&spi->dev);
>> +
>> +     cmr3000_exit(data);
>> +
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int cmr3000_spi_suspend(struct device *dev)
>> +{
>> +     struct spi_device *spi = to_spi_device(dev);
>> +     struct cmr3000_gyro_data *data = dev_get_drvdata(&spi->dev);
>> +
>> +     cmr3000_suspend(data);
>> +
>> +     return 0;
>> +}
>> +
>> +static int cmr3000_spi_resume(struct device *dev)
>> +{
>> +     struct spi_device *spi = to_spi_device(dev);
>> +     struct cmr3000_gyro_data *data = dev_get_drvdata(&spi->dev);
>> +
>> +     cmr3000_resume(data);
>> +
>> +     return 0;
>> +}
>> +
>> +static const struct dev_pm_ops cmr3000_spi_pm_ops = {
>> +     .suspend = cmr3000_spi_suspend,
>> +     .resume = cmr3000_spi_resume,
>> +};
>> +#endif
>> +
>> +static SIMPLE_DEV_PM_OPS(cmr3000_spi_pm, cmr3000_spi_suspend,
>> +                      cmr3000_spi_resume);
>> +
>> +static struct spi_driver cmr3000_driver = {
>> +     .driver = {
>> +                .name = "cmr3000_d01",
>> +                .bus = &spi_bus_type,
>> +                .owner = THIS_MODULE,
>> +                .pm = &cmr3000_spi_pm,
>> +                },
>> +     .probe = cmr3000_spi_probe,
>> +     .remove = __devexit_p(cmr3000_spi_remove),
>> +};
>> +
>> +static int __init cmr3000_spi_init(void)
>> +{
>> +     return spi_register_driver(&cmr3000_driver);
>> +}
>> +
>> +static void __exit cmr3000_spi_exit(void)
>> +{
>> +     spi_unregister_driver(&cmr3000_driver);
>> +}
>> +
>> +module_init(cmr3000_spi_init);
>> +module_exit(cmr3000_spi_exit);
>> +
>> +MODULE_DESCRIPTION("CMR3000-D0x Gyroscope SPI Driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
>> diff --git a/include/linux/input/cmr3000.h b/include/linux/input/cmr3000.h
>> new file mode 100644
>> index 0000000..dfcf9e3
>> --- /dev/null
>> +++ b/include/linux/input/cmr3000.h
>> @@ -0,0 +1,54 @@
>> +/*
>> + * VTI CMR3000_Dxx Gyroscope driver
>> + *
>> + * Copyright (C) 2011 Qtechnology
>> + * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com>
>> + *
>> + * Based on:
>> + *   include/linux/input/cma3000.h by Hemanth V
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef _LINUX_CMR3000_H
>> +#define _LINUX_CMR3000_H
>> +
>> +#define CMRMODE_DEFAULT    0
>> +#define CMRMODE_STANDBY    1
>> +#define CMRMODE_MEAS20     2
>> +#define CMRMODE_MEAS80     3
>> +#define CMRMODE_POFF       0
>> +
>> +#define CMRIRQLEVEL_LOW    1
>> +#define CMRIRQLEVEL_HIGH   0
>> +
>> +#define CMRRANGE   3072
>> +
>> +/**
>> + * struct cmr3000_platform_data - CMR3000 Platform data
>> + * @fuzz_x: Noise on X Axis
>> + * @fuzz_y: Noise on Y Axis
>> + * @fuzz_z: Noise on Z Axis
>> + * @mode: Operating mode
>> + * @irq_level: Irq level
>> + */
>> +struct cmr3000_platform_data {
>> +     int fuzz_x;
>> +     int fuzz_y;
>> +     int fuzz_z;
>> +     uint8_t irq_level;
>> +     uint8_t mode;
>> +     unsigned long irqflags;
>> +};
>> +
>> +#endif
>> --
>> 1.7.7
>>
>



--
Ricardo Ribalda
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2011-10-25 09:29    [W:0.119 / U:17.528 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site