Commit 4903a2ddb73cb7315cb0b42fc1c354c6bad04bff

Authored by Anil Kumar Ch
1 parent 565a55c815
Exists in master

lis3lv02d: Add STMicroelectronics lis33ldlh digital accelerometer

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: Anil Kumar Ch <anilkumar@ti.com>

Showing 4 changed files with 173 additions and 5 deletions Side-by-side Diff

drivers/misc/lis3lv02d/lis3lv02d.c
... ... @@ -80,6 +80,17 @@
80 80 #define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
81 81 #define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)
82 82  
  83 +/* Sensitivity values for -2G, -4G, -8G and +2G, +4G, +8G scale */
  84 +#define LIS3DLH_SENSITIVITY_2G (LIS3_ACCURACY * 1)
  85 +#define LIS3DLH_SENSITIVITY_4G (LIS3_ACCURACY * 2)
  86 +#define LIS3DLH_SENSITIVITY_8G ((LIS3_ACCURACY * 39)/10)
  87 +
  88 +#define SHIFT_ADJ_2G 4
  89 +#define SHIFT_ADJ_4G 3
  90 +#define SHIFT_ADJ_8G 2
  91 +
  92 +#define FS_MASK (0x3 << 4)
  93 +
83 94 #define LIS3_DEFAULT_FUZZ_12B 3
84 95 #define LIS3_DEFAULT_FLAT_12B 3
85 96 #define LIS3_DEFAULT_FUZZ_8B 1
... ... @@ -148,6 +159,12 @@
148 159 return -hw_values[-axis - 1];
149 160 }
150 161  
  162 +static int lis3lv02d_decode(u8 pl, u8 ph, int adj)
  163 +{
  164 + s16 v = pl | ph << 8;
  165 + return (int) v >> adj;
  166 +}
  167 +
151 168 /**
152 169 * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer
153 170 * @lis3: pointer to the device struct
... ... @@ -176,9 +193,24 @@
176 193 position[i] = (s8)data[i * 2];
177 194 }
178 195 } else {
179   - position[0] = lis3->read_data(lis3, OUTX);
180   - position[1] = lis3->read_data(lis3, OUTY);
181   - position[2] = lis3->read_data(lis3, OUTZ);
  196 + if (lis3_dev.whoami == WAI_3DLH) {
  197 + position[0] =
  198 + lis3lv02d_decode(lis3->read_data(lis3, OUTX_L),
  199 + lis3->read_data(lis3, OUTX_H),
  200 + lis3_dev.shift_adj);
  201 + position[1] =
  202 + lis3lv02d_decode(lis3->read_data(lis3, OUTY_L),
  203 + lis3->read_data(lis3, OUTY_H),
  204 + lis3_dev.shift_adj);
  205 + position[2] =
  206 + lis3lv02d_decode(lis3->read_data(lis3, OUTZ_L),
  207 + lis3->read_data(lis3, OUTZ_H),
  208 + lis3_dev.shift_adj);
  209 + } else {
  210 + position[0] = lis3->read_data(lis3, OUTX);
  211 + position[1] = lis3->read_data(lis3, OUTY);
  212 + position[2] = lis3->read_data(lis3, OUTZ);
  213 + }
182 214 }
183 215  
184 216 for (i = 0; i < 3; i++)
... ... @@ -193,6 +225,7 @@
193 225 static int lis3_12_rates[4] = {40, 160, 640, 2560};
194 226 static int lis3_8_rates[2] = {100, 400};
195 227 static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
  228 +static int lis3_3dlh_rates[4] = {50, 100, 400, 1000};
196 229  
197 230 /* ODR is Output Data Rate */
198 231 static int lis3lv02d_get_odr(void)
... ... @@ -253,7 +286,7 @@
253 286 (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
254 287 }
255 288  
256   - if (lis3_dev.whoami == WAI_3DC) {
  289 + if ((lis3_dev.whoami == WAI_3DC) || (lis3_dev.whoami == WAI_3DLH)) {
257 290 ctlreg = CTRL_REG4;
258 291 selftest = CTRL4_ST0;
259 292 } else {
... ... @@ -379,6 +412,8 @@
379 412 lis3->read(lis3, CTRL_REG2, &reg);
380 413 if (lis3->whoami == WAI_12B)
381 414 reg |= CTRL2_BDU | CTRL2_BOOT;
  415 + else if (lis3->whoami == WAI_3DLH)
  416 + reg |= CTRL2_BOOT_3DLH;
382 417 else
383 418 reg |= CTRL2_BOOT_8B;
384 419 lis3->write(lis3, CTRL_REG2, reg);
... ... @@ -687,6 +722,36 @@
687 722 }
688 723 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
689 724  
  725 +static void lis3lv02d_update_g_range(struct lis3lv02d *lis3)
  726 +{
  727 + u8 reg;
  728 + u8 val;
  729 + u8 shift;
  730 +
  731 + switch (lis3->g_range) {
  732 + case 8:
  733 + val = FS_8G_REGVAL;
  734 + shift = SHIFT_ADJ_8G;
  735 + lis3->scale = LIS3DLH_SENSITIVITY_8G;
  736 + break;
  737 + case 4:
  738 + val = FS_4G_REGVAL;
  739 + shift = SHIFT_ADJ_4G;
  740 + lis3->scale = LIS3DLH_SENSITIVITY_4G;
  741 + break;
  742 + case 2:
  743 + default:
  744 + val = FS_2G_REGVAL;
  745 + shift = SHIFT_ADJ_2G;
  746 + lis3->scale = LIS3DLH_SENSITIVITY_2G;
  747 + break;
  748 + }
  749 +
  750 + lis3->shift_adj = shift;
  751 + lis3->read(lis3, CTRL_REG4, &reg);
  752 + lis3->write(lis3, CTRL_REG4, ((reg & ~FS_MASK) | val));
  753 +}
  754 +
690 755 /* Sysfs stuff */
691 756 static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
692 757 {
... ... @@ -751,6 +816,13 @@
751 816 return sprintf(buf, "%d\n", lis3lv02d_get_odr());
752 817 }
753 818  
  819 +static ssize_t lis3lv02d_range_show(struct device *dev,
  820 + struct device_attribute *attr, char *buf)
  821 +{
  822 + lis3lv02d_sysfs_poweron(&lis3_dev);
  823 + return sprintf(buf, "%d\n", lis3_dev.g_range);
  824 +}
  825 +
754 826 static ssize_t lis3lv02d_rate_set(struct device *dev,
755 827 struct device_attribute *attr, const char *buf,
756 828 size_t count)
757 829  
758 830  
... ... @@ -767,15 +839,33 @@
767 839 return count;
768 840 }
769 841  
  842 +static ssize_t lis3lv02d_range_set(struct device *dev,
  843 + struct device_attribute *attr, const char *buf,
  844 + size_t count)
  845 +{
  846 + unsigned long range;
  847 +
  848 + if (strict_strtoul(buf, 0, &range))
  849 + return -EINVAL;
  850 +
  851 + lis3_dev.g_range = range;
  852 + lis3lv02d_update_g_range(&lis3_dev);
  853 +
  854 + return count;
  855 +}
  856 +
770 857 static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL);
771 858 static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL);
772 859 static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show,
773 860 lis3lv02d_rate_set);
  861 +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, lis3lv02d_range_show,
  862 + lis3lv02d_range_set);
774 863  
775 864 static struct attribute *lis3lv02d_attributes[] = {
776 865 &dev_attr_selftest.attr,
777 866 &dev_attr_position.attr,
778 867 &dev_attr_rate.attr,
  868 + &dev_attr_range.attr,
779 869 NULL
780 870 };
781 871  
... ... @@ -910,6 +1000,19 @@
910 1000 dev->odrs = lis3_3dc_rates;
911 1001 dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
912 1002 dev->scale = LIS3_SENSITIVITY_8B;
  1003 + break;
  1004 + case WAI_3DLH:
  1005 + pr_info("8 bits 3DLH sensor found\n");
  1006 + dev->read_data = lis3lv02d_read_8;
  1007 + dev->mdps_max_val = 128;
  1008 + dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
  1009 + dev->odrs = lis3_3dlh_rates;
  1010 + dev->odr_mask = CTRL1_DR0 | CTRL1_DR1;
  1011 + if (dev->pdata) {
  1012 + dev->g_range = dev->pdata->g_range;
  1013 + lis3lv02d_update_g_range(dev);
  1014 + } else
  1015 + dev->scale = LIS3DLH_SENSITIVITY_2G;
913 1016 break;
914 1017 default:
915 1018 pr_err("unknown sensor type 0x%X\n", dev->whoami);
drivers/misc/lis3lv02d/lis3lv02d.h
... ... @@ -94,13 +94,29 @@
94 94 DD_THSE_H = 0x3F,
95 95 };
96 96  
  97 +enum lis331dlh_reg {
  98 + CTRL_REG5 = 0x24,
  99 + HP_FILTER_RESET_3DLH = 0x25,
  100 + REFERENCE = 0x26,
  101 +};
  102 +
97 103 enum lis3_who_am_i {
  104 + WAI_3DLH = 0x32, /* 8 bits: LIS331DLH */
98 105 WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
99 106 WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
100 107 WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
101 108 WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
102 109 };
103 110  
  111 +enum lis3_type {
  112 + LIS3DC,
  113 + HP3DC,
  114 + LIS3LV02D,
  115 + LIS2302D,
  116 + LIS331DLF,
  117 + LIS331DLH,
  118 +};
  119 +
104 120 enum lis3lv02d_ctrl1_12b {
105 121 CTRL1_Xen = 0x01,
106 122 CTRL1_Yen = 0x02,
... ... @@ -128,6 +144,32 @@
128 144 CTRL1_ODR3 = 0x80,
129 145 };
130 146  
  147 +enum lis331dlh_ctrl1 {
  148 + CTRL1_DR0 = 0x08,
  149 + CTRL1_DR1 = 0x10,
  150 + CTRL1_PM0 = 0x20,
  151 + CTRL1_PM1 = 0x40,
  152 + CTRL1_PM2 = 0x80,
  153 +};
  154 +
  155 +enum lis331dlh_ctrl2 {
  156 + CTRL2_HPEN1 = 0x04,
  157 + CTRL2_HPEN2 = 0x08,
  158 + CTRL2_FDS_3DLH = 0x10,
  159 + CTRL2_BOOT_3DLH = 0x80,
  160 +};
  161 +
  162 +enum lis331dlh_ctrl4 {
  163 + CTRL4_STSIGN = 0x08,
  164 + CTRL4_BLE = 0x40,
  165 + CTRL4_BDU = 0x80,
  166 +};
  167 +
  168 +enum lis331dlh_ctrl5 {
  169 + CTRL5_TURNON0 = 0x01,
  170 + CTRL5_TURNON1 = 0x20,
  171 +};
  172 +
131 173 enum lis3lv02d_ctrl2 {
132 174 CTRL2_DAS = 0x01,
133 175 CTRL2_SIM = 0x02,
... ... @@ -147,6 +189,13 @@
147 189 CTRL4_FS1 = 0x20,
148 190 };
149 191  
  192 +/* Measurement Range */
  193 +enum lis3lv02d_fs {
  194 + FS_2G_REGVAL = 0x00,
  195 + FS_4G_REGVAL = 0x10,
  196 + FS_8G_REGVAL = 0x30,
  197 +};
  198 +
150 199 enum lis302d_ctrl2 {
151 200 HP_FF_WU2 = 0x08,
152 201 HP_FF_WU1 = 0x04,
... ... @@ -184,6 +233,10 @@
184 233 FF_WU_CFG_AOI = 0x80,
185 234 };
186 235  
  236 +enum lis331dlh_ff_wu_cfg {
  237 + FF_WU_CFG_6D = 0x40,
  238 +};
  239 +
187 240 enum lis3lv02d_ff_wu_src {
188 241 FF_WU_SRC_XL = 0x01,
189 242 FF_WU_SRC_XH = 0x02,
... ... @@ -205,6 +258,10 @@
205 258 DD_CFG_IEND = 0x80,
206 259 };
207 260  
  261 +enum lis331dlh_dd_cfg {
  262 + DD_CFG_6D = 0x40,
  263 +};
  264 +
208 265 enum lis3lv02d_dd_src {
209 266 DD_SRC_XL = 0x01,
210 267 DD_SRC_XH = 0x02,
... ... @@ -279,6 +336,8 @@
279 336  
280 337 struct lis3lv02d_platform_data *pdata; /* for passing board config */
281 338 struct mutex mutex; /* Serialize poll and selftest */
  339 + u8 g_range; /* Hold the g range */
  340 + u8 shift_adj;
282 341 };
283 342  
284 343 int lis3lv02d_init_device(struct lis3lv02d *lis3);
drivers/misc/lis3lv02d/lis3lv02d_i2c.c
... ... @@ -91,7 +91,10 @@
91 91 if (ret < 0)
92 92 return ret;
93 93  
94   - reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
  94 + if (lis3->whoami == WAI_3DLH)
  95 + reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
  96 + else
  97 + reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
95 98 return lis3->write(lis3, CTRL_REG1, reg);
96 99 }
97 100  
... ... @@ -237,6 +240,7 @@
237 240  
238 241 static const struct i2c_device_id lis3lv02d_id[] = {
239 242 {"lis3lv02d", 0 },
  243 + {"lis331dlh", LIS331DLH},
240 244 {}
241 245 };
242 246  
include/linux/lis3lv02d.h
... ... @@ -25,6 +25,7 @@
25 25 * @axis_x: Sensor orientation remapping for x-axis
26 26 * @axis_y: Sensor orientation remapping for y-axis
27 27 * @axis_z: Sensor orientation remapping for z-axis
  28 + * @g_range: Value contains the acceleration range, +/-2, +/-4 and +/-8
28 29 * @driver_features: Enable bits for different features. Disabled by default
29 30 * @default_rate: Default sampling rate. 0 means reset default
30 31 * @setup_resources: Interrupt line setup call back function
... ... @@ -113,6 +114,7 @@
113 114 s8 axis_x;
114 115 s8 axis_y;
115 116 s8 axis_z;
  117 + u8 g_range;
116 118 #define LIS3_USE_REGULATOR_CTRL 0x01
117 119 #define LIS3_USE_BLOCK_READ 0x02
118 120 u16 driver_features;