RE: [PATCH] lis3lv02d: Add STMicroelectronics lis33ldlh digital

From: AnilKumar, Chimata
Date: Tue Jan 17 2012 - 02:33:07 EST


Hi All,

Recalling the patch, provide the comments if there are any if not please include
this patch to v3.3 kernel.

-----Original Message-----
From: AnilKumar, Chimata
Sent: Friday, December 23, 2011 10:55 AM
To: arnd@xxxxxxxx; greg@xxxxxxxxx; eric.piel@xxxxxxxxxxxxxxxx; akpm@xxxxxxxxxxxxxxxxxxxx; broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx
Cc: linux-omap@xxxxxxxxxxxxxxx; Nori, Sekhar; AnilKumar, Chimata
Subject: [PATCH] lis3lv02d: Add STMicroelectronics lis33ldlh digital

This patch adds support for lis33ldlh digital accelerometer to the
lis3lv02d driver family. Adds ID field for detecting the lis33ldlh
module, based on this ID field lis3lv02d driver will export the
lis33ldlh module functionality.

Also exports g_range parameter to user space for run-time value
change. User must give 2/4/8 value depends on requirement.

Signed-off-by: AnilKumar Ch <anilkumar@xxxxxx>
---
drivers/misc/lis3lv02d/lis3lv02d.c | 111 ++++++++++++++++++++++++++++++-
drivers/misc/lis3lv02d/lis3lv02d.h | 59 +++++++++++++++++
drivers/misc/lis3lv02d/lis3lv02d_i2c.c | 6 ++-
include/linux/lis3lv02d.h | 2 +
4 files changed, 173 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index 29d12a7..2381220 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -80,6 +80,17 @@
#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)

+/* Sensitivity values for -2G, -4G, -8G and +2G, +4G, +8G scale */
+#define LIS3DLH_SENSITIVITY_2G (LIS3_ACCURACY * 1)
+#define LIS3DLH_SENSITIVITY_4G (LIS3_ACCURACY * 2)
+#define LIS3DLH_SENSITIVITY_8G ((LIS3_ACCURACY * 39)/10)
+
+#define SHIFT_ADJ_2G 4
+#define SHIFT_ADJ_4G 3
+#define SHIFT_ADJ_8G 2
+
+#define FS_MASK (0x3 << 4)
+
#define LIS3_DEFAULT_FUZZ_12B 3
#define LIS3_DEFAULT_FLAT_12B 3
#define LIS3_DEFAULT_FUZZ_8B 1
@@ -148,6 +159,12 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3])
return -hw_values[-axis - 1];
}

+static int lis3lv02d_decode(u8 pl, u8 ph, int adj)
+{
+ s16 v = pl | ph << 8;
+ return (int) v >> adj;
+}
+
/**
* lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
* @lis3: pointer to the device struct
@@ -176,9 +193,24 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
position[i] = (s8)data[i * 2];
}
} else {
- position[0] = lis3->read_data(lis3, OUTX);
- position[1] = lis3->read_data(lis3, OUTY);
- position[2] = lis3->read_data(lis3, OUTZ);
+ if (lis3_dev.whoami == WAI_3DLH) {
+ position[0] =
+ lis3lv02d_decode(lis3->read_data(lis3, OUTX_L),
+ lis3->read_data(lis3, OUTX_H),
+ lis3_dev.shift_adj);
+ position[1] =
+ lis3lv02d_decode(lis3->read_data(lis3, OUTY_L),
+ lis3->read_data(lis3, OUTY_H),
+ lis3_dev.shift_adj);
+ position[2] =
+ lis3lv02d_decode(lis3->read_data(lis3, OUTZ_L),
+ lis3->read_data(lis3, OUTZ_H),
+ lis3_dev.shift_adj);
+ } else {
+ position[0] = lis3->read_data(lis3, OUTX);
+ position[1] = lis3->read_data(lis3, OUTY);
+ position[2] = lis3->read_data(lis3, OUTZ);
+ }
}

for (i = 0; i < 3; i++)
@@ -193,6 +225,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
static int lis3_12_rates[4] = {40, 160, 640, 2560};
static int lis3_8_rates[2] = {100, 400};
static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
+static int lis3_3dlh_rates[4] = {50, 100, 400, 1000};

/* ODR is Output Data Rate */
static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
@@ -265,7 +298,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
}

- if (lis3->whoami == WAI_3DC) {
+ if ((lis3_dev.whoami == WAI_3DC) || (lis3_dev.whoami == WAI_3DLH)) {
ctlreg = CTRL_REG4;
selftest = CTRL4_ST0;
} else {
@@ -396,6 +429,8 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3)
lis3->read(lis3, CTRL_REG2, &reg);
if (lis3->whoami == WAI_12B)
reg |= CTRL2_BDU | CTRL2_BOOT;
+ else if (lis3->whoami == WAI_3DLH)
+ reg |= CTRL2_BOOT_3DLH;
else
reg |= CTRL2_BOOT_8B;
lis3->write(lis3, CTRL_REG2, reg);
@@ -724,6 +759,36 @@ void lis3lv02d_joystick_disable(struct lis3lv02d *lis3)
}
EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);

+static void lis3lv02d_update_g_range(struct lis3lv02d *lis3)
+{
+ u8 reg;
+ u8 val;
+ u8 shift;
+
+ switch (lis3->g_range) {
+ case 8:
+ val = FS_8G_REGVAL;
+ shift = SHIFT_ADJ_8G;
+ lis3->scale = LIS3DLH_SENSITIVITY_8G;
+ break;
+ case 4:
+ val = FS_4G_REGVAL;
+ shift = SHIFT_ADJ_4G;
+ lis3->scale = LIS3DLH_SENSITIVITY_4G;
+ break;
+ case 2:
+ default:
+ val = FS_2G_REGVAL;
+ shift = SHIFT_ADJ_2G;
+ lis3->scale = LIS3DLH_SENSITIVITY_2G;
+ break;
+ }
+
+ lis3->shift_adj = shift;
+ lis3->read(lis3, CTRL_REG4, &reg);
+ lis3->write(lis3, CTRL_REG4, ((reg & ~FS_MASK) | val));
+}
+
/* Sysfs stuff */
static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
{
@@ -792,6 +857,13 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
return sprintf(buf, "%d\n", lis3lv02d_get_odr(lis3));
}

+static ssize_t lis3lv02d_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ lis3lv02d_sysfs_poweron(&lis3_dev);
+ return sprintf(buf, "%d\n", lis3_dev.g_range);
+}
+
static ssize_t lis3lv02d_rate_set(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
@@ -809,15 +881,33 @@ static ssize_t lis3lv02d_rate_set(struct device *dev,
return count;
}

+static ssize_t lis3lv02d_range_set(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ unsigned long range;
+
+ if (strict_strtoul(buf, 0, &range))
+ return -EINVAL;
+
+ lis3_dev.g_range = range;
+ lis3lv02d_update_g_range(&lis3_dev);
+
+ return count;
+}
+
static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
lis3lv02d_rate_set);
+static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, lis3lv02d_range_show,
+ lis3lv02d_range_set);

static struct attribute *lis3lv02d_attributes[] = {
&dev_attr_selftest.attr,
&dev_attr_position.attr,
&dev_attr_rate.attr,
+ &dev_attr_range.attr,
NULL
};

@@ -954,6 +1044,19 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
lis3->scale = LIS3_SENSITIVITY_8B;
break;
+ case WAI_3DLH:
+ pr_info("8 bits 3DLH sensor found\n");
+ lis3->read_data = lis3lv02d_read_8;
+ lis3->mdps_max_val = 128;
+ lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+ lis3->odrs = lis3_3dlh_rates;
+ lis3->odr_mask = CTRL1_DR0 | CTRL1_DR1;
+ if (lis3->pdata) {
+ lis3->g_range = lis3->pdata->g_range;
+ lis3lv02d_update_g_range(lis3);
+ } else
+ lis3->scale = LIS3DLH_SENSITIVITY_2G;
+ break;
default:
pr_err("unknown sensor type 0x%X\n", lis3->whoami);
return -EINVAL;
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h
index 2b1482a..0e6fe06 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.h
+++ b/drivers/misc/lis3lv02d/lis3lv02d.h
@@ -95,13 +95,29 @@ enum lis3lv02d_reg {
DD_THSE_H = 0x3F,
};

+enum lis331dlh_reg {
+ CTRL_REG5 = 0x24,
+ HP_FILTER_RESET_3DLH = 0x25,
+ REFERENCE = 0x26,
+};
+
enum lis3_who_am_i {
+ WAI_3DLH = 0x32, /* 8 bits: LIS331DLH */
WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
};

+enum lis3_type {
+ LIS3DC,
+ HP3DC,
+ LIS3LV02D,
+ LIS2302D,
+ LIS331DLF,
+ LIS331DLH,
+};
+
enum lis3lv02d_ctrl1_12b {
CTRL1_Xen = 0x01,
CTRL1_Yen = 0x02,
@@ -129,6 +145,32 @@ enum lis3lv02d_ctrl1_3dc {
CTRL1_ODR3 = 0x80,
};

+enum lis331dlh_ctrl1 {
+ CTRL1_DR0 = 0x08,
+ CTRL1_DR1 = 0x10,
+ CTRL1_PM0 = 0x20,
+ CTRL1_PM1 = 0x40,
+ CTRL1_PM2 = 0x80,
+};
+
+enum lis331dlh_ctrl2 {
+ CTRL2_HPEN1 = 0x04,
+ CTRL2_HPEN2 = 0x08,
+ CTRL2_FDS_3DLH = 0x10,
+ CTRL2_BOOT_3DLH = 0x80,
+};
+
+enum lis331dlh_ctrl4 {
+ CTRL4_STSIGN = 0x08,
+ CTRL4_BLE = 0x40,
+ CTRL4_BDU = 0x80,
+};
+
+enum lis331dlh_ctrl5 {
+ CTRL5_TURNON0 = 0x01,
+ CTRL5_TURNON1 = 0x20,
+};
+
enum lis3lv02d_ctrl2 {
CTRL2_DAS = 0x01,
CTRL2_SIM = 0x02,
@@ -148,6 +190,13 @@ enum lis3lv02d_ctrl4_3dc {
CTRL4_FS1 = 0x20,
};

+/* Measurement Range */
+enum lis3lv02d_fs {
+ FS_2G_REGVAL = 0x00,
+ FS_4G_REGVAL = 0x10,
+ FS_8G_REGVAL = 0x30,
+};
+
enum lis302d_ctrl2 {
HP_FF_WU2 = 0x08,
HP_FF_WU1 = 0x04,
@@ -185,6 +234,10 @@ enum lis3lv02d_ff_wu_cfg {
FF_WU_CFG_AOI = 0x80,
};

+enum lis331dlh_ff_wu_cfg {
+ FF_WU_CFG_6D = 0x40,
+};
+
enum lis3lv02d_ff_wu_src {
FF_WU_SRC_XL = 0x01,
FF_WU_SRC_XH = 0x02,
@@ -206,6 +259,10 @@ enum lis3lv02d_dd_cfg {
DD_CFG_IEND = 0x80,
};

+enum lis331dlh_dd_cfg {
+ DD_CFG_6D = 0x40,
+};
+
enum lis3lv02d_dd_src {
DD_SRC_XL = 0x01,
DD_SRC_XH = 0x02,
@@ -282,6 +339,8 @@ struct lis3lv02d {

struct lis3lv02d_platform_data *pdata; /* for passing board config */
struct mutex mutex; /* Serialize poll and selftest */
+ u8 g_range; /* Hold the g range */
+ u8 shift_adj;
};

int lis3lv02d_init_device(struct lis3lv02d *lis3);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index c02fea0..32b322f 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -90,7 +90,10 @@ static int lis3_i2c_init(struct lis3lv02d *lis3)
if (ret < 0)
return ret;

- reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+ if (lis3->whoami == WAI_3DLH)
+ reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
+ else
+ reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
return lis3->write(lis3, CTRL_REG1, reg);
}

@@ -232,6 +235,7 @@ static int lis3_i2c_runtime_resume(struct device *dev)

static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", 0 },
+ {"lis331dlh", LIS331DLH},
{}
};

diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h
index f1664c6..32d4912 100644
--- a/include/linux/lis3lv02d.h
+++ b/include/linux/lis3lv02d.h
@@ -25,6 +25,7 @@
* @axis_x: Sensor orientation remapping for x-axis
* @axis_y: Sensor orientation remapping for y-axis
* @axis_z: Sensor orientation remapping for z-axis
+ * @g_range: Value contains the acceleration range, +/-2, +/-4 and +/-8
* @driver_features: Enable bits for different features. Disabled by default
* @default_rate: Default sampling rate. 0 means reset default
* @setup_resources: Interrupt line setup call back function
@@ -113,6 +114,7 @@ struct lis3lv02d_platform_data {
s8 axis_x;
s8 axis_y;
s8 axis_z;
+ u8 g_range;
#define LIS3_USE_BLOCK_READ 0x02
u16 driver_features;
int default_rate;
--
1.7.0.4

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