lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4CF91AAB.5030408@cam.ac.uk>
Date:	Fri, 03 Dec 2010 16:28:27 +0000
From:	Jonathan Cameron <jic23@....ac.uk>
To:	mems applications <mems.applications@...com>
CC:	dmitry.torokhov@...il.com, linux-input@...r.kernel.org,
	linux-kernel@...r.kernel.org, matteo.dameno@...com,
	carmine.iascone@...com
Subject: Re: [PATCH] input: misc: add lps001wp_prs driver

On 11/29/10 16:43, mems applications wrote:
> From: mems <mems@...s-laptopT43.(none)>
> 
> Added STMicroelectronics LPS001WP pressure sensor device driver

Hi All,

Firstly for those not following the thread. I am reviewing under
the assumption the driver will move out of input.


Review done backwards, so reading the email from the bottom may
make more sense...

There is a fair bit of general cleanup needed in this driver, but
the code looks fundamentally fine to me.

I'd like to see some documentation to accompany this driver.  Without
datasheet diving it's unclear what some of the interface elements are
for.

This is very much a first glance, but cleaning up the silly formatting
issues etc will make future reviews a lot easier.  As a general rule
do this sort of stuff before submitting as it keeps reviewers more
likely to read your drivers!

> 
> Signed-off-by: Matteo Dameno <matteo.dameno@...com>
> ---
>  drivers/input/misc/Kconfig        |   10 +
>  drivers/input/misc/Makefile       |    2 +
>  drivers/input/misc/lps001wp_prs.c | 1288 +++++++++++++++++++++++++++++++++++++
>  include/linux/input/lps001wp.h    |   82 +++
>  4 files changed, 1382 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/misc/lps001wp_prs.c
>  create mode 100644 include/linux/input/lps001wp.h
> 
> diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
> index b99b8cb..689856a 100644
> --- a/drivers/input/misc/Kconfig
> +++ b/drivers/input/misc/Kconfig
> @@ -448,4 +448,14 @@ config INPUT_ADXL34X_SPI
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called adxl34x-spi.
>  
> +config INPUT_LPS001WP_PRS
> +	tristate "STMicro LPS001WP Pressure Temperature Sensor"
> +	depends on I2C
> +	default n
> +	help
> +	 If you say yes here you get support for the 
> +	 STM LPS001D Barometer/Termometer on I2C bus.
Probably a typo in Termometer?  
> +	 This driver can also be built as a module (choose M).
> +	 If so, the module will be called lps001wp_prs.
> +
>  endif
> diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
> index 1fe1f6c..0165e60 100644
> --- a/drivers/input/misc/Makefile
> +++ b/drivers/input/misc/Makefile
> @@ -42,4 +42,6 @@ obj-$(CONFIG_INPUT_WINBOND_CIR)		+= winbond-cir.o
>  obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
>  obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
>  obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
> +obj-$(CONFIG_INPUT_LPS001WP_PRS)	+= lps001wp_prs.o
Side note. The rest of these were in alphabetical order by the look of it...
> +
>  
> diff --git a/drivers/input/misc/lps001wp_prs.c b/drivers/input/misc/lps001wp_prs.c
> new file mode 100644
> index 0000000..e1a3a95
> --- /dev/null
> +++ b/drivers/input/misc/lps001wp_prs.c
> @@ -0,0 +1,1288 @@
> +
> +/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
> +*
> +* File Name	: lps001wp_prs.c
> +* Authors	: MSH - Motion Mems BU - Application Team
> +*		: Matteo Dameno (matteo.dameno@...com)
> +*		: Carmine Iascone (carmine.iascone@...com)
> +*		: Both authors are willing to be considered the contact
> +*		: and update points for the driver.
> +* Version	: V 1.1.1
> +* Date		: 05/11/2010
> +* Description	: LPS001WP 6D module sensor API
> +*
> +********************************************************************************
> +*
> +* 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.
> +*
> +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
> +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
> +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
> +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
> +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
> +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
> +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
> +*
> +* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
> +*
> +******************************************************************************
> +
> + Revision 0.9.0 01/10/2010:
> +	first beta release
> + Revision 1.1.0 05/11/2010:
> +	add sysfs management
> + Revision 1.1.1 22/11/2010:
> +	moved to input/misc
> +	updated USHRT_MAX,SHRT_MAX,SHRT_MIN macros
> +******************************************************************************/
> +
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/i2c.h>
> +
> +#include <linux/input.h>
> +#include <linux/uaccess.h>
> +
> +#include <linux/workqueue.h>
> +#include <linux/irq.h>
> +#include <linux/gpio.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/input/lps001wp.h>
> +
> +
> +
> +#define	DEBUG	1
This shouldn't be in a submitted driver....

> +
> +
> +#define	PR_ABS_MAX	USHRT_MAX
> +
> +#define	PR_ABS_MIN	(u16)(0U)
> +#define	PR_DLT_MAX	SHRT_MAX
> +#define	PR_DLT_MIN	SHRT_MIN
> +#define	TEMP_MAX	SHRT_MAX
> +#define TEMP_MIN	SHRT_MIN
> +
> +
> +#define	SENSITIVITY_T_SHIFT	6	/** =	64 LSB/degrC	*/
> +#define	SENSITIVITY_P_SHIFT	4	/** =	16 LSB/mbar	*/
> +
> +
> +#define	OUTDATA_REG	0x28
> +#define	INDATA_REG	0X30
> +
> +#define	WHOAMI_LPS001WP_PRS	0xBA	/*	Expctd content for WAI	*/
> +
> +/*	CONTROL REGISTERS	*/
> +#define	WHO_AM_I	0x0F		/*	WhoAmI register		*/
> +#define	CTRL_REG1	0x20		/*	power / ODR control reg	*/
> +#define	CTRL_REG2	0x21		/*	boot reg		*/
> +#define	CTRL_REG3	0x22		/*	interrupt control reg	*/
> +
> +#define	STATUS_REG	0X27		/*	status reg		*/
> +
> +#define PRESS_OUT_L	OUTDATA_REG
> +
> +
> +#define	REF_P_L		INDATA_REG	/*	pressure reference	*/
> +#define	REF_P_H		0x31		/*	pressure reference	*/
> +#define	THS_P_L		0x32		/*	pressure threshold	*/
> +#define	THS_P_H		0x33		/*	pressure threshold	*/
> +
> +#define	INT_CFG		0x34		/*	interrupt config	*/
> +#define	INT_SRC		0x35		/*	interrupt source	*/
> +#define	INT_ACK		0x36		/*	interrupt acknoledge	*/
> +/*	end CONTROL REGISTRES	*/
> +
> +
> +/* Barometer and Termometer output data rate ODR */
> +#define	LPS001WP_PRS_ODR_MASK	0x30	/* Mask to access odr bits only	*/
> +#define	LPS001WP_PRS_ODR_7_1	0x00	/* 7Hz baro and 1Hz term ODR	*/
> +#define	LPS001WP_PRS_ODR_7_7	0x01	/* 7Hz baro and 7Hz term ODR	*/
> +#define	LPS001WP_PRS_ODR_12_12	0x11	/* 12.5Hz baro and 12.5Hz term ODR */
> +
> +
> +#define	LPS001WP_PRS_ENABLE_MASK	0x40	/*  */ 
?
> +#define	LPS001WP_PRS_DIFF_MASK		0x08
> +#define LPS001WP_PRS_LPOW_MASK		0x80
inconsistent.
> +
> +#define	LPS001WP_PRS_DIFF_ON		0x08
> +#define	LPS001WP_PRS_DIFF_OFF		0x00
> +
> +#define	LPS001WP_PRS_LPOW_ON		0x80
> +#define	LPS001WP_PRS_LPOW_OFF		0x00
> +
> +#define	FUZZ			0
> +#define	FLAT			0
> +#define	I2C_RETRY_DELAY		5
> +#define	I2C_RETRIES		5
> +#define	I2C_AUTO_INCREMENT	0x80
> +
> +/* RESUME STATE INDICES */
> +#define	RES_CTRL_REG1		0
> +#define	RES_CTRL_REG2		1
> +#define	RES_CTRL_REG3		2
> +#define	RES_REF_P_L		3
> +#define	RES_REF_P_H		4
> +#define	RES_THS_P_L		5
> +#define	RES_THS_P_H		6
> +#define	RES_INT_CFG		7
> +
> +#define	RESUME_ENTRIES		8
Ideally all these defines would be more device specific
LPS001WP_RES_CTRL_REG1 etc as it makes accidental clashes
much less likely in future.

> +/* end RESUME STATE INDICES */
The fact you start something else probably gives this
away without the comment...
> +
> +/* Pressure Sensor Operating Mode */
> +#define	LPS001WP_PRS_DIFF_ENABLE	1
> +#define LPS001WP_PRS_DIFF_DISABLE	0
inconsistent formatting here. Also you appear to be
defining true and false here. Probably not a good idea...

> +#define	LPS001WP_PRS_LPOWER_EN		1
> +#define	LPS001WP_PRS_LPOWER_DIS		0
> +
> +static const struct {
> +	unsigned int cutoff_ms;
> +	unsigned int mask;
> +} lps001wp_prs_odr_table[] = {
> +		{80,	LPS001WP_PRS_ODR_12_12 },
> +		{143,	LPS001WP_PRS_ODR_7_7 },
> +		{1000,	LPS001WP_PRS_ODR_7_1 },
> +};
> +
> +struct lps001wp_prs_data {
> +	struct i2c_client *client;
> +	struct lps001wp_prs_platform_data *pdata;
> +
> +	struct mutex lock;
> +	struct delayed_work input_work;
> +
> +	struct input_dev *input_dev;
> +
> +	int hw_initialized;
> +	/* hw_working=-1 means not tested yet */
> +	int hw_working;
> +	u8 diff_enabled;
> +	u8 lpowmode_enabled ;
> +
> +	atomic_t enabled;
> +	int on_before_suspend;
> +
> +	u8 resume_state[RESUME_ENTRIES];
> +
> +#ifdef DEBUG
> +	u8 reg_addr;
> +#endif
> +};
> +
> +struct outputdata {
> +	u16 abspress;
> +	s16 temperature;
> +	s16 deltapress;
> +};
> +
> +
> +static int lps001wp_prs_i2c_read(struct lps001wp_prs_data *prs,
> +				  u8 *buf, int len)
> +{
> +	int err;
> +	int tries = 0;
> +
> +	struct i2c_msg msgs[] = {
> +		{
> +		 .addr = prs->client->addr,
> +		 .flags = prs->client->flags & I2C_M_TEN,
> +		 .len = 1,
> +		 .buf = buf,
> +		 },
}, {
> +		{
> +		 .addr = prs->client->addr,
> +		 .flags = (prs->client->flags & I2C_M_TEN) | I2C_M_RD,
> +		 .len = len,
> +		 .buf = buf,
> +		 },
> +	};
> +
> +	do {
> +		err = i2c_transfer(prs->client->adapter, msgs, 2);
> +		if (err != 2)
> +			msleep_interruptible(I2C_RETRY_DELAY);
> +	} while ((err != 2) && (++tries < I2C_RETRIES));
> +
> +	if (err != 2) {
> +		dev_err(&prs->client->dev, "read transfer error\n");
> +		err = -EIO;
> +	} else {
> +		err = 0;
> +	}
> +
> +	return err;
> +}
> +
> +static int lps001wp_prs_i2c_write(struct lps001wp_prs_data *prs,
> +				   u8 *buf, int len)
> +{
> +	int err;
> +	int tries = 0;
> +	struct i2c_msg msgs[] = {
> +		{
> +		 .addr = prs->client->addr,
> +		 .flags = prs->client->flags & I2C_M_TEN,
> +		 .len = len + 1,
> +		 .buf = buf,
> +		 },
> +	};
> +
> +	do {
> +		err = i2c_transfer(prs->client->adapter, msgs, 1);
> +		if (err != 1)
> +			msleep_interruptible(I2C_RETRY_DELAY);
> +	} while ((err != 1) && (++tries < I2C_RETRIES));
> +
i2c transfre may have given a real error, so check that first and
pass on if it did. This check then confirms that it sent the right
amount of data.  Does this commonly fail?  It's unusual to hard code
in retrying unless you know a part unless there is a very specific
and well understood reason for it.

> +	if (err != 1) {
> +		dev_err(&prs->client->dev, "write transfer error\n");
> +		err = -EIO;
> +	} else {
> +		err = 0;
> +	}
> +
> +	return err;
> +}
> +
> +static int lps001wp_prs_i2c_update(struct lps001wp_prs_data *prs,
> +			u8 reg_address, u8 mask, u8 new_bit_values)
> +{
> +	int err = -1;
Why init?
> +	u8 rdbuf[1] = { reg_address };
> +	u8 wrbuf[2] = { reg_address , 0x00 };
> +
> +	u8 init_val;
> +	u8 updated_val;
> +	err = lps001wp_prs_i2c_read(prs, rdbuf, 1);
> +	if (!(err < 0)) {
> +		init_val = rdbuf[0];
> +		updated_val = ((mask & new_bit_values) | ((~mask) & init_val));
> +		wrbuf[1] = updated_val;
> +		err = lps001wp_prs_i2c_write(prs, wrbuf, 2);
> +	}
> +	return err;
> +}
> +/* */
> +
> +static int lps001wp_prs_register_write(struct lps001wp_prs_data *prs, u8 *buf,
> +		u8 reg_address, u8 new_value)
> +{
> +	int err = -1;
No need to init.
> +
> +	/* Sets configuration register at reg_address
> +	 *  NOTE: this is a straight overwrite  */
> +	buf[0] = reg_address;
> +	buf[1] = new_value;
> +	err = lps001wp_prs_i2c_write(prs, buf, 1);
> +	if (err < 0)
> +		return err;
> +	return err;
> +}
> +
> +static int lps001wp_prs_register_read(struct lps001wp_prs_data *prs, u8 *buf,
> +		u8 reg_address)
> +{
> +
> +	int err = -1;
No need to init.

> +	buf[0] = (reg_address);
No need for brackets.

> +	err = lps001wp_prs_i2c_read(prs, buf, 1);
> +
> +	return err;
> +}
> +
> +static int lps001wp_prs_register_update(struct lps001wp_prs_data *prs, u8 *buf,
> +		u8 reg_address, u8 mask, u8 new_bit_values)
> +{
> +	int err = -1;
> +	u8 init_val;
> +	u8 updated_val;
> +	err = lps001wp_prs_register_read(prs, buf, reg_address);
> +	if (!(err < 0)) {
> +		init_val = buf[0];
> +		updated_val = ((mask & new_bit_values) | ((~mask) & init_val));
> +		err = lps001wp_prs_register_write(prs, buf, reg_address,
> +				updated_val);
> +	}
> +	return err;
> +}
> +
> +/* */
Nice comment....
> +
> +
> +static int lps001wp_prs_hw_init(struct lps001wp_prs_data *prs)
> +{
> +	int err = -1;
> +	u8 buf[6];
> +
We don't need to know this now the driver is written.
> +	printk(KERN_DEBUG "%s: hw init start\n", LPS001WP_PRS_DEV_NAME);
> +
> +	buf[0] = WHO_AM_I;
> +	err = lps001wp_prs_i2c_read(prs, buf, 1);
> +	if (err < 0)
> +		goto error_firstread;
> +	else
> +		prs->hw_working = 1;
> +	if (buf[0] != WHOAMI_LPS001WP_PRS) {
> +		err = -1; /* TODO:choose the right coded error */
> +		goto error_unknown_device;
> +	}
> +
> +
> +	buf[0] = (I2C_AUTO_INCREMENT | INDATA_REG);
> +	buf[1] = prs->resume_state[RES_REF_P_L];
> +	buf[2] = prs->resume_state[RES_REF_P_H];
> +	buf[3] = prs->resume_state[RES_THS_P_L];
> +	buf[4] = prs->resume_state[RES_THS_P_H];
> +	err = lps001wp_prs_i2c_write(prs, buf, 4);
> +	if (err < 0)
> +		goto error1;
> +
> +	buf[0] = (I2C_AUTO_INCREMENT | CTRL_REG1);
> +	buf[1] = prs->resume_state[RES_CTRL_REG1];
> +	buf[2] = prs->resume_state[RES_CTRL_REG2];
> +	buf[3] = prs->resume_state[RES_CTRL_REG3];
> +	err = lps001wp_prs_i2c_write(prs, buf, 3);
> +	if (err < 0)
> +		goto error1;
> +
> +	buf[0] = INT_CFG;
> +	buf[1] = prs->resume_state[RES_INT_CFG];
> +	err = lps001wp_prs_i2c_write(prs, buf, 1);
> +	if (err < 0)
> +		goto error1;
> +
> +
> +	prs->hw_initialized = 1;
We really don't need to know this unless it commonly fails?
> +	printk(KERN_DEBUG "%s: hw init done\n", LPS001WP_PRS_DEV_NAME);
> +	return 0;
> +
> +error_firstread:
> +	prs->hw_working = 0;
> +	dev_warn(&prs->client->dev, "Error reading WHO_AM_I: is device "
> +		"available/working?\n");
> +	goto error1;
> +error_unknown_device:
> +	dev_err(&prs->client->dev,
> +		"device unknown. Expected: 0x%x,"
> +		" Replies: 0x%x\n", WHOAMI_LPS001WP_PRS, buf[0]);
> +error1:
> +	prs->hw_initialized = 0;
> +	dev_err(&prs->client->dev, "hw init error 0x%x,0x%x: %d\n", buf[0],
> +			buf[1], err);
> +	return err;
> +}
> +
> +static void lps001wp_prs_device_power_off(struct lps001wp_prs_data *prs)
> +{
> +	int err;
> +	u8 buf[2] = { CTRL_REG1, LPS001WP_PRS_PM_OFF };
> +
> +	err = lps001wp_prs_i2c_write(prs, buf, 1);
> +	if (err < 0)
> +		dev_err(&prs->client->dev, "soft power off failed: %d\n", err);
> +
> +	if (prs->pdata->power_off) {
> +		prs->pdata->power_off();
> +		prs->hw_initialized = 0;
> +	}
> +	if (prs->hw_initialized) {
> +		; 
?

> +		prs->hw_initialized = 0;
> +	}
checkpatch will tell you that you have unneeded brackets...
> +
> +}
> +
> +static int lps001wp_prs_device_power_on(struct lps001wp_prs_data *prs)
> +{
> +	int err = -1;
> +
> +	if (prs->pdata->power_on) {
> +		err = prs->pdata->power_on();
> +		if (err < 0) {
> +			dev_err(&prs->client->dev,
> +					"power_on failed: %d\n", err);
> +			return err;
> +		}
> +	}
> +
> +	if (!prs->hw_initialized) {
> +		err = lps001wp_prs_hw_init(prs);
> +		if (prs->hw_working == 1 && err < 0) {
> +			lps001wp_prs_device_power_off(prs);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +
> +
> +int lps001wp_prs_update_odr(struct lps001wp_prs_data *prs, int poll_interval_ms)
> +{
> +	int err = -1;
> +	int i;
> +
> +	u8 buf[2];
> +	u8 updated_val;
> +	u8 init_val;
> +	u8 new_val;
> +	u8 mask = LPS001WP_PRS_ODR_MASK;
> +
> +	/* Following, looks for the longest possible odr interval scrolling the
> +	 * odr_table vector from the end (shortest interval) backward (longest
> +	 * interval), to support the poll_interval requested by the system.
> +	 * It must be the longest interval lower then the poll interval.*/
> +	for (i = ARRAY_SIZE(lps001wp_prs_odr_table) - 1; i >= 0; i--) {
> +		if (lps001wp_prs_odr_table[i].cutoff_ms <= poll_interval_ms)
> +			break;
> +	}
> +
> +	new_val = lps001wp_prs_odr_table[i].mask;
> +
> +	/* If device is currently enabled, we need to write new
> +	 *  configuration out to it */
> +	if (atomic_read(&prs->enabled)) {
> +		buf[0] = CTRL_REG1;
> +		err = lps001wp_prs_i2c_read(prs, buf, 1);
> +		if (err < 0)
> +			goto error;
> +		init_val = buf[0];
> +		prs->resume_state[RES_CTRL_REG1] = init_val;
> +
> +		buf[0] = CTRL_REG1;
> +		updated_val = ((mask & new_val) | ((~mask) & init_val));
> +		buf[1] = updated_val;
> +		buf[0] = CTRL_REG1;
You just set buf[0] 3 lines up...

> +		err = lps001wp_prs_i2c_write(prs, buf, 1);
> +		if (err < 0)
> +			goto error;
> +		prs->resume_state[RES_CTRL_REG1] = updated_val;
> +	}
> +	return err;
> +
> +error:
> +	dev_err(&prs->client->dev, "update odr failed 0x%x,0x%x: %d\n",
> +			buf[0], buf[1], err);
> +
> +	return err;
> +}
> +
> +static int lps001wp_prs_set_press_reference(struct lps001wp_prs_data *prs,
> +				u16 new_reference)
> +{
> +	int err = -1;
> +	u8 const reg_addressL = REF_P_L;
> +	u8 const reg_addressH = REF_P_H;
> +	u8 bit_valuesL, bit_valuesH;
> +	u8 buf[2];
> +
> +	bit_valuesL = (u8) (new_reference & 0x00FF);
> +	bit_valuesH = (u8)((new_reference & 0xFF00) >> 8);
> +
> +	err = lps001wp_prs_register_write(prs, buf, reg_addressL,
> +			bit_valuesL);
> +	if (err < 0)
> +		return err;
> +	err = lps001wp_prs_register_write(prs, buf, reg_addressH,
> +			bit_valuesH);
> +	if (err < 0) {
> +		lps001wp_prs_register_write(prs, buf, reg_addressL,
> +				prs->resume_state[RES_REF_P_L]);
> +		return err;
> +	}
> +	prs->resume_state[RES_REF_P_L] = bit_valuesL;
> +	prs->resume_state[RES_REF_P_H] = bit_valuesH;
> +	return err;
> +}
> +
> +static int lps001wp_prs_get_press_reference(struct lps001wp_prs_data *prs,
> +		u16 *buf16)
> +{
> +	int err = -1;
why init?
> +
> +	u8 bit_valuesL, bit_valuesH;
> +	u8 buf[2] = {0};
Does it need to be initilaized?

> +	u16 temp = 0;
> +
> +	err = lps001wp_prs_register_read(prs, buf, REF_P_L);
> +	if (err < 0)
> +		return err;
> +	bit_valuesL = buf[0];
> +	err = lps001wp_prs_register_read(prs, buf, REF_P_H);
> +	if (err < 0)
> +		return err;
> +	bit_valuesH = buf[0];
> +
> +	temp = (((u16) bit_valuesH) << 8);
> +	*buf16 = (temp | ((u16) bit_valuesL));
> +
> +	return err;
> +}
> +
> +static int lps001wp_prs_lpow_manage(struct lps001wp_prs_data *prs, u8 control)
> +{
> +	int err = -1;
> +	u8 buf[2] = {0x00, 0x00};
> +	u8 const mask = LPS001WP_PRS_LPOW_MASK;
> +	u8 bit_values = LPS001WP_PRS_LPOW_OFF;
> +
> +	if (control >= LPS001WP_PRS_LPOWER_EN) {
Is this just verifying if the value is not 0?  If so get
rid of the confusing define and just do
if (control)
> +		;
?
> +		bit_values = LPS001WP_PRS_LPOW_ON;
> +	}
> +
> +	err = lps001wp_prs_register_update(prs, buf, CTRL_REG1,
> +			mask, bit_values);
> +
> +	if (err < 0)
> +		return err;
> +	prs->resume_state[RES_CTRL_REG1] = ((mask & bit_values) |
> +			(~mask & prs->resume_state[RES_CTRL_REG1]));
> +	if (bit_values == LPS001WP_PRS_LPOW_ON)
> +		prs->lpowmode_enabled = 1;
> +	else
> +		prs->lpowmode_enabled = 0;
> +	return err;
> +}
> +
> +static int lps001wp_prs_diffen_manage(struct lps001wp_prs_data *prs, u8 control)
> +{
> +	int err = -1;
No need to init.
> +	u8 buf[2] = {0x00, 0x00};
Need to init buf?

> +	u8 const mask = LPS001WP_PRS_DIFF_MASK;
> +	u8 bit_values = LPS001WP_PRS_DIFF_OFF;
> +
> +	if (control >= LPS001WP_PRS_DIFF_ENABLE) {
Checking if 0. Make that apparent, don't hide it in a define.
> +		;
?
> +		bit_values = LPS001WP_PRS_DIFF_ON;
> +	}
Please run checkpatch.pl over this as there are some element I
would imagine it will point out in the formating.

> +
> +	err = lps001wp_prs_register_update(prs, buf, CTRL_REG1,
> +			mask, bit_values);
> +
> +	if (err < 0)
> +		return err;
> +	prs->resume_state[RES_CTRL_REG1] = ((mask & bit_values) |
> +			(~mask & prs->resume_state[RES_CTRL_REG1]));
> +	if (bit_values == LPS001WP_PRS_DIFF_ON)
> +		prs->diff_enabled = 1;
> +	else
> +		prs->diff_enabled = 0;
prs->diff_enabled = !!(bit_values ==  LPS001WP_PRS_DIFF_ON);

> +	return err;
> +}
> +
> +
> +static int lps001wp_prs_get_presstemp_data(struct lps001wp_prs_data *prs,
> +						struct outputdata *out)
> +{
> +	int err = -1;
> +	/* Data bytes from hardware	PRESS_OUT_L, PRESS_OUT_H,
> +	 *				TEMP_OUT_L, TEMP_OUT_H,
> +	 *				DELTA_L, DELTA_H */
> +	u8 prs_data[6];

u8 prs_data[6] = {
   (I2C_AUTO_INCREMENT | OUTDATA_REG),   
}; 

Technically may be more computationaly expensive, but only marginally
and it's easier to read. Note all other values will be zeroed.
> +
> +	u16 abspr;
> +	s16 temperature, deltapr;
> +	int regToRead = 4;
> +	prs_data[4] = 0;
> +	prs_data[5] = 0;
> +
> +	if (prs->diff_enabled)
> +		regToRead = 6;
> +
> +	prs_data[0] = (I2C_AUTO_INCREMENT | OUTDATA_REG);
> +	err = lps001wp_prs_i2c_read(prs, prs_data, regToRead);
> +	if (err < 0)
> +		return err;
> +
> +	abspr = ((((u16) prs_data[1] << 8) | ((u16) prs_data[0])));
As prs_data is aligned you can use soem of the endian switching functions
to do this.

> +	temperature = ((s16) (((u16) prs_data[3] << 8) | ((u16)prs_data[2])));
> +
> +	out->abspress = abspr;
Why the use of temporaries to construct these values if you are only going to
assign them here?
> +	out->temperature = temperature;
> +
> +	deltapr = ((s16) (((u16) prs_data[5] << 8) | ((u16)prs_data[4])));
Again, suitable endian funcs should do this nice and cleanly. It also may
not be necessary depending on endianness of the machine (may be a simple
copy).
> +	out->deltapress = deltapr;
> +
> +	return err;
> +}
> +
> +static void lps001wp_prs_report_values(struct lps001wp_prs_data *prs,
> +					struct outputdata *out)
> +{
> +	input_report_abs(prs->input_dev, ABS_PR, out->abspress);
> +	input_report_abs(prs->input_dev, ABS_TEMP, out->temperature);
> +	input_report_abs(prs->input_dev, ABS_DLTPR, out->deltapress);
> +	input_sync(prs->input_dev);
> +}
> +
> +static int lps001wp_prs_enable(struct lps001wp_prs_data *prs)
> +{
> +	int err;
> +
> +	if (!atomic_cmpxchg(&prs->enabled, 0, 1)) {
> +		err = lps001wp_prs_device_power_on(prs);
> +		if (err < 0) {
> +			atomic_set(&prs->enabled, 0);
> +			return err;
> +		}
> +		schedule_delayed_work(&prs->input_work,
> +			msecs_to_jiffies(prs->pdata->poll_interval));
> +	}
> +
> +	return 0;
> +}
> +
> +static int lps001wp_prs_disable(struct lps001wp_prs_data *prs)
> +{
> +	if (atomic_cmpxchg(&prs->enabled, 1, 0)) {
> +		cancel_delayed_work_sync(&prs->input_work);
> +		lps001wp_prs_device_power_off(prs);
> +	}
> +
> +	return 0;
> +}
> +
> +static ssize_t read_single_reg(struct device *dev, char *buf, u8 reg)
> +{
> +	ssize_t ret;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	int rc = 0;
> +
> +	u8 data = reg;
> +	rc = lps001wp_prs_i2c_read(prs, &data, 1);
> +	/*TODO: error need to be managed */
> +	ret = sprintf(buf, "0x%02x\n", data);
That's going to want fixing :) Actually function doesn't seem to be
called so clean it out entirely.

> +	return ret;
> +
> +}
> +
> +static int write_reg(struct device *dev, const char *buf, u8 reg)
Is this used anywhere?
> +{
> +	int rc = 0;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	u8 x[2];
> +	unsigned long val;
> +
> +	if (strict_strtoul(buf, 16, &val))
> +		return -EINVAL;
> +
> +	x[0] = reg;
> +	x[1] = val;
> +	rc = lps001wp_prs_i2c_write(prs, x, 1);
> +	/*TODO: error need to be managed */
> +	return rc;
> +}
> +
> +static ssize_t attr_get_polling_rate(struct device *dev,
> +				     struct device_attribute *attr,
> +				     char *buf)
> +{
> +	int val;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	mutex_lock(&prs->lock);
> +	val = prs->pdata->poll_interval;
> +	mutex_unlock(&prs->lock);
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t attr_set_polling_rate(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t size)
> +{
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long interval_ms;
> +
> +	if (strict_strtoul(buf, 10, &interval_ms))
> +		return -EINVAL;
> +	if (!interval_ms)
> +		return -EINVAL;
> +	mutex_lock(&prs->lock);
> +	prs->pdata->poll_interval = interval_ms;
> +	lps001wp_prs_update_odr(prs, interval_ms);
> +	mutex_unlock(&prs->lock);
> +	return size;
> +}
> +
> +static ssize_t attr_get_diff_enable(struct device *dev,
> +				     struct device_attribute *attr,
> +				     char *buf)
> +{
> +	u8 val;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	mutex_lock(&prs->lock);
> +	val = prs->diff_enabled;
> +	mutex_unlock(&prs->lock);
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t attr_set_diff_enable(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t size)
> +{
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long val;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	mutex_lock(&prs->lock);
I'm unclear what values val can take here. They look a little bit
magic to me...
> +	lps001wp_prs_diffen_manage(prs, (u8) val);
> +	mutex_unlock(&prs->lock);
> +	return size;
> +}
> +
> +static ssize_t attr_get_enable(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	int val = atomic_read(&prs->enabled);
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t attr_set_enable(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long val;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	if (val)
> +		lps001wp_prs_enable(prs);
> +	else
> +		lps001wp_prs_disable(prs);
> +
> +	return size;
> +}
> +
> +static ssize_t attr_get_press_ref(struct device *dev,
> +				  struct device_attribute *attr, char *buf)
> +{
> +	int err = -1;
No need to initialize err.
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	u16 val = 0;
or I'd imagine val?
> +
> +	mutex_lock(&prs->lock);
> +	err = lps001wp_prs_get_press_reference(prs, &val);
> +	mutex_unlock(&prs->lock);
> +	if (err < 0)
> +		return err;
> +
> +	return sprintf(buf, "%d\n", val);
> +}
> +
What are the units of the reference pressure?  If they are not
in appropriate SI units, then either you will want to convert them
or take a look at how we handle _scale and _offset in IIO.
> +static ssize_t attr_set_press_ref(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf, size_t size)
> +{
> +	int err = -1;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long val = 0;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	if (val < PR_ABS_MIN || val > PR_ABS_MAX)
> +		return -EINVAL;
> +
> +	mutex_lock(&prs->lock);
> +	err = lps001wp_prs_set_press_reference(prs, val);
> +	mutex_unlock(&prs->lock);
> +	if (err < 0)
> +		return err;
> +	return size;
> +}
> +
> +
> +static ssize_t attr_get_lowpowmode(struct device *dev,
> +				   struct device_attribute *attr, char *buf)
> +{
> +	u8 val;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	mutex_lock(&prs->lock);
> +	val = prs->lpowmode_enabled;
> +	mutex_unlock(&prs->lock);
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t attr_set_lowpowmode(struct device *dev,
> +				   struct device_attribute *attr,
> +				   const char *buf, size_t size)
> +{
> +	int err = -1;
err is always set. So no need to initialize.
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long val;
> +
> +	if (strict_strtoul(buf, 10, &val))
> +		return -EINVAL;
> +
> +	mutex_lock(&prs->lock);
> +	err = lps001wp_prs_lpow_manage(prs, (u8) val);
This looks like it might involve some magic numbers.  Documentation
might show be to be wrong, but it certainly looks suspicious.

> +	mutex_unlock(&prs->lock);
> +	if (err < 0)
> +		return err;
Blank line here would make this more readable.
> +	return size;
> +}
> +
> +
> +#ifdef DEBUG
None of these have any place in a driver being submitted to the kernel.
Please remove them.

> +static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	int rc;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	u8 x[2];
> +	unsigned long val;
> +
> +	if (strict_strtoul(buf, 16, &val))
> +		return -EINVAL;
> +	mutex_lock(&prs->lock);
> +	x[0] = prs->reg_addr;
> +	mutex_unlock(&prs->lock);
> +	x[1] = val;
> +	rc = lps001wp_prs_i2c_write(prs, x, 1);
> +	/*TODO: error need to be managed */
> +	return size;
> +}
> +
> +static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr,
> +				char *buf)
> +{
> +	ssize_t ret;
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	int rc;
> +	u8 data;
> +
> +	mutex_lock(&prs->lock);
> +	data = prs->reg_addr;
> +	mutex_unlock(&prs->lock);
> +	rc = lps001wp_prs_i2c_read(prs, &data, 1);
> +	/*TODO: error need to be managed */
> +	ret = sprintf(buf, "0x%02x\n", data);
> +	return ret;
> +}
> +
> +static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	struct lps001wp_prs_data *prs = dev_get_drvdata(dev);
> +	unsigned long val;
> +	if (strict_strtoul(buf, 16, &val))
> +		return -EINVAL;
> +	mutex_lock(&prs->lock);
> +	prs->reg_addr = val;
> +	mutex_unlock(&prs->lock);
> +	return size;
> +}
> +#endif
> +
> +
> +
> +static struct device_attribute attributes[] = {
* These all need documentation as they add new attributes to sysfs. Documentation/abi/
is the place to put it in the relevant format.
* Secondly we need to standarise these interfaces as much as possible in order
to allow for userspace code to work with different phyiscal sensors. This is a lot
of what we have been doing in IIO. 

First general point on interfaces.  Always take into account that other devices
may provide additional functionality to what you are doing so you MUST make
names specific to what they actually control.

> +	__ATTR(pollrate_ms, 0664, attr_get_polling_rate, attr_set_polling_rate),
Rate is a very confusing term to use.  In many cases, e.g. data rate it would
be measured in say bits per second. Hence it would be a frequency of the sending
of a bit.  Thus it can't be measured in millisecs.  Period is a more appropriate
term. IIO went with frequency in Hz to avoid exactly this confusion.

> +	__ATTR(enable, 0664, attr_get_enable, attr_set_enable),
enable what?

> +	__ATTR(diff_enable, 0664, attr_get_diff_enable, attr_set_diff_enable),
enable difference of what?

> +	__ATTR(press_reference, 0664, attr_get_press_ref, attr_set_press_ref),
This is the first one to mention press (pressure?). That's good, but the meaning
of reference is a bit device specific. Perhaps documentation would convince
me it is a good choice of name.
> +	__ATTR(lowpow_enable, 0664, attr_get_lowpowmode, attr_set_lowpowmode),
Again this is very device specific. With documentation we might be able to discuss
more useful naming or whether this is the appropriate option.

Get these debug elements out of the interface. This sort of raw access doesn't belong is sysfs.
> +#ifdef DEBUG
> +	__ATTR(reg_value, 0664, attr_reg_get, attr_reg_set),
> +	__ATTR(reg_addr, 0220, NULL, attr_addr_set),
> +#endif
> +};
Why not use an attribute_group and standard registration functions to
add this lot?
> +
Please rename function to be more driver specific. This sort
of general name could well be used and exported elsewhere in the kernel.

> +static int create_sysfs_interfaces(struct device *dev)
> +{
> +	int i;
> +	for (i = 0; i < ARRAY_SIZE(attributes); i++)
> +		if (device_create_file(dev, attributes + i))
I guess this returns a useful error. So don't eat it, but instead
return that from this function and pass on appropriately.
> +			goto error;
> +	return 0;
> +
> +error:
> +	for ( ; i >= 0; i--)
> +		device_remove_file(dev, attributes + i);
> +	dev_err(dev, "%s:Unable to create interface\n", __func__);
> +	return -1;
> +}
> +
> +static int remove_sysfs_interfaces(struct device *dev)
> +{
> +	int i;
> +	for (i = 0; i < ARRAY_SIZE(attributes); i++)
> +		device_remove_file(dev, attributes + i);
> +	return 0;
This never returns anything useful so make function void and
don't bother returning anything.
> +}
> +
> +
> +static void lps001wp_prs_input_work_func(struct work_struct *work)
> +{
> +	struct lps001wp_prs_data *prs;
> +
> +	struct outputdata output;
> +	struct outputdata *out = &output;
> +	int err;
> +
> +	prs = container_of((struct delayed_work *)work,
> +				struct lps001wp_prs_data, input_work);
  It's simply macro based pointer magic so i'd just have
struct lps001wp_prs_data *prs = container_of((struct delayed_work *)work,
       			struct lps001wp_prs_data, input_work);
at the top of the function.
> +
> +	mutex_lock(&prs->lock);
> +	err = lps001wp_prs_get_presstemp_data(prs, out);
out is never modified, so why not use &output directly in the call and
remove out entirely?
> +	if (err < 0)
> +		dev_err(&prs->client->dev, "get_pressure_data failed\n");
> +	else
> +		lps001wp_prs_report_values(prs, out);
> +
> +	schedule_delayed_work(&prs->input_work,
> +				msecs_to_jiffies(prs->pdata->poll_interval));
> +	mutex_unlock(&prs->lock);
> +}
> +
> +int lps001wp_prs_input_open(struct input_dev *input)
> +{
> +	struct lps001wp_prs_data *prs = input_get_drvdata(input);
> +
> +	return lps001wp_prs_enable(prs);
> +}
> +
> +void lps001wp_prs_input_close(struct input_dev *dev)
> +{
> +	struct lps001wp_prs_data *prs = input_get_drvdata(dev);
lps001wp_prs_disable(input_get_drvdata(dev));
is shorter and still pretty clear.
> +
> +	lps001wp_prs_disable(prs);
> +}
> +
> +
> +static int lps001wp_prs_validate_pdata(struct lps001wp_prs_data *prs)
> +{
> +	prs->pdata->poll_interval = max(prs->pdata->poll_interval,
> +					prs->pdata->min_interval);
> +
This leave poll_interval as either poll_interval before this or min_interval.

The next line verifies poll_interval is less than min_interval. Obviously
that's not the case if it is min_interval.

Hence I think whole case could be written as
if (poll_interval < min_interval)
   return -EINVAL;
> +	/* Enforce minimum polling interval */
> +	if (prs->pdata->poll_interval < prs->pdata->min_interval) {
> +		dev_err(&prs->client->dev, "minimum poll interval violated\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int lps001wp_prs_input_init(struct lps001wp_prs_data *prs)
> +{
> +	int err;
> +
> +	INIT_DELAYED_WORK(&prs->input_work, lps001wp_prs_input_work_func);
> +	prs->input_dev = input_allocate_device();
> +	if (!prs->input_dev) {
> +		err = -ENOMEM;
> +		dev_err(&prs->client->dev, "input device allocate failed\n");
> +		goto err0;
> +	}
> +
> +	prs->input_dev->open = lps001wp_prs_input_open;
> +	prs->input_dev->close = lps001wp_prs_input_close;
> +	prs->input_dev->name = LPS001WP_PRS_DEV_NAME;
> +	prs->input_dev->id.bustype = BUS_I2C;
> +	prs->input_dev->dev.parent = &prs->client->dev;
> +
> +	input_set_drvdata(prs->input_dev, prs);
> +
> +	set_bit(EV_ABS, prs->input_dev->evbit);
> +
> +	input_set_abs_params(prs->input_dev, ABS_PR,
> +			PR_ABS_MIN, PR_ABS_MAX, FUZZ, FLAT);
> +	input_set_abs_params(prs->input_dev, ABS_TEMP,
> +			PR_DLT_MIN, PR_DLT_MAX, FUZZ, FLAT);
> +	input_set_abs_params(prs->input_dev, ABS_DLTPR,
> +			TEMP_MIN, TEMP_MAX, FUZZ, FLAT);
> +
> +
> +	prs->input_dev->name = "LPS001WP barometer";
> +
> +	err = input_register_device(prs->input_dev);
> +	if (err) {
> +		dev_err(&prs->client->dev,
> +			"unable to register input polled device %s\n",
> +			prs->input_dev->name);
> +		goto err1;
> +	}
> +
> +	return 0;
> +
> +err1:
> +	input_free_device(prs->input_dev);
> +err0:
> +	return err;
> +}
> +
> +static void lps001wp_prs_input_cleanup(struct lps001wp_prs_data *prs)
> +{
> +	input_unregister_device(prs->input_dev);
> +	input_free_device(prs->input_dev);
> +}
> +
> +static int lps001wp_prs_probe(struct i2c_client *client,
> +					const struct i2c_device_id *id)
> +{
> +	struct lps001wp_prs_data *prs;
> +	int err = -1;
Don't think you need to initialize err.  Looks to me like it always will
be set to a value anyway.

> +	int tempvalue;
> +
> +	pr_info("%s: probe start.\n", LPS001WP_PRS_DEV_NAME);
> +
> +	if (client->dev.platform_data == NULL) {
> +		dev_err(&client->dev, "platform data is NULL. exiting.\n");
> +		err = -ENODEV;

Going to this error label certainly looks a little 'unusual' given
you haven't checked the functionality yet.  I'd rename it appropriately.
> +		goto exit_check_functionality_failed;
> +	}
> +
If you need all of the following, why not combine them into a single
check?
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		dev_err(&client->dev, "client not i2c capable\n");
We probably don't care about the message here. It's not something
that will occur in any real device...  
> +		err = -ENODEV;
> +		goto exit_check_functionality_failed;
> +	}
> +
> +	if (!i2c_check_functionality(client->adapter,
> +					I2C_FUNC_SMBUS_BYTE |
> +					I2C_FUNC_SMBUS_BYTE_DATA |
> +					I2C_FUNC_SMBUS_WORD_DATA)) {
> +		dev_err(&client->dev, "client not smb-i2c capable:2\n");
> +		err = -EIO;
> +		goto exit_check_functionality_failed;
> +	}
> +
> +
> +	if (!i2c_check_functionality(client->adapter,
> +						I2C_FUNC_SMBUS_I2C_BLOCK)){
> +		dev_err(&client->dev, "client not smb-i2c capable:3\n");
> +		err = -EIO;
> +		goto exit_check_functionality_failed;
> +	}
> +
> +
> +	prs = kzalloc(sizeof(struct lps001wp_prs_data), GFP_KERNEL);
> +	if (prs == NULL) {
> +		err = -ENOMEM;
> +		dev_err(&client->dev,
> +				"failed to allocate memory for module data: "
> +					"%d\n", err);
> +		goto exit_alloc_data_failed;
> +	}
> +
> +	mutex_init(&prs->lock);
> +	mutex_lock(&prs->lock);
> +
> +	prs->client = client;
> +	i2c_set_clientdata(client, prs);
> +
> +
> +	if (i2c_smbus_read_byte(client) < 0) {
> +		printk(KERN_ERR "i2c_smbus_read_byte error!!\n");
Lose the exclamation marks if not the whole error message.
> +		goto err_mutexunlockfreedata;
> +	} else {
This we definitely don't need to know. It's useful whilst writing
drivers but not when they are normally in use.
> +		printk(KERN_DEBUG "%s Device detected!\n",
> +							LPS001WP_PRS_DEV_NAME);
> +	}
> +
> +	/* read chip id */
> +	tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I);
> +	if ((tempvalue & 0x00FF) == WHOAMI_LPS001WP_PRS) {
> +		printk(KERN_DEBUG "%s I2C driver registered!\n",
> +							LPS001WP_PRS_DEV_NAME);
> +	} else {
> +		prs->client = NULL;
> +		printk(KERN_DEBUG "I2C driver not registered!"
> +				" Device unknown\n");
set the error code appropriately? -ENODEV seems right to me.
> +		goto err_mutexunlockfreedata;
> +	}
> +
> +	prs->pdata = kmalloc(sizeof(*prs->pdata), GFP_KERNEL);
> +	if (prs->pdata == NULL) {
> +		err = -ENOMEM;
> +		dev_err(&client->dev,
> +				"failed to allocate memory for pdata: %d\n",
> +				err);
> +		goto err_mutexunlockfreedata;
> +	}
> +
> +	memcpy(prs->pdata, client->dev.platform_data, sizeof(*prs->pdata));
kmemdup should work for the above.
> +
> +	err = lps001wp_prs_validate_pdata(prs);
> +	if (err < 0) {
> +		dev_err(&client->dev, "failed to validate platform data\n");
> +		goto exit_kfree_pdata;
> +	}
> +
> +	i2c_set_clientdata(client, prs);
You've already done this.
> +
> +
> +	if (prs->pdata->init) {
> +		err = prs->pdata->init();
What does this init typically do?  (just curious!)
> +		if (err < 0) {
> +			dev_err(&client->dev, "init failed: %d\n", err);
> +			goto err2;
After a lot of very specific error labels, this one seems rather out
of place.
> +		}
> +	}
> +
> +	memset(prs->resume_state, 0, ARRAY_SIZE(prs->resume_state));
Would be cleaner (in code) to use kzalloc then get rid of all the code
initializing bits of prs to 0.  It might technically take a tiny
bit longer, but it's probably worth it for the cleaner code.
> +
> +	prs->resume_state[RES_CTRL_REG1] = LPS001WP_PRS_PM_NORMAL;
> +	prs->resume_state[RES_CTRL_REG2] = 0x00;
> +	prs->resume_state[RES_CTRL_REG3] = 0x00;
> +	prs->resume_state[RES_REF_P_L] = 0x00;
> +	prs->resume_state[RES_REF_P_H] = 0x00;
> +	prs->resume_state[RES_THS_P_L] = 0x00;
> +	prs->resume_state[RES_THS_P_H] = 0x00;
> +	prs->resume_state[RES_INT_CFG] = 0x00;
> +
> +	err = lps001wp_prs_device_power_on(prs);
> +	if (err < 0) {
> +		dev_err(&client->dev, "power on failed: %d\n", err);
> +		goto err2;
> +	}
> +
> +	prs->diff_enabled = 0;
> +	prs->lpowmode_enabled = 0;
> +	atomic_set(&prs->enabled, 1);
> +
> +	err = lps001wp_prs_update_odr(prs, prs->pdata->poll_interval);
> +	if (err < 0) {
> +		dev_err(&client->dev, "update_odr failed\n");
> +		goto err_power_off;
> +	}
> +
> +	err = lps001wp_prs_input_init(prs);
> +	if (err < 0) {
> +		dev_err(&client->dev, "input init failed\n");
> +		goto err_power_off;
> +	}
> +
> +
> +	err = create_sysfs_interfaces(&client->dev);
> +	if (err < 0) {
There is an informative error in the error path of the above function. I don't
think we need another here.
> +		dev_err(&client->dev,
> +			"device LPS001WP_PRS_DEV_NAME sysfs register failed\n");
> +		goto err_input_cleanup;
> +	}
> +
> +
> +	lps001wp_prs_device_power_off(prs);
> +
> +	/* As default, do not report information */
> +	atomic_set(&prs->enabled, 0);
> +
> +
> +	mutex_unlock(&prs->lock);
> +
> +	dev_info(&client->dev, "%s: probed\n", LPS001WP_PRS_DEV_NAME);
> +
> +	return 0;
> +
> +/*
> +remove_sysfs_int:
> +	remove_sysfs_interfaces(&client->dev);
> +*/
> +err_input_cleanup:
> +	lps001wp_prs_input_cleanup(prs);
> +err_power_off:
> +	lps001wp_prs_device_power_off(prs);
> +err2:
> +	if (prs->pdata->exit)
> +		prs->pdata->exit();
> +exit_kfree_pdata:
> +	kfree(prs->pdata);
> +
> +err_mutexunlockfreedata:
> +	mutex_unlock(&prs->lock);
> +	kfree(prs);
> +exit_alloc_data_failed:
> +exit_check_functionality_failed:
> +	printk(KERN_ERR "%s: Driver Init failed\n", LPS001WP_PRS_DEV_NAME);
> +	return err;
> +}
> +
> +static int __devexit lps001wp_prs_remove(struct i2c_client *client)
> +{
> +	struct lps001wp_prs_data *prs = i2c_get_clientdata(client);
> +
> +	lps001wp_prs_input_cleanup(prs);
> +	lps001wp_prs_device_power_off(prs);
> +	remove_sysfs_interfaces(&client->dev);
> +
> +	if (prs->pdata->exit)
> +		prs->pdata->exit();
> +	kfree(prs->pdata);
> +	kfree(prs);
> +
> +	return 0;
> +}
> +
> +static int lps001wp_prs_resume(struct i2c_client *client)
> +{
> +	struct lps001wp_prs_data *prs = i2c_get_clientdata(client);
> +
> +	if (prs->on_before_suspend)
> +		return lps001wp_prs_enable(prs);
> +	return 0;
> +}
> +
> +static int lps001wp_prs_suspend(struct i2c_client *client, pm_message_t mesg)
> +{
> +	struct lps001wp_prs_data *prs = i2c_get_clientdata(client);
> +
> +	prs->on_before_suspend = atomic_read(&prs->enabled);
> +	return lps001wp_prs_disable(prs);
> +}
> +
> +static const struct i2c_device_id lps001wp_prs_id[]
> +		= { { LPS001WP_PRS_DEV_NAME, 0}, { },};
> +
> +MODULE_DEVICE_TABLE(i2c, lps001wp_prs_id);
> +
> +static struct i2c_driver lps001wp_prs_driver = {
> +	.driver = {
> +			.name = LPS001WP_PRS_DEV_NAME,
> +			.owner = THIS_MODULE,
> +	},
> +	.probe = lps001wp_prs_probe,
> +	.remove = __devexit_p(lps001wp_prs_remove),
> +	.id_table = lps001wp_prs_id,
Probably want the usual removal of these if power management
code isn't in the kernel.
> +	.resume = lps001wp_prs_resume,
> +	.suspend = lps001wp_prs_suspend,
> +};
> +
> +static int __init lps001wp_prs_init(void)
> +{
> +	printk(KERN_DEBUG "%s barometer driver: init\n",
> +						LPS001WP_PRS_DEV_NAME);
No 
> +	return i2c_add_driver(&lps001wp_prs_driver);
> +}
> +
> +static void __exit lps001wp_prs_exit(void)
> +{
> +	#if DEBUG
> +	printk(KERN_DEBUG "%s barometer driver exit\n",
> +						LPS001WP_PRS_DEV_NAME);
> +	#endif
Lose these debug statements.  They are handy when writing the driver, but
don't tell us anything terribly useful in one that works.

> +	i2c_del_driver(&lps001wp_prs_driver);
> +	return;
> +}
> +
> +module_init(lps001wp_prs_init);
> +module_exit(lps001wp_prs_exit);
> +
> +MODULE_DESCRIPTION("STMicrolelectronics lps001wp pressure sensor misc driver");
> +MODULE_AUTHOR("Matteo Dameno, Carmine Iascone, STMicroelectronics");
> +MODULE_LICENSE("GPL");
> +
> diff --git a/include/linux/input/lps001wp.h b/include/linux/input/lps001wp.h
> new file mode 100644
> index 0000000..4c3e307
> --- /dev/null
> +++ b/include/linux/input/lps001wp.h
> @@ -0,0 +1,82 @@
> +/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
> +*
> +* File Name	: lps001wp.h
> +* Authors	: MSH - Motion Mems BU - Application Team
> +*		: Matteo Dameno (matteo.dameno@...com)*
> +*		: Carmine Iascone (carmine.iascone@...com)
> +* Version	: V 1.1.1
Don't bother with version numbers or dates in drivers.
They tend not to get updated and git history is often more informative.
I guess if this section is company policy no one will really mind that much.
> +* Date		: 05/11/2010
> +* Description	: LPS001WP 6D module sensor API
> +*
> +********************************************************************************
> +*
> +* 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.
> +*
> +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
> +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
> +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
> +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
> +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
> +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
> +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
I'm not sure what the view on statements like this in kernel is, but it might
cause some comments...
> +*
> +* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
Tough.  If someone else finds another part that is sufficiently similar they will
add it to this driver and use your code for something else ;)
> +*
> +*******************************************************************************/
> +
> +#ifndef	__LPS001WP_H__
> +#define	__LPS001WP_H__
> +
> +
> +#include	<linux/input.h>
Why this include?
> +
> +#define	SAD0L				0x00
> +#define	SAD0H				0x01
> +#define	LPS001WP_PRS_I2C_SADROOT	0x2E
> +#define	LPS001WP_PRS_I2C_SAD_L		((LPS001WP_PRS_I2C_SADROOT<<1)|SAD0L)
> +#define	LPS001WP_PRS_I2C_SAD_H		((LPS001WP_PRS_I2C_SADROOT<<1)|SAD0H)
> +#define	LPS001WP_PRS_DEV_NAME		"lps001wp_prs_sysfs"
> +
> +/* input define mappings */
> +#define ABS_PR		ABS_PRESSURE
> +#define ABS_TEMP	ABS_GAS
> +#define ABS_DLTPR	ABS_MISC
> +
> +
> +
That's an awfully heavily hightlighted comment. I'd just
go with the relevant middle line...
> +/************************************************/
> +/* 	Pressure section defines	 	*/
> +/************************************************/
> +
> +/* Pressure Sensor Operating Mode */
> +#define	LPS001WP_PRS_ENABLE		0x01
> +#define	LPS001WP_PRS_DISABLE		0x00
Some excessive white space here.  There is very rarely any
reason to have more than one blank line.  This is true
all over the driver.  Please clean the whole thing up
appropriately.  Other drivers will act as good examples
of the style people tend to use.
> +
> +
> +
> +
> +#define	LPS001WP_PRS_PM_NORMAL		0x40
> +#define	LPS001WP_PRS_PM_OFF		LPS001WP_PRS_DISABLE
> +
> +#define	SENSITIVITY_T		64	/** =	64 LSB/degrC	*/
> +#define	SENSITIVITY_P		16	/** =	16 LSB/mbar	*/
> +
> +
> +#ifdef __KERNEL__
Some kernel doc formated documentation for this structure would be a
good addition.
> +struct lps001wp_prs_platform_data {
> +
> +	int poll_interval;
> +	int min_interval;
> +
> +	int (*init)(void);
> +	void (*exit)(void);
> +	int (*power_on)(void);
> +	int (*power_off)(void);
> +
> +};
> +
> +#endif /* __KERNEL__ */
> +
> +#endif  /* __LPS001WP_H__ */

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ