[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1452666204-372-1-git-send-email-jeffrey.lin@rad-ic.com>
Date: Wed, 13 Jan 2016 14:23:24 +0800
From: Jeffrey Lin <yajohn@...il.com>
To: dmitry.torokhov@...il.com, rydberg@...omail.se
Cc: jeffrey.lin@...-ic.com, roger.yang@...-ic.com, KP.li@...-ic.com,
linux-kernel@...r.kernel.org, linux-input@...r.kernel.org
Subject: [PATCH] driver: input :touchscreen : add Raydium I2C touch driver
This patch is porting Raydium I2C touch driver. Developer can enable raydium touch driver by modifying define
"CONFIG_TOUCHSCREEN_RM_TS".
Signed-off-by: jeffrey lin <jeffrey.lin@...-ic.com>
---
drivers/input/touchscreen/rm31100_ts.c | 571 +++++++++++++++------------------
1 file changed, 250 insertions(+), 321 deletions(-)
diff --git a/drivers/input/touchscreen/rm31100_ts.c b/drivers/input/touchscreen/rm31100_ts.c
index 941fa31..e024bbd 100644
--- a/drivers/input/touchscreen/rm31100_ts.c
+++ b/drivers/input/touchscreen/rm31100_ts.c
@@ -28,14 +28,11 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
-#ifdef CONFIG_MISC_DEV
-#include <linux/miscdevice.h>
-#endif
#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <linux/input/mt.h>
@@ -65,27 +62,15 @@ struct rm31100_ts_data {
};
struct rm3110x_ts_platform_data {
- int (*power_on)(int on);
- int (*dev_setup)(bool on);
- const char *ts_name;
u32 dis_min_x; /* display resoltion ABS min*/
u32 dis_max_x;/* display resoltion ABS max*/
u32 dis_min_y;
u32 dis_max_y;
- u32 min_touch; /* no.of touches supported */
- u32 max_touch;
- u32 min_tid; /* track id */
- u32 max_tid;
- u32 min_width;/* size of the finger */
- u32 max_width;
u32 res_x; /* TS resolution unit*/
u32 res_y;
u32 swap_xy;
u8 nfingers;
- u32 irq_gpio;
- int resout_gpio;
bool wakeup;
- u32 irq_cfg;
};
static struct rm31100_ts_data devices[] = {
@@ -101,11 +86,26 @@ static struct rm31100_ts_data devices[] = {
.touch_meta_data = 1,
.finger_size = 70,
},
+ [1] = {
+ .x_index = 2,
+ .y_index = 4,
+ .z_index = 6,
+ .id_index = 1,
+ .data_reg = 0x0,
+ .status_reg = 0,
+ .update_data = 0x0,
+ .touch_bytes = 6,
+ .touch_meta_data = 1,
+ .finger_size = 70,
+ },
};
struct rm31100_ts {
struct i2c_client *client;
struct input_dev *input;
+ struct regulator *dvdd;
+ struct regulator *avdd;
+ struct gpio_desc *resout_gpio;
struct rm3110x_ts_platform_data *pdata;
struct rm31100_ts_data *dd;
u8 *touch_data;
@@ -115,9 +115,10 @@ struct rm31100_ts {
bool int_pending;
struct mutex access_lock;
u32 pen_irq;
+ u8 fw_version;
+ u8 u8_sub_version;
};
-struct rm31100_ts *pts;
/*
static inline u16 join_bytes(u8 a, u8 b)
{
@@ -168,19 +169,6 @@ static int rm31100_ts_read(struct i2c_client *client, u8 reg, u8 *buf, int num)
return i2c_transfer(client->adapter, xfer_msg, 2);
}
-static int
-rm31100_ts_write_client_dma(struct i2c_client *client, u8 *buf, int num)
-{
- struct i2c_msg xfer_msg[1];
-
- xfer_msg[0].addr = I2C_DMA_CLIENT_ADDR;
- xfer_msg[0].len = num;
- xfer_msg[0].flags = 0;
- xfer_msg[0].buf = buf;
-
- return i2c_transfer(client->adapter, xfer_msg, 1);
-}
-
static int rm31100_ts_write(struct i2c_client *client, u8 *buf, int num)
{
struct i2c_msg xfer_msg[1];
@@ -192,119 +180,27 @@ static int rm31100_ts_write(struct i2c_client *client, u8 *buf, int num)
return i2c_transfer(client->adapter, xfer_msg, 1);
}
-#ifdef CONFIG_MISC_DEV
-static int dev_open(struct inode *inode, struct file *filp)
-{
- mutex_lock(&pts->access_lock);
- return 0;
-}
-static int dev_release(struct inode *inode, struct file *filp)
+static ssize_t rm_fw_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- mutex_unlock(&pts->access_lock);
- return 0;
-}
-static ssize_t
-dev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
-{
- u8 *kbuf;
- struct i2c_msg xfer_msg;
- /*static char out[] = "1234567890";*/
- /*static int idx;*//*= 0; remove by checkpatch*/
- int i;
-
- kbuf = kmalloc(count, GFP_KERNEL);
- if (kbuf == NULL)
- return -ENOMEM;
-
- /*xfer_msg.addr = pts->client->addr;*/
- xfer_msg.addr = I2C_CLIENT_ADDR;
- xfer_msg.len = count;
- xfer_msg.flags = I2C_M_RD;
- xfer_msg.buf = kbuf;
-
- i2c_transfer(pts->client->adapter, &xfer_msg, 1);
-
- if (copy_to_user(buf, kbuf, count) == 0)
- return count;
- else
- return -EFAULT;
+ struct rm31100_ts *info = dev_get_drvdata(dev);
+ return sprintf(buf, "Release V 0x%02X, Test V 0x%02X\n",
+ info.u8_version,
+ info.u8_sub_version);
}
-static ssize_t
-dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
-{
- u8 *kbuf;
- ssize_t status = 0;
- int i;
-
- kbuf = kmalloc(count, GFP_KERNEL);
- if (kbuf == NULL) {
- dev_err("kmalloc() fail\n");
- return -ENOMEM;
- }
-
- if (copy_from_user(kbuf, buf, count) == 0) {
- pts->client->addr = I2C_CLIENT_ADDR;
- if (rm31100_ts_write(pts->client, kbuf, count) < 0)
- status = -EFAULT;
- else
- status = count;
- } else {
- dev_err("copy_from_user() fail\n");
- status = -EFAULT;
- }
-
- kfree(kbuf);
- return status;
-}
+static DEVICE_ATTR(fw_version, S_IRUGO, rm_fw_version_show, NULL);
-static const struct file_operations dev_fops = {
- .owner = THIS_MODULE,
- .open = dev_open,
- .release = dev_release,
- .read = dev_read,
- .write = dev_write,
- /*.unlocked_ioctl = dev_ioctl,*/
+static struct attribute *rm_ts_attributes[] = {
+ &dev_attr_fw_version.attr,
+ NULL
};
-static struct miscdevice raydium_ts_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "raydium_ts",
- .fops = &dev_fops,
+static const struct attribute_group rm_ts_attr_group = {
+ .attrs = rm_ts_attributes,
};
-#endif
-
-
-ssize_t show(struct device_driver *drv, char *buff)
-{
- struct i2c_msg xfer_msg;
- int num = 10;
- char buf[100];
- /*int i;*/
-
- xfer_msg.addr = pts->client->addr;
- xfer_msg.len = num;
- xfer_msg.flags = I2C_M_RD;
- xfer_msg.buf = buf;
- pts->client->addr = I2C_CLIENT_ADDR;
- i2c_transfer(pts->client->adapter, &xfer_msg, 1);
-
- return 0;
-}
-
-ssize_t store(struct device_driver *drv, const char *buf, size_t count)
-{
- /*unsigned char pkt[] = { 0xF2, 5, 1, 1 };*/
- unsigned char pkt[] = { 0xF1, 5, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
-
- pts->client->addr = I2C_CLIENT_ADDR;
- rm31100_ts_write(pts->client, pkt, sizeof(pkt));
-
- return sizeof(pkt);
-}
-
-DRIVER_ATTR(myAttr, 0x777, show, store);
static void report_data(struct rm31100_ts *dev, u16 x, u16 y,
u8 pressure, u8 id)
@@ -319,10 +215,6 @@ static void report_data(struct rm31100_ts *dev, u16 x, u16 y,
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, dev->dd->finger_size);
-/*
- dev_dbg("%s(): id =%2hhd, x =%4hd, y =%4hd, pressure = %hhd\n",
- __func__, id, x, y, pressure);
-*/
}
static void process_rm31100_data(struct rm31100_ts *ts)
@@ -348,32 +240,18 @@ static void process_rm31100_data(struct rm31100_ts *ts)
input_mt_sync(ts->input);
ts->prev_touches = touches;
- /*input_report_key(ts->input, BTN_TOUCH, 1);*/
+
input_mt_report_pointer_emulation(ts->input, true);
input_sync(ts->input);
}
-/*static void rm31100_ts_xy_worker(struct work_struct *work) JL remove*/
static void rm31100_ts_xy_worker(struct rm31100_ts *work)
{
int rc;
- u8 client_dma_package[4] = {0x0f, 0x00, 0x20, 0x81};
struct rm31100_ts *ts = work;
- if (ts->is_suspended == true) {
- dev_dbg(&ts->client->dev, "TS is supended\n");
- ts->int_pending = true;
- return;
- }
-
mutex_lock(&ts->access_lock);
/* read data from DATA_REG */
- /*RM31100 DMA Mode*/
- rc = rm31100_ts_write_client_dma(ts->client, client_dma_package, 0x04);
- if (rc < 0) {
- dev_err(&ts->client->dev, "write client dma failed\n");
- goto schedule;
- }
rc = rm31100_ts_read(ts->client, ts->dd->data_reg, ts->touch_data,
ts->dd->data_size);
@@ -410,6 +288,61 @@ static irqreturn_t rm31100_ts_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int rm_ts_power_on(struct rm31100_ts *ts)
+{
+ int error;
+
+ /*
+ * If we do not have reset gpio assume platform firmware
+ * controls regulators and does power them on for us.
+ */
+ if (IS_ERR_OR_NULL(ts->resout_gpio))
+ return 0;
+
+ gpiod_set_value_cansleep(ts->resout_gpio, 1);
+
+ error = regulator_enable(ts->avdd);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "failed to enable avdd regulator: %d\n",
+ error);
+ goto release_reset_gpio;
+ }
+
+ error = regulator_enable(ts->dvdd);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "failed to enable dvdd regulator: %d\n",
+ error);
+ regulator_disable(ts->dvdd);
+ goto release_reset_gpio;
+ }
+
+release_reset_gpio:
+ gpiod_set_value_cansleep(ts->resout_gpio, 0);
+ if (error)
+ return error;
+
+ msleep(20);
+
+ return 0;
+}
+
+static void rm_ts_power_off(void *_data)
+{
+ struct rm31100_ts *data = _data;
+
+ if (!IS_ERR_OR_NULL(data->resout_gpio)) {
+ /*
+ * Activate reset gpio to prevent leakage through the
+ * pin once we shut off power to the controller.
+ */
+ gpiod_set_value_cansleep(data->resout_gpio, 1);
+ regulator_disable(data->avdd);
+ regulator_disable(data->dvdd);
+ }
+}
+
static int rm31100_ts_init_ts(struct i2c_client *client, struct rm31100_ts *ts)
{
/*struct input_dev *input_device;*/
@@ -453,8 +386,7 @@ static int rm31100_ts_init_ts(struct i2c_client *client, struct rm31100_ts *ts)
return 0;
}
-#ifdef CONFIG_PM
-static int rm31100_ts_suspend(struct device *dev)
+static int __maybe_unused rm31100_ts_suspend(struct device *dev)
{
struct rm31100_ts *ts = dev_get_drvdata(dev);
int rc = 0;
@@ -467,19 +399,14 @@ static int rm31100_ts_suspend(struct device *dev)
disable_irq(ts->pen_irq);
- gpio_free(ts->pdata->irq_gpio);
+ gpiod_set_value_cansleep(ts->resout_gpio, 0);
+
+ rm_ts_power_off(ts);
- if (ts->pdata->power_on) {
- rc = ts->pdata->power_on(0);
- if (rc) {
- dev_err(dev, "unable to goto suspend\n");
- return rc;
- }
- }
return 0;
}
-static int rm31100_ts_resume(struct device *dev)
+static int __maybe_unused rm31100_ts_resume(struct device *dev)
{
struct rm31100_ts *ts = dev_get_drvdata(dev);
@@ -493,12 +420,10 @@ static int rm31100_ts_resume(struct device *dev)
if (ts->int_pending == true)
ts->int_pending = false;
} else {
- if (ts->pdata->power_on) {
- rc = ts->pdata->power_on(1);
- if (rc) {
- dev_err(dev, "unable to resume\n");
- return rc;
- }
+ rc = rm_ts_power_on(ts);
+ if (rc) {
+ dev_err(dev, "unable to resume\n");
+ return rc;
}
enable_irq(ts->pen_irq);
@@ -522,11 +447,15 @@ static int rm31100_ts_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops rm31100_ts_pm_ops = {
- .suspend = rm31100_ts_suspend,
- .resume = rm31100_ts_resume,
-};
-#endif
+static void rm_ts_remove_sysfs_group(void *_data)
+{
+ struct rm31100_ts *ts = _data;
+
+ sysfs_remove_group(&ts->client->dev.kobj, &rm_ts_attr_group);
+}
+
+static SIMPLE_DEV_PM_OPS(rm31100_ts_pm_ops,
+ rm31100_ts_suspend, rm31100_ts_resume);
static int rm_input_dev_create(struct rm31100_ts *ts)
{
@@ -546,17 +475,26 @@ static int rm_input_dev_create(struct rm31100_ts *ts)
input_device->dev.parent = &ts->client->dev;
input_set_drvdata(input_device, ts);
- __set_bit(EV_ABS, input_device->evbit);
- __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
__set_bit(BTN_TOUCH, input_device->keybit);
+ __set_bit(EV_ABS, input_device->evbit);
+ __set_bit(EV_KEY, input_device->evbit);
+
+ /* For single touch */
+ input_set_abs_params(input_device, ABS_X,
+ ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
+ input_set_abs_params(input_device, ABS_Y,
+ ts->pdata->dis_min_x, ts->pdata->dis_max_y, 0, 0);
+ input_set_abs_params(input_device, ABS_PRESSURE,
+ 0, 255, 0, 0);
+ input_abs_set_res(input_device, ABS_X, ts->pdata->res_x);
+ input_abs_set_res(input_device, ABS_Y, ts->pdata->res_y);
+
+ /* Multitouch input params setup */
+ rc = input_mt_init_slots(input_device,
+ MAX_REPORT_TOUCHED_POINTS, INPUT_MT_DIRECT);
+ if (rc)
+ goto error_unreg_device;
-
- if (ts->device_id == rm31100) {
- /* set up virtual key */
- __set_bit(EV_KEY, input_device->evbit);
- }
- input_mt_init_slots(input_device,
- MAX_REPORT_TOUCHED_POINTS, 0);
input_set_abs_params(input_device, ABS_MT_POSITION_X,
ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
input_set_abs_params(input_device, ABS_MT_POSITION_Y,
@@ -565,6 +503,9 @@ static int rm_input_dev_create(struct rm31100_ts *ts)
0, 0xFF, 0, 0);
input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
0, 0xFF, 0, 0);
+ input_abs_set_res(input_device, ABS_MT_POSITION_X, ts->pdata->res_x);
+ input_abs_set_res(input_device, ABS_MT_POSITION_Y, ts->pdata->res_y);
+
rc = input_register_device(input_device);
if (rc)
goto error_unreg_device;
@@ -581,15 +522,7 @@ error_alloc_dev:
static int rm31100_initialize(struct i2c_client *client)
{
struct rm31100_ts *ts = i2c_get_clientdata(client);
- int rc = 0, /*retry_cnt = 0,*/ temp_reg;
- /* power on the device */
- if (ts->pdata->power_on) {
- rc = ts->pdata->power_on(1);
- if (rc) {
- pr_err("%s: Unable to power on the device\n", __func__);
- goto error_dev_setup;
- }
- }
+ int rc = 0, temp_reg;
/* read one byte to make sure i2c device exists */
if (ts->device_id == rm3110x)
@@ -602,190 +535,186 @@ static int rm31100_initialize(struct i2c_client *client)
rc = rm31100_ts_read_reg_u8(client, temp_reg);
if (rc < 0) {
dev_err(&client->dev, "i2c sanity check failed\n");
- goto error_power_on;
+ return rc;
}
rc = rm31100_ts_init_ts(client, ts);
if (rc < 0) {
dev_err(&client->dev, "rm31100_ts init failed\n");
- goto error_mutex_destroy;
- }
-
- /* configure touchscreen reset out gpio */
- rc = gpio_request(ts->pdata->resout_gpio, "rm31100_resout_gpio");
- if (rc) {
- pr_err("%s: unable to request gpio %d\n",
- __func__, ts->pdata->resout_gpio);
- goto error_uninit_ts;
- }
-
- rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
- if (rc) {
- pr_err("%s: unable to set direction for gpio %d\n",
- __func__, ts->pdata->resout_gpio);
- goto error_resout_gpio_dir;
+ return rc;
}
- /* reset gpio stabilization time */
- msleep(20);
return 0;
-error_resout_gpio_dir:
- if (ts->pdata->resout_gpio >= 0)
- gpio_free(ts->pdata->resout_gpio);
-error_uninit_ts:
- input_unregister_device(ts->input);
- kfree(ts->touch_data);
-error_mutex_destroy:
- mutex_destroy(&ts->access_lock);
-error_power_on:
- if (ts->pdata->power_on)
- ts->pdata->power_on(0);
-error_dev_setup:
- if (ts->pdata->dev_setup)
- ts->pdata->dev_setup(0);
- return rc;
}
-static void rm_initialize_async(void *data, async_cookie_t cookie)
+static int rm31100_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct rm31100_ts *ts = data;
- struct i2c_client *client = ts->client;
- unsigned long irqflags;
- int err = 0;
-
- mutex_lock(&ts->access_lock);
+ struct rm31100_ts *ts;
+ struct rm3110x_ts_platform_data *pdata = client->dev.platform_data;
+ int rc;
+ union i2c_smbus_data dummy;
- err = rm31100_initialize(client);
- if (err < 0) {
- dev_err(&client->dev, "probe failed! unbind device.\n");
- goto error_free_mem;
+ ts = devm_kzalloc(&client->dev, sizeof(struct rm31100_ts), GFP_KERNEL);
+ if (!ts) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
}
- err = rm_input_dev_create(ts);
- if (err) {
- dev_err(&client->dev, "%s crated failed, %d\n", __func__, err);
- goto error_goio_release;
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ dev_err(&client->dev, "I2C functionality not supported\n");
+ rc = -EIO;
+ goto error_touch_data_alloc;
}
- irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING;
+ ts->client = client;
+ ts->pdata = pdata;
+ i2c_set_clientdata(client, ts);
+ ts->device_id = id->driver_data;
- err = request_threaded_irq(ts->pen_irq, NULL,
- rm31100_ts_irq,
- irqflags | IRQF_ONESHOT,
- ts->client->dev.driver->name, ts);
- if (err) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- goto error_dev_release;
- }
+ ts->is_suspended = false;
+ ts->int_pending = false;
- mutex_unlock(&ts->access_lock);
+ mutex_init(&ts->access_lock);
- return;
+ ts->avdd = devm_regulator_get(&client->dev, "avdd");
+ if (IS_ERR(ts->avdd)) {
+ rc = PTR_ERR(ts->avdd);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&client->dev,
+ "Failed to get 'avdd' regulator: %d\n",
+ rc);
+ return rc;
+ }
-error_dev_release:
- input_free_device(ts->input);
-error_goio_release:
- if (ts->pdata->resout_gpio >= 0)
- gpio_free(ts->pdata->resout_gpio);
-error_free_mem:
- mutex_unlock(&ts->access_lock);
- kfree(ts);
- return;
-}
+ ts->dvdd = devm_regulator_get(&client->dev, "dvdd");
+ if (IS_ERR(ts->dvdd)) {
+ rc = PTR_ERR(ts->dvdd);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&client->dev,
+ "Failed to get 'dvdd' regulator: %d\n",
+ rc);
+ return rc;
+ }
+
+ ts->resout_gpio = devm_gpiod_get(&client->dev, "rm31100_resout_gpio");
+ if (IS_ERR(ts->resout_gpio)) {
+ rc = PTR_ERR(ts->resout_gpio);
+
+ /*
+ * On Chromebooks vendors like to source touch panels from
+ * different vendors, but they are connected to the same
+ * regulators/GPIO pin. The drivers also use asynchronous
+ * probing, which means that more than one driver will
+ * attempt to claim the reset line. If we find it busy,
+ * let's try again later.
+ */
+ if (rc == -EBUSY) {
+ dev_info(&client->dev,
+ "reset gpio is busy, deferring probe\n");
+ return -EPROBE_DEFER;
+ }
+ if (rc == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
-/*static int __devinit rm31100_ts_probe(struct i2c_client *client,
- const struct i2c_device_id *id)*/
-static int rm31100_ts_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct rm31100_ts *ts;
- struct rm3110x_ts_platform_data *pdata = client->dev.platform_data;
- int rc/*, temp_reg*/;
- union i2c_smbus_data dummy;
+ if (rc != -ENOENT && rc != -ENOSYS) {
+ dev_err(&client->dev,
+ "failed to get reset gpio: %d\n",
+ rc);
+ return rc;
+ }
- if (!pdata) {
- dev_err(&client->dev, "platform data is required!\n");
- return -EINVAL;
+ } else {
+ rc = gpiod_direction_output(ts->resout_gpio, 0);
+ if (rc) {
+ dev_err(&client->dev,
+ "failed to configure reset gpio as output: %d\n",
+ rc);
+ return rc;
+ }
}
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_WORD_DATA)) {
- dev_err(&client->dev, "I2C functionality not supported\n");
- return -EIO;
+ rc = rm_ts_power_on(ts);
+ if (rc)
+ return rc;
+
+ rc = devm_add_action(&client->dev, rm_ts_power_off, ts);
+ if (rc) {
+ dev_err(&client->dev,
+ "failed to install power off action: %d\n", rc);
+ rm_ts_power_off(ts);
+ return rc;
}
+
/* Make sure there is something at this address */
if (i2c_smbus_xfer(client->adapter, client->addr, 0,
I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
return -ENODEV;
- ts = kzalloc(sizeof(*ts), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
- pts = ts;
-
- /* Enable runtime PM ops, start in ACTIVE mode */
- rc = pm_runtime_set_active(&client->dev);
- if (rc < 0)
- dev_warn(&client->dev, "unable to set runtime pm state\n");
- pm_runtime_enable(&client->dev);
-
- ts->client = client;
- ts->pdata = pdata;
- i2c_set_clientdata(client, ts);
- ts->device_id = id->driver_data;
+ rc = rm31100_initialize(client);
+ if (rc < 0) {
+ dev_err(&client->dev, "probe failed! unbind device.\n");
+ return rc;
+ }
- if (ts->pdata->dev_setup) {
- rc = ts->pdata->dev_setup(1);
- if (rc < 0) {
- dev_err(&client->dev, "dev setup failed\n");
- goto error_touch_data_alloc;
- }
+ rc = rm_input_dev_create(ts);
+ if (rc) {
+ dev_err(&client->dev, "%s crated failed, %d\n", __func__, err);
+ return rc;
}
+ rc = devm_request_threaded_irq(&client->dev, ts->pen_irq,
+ NULL, rm31100_ts_irq,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ client->name, ts);
+ if (rc) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ return rc;
+ }
- ts->is_suspended = false;
- ts->int_pending = false;
- /*mutex_init(&ts->sus_lock); JL remove*/
- mutex_init(&ts->access_lock);
+ device_set_wakeup_enable(&client->dev, false);
- async_schedule(rm_initialize_async, ts);
+ rc = sysfs_create_group(&client->dev.kobj, &rm_ts_attr_group);
+ if (rc) {
+ dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
+ rc);
+ return rc;
+ }
- device_init_wakeup(&client->dev, ts->pdata->wakeup);
+ rc = devm_add_action(&client->dev,
+ rm_ts_remove_sysfs_group, ts);
+ if (rc) {
+ rm_ts_remove_sysfs_group(ts);
+ dev_err(&client->dev,
+ "Failed to add sysfs cleanup action: %d\n",
+ rc);
+ return rc;
+ }
return 0;
error_touch_data_alloc:
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_disable(&client->dev);
kfree(ts);
return rc;
}
-/*static int __devexit RM31100_ts_remove(struct i2c_client *client)*/
static int rm31100_ts_remove(struct i2c_client *client)
{
struct rm31100_ts *ts = i2c_get_clientdata(client);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_disable(&client->dev);
-
device_init_wakeup(&client->dev, 0);
free_irq(ts->pen_irq, ts);
- gpio_free(ts->pdata->irq_gpio);
+ if (ts->resout_gpio >= 0)
+ gpiod_set_value_cansleep(ts->resout_gpio, 0);
- if (ts->pdata->resout_gpio >= 0)
- gpio_free(ts->pdata->resout_gpio);
input_unregister_device(ts->input);
/*mutex_destroy(&ts->sus_lock); JL remove*/
mutex_destroy(&ts->access_lock);
- if (ts->pdata->power_on)
- ts->pdata->power_on(0);
-
- if (ts->pdata->dev_setup)
- ts->pdata->dev_setup(0);
+ rm_ts_power_off(ts);
kfree(ts->touch_data);
kfree(ts);
--
2.1.2
Powered by blists - more mailing lists