Re: [PATCH] iio: accel: add Freescale MMA7455L 3-axis accelerometer driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> >> Add support for Freescale MMA7455L 3-axis in 10-bit mode with both
> >> I2C and SPI bus support. This is a rather simple driver that
> >> currently doesn't support all the hardware features of MMA7455L.
> >
> > please add a link to the datasheet
> 
> Sure.
> 
> >
> > comments below
> >
> >> Tested on Embedded Artists' LPC4357 Dev Kit using I2C bus.
> >>
> >> Signed-off-by: Joachim Eastwood <manabian@xxxxxxxxx>
> >> ---
> >>
> >>  drivers/iio/accel/Kconfig   |  14 ++
> >>  drivers/iio/accel/Makefile  |   1 +
> >>  drivers/iio/accel/mma7455.c | 424 ++++++++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 439 insertions(+)
> >>  create mode 100644 drivers/iio/accel/mma7455.c
> >>
> >> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> >> index a59047d7657e..8ccb3de85484 100644
> >> --- a/drivers/iio/accel/Kconfig
> >> +++ b/drivers/iio/accel/Kconfig
> >> @@ -99,6 +99,20 @@ config KXCJK1013
> >>         To compile this driver as a module, choose M here: the module will
> >>         be called kxcjk-1013.
> >>
> >> +config MMA7455
> >> +     tristate "Freescale MMA7455L Accelerometer Driver"
> >> +     depends on I2C || SPI_MASTER
> >> +     select IIO_BUFFER
> >> +     select IIO_TRIGGERED_BUFFER
> >> +     select REGMAP_I2C if I2C
> >> +     select REGMAP_SPI if SPI_MASTER
> >> +     help
> >> +       Say yes here to build support for the Freescale MMA7455L 3-axis
> >> +       accelerometer.
> >> +
> >> +       To compile this driver as a module, choose M here: the module
> >> +       will be called mma7455.
> >> +
> >>  config MMA8452
> >>       tristate "Freescale MMA8452Q Accelerometer Driver"
> >>       depends on I2C
> >> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
> >> index ebd2675b2a02..6ac9382761f8 100644
> >> --- a/drivers/iio/accel/Makefile
> >> +++ b/drivers/iio/accel/Makefile
> >> @@ -8,6 +8,7 @@ obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o
> >>  obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
> >>  obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
> >>  obj-$(CONFIG_KXSD9)  += kxsd9.o
> >> +obj-$(CONFIG_MMA7455)        += mma7455.o
> >>  obj-$(CONFIG_MMA8452)        += mma8452.o
> >>
> >>  obj-$(CONFIG_MMA9551_CORE)   += mma9551_core.o
> >> diff --git a/drivers/iio/accel/mma7455.c b/drivers/iio/accel/mma7455.c
> >> new file mode 100644
> >> index 000000000000..fa62f2bcb54a
> >> --- /dev/null
> >> +++ b/drivers/iio/accel/mma7455.c
> >> @@ -0,0 +1,424 @@
> >> +/*
> >> + * mma7455.c - Support for Freescale MMA7455L 3-axis 10-bit accelerometer
> >> + * Copyright 2015 Joachim Eastwood <manabian@xxxxxxxxx>
> >> + *
> >> + * Based on MMA8452Q IIO driver
> >> + * Copyright 2014 Peter Meerwald <pmeerw@xxxxxxxxxx>
> >> + *
> >> + * 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.
> >> + *
> >> + * UNSUPPORTED hardware features:
> >> + *  - 8-bit mode with different scales
> >> + *  - INT1/INT2 interrupts
> >> + *  - Offset calibration
> >> + *  - Events
> >> + */
> >> +
> >> +#include <linux/delay.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/iio/iio.h>
> >> +#include <linux/iio/sysfs.h>
> >> +#include <linux/iio/buffer.h>
> >> +#include <linux/iio/trigger.h>
> >> +#include <linux/iio/trigger_consumer.h>
> >> +#include <linux/iio/triggered_buffer.h>
> >> +#include <linux/module.h>
> >> +#include <linux/regmap.h>
> >> +#include <linux/spi/spi.h>
> >> +
> >> +#define MMA7455_REG_XOUTL            0x00
> >> +#define MMA7455_REG_XOUTH            0x01
> >> +#define MMA7455_REG_YOUTL            0x02
> >> +#define MMA7455_REG_YOUTH            0x03
> >> +#define MMA7455_REG_ZOUTL            0x04
> >> +#define MMA7455_REG_ZOUTH            0x05
> >> +#define MMA7455_REG_STATUS           0x09
> >> +#define  MMA7455_STATUS_DRDY         BIT(0)
> >
> > whitespace inconsistencies
> 
> This is actually intentional and used to show that it is a field in a
> register. If you don't like it I can remove it.

hm, I didn't get it; it's probably a good idea :)
 
> >> +#define MMA7455_REG_WHOAMI           0x0f
> >> +#define  MMA7455_WHOAMI_ID           0x55
> >> +#define MMA7455_REG_MCTL             0x16
> >> +#define  MMA7455_MCTL_MODE_STANDBY   0x00
> >> +#define  MMA7455_MCTL_MODE_MEASURE   0x01
> >> +#define MMA7455_REG_CTL1             0x18
> >> +#define  MMA7455_CTL1_DFBW_MASK              BIT(7)
> >> +#define  MMA7455_CTL1_DFBW_125HZ     BIT(7)
> >> +#define  MMA7455_CTL1_DFBW_62_5HZ    0
> >> +#define MMA7455_REG_TW                       0x1e
> >> +
> >> +/*
> >> + * When MMA7455 is used in 10-bit it has a fullscale of -8g
> >> + * corresponding to raw value -512. The userspace interface
> >> + * uses m/s^2 and we declare micro units.
> >> + * So scale factor is given by:
> >> + *       g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665
> >> + */
> >> +#define MMA7455_10BIT_SCALE  153229
> >> +
> >> +struct mma7455_data {
> >> +     struct regmap *regmap;
> >> +     struct device *dev;
> >> +};
> >> +
> >> +static int mma7455_drdy(struct mma7455_data *mma7455)
> >> +{
> >> +     unsigned int reg;
> >> +     int tries = 10;
> >> +     int ret;
> >> +
> >> +     while (tries-- > 0) {
> >> +             ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
> >> +             if (ret)
> >> +                     return ret;
> >> +
> >> +             if (reg & MMA7455_STATUS_DRDY)
> >> +                     return 0;
> >> +
> >> +             msleep(20);
> >> +     }
> >> +
> >> +     dev_warn(mma7455->dev, "data not ready\n");
> >> +
> >> +     return -EIO;
> >> +}
> >> +
> >> +static irqreturn_t mma7455_trigger_handler(int irq, void *p)
> >> +{
> >> +     struct iio_poll_func *pf = p;
> >> +     struct iio_dev *indio_dev = pf->indio_dev;
> >> +     struct mma7455_data *mma7455 = iio_priv(indio_dev);
> >> +     u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
> >> +     int ret;
> >> +
> >> +     ret = mma7455_drdy(mma7455);
> >> +     if (ret)
> >> +             goto done;
> >> +
> >> +     ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
> >> +                            sizeof(s16) * 3);
> >
> > use le16 to hint which endianness the device registers have
> 
> OK.
> 
> >> +     if (ret)
> >> +             goto done;
> >> +
> >> +     iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
> >> +
> >> +done:
> >> +     iio_trigger_notify_done(indio_dev->trig);
> >> +
> >> +     return IRQ_HANDLED;
> >> +}
> >> +
> >> +static int mma7455_read_raw(struct iio_dev *indio_dev,
> >> +                         struct iio_chan_spec const *chan,
> >> +                         int *val, int *val2, long mask)
> >> +{
> >> +     struct mma7455_data *mma7455 = iio_priv(indio_dev);
> >> +     unsigned int reg = 0;
> >
> > initialization not needed
> 
> I think it may complain when used in regmap_bulk_read() later. I'll check.

yes, better leave it in; not sure how _read() is implemented when less 
then sizeof(unsigned int) is read
 
> 
> >> +     int ret;
> >> +
> >> +     switch (mask) {
> >> +     case IIO_CHAN_INFO_RAW:
> >> +             if (iio_buffer_enabled(indio_dev))
> >> +                     return -EBUSY;
> >> +
> >> +             ret = mma7455_drdy(mma7455);
> >> +             if (ret)
> >> +                     return ret;
> >> +
> >> +             ret = regmap_bulk_read(mma7455->regmap, chan->scan_index * 2,
> >
> > it would be clearer to use chan->address instead of computing the register
> 
> ah, I didn't noticed the address field in chan_spec. I'll use that in
> the next version.
> 
> >
> > instead of s16 I suggest to use le16
> 
> OK.
> 
> > using regmap_bulk_read(), there is no endianness conversion; the driver
> > will only work when chip endianness equals CPU endianness
> 
> I'll add conversion using the to_cpu-functions in the next version.
> 
> >
> >> +                                    &reg, sizeof(s16));
> >> +             if (ret)
> >> +                     return ret;
> >> +
> >> +             *val = sign_extend32(reg, 9);
> >> +
> >> +             return IIO_VAL_INT;
> >> +
> >> +     case IIO_CHAN_INFO_SCALE:
> >> +             *val = 0;
> >> +             *val2 = MMA7455_10BIT_SCALE;
> >> +
> >> +             return IIO_VAL_INT_PLUS_MICRO;
> >> +
> >> +     case IIO_CHAN_INFO_SAMP_FREQ:
> >> +             ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
> >> +             if (ret)
> >> +                     return ret;
> >> +
> >> +             if (reg & MMA7455_CTL1_DFBW_MASK)
> >> +                     *val = 250;
> >> +             else
> >> +                     *val = 125;
> >> +
> >> +             return IIO_VAL_INT;
> >> +     }
> >> +
> >> +     return -EINVAL;
> >> +}
> >> +
> >> +static int mma7455_write_raw(struct iio_dev *indio_dev,
> >> +                          struct iio_chan_spec const *chan,
> >> +                          int val, int val2, long mask)
> >> +{
> >> +     struct mma7455_data *mma7455 = iio_priv(indio_dev);
> >> +     int i;
> >> +
> >> +     if (iio_buffer_enabled(indio_dev))
> >> +             return -EBUSY;
> >> +
> >> +     switch (mask) {
> >> +     case IIO_CHAN_INFO_SAMP_FREQ:
> >
> > check val2 == 0
> 
> OK.
> 
> >> +             if (val == 250)
> >> +                     i = MMA7455_CTL1_DFBW_125HZ;
> >> +             else if (val == 125)
> >> +                     i = MMA7455_CTL1_DFBW_62_5HZ;
> >> +             else
> >> +                     return -EINVAL;
> >> +
> >> +             return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
> >> +                                       MMA7455_CTL1_DFBW_MASK, i);
> >> +
> >> +     case IIO_CHAN_INFO_SCALE:
> >> +             /* In 10-bit mode there is only one scale available */
> >> +             if (val == 0 && val2 == MMA7455_10BIT_SCALE)
> >> +                     return 0;
> >> +             break;
> >> +     }
> >> +
> >> +     return -EINVAL;
> >> +}
> 
> 
> Thanks for reviewing, I'll implement the changes in the next version.
> 
> 
> regards,
> Joachim Eastwood
> 

-- 

Peter Meerwald
+43-664-2444418 (mobile)
--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux