Re: [PATCH v6] add support for Freescale's MMA8653FC 10 bit accelerometer

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

 



On Fri, Mar 27, 2015 at 08:38:55AM +0100, Martin Kepplinger wrote:
> From: Martin Kepplinger <martin.kepplinger@xxxxxxxxxxxxxxxxxxxxx>
> 
> The MMA8653FC is a low-power, three-axis, capacitive micromachined
> accelerometer with 10 bits of resolution with flexible user-programmable
> options.
> 
> Embedded interrupt functions enable overall power savings, by relieving the
> host processor from continuously polling data, for example using the poll()
> system call.
> 
> The device can be configured to generate wake-up interrupt signals from any
> combination of the configurable embedded functions, enabling the MMA8653FC
> to monitor events while remaining in a low-power mode during periods of
> inactivity.
> 
> This driver provides devicetree properties to program the device's behaviour
> and a simple, tested and documented sysfs interface. The data sheet and more
> information is available on Freescale's website.
> 
> Signed-off-by: Martin Kepplinger <martin.kepplinger@xxxxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Christoph Muellner <christoph.muellner@xxxxxxxxxxxxxxxxxxxxx>
> ---
> 
> patch revision history
> ......................
> v6 fix staging integration, base it on next-20150326 and change recipients
> v5 clean up (suggested by Varka Bhadram) and move the driver to staging
> v4 changes DT propery names, adds a missing interrupt source and removes
>    the DT option to set interrupt line active high due to unsuccesful testing
> v3 moves the driver from drivers/input/misc to drivers/misc
> v2 corrects licensing and commit messages and adds appropriate recipients
> 
>  drivers/staging/Kconfig               |   2 +
>  drivers/staging/Makefile              |   1 +
>  drivers/staging/mma8653fc/Kconfig     |  10 +
>  drivers/staging/mma8653fc/Makefile    |   1 +
>  drivers/staging/mma8653fc/TODO        | 146 ++++++
>  drivers/staging/mma8653fc/mma8653fc.c | 864 ++++++++++++++++++++++++++++++++++
>  6 files changed, 1024 insertions(+)
>  create mode 100644 drivers/staging/mma8653fc/Kconfig
>  create mode 100644 drivers/staging/mma8653fc/Makefile
>  create mode 100644 drivers/staging/mma8653fc/TODO
>  create mode 100644 drivers/staging/mma8653fc/mma8653fc.c
> 
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index bfacf69..834d949 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -112,4 +112,6 @@ source "drivers/staging/i2o/Kconfig"
>  
>  source "drivers/staging/fsl-mc/Kconfig"
>  
> +source "drivers/staging/mma8653fc/Kconfig"
> +
>  endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index 2bbd1bf..cfea86a 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD)	+= clocking-wizard/
>  obj-$(CONFIG_FB_TFT)		+= fbtft/
>  obj-$(CONFIG_I2O)		+= i2o/
>  obj-$(CONFIG_FSL_MC_BUS)	+= fsl-mc/
> +obj-$(CONFIG_MMA8653FC)		+= mma8653fc/
> diff --git a/drivers/staging/mma8653fc/Kconfig b/drivers/staging/mma8653fc/Kconfig
> new file mode 100644
> index 0000000..988451b
> --- /dev/null
> +++ b/drivers/staging/mma8653fc/Kconfig
> @@ -0,0 +1,10 @@
> +config MMA8653FC
> +        tristate "MMA8653FC - Freescale's 3-Axis, 10-bit Digital Accelerometer"
> +        depends on I2C
> +        default n
> +        help
> +          Say Y here if you want to support Freescale's MMA8653FC Accelerometer
> +          through I2C interface.
> +
> +          To compile this driver as a module, choose M here: the
> +          module will be called mma8653fc.
> diff --git a/drivers/staging/mma8653fc/Makefile b/drivers/staging/mma8653fc/Makefile
> new file mode 100644
> index 0000000..9a245a3
> --- /dev/null
> +++ b/drivers/staging/mma8653fc/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_MMA8653FC)         += mma8653fc.o
> diff --git a/drivers/staging/mma8653fc/TODO b/drivers/staging/mma8653fc/TODO
> new file mode 100644
> index 0000000..0a31225
> --- /dev/null
> +++ b/drivers/staging/mma8653fc/TODO
> @@ -0,0 +1,146 @@
> +- move to IIO device API. The current DT/sysfs interface is documented below
> +
> +Documentation/ABI/testing/...
> +-----------------------------
> +What:		/sys/bus/i2c/drivers/mma8653fc/*/standby
> +Date:		March 2015
> +Contact:	Martin Kepplinger <martin.kepplinger@xxxxxxxxxxxxxxxxxxxxx>
> +Description:
> +		Write 0 to this in order to turn on the device, and 1 to turn
> +		it off. Read to see if it is turned on or off.
> +
> +
> +What:		/sys/bus/i2c/drivers/mma8653fc/*/currentmode
> +Date:		March 2015
> +Contact:	Martin Kepplinger <martin.kepplinger@xxxxxxxxxxxxxxxxxxxxx>
> +Description:
> +		Reading this provides the current state of the device, read
> +		directly from a register. This can be "standby", "wake" or
> +		"sleep".
> +
> +
> +What:		/sys/bus/i2c/drivers/mma8653fc/*/position
> +Date:		March 2015
> +Contact:	Martin Kepplinger <martin.kepplinger@xxxxxxxxxxxxxxxxxxxxx>
> +Description:
> +		Read only. Without interrupts enabled gets current position
> +		values by reading. Poll "position" with interrupt conditions
> +		set, to get notified; see Documentation/.../fsl,mma8653fc.txt
> +
> +		position file format:
> +		"x y z [landscape/portrait status] [front/back status]"
> +
> +		x y z values:
> +			in mg
> +		landscape/portrait status char:
> +			r	landscape right
> +			d	portrait down
> +			u	portrait up
> +			l	landscape left
> +		front/back status char:
> +			f	front facing
> +			b	back facing
> +
> +
> +Documentation/devicetree/bindings/...
> +-------------------------------------
> +Required properties:
> +- compatible
> +	"fsl,mma8653fc"
> +- reg
> +	I2C address
> +
> +Optional properties:
> +
> +- interrupt-parent
> +	a phandle for the interrupt controller (see
> +	Documentation/devicetree/bindings/interrupt-controller/interrupts.txt)
> +- interrupts
> +	interrupt line to which the chip is connected (active low)
> +- int1
> +	set to use interrupt line 1, default is line 2
> +	the interrupt sources can be routed to one of the two lines
> +- ir-freefall-motion-x
> +	activate freefall/motion interrupts on x axis
> +- ir-freefall-motion-y
> +	activate freefall/motion interrupts on y axis
> +- ir-freefall-motion-z
> +	activate freefall/motion interrupts on z axis
> +- irq-threshold
> +	0 < value < 8000: threshold for motion interrupts in mg
> +- ir-landscape-portrait
> +	activate landscape/portrait interrupts
> +- ir-auto-wake
> +	activate wake/sleep change interrupts
> +- ir-data-ready:
> +	activate data-ready interrupts
> +	Interrupt events can be activated in any combination.
> +- dynamic-range
> +	2, 4, or 8: dynamic measurement range in g, default: 2
> +	In ±2 g mode, sensitivity = 256 counts/g.
> +	In ±4 g mode, sensitivity = 128 counts/g.
> +	In ±8 g mode, sensitivity = 64 counts/g.
> +- auto-wake-sleep
> +	auto sleep mode (lower frequency)
> +- motion-mode
> +	use motion mode instead of freefall mode (trigger if >threshold).
> +	per default an interrupt occurs if motion values fall below the
> +	value set in "threshold" and therefore can detect free fall on the
> +	vertical axis (depending on the position of the device).
> +	Setting this values inverts the behaviour and an interrupt occurs
> +	above the threshold value, so usually activate horizontal axis in
> +	this case.
> +
> +- x-offset
> +	0 < value < 500: calibration offset in mg
> +	The offset correction values are used to realign the Zero-g position
> +	of the X, Y, and Z-axis after the device is mounted on a board.
> +	this value has an offset of 250 itself:
> +	0 is -250mg, 250 is 0 mg, 500 is 250mg
> +- y-offset
> +	see x-offset
> +- z-offset
> +	see x-offset
> +
> +Example 1:
> +for a device laying on flat ground to recognize acceleration over 100mg.
> +x-axis is calibrated to +10mg. Adapt interrupt line to your device.
> +
> +mma8653fc@1d {
> +		compatible = "fsl,mma8653fc";
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <5 0>;
> +		reg = <0x1d>;
> +
> +		dynamic-range = <2>;
> +		motion-mode;
> +		ir-freefall-motion-x;
> +		ir-freefall-motion-y;
> +		irq-threshold = <100>;
> +		x-offset = <160>;

Just one tab.

> +};
> +
> +Example 2:
> +for a device mounted on a wall with y being the vertical axis. This recognizes
> +y-acceleration below 800mg, so free fall or changing the orientation of the
> +device (y not being the vertical axis and having ~1000mg anymore).
> +
> +mma8653fc@1d {
> +		compatible = "fsl,mma8653fc";
> +		interrupt-parent = <&gpio1>;
> +		interrupts = <5 0>;
> +		reg = <0x1d>;
> +
> +		dynamic-range = <2>;
> +		ir-freefall-motion-y;
> +		irq-threshold = <800>;
> +};
> +
> +Example 3:
> +minimal example. lets users read current acceleration values. No polling
> +is available.
> +
> +mma8653fc@1d {
> +		compatible = "fsl,mma8653fc";
> +		reg = <0x1d>;
> +};
> diff --git a/drivers/staging/mma8653fc/mma8653fc.c b/drivers/staging/mma8653fc/mma8653fc.c
> new file mode 100644
> index 0000000..4bd7f99
> --- /dev/null
> +++ b/drivers/staging/mma8653fc/mma8653fc.c
> @@ -0,0 +1,864 @@
> +/*
> + * mma8653fc.c - Support for Freescale MMA8653FC 3-axis 10-bit accelerometer
> + *
> + * Copyright (c) 2014 Theobroma Systems Design and Consulting GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/types.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +
> +#define DRV_NAME	"mma8653fc"
> +#define MMA8653FC_DEVICE_ID	0x5a
> +
> +#define MMA8653FC_STATUS	0x00
> +
> +#define ZYXOW_MASK	0x80
> +#define ZYXDR		0x08
> +
> +#define MMA8653FC_WHO_AM_I	0x0d
> +
> +#define MMA8653FC_SYSMOD	0x0b
> +#define STATE_STANDBY	0x00
> +#define STATE_WAKE	0x01
> +#define STATE_SLEEP	0x02
> +
> +#define MMA8450_STATUS_ZXYDR	0x08
> +
> +/*
> + * 10 bit output data registers
> + * MSB: 7:0 bits 9:2 of data word
> + * LSB: 7:6 bits 1:0 of data word
> + */
> +#define MMA8653FC_OUT_X_MSB	0x01
> +#define MMA8653FC_OUT_X_LSB	0x02
> +#define MMA8653FC_OUT_Y_MSB	0x03
> +#define MMA8653FC_OUT_Y_LSB	0x04
> +#define MMA8653FC_OUT_Z_MSB	0x05
> +#define MMA8653FC_OUT_Z_LSB	0x06
> +
> +/*
> + * Portrait/Landscape Status
> + */
> +#define MMA8653FC_PL_STATUS	0x10
> +
> +#define NEWLP		0x80
> +#define LAPO_HIGH	0x04
> +#define LAPO_LOW	0x02
> +#define BAFRO		0x01
> +
> +/*
> + * Portrait/Landscape Configuration
> + */
> +#define MMA8653FC_PL_CFG	0x11
> +
> +#define PL_EN		(1 << 6)
> +
> +/*
> + * Data calibration registers
> + */
> +#define MMA8653FC_OFF_X		0x2f
> +#define MMA8653FC_OFF_Y		0x30
> +#define MMA8653FC_OFF_Z		0x31
> +
> +/* 0 to 500 for dts, but -250 to 250 in mg */
> +#define DEFAULT_OFF	250
> +
> +/*
> + * bits 1:0 dynamic range
> + * 00 +/- 2g
> + * 01 +/- 4g
> + * 10 +/- 8g
> + *
> + * HPF_Out bit 4 - data high pass or low pass filtered
> + */
> +#define MMA8653FC_XYZ_DATA_CFG	0x0e
> +
> +#define RANGE_MASK	0x03
> +#define RANGE2G		0x00
> +#define RANGE4G		0x01
> +#define RANGE8G		0x02
> +/* values for calculation */
> +#define SHIFT_2G	8
> +#define INCR_2G		128
> +#define SHIFT_4G	7
> +#define INCR_4G		64
> +#define SHIFT_8G	6
> +#define INCR_8G		32
> +#define DYN_RANGE_2G	2
> +#define DYN_RANGE_4G	4
> +#define DYN_RANGE_8G	8
> +
> +/*
> + * System Control Reg 1
> + */
> +#define MMA8653FC_CTRL_REG1	0x2a
> +
> +#define ACTIVE_BIT	(1 << 0)
> +#define ODR_MASK	0x38
> +#define ODR_DEFAULT	0x20 /* 50 Hz */
> +#define ASLP_RATE_MASK	0xc0
> +#define ASLP_RATE_DEFAULT 0x80 /* 6.25 Hz */
> +
> +/*
> + * Sys Control Reg 2
> + *
> + * auto-sleep enable, software reset
> + */
> +#define MMA8653FC_CTRL_REG2	0x2b
> +
> +#define SLPE		(1 << 2)
> +#define SELFTEST	(1 << 7)
> +#define SOFT_RESET	(1 << 6)
> +
> +/*
> + * Interrupt Source
> + */
> +#define MMA8653FC_INT_SOURCE	0x0c
> +
> +#define SRC_ASLP	(1 << 7)
> +#define SRC_LNDPRT	(1 << 4)
> +#define SRC_FF_MT	(1 << 2)
> +#define SRC_DRDY	(1 << 0)
> +
> +/*
> + * Interrupt Control Register
> + *
> + * default: active low
> + * default push-pull, not open-drain
> + */
> +#define MMA8653FC_CTRL_REG3	0x2c
> +
> +#define WAKE_LNDPRT	(1 << 5)
> +#define WAKE_FF_MT	(1 << 3)
> +#define IPOL		(1 << 1)
> +#define PP_OD		(1 << 0)
> +
> +/*
> + * Interrupt Enable Register
> + */
> +#define MMA8653FC_CTRL_REG4	0x2d
> +
> +#define INT_EN_ASLP	(1 << 7)
> +#define INT_EN_LNDPRT	(1 << 4)
> +#define INT_EN_FF_MT	(1 << 2)
> +#define INT_EN_DRDY	(1 << 0)
> +
> +/*
> + * Interrupt Configuration Register
> + * bit value 0 ... INT2 (default)
> + * bit value 1 ... INT1
> + */
> +#define MMA8653FC_CTRL_REG5	0x2e
> +
> +#define INT_CFG_ASLP	(1 << 7)
> +#define INT_CFG_LNDPRT	(1 << 4)
> +#define INT_CFG_FF_MT	(1 << 2)
> +#define INT_CFG_DRDY	(1 << 0)
> +
> +/*
> + * Freefall / Motion Configuration Register
> + *
> + * Event Latch enable/disable, motion or freefall mode
> + * and event flag enable per axis
> + */
> +#define MMA8653FC_FF_MT_CFG	0x15
> +
> +#define FF_MT_CFG_ELE	(1 << 7)
> +#define FF_MT_CFG_OAE	(1 << 6)
> +#define FF_MT_CFG_ZEFE	(1 << 5)
> +#define FF_MT_CFG_YEFE	(1 << 4)
> +#define FF_MT_CFG_XEFE	(1 << 3)
> +
> +/*
> + * Freefall / Motion Source Register
> + */
> +#define MMA8653FC_FF_MT_SRC	0x16
> +
> +/*
> + * Freefall / Motion Threshold Register
> + *
> + * define motion threshold
> + * 0.063 g/LSB, 127 counts(0x7f) (7 bit from LSB)
> + * range: 0.063g - 8g
> + */
> +#define MMA8653FC_FF_MT_THS	0x17
> +
> +struct axis_triple {
> +	s16 x;
> +	s16 y;
> +	s16 z;
> +};
> +
> +struct mma8653fc_pdata {
> +	s8 x_axis_offset;
> +	s8 y_axis_offset;
> +	s8 z_axis_offset;
> +	bool auto_wake_sleep;
> +	u32 range;
> +	bool int1;
> +	bool motion_mode;
> +	u8 freefall_motion_thr;
> +	bool int_src_data_ready;
> +	bool int_src_ff_mt_x;
> +	bool int_src_ff_mt_y;
> +	bool int_src_ff_mt_z;
> +	bool int_src_lndprt;
> +	bool int_src_aslp;
> +};
> +
> +struct mma8653fc {
> +	struct i2c_client *client;
> +	struct mutex mutex;
> +	struct mma8653fc_pdata pdata;
> +	struct axis_triple saved;
> +	char orientation;
> +	char bafro;
> +	bool standby;
> +	int irq;
> +	unsigned int_mask;
> +	u8 (*read)(struct mma8653fc *, unsigned char);
> +	void (*write)(struct mma8653fc *, unsigned char, unsigned char);
> +};
> +
> +/* defaults */
> +static const struct mma8653fc_pdata mma8653fc_default_init = {
> +	.range = 2,
> +	.x_axis_offset = DEFAULT_OFF,
> +	.y_axis_offset = DEFAULT_OFF,
> +	.z_axis_offset = DEFAULT_OFF,
> +	.auto_wake_sleep = false,
> +	.int1 = false,
> +	.motion_mode = false,
> +	.freefall_motion_thr = 5,
> +	.int_src_data_ready = false,
> +	.int_src_ff_mt_x = false,
> +	.int_src_ff_mt_y = false,
> +	.int_src_ff_mt_z = false,
> +	.int_src_lndprt = false,
> +	.int_src_aslp = false,
> +};
> +
> +static void mma8653fc_get_triple(struct mma8653fc *mma)
> +{
> +	u8 buf[6];
> +	u8 status;
> +
> +	buf[0] = 0;

We don't use this.

> +
> +	status = mma->read(mma, MMA8653FC_STATUS);
> +	if (status & ZYXOW_MASK)
> +		dev_dbg(&mma->client->dev, "previous read not completed\n");
> +
> +	buf[0] = mma->read(mma, MMA8653FC_OUT_X_MSB);
> +	buf[1] = mma->read(mma, MMA8653FC_OUT_X_LSB);
> +	buf[2] = mma->read(mma, MMA8653FC_OUT_Y_MSB);
> +	buf[3] = mma->read(mma, MMA8653FC_OUT_Y_LSB);
> +	buf[4] = mma->read(mma, MMA8653FC_OUT_Z_MSB);
> +	buf[5] = mma->read(mma, MMA8653FC_OUT_Z_LSB);
> +
> +	mutex_lock(&mma->mutex);
> +	/* move from registers to s16 */
> +	mma->saved.x = (buf[1] | (buf[0] << 8)) >> 6;
> +	mma->saved.y = (buf[3] | (buf[2] << 8)) >> 6;
> +	mma->saved.z = (buf[5] | (buf[4] << 8)) >> 6;

Why is buf[] and array instead of individual variables?

u8 x_msb, x_lsb, etc..

> +	mma->saved.x = sign_extend32(mma->saved.x, 9);
> +	mma->saved.y = sign_extend32(mma->saved.y, 9);
> +	mma->saved.z = sign_extend32(mma->saved.z, 9);
> +
> +	/* calc g, see data sheet and application note */
> +	switch (mma->pdata.range) {
> +	case DYN_RANGE_2G:
> +		mma->saved.x = le16_to_cpu((1000 * mma->saved.x +
> +					    INCR_2G) >> SHIFT_2G);

It might be nicer to break these up like this:

		mma->saved.x = le16_to_cpu((1000 * mma->saved.x + INCR_2G) >>
					   SHIFT_2G);

Little endian math always confuses me.  mma->saved.x starts as little
endian and then we multiply it and add and shift and change it to cpu
endian?  Does that work?

> +		mma->saved.y = le16_to_cpu((1000 * mma->saved.y +
> +					   INCR_2G) >> SHIFT_2G);
> +		mma->saved.z = le16_to_cpu((1000 * mma->saved.z +
> +					   INCR_2G) >> SHIFT_2G);
> +		break;
> +	case DYN_RANGE_4G:
> +		mma->saved.x = le16_to_cpu((1000 * mma->saved.x +
> +					   INCR_4G) >> SHIFT_4G);
> +		mma->saved.y = le16_to_cpu((1000 * mma->saved.y +
> +					   INCR_4G) >> SHIFT_4G);
> +		mma->saved.z = le16_to_cpu((1000 * mma->saved.z +
> +					   INCR_4G) >> SHIFT_4G);
> +		break;
> +	case DYN_RANGE_8G:
> +		mma->saved.x = le16_to_cpu((1000 * mma->saved.x +
> +					   INCR_8G) >> SHIFT_8G);
> +		mma->saved.y = le16_to_cpu((1000 * mma->saved.y +
> +					   INCR_8G) >> SHIFT_8G);
> +		mma->saved.z = le16_to_cpu((1000 * mma->saved.z +
> +					   INCR_8G) >> SHIFT_8G);
> +		break;
> +	default:
> +		dev_err(&mma->client->dev, "internal data corrupt\n");
> +	}
> +	mutex_unlock(&mma->mutex);
> +}
> +
> +static void mma8653fc_get_orientation(struct mma8653fc *mma, u8 byte)
> +{
> +	if ((byte & LAPO_HIGH) && !(LAPO_LOW))
> +		mma->orientation = 'r'; /* landscape right */
> +	if (!(byte & LAPO_HIGH) && (byte & LAPO_LOW))
> +		mma->orientation = 'd'; /* portrait down */
> +	if (!(byte & LAPO_HIGH) && !(byte & LAPO_LOW))
> +		mma->orientation = 'u'; /* portrait up */
> +	if ((byte & LAPO_HIGH) && (byte & LAPO_LOW))
> +		mma->orientation = 'l'; /* landscape left */
> +
> +	if (byte & BAFRO)
> +		mma->bafro = 'b'; /* back facing */
> +	else
> +		mma->bafro = 'f'; /* front facing */

We could use defines here maybe:

#define LANDSCAPE_RIGHT 'r'

> +}
> +
> +static irqreturn_t mma8653fc_irq(int irq, void *handle)
> +{
> +	struct mma8653fc *mma = handle;
> +	u8 int_src;
> +	u8 byte;
> +
> +	int_src = mma->read(mma, MMA8653FC_INT_SOURCE);
> +	if (int_src & SRC_DRDY)
> +		/* data ready handle */

Where is the body of this if statement?

> +	if (int_src & SRC_FF_MT) {
> +		/* freefall/motion change handle */
> +		dev_dbg(&mma->client->dev,
> +			"freefall or motion change\n");
> +		byte = mma->read(mma, MMA8653FC_FF_MT_SRC);
> +	}
> +	if (int_src & SRC_LNDPRT) {
> +		/* landscape/portrait change handle */
> +		dev_dbg(&mma->client->dev,
> +			"landscape / portrait change\n");
> +		byte = mma->read(mma, MMA8653FC_PL_STATUS);
> +		mma8653fc_get_orientation(mma, byte);
> +	}
> +	if (int_src & SRC_ASLP)
> +		/* autosleep change handle */

Same.

> +	mma8653fc_get_triple(mma);
> +
> +	sysfs_notify(&mma->client->dev.kobj, NULL, "position");
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void __mma8653fc_enable(struct mma8653fc *mma)
> +{
> +	u8 byte;
> +
> +	byte = mma->read(mma, MMA8653FC_CTRL_REG1);
> +	mma->write(mma, MMA8653FC_CTRL_REG1, byte | ACTIVE_BIT);
> +}
> +
> +static void __mma8653fc_disable(struct mma8653fc *mma)
> +{
> +	u8 byte;
> +
> +	byte = mma->read(mma, MMA8653FC_CTRL_REG1);
> +	mma->write(mma, MMA8653FC_CTRL_REG1, byte & ~ACTIVE_BIT);
> +}
> +
> +static ssize_t mma8653fc_standby_show(struct device *dev,
> +				    struct device_attribute *attr, char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct mma8653fc *mma = i2c_get_clientdata(client);
> +
> +	return scnprintf(buf, PAGE_SIZE, "%u\n", mma->standby);
> +}
> +
> +static ssize_t mma8653fc_standby_store(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct mma8653fc *mma = i2c_get_clientdata(client);
> +	unsigned int val;
> +	int error;
> +
> +	error = kstrtouint(buf, 10, &val);
> +	if (error)
> +		return error;
> +
> +	mutex_lock(&mma->mutex);
> +
> +	if (val) {
> +		if (!mma->standby)
> +			__mma8653fc_disable(mma);
> +	} else {
> +		if (mma->standby)
> +			__mma8653fc_enable(mma);
> +	}
> +
> +	mma->standby = !!val;
> +
> +	mutex_unlock(&mma->mutex);
> +
> +	return count;
> +}
> +
> +static DEVICE_ATTR(standby, 0664, mma8653fc_standby_show,
> +				  mma8653fc_standby_store);
> +
> +static ssize_t mma8653fc_currentmode_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct mma8653fc *mma = i2c_get_clientdata(client);
> +	ssize_t count;
> +	u8 byte;
> +
> +	byte = mma->read(mma, MMA8653FC_SYSMOD);
> +	if (byte < 0)
> +		return byte;
> +
> +	switch (byte) {
> +	case STATE_STANDBY:
> +		count = scnprintf(buf, PAGE_SIZE, "standby\n");
> +		break;
> +	case STATE_WAKE:
> +		count = scnprintf(buf, PAGE_SIZE, "wake\n");
> +		break;
> +	case STATE_SLEEP:
> +		count = scnprintf(buf, PAGE_SIZE, "sleep\n");
> +		break;
> +	default:
> +		count = scnprintf(buf, PAGE_SIZE, "unknown\n");
> +	}
> +	return count;
> +}
> +static DEVICE_ATTR(currentmode, S_IRUGO, mma8653fc_currentmode_show, NULL);
> +
> +static ssize_t mma8653fc_position_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct mma8653fc *mma = i2c_get_clientdata(client);
> +	ssize_t count;
> +	u8 byte;
> +
> +	if (!mma->irq) {
> +		byte = mma->read(mma, MMA8653FC_PL_STATUS);
> +		if (byte & NEWLP)
> +			mma8653fc_get_orientation(mma, byte);
> +
> +		byte = mma->read(mma, MMA8653FC_STATUS);
> +		if (byte & ZYXDR)
> +			mma8653fc_get_triple(mma);
> +
> +		msleep(20);
> +		dev_dbg(&client->dev, "data polled\n");
> +	}
> +	mutex_lock(&mma->mutex);
> +	count = scnprintf(buf, PAGE_SIZE, "%d %d %d %c %c\n",
> +			mma->saved.x, mma->saved.y, mma->saved.z,
> +			mma->orientation, mma->bafro);
> +	mutex_unlock(&mma->mutex);
> +
> +	return count;
> +}
> +static DEVICE_ATTR(position, S_IRUGO, mma8653fc_position_show, NULL);
> +
> +static struct attribute *mma8653fc_attributes[] = {
> +	&dev_attr_position.attr,
> +	&dev_attr_standby.attr,
> +	&dev_attr_currentmode.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group mma8653fc_attr_group = {
> +	.attrs = mma8653fc_attributes,
> +};
> +
> +static u8 mma8653fc_read(struct mma8653fc *mma, unsigned char reg)
> +{
> +	u8 val;
> +
> +	val = i2c_smbus_read_byte_data(mma->client, reg);
> +	if (val < 0) {

u8 is never less than zero.

> +		dev_err(&mma->client->dev,
> +			"failed to read %x register\n", reg);
> +	}
> +	return val;
> +}
> +
> +static void mma8653fc_write(struct mma8653fc *mma, unsigned char reg,
> +			   unsigned char val)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_write_byte_data(mma->client, reg, val);
> +	if (ret) {
> +		dev_err(&mma->client->dev,
> +			"failed to write %x register\n", reg);
> +	}
> +}
> +
> +static const struct of_device_id mma8653fc_dt_ids[] = {
> +	{ .compatible = "fsl,mma8653fc", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, mma8653fc_dt_ids);
> +
> +static const struct mma8653fc_pdata *mma8653fc_probe_dt(struct device *dev)
> +{
> +	struct mma8653fc_pdata *pdata;
> +	struct device_node *node = dev->of_node;
> +	const struct of_device_id *match;
> +	u32 testu32;
> +	s32 tests32;
> +
> +	if (!node) {
> +		dev_err(dev, "no associated DT data\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	match = of_match_device(mma8653fc_dt_ids, dev);
> +	if (!match) {
> +		dev_err(dev, "unknown device model\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return ERR_PTR(-ENOMEM);
> +
> +	*pdata = mma8653fc_default_init;
> +
> +	/* overwrite from dts */
> +	testu32 = pdata->x_axis_offset;
> +	tests32 = 0;

Not used.

> +	of_property_read_u32(node, "x-offset", &testu32);
> +	tests32 = testu32 - DEFAULT_OFF;
> +	if ((tests32) && (tests32 <= DEFAULT_OFF) &&
> +	    (tests32 >= -DEFAULT_OFF)) {

Emacs adds parenthesis all over the place because it is trying to
convert the world to LISP.

> +		dev_info(dev, "use %dmg offset on X axis\n", tests32);
> +		/* calc register value, resolution: 1.96mg */
> +		pdata->x_axis_offset = (s8) (tests32 / 2);
> +	}
> +	testu32 = pdata->y_axis_offset;
> +	tests32 = 0;

Not used.

The signedness bug and the missing if statement bodies could have been
caught by Smatch I think.  It might be worth running.  It gets run
automatically after merging also.  http://smatch.sf.net

regards,
dan carpenter

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux