cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cma3000_d0x.c (8946B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * VTI CMA3000_D0x Accelerometer driver
      4 *
      5 * Copyright (C) 2010 Texas Instruments
      6 * Author: Hemanth V <hemanthv@ti.com>
      7 */
      8
      9#include <linux/types.h>
     10#include <linux/interrupt.h>
     11#include <linux/delay.h>
     12#include <linux/slab.h>
     13#include <linux/input.h>
     14#include <linux/input/cma3000.h>
     15#include <linux/module.h>
     16
     17#include "cma3000_d0x.h"
     18
     19#define CMA3000_WHOAMI      0x00
     20#define CMA3000_REVID       0x01
     21#define CMA3000_CTRL        0x02
     22#define CMA3000_STATUS      0x03
     23#define CMA3000_RSTR        0x04
     24#define CMA3000_INTSTATUS   0x05
     25#define CMA3000_DOUTX       0x06
     26#define CMA3000_DOUTY       0x07
     27#define CMA3000_DOUTZ       0x08
     28#define CMA3000_MDTHR       0x09
     29#define CMA3000_MDFFTMR     0x0A
     30#define CMA3000_FFTHR       0x0B
     31
     32#define CMA3000_RANGE2G    (1 << 7)
     33#define CMA3000_RANGE8G    (0 << 7)
     34#define CMA3000_BUSI2C     (0 << 4)
     35#define CMA3000_MODEMASK   (7 << 1)
     36#define CMA3000_GRANGEMASK (1 << 7)
     37
     38#define CMA3000_STATUS_PERR    1
     39#define CMA3000_INTSTATUS_FFDET (1 << 2)
     40
     41/* Settling time delay in ms */
     42#define CMA3000_SETDELAY    30
     43
     44/* Delay for clearing interrupt in us */
     45#define CMA3000_INTDELAY    44
     46
     47
     48/*
     49 * Bit weights in mg for bit 0, other bits need
     50 * multiply factor 2^n. Eight bit is the sign bit.
     51 */
     52#define BIT_TO_2G  18
     53#define BIT_TO_8G  71
     54
     55struct cma3000_accl_data {
     56	const struct cma3000_bus_ops *bus_ops;
     57	const struct cma3000_platform_data *pdata;
     58
     59	struct device *dev;
     60	struct input_dev *input_dev;
     61
     62	int bit_to_mg;
     63	int irq;
     64
     65	int g_range;
     66	u8 mode;
     67
     68	struct mutex mutex;
     69	bool opened;
     70	bool suspended;
     71};
     72
     73#define CMA3000_READ(data, reg, msg) \
     74	(data->bus_ops->read(data->dev, reg, msg))
     75#define CMA3000_SET(data, reg, val, msg) \
     76	((data)->bus_ops->write(data->dev, reg, val, msg))
     77
     78/*
     79 * Conversion for each of the eight modes to g, depending
     80 * on G range i.e 2G or 8G. Some modes always operate in
     81 * 8G.
     82 */
     83
     84static int mode_to_mg[8][2] = {
     85	{ 0, 0 },
     86	{ BIT_TO_8G, BIT_TO_2G },
     87	{ BIT_TO_8G, BIT_TO_2G },
     88	{ BIT_TO_8G, BIT_TO_8G },
     89	{ BIT_TO_8G, BIT_TO_8G },
     90	{ BIT_TO_8G, BIT_TO_2G },
     91	{ BIT_TO_8G, BIT_TO_2G },
     92	{ 0, 0},
     93};
     94
     95static void decode_mg(struct cma3000_accl_data *data, int *datax,
     96				int *datay, int *dataz)
     97{
     98	/* Data in 2's complement, convert to mg */
     99	*datax = ((s8)*datax) * data->bit_to_mg;
    100	*datay = ((s8)*datay) * data->bit_to_mg;
    101	*dataz = ((s8)*dataz) * data->bit_to_mg;
    102}
    103
    104static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
    105{
    106	struct cma3000_accl_data *data = dev_id;
    107	int datax, datay, dataz, intr_status;
    108	u8 ctrl, mode, range;
    109
    110	intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
    111	if (intr_status < 0)
    112		return IRQ_NONE;
    113
    114	/* Check if free fall is detected, report immediately */
    115	if (intr_status & CMA3000_INTSTATUS_FFDET) {
    116		input_report_abs(data->input_dev, ABS_MISC, 1);
    117		input_sync(data->input_dev);
    118	} else {
    119		input_report_abs(data->input_dev, ABS_MISC, 0);
    120	}
    121
    122	datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
    123	datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
    124	dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
    125
    126	ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
    127	mode = (ctrl & CMA3000_MODEMASK) >> 1;
    128	range = (ctrl & CMA3000_GRANGEMASK) >> 7;
    129
    130	data->bit_to_mg = mode_to_mg[mode][range];
    131
    132	/* Interrupt not for this device */
    133	if (data->bit_to_mg == 0)
    134		return IRQ_NONE;
    135
    136	/* Decode register values to milli g */
    137	decode_mg(data, &datax, &datay, &dataz);
    138
    139	input_report_abs(data->input_dev, ABS_X, datax);
    140	input_report_abs(data->input_dev, ABS_Y, datay);
    141	input_report_abs(data->input_dev, ABS_Z, dataz);
    142	input_sync(data->input_dev);
    143
    144	return IRQ_HANDLED;
    145}
    146
    147static int cma3000_reset(struct cma3000_accl_data *data)
    148{
    149	int val;
    150
    151	/* Reset sequence */
    152	CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
    153	CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
    154	CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
    155
    156	/* Settling time delay */
    157	mdelay(10);
    158
    159	val = CMA3000_READ(data, CMA3000_STATUS, "Status");
    160	if (val < 0) {
    161		dev_err(data->dev, "Reset failed\n");
    162		return val;
    163	}
    164
    165	if (val & CMA3000_STATUS_PERR) {
    166		dev_err(data->dev, "Parity Error\n");
    167		return -EIO;
    168	}
    169
    170	return 0;
    171}
    172
    173static int cma3000_poweron(struct cma3000_accl_data *data)
    174{
    175	const struct cma3000_platform_data *pdata = data->pdata;
    176	u8 ctrl = 0;
    177	int ret;
    178
    179	if (data->g_range == CMARANGE_2G) {
    180		ctrl = (data->mode << 1) | CMA3000_RANGE2G;
    181	} else if (data->g_range == CMARANGE_8G) {
    182		ctrl = (data->mode << 1) | CMA3000_RANGE8G;
    183	} else {
    184		dev_info(data->dev,
    185			 "Invalid G range specified, assuming 8G\n");
    186		ctrl = (data->mode << 1) | CMA3000_RANGE8G;
    187	}
    188
    189	ctrl |= data->bus_ops->ctrl_mod;
    190
    191	CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
    192		    "Motion Detect Threshold");
    193	CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
    194		    "Time register");
    195	CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
    196		    "Free fall threshold");
    197	ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
    198	if (ret < 0)
    199		return -EIO;
    200
    201	msleep(CMA3000_SETDELAY);
    202
    203	return 0;
    204}
    205
    206static int cma3000_poweroff(struct cma3000_accl_data *data)
    207{
    208	int ret;
    209
    210	ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
    211	msleep(CMA3000_SETDELAY);
    212
    213	return ret;
    214}
    215
    216static int cma3000_open(struct input_dev *input_dev)
    217{
    218	struct cma3000_accl_data *data = input_get_drvdata(input_dev);
    219
    220	mutex_lock(&data->mutex);
    221
    222	if (!data->suspended)
    223		cma3000_poweron(data);
    224
    225	data->opened = true;
    226
    227	mutex_unlock(&data->mutex);
    228
    229	return 0;
    230}
    231
    232static void cma3000_close(struct input_dev *input_dev)
    233{
    234	struct cma3000_accl_data *data = input_get_drvdata(input_dev);
    235
    236	mutex_lock(&data->mutex);
    237
    238	if (!data->suspended)
    239		cma3000_poweroff(data);
    240
    241	data->opened = false;
    242
    243	mutex_unlock(&data->mutex);
    244}
    245
    246void cma3000_suspend(struct cma3000_accl_data *data)
    247{
    248	mutex_lock(&data->mutex);
    249
    250	if (!data->suspended && data->opened)
    251		cma3000_poweroff(data);
    252
    253	data->suspended = true;
    254
    255	mutex_unlock(&data->mutex);
    256}
    257EXPORT_SYMBOL(cma3000_suspend);
    258
    259
    260void cma3000_resume(struct cma3000_accl_data *data)
    261{
    262	mutex_lock(&data->mutex);
    263
    264	if (data->suspended && data->opened)
    265		cma3000_poweron(data);
    266
    267	data->suspended = false;
    268
    269	mutex_unlock(&data->mutex);
    270}
    271EXPORT_SYMBOL(cma3000_resume);
    272
    273struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
    274				       const struct cma3000_bus_ops *bops)
    275{
    276	const struct cma3000_platform_data *pdata = dev_get_platdata(dev);
    277	struct cma3000_accl_data *data;
    278	struct input_dev *input_dev;
    279	int rev;
    280	int error;
    281
    282	if (!pdata) {
    283		dev_err(dev, "platform data not found\n");
    284		error = -EINVAL;
    285		goto err_out;
    286	}
    287
    288
    289	/* if no IRQ return error */
    290	if (irq == 0) {
    291		error = -EINVAL;
    292		goto err_out;
    293	}
    294
    295	data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
    296	input_dev = input_allocate_device();
    297	if (!data || !input_dev) {
    298		error = -ENOMEM;
    299		goto err_free_mem;
    300	}
    301
    302	data->dev = dev;
    303	data->input_dev = input_dev;
    304	data->bus_ops = bops;
    305	data->pdata = pdata;
    306	data->irq = irq;
    307	mutex_init(&data->mutex);
    308
    309	data->mode = pdata->mode;
    310	if (data->mode > CMAMODE_POFF) {
    311		data->mode = CMAMODE_MOTDET;
    312		dev_warn(dev,
    313			 "Invalid mode specified, assuming Motion Detect\n");
    314	}
    315
    316	data->g_range = pdata->g_range;
    317	if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
    318		dev_info(dev,
    319			 "Invalid G range specified, assuming 8G\n");
    320		data->g_range = CMARANGE_8G;
    321	}
    322
    323	input_dev->name = "cma3000-accelerometer";
    324	input_dev->id.bustype = bops->bustype;
    325	input_dev->open = cma3000_open;
    326	input_dev->close = cma3000_close;
    327
    328	 __set_bit(EV_ABS, input_dev->evbit);
    329
    330	input_set_abs_params(input_dev, ABS_X,
    331			-data->g_range, data->g_range, pdata->fuzz_x, 0);
    332	input_set_abs_params(input_dev, ABS_Y,
    333			-data->g_range, data->g_range, pdata->fuzz_y, 0);
    334	input_set_abs_params(input_dev, ABS_Z,
    335			-data->g_range, data->g_range, pdata->fuzz_z, 0);
    336	input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
    337
    338	input_set_drvdata(input_dev, data);
    339
    340	error = cma3000_reset(data);
    341	if (error)
    342		goto err_free_mem;
    343
    344	rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
    345	if (rev < 0) {
    346		error = rev;
    347		goto err_free_mem;
    348	}
    349
    350	pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
    351
    352	error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
    353				     pdata->irqflags | IRQF_ONESHOT,
    354				     "cma3000_d0x", data);
    355	if (error) {
    356		dev_err(dev, "request_threaded_irq failed\n");
    357		goto err_free_mem;
    358	}
    359
    360	error = input_register_device(data->input_dev);
    361	if (error) {
    362		dev_err(dev, "Unable to register input device\n");
    363		goto err_free_irq;
    364	}
    365
    366	return data;
    367
    368err_free_irq:
    369	free_irq(irq, data);
    370err_free_mem:
    371	input_free_device(input_dev);
    372	kfree(data);
    373err_out:
    374	return ERR_PTR(error);
    375}
    376EXPORT_SYMBOL(cma3000_init);
    377
    378void cma3000_exit(struct cma3000_accl_data *data)
    379{
    380	free_irq(data->irq, data);
    381	input_unregister_device(data->input_dev);
    382	kfree(data);
    383}
    384EXPORT_SYMBOL(cma3000_exit);
    385
    386MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
    387MODULE_LICENSE("GPL");
    388MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");