1e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* 2e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * Copyright (C) 2011 Kionix, Inc. 3e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * Written by Chris Hudson <chudson@kionix.com> 4e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * 5e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * This program is free software; you can redistribute it and/or modify 6e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * it under the terms of the GNU General Public License version 2 as 7e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * published by the Free Software Foundation. 8e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * 9e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * This program is distributed in the hope that it will be useful, 10e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * but WITHOUT ANY WARRANTY; without even the implied warranty of 11e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * GNU General Public License for more details. 13e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * 14e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * You should have received a copy of the GNU General Public License 15e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * along with this program; if not, write to the Free Software 16e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 17e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * 02111-1307, USA 18e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson */ 19e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 20e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/delay.h> 21e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/i2c.h> 22e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/input.h> 23e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/interrupt.h> 242501ec97663d84cfbc8fd8848c382f89c3bf8d1dStephen Rothwell#include <linux/module.h> 25e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/slab.h> 26e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/input/kxtj9.h> 27e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#include <linux/input-polldev.h> 28e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 29e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define NAME "kxtj9" 30e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define G_MAX 8000 31e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* OUTPUT REGISTERS */ 32e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define XOUT_L 0x06 33e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define WHO_AM_I 0x0F 34e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* CONTROL REGISTERS */ 35e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define INT_REL 0x1A 36e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define CTRL_REG1 0x1B 37e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define INT_CTRL1 0x1E 38e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define DATA_CTRL 0x21 39e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* CONTROL REGISTER 1 BITS */ 40e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define PC1_OFF 0x7F 41e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define PC1_ON (1 << 7) 42e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* Data ready funtion enable bit: set during probe if using irq mode */ 43e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define DRDYE (1 << 5) 44043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson/* DATA CONTROL REGISTER BITS */ 45043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR12_5F 0 46043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR25F 1 47043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR50F 2 48043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR100F 3 49043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR200F 4 50043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR400F 5 51043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson#define ODR800F 6 52e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* INTERRUPT CONTROL REGISTER 1 BITS */ 53e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* Set these during probe if using irq mode */ 54e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define KXTJ9_IEL (1 << 3) 55e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define KXTJ9_IEA (1 << 4) 56e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define KXTJ9_IEN (1 << 5) 57e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* INPUT_ABS CONSTANTS */ 58e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define FUZZ 3 59e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define FLAT 3 60e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* RESUME STATE INDICES */ 61e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define RES_DATA_CTRL 0 62e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define RES_CTRL_REG1 1 63e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define RES_INT_CTRL1 2 64e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#define RESUME_ENTRIES 3 65e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 66e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* 67e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * The following table lists the maximum appropriate poll interval for each 68e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * available output data rate. 69e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson */ 70e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic const struct { 71e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson unsigned int cutoff; 72e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson u8 mask; 73e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} kxtj9_odr_table[] = { 74e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 3, ODR800F }, 75e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 5, ODR400F }, 76e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 10, ODR200F }, 77e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 20, ODR100F }, 78e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 40, ODR50F }, 79e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 80, ODR25F }, 80e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 0, ODR12_5F}, 81e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 82e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 83e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstruct kxtj9_data { 84e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_client *client; 85e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_platform_data pdata; 86e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev; 87e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE 88e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_polled_dev *poll_dev; 89e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#endif 90e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson unsigned int last_poll_interval; 91e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson u8 shift; 92e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson u8 ctrl_reg1; 93e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson u8 data_ctrl; 94e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson u8 int_ctrl; 95e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 96e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 97e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len) 98e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 99e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_msg msgs[] = { 100e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 101e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .addr = tj9->client->addr, 102e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .flags = tj9->client->flags, 103e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .len = 1, 104e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .buf = &addr, 105e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson }, 106e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { 107e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .addr = tj9->client->addr, 108e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .flags = tj9->client->flags | I2C_M_RD, 109e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .len = len, 110e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .buf = data, 111e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson }, 112e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson }; 113e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 114e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return i2c_transfer(tj9->client->adapter, msgs, 2); 115e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 116e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 117e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_report_acceleration_data(struct kxtj9_data *tj9) 118e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 119e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ 120e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson s16 x, y, z; 121e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 122e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 123e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6); 124e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 125e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, "accelerometer data read failed\n"); 126e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 127043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]); 128043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]); 129043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]); 130043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson 131043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson x >>= tj9->shift; 132043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson y >>= tj9->shift; 133043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson z >>= tj9->shift; 134e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 135e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x); 136e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y); 137e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z); 138e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_sync(tj9->input_dev); 139e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 140e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 141e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic irqreturn_t kxtj9_isr(int irq, void *dev) 142e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 143e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = dev; 144e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 145e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 146e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* data ready is the only possible interrupt type */ 147e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_report_acceleration_data(tj9); 148e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 149e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_read_byte_data(tj9->client, INT_REL); 150e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 151e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, 152e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "error clearing interrupt status: %d\n", err); 153e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 154e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return IRQ_HANDLED; 155e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 156e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 157e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range) 158e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 159e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson switch (new_g_range) { 160e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson case KXTJ9_G_2G: 161e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->shift = 4; 162e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson break; 163e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson case KXTJ9_G_4G: 164e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->shift = 3; 165e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson break; 166e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson case KXTJ9_G_8G: 167e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->shift = 2; 168e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson break; 169e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson default: 170e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -EINVAL; 171e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 172e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 173e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 &= 0xe7; 174e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 |= new_g_range; 175e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 176e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 177e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 178e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 179e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval) 180e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 181e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 182e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int i; 183e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 184e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* Use the lowest ODR that can support the requested poll interval */ 185e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) { 186e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->data_ctrl = kxtj9_odr_table[i].mask; 187e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (poll_interval < kxtj9_odr_table[i].cutoff) 188e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson break; 189e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 190e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 191e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0); 192e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 193e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 194e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 195e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl); 196e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 197e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 198e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 199e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); 200e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 201e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 202e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 203e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 204e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 205e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 206e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_device_power_on(struct kxtj9_data *tj9) 207e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 208e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->pdata.power_on) 209e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return tj9->pdata.power_on(); 210e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 211e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 212e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 213e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 214e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_device_power_off(struct kxtj9_data *tj9) 215e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 216e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 217e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 218e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 &= PC1_OFF; 219e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); 220e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 221e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, "soft power off failed\n"); 222e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 223e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->pdata.power_off) 224e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->pdata.power_off(); 225e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 226e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 227e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_enable(struct kxtj9_data *tj9) 228e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 229e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 230e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 231e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_device_power_on(tj9); 232e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 233e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 234e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 235e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* ensure that PC1 is cleared before updating control registers */ 236e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0); 237e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 238e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 239e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 240e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* only write INT_CTRL_REG1 if in irq mode */ 241e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->client->irq) { 242e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, 243e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson INT_CTRL1, tj9->int_ctrl); 244e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 245e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 246e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 247e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 248e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_update_g_range(tj9, tj9->pdata.g_range); 249e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 250e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 251e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 252e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* turn on outputs */ 253e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 |= PC1_ON; 254e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); 255e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 256e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 257e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 258e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_update_odr(tj9, tj9->last_poll_interval); 259e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 260e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 261e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 262e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* clear initial interrupt if in irq mode */ 263e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->client->irq) { 264e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = i2c_smbus_read_byte_data(tj9->client, INT_REL); 265e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) { 266e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, 267e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "error clearing interrupt: %d\n", err); 268e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto fail; 269e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 270e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 271e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 272e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 273e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 274e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonfail: 275e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_device_power_off(tj9); 276e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 277e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 278e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 279e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_disable(struct kxtj9_data *tj9) 280e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 281e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_device_power_off(tj9); 282e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 283e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 284e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_input_open(struct input_dev *input) 285e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 286e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = input_get_drvdata(input); 287e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 288e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return kxtj9_enable(tj9); 289e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 290e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 291e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_input_close(struct input_dev *dev) 292e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 293e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = input_get_drvdata(dev); 294e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 295e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_disable(tj9); 296e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 297e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 2985298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic void kxtj9_init_input_device(struct kxtj9_data *tj9, 299e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev) 300e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 301e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson __set_bit(EV_ABS, input_dev->evbit); 302e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); 303e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); 304e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); 305e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 306e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev->name = "kxtj9_accel"; 307e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev->id.bustype = BUS_I2C; 308e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev->dev.parent = &tj9->client->dev; 309e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 310e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 3115298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int kxtj9_setup_input_device(struct kxtj9_data *tj9) 312e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 313e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev; 314e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 315e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 316e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev = input_allocate_device(); 3174fd9fcf7c1ee6c339504525b43ad5e77334ff1b5Dan Carpenter if (!input_dev) { 318e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, "input device allocate failed\n"); 319e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -ENOMEM; 320e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 321e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 322e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->input_dev = input_dev; 323e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 324e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev->open = kxtj9_input_open; 325e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_dev->close = kxtj9_input_close; 326e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_set_drvdata(input_dev, tj9); 327e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 328e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_init_input_device(tj9, input_dev); 329e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 330e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = input_register_device(tj9->input_dev); 331e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) { 332e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, 333e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "unable to register input polled device %s: %d\n", 334e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->input_dev->name, err); 335e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_free_device(tj9->input_dev); 336e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 337e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 338e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 339e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 340e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 341e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 342e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* 343e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * When IRQ mode is selected, we need to provide an interface to allow the user 344e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * to change the output data rate of the part. For consistency, we are using 345e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * the set_poll method, which accepts a poll interval in milliseconds, and then 346e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * calls update_odr() while passing this value as an argument. In IRQ mode, the 347e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * data outputs will not be read AT the requested poll interval, rather, the 348e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * lowest ODR that can support the requested interval. The client application 349e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * will be responsible for retrieving data from the input node at the desired 350e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * interval. 351e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson */ 352e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 353e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* Returns currently selected poll interval (in ms) */ 354e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic ssize_t kxtj9_get_poll(struct device *dev, 355e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct device_attribute *attr, char *buf) 356e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 357e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_client *client = to_i2c_client(dev); 358e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = i2c_get_clientdata(client); 359e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 360e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return sprintf(buf, "%d\n", tj9->last_poll_interval); 361e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 362e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 363e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson/* Allow users to select a new poll interval (in ms) */ 364e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, 365e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson const char *buf, size_t count) 366e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 367e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_client *client = to_i2c_client(dev); 368e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = i2c_get_clientdata(client); 369e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev = tj9->input_dev; 370e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson unsigned int interval; 371e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int error; 372e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 373e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson error = kstrtouint(buf, 10, &interval); 374e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (error < 0) 375e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return error; 376e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 377e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* Lock the device to prevent races with open/close (and itself) */ 3786eab7ce65a4e6fae1d2cb5d866515ed288f2fdccDan Carpenter mutex_lock(&input_dev->mutex); 379e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 380e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson disable_irq(client->irq); 381e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 382e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* 383e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * Set current interval to the greater of the minimum interval or 384e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson * the requested interval 385e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson */ 386e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->last_poll_interval = max(interval, tj9->pdata.min_interval); 387e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 388e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_update_odr(tj9, tj9->last_poll_interval); 389e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 390e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson enable_irq(client->irq); 391e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson mutex_unlock(&input_dev->mutex); 392e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 393e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return count; 394e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 395e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 396e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll); 397e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 398e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic struct attribute *kxtj9_attributes[] = { 399e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson &dev_attr_poll.attr, 400e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson NULL 401e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 402e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 403e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic struct attribute_group kxtj9_attribute_group = { 404e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .attrs = kxtj9_attributes 405e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 406e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 407e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 408e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE 409e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_poll(struct input_polled_dev *dev) 410e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 411e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = dev->private; 412e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson unsigned int poll_interval = dev->poll_interval; 413e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 414e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_report_acceleration_data(tj9); 415e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 416e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (poll_interval != tj9->last_poll_interval) { 417e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_update_odr(tj9, poll_interval); 418e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->last_poll_interval = poll_interval; 419e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 420e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 421e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 422e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_polled_input_open(struct input_polled_dev *dev) 423e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 424e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = dev->private; 425e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 426e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_enable(tj9); 427e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 428e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 429e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic void kxtj9_polled_input_close(struct input_polled_dev *dev) 430e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 431e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = dev->private; 432e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 433e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_disable(tj9); 434e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 435e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 4365298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int kxtj9_setup_polled_device(struct kxtj9_data *tj9) 437e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 438e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 439e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_polled_dev *poll_dev; 440e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson poll_dev = input_allocate_polled_device(); 441e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 442e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (!poll_dev) { 443e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, 444e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "Failed to allocate polled device\n"); 445e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -ENOMEM; 446e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 447e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 448e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->poll_dev = poll_dev; 449e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->input_dev = poll_dev->input; 450e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 451e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson poll_dev->private = tj9; 452e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson poll_dev->poll = kxtj9_poll; 453e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson poll_dev->open = kxtj9_polled_input_open; 454e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson poll_dev->close = kxtj9_polled_input_close; 455e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 456e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_init_input_device(tj9, poll_dev->input); 457e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 458e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = input_register_polled_device(poll_dev); 459e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) { 460e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, 461e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "Unable to register polled device, err=%d\n", err); 462e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_free_polled_device(poll_dev); 463e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 464e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 465e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 466e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 467e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 468e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 469e2619cf78e19476bfd7ceaefa9eff0847529346eBill Pembertonstatic void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) 470e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 471e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_unregister_polled_device(tj9->poll_dev); 472e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_free_polled_device(tj9->poll_dev); 473e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 474e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 475e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#else 476e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 477e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9) 478e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 479e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -ENOSYS; 480e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 481e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 482e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) 483e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 484e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 485e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 486e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#endif 487e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 4885298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int kxtj9_verify(struct kxtj9_data *tj9) 489e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 490e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int retval; 491e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 492e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson retval = kxtj9_device_power_on(tj9); 493e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (retval < 0) 494e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return retval; 495e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 496e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I); 497e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (retval < 0) { 498e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&tj9->client->dev, "read err int source\n"); 499e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto out; 500e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 501e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 502043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson retval = (retval != 0x07 && retval != 0x08) ? -EIO : 0; 503e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 504e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonout: 505e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_device_power_off(tj9); 506e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return retval; 507e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 508e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 5095298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int kxtj9_probe(struct i2c_client *client, 510e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson const struct i2c_device_id *id) 511e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 512c838cb3d477f79738ee03ede53a3f724021f3ae0Jingoo Han const struct kxtj9_platform_data *pdata = 513c838cb3d477f79738ee03ede53a3f724021f3ae0Jingoo Han dev_get_platdata(&client->dev); 514e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9; 515e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int err; 516e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 517e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (!i2c_check_functionality(client->adapter, 518e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) { 519e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, "client is not i2c capable\n"); 520e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -ENXIO; 521e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 522e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 523e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (!pdata) { 524e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, "platform data is NULL; exiting\n"); 525e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -EINVAL; 526e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 527e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 528e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL); 529e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (!tj9) { 530e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, 531e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "failed to allocate memory for module data\n"); 532e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return -ENOMEM; 533e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 534e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 535e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->client = client; 536e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->pdata = *pdata; 537e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 538e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (pdata->init) { 539e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = pdata->init(); 540e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) 541e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_free_mem; 542e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 543e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 544e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_verify(tj9); 545e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err < 0) { 546e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, "device not recognized\n"); 547e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_pdata_exit; 548e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 549e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 550e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson i2c_set_clientdata(client, tj9); 551e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 552e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range; 553043916608c4b309e98a1650520ed4e88ec5e9123Christopher Hudson tj9->last_poll_interval = tj9->pdata.init_interval; 554e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 555e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (client->irq) { 556e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson /* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */ 557e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL; 558e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->ctrl_reg1 |= DRDYE; 559e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 560e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_setup_input_device(tj9); 561e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) 562e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_pdata_exit; 563e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 564e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = request_threaded_irq(client->irq, NULL, kxtj9_isr, 565e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson IRQF_TRIGGER_RISING | IRQF_ONESHOT, 566e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson "kxtj9-irq", tj9); 567e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) { 568e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, "request irq failed: %d\n", err); 569e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_destroy_input; 570e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 571e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 572e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group); 573e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) { 574e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson dev_err(&client->dev, "sysfs create failed: %d\n", err); 575e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_free_irq; 576e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 577e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 578e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } else { 579e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson err = kxtj9_setup_polled_device(tj9); 580e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (err) 581e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson goto err_pdata_exit; 582e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 583e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 584e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 585e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 586e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonerr_free_irq: 587e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson free_irq(client->irq, tj9); 588e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonerr_destroy_input: 589e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_unregister_device(tj9->input_dev); 590e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonerr_pdata_exit: 591e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->pdata.exit) 592e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->pdata.exit(); 593e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonerr_free_mem: 594e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kfree(tj9); 595e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return err; 596e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 597e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 598e2619cf78e19476bfd7ceaefa9eff0847529346eBill Pembertonstatic int kxtj9_remove(struct i2c_client *client) 599e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 600e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = i2c_get_clientdata(client); 601e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 602e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (client->irq) { 603e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group); 604e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson free_irq(client->irq, tj9); 605e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson input_unregister_device(tj9->input_dev); 606e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } else { 607e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_teardown_polled_device(tj9); 608e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson } 609e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 610e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (tj9->pdata.exit) 611e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson tj9->pdata.exit(); 612e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 613e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kfree(tj9); 614e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 615e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 616e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 617e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 618e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#ifdef CONFIG_PM_SLEEP 619e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_suspend(struct device *dev) 620e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 621e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_client *client = to_i2c_client(dev); 622e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = i2c_get_clientdata(client); 623e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev = tj9->input_dev; 624e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 625e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson mutex_lock(&input_dev->mutex); 626e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 627e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (input_dev->users) 628e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_disable(tj9); 629e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 630e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson mutex_unlock(&input_dev->mutex); 631e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return 0; 632e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 633e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 634e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic int kxtj9_resume(struct device *dev) 635e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson{ 636e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct i2c_client *client = to_i2c_client(dev); 637e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct kxtj9_data *tj9 = i2c_get_clientdata(client); 638e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson struct input_dev *input_dev = tj9->input_dev; 639e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson int retval = 0; 640e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 641e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson mutex_lock(&input_dev->mutex); 642e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 643e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson if (input_dev->users) 644e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson kxtj9_enable(tj9); 645e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 646e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson mutex_unlock(&input_dev->mutex); 647e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson return retval; 648e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson} 649e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson#endif 650e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 651e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); 652e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 653e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic const struct i2c_device_id kxtj9_id[] = { 654e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { NAME, 0 }, 655e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson { }, 656e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 657e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 658e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris HudsonMODULE_DEVICE_TABLE(i2c, kxtj9_id); 659e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 660e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudsonstatic struct i2c_driver kxtj9_driver = { 661e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .driver = { 662e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .name = NAME, 663e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .owner = THIS_MODULE, 664e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .pm = &kxtj9_pm_ops, 665e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson }, 666e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .probe = kxtj9_probe, 6671cb0aa88179b7a71c240529e9d781d7bbb43d2e8Bill Pemberton .remove = kxtj9_remove, 668e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson .id_table = kxtj9_id, 669e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson}; 670e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 6711b92c1cf6b638e7cbe9fdaac3f6efb8874f5cc02Axel Linmodule_i2c_driver(kxtj9_driver); 672e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris Hudson 673e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris HudsonMODULE_DESCRIPTION("KXTJ9 accelerometer driver"); 674e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris HudsonMODULE_AUTHOR("Chris Hudson <chudson@kionix.com>"); 675e8e70d83912b40c5c9ea7b85a6110b9925fbed62Chris HudsonMODULE_LICENSE("GPL"); 676