Add support for CMA3000 Tri-axis accelerometer, which supports Motion detect, Measurement and Free fall modes. CMA3000 supports both I2C/SPI bus for communication, currently the driver supports I2C based communication.
Unified · Split
| @@ -0,0 +1,115 @@ | ||
| 1 | +Kernel driver for CMA3000-D0x | |
| 2 | +============================ | |
| 3 | + | |
| 4 | +Supported chips: | |
| 5 | +* VTI CMA3000-D0x | |
| 6 | +Datasheet: | |
| 7 | + CMA3000-D0X Product Family Specification 8281000A.02.pdf | |
| 8 | + <http://www.vti.fi/en/> | |
| 9 | + | |
| 10 | +Author: Hemanth V <hemanthv@ti.com> | |
| 11 | + | |
| 12 | + | |
| 13 | +Description | |
| 14 | +----------- | |
| 15 | +CMA3000 Tri-axis accelerometer supports Motion detect, Measurement and | |
| 16 | +Free fall modes. | |
| 17 | + | |
| 18 | +Motion Detect Mode: Its the low power mode where interrupts are generated only | |
| 19 | +when motion exceeds the defined thresholds. | |
| 20 | + | |
| 21 | +Measurement Mode: This mode is used to read the acceleration data on X,Y,Z | |
| 22 | +axis and supports 400, 100, 40 Hz sample frequency. | |
| 23 | + | |
| 24 | +Free fall Mode: This mode is intended to save system resources. | |
| 25 | + | |
| 26 | +Threshold values: Chip supports defining threshold values for above modes | |
| 27 | +which includes time and g value. Refer product specifications for more details. | |
| 28 | + | |
| 29 | +CMA3000 chip supports mutually exclusive I2C and SPI interfaces for | |
| 30 | +communication, currently the driver supports I2C based communication only. | |
| 31 | +Initial configuration for bus mode is set in non volatile memory and can later | |
| 32 | +be modified through bus interface command. | |
| 33 | + | |
| 34 | +Driver reports acceleration data through input subsystem. It generates ABS_MISC | |
| 35 | +event with value 1 when free fall is detected. | |
| 36 | + | |
| 37 | +Platform data need to be configured for initial default values. | |
| 38 | + | |
| 39 | +Platform Data | |
| 40 | +------------- | |
| 41 | +fuzz_x: Noise on X Axis | |
| 42 | + | |
| 43 | +fuzz_y: Noise on Y Axis | |
| 44 | + | |
| 45 | +fuzz_z: Noise on Z Axis | |
| 46 | + | |
| 47 | +g_range: G range in milli g i.e 2000 or 8000 | |
| 48 | + | |
| 49 | +mode: Default Operating mode | |
| 50 | + | |
| 51 | +mdthr: Motion detect g range threshold value | |
| 52 | + | |
| 53 | +mdfftmr: Motion detect and free fall time threshold value | |
| 54 | + | |
| 55 | +ffthr: Free fall g range threshold value | |
| 56 | + | |
| 57 | +Input Interface | |
| 58 | +-------------- | |
| 59 | +Input driver version is 1.0.0 | |
| 60 | +Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0 | |
| 61 | +Input device name: "cma3000-accelerometer" | |
| 62 | +Supported events: | |
| 63 | + Event type 0 (Sync) | |
| 64 | + Event type 3 (Absolute) | |
| 65 | + Event code 0 (X) | |
| 66 | + Value 47 | |
| 67 | + Min -8000 | |
| 68 | + Max 8000 | |
| 69 | + Fuzz 200 | |
| 70 | + Event code 1 (Y) | |
| 71 | + Value -28 | |
| 72 | + Min -8000 | |
| 73 | + Max 8000 | |
| 74 | + Fuzz 200 | |
| 75 | + Event code 2 (Z) | |
| 76 | + Value 905 | |
| 77 | + Min -8000 | |
| 78 | + Max 8000 | |
| 79 | + Fuzz 200 | |
| 80 | + Event code 40 (Misc) | |
| 81 | + Value 0 | |
| 82 | + Min 0 | |
| 83 | + Max 1 | |
| 84 | + Event type 4 (Misc) | |
| 85 | + | |
| 86 | + | |
| 87 | +Register/Platform parameters Description | |
| 88 | +---------------------------------------- | |
| 89 | + | |
| 90 | +mode: | |
| 91 | + 0: power down mode | |
| 92 | + 1: 100 Hz Measurement mode | |
| 93 | + 2: 400 Hz Measurement mode | |
| 94 | + 3: 40 Hz Measurement mode | |
| 95 | + 4: Motion Detect mode (default) | |
| 96 | + 5: 100 Hz Free fall mode | |
| 97 | + 6: 40 Hz Free fall mode | |
| 98 | + 7: Power off mode | |
| 99 | + | |
| 100 | +grange: | |
| 101 | + 2000: 2000 mg or 2G Range | |
| 102 | + 8000: 8000 mg or 8G Range | |
| 103 | + | |
| 104 | +mdthr: | |
| 105 | + X: X * 71mg (8G Range) | |
| 106 | + X: X * 18mg (2G Range) | |
| 107 | + | |
| 108 | +mdfftmr: | |
| 109 | + X: (X & 0x70) * 100 ms (MDTMR) | |
| 110 | + (X & 0x0F) * 2.5 ms (FFTMR 400 Hz) | |
| 111 | + (X & 0x0F) * 10 ms (FFTMR 100 Hz) | |
| 112 | + | |
| 113 | +ffthr: | |
| 114 | + X: (X >> 2) * 18mg (2G Range) | |
| 115 | + X: (X & 0x0F) * 71 mg (8G Range) | |
| @@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI · 447 unmodified lines | ||
| 448 | 448 | To compile this driver as a module, choose M here: the |
| 449 | 449 | module will be called adxl34x-spi. |
| 450 | 450 | |
| 451 | +config INPUT_CMA3000 | |
| 452 | + tristate "VTI CMA3000 Tri-axis accelerometer" | |
| 453 | + help | |
| 454 | + Say Y here if you want to use VTI CMA3000_D0x Accelerometer | |
| 455 | + driver | |
| 456 | + | |
| 457 | + This driver currently only supports I2C interface to the | |
| 458 | + controller. Also select the I2C method. | |
| 459 | + | |
| 460 | + If unsure, say N | |
| 461 | + | |
| 462 | + To compile this driver as a module, choose M here: the | |
| 463 | + module will be called cma3000_d0x. | |
| 464 | + | |
| 465 | +config INPUT_CMA3000_I2C | |
| 466 | + tristate "Support I2C bus connection" | |
| 467 | + depends on INPUT_CMA3000 && I2C | |
| 468 | + help | |
| 469 | + Say Y here if you want to use VTI CMA3000_D0x Accelerometer | |
| 470 | + through I2C interface. | |
| 471 | + | |
| 472 | + To compile this driver as a module, choose M here: the | |
| 473 | + module will be called cma3000_d0x_i2c. | |
| 474 | + | |
| 451 | 475 | endif |
| @@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o · 17 unmodified lines | ||
| 18 | 18 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
| 19 | 19 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o |
| 20 | 20 | obj-$(CONFIG_INPUT_CM109) += cm109.o |
| 21 | +obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o | |
| 22 | +obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o | |
| 21 | 23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
| 22 | 24 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
| 23 | 25 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
| @@ -0,0 +1,398 @@ | ||
| 1 | +/* | |
| 2 | + * VTI CMA3000_D0x Accelerometer driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2010 Texas Instruments | |
| 5 | + * Author: Hemanth V <hemanthv@ti.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License version 2 as published by | |
| 9 | + * the Free Software Foundation. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 14 | + * more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU General Public License along with | |
| 17 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#include <linux/types.h> | |
| 21 | +#include <linux/interrupt.h> | |
| 22 | +#include <linux/delay.h> | |
| 23 | +#include <linux/slab.h> | |
| 24 | +#include <linux/input.h> | |
| 25 | +#include <linux/input/cma3000.h> | |
| 26 | + | |
| 27 | +#include "cma3000_d0x.h" | |
| 28 | + | |
| 29 | +#define CMA3000_WHOAMI 0x00 | |
| 30 | +#define CMA3000_REVID 0x01 | |
| 31 | +#define CMA3000_CTRL 0x02 | |
| 32 | +#define CMA3000_STATUS 0x03 | |
| 33 | +#define CMA3000_RSTR 0x04 | |
| 34 | +#define CMA3000_INTSTATUS 0x05 | |
| 35 | +#define CMA3000_DOUTX 0x06 | |
| 36 | +#define CMA3000_DOUTY 0x07 | |
| 37 | +#define CMA3000_DOUTZ 0x08 | |
| 38 | +#define CMA3000_MDTHR 0x09 | |
| 39 | +#define CMA3000_MDFFTMR 0x0A | |
| 40 | +#define CMA3000_FFTHR 0x0B | |
| 41 | + | |
| 42 | +#define CMA3000_RANGE2G (1 << 7) | |
| 43 | +#define CMA3000_RANGE8G (0 << 7) | |
| 44 | +#define CMA3000_BUSI2C (0 << 4) | |
| 45 | +#define CMA3000_MODEMASK (7 << 1) | |
| 46 | +#define CMA3000_GRANGEMASK (1 << 7) | |
| 47 | + | |
| 48 | +#define CMA3000_STATUS_PERR 1 | |
| 49 | +#define CMA3000_INTSTATUS_FFDET (1 << 2) | |
| 50 | + | |
| 51 | +/* Settling time delay in ms */ | |
| 52 | +#define CMA3000_SETDELAY 30 | |
| 53 | + | |
| 54 | +/* Delay for clearing interrupt in us */ | |
| 55 | +#define CMA3000_INTDELAY 44 | |
| 56 | + | |
| 57 | + | |
| 58 | +/* | |
| 59 | + * Bit weights in mg for bit 0, other bits need | |
| 60 | + * multipy factor 2^n. Eight bit is the sign bit. | |
| 61 | + */ | |
| 62 | +#define BIT_TO_2G 18 | |
| 63 | +#define BIT_TO_8G 71 | |
| 64 | + | |
| 65 | +struct cma3000_accl_data { | |
| 66 | + const struct cma3000_bus_ops *bus_ops; | |
| 67 | + const struct cma3000_platform_data *pdata; | |
| 68 | + | |
| 69 | + struct device *dev; | |
| 70 | + struct input_dev *input_dev; | |
| 71 | + | |
| 72 | + int bit_to_mg; | |
| 73 | + int irq; | |
| 74 | + | |
| 75 | + int g_range; | |
| 76 | + u8 mode; | |
| 77 | + | |
| 78 | + struct mutex mutex; | |
| 79 | + bool opened; | |
| 80 | + bool suspended; | |
| 81 | +}; | |
| 82 | + | |
| 83 | +#define CMA3000_READ(data, reg, msg) \ | |
| 84 | + (data->bus_ops->read(data->dev, reg, msg)) | |
| 85 | +#define CMA3000_SET(data, reg, val, msg) \ | |
| 86 | + ((data)->bus_ops->write(data->dev, reg, val, msg)) | |
| 87 | + | |
| 88 | +/* | |
| 89 | + * Conversion for each of the eight modes to g, depending | |
| 90 | + * on G range i.e 2G or 8G. Some modes always operate in | |
| 91 | + * 8G. | |
| 92 | + */ | |
| 93 | + | |
| 94 | +static int mode_to_mg[8][2] = { | |
| 95 | + { 0, 0 }, | |
| 96 | + { BIT_TO_8G, BIT_TO_2G }, | |
| 97 | + { BIT_TO_8G, BIT_TO_2G }, | |
| 98 | + { BIT_TO_8G, BIT_TO_8G }, | |
| 99 | + { BIT_TO_8G, BIT_TO_8G }, | |
| 100 | + { BIT_TO_8G, BIT_TO_2G }, | |
| 101 | + { BIT_TO_8G, BIT_TO_2G }, | |
| 102 | + { 0, 0}, | |
| 103 | +}; | |
| 104 | + | |
| 105 | +static void decode_mg(struct cma3000_accl_data *data, int *datax, | |
| 106 | + int *datay, int *dataz) | |
| 107 | +{ | |
| 108 | + /* Data in 2's complement, convert to mg */ | |
| 109 | + *datax = ((s8)*datax) * data->bit_to_mg; | |
| 110 | + *datay = ((s8)*datay) * data->bit_to_mg; | |
| 111 | + *dataz = ((s8)*dataz) * data->bit_to_mg; | |
| 112 | +} | |
| 113 | + | |
| 114 | +static irqreturn_t cma3000_thread_irq(int irq, void *dev_id) | |
| 115 | +{ | |
| 116 | + struct cma3000_accl_data *data = dev_id; | |
| 117 | + int datax, datay, dataz; | |
| 118 | + u8 ctrl, mode, range, intr_status; | |
| 119 | + | |
| 120 | + intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status"); | |
| 121 | + if (intr_status < 0) | |
| 122 | + return IRQ_NONE; | |
| 123 | + | |
| 124 | + /* Check if free fall is detected, report immediately */ | |
| 125 | + if (intr_status & CMA3000_INTSTATUS_FFDET) { | |
| 126 | + input_report_abs(data->input_dev, ABS_MISC, 1); | |
| 127 | + input_sync(data->input_dev); | |
| 128 | + } else { | |
| 129 | + input_report_abs(data->input_dev, ABS_MISC, 0); | |
| 130 | + } | |
| 131 | + | |
| 132 | + datax = CMA3000_READ(data, CMA3000_DOUTX, "X"); | |
| 133 | + datay = CMA3000_READ(data, CMA3000_DOUTY, "Y"); | |
| 134 | + dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z"); | |
| 135 | + | |
| 136 | + ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl"); | |
| 137 | + mode = (ctrl & CMA3000_MODEMASK) >> 1; | |
| 138 | + range = (ctrl & CMA3000_GRANGEMASK) >> 7; | |
| 139 | + | |
| 140 | + data->bit_to_mg = mode_to_mg[mode][range]; | |
| 141 | + | |
| 142 | + /* Interrupt not for this device */ | |
| 143 | + if (data->bit_to_mg == 0) | |
| 144 | + return IRQ_NONE; | |
| 145 | + | |
| 146 | + /* Decode register values to milli g */ | |
| 147 | + decode_mg(data, &datax, &datay, &dataz); | |
| 148 | + | |
| 149 | + input_report_abs(data->input_dev, ABS_X, datax); | |
| 150 | + input_report_abs(data->input_dev, ABS_Y, datay); | |
| 151 | + input_report_abs(data->input_dev, ABS_Z, dataz); | |
| 152 | + input_sync(data->input_dev); | |
| 153 | + | |
| 154 | + return IRQ_HANDLED; | |
| 155 | +} | |
| 156 | + | |
| 157 | +static int cma3000_reset(struct cma3000_accl_data *data) | |
| 158 | +{ | |
| 159 | + int val; | |
| 160 | + | |
| 161 | + /* Reset sequence */ | |
| 162 | + CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset"); | |
| 163 | + CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset"); | |
| 164 | + CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset"); | |
| 165 | + | |
| 166 | + /* Settling time delay */ | |
| 167 | + mdelay(10); | |
| 168 | + | |
| 169 | + val = CMA3000_READ(data, CMA3000_STATUS, "Status"); | |
| 170 | + if (val < 0) { | |
| 171 | + dev_err(data->dev, "Reset failed\n"); | |
| 172 | + return val; | |
| 173 | + } | |
| 174 | + | |
| 175 | + if (val & CMA3000_STATUS_PERR) { | |
| 176 | + dev_err(data->dev, "Parity Error\n"); | |
| 177 | + return -EIO; | |
| 178 | + } | |
| 179 | + | |
| 180 | + return 0; | |
| 181 | +} | |
| 182 | + | |
| 183 | +static int cma3000_poweron(struct cma3000_accl_data *data) | |
| 184 | +{ | |
| 185 | + const struct cma3000_platform_data *pdata = data->pdata; | |
| 186 | + u8 ctrl = 0; | |
| 187 | + int ret; | |
| 188 | + | |
| 189 | + if (data->g_range == CMARANGE_2G) { | |
| 190 | + ctrl = (data->mode << 1) | CMA3000_RANGE2G; | |
| 191 | + } else if (data->g_range == CMARANGE_8G) { | |
| 192 | + ctrl = (data->mode << 1) | CMA3000_RANGE8G; | |
| 193 | + } else { | |
| 194 | + dev_info(data->dev, | |
| 195 | + "Invalid G range specified, assuming 8G\n"); | |
| 196 | + ctrl = (data->mode << 1) | CMA3000_RANGE8G; | |
| 197 | + } | |
| 198 | + | |
| 199 | + ctrl |= data->bus_ops->ctrl_mod; | |
| 200 | + | |
| 201 | + CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr, | |
| 202 | + "Motion Detect Threshold"); | |
| 203 | + CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr, | |
| 204 | + "Time register"); | |
| 205 | + CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr, | |
| 206 | + "Free fall threshold"); | |
| 207 | + ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting"); | |
| 208 | + if (ret < 0) | |
| 209 | + return -EIO; | |
| 210 | + | |
| 211 | + msleep(CMA3000_SETDELAY); | |
| 212 | + | |
| 213 | + return 0; | |
| 214 | +} | |
| 215 | + | |
| 216 | +static int cma3000_poweroff(struct cma3000_accl_data *data) | |
| 217 | +{ | |
| 218 | + int ret; | |
| 219 | + | |
| 220 | + ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting"); | |
| 221 | + msleep(CMA3000_SETDELAY); | |
| 222 | + | |
| 223 | + return ret; | |
| 224 | +} | |
| 225 | + | |
| 226 | +static int cma3000_open(struct input_dev *input_dev) | |
| 227 | +{ | |
| 228 | + struct cma3000_accl_data *data = input_get_drvdata(input_dev); | |
| 229 | + | |
| 230 | + mutex_lock(&data->mutex); | |
| 231 | + | |
| 232 | + if (!data->suspended) | |
| 233 | + cma3000_poweron(data); | |
| 234 | + | |
| 235 | + data->opened = true; | |
| 236 | + | |
| 237 | + mutex_unlock(&data->mutex); | |
| 238 | + | |
| 239 | + return 0; | |
| 240 | +} | |
| 241 | + | |
| 242 | +static void cma3000_close(struct input_dev *input_dev) | |
| 243 | +{ | |
| 244 | + struct cma3000_accl_data *data = input_get_drvdata(input_dev); | |
| 245 | + | |
| 246 | + mutex_lock(&data->mutex); | |
| 247 | + | |
| 248 | + if (!data->suspended) | |
| 249 | + cma3000_poweroff(data); | |
| 250 | + | |
| 251 | + data->opened = false; | |
| 252 | + | |
| 253 | + mutex_unlock(&data->mutex); | |
| 254 | +} | |
| 255 | + | |
| 256 | +void cma3000_suspend(struct cma3000_accl_data *data) | |
| 257 | +{ | |
| 258 | + mutex_lock(&data->mutex); | |
| 259 | + | |
| 260 | + if (!data->suspended && data->opened) | |
| 261 | + cma3000_poweroff(data); | |
| 262 | + | |
| 263 | + data->suspended = true; | |
| 264 | + | |
| 265 | + mutex_unlock(&data->mutex); | |
| 266 | +} | |
| 267 | +EXPORT_SYMBOL(cma3000_suspend); | |
| 268 | + | |
| 269 | + | |
| 270 | +void cma3000_resume(struct cma3000_accl_data *data) | |
| 271 | +{ | |
| 272 | + mutex_lock(&data->mutex); | |
| 273 | + | |
| 274 | + if (data->suspended && data->opened) | |
| 275 | + cma3000_poweron(data); | |
| 276 | + | |
| 277 | + data->suspended = false; | |
| 278 | + | |
| 279 | + mutex_unlock(&data->mutex); | |
| 280 | +} | |
| 281 | +EXPORT_SYMBOL(cma3000_resume); | |
| 282 | + | |
| 283 | +struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, | |
| 284 | + const struct cma3000_bus_ops *bops) | |
| 285 | +{ | |
| 286 | + const struct cma3000_platform_data *pdata = dev->platform_data; | |
| 287 | + struct cma3000_accl_data *data; | |
| 288 | + struct input_dev *input_dev; | |
| 289 | + int rev; | |
| 290 | + int error; | |
| 291 | + | |
| 292 | + if (!pdata) { | |
| 293 | + dev_err(dev, "platform data not found\n"); | |
| 294 | + error = -EINVAL; | |
| 295 | + goto err_out; | |
| 296 | + } | |
| 297 | + | |
| 298 | + | |
| 299 | + /* if no IRQ return error */ | |
| 300 | + if (irq == 0) { | |
| 301 | + error = -EINVAL; | |
| 302 | + goto err_out; | |
| 303 | + } | |
| 304 | + | |
| 305 | + data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL); | |
| 306 | + input_dev = input_allocate_device(); | |
| 307 | + if (!data || !input_dev) { | |
| 308 | + error = -ENOMEM; | |
| 309 | + goto err_free_mem; | |
| 310 | + } | |
| 311 | + | |
| 312 | + data->dev = dev; | |
| 313 | + data->input_dev = input_dev; | |
| 314 | + data->bus_ops = bops; | |
| 315 | + data->pdata = pdata; | |
| 316 | + data->irq = irq; | |
| 317 | + mutex_init(&data->mutex); | |
| 318 | + | |
| 319 | + data->mode = pdata->mode; | |
| 320 | + if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) { | |
| 321 | + data->mode = CMAMODE_MOTDET; | |
| 322 | + dev_warn(dev, | |
| 323 | + "Invalid mode specified, assuming Motion Detect\n"); | |
| 324 | + } | |
| 325 | + | |
| 326 | + data->g_range = pdata->g_range; | |
| 327 | + if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) { | |
| 328 | + dev_info(dev, | |
| 329 | + "Invalid G range specified, assuming 8G\n"); | |
| 330 | + data->g_range = CMARANGE_8G; | |
| 331 | + } | |
| 332 | + | |
| 333 | + input_dev->name = "cma3000-accelerometer"; | |
| 334 | + input_dev->id.bustype = bops->bustype; | |
| 335 | + input_dev->open = cma3000_open; | |
| 336 | + input_dev->close = cma3000_close; | |
| 337 | + | |
| 338 | + __set_bit(EV_ABS, input_dev->evbit); | |
| 339 | + | |
| 340 | + input_set_abs_params(input_dev, ABS_X, | |
| 341 | + -data->g_range, data->g_range, pdata->fuzz_x, 0); | |
| 342 | + input_set_abs_params(input_dev, ABS_Y, | |
| 343 | + -data->g_range, data->g_range, pdata->fuzz_y, 0); | |
| 344 | + input_set_abs_params(input_dev, ABS_Z, | |
| 345 | + -data->g_range, data->g_range, pdata->fuzz_z, 0); | |
| 346 | + input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); | |
| 347 | + | |
| 348 | + input_set_drvdata(input_dev, data); | |
| 349 | + | |
| 350 | + error = cma3000_reset(data); | |
| 351 | + if (error) | |
| 352 | + goto err_free_mem; | |
| 353 | + | |
| 354 | + rev = CMA3000_READ(data, CMA3000_REVID, "Revid"); | |
| 355 | + if (rev < 0) { | |
| 356 | + error = rev; | |
| 357 | + goto err_free_mem; | |
| 358 | + } | |
| 359 | + | |
| 360 | + pr_info("CMA3000 Accelerometer: Revision %x\n", rev); | |
| 361 | + | |
| 362 | + error = request_threaded_irq(irq, NULL, cma3000_thread_irq, | |
| 363 | + pdata->irqflags | IRQF_ONESHOT, | |
| 364 | + "cma3000_d0x", data); | |
| 365 | + if (error) { | |
| 366 | + dev_err(dev, "request_threaded_irq failed\n"); | |
| 367 | + goto err_free_mem; | |
| 368 | + } | |
| 369 | + | |
| 370 | + error = input_register_device(data->input_dev); | |
| 371 | + if (error) { | |
| 372 | + dev_err(dev, "Unable to register input device\n"); | |
| 373 | + goto err_free_irq; | |
| 374 | + } | |
| 375 | + | |
| 376 | + return data; | |
| 377 | + | |
| 378 | +err_free_irq: | |
| 379 | + free_irq(irq, data); | |
| 380 | +err_free_mem: | |
| 381 | + input_free_device(input_dev); | |
| 382 | + kfree(data); | |
| 383 | +err_out: | |
| 384 | + return ERR_PTR(error); | |
| 385 | +} | |
| 386 | +EXPORT_SYMBOL(cma3000_init); | |
| 387 | + | |
| 388 | +void cma3000_exit(struct cma3000_accl_data *data) | |
| 389 | +{ | |
| 390 | + free_irq(data->irq, data); | |
| 391 | + input_unregister_device(data->input_dev); | |
| 392 | + kfree(data); | |
| 393 | +} | |
| 394 | +EXPORT_SYMBOL(cma3000_exit); | |
| 395 | + | |
| 396 | +MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver"); | |
| 397 | +MODULE_LICENSE("GPL"); | |
| 398 | +MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +/* | |
| 2 | + * VTI CMA3000_D0x Accelerometer driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2010 Texas Instruments | |
| 5 | + * Author: Hemanth V <hemanthv@ti.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License version 2 as published by | |
| 9 | + * the Free Software Foundation. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 14 | + * more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU General Public License along with | |
| 17 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#ifndef _INPUT_CMA3000_H | |
| 21 | +#define _INPUT_CMA3000_H | |
| 22 | + | |
| 23 | +#include <linux/types.h> | |
| 24 | +#include <linux/input.h> | |
| 25 | + | |
| 26 | +struct device; | |
| 27 | +struct cma3000_accl_data; | |
| 28 | + | |
| 29 | +struct cma3000_bus_ops { | |
| 30 | + u16 bustype; | |
| 31 | + u8 ctrl_mod; | |
| 32 | + int (*read)(struct device *, u8, char *); | |
| 33 | + int (*write)(struct device *, u8, u8, char *); | |
| 34 | +}; | |
| 35 | + | |
| 36 | +struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, | |
| 37 | + const struct cma3000_bus_ops *bops); | |
| 38 | +void cma3000_exit(struct cma3000_accl_data *); | |
| 39 | +void cma3000_suspend(struct cma3000_accl_data *); | |
| 40 | +void cma3000_resume(struct cma3000_accl_data *); | |
| 41 | + | |
| 42 | +#endif | |
| @@ -0,0 +1,141 @@ | ||
| 1 | +/* | |
| 2 | + * Implements I2C interface for VTI CMA300_D0x Accelerometer driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2010 Texas Instruments | |
| 5 | + * Author: Hemanth V <hemanthv@ti.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License version 2 as published by | |
| 9 | + * the Free Software Foundation. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 14 | + * more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU General Public License along with | |
| 17 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#include <linux/module.h> | |
| 21 | +#include <linux/i2c.h> | |
| 22 | +#include <linux/input/cma3000.h> | |
| 23 | +#include "cma3000_d0x.h" | |
| 24 | + | |
| 25 | +static int cma3000_i2c_set(struct device *dev, | |
| 26 | + u8 reg, u8 val, char *msg) | |
| 27 | +{ | |
| 28 | + struct i2c_client *client = to_i2c_client(dev); | |
| 29 | + int ret; | |
| 30 | + | |
| 31 | + ret = i2c_smbus_write_byte_data(client, reg, val); | |
| 32 | + if (ret < 0) | |
| 33 | + dev_err(&client->dev, | |
| 34 | + "%s failed (%s, %d)\n", __func__, msg, ret); | |
| 35 | + return ret; | |
| 36 | +} | |
| 37 | + | |
| 38 | +static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg) | |
| 39 | +{ | |
| 40 | + struct i2c_client *client = to_i2c_client(dev); | |
| 41 | + int ret; | |
| 42 | + | |
| 43 | + ret = i2c_smbus_read_byte_data(client, reg); | |
| 44 | + if (ret < 0) | |
| 45 | + dev_err(&client->dev, | |
| 46 | + "%s failed (%s, %d)\n", __func__, msg, ret); | |
| 47 | + return ret; | |
| 48 | +} | |
| 49 | + | |
| 50 | +static const struct cma3000_bus_ops cma3000_i2c_bops = { | |
| 51 | + .bustype = BUS_I2C, | |
| 52 | +#define CMA3000_BUSI2C (0 << 4) | |
| 53 | + .ctrl_mod = CMA3000_BUSI2C, | |
| 54 | + .read = cma3000_i2c_read, | |
| 55 | + .write = cma3000_i2c_set, | |
| 56 | +}; | |
| 57 | + | |
| 58 | +static int __devinit cma3000_i2c_probe(struct i2c_client *client, | |
| 59 | + const struct i2c_device_id *id) | |
| 60 | +{ | |
| 61 | + struct cma3000_accl_data *data; | |
| 62 | + | |
| 63 | + data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops); | |
| 64 | + if (IS_ERR(data)) | |
| 65 | + return PTR_ERR(data); | |
| 66 | + | |
| 67 | + i2c_set_clientdata(client, data); | |
| 68 | + | |
| 69 | + return 0; | |
| 70 | +} | |
| 71 | + | |
| 72 | +static int __devexit cma3000_i2c_remove(struct i2c_client *client) | |
| 73 | +{ | |
| 74 | + struct cma3000_accl_data *data = i2c_get_clientdata(client); | |
| 75 | + | |
| 76 | + cma3000_exit(data); | |
| 77 | + | |
| 78 | + return 0; | |
| 79 | +} | |
| 80 | + | |
| 81 | +#ifdef CONFIG_PM | |
| 82 | +static int cma3000_i2c_suspend(struct device *dev) | |
| 83 | +{ | |
| 84 | + struct i2c_client *client = to_i2c_client(dev); | |
| 85 | + struct cma3000_accl_data *data = i2c_get_clientdata(client); | |
| 86 | + | |
| 87 | + cma3000_suspend(data); | |
| 88 | + | |
| 89 | + return 0; | |
| 90 | +} | |
| 91 | + | |
| 92 | +static int cma3000_i2c_resume(struct device *dev) | |
| 93 | +{ | |
| 94 | + struct i2c_client *client = to_i2c_client(dev); | |
| 95 | + struct cma3000_accl_data *data = i2c_get_clientdata(client); | |
| 96 | + | |
| 97 | + cma3000_resume(data); | |
| 98 | + | |
| 99 | + return 0; | |
| 100 | +} | |
| 101 | + | |
| 102 | +static const struct dev_pm_ops cma3000_i2c_pm_ops = { | |
| 103 | + .suspend = cma3000_i2c_suspend, | |
| 104 | + .resume = cma3000_i2c_resume, | |
| 105 | +}; | |
| 106 | +#endif | |
| 107 | + | |
| 108 | +static const struct i2c_device_id cma3000_i2c_id[] = { | |
| 109 | + { "cma3000_d01", 0 }, | |
| 110 | + { }, | |
| 111 | +}; | |
| 112 | + | |
| 113 | +static struct i2c_driver cma3000_i2c_driver = { | |
| 114 | + .probe = cma3000_i2c_probe, | |
| 115 | + .remove = __devexit_p(cma3000_i2c_remove), | |
| 116 | + .id_table = cma3000_i2c_id, | |
| 117 | + .driver = { | |
| 118 | + .name = "cma3000_i2c_accl", | |
| 119 | + .owner = THIS_MODULE, | |
| 120 | +#ifdef CONFIG_PM | |
| 121 | + .pm = &cma3000_i2c_pm_ops, | |
| 122 | +#endif | |
| 123 | + }, | |
| 124 | +}; | |
| 125 | + | |
| 126 | +static int __init cma3000_i2c_init(void) | |
| 127 | +{ | |
| 128 | + return i2c_add_driver(&cma3000_i2c_driver); | |
| 129 | +} | |
| 130 | + | |
| 131 | +static void __exit cma3000_i2c_exit(void) | |
| 132 | +{ | |
| 133 | + i2c_del_driver(&cma3000_i2c_driver); | |
| 134 | +} | |
| 135 | + | |
| 136 | +module_init(cma3000_i2c_init); | |
| 137 | +module_exit(cma3000_i2c_exit); | |
| 138 | + | |
| 139 | +MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver"); | |
| 140 | +MODULE_LICENSE("GPL"); | |
| 141 | +MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); | |
| @@ -0,0 +1,59 @@ | ||
| 1 | +/* | |
| 2 | + * VTI CMA3000_Dxx Accelerometer driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2010 Texas Instruments | |
| 5 | + * Author: Hemanth V <hemanthv@ti.com> | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License version 2 as published by | |
| 9 | + * the Free Software Foundation. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 14 | + * more details. | |
| 15 | + * | |
| 16 | + * You should have received a copy of the GNU General Public License along with | |
| 17 | + * this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | + */ | |
| 19 | + | |
| 20 | +#ifndef _LINUX_CMA3000_H | |
| 21 | +#define _LINUX_CMA3000_H | |
| 22 | + | |
| 23 | +#define CMAMODE_DEFAULT 0 | |
| 24 | +#define CMAMODE_MEAS100 1 | |
| 25 | +#define CMAMODE_MEAS400 2 | |
| 26 | +#define CMAMODE_MEAS40 3 | |
| 27 | +#define CMAMODE_MOTDET 4 | |
| 28 | +#define CMAMODE_FF100 5 | |
| 29 | +#define CMAMODE_FF400 6 | |
| 30 | +#define CMAMODE_POFF 7 | |
| 31 | + | |
| 32 | +#define CMARANGE_2G 2000 | |
| 33 | +#define CMARANGE_8G 8000 | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * struct cma3000_i2c_platform_data - CMA3000 Platform data | |
| 37 | + * @fuzz_x: Noise on X Axis | |
| 38 | + * @fuzz_y: Noise on Y Axis | |
| 39 | + * @fuzz_z: Noise on Z Axis | |
| 40 | + * @g_range: G range in milli g i.e 2000 or 8000 | |
| 41 | + * @mode: Operating mode | |
| 42 | + * @mdthr: Motion detect threshold value | |
| 43 | + * @mdfftmr: Motion detect and free fall time value | |
| 44 | + * @ffthr: Free fall threshold value | |
| 45 | + */ | |
| 46 | + | |
| 47 | +struct cma3000_platform_data { | |
| 48 | + int fuzz_x; | |
| 49 | + int fuzz_y; | |
| 50 | + int fuzz_z; | |
| 51 | + int g_range; | |
| 52 | + uint8_t mode; | |
| 53 | + uint8_t mdthr; | |
| 54 | + uint8_t mdfftmr; | |
| 55 | + uint8_t ffthr; | |
| 56 | + unsigned long irqflags; | |
| 57 | +}; | |
| 58 | + | |
| 59 | +#endif | |