blob: bb8512681b0b7dcec2d4d351adb8de794d80dbb2 [file] [log] [blame]
/* drivers/input/misc/ots_pat9126/pat9126_linux_driver.c
*
* Copyright (c) 2016, The Linux Foundation. All rights reserved.
*
*/
#include <linux/input.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include "pat9126.h"
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/string.h>
#include <linux/soc/qcom/panel_event_notifier.h>
#define WAKE_SENSITIVITY 1
#define PIXART_PAT9126_SLOP 13
#define SENSITIVITY_LEN 4 /* range "0" - "255" */
#define DISPLAY_BLANKED 0
#define DISPLAY_UNBLANKED 1
struct pixart_pat9126_data {
struct i2c_client *client;
struct input_dev *input;
int irq;
u32 irq_flags;
struct device *pat9126_device;
u32 press_keycode;
bool press_en;
bool inverse_x;
bool inverse_y;
u32 vdd_active_load;
u32 vld_active_load;
u32 vdd_sleep_load;
u32 vld_sleep_load;
int state;
int display_mode;
u8 crown_sensitivity;
u8 current_sensitivity;
u8 slop;
bool wake_handled;
struct work_struct work;
struct workqueue_struct *workqueue;
struct delayed_work polling_work;
struct delayed_work resume_work;
struct drm_panel *active_panel;
void *notifier_cookie;
struct mutex mtx;
struct regulator *vdd_supply;
struct regulator *vld_supply;
};
#define PAT9126_STATE_SUSPEND 0
#define PAT9126_STATE_ON 1
#define PAT9126_STATE_RESUMING 2
struct rw_reg_info {
char flag; /*R/W char*/
long w_addr;
long r_addr;
long r_data;
};
struct rw_reg_info pat9126_reg_info;
/* Declaration of suspend and resume functions */
static void pat9126_drm_panel_notifier_callback(enum panel_event_notifier_tag tag,
struct panel_event_notification *notification, void *data);
static int pat9126_display_suspend(struct device *dev);
static int pat9126_display_resume(struct device *dev);
static int pat9126_set_loads_active(struct pixart_pat9126_data *data)
{
int ret;
ret = regulator_set_load(data->vdd_supply, data->vdd_active_load);
if (ret) {
pr_err("[PAT9126]: Failed to set vdd regulator load\n");
return ret;
}
ret = regulator_set_load(data->vld_supply, data->vld_active_load);
if (ret) {
pr_err("[PAT9126]: Failed to set vld regulator load\n");
return ret;
}
return 0;
}
static int pat9126_set_loads_sleep(struct pixart_pat9126_data *data)
{
int ret;
ret = regulator_set_load(data->vdd_supply, data->vdd_sleep_load);
if (ret) {
pr_err("[PAT9126]: Failed to set vdd regulator load\n");
return ret;
}
ret = regulator_set_load(data->vld_supply, data->vld_sleep_load);
if (ret) {
pr_err("[PAT9126]: Failed to set vld regulator load\n");
return ret;
}
return 0;
}
static int pat9126_enable_regulators(struct pixart_pat9126_data *data)
{
int ret;
ret = regulator_enable(data->vdd_supply);
if (ret) {
pr_err("[PAT9126]: Failed to enable vdd regulator\n");
return ret;
}
ret = regulator_enable(data->vld_supply);
if (ret) {
pr_err("[PAT9126]: Failed to enable vld regulator\n");
return ret;
}
return 0;
}
static void pat9126_disable_regulators(struct pixart_pat9126_data *data)
{
int ret;
ret = regulator_disable(data->vld_supply);
if (ret) {
pr_err("[PAT9126]: Failed to disable vld regulator\n");
}
ret = regulator_disable(data->vdd_supply);
if (ret) {
pr_err("[PAT9126]: Failed to disable vdd regulator\n");
}
}
static int pat9126_write(struct i2c_client *client, u8 addr, u8 data)
{
u8 buf[BUF_SIZE];
struct device *dev = &client->dev;
buf[0] = addr;
buf[1] = data;
/* Returns negative errno, or else the number of bytes written. */
if (i2c_master_send(client, buf, BUF_SIZE) < 0) {
dev_err(dev, "%s Failed: writing to reg 0x%x\n", __func__, addr);
return -EIO;
}
return 0;
}
static int pat9126_read(struct i2c_client *client, u8 addr, u8 *data)
{
struct device *dev = &client->dev;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &addr,
}, {
.addr = client->addr,
.flags = 1,
.len = 1,
.buf = data,
}
};
if (i2c_transfer(client->adapter, msg, 2) != 2) {
dev_err(dev, "%s Failed: reading reg 0x%x\n", __func__,
addr);
return -EIO;
}
return 0;
}
static int pat9126_write_verified(struct i2c_client *client, u8 address, u8 data)
{
int i, ret;
u8 read_value;
for (i = 0; i < PAT9150_I2C_RETRY; i++) {
ret = pat9126_write(client, address, data);
if (ret < 0)
return ret;
ret = pat9126_read(client, address, &read_value);
if (ret < 0)
return ret;
if (read_value == data)
return 0;
msleep(1);
}
return -EIO;
}
void delay(int ms)
{
msleep(ms);
}
int pat9126_sensor_init(struct i2c_client *client)
{
u8 id = 0;
int ret = 0;
/*
* Read sensor_pid in address 0x00 to check if the
* serial link is valid, read value should be 0x31.
*/
pat9126_read(client, PIXART_PAT9126_PRODUCT_ID1_REG, &id);
if (id != PIXART_PAT9126_SENSOR_ID) {
pr_err("[PAT9126]: PID mismatch (id = 0x%x)", id);
return (-1);
}
/*
* PAT9126 sensor recommended settings:
* switch to bank0, not allowed to perform pat9126_write_verified
*/
pat9126_write(client, PIXART_PAT9126_SELECT_BANK_REG,
PIXART_PAT9126_BANK0);
/*
* software reset (i.e. set bit7 to 1).
* It will reset to 0 automatically
* so perform OTS_RegWriteRead is not allowed.
*/
pat9126_write(client, PIXART_PAT9126_CONFIG_REG,
PIXART_PAT9126_RESET);
/* delay 1ms */
usleep_range(RESET_DELAY_US, RESET_DELAY_US + 1);
/* disable write protect */
if (pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_DISABLE_WRITE_PROTECT) < 0)
return (-1);
/* set X-axis resolution (depends on application) */
if (pat9126_write_verified(client, PIXART_PAT9126_SET_CPI_RES_X_REG,
PIXART_PAT9126_CPI_RESOLUTION_X) < 0)
return (-1);
/* set Y-axis resolution (depends on application) */
if (pat9126_write_verified(client, PIXART_PAT9126_SET_CPI_RES_Y_REG,
PIXART_PAT9126_CPI_RESOLUTION_Y) < 0)
return (-1);
/* set 12-bit X/Y data format (depends on application) */
if (pat9126_write_verified(client, PIXART_PAT9126_ORIENTATION_REG,
PIXART_PAT9126_MOTION_DATA_LENGTH) < 0)
return (-1);
/* ONLY for VDD=VDDA=1.7~1.9V: for power saving */
if (pat9126_write_verified(client, PIXART_PAT9126_VOLTAGE_SEGMENT_SEL_REG,
PIXART_PAT9126_LOW_VOLTAGE_SEGMENT) < 0)
return (-1);
pat9126_write_verified(client, PIXART_PAT9126_SENSOR_MODE_SELECT_REG,
PIXART_PAT9126_SENSOR_SET_MODE2);
pat9126_write_verified(client, PIXART_PAT9126_AE_ENABLE, PIXART_PAT9126_AE_ENABLE_VAL);
pat9126_write_verified(client, PIXART_PAT9126_NY_MIN, PIXART_PAT9126_NY_MIN_VAL);
ret = pat9126_enable_mot(client);
if (ret < 0) {
pr_err("[PAT9126]: Enable Motion FAIL.");
}
/* enable write protect */
pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_ENABLE_WRITE_PROTECT);
return ret;
}
int pat9126_disable_mot(struct i2c_client *client, int16_t detect_freq)
{
uint8_t tmp_1 = 0;
uint8_t sensor_pid = 0;
pat9126_read(client, PIXART_PAT9126_PRODUCT_ID1_REG, &sensor_pid);
if (sensor_pid != PIXART_PAT9126_SENSOR_ID) {
return (-1);
}
pat9126_write_verified(client, PIXART_PAT9126_SENSOR_MODE_SELECT_REG,
PIXART_PAT9126_SENSOR_DEFAULT_MODE2); // Set motion to open drain
pat9126_read(client, PIXART_PAT9126_SENSOR_MODE_SELECT_REG, &tmp_1);
pr_debug("[PAT9126]: Open drain mode motion: 0x%2x. \n", tmp_1);
pat9126_write_verified(client, PIXART_PAT9126_SLEEP2_MODE_FREQ_REG,
detect_freq);
pat9126_write(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG,
PIXART_PAT9126_FORCE_ENTER_SLEEP2_MODE);
return 0;
}
int pat9126_enable_mot(struct i2c_client *client)
{
uint8_t tmp_1 = 0;
uint8_t sensor_pid = 0;
pat9126_read(client, PIXART_PAT9126_PRODUCT_ID1_REG, &sensor_pid);
if (sensor_pid != PIXART_PAT9126_SENSOR_ID) {
return (-1);
}
pat9126_write_verified(client, PIXART_PAT9126_SENSOR_MODE_SELECT_REG,
PIXART_PAT9126_SENSOR_SET_MODE2); // Set motion to drive mode
pat9126_read(client, PIXART_PAT9126_SENSOR_MODE_SELECT_REG, &tmp_1);
pr_debug("[PAT9126]: Drive mode motion: 0x%2x. \n", tmp_1);
/*Read Register for Pulling Up Motion IRQ*/
pat9126_read(client, PIXART_PAT9126_MOTION_STATUS_REG, &tmp_1);
pat9126_read(client, PIXART_PAT9126_DELTA_X_LO_REG, &tmp_1);
pat9126_read(client, PIXART_PAT9126_DELTA_Y_LO_REG, &tmp_1);
pat9126_read(client, PIXART_PAT9126_DELTA_XY_HI_REG, &tmp_1);
delay(1); /* delay 1ms */
pat9126_write_verified(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG,
PIXART_PAT9126_WAKEUP_MODE);
pat9126_read(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, &tmp_1);
pr_debug("[PAT9126]: Enable sleep1 and disable sleep2 mode: 0x%2x. \n", tmp_1);
return 0;
}
int pat9126_enable_mot_write_protected(struct i2c_client *client) {
int result;
pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_DISABLE_WRITE_PROTECT);
result = pat9126_enable_mot(client);
pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_ENABLE_WRITE_PROTECT);
if (result) {
pr_err("[PAT9126] %s: failed to enable sensor\n", __func__);
}
return result;
}
int pat9126_disable_mot_write_protected(struct i2c_client *client) {
int result;
pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_DISABLE_WRITE_PROTECT);
result = pat9126_disable_mot(client, PIXART_PAT9126_SLEEP_MODE_FREQ_1024MS);
pat9126_write_verified(client, PIXART_PAT9126_WRITE_PROTECT_REG,
PIXART_PAT9126_ENABLE_WRITE_PROTECT);
if (result) {
pr_err("[PAT9126] %s: failed to disable sensor\n", __func__);
}
return result;
}
/* Read motion */
void pat9126_read_motion(struct i2c_client *client, int16_t *dx16, int16_t *dy16)
{
/* Be sure to use unsigned values for the low bytes to
avoid unintended sign extension (b/234361169) */
uint8_t deltaX_l = 0, deltaY_l = 0, deltaXY_h = 0;
int16_t deltaX_h = 0, deltaY_h = 0;
uint8_t motion = 0;
pat9126_read(client, PIXART_PAT9126_MOTION_STATUS_REG, &motion);
pr_debug("[pat9126]: Motion BIT: 0x%2x\n", motion);
if (motion & PIXART_PAT9126_VALID_MOTION_DATA) {
pat9126_read(client, PIXART_PAT9126_DELTA_X_LO_REG, &deltaX_l);
pat9126_read(client, PIXART_PAT9126_DELTA_Y_LO_REG, &deltaY_l);
pat9126_read(client, PIXART_PAT9126_DELTA_XY_HI_REG, &deltaXY_h);
deltaX_h = (deltaXY_h & 0xF0);
deltaX_h <<= 4;
/* 12-bit data convert to 16-bit */
if (deltaX_h & 0x800)
deltaX_h |= 0xf000;
deltaY_h = (deltaXY_h & 0xF);
deltaY_h <<= 8;
/* 12-bit data convert to 16-bit */
if (deltaY_h & 0x800)
deltaY_h |= 0xf000;
}
*dx16 = deltaX_h | (int16_t) deltaX_l;
*dy16 = deltaY_h | (int16_t) deltaY_l;
}
static void pat9126_work_handler(struct work_struct *work)
{
int8_t slop = 0;
int16_t delta_x = 0, delta_y = 0;
struct delayed_work *dw = to_delayed_work(work);
struct pixart_pat9126_data *data = \
container_of(dw, struct pixart_pat9126_data, polling_work);
struct input_dev *ipdev = data->input;
struct device *dev = &data->client->dev;
ktime_t timestamp = ktime_set(0, 0);
mutex_lock(&data->mtx);
if (data->state == PAT9126_STATE_RESUMING) {
pr_warn("[PAT9126] %s: work handler run before resume complete\n", __func__);
goto end_work_handler;
}
/* check if MOTION bit is set or not */
pat9126_read_motion(data->client, &delta_x, &delta_y);
timestamp = ktime_get();
dev_dbg(dev, "delta_x: %d, delta_y: %d\n", delta_x, delta_y);
/* Inverse x depending upon the device orientation */
delta_x = (data->inverse_x) ? -delta_x : delta_x;
/* Inverse y depending upon the device orientation */
delta_y = (data->inverse_y) ? -delta_y : delta_y;
dev_dbg(dev, "delta_x = 0x%2x, delta_y = 0x%2x\n",
delta_x, delta_y);
if (delta_x != 0) {
/* Send delta_x as REL_WHEEL for rotation */
input_set_timestamp(ipdev, timestamp);
slop = (delta_x < 0) ? -(data->slop) : data->slop;
if (WAKE_SENSITIVITY == data->current_sensitivity &&
!data->wake_handled) {
input_report_rel(ipdev, REL_WHEEL, slop);
data->wake_handled = true;
pr_info("[PAT9126] WHEEL distance : %d\n", slop);
}
else {
input_report_rel(ipdev, REL_WHEEL, delta_x);
pr_info("[PAT9126] WHEEL distance : %d\n", delta_x);
}
input_sync(ipdev);
}
end_work_handler:
enable_irq(data->client->irq);
mutex_unlock(&data->mtx);
}
static irqreturn_t pat9126_irq(int irq, void *dev_data)
{
struct pixart_pat9126_data *data = dev_data;
bool result = false;
disable_irq_nosync(irq);
if (!work_pending(&data->work)) {
result = schedule_delayed_work(&data->polling_work, msecs_to_jiffies(10));
if (result == false) {
/* queue_work fail */
pr_err("%s:queue_work fail.\n",__func__);
}
} else {
/* work pending */
pr_err("%s:queue_work pending.\n",__func__);
}
return IRQ_HANDLED;
}
static void pat9126_sensitivity_write(struct pixart_pat9126_data *data,
u8 sensitivity) {
struct i2c_client *client = data->client;
pr_info("[PAT9126] set sensitivity: %d\n", sensitivity);
pat9126_write(client, PIXART_PAT9126_SET_CPI_RES_X_REG, sensitivity);
data->current_sensitivity = sensitivity;
}
static ssize_t pat9126_sensitivity_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
if (!kstrtou8(buf, 0, &data->crown_sensitivity)) {
pat9126_sensitivity_write(data, data->crown_sensitivity);
}
return count;
}
static ssize_t pat9126_sensitivity_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
int count = 0;
uint8_t tmp;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_SET_CPI_RES_X_REG, &tmp);
count += sprintf(buf, "0x%2x\n", tmp);
return count;
}
static ssize_t pat9126_slop_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
if (!kstrtou8(buf, 0, &data->slop)) {
return count;
}
return count;
}
static ssize_t pat9126_slop_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
int count = 0;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
count += sprintf(buf, "0x%2x\n", data->slop);
return count;
}
static ssize_t pat9126_id_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
int count = 0;
uint8_t maj, min;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_PRODUCT_ID1_REG, &maj);
pat9126_read(client, PIXART_PAT9126_PRODUCT_ID2_REG, &min);
count += sprintf(buf, "0x%2x 0x%2x\n", maj, min);
return count;
}
static ssize_t pat9126_max_sleep_level_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
u8 tmp, sleep_mode;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, &sleep_mode);
if (kstrtou8(buf, 0, &tmp)) {
return count;
}
dev_dbg(dev, "Max sleep level: %u\n", tmp);
sleep_mode &= ~SLEEP_MODES_ENABLED_MASK;
if (tmp == 0) {
sleep_mode |= SLEEP_MODES_ENABLED_ZERO;
} else if (tmp == 1) {
sleep_mode |= SLEEP_MODES_ENABLED_ONE;
} else if (tmp == 2) {
sleep_mode |= SLEEP_MODES_ENABLED_TWO;
}
pat9126_write(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, sleep_mode);
return count;
}
static ssize_t pat9126_max_sleep_level_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
int count = 0;
uint8_t sleep_mode;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, &sleep_mode);
switch (sleep_mode & SLEEP_MODES_ENABLED_MASK) {
case SLEEP_MODES_ENABLED_TWO:
count += sprintf(buf, "2\n");
break;
case SLEEP_MODES_ENABLED_ONE:
count += sprintf(buf, "1\n");
break;
default:
/* Note: this case covers '01' and '00' which both
correspond to zero sleep modes */
count += sprintf(buf, "0\n");
break;
}
return count;
}
static ssize_t pat9126_sleep_level_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
u8 tmp, sleep_mode;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, &sleep_mode);
if (kstrtou8(buf, 0, &tmp)) {
return count;
}
dev_dbg(dev, "Setting sleep level: %u\n", tmp);
if (tmp == 0) {
sleep_mode &= ~SLEEP_MODE_MASK;
sleep_mode |= SLEEP_MODE_WAKE;
} else if (tmp == 1) {
/* Can't switch to sleep mode #1 if disabled */
if ((sleep_mode & SLEEP_MODES_ENABLED_MASK) != SLEEP_MODES_ENABLED_ZERO) {
sleep_mode &= ~SLEEP_MODE_MASK;
sleep_mode |= SLEEP_MODE_ONE;
}
} else if (tmp == 2) {
/* Can't switch to sleep mode #2 if disabled */
if ((sleep_mode & SLEEP_MODES_ENABLED_MASK) == SLEEP_MODES_ENABLED_TWO) {
sleep_mode &= ~SLEEP_MODE_MASK;
sleep_mode |= SLEEP_MODE_TWO;
}
}
pat9126_write(client, PIXART_PAT9126_SLEEP_MODE_SELECT_REG, sleep_mode);
return count;
}
static int pat9126_pd_write(struct device *dev, u8 val) {
u8 config;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_CONFIG_REG, &config);
config &= ~POWER_DOWN_ENABLE_BIT;
if (val) {
config |= POWER_DOWN_ENABLE_BIT;
}
pat9126_write(client, PIXART_PAT9126_CONFIG_REG, config);
return 0;
}
static ssize_t pat9126_pd_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count) {
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
u8 tmp;
if (!kstrtou8(buf, 0, &tmp)) {
dev_dbg(dev, "power down: %d\n", (tmp ? 1 : 0));
if (!tmp) {
pat9126_set_loads_active(data);
}
pat9126_pd_write(dev, tmp);
if (tmp) {
pat9126_set_loads_sleep(data);
}
} else {
dev_warn(dev, "failed to parse sysfs arg: '%s'\n", buf);
}
return count;
}
static ssize_t pat9126_pd_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
int count = 0;
uint8_t tmp;
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
struct i2c_client *client = data->client;
pat9126_read(client, PIXART_PAT9126_CONFIG_REG, &tmp);
tmp = ((POWER_DOWN_ENABLE_BIT & tmp) ? 1 : 0);
count += sprintf(buf, "0x%x\n", tmp);
return count;
}
static void pat9126_complete_resume(struct work_struct *work) {
struct delayed_work *dw = to_delayed_work(work);
struct pixart_pat9126_data *data =
container_of(dw, struct pixart_pat9126_data, resume_work);
int ret = 0;
mutex_lock(&data->mtx);
if (data->state != PAT9126_STATE_RESUMING) {
if (data->state == PAT9126_STATE_ON) {
pr_warn("[PAT9126] %s: Already resumed\n", __func__);
} else {
// If suspend is called before resume is complete
// resume will be aborted
pr_info("[PAT9126] %s: Resume aborted\n", __func__);
}
goto end_complete_resume;
}
ret = pat9126_set_loads_active(data);
if (ret) {
goto end_complete_resume;
}
pat9126_enable_mot_write_protected(data->client);
data->state = PAT9126_STATE_ON;
end_complete_resume:
mutex_unlock(&data->mtx);
}
static DEVICE_ATTR
(crown_sensitivity, S_IRUGO | S_IWUSR | S_IWGRP, pat9126_sensitivity_show, pat9126_sensitivity_store);
static DEVICE_ATTR
(id, S_IRUGO, pat9126_id_show, NULL);
static DEVICE_ATTR
(max_sleep_level, S_IRUGO | S_IWUSR | S_IWGRP, pat9126_max_sleep_level_show, pat9126_max_sleep_level_store);
static DEVICE_ATTR
(sleep_level, S_IWUSR | S_IWGRP, NULL, pat9126_sleep_level_store);
static DEVICE_ATTR
(pd, S_IRUGO | S_IWUSR | S_IWGRP, pat9126_pd_show, pat9126_pd_store);
static DEVICE_ATTR
(slop, S_IRUGO | S_IWUSR | S_IWGRP, pat9126_slop_show, pat9126_slop_store);
static struct attribute *pat9126_attr_list[] = {
&dev_attr_crown_sensitivity.attr,
&dev_attr_id.attr,
&dev_attr_max_sleep_level.attr,
&dev_attr_sleep_level.attr,
&dev_attr_pd.attr,
&dev_attr_slop.attr,
NULL,
};
static struct attribute_group pat9126_attr_grp = {
.attrs = pat9126_attr_list,
};
static int pat9126_parse_dt(struct device *dev,
struct pixart_pat9126_data *data)
{
struct device_node *np = dev->of_node;
u32 temp_val;
int ret;
data->inverse_x = of_property_read_bool(np, "pixart,inverse-x");
data->inverse_y = of_property_read_bool(np, "pixart,inverse-y");
data->press_en = of_property_read_bool(np, "pixart,press-enabled");
if (data->press_en) {
ret = of_property_read_u32(np, "pixart,press-keycode",
&temp_val);
if (!ret) {
data->press_keycode = temp_val;
} else {
dev_err(dev, "Unable to parse press-keycode\n");
return ret;
}
}
ret = of_property_read_u32(np, "pixart,vdd-active-load",
&temp_val);
if (!ret) {
data->vdd_active_load = temp_val;
} else {
dev_err(dev, "Unable to parse vdd-active-load\n");
return ret;
}
ret = of_property_read_u32(np, "pixart,vld-active-load",
&temp_val);
if (!ret) {
data->vld_active_load = temp_val;
} else {
dev_err(dev, "Unable to parse vld-active-load\n");
return ret;
}
ret = of_property_read_u32(np, "pixart,vdd-sleep-load",
&temp_val);
if (!ret) {
data->vdd_sleep_load = temp_val;
} else {
dev_err(dev, "Unable to parse vdd-sleep-load\n");
return ret;
}
ret = of_property_read_u32(np, "pixart,vld-sleep-load",
&temp_val);
if (!ret) {
data->vld_sleep_load = temp_val;
} else {
dev_err(dev, "Unable to parse vld-sleep-load\n");
return ret;
}
data->vld_supply = devm_regulator_get(dev, "pixart,vld");
if (IS_ERR(data->vld_supply)) {
ret = PTR_ERR(data->vld_supply);
dev_err(dev, "get vld regulator failed, ret=%d\n", ret);
return ret;
}
data->vdd_supply = devm_regulator_get(dev, "pixart,vdd");
if (IS_ERR(data->vdd_supply)) {
ret = PTR_ERR(data->vdd_supply);
dev_err(dev, "get vdd regulator failed, ret=%d\n", ret);
return ret;
}
return 0;
}
static int pat9126_register_panel_notifier(struct pixart_pat9126_data *data)
{
struct device_node *np = data->client->dev.of_node;
struct device_node *pnode;
struct drm_panel *panel;
void *cookie = NULL;
int i, count, rc;
count = of_count_phandle_with_args(np, "display-panels", NULL);
if (count <= 0)
return 0;
for (i = 0; i < count; i++) {
pnode = of_parse_phandle(np, "display-panels", i);
if (!pnode)
return -ENODEV;
panel = of_drm_find_panel(pnode);
of_node_put(pnode);
if (!IS_ERR(panel)) {
data->active_panel = panel;
break;
}
}
if (!data->active_panel) {
rc = PTR_ERR(panel);
if (rc != -EPROBE_DEFER)
pr_err("failed to find active panel, rc=%d\n", rc);
return rc;
}
cookie = panel_event_notifier_register(
PANEL_EVENT_NOTIFICATION_PRIMARY,
PANEL_EVENT_NOTIFIER_CLIENT_SECONDARY_TOUCH,
data->active_panel,
&pat9126_drm_panel_notifier_callback,
data);
if (IS_ERR(cookie)) {
rc = PTR_ERR(cookie);
pr_err("failed to register panel event notifier, rc=%d\n", rc);
return rc;
}
pr_debug("register panel notifier successful\n");
data->notifier_cookie = cookie;
return 0;
}
static void pat9126_unregister_panel_notifier(struct pixart_pat9126_data *data)
{
if (data->notifier_cookie)
panel_event_notifier_unregister(data->notifier_cookie);
}
static int pixart_input_open(struct input_dev *dev) {
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) input_get_drvdata(dev);
mutex_lock(&data->mtx);
if (data->display_mode == DISPLAY_UNBLANKED) {
// Display On
pat9126_sensitivity_write(data, data->crown_sensitivity);
pat9126_enable_mot_write_protected(data->client);
data->state = PAT9126_STATE_ON;
} else {
// Display Suspended
pat9126_sensitivity_write(data, WAKE_SENSITIVITY);
enable_irq_wake(data->client->irq);
pat9126_disable_mot_write_protected(data->client);
data->state = PAT9126_STATE_SUSPEND;
data->wake_handled = false;
}
mutex_unlock(&data->mtx);
return 0;
}
static void pixart_input_close(struct input_dev *dev) {
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) input_get_drvdata(dev);
pr_info("[PAT9126]: disabling wake on irq %d", data->client->irq);
mutex_lock(&data->mtx);
if (data->state == PAT9126_STATE_SUSPEND) {
// Wake irq was enabled in pat9126_display_suspend so we need to disable the irq
disable_irq_wake(data->client->irq);
} else {
// Wake irq wasn't enabled in pat9126_display_suspend nor was the device disabled
// so we need to put the pat9126 device into sleep2 mode
pat9126_disable_mot_write_protected(data->client);
}
mutex_unlock(&data->mtx);
}
static int pat9126_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
struct pixart_pat9126_data *data;
struct input_dev *input;
struct device *dev = &client->dev;
struct device_node *dp = NULL;
dp = client->dev.of_node;
ret = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
if (ret < 0) {
dev_err(dev, "I2C not supported\n");
return -ENXIO;
}
data = devm_kzalloc(dev, sizeof(struct pixart_pat9126_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
ret = pat9126_parse_dt(dev, data);
if (ret) {
dev_err(dev, "DT parsing failed, errno:%d\n", ret);
return ret;
}
data->client = client;
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Failed to alloc input device\n");
return -ENOMEM;
}
input_set_capability(input, EV_REL, REL_WHEEL);
if (data->press_en)
input_set_capability(input, EV_KEY, data->press_keycode);
i2c_set_clientdata(client, data);
input_set_drvdata(input, data);
input->name = PAT9126_DEV_NAME;
input->phys = PAT9126_DEV_PHYS;
input->open = pixart_input_open;
input->close = pixart_input_close;
data->input = input;
ret = input_register_device(data->input);
if (ret < 0) {
dev_err(dev, "Failed to register input device\n");
return ret;
}
ret = pinctrl_pm_select_default_state(dev);
if (ret < 0)
dev_err(dev, "Could not set pin to active state %d\n", ret);
ret = pat9126_set_loads_active(data);
if (ret < 0) {
return ret;
}
ret = pat9126_enable_regulators(data);
if (ret < 0) {
goto err_regulators;
}
usleep_range(DELAY_BETWEEN_REG_US, DELAY_BETWEEN_REG_US + 1);
/*
* Initialize pixart sensor after some delay, when vdd
* regulator is enabled
*/
if (pat9126_sensor_init(data->client) < 0) {
ret = -ENODEV;
dev_err(dev, "Failed to initialize sensor %d\n", ret);
goto err_regulators;
}
mutex_init(&data->mtx);
data->state = PAT9126_STATE_ON;
data->display_mode = DISPLAY_UNBLANKED;
data->crown_sensitivity = PIXART_PAT9126_CPI_RESOLUTION_X;
data->current_sensitivity = PIXART_PAT9126_CPI_RESOLUTION_X;
data->slop = PIXART_PAT9126_SLOP;
data->wake_handled = false;
ret = pat9126_register_panel_notifier(data);
if (ret) {
dev_err(dev, "register panel_notifier failed, errno:%d\n", ret);
goto err_regulators;
}
INIT_DELAYED_WORK(&data->polling_work, pat9126_work_handler);
INIT_DELAYED_WORK(&data->resume_work, pat9126_complete_resume);
pr_err("[PAT9126]: Probe Enable Irq. \n");
ret = devm_request_threaded_irq(dev, client->irq, NULL, pat9126_irq,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"pixart_pat9126_irq", data);
if (ret) {
dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, ret);
goto err_request_threaded_irq;
}
ret = sysfs_create_group(&client->dev.kobj, &pat9126_attr_grp);
if (ret) {
dev_err(dev, "Failed to create sysfs group, errno:%d\n", ret);
goto err_sysfs_create;
}
return 0;
err_sysfs_create:
disable_irq(client->irq);
err_request_threaded_irq:
cancel_work_sync(&data->work);
destroy_workqueue(data->workqueue);
err_regulators:
pat9126_disable_regulators(data);
return ret;
}
static int pat9126_i2c_remove(struct i2c_client *client)
{
int ret = 0;
struct device *dev = &client->dev;
struct pixart_pat9126_data *data = i2c_get_clientdata(client);
dev_dbg(dev, "%s\n", __func__);
if (data) {
pat9126_unregister_panel_notifier(data);
pat9126_disable_regulators(data);
}
return ret;
}
static void pat9126_drm_panel_notifier_callback(enum panel_event_notifier_tag tag,
struct panel_event_notification *notification, void *data)
{
struct pixart_pat9126_data *pat9126 = data;
if (!notification) {
return;
}
switch (notification->notif_type) {
case DRM_PANEL_EVENT_UNBLANK:
if (!notification->notif_data.early_trigger) {
pat9126_display_resume(&pat9126->client->dev);
pat9126->display_mode = DISPLAY_UNBLANKED;
}
break;
case DRM_PANEL_EVENT_BLANK:
case DRM_PANEL_EVENT_BLANK_LP:
if (notification->notif_data.early_trigger) {
pat9126_display_suspend(&pat9126->client->dev);
pat9126->display_mode = DISPLAY_BLANKED;
}
break;
default:
break;
}
return;
}
static int pat9126_display_suspend(struct device *dev)
{
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
mutex_lock(&data->mtx);
pr_debug("[PAT9126] %s\n", __func__);
if (data->input->users == 0) {
goto end_suspend;
}
if (data->state != PAT9126_STATE_ON) {
if (data->state == PAT9126_STATE_SUSPEND) {
pr_warn("[PAT9126] %s: Redundant call to suspend\n", __func__);
} else {
// PAT9126_STATE_RESUMING
pr_info("[PAT9126] %s: Aborting resume\n", __func__);
}
goto end_suspend;
}
/* Set low sensitivity */
pat9126_sensitivity_write(data, WAKE_SENSITIVITY);
data->wake_handled = false;
enable_irq_wake(data->client->irq);
pat9126_disable_mot_write_protected(data->client);
pat9126_set_loads_sleep(data);
end_suspend:
data->state = PAT9126_STATE_SUSPEND;
mutex_unlock(&data->mtx);
return 0;
}
static int pat9126_display_resume(struct device *dev)
{
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
pr_debug("[PAT9126] %s\n", __func__);
mutex_lock(&data->mtx);
if (data->state != PAT9126_STATE_SUSPEND) {
pr_warn("[PAT9126] %s: Redundant call to resume\n", __func__);
mutex_unlock(&data->mtx);
return 0;
}
/* Skip if input device is closed */
if (data->input->users == 0) {
mutex_unlock(&data->mtx);
return 0;
}
/* Set regular sensitivity */
pat9126_sensitivity_write(data, data->crown_sensitivity);
disable_irq_wake(data->client->irq);
data->state = PAT9126_STATE_RESUMING;
mutex_unlock(&data->mtx);
if (!schedule_delayed_work(&data->resume_work, msecs_to_jiffies(10))) {
pr_err("[PAT9126] %s: Failed to schedule delayed resume\n", __func__);
// Note that we must release the mutex (as above) before
// calling this function.
pat9126_complete_resume(&data->resume_work.work);
}
return 0;
}
static int pat9126_pm_suspend_late(struct device *dev)
{
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
mutex_lock(&data->mtx);
return 0;
}
static int pat9126_pm_resume_early(struct device *dev)
{
struct pixart_pat9126_data *data =
(struct pixart_pat9126_data *) dev_get_drvdata(dev);
mutex_unlock(&data->mtx);
return 0;
}
static const struct i2c_device_id pat9126_device_id[] = {
{PAT9126_DEV_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pat9126_device_id);
static const struct dev_pm_ops pat9126_pm_ops = {
.suspend_late = pat9126_pm_suspend_late,
.resume_early = pat9126_pm_resume_early
};
static const struct of_device_id pixart_pat9126_match_table[] = {
{ .compatible = "pixart,pat9126",},
{ },
};
static struct i2c_driver pat9126_i2c_driver = {
.driver = {
.name = PAT9126_DEV_NAME,
.owner = THIS_MODULE,
.pm = &pat9126_pm_ops,
.of_match_table = pixart_pat9126_match_table,
},
.probe = pat9126_i2c_probe,
.remove = pat9126_i2c_remove,
.id_table = pat9126_device_id,
};
module_i2c_driver(pat9126_i2c_driver);
MODULE_AUTHOR("pixart");
MODULE_DESCRIPTION("pixart pat9126 driver");
MODULE_LICENSE("GPL");