blob: a6ec6eb2130722e303982a9fb961debed14ec663 [file] [log] [blame] [edit]
/*
* mms_ts.c - Touchscreen driver for Melfas MMS-series touch controllers
*
* Copyright (C) 2011 Google Inc.
* Author: Dima Zavin <[email protected]>
* Simon Wilson <[email protected]>
*
* ISP reflashing code based on original code from Melfas.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
//#define DEBUG
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/platform_data/mms_ts.h>
#include <asm/unaligned.h>
#define MAX_FINGERS 10
#define MAX_WIDTH 30
#define MAX_PRESSURE 255
/* Registers */
#define MMS_MODE_CONTROL 0x01
#define MMS_XYRES_HI 0x02
#define MMS_XRES_LO 0x03
#define MMS_YRES_LO 0x04
#define MMS_INPUT_EVENT_PKT_SZ 0x0F
#define MMS_INPUT_EVENT0 0x10
#define FINGER_EVENT_SZ 6
#define MMS_TSP_REVISION 0xF0
#define MMS_HW_REVISION 0xF1
#define MMS_COMPAT_GROUP 0xF2
#define MMS_FW_VERSION 0xF3
enum {
ISP_MODE_FLASH_ERASE = 0x59F3,
ISP_MODE_FLASH_WRITE = 0x62CD,
ISP_MODE_FLASH_READ = 0x6AC9,
};
/* each address addresses 4-byte words */
#define ISP_MAX_FW_SIZE (0x1F00 * 4)
#define ISP_IC_INFO_ADDR 0x1F00
static bool mms_force_reflash = false;
module_param_named(force_reflash, mms_force_reflash, bool, S_IWUSR | S_IRUGO);
static bool mms_flash_from_probe;
module_param_named(flash_from_probe, mms_flash_from_probe, bool,
S_IWUSR | S_IRUGO);
static bool mms_die_on_flash_fail = true;
module_param_named(die_on_flash_fail, mms_die_on_flash_fail, bool,
S_IWUSR | S_IRUGO);
struct mms_ts_info {
struct i2c_client *client;
struct input_dev *input_dev;
char phys[32];
int max_x;
int max_y;
bool invert_x;
bool invert_y;
int irq;
struct mms_ts_platform_data *pdata;
char *fw_name;
struct completion init_done;
struct early_suspend early_suspend;
/* protects the enabled flag */
struct mutex lock;
bool enabled;
};
struct mms_fw_image {
__le32 hdr_len;
__le32 data_len;
__le32 fw_ver;
__le32 hdr_ver;
u8 data[0];
} __attribute__ ((packed));
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mms_ts_early_suspend(struct early_suspend *h);
static void mms_ts_late_resume(struct early_suspend *h);
#endif
static irqreturn_t mms_ts_interrupt(int irq, void *dev_id)
{
struct mms_ts_info *info = dev_id;
struct i2c_client *client = info->client;
u8 buf[MAX_FINGERS*FINGER_EVENT_SZ] = { 0 };
int ret;
int i;
int sz;
u8 reg = MMS_INPUT_EVENT0;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.buf = &reg,
.len = 1,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.buf = buf,
},
};
sz = i2c_smbus_read_byte_data(client, MMS_INPUT_EVENT_PKT_SZ);
if (sz < 0) {
dev_err(&client->dev, "%s bytes=%d\n", __func__, sz);
goto out;
}
dev_dbg(&client->dev, "bytes available: %d\n", sz);
BUG_ON(sz > MAX_FINGERS*FINGER_EVENT_SZ);
if (sz == 0)
goto out;
msg[1].len = sz;
ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
if (ret != ARRAY_SIZE(msg)) {
dev_err(&client->dev,
"failed to read %d bytes of touch data (%d)\n",
sz, ret);
goto out;
}
#if defined(VERBOSE_DEBUG)
print_hex_dump(KERN_DEBUG, "mms_ts raw: ",
DUMP_PREFIX_OFFSET, 32, 1, buf, sz, false);
#endif
for (i = 0; i < sz; i += FINGER_EVENT_SZ) {
u8 *tmp = &buf[i];
int id = (tmp[0] & 0xf) - 1;
int x = tmp[2] | ((tmp[1] & 0xf) << 8);
int y = tmp[3] | (((tmp[1] >> 4) & 0xf) << 8);
if (info->invert_x) {
x = info->max_x - x;
if (x < 0)
x = 0;
}
if (info->invert_y) {
y = info->max_y - y;
if (y < 0)
y = 0;
}
if ((tmp[0] & 0x80) == 0) {
dev_dbg(&client->dev, "finger %d up\n", id);
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, false);
continue;
}
input_mt_slot(info->input_dev, id);
input_mt_report_slot_state(info->input_dev,
MT_TOOL_FINGER, true);
input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, tmp[4]);
input_report_abs(info->input_dev, ABS_MT_PRESSURE, tmp[5]);
input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
dev_dbg(&client->dev,
"finger %d: x=%d y=%d p=%d w=%d\n", id, x, y, tmp[5],
tmp[4]);
}
input_sync(info->input_dev);
out:
return IRQ_HANDLED;
}
static void hw_reboot(struct mms_ts_info *info, bool bootloader)
{
gpio_direction_output(info->pdata->gpio_vdd_en, 0);
gpio_direction_output(info->pdata->gpio_sda, bootloader ? 0 : 1);
gpio_direction_output(info->pdata->gpio_scl, bootloader ? 0 : 1);
gpio_direction_output(info->pdata->gpio_resetb, 0);
msleep(30);
gpio_set_value(info->pdata->gpio_vdd_en, 1);
msleep(30);
if (bootloader) {
gpio_set_value(info->pdata->gpio_scl, 0);
gpio_set_value(info->pdata->gpio_sda, 1);
} else {
gpio_set_value(info->pdata->gpio_resetb, 1);
gpio_direction_input(info->pdata->gpio_resetb);
gpio_direction_input(info->pdata->gpio_scl);
gpio_direction_input(info->pdata->gpio_sda);
}
msleep(40);
}
static inline void hw_reboot_bootloader(struct mms_ts_info *info)
{
hw_reboot(info, true);
}
static inline void hw_reboot_normal(struct mms_ts_info *info)
{
hw_reboot(info, false);
}
static inline void mms_pwr_on_reset(struct mms_ts_info *info)
{
struct i2c_adapter *adapter = to_i2c_adapter(info->client->dev.parent);
if (!info->pdata->mux_fw_flash) {
dev_info(&info->client->dev,
"missing platform data, can't do power-on-reset\n");
return;
}
i2c_lock_adapter(adapter);
info->pdata->mux_fw_flash(true);
gpio_direction_output(info->pdata->gpio_vdd_en, 0);
gpio_direction_output(info->pdata->gpio_sda, 1);
gpio_direction_output(info->pdata->gpio_scl, 1);
gpio_direction_output(info->pdata->gpio_resetb, 1);
msleep(50);
gpio_direction_output(info->pdata->gpio_vdd_en, 1);
msleep(50);
info->pdata->mux_fw_flash(false);
i2c_unlock_adapter(adapter);
/* TODO: Seems long enough for the firmware to boot.
* Find the right value */
msleep(250);
}
static void isp_toggle_clk(struct mms_ts_info *info, int start_lvl, int end_lvl,
int hold_us)
{
gpio_set_value(info->pdata->gpio_scl, start_lvl);
udelay(hold_us);
gpio_set_value(info->pdata->gpio_scl, end_lvl);
udelay(hold_us);
}
/* 1 <= cnt <= 32 bits to write */
static void isp_send_bits(struct mms_ts_info *info, u32 data, int cnt)
{
gpio_direction_output(info->pdata->gpio_resetb, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 0);
/* clock out the bits, msb first */
while (cnt--) {
gpio_set_value(info->pdata->gpio_sda, (data >> cnt) & 1);
udelay(3);
isp_toggle_clk(info, 1, 0, 3);
}
}
/* 1 <= cnt <= 32 bits to read */
static u32 isp_recv_bits(struct mms_ts_info *info, int cnt)
{
u32 data = 0;
gpio_direction_output(info->pdata->gpio_resetb, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_set_value(info->pdata->gpio_sda, 0);
gpio_direction_input(info->pdata->gpio_sda);
/* clock in the bits, msb first */
while (cnt--) {
isp_toggle_clk(info, 0, 1, 1);
data = (data << 1) | (!!gpio_get_value(info->pdata->gpio_sda));
}
gpio_direction_output(info->pdata->gpio_sda, 0);
return data;
}
static void isp_enter_mode(struct mms_ts_info *info, u32 mode)
{
int cnt;
unsigned long flags;
local_irq_save(flags);
gpio_direction_output(info->pdata->gpio_resetb, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 1);
mode &= 0xffff;
for (cnt = 15; cnt >= 0; cnt--) {
gpio_set_value(info->pdata->gpio_resetb, (mode >> cnt) & 1);
udelay(3);
isp_toggle_clk(info, 1, 0, 3);
}
gpio_set_value(info->pdata->gpio_resetb, 0);
local_irq_restore(flags);
}
static void isp_exit_mode(struct mms_ts_info *info)
{
int i;
unsigned long flags;
local_irq_save(flags);
gpio_direction_output(info->pdata->gpio_resetb, 0);
udelay(3);
for (i = 0; i < 10; i++)
isp_toggle_clk(info, 1, 0, 3);
local_irq_restore(flags);
}
static void flash_set_address(struct mms_ts_info *info, u16 addr)
{
/* Only 13 bits of addr are valid.
* The addr is in bits 13:1 of cmd */
isp_send_bits(info, (u32)(addr & 0x1fff) << 1, 18);
}
static void flash_erase(struct mms_ts_info *info)
{
isp_enter_mode(info, ISP_MODE_FLASH_ERASE);
gpio_direction_output(info->pdata->gpio_resetb, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 1);
/* 4 clock cycles with different timings for the erase to
* get processed, clk is already 0 from above */
udelay(7);
isp_toggle_clk(info, 1, 0, 3);
udelay(7);
isp_toggle_clk(info, 1, 0, 3);
usleep_range(25000, 35000);
isp_toggle_clk(info, 1, 0, 3);
usleep_range(150, 200);
isp_toggle_clk(info, 1, 0, 3);
gpio_set_value(info->pdata->gpio_sda, 0);
isp_exit_mode(info);
}
static u32 flash_readl(struct mms_ts_info *info, u16 addr)
{
int i;
u32 val;
unsigned long flags;
local_irq_save(flags);
isp_enter_mode(info, ISP_MODE_FLASH_READ);
flash_set_address(info, addr);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_sda, 0);
udelay(40);
/* data load cycle */
for (i = 0; i < 6; i++)
isp_toggle_clk(info, 1, 0, 10);
val = isp_recv_bits(info, 32);
isp_exit_mode(info);
local_irq_restore(flags);
return val;
}
static void flash_writel(struct mms_ts_info *info, u16 addr, u32 val)
{
unsigned long flags;
local_irq_save(flags);
isp_enter_mode(info, ISP_MODE_FLASH_WRITE);
flash_set_address(info, addr);
isp_send_bits(info, val, 32);
gpio_direction_output(info->pdata->gpio_sda, 1);
/* 6 clock cycles with different timings for the data to get written
* into flash */
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 6);
isp_toggle_clk(info, 0, 1, 12);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 0, 1, 3);
isp_toggle_clk(info, 1, 0, 1);
gpio_direction_output(info->pdata->gpio_sda, 0);
isp_exit_mode(info);
local_irq_restore(flags);
usleep_range(300, 400);
}
static bool flash_is_erased(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
u32 val;
u16 addr;
for (addr = 0; addr < (ISP_MAX_FW_SIZE / 4); addr++) {
udelay(40);
val = flash_readl(info, addr);
if (val != 0xffffffff) {
dev_dbg(&client->dev,
"addr 0x%x not erased: 0x%08x != 0xffffffff\n",
addr, val);
return false;
}
}
return true;
}
static int fw_write_image(struct mms_ts_info *info, const u8 *data, size_t len)
{
struct i2c_client *client = info->client;
u16 addr = 0;
for (addr = 0; addr < (len / 4); addr++, data += 4) {
u32 val = get_unaligned_le32(data);
u32 verify_val;
int retries = 3;
while (retries--) {
flash_writel(info, addr, val);
verify_val = flash_readl(info, addr);
if (val == verify_val)
break;
dev_err(&client->dev,
"mismatch @ addr 0x%x: 0x%x != 0x%x\n",
addr, verify_val, val);
hw_reboot_bootloader(info);
continue;
}
if (retries < 0)
return -ENXIO;
}
return 0;
}
static int fw_download(struct mms_ts_info *info, const u8 *data, size_t len)
{
struct i2c_client *client = info->client;
u32 val;
int ret = 0;
if (len % 4) {
dev_err(&client->dev,
"fw image size (%d) must be a multiple of 4 bytes\n",
len);
return -EINVAL;
} else if (len > ISP_MAX_FW_SIZE) {
dev_err(&client->dev,
"fw image is too big, %d > %d\n", len, ISP_MAX_FW_SIZE);
return -EINVAL;
}
dev_info(&client->dev, "fw download start\n");
gpio_direction_output(info->pdata->gpio_vdd_en, 0);
gpio_direction_output(info->pdata->gpio_sda, 0);
gpio_direction_output(info->pdata->gpio_scl, 0);
gpio_direction_output(info->pdata->gpio_resetb, 0);
hw_reboot_bootloader(info);
val = flash_readl(info, ISP_IC_INFO_ADDR);
dev_info(&client->dev, "IC info: 0x%02x (%x)\n", val & 0xff, val);
dev_info(&client->dev, "fw erase...\n");
flash_erase(info);
if (!flash_is_erased(info)) {
ret = -ENXIO;
goto err;
}
dev_info(&client->dev, "fw write...\n");
/* XXX: what does this do?! */
flash_writel(info, ISP_IC_INFO_ADDR, 0xffffff00 | (val & 0xff));
usleep_range(1000, 1500);
ret = fw_write_image(info, data, len);
if (ret)
goto err;
usleep_range(1000, 1500);
hw_reboot_normal(info);
usleep_range(1000, 1500);
dev_info(&client->dev, "fw download done...\n");
return 0;
err:
dev_err(&client->dev, "fw download failed...\n");
hw_reboot_normal(info);
return ret;
}
static int get_fw_version(struct mms_ts_info *info)
{
int ret;
int retries = 3;
/* this seems to fail sometimes after a reset.. retry a few times */
do {
ret = i2c_smbus_read_byte_data(info->client, MMS_FW_VERSION);
} while (ret < 0 && retries-- > 0);
return ret;
}
static int mms_ts_enable(struct mms_ts_info *info)
{
mutex_lock(&info->lock);
if (info->enabled)
goto out;
/* wake up the touch controller. */
i2c_smbus_write_byte_data(info->client, 0, 0);
usleep_range(3000, 5000);
info->enabled = true;
enable_irq(info->irq);
out:
mutex_unlock(&info->lock);
return 0;
}
static int mms_ts_disable(struct mms_ts_info *info)
{
mutex_lock(&info->lock);
if (!info->enabled)
goto out;
disable_irq(info->irq);
i2c_smbus_write_byte_data(info->client, MMS_MODE_CONTROL, 0);
usleep_range(10000, 12000);
info->enabled = false;
out:
mutex_unlock(&info->lock);
return 0;
}
static int mms_ts_input_open(struct input_dev *dev)
{
struct mms_ts_info *info = input_get_drvdata(dev);
int ret;
ret = wait_for_completion_interruptible_timeout(&info->init_done,
msecs_to_jiffies(90 * MSEC_PER_SEC));
if (ret > 0) {
if (info->irq != -1)
ret = mms_ts_enable(info);
else
ret = -ENXIO;
} else if (ret < 0) {
dev_err(&dev->dev,
"error while waiting for device to init (%d)\n", ret);
ret = -ENXIO;
} else if (ret == 0) {
dev_err(&dev->dev,
"timedout while waiting for device to init\n");
ret = -ENXIO;
}
return ret;
}
static void mms_ts_input_close(struct input_dev *dev)
{
struct mms_ts_info *info = input_get_drvdata(dev);
mms_ts_disable(info);
}
static int mms_ts_finish_config(struct mms_ts_info *info)
{
struct i2c_client *client = info->client;
int ret;
ret = request_threaded_irq(client->irq, NULL, mms_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"mms_ts", info);
if (ret < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_req_irq;
}
disable_irq(client->irq);
info->irq = client->irq;
barrier();
dev_info(&client->dev,
"Melfas MMS-series touch controller initialized\n");
complete_all(&info->init_done);
return 0;
err_req_irq:
return ret;
}
static void mms_ts_fw_load(const struct firmware *fw, void *context)
{
struct mms_ts_info *info = context;
struct i2c_client *client = info->client;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int ret = 0;
int ver;
int retries = 3;
struct mms_fw_image *fw_img;
ver = get_fw_version(info);
if (ver < 0) {
ver = 0;
dev_err(&client->dev,
"can't read version, controller dead? forcing reflash");
}
if (!fw) {
dev_info(&client->dev, "could not find firmware file '%s'\n",
info->fw_name);
goto done;
}
fw_img = (struct mms_fw_image *)fw->data;
if (fw_img->hdr_len != sizeof(struct mms_fw_image) ||
fw_img->data_len + fw_img->hdr_len != fw->size ||
fw_img->hdr_ver != 0x1) {
dev_err(&client->dev,
"firmware image '%s' invalid, may continue\n",
info->fw_name);
goto err;
}
if (ver == fw_img->fw_ver && !mms_force_reflash) {
dev_info(&client->dev,
"fw version 0x%02x already present\n", ver);
goto done;
}
dev_info(&client->dev, "need fw update (0x%02x != 0x%02x)\n",
ver, fw_img->fw_ver);
if (!info->pdata || !info->pdata->mux_fw_flash) {
dev_err(&client->dev,
"fw cannot be updated, missing platform data\n");
goto err;
}
while (retries--) {
i2c_lock_adapter(adapter);
info->pdata->mux_fw_flash(true);
ret = fw_download(info, fw_img->data, fw_img->data_len);
info->pdata->mux_fw_flash(false);
i2c_unlock_adapter(adapter);
if (ret < 0) {
dev_err(&client->dev,
"error updating firmware to version 0x%02x\n",
fw_img->fw_ver);
if (retries)
dev_err(&client->dev, "retrying flashing\n");
continue;
}
ver = get_fw_version(info);
if (ver == fw_img->fw_ver) {
dev_info(&client->dev,
"fw update done. ver = 0x%02x\n", ver);
goto done;
} else {
dev_err(&client->dev,
"ERROR: fw update succeeded, but fw version is still wrong (0x%x != 0x%x)\n",
ver, fw_img->fw_ver);
}
if (retries)
dev_err(&client->dev, "retrying flashing\n");
}
dev_err(&client->dev, "could not flash firmware, ran out of retries\n");
BUG_ON(mms_die_on_flash_fail);
err:
/* complete anyway, so open() doesn't get blocked */
complete_all(&info->init_done);
goto out;
done:
mms_ts_finish_config(info);
out:
release_firmware(fw);
}
static int __devinit mms_ts_config(struct mms_ts_info *info, bool nowait)
{
struct i2c_client *client = info->client;
int ret = 0;
const char *filename = info->pdata->fw_name ?: "mms144_ts.fw";
mms_pwr_on_reset(info);
if (nowait) {
const struct firmware *fw;
info->fw_name = kasprintf(GFP_KERNEL, "melfas/%s", filename);
ret = request_firmware(&fw, info->fw_name, &client->dev);
if (ret) {
dev_err(&client->dev,
"error requesting built-in firmware\n");
goto out;
}
mms_ts_fw_load(fw, info);
} else {
info->fw_name = kstrdup(filename, GFP_KERNEL);
ret = request_firmware_nowait(THIS_MODULE, true, info->fw_name,
&client->dev, GFP_KERNEL,
info, mms_ts_fw_load);
if (ret)
dev_err(&client->dev,
"cannot schedule firmware update (%d)\n", ret);
}
out:
return ret;
}
static int __devinit mms_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct mms_ts_info *info;
struct input_dev *input_dev;
int ret = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return -EIO;
info = kzalloc(sizeof(struct mms_ts_info), GFP_KERNEL);
input_dev = input_allocate_device();
if (!info || !input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
goto err_alloc;
}
info->client = client;
info->input_dev = input_dev;
info->pdata = client->dev.platform_data;
init_completion(&info->init_done);
info->irq = -1;
mutex_init(&info->lock);
if (info->pdata) {
info->max_x = info->pdata->max_x;
info->max_y = info->pdata->max_y;
info->invert_x = info->pdata->invert_x;
info->invert_y = info->pdata->invert_y;
} else {
info->max_x = 720;
info->max_y = 1280;
}
input_mt_init_slots(input_dev, MAX_FINGERS);
snprintf(info->phys, sizeof(info->phys),
"%s/input0", dev_name(&client->dev));
input_dev->name = "Melfas MMSxxx Touchscreen";
input_dev->phys = info->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_dev->open = mms_ts_input_open;
input_dev->close = mms_ts_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_WIDTH, 0, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, info->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, info->max_y, 0, 0);
input_set_drvdata(input_dev, info);
ret = input_register_device(input_dev);
if (ret) {
dev_err(&client->dev, "failed to register input dev (%d)\n",
ret);
goto err_reg_input_dev;
}
i2c_set_clientdata(client, info);
ret = mms_ts_config(info, mms_flash_from_probe);
if (ret) {
dev_err(&client->dev, "failed to initialize (%d)\n", ret);
goto err_config;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
info->early_suspend.suspend = mms_ts_early_suspend;
info->early_suspend.resume = mms_ts_late_resume;
register_early_suspend(&info->early_suspend);
#endif
return 0;
err_config:
input_unregister_device(input_dev);
input_dev = NULL;
err_reg_input_dev:
err_alloc:
input_free_device(input_dev);
kfree(info->fw_name);
kfree(info);
return ret;
}
static int __devexit mms_ts_remove(struct i2c_client *client)
{
struct mms_ts_info *info = i2c_get_clientdata(client);
if (info->irq >= 0)
free_irq(info->irq, info);
input_unregister_device(info->input_dev);
kfree(info->fw_name);
kfree(info);
return 0;
}
#if defined(CONFIG_PM) || defined(CONFIG_HAS_EARLYSUSPEND)
static int mms_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms_ts_info *info = i2c_get_clientdata(client);
int i;
/* TODO: turn off the power (set vdd_en to 0) to the touchscreen
* on suspend
*/
mutex_lock(&info->input_dev->mutex);
if (!info->input_dev->users)
goto out;
mms_ts_disable(info);
for (i = 0; i < MAX_FINGERS; i++) {
input_mt_slot(info->input_dev, i);
input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER,
false);
}
input_sync(info->input_dev);
out:
mutex_unlock(&info->input_dev->mutex);
return 0;
}
static int mms_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms_ts_info *info = i2c_get_clientdata(client);
int ret = 0;
mutex_lock(&info->input_dev->mutex);
if (info->input_dev->users)
ret = mms_ts_enable(info);
mutex_unlock(&info->input_dev->mutex);
return ret;
}
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mms_ts_early_suspend(struct early_suspend *h)
{
struct mms_ts_info *info;
info = container_of(h, struct mms_ts_info, early_suspend);
mms_ts_suspend(&info->client->dev);
}
static void mms_ts_late_resume(struct early_suspend *h)
{
struct mms_ts_info *info;
info = container_of(h, struct mms_ts_info, early_suspend);
mms_ts_resume(&info->client->dev);
}
#endif
#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
static const struct dev_pm_ops mms_ts_pm_ops = {
.suspend = mms_ts_suspend,
.resume = mms_ts_resume,
};
#endif
static const struct i2c_device_id mms_ts_id[] = {
{ "mms_ts", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mms_ts_id);
static struct i2c_driver mms_ts_driver = {
.probe = mms_ts_probe,
.remove = __devexit_p(mms_ts_remove),
.driver = {
.name = "mms_ts",
#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
.pm = &mms_ts_pm_ops,
#endif
},
.id_table = mms_ts_id,
};
static int __init mms_ts_init(void)
{
return i2c_add_driver(&mms_ts_driver);
}
static void __exit mms_ts_exit(void)
{
i2c_del_driver(&mms_ts_driver);
}
module_init(mms_ts_init);
module_exit(mms_ts_exit);
/* Module information */
MODULE_DESCRIPTION("Touchscreen driver for Melfas MMS-series controllers");
MODULE_LICENSE("GPL");