aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorBill Crossley <billcrossley@gmail.com>2012-03-26 16:27:58 -0400
committerBill Crossley <billcrossley@gmail.com>2012-03-30 11:55:43 -0400
commit6307b809ed56f10c640057a02711637ac9cfb8eb (patch)
tree44c737e8759fd40154cf6927409c3fc2006c1cd3 /drivers/input
parent2531214b7b6aeb61a4977131a8c939787a1f2c1a (diff)
downloadkernel_samsung_aries-6307b809ed56f10c640057a02711637ac9cfb8eb.zip
kernel_samsung_aries-6307b809ed56f10c640057a02711637ac9cfb8eb.tar.gz
kernel_samsung_aries-6307b809ed56f10c640057a02711637ac9cfb8eb.tar.bz2
Fascinate-specific sensor fixes for orientation.
General sensor fixes for light level sensor.
Diffstat (limited to 'drivers/input')
-rwxr-xr-xdrivers/input/misc/Makefile11
-rwxr-xr-xdrivers/input/misc/gp2a_atlas.c4
-rwxr-xr-xdrivers/input/misc/kr3dh.c4
-rw-r--r--drivers/input/misc/kr3dh_cdma.c676
-rw-r--r--drivers/input/misc/orientation.c20
5 files changed, 703 insertions, 12 deletions
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 98e0892..0a6f6ad 100755
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -19,12 +19,15 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_BMA023) += bma023.o
-obj-$(CONFIG_INPUT_KR3DH) += kr3dh.o
ifeq ($(CONFIG_SAMSUNG_FASCINATE),y)
obj-$(CONFIG_INPUT_YAS529) += yas529_atlas.o
+obj-$(CONFIG_INPUT_KR3DH) += kr3dh_cdma.o
+obj-$(CONFIG_OPTICAL_GP2A) += gp2a_atlas.o
else
obj-$(CONFIG_INPUT_YAS529) += yas529.o
+obj-$(CONFIG_INPUT_KR3DH) += kr3dh.o
+obj-$(CONFIG_OPTICAL_GP2A) += gp2a.o
endif
obj-$(CONFIG_INPUT_ORIENTATION) += orientation.o
@@ -60,9 +63,3 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
-ifeq ($(CONFIG_SAMSUNG_FASCINATE),y)
-obj-$(CONFIG_OPTICAL_GP2A) += gp2a_atlas.o
-else
-obj-$(CONFIG_OPTICAL_GP2A) += gp2a.o
-endif
-
diff --git a/drivers/input/misc/gp2a_atlas.c b/drivers/input/misc/gp2a_atlas.c
index 7375951..1f65428 100755
--- a/drivers/input/misc/gp2a_atlas.c
+++ b/drivers/input/misc/gp2a_atlas.c
@@ -527,7 +527,7 @@ static int gp2a_i2c_probe(struct i2c_client *client,
}
gp2a->proximity_input_dev = input_dev;
input_set_drvdata(input_dev, gp2a);
- input_dev->name = "proximity_sensor";
+ input_dev->name = "proximity";
input_set_capability(input_dev, EV_ABS, ABS_DISTANCE);
input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0);
@@ -569,7 +569,7 @@ static int gp2a_i2c_probe(struct i2c_client *client,
goto err_input_allocate_device_light;
}
input_set_drvdata(input_dev, gp2a);
- input_dev->name = "light_sensor";
+ input_dev->name = "lightsensor-level";
input_set_capability(input_dev, EV_ABS, ABS_MISC);
input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
diff --git a/drivers/input/misc/kr3dh.c b/drivers/input/misc/kr3dh.c
index dd295df..bb6555a 100755
--- a/drivers/input/misc/kr3dh.c
+++ b/drivers/input/misc/kr3dh.c
@@ -30,7 +30,7 @@
#define DEVICE_ID (0x32)
#define KR3DH_NAME "kr3dh"
#define KR3DH_RESOLUTION 16384 /* [count/G] */
-#define GRAVITY_EARTH 9806550
+#define GRAVITY_EARTH 9806650
#define ABSMIN_2G (-GRAVITY_EARTH * 2)
#define ABSMAX_2G (GRAVITY_EARTH * 2)
@@ -415,7 +415,7 @@ static ssize_t kr3dh_delay_store(struct device *dev,
const char *buf, size_t count)
{
unsigned long delay = simple_strtoul(buf, NULL, 10);
-
+
kr3dh_set_delay(dev, delay);
return count;
diff --git a/drivers/input/misc/kr3dh_cdma.c b/drivers/input/misc/kr3dh_cdma.c
new file mode 100644
index 0000000..d96f9f8
--- /dev/null
+++ b/drivers/input/misc/kr3dh_cdma.c
@@ -0,0 +1,676 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include "kr3dh_reg.h"
+
+
+
+#define TRACE_FUNC() pr_info(KR3DH_NAME ": <trace> %s()\n", __FUNCTION__)
+
+/* The default settings when sensor is on is for all 3 axis to be enabled
+ * and output data rate set to 400Hz. Output is via a ioctl read call.
+*/
+#define DEFAULT_POWER_ON_SETTING (ODR400 | ENABLE_ALL_AXES)
+#define READ_REPEAT_SHIFT 3
+#define READ_REPEAT (1 << READ_REPEAT_SHIFT)
+
+#define DEVICE_ID (0x32)
+#define KR3DH_NAME "kr3dh"
+#define KR3DH_RESOLUTION 16384 /* [count/G] */
+#define GRAVITY_EARTH 9806650
+#define ABSMIN_2G (-GRAVITY_EARTH * 2)
+#define ABSMAX_2G (GRAVITY_EARTH * 2)
+
+
+
+static const struct odr_delay {
+ u8 odr; /* odr reg setting */
+ s64 delay; /* odr in ns */
+}kr3dh_odr_table [] = {
+ { ODR400, 2500000LL }, /* 400Hz */
+ { ODR100, 10000000LL }, /* 100Hz */
+ { ODR50, 20000000LL }, /* 50Hz */
+ { ODR10, 100000000LL }, /* 10Hz */
+ { ODR5, 200000000LL }, /* 5Hz */
+ { ODR2, 500000000LL }, /* 2Hz */
+ { ODR1, 1000000000LL }, /* 1Hz */
+ { ODRHALF, 2000000000LL }, /* 0.5Hz */
+};
+
+#define event_delay(s) (delay_to_jiffies(((s) / (1000 * 1000))))
+#define delay_to_jiffies(d) ((d)?msecs_to_jiffies(d):1)
+#define actual_delay(d) (jiffies_to_msecs(delay_to_jiffies(d)))
+
+
+/* KR3DM acceleration data */
+struct acceleration {
+ int axis[3];
+};
+
+/*
+ * driver private data
+ */
+struct kr3dh_data {
+ atomic_t enable; /* attribute value */
+ atomic_t delay; /* attribute value */
+ atomic_t position; /* attribute value */
+ u8 ctrl_reg1_shadow;
+ struct acceleration last; /* last measured data */
+ struct mutex enable_mutex;
+ struct mutex data_mutex;
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct delayed_work work;
+};
+
+
+/*
+ * Transformation matrix for chip mounting position
+ */
+static const int kr3dh_position_map[][3][3] = {
+ {{ 0, -1, 0}, { 1, 0, 0}, { 0, 0, 1}}, /* top/upper-left */
+ {{ 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}}, /* top/upper-right */
+ {{ 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1}}, /* top/lower-right */
+ {{-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1}}, /* top/lower-left */
+ {{ 0, 1, 0}, { 1, 0, 0}, { 0, 0, -1}}, /* bottom/upper-right */
+ {{-1, 0, 0}, { 0, 1, 0}, { 0, 0, -1}}, /* bottom/upper-left */
+ {{ 0, -1, 0}, {-1, 0, 0}, { 0, 0, -1}}, /* bottom/lower-left */
+ {{ 1, 0, 0}, { 0, -1, 0}, { 0, 0, -1}}, /* bottom/lower-right */
+};
+
+
+
+static int kr3dh_power_down(struct kr3dh_data *kr3dh)
+{
+ int res = 0;
+
+ res = i2c_smbus_write_byte_data(kr3dh->client,
+ CTRL_REG1, PM_OFF);
+
+ res = i2c_smbus_write_byte_data(kr3dh->client,
+ CTRL_REG5, 0x00);
+
+ return res;
+}
+
+static int kr3dh_power_up(struct kr3dh_data *kr3dh)
+{
+ int res = 0;
+
+ res = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG1,
+ kr3dh->ctrl_reg1_shadow);
+
+ res = i2c_smbus_write_byte_data(kr3dh->client,
+ CTRL_REG5, 0x03);
+
+ return res;
+
+}
+
+static int kr3dh_measure(struct kr3dh_data *kr3dh, struct acceleration *accel);
+
+static int kr3dh_hw_init(struct kr3dh_data *kr3dh)
+{
+ int err = 0;
+
+ kr3dh->ctrl_reg1_shadow = DEFAULT_POWER_ON_SETTING;
+ err = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG1,
+ DEFAULT_POWER_ON_SETTING);
+ if (err) {
+ pr_err("kr3dh_hw_init() i2c write ctrl_reg1 failed\n");
+ }
+
+ /* Disables Filters */
+ err = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG2,0x00);
+ if (err) {
+ pr_err("kr3dh_hw_init() i2c write ctrl_reg2 failed\n");
+ }
+
+ /* Disable Interrupts */
+ err = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG3,0x00);
+ if (err) {
+ pr_err("kr3dh_hw_init() i2c write ctrl_reg3 failed\n");
+ }
+
+ /* Non Continous mode, Little Endian, 2G Range */
+ err = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG4,0x80);
+ if (err) {
+ pr_err("kr3dh_hw_init() i2c write ctrl_reg4 failed\n");
+ }
+
+ /* Sleep to Wake: TurnON */
+ err = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG5,0x03);
+ if (err) {
+ pr_err("kr3dh_hw_init() i2c write ctrl_reg5 failed\n");
+ }
+
+ return err;
+}
+
+static int kr3dh_get_enable(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ return atomic_read(&kr3dh->enable);
+
+}
+
+static void kr3dh_set_enable(struct device *dev, int enable)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+ int delay = atomic_read(&kr3dh->delay);
+
+ mutex_lock(&kr3dh->enable_mutex);
+
+ if (enable) { /* enable if state will be changed */
+ if (!atomic_cmpxchg(&kr3dh->enable, 0, 1)) {
+ kr3dh_power_up(kr3dh);
+ schedule_delayed_work(&kr3dh->work,
+ event_delay(delay) + 1);
+ }
+ } else { /* disable if state will be changed */
+ if (atomic_cmpxchg(&kr3dh->enable, 1, 0)) {
+ cancel_delayed_work_sync(&kr3dh->work);
+ kr3dh_power_down(kr3dh);
+ }
+ }
+ atomic_set(&kr3dh->enable, enable);
+
+ mutex_unlock(&kr3dh->enable_mutex);
+
+}
+
+static int kr3dh_get_delay(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ return atomic_read(&kr3dh->delay);
+}
+
+static void kr3dh_set_delay(struct device *dev, s64 delay)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+ u8 odr_value;
+ int i, res = 0;
+ unsigned long delay_ms = 0;
+
+ /* determine optimum ODR */
+ for (i = 1; (i < ARRAY_SIZE(kr3dh_odr_table)) &&
+ (delay >= kr3dh_odr_table[i].delay); i++)
+ ;
+ odr_value = kr3dh_odr_table[i-1].odr;
+ atomic_set(&kr3dh->delay, delay);
+
+ mutex_lock(&kr3dh->enable_mutex);
+
+ if (kr3dh_get_enable(dev)) {
+ cancel_delayed_work_sync(&kr3dh->work);
+ if (odr_value != (kr3dh->ctrl_reg1_shadow & ODR_MASK)) {
+ u8 ctrl = (kr3dh->ctrl_reg1_shadow & ~ODR_MASK);
+ ctrl |= odr_value;
+ kr3dh->ctrl_reg1_shadow = ctrl;
+ res = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG1, ctrl);
+ printk("writing odr value 0x%x\n", odr_value);
+ }
+ delay_ms = delay ;
+ delay_ms = delay_ms / 1000;
+ delay_ms = delay_ms / 1000;
+
+ schedule_delayed_work(&kr3dh->work,
+ delay_to_jiffies(delay_ms) + 1);
+ } else {
+ kr3dh_power_up(kr3dh);
+ if (odr_value != (kr3dh->ctrl_reg1_shadow & ODR_MASK)) {
+ u8 ctrl = (kr3dh->ctrl_reg1_shadow & ~ODR_MASK);
+ ctrl |= odr_value;
+ kr3dh->ctrl_reg1_shadow = ctrl;
+ res = i2c_smbus_write_byte_data(kr3dh->client, CTRL_REG1, ctrl);
+ printk("writing odr value 0x%x\n", odr_value);
+ }
+
+ kr3dh_power_down(kr3dh);
+ }
+
+ mutex_unlock(&kr3dh->enable_mutex);
+}
+
+static int kr3dh_set_position(struct device *dev, int position)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ return atomic_set(&kr3dh->position, position);
+
+}
+
+static int kr3dh_get_position(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ return atomic_read(&kr3dh->position);
+
+}
+int kr3dh_i2c_byte_read(struct i2c_client *client, u8 command)
+{
+ union i2c_smbus_data data;
+ int status;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (status < 0) {
+ pr_err("I2C read error: acceleration not read\n");
+ }
+ return (status < 0) ? status : data.byte;
+}
+
+static int kr3dh_measure(struct kr3dh_data *kr3dh, struct acceleration *accel)
+{
+ int i =0;
+ int j = 0;
+ int value;
+ int pos = (int)atomic_read(&kr3dh->position);
+ unsigned char buf[6] = {0};
+ short int raw[3] = {0};
+ long long g;
+
+ for (i = 0; i < 6; i++) {
+ buf[i] = kr3dh_i2c_byte_read(kr3dh->client, AXISDATA_REG + i);
+ }
+ for (i = 0; i < 3; i++) {
+ raw[i] = (unsigned short)(buf[i*2+1]<<8) + (unsigned short)buf[i*2];
+ }
+ for (i = 0; i < 3; i++) {
+ value = 0;
+ for (j = 0; j < 3; j++) {
+ value += kr3dh_position_map[pos][i][j] * (int)raw[j];
+ }
+ /* normalisation*/
+ // here we want to report a range of -512 .. 512, corresponding to -2g .. 2g
+ // 'value' is between -32768 .. 32768, corresponding also to -2g .. 2g
+ // so .. trim off the 6 lower bits and we should be good.
+ g = value >> 6;
+
+ //g = (long long)value * GRAVITY_EARTH / KR3DH_RESOLUTION;
+ accel->axis[i] = g;
+ }
+
+ return 0;
+}
+
+static void kr3dh_work_func(struct work_struct *work)
+{
+ struct kr3dh_data *kr3dh = container_of((struct delayed_work *)work,
+ struct kr3dh_data, work);
+ struct acceleration accel;
+ unsigned long delay = event_delay(atomic_read(&kr3dh->delay));
+
+ kr3dh_measure(kr3dh, &accel);
+
+ input_report_rel(kr3dh->input, REL_X, accel.axis[0]);
+ input_report_rel(kr3dh->input, REL_Y, accel.axis[1]);
+ input_report_rel(kr3dh->input, REL_Z, accel.axis[2]);
+ input_sync(kr3dh->input);
+
+ mutex_lock(&kr3dh->data_mutex);
+ kr3dh->last = accel;
+ mutex_unlock(&kr3dh->data_mutex);
+
+ schedule_delayed_work(&kr3dh->work, delay);
+
+}
+
+/*
+ * Input device interface
+ */
+static int kr3dh_input_init(struct i2c_client *client, struct kr3dh_data *kr3dh)
+{
+ struct input_dev *dev;
+ int err;
+
+ dev = input_allocate_device();
+ if (!dev) {
+ return -ENOMEM;
+ }
+ dev->name = "accelerometer_sensor";
+ dev->id.bustype = BUS_I2C;
+
+ /* X */
+ input_set_capability(dev, EV_REL, REL_X);
+ input_set_abs_params(dev, REL_X, ABSMIN_2G, ABSMAX_2G, 0, 0);
+ /* Y */
+ input_set_capability(dev, EV_REL, REL_Y);
+ input_set_abs_params(dev, REL_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);
+ /* Z */
+ input_set_capability(dev, EV_REL, REL_Z);
+ input_set_abs_params(dev, REL_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);
+ input_set_drvdata(dev, kr3dh);
+ dev->dev.parent = &client->dev;
+
+ err = input_register_device(dev);
+ if (err < 0) {
+ input_free_device(dev);
+ return err;
+ }
+ kr3dh->input = dev;
+
+ return 0;
+
+}
+
+static void kr3dh_input_fini(struct kr3dh_data *kr3dh)
+{
+ struct input_dev *dev = kr3dh->input;
+
+ input_unregister_device(dev);
+ input_free_device(dev);
+
+}
+
+/*
+ * sysfs device attributes
+ */
+
+static ssize_t kr3dh_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", kr3dh_get_enable(dev));
+}
+
+static ssize_t kr3dh_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long enable = simple_strtoul(buf, NULL, 10);
+
+ if ((enable == 0) || (enable == 1)) {
+ kr3dh_set_enable(dev, enable);
+ }
+
+ return count;
+
+}
+
+static ssize_t kr3dh_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ /* delay is "displayed" here as ms, but we have stored it as ns */
+ return sprintf(buf, "%d\n", kr3dh_get_delay(dev) / 1000000 );
+}
+
+static ssize_t kr3dh_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long delay = simple_strtoul(buf, NULL, 10);
+
+ /* delay comes in here as miliseconds, but the system wants it as nanoseconds */
+ delay *= 1000000;
+
+ kr3dh_set_delay(dev, delay);
+
+ return count;
+}
+
+static ssize_t kr3dh_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", kr3dh_get_position(dev));
+}
+
+static ssize_t kr3dh_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long position;
+
+ position = simple_strtoul(buf, NULL,10);
+ if ((position >= 0) && (position <= 7)) {
+ kr3dh_set_position(dev, position);
+ }
+
+ return count;
+}
+
+static ssize_t kr3dh_wake_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input = to_input_dev(dev);
+ static atomic_t serial = ATOMIC_INIT(0);
+
+ input_report_abs(input, ABS_MISC, atomic_inc_return(&serial));
+
+ return count;
+
+}
+
+static ssize_t kr3dh_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct kr3dh_data *kr3dh = input_get_drvdata(input);
+ struct acceleration accel;
+
+ mutex_lock(&kr3dh->data_mutex);
+ accel = kr3dh->last;
+ mutex_unlock(&kr3dh->data_mutex);
+
+ return sprintf(buf, "%d %d %d\n", accel.axis[0], accel.axis[1], accel.axis[2]);
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
+ kr3dh_enable_show, kr3dh_enable_store);
+static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
+ kr3dh_delay_show, kr3dh_delay_store);
+static DEVICE_ATTR(position, S_IRUGO|S_IWUSR,
+ kr3dh_position_show, kr3dh_position_store);
+static DEVICE_ATTR(wake, S_IWUSR|S_IWGRP,
+ NULL, kr3dh_wake_store);
+static DEVICE_ATTR(data, S_IRUGO,
+ kr3dh_data_show, NULL);
+
+static struct attribute *kr3dh_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_position.attr,
+ &dev_attr_wake.attr,
+ &dev_attr_data.attr,
+ NULL
+};
+
+static struct attribute_group kr3dh_attribute_group = {
+ .attrs = kr3dh_attributes
+};
+
+
+static int kr3dh_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ int ret = 0;
+ int err = 0;
+ /* read chip id */
+ ret = i2c_smbus_read_byte_data(client, WHO_AM_I);
+
+ printk("KR3DH: DEVICE_ID -> %x\n", ret);
+ if (ret != DEVICE_ID) {
+ if (ret < 0) {
+ pr_err("%s: i2c for reading chip id failed\n",
+ __func__);
+ err = ret;
+ } else {
+ pr_err("%s : Device identification failed\n",
+ __func__);
+ err = -ENODEV;
+ }
+ }
+ return err;
+}
+
+static int kr3dh_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct kr3dh_data *kr3dh;
+ int err;
+
+ /* setup private data */
+ kr3dh = kzalloc(sizeof(struct kr3dh_data), GFP_KERNEL);
+ if (!kr3dh) {
+ err = -ENOMEM;
+ goto error_0;
+ }
+ mutex_init(&kr3dh->enable_mutex);
+ mutex_init(&kr3dh->data_mutex);
+
+ /* setup i2c client */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ {
+ err = -ENODEV;
+ goto error_1;
+ }
+ i2c_set_clientdata(client, kr3dh);
+ kr3dh->client = client;
+
+ /* detect and init hardware */
+ if ((err = kr3dh_detect(client, NULL))) {
+ goto error_1;
+ }
+ dev_info(&client->dev, "%s found\n", id->name);
+
+ kr3dh_hw_init(kr3dh);
+ kr3dh_set_delay(&client->dev, 20000000LL);
+ kr3dh_set_position(&client->dev, 2);
+
+ /* setup driver interfaces */
+ INIT_DELAYED_WORK(&kr3dh->work, kr3dh_work_func);
+
+ err = kr3dh_input_init(client, kr3dh);
+ if (err < 0) {
+ goto error_1;
+ }
+
+ err = sysfs_create_group(&kr3dh->input->dev.kobj, &kr3dh_attribute_group);
+ if (err < 0) {
+ goto error_2;
+ }
+
+ return 0;
+
+error_2:
+ kr3dh_input_fini(kr3dh);
+error_1:
+ kfree(kr3dh);
+error_0:
+ return err;
+
+
+
+}
+
+static int kr3dh_remove(struct i2c_client *client)
+{
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ kr3dh_set_enable(&client->dev, 0);
+
+ sysfs_remove_group(&kr3dh->input->dev.kobj, &kr3dh_attribute_group);
+ kr3dh_input_fini(kr3dh);
+ kfree(kr3dh);
+
+ return 0;
+}
+
+static int kr3dh_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+
+ TRACE_FUNC();
+
+ mutex_lock(&kr3dh->enable_mutex);
+
+ if (kr3dh_get_enable(&client->dev)) {
+ cancel_delayed_work_sync(&kr3dh->work);
+ kr3dh_power_down(kr3dh);
+ }
+ mutex_unlock(&kr3dh->enable_mutex);
+
+ return 0;
+}
+
+static int kr3dh_resume(struct i2c_client *client)
+{
+ struct kr3dh_data *kr3dh = i2c_get_clientdata(client);
+ int delay = atomic_read(&kr3dh->delay);
+
+ TRACE_FUNC();
+
+ kr3dh_hw_init(kr3dh);
+ kr3dh_set_delay(&client->dev, delay);
+
+ mutex_lock(&kr3dh->enable_mutex);
+
+ if (kr3dh_get_enable(&client->dev)) {
+ kr3dh_power_up(kr3dh);
+ schedule_delayed_work(&kr3dh->work,
+ event_delay(delay) + 1);
+ }
+ mutex_unlock(&kr3dh->enable_mutex);
+ return 0;
+}
+
+static const struct i2c_device_id kr3dh_id[] = {
+ {KR3DH_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, kr3dh_id);
+
+struct i2c_driver kr3dh_driver ={
+ .driver = {
+ .name = "kr3dh",
+ .owner = THIS_MODULE,
+ },
+ .probe = kr3dh_probe,
+ .remove = kr3dh_remove,
+ .suspend = kr3dh_suspend,
+ .resume = kr3dh_resume,
+ .id_table = kr3dh_id,
+};
+
+/*
+ * Module init and exit
+ */
+static int __init kr3dh_init(void)
+{
+ return i2c_add_driver(&kr3dh_driver);
+}
+module_init(kr3dh_init);
+
+static void __exit kr3dh_exit(void)
+{
+ i2c_del_driver(&kr3dh_driver);
+}
+module_exit(kr3dh_exit);
+
+MODULE_AUTHOR("Samsung");
+MODULE_DESCRIPTION("KR3DH 3 axis accelerometer driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
+
diff --git a/drivers/input/misc/orientation.c b/drivers/input/misc/orientation.c
index 1961ff7..f73d620 100644
--- a/drivers/input/misc/orientation.c
+++ b/drivers/input/misc/orientation.c
@@ -209,15 +209,33 @@ orientation_probe(struct platform_device *pdev)
}
set_bit(EV_REL, input_data->evbit);
- input_set_capability(input_data, EV_REL, REL_X);
+
+ // we now have to set params for each of these since the place to store them is
+ // allocated dynamically. For a REL axis like these, the min and max values are not
+ // considered when deciding how to handle the event, so they shouldn't matter.
+ // I just picked some values that seemed to make sense in terms of an orientation sensor
+ // just in case..
+ input_set_capability(input_data, EV_REL, REL_X);
+ input_set_abs_params(input_data, REL_X, -3600, 3600, 0, 0);
+
input_set_capability(input_data, EV_REL, REL_Y);
+ input_set_abs_params(input_data, REL_Y, -3600, 3600, 0, 0);
+
input_set_capability(input_data, EV_REL, REL_Z);
+ input_set_abs_params(input_data, REL_Z, -3600, 3600, 0, 0);
+
/* sattus */
input_set_capability(input_data, EV_REL, REL_STATUS);
+ input_set_abs_params(input_data, REL_STATUS, -3600, 3600, 0, 0);
+
/* wake */
input_set_capability(input_data, EV_REL, REL_WAKE);
+ input_set_abs_params(input_data, REL_WAKE, -3600, 3600, 0, 0);
+
/* enabled/delay */
input_set_capability(input_data, EV_REL, REL_CONTROL_REPORT);
+ input_set_abs_params(input_data, REL_CONTROL_REPORT, -3600, 3600, 0, 0);
+
input_data->name = SENSOR_NAME;
err = input_register_device(input_data);