18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VTI CMA3000_D0x Accelerometer driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Texas Instruments 68c2ecf20Sopenharmony_ci * Author: Hemanth V <hemanthv@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/input.h> 148c2ecf20Sopenharmony_ci#include <linux/input/cma3000.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "cma3000_d0x.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define CMA3000_WHOAMI 0x00 208c2ecf20Sopenharmony_ci#define CMA3000_REVID 0x01 218c2ecf20Sopenharmony_ci#define CMA3000_CTRL 0x02 228c2ecf20Sopenharmony_ci#define CMA3000_STATUS 0x03 238c2ecf20Sopenharmony_ci#define CMA3000_RSTR 0x04 248c2ecf20Sopenharmony_ci#define CMA3000_INTSTATUS 0x05 258c2ecf20Sopenharmony_ci#define CMA3000_DOUTX 0x06 268c2ecf20Sopenharmony_ci#define CMA3000_DOUTY 0x07 278c2ecf20Sopenharmony_ci#define CMA3000_DOUTZ 0x08 288c2ecf20Sopenharmony_ci#define CMA3000_MDTHR 0x09 298c2ecf20Sopenharmony_ci#define CMA3000_MDFFTMR 0x0A 308c2ecf20Sopenharmony_ci#define CMA3000_FFTHR 0x0B 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define CMA3000_RANGE2G (1 << 7) 338c2ecf20Sopenharmony_ci#define CMA3000_RANGE8G (0 << 7) 348c2ecf20Sopenharmony_ci#define CMA3000_BUSI2C (0 << 4) 358c2ecf20Sopenharmony_ci#define CMA3000_MODEMASK (7 << 1) 368c2ecf20Sopenharmony_ci#define CMA3000_GRANGEMASK (1 << 7) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define CMA3000_STATUS_PERR 1 398c2ecf20Sopenharmony_ci#define CMA3000_INTSTATUS_FFDET (1 << 2) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Settling time delay in ms */ 428c2ecf20Sopenharmony_ci#define CMA3000_SETDELAY 30 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Delay for clearing interrupt in us */ 458c2ecf20Sopenharmony_ci#define CMA3000_INTDELAY 44 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * Bit weights in mg for bit 0, other bits need 508c2ecf20Sopenharmony_ci * multiply factor 2^n. Eight bit is the sign bit. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci#define BIT_TO_2G 18 538c2ecf20Sopenharmony_ci#define BIT_TO_8G 71 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct cma3000_accl_data { 568c2ecf20Sopenharmony_ci const struct cma3000_bus_ops *bus_ops; 578c2ecf20Sopenharmony_ci const struct cma3000_platform_data *pdata; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci struct device *dev; 608c2ecf20Sopenharmony_ci struct input_dev *input_dev; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci int bit_to_mg; 638c2ecf20Sopenharmony_ci int irq; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci int g_range; 668c2ecf20Sopenharmony_ci u8 mode; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci struct mutex mutex; 698c2ecf20Sopenharmony_ci bool opened; 708c2ecf20Sopenharmony_ci bool suspended; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define CMA3000_READ(data, reg, msg) \ 748c2ecf20Sopenharmony_ci (data->bus_ops->read(data->dev, reg, msg)) 758c2ecf20Sopenharmony_ci#define CMA3000_SET(data, reg, val, msg) \ 768c2ecf20Sopenharmony_ci ((data)->bus_ops->write(data->dev, reg, val, msg)) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Conversion for each of the eight modes to g, depending 808c2ecf20Sopenharmony_ci * on G range i.e 2G or 8G. Some modes always operate in 818c2ecf20Sopenharmony_ci * 8G. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int mode_to_mg[8][2] = { 858c2ecf20Sopenharmony_ci { 0, 0 }, 868c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_2G }, 878c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_2G }, 888c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_8G }, 898c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_8G }, 908c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_2G }, 918c2ecf20Sopenharmony_ci { BIT_TO_8G, BIT_TO_2G }, 928c2ecf20Sopenharmony_ci { 0, 0}, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void decode_mg(struct cma3000_accl_data *data, int *datax, 968c2ecf20Sopenharmony_ci int *datay, int *dataz) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci /* Data in 2's complement, convert to mg */ 998c2ecf20Sopenharmony_ci *datax = ((s8)*datax) * data->bit_to_mg; 1008c2ecf20Sopenharmony_ci *datay = ((s8)*datay) * data->bit_to_mg; 1018c2ecf20Sopenharmony_ci *dataz = ((s8)*dataz) * data->bit_to_mg; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic irqreturn_t cma3000_thread_irq(int irq, void *dev_id) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct cma3000_accl_data *data = dev_id; 1078c2ecf20Sopenharmony_ci int datax, datay, dataz, intr_status; 1088c2ecf20Sopenharmony_ci u8 ctrl, mode, range; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status"); 1118c2ecf20Sopenharmony_ci if (intr_status < 0) 1128c2ecf20Sopenharmony_ci return IRQ_NONE; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Check if free fall is detected, report immediately */ 1158c2ecf20Sopenharmony_ci if (intr_status & CMA3000_INTSTATUS_FFDET) { 1168c2ecf20Sopenharmony_ci input_report_abs(data->input_dev, ABS_MISC, 1); 1178c2ecf20Sopenharmony_ci input_sync(data->input_dev); 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci input_report_abs(data->input_dev, ABS_MISC, 0); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci datax = CMA3000_READ(data, CMA3000_DOUTX, "X"); 1238c2ecf20Sopenharmony_ci datay = CMA3000_READ(data, CMA3000_DOUTY, "Y"); 1248c2ecf20Sopenharmony_ci dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl"); 1278c2ecf20Sopenharmony_ci mode = (ctrl & CMA3000_MODEMASK) >> 1; 1288c2ecf20Sopenharmony_ci range = (ctrl & CMA3000_GRANGEMASK) >> 7; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci data->bit_to_mg = mode_to_mg[mode][range]; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Interrupt not for this device */ 1338c2ecf20Sopenharmony_ci if (data->bit_to_mg == 0) 1348c2ecf20Sopenharmony_ci return IRQ_NONE; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Decode register values to milli g */ 1378c2ecf20Sopenharmony_ci decode_mg(data, &datax, &datay, &dataz); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci input_report_abs(data->input_dev, ABS_X, datax); 1408c2ecf20Sopenharmony_ci input_report_abs(data->input_dev, ABS_Y, datay); 1418c2ecf20Sopenharmony_ci input_report_abs(data->input_dev, ABS_Z, dataz); 1428c2ecf20Sopenharmony_ci input_sync(data->input_dev); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int cma3000_reset(struct cma3000_accl_data *data) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci int val; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Reset sequence */ 1528c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset"); 1538c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset"); 1548c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Settling time delay */ 1578c2ecf20Sopenharmony_ci mdelay(10); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci val = CMA3000_READ(data, CMA3000_STATUS, "Status"); 1608c2ecf20Sopenharmony_ci if (val < 0) { 1618c2ecf20Sopenharmony_ci dev_err(data->dev, "Reset failed\n"); 1628c2ecf20Sopenharmony_ci return val; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (val & CMA3000_STATUS_PERR) { 1668c2ecf20Sopenharmony_ci dev_err(data->dev, "Parity Error\n"); 1678c2ecf20Sopenharmony_ci return -EIO; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int cma3000_poweron(struct cma3000_accl_data *data) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci const struct cma3000_platform_data *pdata = data->pdata; 1768c2ecf20Sopenharmony_ci u8 ctrl = 0; 1778c2ecf20Sopenharmony_ci int ret; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (data->g_range == CMARANGE_2G) { 1808c2ecf20Sopenharmony_ci ctrl = (data->mode << 1) | CMA3000_RANGE2G; 1818c2ecf20Sopenharmony_ci } else if (data->g_range == CMARANGE_8G) { 1828c2ecf20Sopenharmony_ci ctrl = (data->mode << 1) | CMA3000_RANGE8G; 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci dev_info(data->dev, 1858c2ecf20Sopenharmony_ci "Invalid G range specified, assuming 8G\n"); 1868c2ecf20Sopenharmony_ci ctrl = (data->mode << 1) | CMA3000_RANGE8G; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ctrl |= data->bus_ops->ctrl_mod; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr, 1928c2ecf20Sopenharmony_ci "Motion Detect Threshold"); 1938c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr, 1948c2ecf20Sopenharmony_ci "Time register"); 1958c2ecf20Sopenharmony_ci CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr, 1968c2ecf20Sopenharmony_ci "Free fall threshold"); 1978c2ecf20Sopenharmony_ci ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting"); 1988c2ecf20Sopenharmony_ci if (ret < 0) 1998c2ecf20Sopenharmony_ci return -EIO; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci msleep(CMA3000_SETDELAY); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int cma3000_poweroff(struct cma3000_accl_data *data) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting"); 2118c2ecf20Sopenharmony_ci msleep(CMA3000_SETDELAY); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int cma3000_open(struct input_dev *input_dev) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct cma3000_accl_data *data = input_get_drvdata(input_dev); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!data->suspended) 2238c2ecf20Sopenharmony_ci cma3000_poweron(data); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci data->opened = true; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void cma3000_close(struct input_dev *input_dev) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct cma3000_accl_data *data = input_get_drvdata(input_dev); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!data->suspended) 2398c2ecf20Sopenharmony_ci cma3000_poweroff(data); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci data->opened = false; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_civoid cma3000_suspend(struct cma3000_accl_data *data) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!data->suspended && data->opened) 2518c2ecf20Sopenharmony_ci cma3000_poweroff(data); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci data->suspended = true; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cma3000_suspend); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid cma3000_resume(struct cma3000_accl_data *data) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci mutex_lock(&data->mutex); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (data->suspended && data->opened) 2658c2ecf20Sopenharmony_ci cma3000_poweron(data); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci data->suspended = false; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci mutex_unlock(&data->mutex); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cma3000_resume); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistruct cma3000_accl_data *cma3000_init(struct device *dev, int irq, 2748c2ecf20Sopenharmony_ci const struct cma3000_bus_ops *bops) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci const struct cma3000_platform_data *pdata = dev_get_platdata(dev); 2778c2ecf20Sopenharmony_ci struct cma3000_accl_data *data; 2788c2ecf20Sopenharmony_ci struct input_dev *input_dev; 2798c2ecf20Sopenharmony_ci int rev; 2808c2ecf20Sopenharmony_ci int error; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (!pdata) { 2838c2ecf20Sopenharmony_ci dev_err(dev, "platform data not found\n"); 2848c2ecf20Sopenharmony_ci error = -EINVAL; 2858c2ecf20Sopenharmony_ci goto err_out; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* if no IRQ return error */ 2908c2ecf20Sopenharmony_ci if (irq == 0) { 2918c2ecf20Sopenharmony_ci error = -EINVAL; 2928c2ecf20Sopenharmony_ci goto err_out; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL); 2968c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 2978c2ecf20Sopenharmony_ci if (!data || !input_dev) { 2988c2ecf20Sopenharmony_ci error = -ENOMEM; 2998c2ecf20Sopenharmony_ci goto err_free_mem; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci data->dev = dev; 3038c2ecf20Sopenharmony_ci data->input_dev = input_dev; 3048c2ecf20Sopenharmony_ci data->bus_ops = bops; 3058c2ecf20Sopenharmony_ci data->pdata = pdata; 3068c2ecf20Sopenharmony_ci data->irq = irq; 3078c2ecf20Sopenharmony_ci mutex_init(&data->mutex); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci data->mode = pdata->mode; 3108c2ecf20Sopenharmony_ci if (data->mode > CMAMODE_POFF) { 3118c2ecf20Sopenharmony_ci data->mode = CMAMODE_MOTDET; 3128c2ecf20Sopenharmony_ci dev_warn(dev, 3138c2ecf20Sopenharmony_ci "Invalid mode specified, assuming Motion Detect\n"); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci data->g_range = pdata->g_range; 3178c2ecf20Sopenharmony_ci if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) { 3188c2ecf20Sopenharmony_ci dev_info(dev, 3198c2ecf20Sopenharmony_ci "Invalid G range specified, assuming 8G\n"); 3208c2ecf20Sopenharmony_ci data->g_range = CMARANGE_8G; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci input_dev->name = "cma3000-accelerometer"; 3248c2ecf20Sopenharmony_ci input_dev->id.bustype = bops->bustype; 3258c2ecf20Sopenharmony_ci input_dev->open = cma3000_open; 3268c2ecf20Sopenharmony_ci input_dev->close = cma3000_close; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci __set_bit(EV_ABS, input_dev->evbit); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_X, 3318c2ecf20Sopenharmony_ci -data->g_range, data->g_range, pdata->fuzz_x, 0); 3328c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Y, 3338c2ecf20Sopenharmony_ci -data->g_range, data->g_range, pdata->fuzz_y, 0); 3348c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_Z, 3358c2ecf20Sopenharmony_ci -data->g_range, data->g_range, pdata->fuzz_z, 0); 3368c2ecf20Sopenharmony_ci input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci input_set_drvdata(input_dev, data); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci error = cma3000_reset(data); 3418c2ecf20Sopenharmony_ci if (error) 3428c2ecf20Sopenharmony_ci goto err_free_mem; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci rev = CMA3000_READ(data, CMA3000_REVID, "Revid"); 3458c2ecf20Sopenharmony_ci if (rev < 0) { 3468c2ecf20Sopenharmony_ci error = rev; 3478c2ecf20Sopenharmony_ci goto err_free_mem; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci pr_info("CMA3000 Accelerometer: Revision %x\n", rev); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci error = request_threaded_irq(irq, NULL, cma3000_thread_irq, 3538c2ecf20Sopenharmony_ci pdata->irqflags | IRQF_ONESHOT, 3548c2ecf20Sopenharmony_ci "cma3000_d0x", data); 3558c2ecf20Sopenharmony_ci if (error) { 3568c2ecf20Sopenharmony_ci dev_err(dev, "request_threaded_irq failed\n"); 3578c2ecf20Sopenharmony_ci goto err_free_mem; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci error = input_register_device(data->input_dev); 3618c2ecf20Sopenharmony_ci if (error) { 3628c2ecf20Sopenharmony_ci dev_err(dev, "Unable to register input device\n"); 3638c2ecf20Sopenharmony_ci goto err_free_irq; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return data; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cierr_free_irq: 3698c2ecf20Sopenharmony_ci free_irq(irq, data); 3708c2ecf20Sopenharmony_cierr_free_mem: 3718c2ecf20Sopenharmony_ci input_free_device(input_dev); 3728c2ecf20Sopenharmony_ci kfree(data); 3738c2ecf20Sopenharmony_cierr_out: 3748c2ecf20Sopenharmony_ci return ERR_PTR(error); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cma3000_init); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_civoid cma3000_exit(struct cma3000_accl_data *data) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci free_irq(data->irq, data); 3818c2ecf20Sopenharmony_ci input_unregister_device(data->input_dev); 3828c2ecf20Sopenharmony_ci kfree(data); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cma3000_exit); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver"); 3878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3888c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); 389