* [PATCH] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Yoichi Yuasa @ 2014-07-31 10:54 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: yuasa, linux-input
Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
---
drivers/input/touchscreen/Kconfig | 11 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/rohm_bu21023.c | 791 ++++++++++++++++++++++++++++++
drivers/input/touchscreen/rohm_bu21023.h | 255 ++++++++++
4 files changed, 1058 insertions(+)
create mode 100644 drivers/input/touchscreen/rohm_bu21023.c
create mode 100644 drivers/input/touchscreen/rohm_bu21023.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6bb9a7d..9ae5c88 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -950,4 +950,15 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_ROHM_BU21023
+ tristate "ROHM BU21023/24 Dual touch support resistive touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a touchscreen using ROHM BU21023/24.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21023_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 4be94fc..af766d0 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
new file mode 100644
index 0000000..317d59b
--- /dev/null
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -0,0 +1,791 @@
+/*
+ * ROHM BU21023/24 Dual touch support resistive touch screen driver
+ * Copyright (C) 2012 ROHM CO.,LTD.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "rohm_bu21023.h"
+
+struct rohm_ts_point {
+ unsigned int x;
+ unsigned int y;
+};
+
+struct rohm_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+
+ int use_irq;
+ struct hrtimer hrtimer;
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+
+ unsigned int untouch_count;
+ unsigned int single_touch_count;
+ unsigned int dual_touch_count;
+ unsigned int prev_touch_report;
+};
+
+/*
+ * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24
+ * @adap: Handle to I2C bus
+ * @msgs: combined messages to execute
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Note
+ * In BU21023/24 burst read, stop condition is needed after "address write".
+ * Therefore, transmission is performed in 2 steps.
+ */
+static inline int rohm_i2c_burst_read(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ int ret, i;
+
+ if (!adap->algo->master_xfer) {
+ dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ i2c_lock_adapter(adap);
+
+ for (i = 0; i < num; i++) {
+ ret = __i2c_transfer(adap, &msgs[i], 1);
+ if (ret < 0)
+ break;
+
+ ret = i;
+ }
+
+ i2c_unlock_adapter(adap);
+
+ return ret;
+}
+
+static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
+{
+ struct i2c_client *client = ts->client;
+ struct device *dev = &client->dev;
+ struct i2c_msg msg[2];
+ u8 buf[33];
+ u8 addr_buf; /* burst read start address */
+
+ int retry;
+ bool success = false;
+ bool first_time = true;
+ bool calibration_done;
+
+ u8 reg1, reg2, reg3;
+ u8 reg1_orig, reg2_orig, reg3_orig;
+
+ s32 val;
+
+ int calib_x = 0, calib_y = 0;
+ int reg_x, reg_y;
+ int err_x, err_y;
+
+ int ret;
+ int i;
+
+ addr_buf = PRM1_X_H;
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &addr_buf;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(buf);
+ msg[1].buf = buf;
+
+#define READ_CALIB_BUF(reg) ((u16)buf[((reg) - PRM1_X_H)])
+
+ reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1);
+ reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2);
+ reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3);
+
+ if (ts->use_irq)
+ disable_irq(client->irq);
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | SLEEP_IN | SLEEP_OUT |
+ PROGRAM_LOAD_DONE);
+
+ i2c_smbus_write_byte_data(client, TEST1, DUALTOUCH_STABILIZE_ON);
+
+ for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) {
+ /* wait 2 sampling for update */
+ mdelay(2 * SAMPLING_DELAY);
+
+ ret = rohm_i2c_burst_read(client->adapter, msg, 2);
+ if (!ret) {
+ dev_err(dev, "I2C transfer error\n");
+ return ret;
+ }
+
+ if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT)
+ continue;
+
+ if (first_time) {
+ /* generate calibration parameter */
+ calib_x =
+ (READ_CALIB_BUF(PRM1_X_H) << 2 |
+ READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET;
+ calib_y =
+ (READ_CALIB_BUF(PRM1_Y_H) << 2 |
+ READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET;
+
+ i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON |
+ DUALTOUCH_REG_ON);
+
+ first_time = false;
+ } else {
+ /* generate adjustment parameter */
+ err_x = READ_CALIB_BUF(PRM1_X_H) << 2 |
+ READ_CALIB_BUF(PRM1_X_L);
+ err_y = READ_CALIB_BUF(PRM1_Y_H) << 2 |
+ READ_CALIB_BUF(PRM1_Y_L);
+
+ /* X axis ajust */
+ if (err_x <= 4)
+ calib_x -= AXIS_ADJUST;
+ else if (err_x >= 60)
+ calib_x += AXIS_ADJUST;
+
+ /* Y axis ajust */
+ if (err_y <= 4)
+ calib_y -= AXIS_ADJUST;
+ else if (err_y >= 60)
+ calib_y += AXIS_ADJUST;
+ }
+
+ /* generate calibration setting value */
+ reg_x = calib_x + ((calib_x & 0x200) << 1);
+ reg_y = calib_y + ((calib_y & 0x200) << 1);
+
+ /* convert for register format */
+ reg1 = reg_x >> 3;
+ reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7);
+ reg3 = reg_y >> 3;
+
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG1, reg1);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG2, reg2);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG3, reg3);
+
+ /*
+ * force calibration sequcence
+ */
+ i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_OFF);
+
+ i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_ON);
+
+ /* clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ /*
+ * Wait for the status change of calibration, max 10 sampling
+ */
+ calibration_done = false;
+
+ for (i = 0; i < 10; i++) {
+ mdelay(SAMPLING_DELAY);
+
+ val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE);
+ if (!(val & CALIBRATION_MASK)) {
+ calibration_done = true;
+ break;
+ }
+ }
+
+ if (calibration_done) {
+ val = i2c_smbus_read_byte_data(client, INT_STATUS);
+ if (val == CALIBRATION_DONE) {
+ success = true;
+ break;
+ }
+ } else
+ dev_warn(dev, "Calibration timeout\n");
+ }
+
+ if (!success) {
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG1, reg1_orig);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG2, reg2_orig);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG3, reg3_orig);
+
+ /* calibration data enable */
+ i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON |
+ DUALTOUCH_REG_ON);
+
+ /* wait 10 sampling */
+ mdelay(10 * SAMPLING_DELAY);
+
+ dev_warn(dev, "Failed to manual calibration\n");
+ ret = -EBUSY;
+ } else {
+ dev_dbg(dev, "Manual calibration done\n");
+ ret = 0;
+ }
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | CALIBRATION_DONE |
+ SLEEP_IN | SLEEP_OUT |
+ PROGRAM_LOAD_DONE | ERROR);
+
+ /* Clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ if (ts->use_irq)
+ enable_irq(client->irq);
+
+ return ret;
+}
+
+static unsigned long inactive_polling_interval[2] = { 1, 0 };
+static unsigned long active_polling_interval[2] = { 0, 10000000 };
+
+module_param_array(inactive_polling_interval, ulong, NULL, S_IRUGO | S_IWUSR);
+module_param_array(active_polling_interval, ulong, NULL, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(inactive_polling_interval,
+ "Polling interval for un-touch detection");
+MODULE_PARM_DESC(active_polling_interval,
+ "Polling interval for touch detection");
+
+#define INACTIVE_POLLING_INTERVAL_KTIME \
+ ktime_set(inactive_polling_interval[0], inactive_polling_interval[1])
+#define ACTIVE_POLLING_INTERVAL_KTIME \
+ ktime_set(active_polling_interval[0], active_polling_interval[1])
+
+static unsigned int untouch_threshold[3] = { 0, 1, 5 };
+static unsigned int single_touch_threshold[3] = { 0, 0, 4 };
+static unsigned int dual_touch_threshold[3] = { 10, 8, 0 };
+
+module_param_array(untouch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(single_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(dual_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(untouch_threshold, "Thresholds for un-touch detection");
+MODULE_PARM_DESC(single_touch_threshold,
+ "Thresholds for single touch detection");
+MODULE_PARM_DESC(dual_touch_threshold, "Thresholds for dual touch detection");
+
+static void rohm_ts_work_func(struct work_struct *work)
+{
+ struct rohm_ts_data *ts = container_of(work, struct rohm_ts_data, work);
+ struct i2c_client *client = ts->client;
+ struct input_dev *input_dev = ts->input_dev;
+ struct device *dev = &client->dev;
+ struct i2c_msg msg[2];
+ u16 addr = client->addr;
+ u8 addr_buf;
+ u8 buf[10]; /* for 0x20-0x29 */
+
+ struct rohm_ts_point tp1, tp2;
+ u8 touch_flags;
+ unsigned int threshold;
+ int touch_report = -1;
+ unsigned int prev_touch_report = ts->prev_touch_report;
+ bool next_sensing_immediately = false;
+
+ int ret;
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | CALIBRATION_DONE |
+ SLEEP_OUT | SLEEP_IN | PROGRAM_LOAD_DONE |
+ ERROR);
+
+ /* Clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ addr_buf = POS_X1_H;
+ msg[0].addr = addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &addr_buf;
+
+ msg[1].addr = addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(buf);
+ msg[1].buf = buf;
+
+#define READ_POS_BUF(reg) ((u16)buf[((reg) - POS_X1_H)])
+
+ ret = rohm_i2c_burst_read(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(dev, "I2C transfer error\n");
+ return;
+ }
+
+ touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK;
+ if (touch_flags) {
+ next_sensing_immediately = true;
+
+ /* generate coordinates */
+ tp1.x = (READ_POS_BUF(POS_X1_H) << 2) | READ_POS_BUF(POS_X1_L);
+ tp1.y = (READ_POS_BUF(POS_Y1_H) << 2) | READ_POS_BUF(POS_Y1_L);
+ tp2.x = (READ_POS_BUF(POS_X2_H) << 2) | READ_POS_BUF(POS_X2_L);
+ tp2.y = (READ_POS_BUF(POS_Y2_H) << 2) | READ_POS_BUF(POS_Y2_L);
+
+ switch (touch_flags) {
+ case SINGLE_TOUCH:
+ ts->untouch_count = 0;
+ ts->single_touch_count++;
+ ts->dual_touch_count = 0;
+
+ threshold = single_touch_threshold[prev_touch_report];
+ if (ts->single_touch_count > threshold)
+ touch_report = 1;
+
+ if (touch_report == 1) {
+ if (tp2.x != 0 && tp2.y != 0) {
+ tp1.x = tp2.x;
+ tp1.y = tp2.y;
+ tp2.x = 0;
+ tp2.y = 0;
+ }
+ }
+ break;
+ case DUAL_TOUCH:
+ ts->untouch_count = 0;
+ ts->single_touch_count = 0;
+ ts->dual_touch_count++;
+
+ threshold = dual_touch_threshold[prev_touch_report];
+ if (ts->dual_touch_count > threshold)
+ touch_report = 2;
+ break;
+ default:
+ dev_err(dev,
+ "Three or more touches are not supported\n");
+ break;
+ }
+ } else {
+ ts->untouch_count++;
+
+ threshold = untouch_threshold[prev_touch_report];
+ if (ts->untouch_count > threshold) {
+ ts->untouch_count = 0;
+ ts->single_touch_count = 0;
+ ts->dual_touch_count = 0;
+
+ touch_report = 0;
+ } else if (prev_touch_report > 0) {
+ next_sensing_immediately = true;
+ }
+ }
+
+ switch (touch_report) {
+ case 0:
+ input_mt_sync(input_dev);
+
+ input_sync(input_dev);
+ ts->prev_touch_report = touch_report;
+ break;
+ case 1:
+ input_report_abs(input_dev, ABS_MT_POSITION_X, tp1.x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, tp1.y);
+ input_mt_sync(input_dev);
+
+ input_sync(input_dev);
+ ts->prev_touch_report = touch_report;
+ break;
+ case 2:
+ input_report_abs(input_dev, ABS_MT_POSITION_X, tp1.x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, tp1.y);
+ input_mt_sync(input_dev);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, tp2.x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, tp2.y);
+ input_mt_sync(input_dev);
+
+ input_sync(input_dev);
+ ts->prev_touch_report = touch_report;
+ break;
+ default:
+ break;
+ }
+
+ /* set next sensing time */
+ if (next_sensing_immediately) {
+ hrtimer_start(&ts->hrtimer,
+ ACTIVE_POLLING_INTERVAL_KTIME, HRTIMER_MODE_REL);
+ } else {
+ if (READ_POS_BUF(TOUCH_GESTURE) & CALIBRATION_REQUEST)
+ rohm_ts_manual_calibration(ts);
+
+ if (ts->use_irq) {
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ CALIBRATION_DONE |
+ SLEEP_OUT | SLEEP_IN |
+ PROGRAM_LOAD_DONE);
+ } else {
+ hrtimer_start(&ts->hrtimer,
+ INACTIVE_POLLING_INTERVAL_KTIME,
+ HRTIMER_MODE_REL);
+ }
+ }
+}
+
+static enum hrtimer_restart rohm_ts_timer_func(struct hrtimer *hrtimer)
+{
+ struct rohm_ts_data *ts =
+ container_of(hrtimer, struct rohm_ts_data, hrtimer);
+
+ queue_work(ts->workqueue, &ts->work);
+
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t rohm_ts_irq_handler(int irq, void *dev_id)
+{
+ struct rohm_ts_data *ts = dev_id;
+
+ queue_work(ts->workqueue, &ts->work);
+
+ return IRQ_HANDLED;
+}
+
+static int rohm_ts_load_firmware(struct i2c_client *client,
+ const char *firmware_name)
+{
+ struct device *dev = &client->dev;
+ const struct firmware *firmware = NULL;
+ s32 status;
+ int blocks, remainder, retry, offset;
+ int ret;
+ int i;
+
+ ret = request_firmware(&firmware, firmware_name, dev);
+ if (ret) {
+ dev_err(dev, "Unable to open firmware %s\n", firmware_name);
+ return ret;
+ }
+
+ blocks = firmware->size / FIRMWARE_BLOCK_SIZE;
+ remainder = firmware->size % FIRMWARE_BLOCK_SIZE;
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | CALIBRATION_DONE |
+ SLEEP_IN | SLEEP_OUT);
+
+ for (retry = 0; retry < FIRMWARE_RETRY_MAX; retry++) {
+ i2c_smbus_write_byte_data(client, COMMON_SETUP1,
+ COMMON_SETUP1_DEFAULT);
+ i2c_smbus_write_byte_data(client, EX_ADDR_H, 0);
+ i2c_smbus_write_byte_data(client, EX_ADDR_L, 0);
+
+ offset = 0;
+
+ /* firmware load to the device */
+ for (i = 0; i < blocks; i++) {
+ i2c_smbus_write_i2c_block_data(client, EX_WDAT,
+ FIRMWARE_BLOCK_SIZE,
+ &firmware->data[offset]);
+ offset += FIRMWARE_BLOCK_SIZE;
+ }
+
+ if (remainder)
+ i2c_smbus_write_i2c_block_data(client, EX_WDAT,
+ remainder,
+ &firmware->data[offset]);
+
+ /* check formware load result */
+ status = i2c_smbus_read_byte_data(client, INT_STATUS);
+
+ /* clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ if (status == PROGRAM_LOAD_DONE)
+ break;
+
+ dev_warn(dev, "Retry firmware load\n");
+
+ /* settings for retry */
+ i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+ }
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | CALIBRATION_DONE |
+ SLEEP_IN | SLEEP_OUT |
+ PROGRAM_LOAD_DONE | ERROR);
+
+ release_firmware(firmware);
+
+ if (retry >= FIRMWARE_RETRY_MAX)
+ return -EBUSY;
+
+ return 0;
+}
+
+static bool swap_xy;
+module_param(swap_xy, bool, S_IRUGO);
+MODULE_PARM_DESC(swap_xy, "Swap X-axis and Y-axis");
+
+static bool inv_x;
+module_param(inv_x, bool, S_IRUGO);
+MODULE_PARM_DESC(inv_x, "Invert X-axis");
+
+static bool inv_y;
+module_param(inv_y, bool, S_IRUGO);
+MODULE_PARM_DESC(inv_y, "Invert Y-axis");
+
+static int rohm_ts_device_init(struct i2c_client *client)
+{
+ u8 val;
+ int ret;
+
+ /*
+ * Wait 200usec for reset
+ */
+ udelay(200);
+
+ /* Release analog reset */
+ ret = i2c_smbus_write_byte_data(client, SYSTEM, ANALOG_POWER_ON);
+ if (ret < 0)
+ return ret;
+
+ /* Waiting for the analog warm-up, max. 200usec */
+ udelay(200);
+
+ /* clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ val = MAF_1SAMPLE;
+ if (swap_xy)
+ val |= SWAP_XY;
+ if (inv_x)
+ val |= INV_X;
+ if (inv_y)
+ val |= INV_Y;
+
+ i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+ i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0);
+ i2c_smbus_write_byte_data(client, COMMON_SETUP2, val);
+ i2c_smbus_write_byte_data(client, COMMON_SETUP3,
+ SEL_TBL_DEFAULT | EN_GESTURE | EN_MULTI);
+ i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE,
+ THRESHOLD_GESTURE_DEFAULT);
+
+ i2c_smbus_write_byte_data(client, INTERVAL_TIME, INTERVAL_TIME_DEFAULT);
+ i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ);
+ i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME,
+ PRM_SWOFF_TIME_DEFAULT);
+ i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT);
+ i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT);
+
+ /*
+ * Panel setup, these values change with the panel.
+ */
+ i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT);
+ i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT);
+ i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT);
+ i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT);
+ i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH,
+ THRESHOLD_TOUCH_DEFAULT);
+ i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT);
+ i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT);
+ i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT);
+
+ /* Fixed value settings */
+ i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST,
+ CALIBRATION_ADJUST_DEFAULT);
+ i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT);
+ i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON | DUALTOUCH_REG_ON);
+
+ ret = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME);
+ if (ret) {
+ dev_err(&client->dev, "Failed to firmware load\n");
+ return ret;
+ }
+
+ /*
+ * Manual calibration results are not changed in same environment.
+ * If the force calibration is performed,
+ * the controller will not require calibration request interrupt
+ * when the typical values are set to the calibration registers.
+ */
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
+ CALIBRATION_REG1_DEFAULT);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
+ CALIBRATION_REG2_DEFAULT);
+ i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
+ CALIBRATION_REG3_DEFAULT);
+
+ i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_OFF);
+ i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_ON);
+
+ /* Clear all interrupts */
+ i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ /* Enable coordinates update interrupt */
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ CALIBRATION_DONE | SLEEP_OUT | SLEEP_IN |
+ PROGRAM_LOAD_DONE);
+
+ i2c_smbus_write_byte_data(client, ERR_MASK,
+ PROGRAM_LOAD_ERR | CPU_TIMEOUT | ADC_TIMEOUT);
+
+ /* controller CPU power on */
+ i2c_smbus_write_byte_data(client, SYSTEM,
+ CPU_POWER_ON | ANALOG_POWER_ON);
+
+ return 0;
+}
+
+static int rohm_bu21023_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rohm_ts_data *ts;
+ struct device *dev = &client->dev;
+ struct input_dev *input_dev;
+ int ret;
+
+ ts = kzalloc(sizeof(struct rohm_ts_data), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ INIT_WORK(&ts->work, rohm_ts_work_func);
+
+ ts->client = client;
+ i2c_set_clientdata(client, ts);
+
+ ret = rohm_ts_device_init(client);
+ if (ret) {
+ dev_err(dev, "Failed to device initialization\n");
+ goto err_ts_free_exit;
+ }
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ ret = -ENOMEM;
+ dev_err(dev, "Failed to allocate input device\n");
+ goto err_ts_free_exit;
+ }
+
+ input_dev->name = BU21023_NAME;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ ts->input_dev = input_dev;
+
+ set_bit(EV_SYN, input_dev->evbit);
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0);
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ dev_err(dev, "Unable to register input device\n");
+ goto err_input_free_device_exit;
+ }
+
+ ts->workqueue = create_singlethread_workqueue("rohm_ts_wq");
+ if (!ts->workqueue) {
+ dev_err(dev, "Cannot create workqueue\n");
+ ret = -ENOMEM;
+ goto err_input_unregister_device_exit;
+ }
+
+ if (client->irq) {
+ ret = request_irq(client->irq, rohm_ts_irq_handler,
+ IRQF_TRIGGER_FALLING, client->name, ts);
+
+ /* If the request IRQ failed, use polling mode */
+ if (!ret)
+ ts->use_irq = 1;
+ }
+
+ hrtimer_init(&ts->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->hrtimer.function = rohm_ts_timer_func;
+ if (!ts->use_irq)
+ hrtimer_start(&ts->hrtimer, INACTIVE_POLLING_INTERVAL_KTIME,
+ HRTIMER_MODE_REL);
+
+ dev_info(dev, "%s mode\n", ts->use_irq ? "interrupt" : "polling");
+
+ return 0;
+
+err_input_unregister_device_exit:
+ input_unregister_device(input_dev);
+
+err_input_free_device_exit:
+ input_free_device(input_dev);
+
+err_ts_free_exit:
+ kfree(ts);
+
+ return ret;
+}
+
+static int rohm_bu21023_i2c_remove(struct i2c_client *client)
+{
+ struct rohm_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->use_irq)
+ free_irq(client->irq, ts);
+ else
+ hrtimer_cancel(&ts->hrtimer);
+
+ if (ts->workqueue)
+ destroy_workqueue(ts->workqueue);
+
+ input_unregister_device(ts->input_dev);
+
+ i2c_smbus_write_byte_data(client, SYSTEM,
+ ANALOG_POWER_ON | CPU_POWER_OFF);
+
+ i2c_smbus_write_byte_data(client, SYSTEM,
+ ANALOG_POWER_OFF | CPU_POWER_OFF);
+
+ kfree(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
+ {BU21023_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
+
+static struct i2c_driver rohm_bu21023_i2c_driver = {
+ .driver = {
+ .name = BU21023_NAME,
+ },
+ .probe = rohm_bu21023_i2c_probe,
+ .remove = rohm_bu21023_i2c_remove,
+ .id_table = rohm_bu21023_i2c_id,
+};
+
+module_i2c_driver(rohm_bu21023_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/rohm_bu21023.h b/drivers/input/touchscreen/rohm_bu21023.h
new file mode 100644
index 0000000..2db32848
--- /dev/null
+++ b/drivers/input/touchscreen/rohm_bu21023.h
@@ -0,0 +1,255 @@
+/*
+ * ROHM BU21023/24 Dual touch support resistive touch screen driver
+ * Copyright (C) 2012 ROHM CO.,LTD.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _BU21023_TS_H
+#define _BU21023_TS_H
+
+#define BU21023_NAME "bu21023_ts"
+#define BU21023_FIRMWARE_NAME "bu21023.bin"
+
+#define AXIS_ADJUST 4
+#define AXIS_OFFSET 8
+
+#define FIRMWARE_BLOCK_SIZE 32
+#define FIRMWARE_RETRY_MAX 4
+
+#define SAMPLING_DELAY 12 /* msec */
+
+#define CALIBRATION_RETRY_MAX 6
+
+#define ROHM_TS_ABS_X_MIN 40
+#define ROHM_TS_ABS_X_MAX 990
+#define ROHM_TS_ABS_Y_MIN 160
+#define ROHM_TS_ABS_Y_MAX 920
+
+/*
+ * BU21023GUL/BU21023MUV/BU21024FV-M registers map
+ */
+#define VADOUT_YP_H 0x00
+#define VADOUT_YP_L 0x01
+#define VADOUT_XP_H 0x02
+#define VADOUT_XP_L 0x03
+#define VADOUT_YN_H 0x04
+#define VADOUT_YN_L 0x05
+#define VADOUT_XN_H 0x06
+#define VADOUT_XN_L 0x07
+
+#define PRM1_X_H 0x08
+#define PRM1_X_L 0x09
+#define PRM1_Y_H 0x0a
+#define PRM1_Y_L 0x0b
+#define PRM2_X_H 0x0c
+#define PRM2_X_L 0x0d
+#define PRM2_Y_H 0x0e
+#define PRM2_Y_L 0x0f
+
+#define MLT_PRM_MONI_X 0x10
+#define MLT_PRM_MONI_Y 0x11
+
+#define DEBUG_MONI_1 0x12
+#define DEBUG_MONI_2 0x13
+
+#define VADOUT_ZX_H 0x14
+#define VADOUT_ZX_L 0x15
+#define VADOUT_ZY_H 0x16
+#define VADOUT_ZY_L 0x17
+
+#define Z_PARAM_H 0x18
+#define Z_PARAM_L 0x19
+
+/*
+ * Value for VADOUT_*_L
+ */
+#define VADOUT_L_MASK 0x01
+
+/*
+ * Value for PRM*_*_L
+ */
+#define PRM_L_MASK 0x01
+
+#define POS_X1_H 0x20
+#define POS_X1_L 0x21
+#define POS_Y1_H 0x22
+#define POS_Y1_L 0x23
+#define POS_X2_H 0x24
+#define POS_X2_L 0x25
+#define POS_Y2_H 0x26
+#define POS_Y2_L 0x27
+
+/*
+ * Value for POS_*_L
+ */
+#define POS_L_MASK 0x01
+
+#define TOUCH 0x28
+#define TOUCH_DETECT 0x01
+
+#define TOUCH_GESTURE 0x29
+#define SINGLE_TOUCH 0x01
+#define DUAL_TOUCH 0x03
+#define TOUCH_MASK 0x03
+#define CALIBRATION_REQUEST 0x04
+#define CALIBRATION_STATUS 0x08
+#define CALIBRATION_MASK 0x0c
+#define GESTURE_SPREAD 0x10
+#define GESTURE_PINCH 0x20
+#define GESTURE_ROTATE_R 0x40
+#define GESTURE_ROTATE_L 0x80
+
+#define INT_STATUS 0x2a
+#define INT_MASK 0x3d
+#define INT_CLEAR 0x3e
+
+/*
+ * Values for INT_*
+ */
+#define COORD_UPDATE 0x01
+#define CALIBRATION_DONE 0x02
+#define SLEEP_IN 0x04
+#define SLEEP_OUT 0x08
+#define PROGRAM_LOAD_DONE 0x10
+#define ERROR 0x80
+
+#define ERR_STATUS 0x2b
+#define ERR_MASK 0x3f
+
+/*
+ * Values for ERR_*
+ */
+#define ADC_TIMEOUT 0x01
+#define CPU_TIMEOUT 0x02
+#define CALIBRATION_ERR 0x04
+#define PROGRAM_LOAD_ERR 0x10
+
+#define COMMON_SETUP1 0x30
+#define PROGRAM_LOAD_HOST 0x02
+#define PROGRAM_LOAD_EEPROM 0x03
+#define CENSOR_4PORT 0x04
+#define CENSOR_8PORT 0x00 /* Not supported by BU21023 */
+#define CALIBRATION_TYPE_DEFAULT 0x08
+#define CALIBRATION_TYPE_SPECIAL 0x00
+#define INT_ACTIVE_HIGH 0x10
+#define INT_ACTIVE_LOW 0x00
+#define AUTO_CALIBRATION 0x40
+#define MANUAL_CALIBRATION 0x00
+#define COMMON_SETUP1_DEFAULT 0x4e
+
+#define COMMON_SETUP2 0x31
+#define MAF_NONE 0x00
+#define MAF_1SAMPLE 0x01
+#define MAF_3SAMPLES 0x02
+#define MAF_5SAMPLES 0x03
+#define INV_Y 0x04
+#define INV_X 0x08
+#define SWAP_XY 0x10
+
+#define COMMON_SETUP3 0x32
+#define EN_SLEEP 0x01
+#define EN_MULTI 0x02
+#define EN_GESTURE 0x04
+#define EN_INTVL 0x08
+#define SEL_STEP 0x10
+#define SEL_MULTI 0x20
+#define SEL_TBL_DEFAULT 0x40
+
+#define INTERVAL_TIME 0x33
+#define INTERVAL_TIME_DEFAULT 0x10
+
+#define STEP_X 0x34
+#define STEP_X_DEFAULT 0x41
+
+#define STEP_Y 0x35
+#define STEP_Y_DEFAULT 0x8d
+
+#define OFFSET_X 0x38
+#define OFFSET_X_DEFAULT 0x0c
+
+#define OFFSET_Y 0x39
+#define OFFSET_Y_DEFAULT 0x0c
+
+#define THRESHOLD_TOUCH 0x3a
+#define THRESHOLD_TOUCH_DEFAULT 0xa0
+
+#define THRESHOLD_GESTURE 0x3b
+#define THRESHOLD_GESTURE_DEFAULT 0x17
+
+#define SYSTEM 0x40
+#define ANALOG_POWER_ON 0x01
+#define ANALOG_POWER_OFF 0x00
+#define CPU_POWER_ON 0x02
+#define CPU_POWER_OFF 0x00
+
+#define FORCE_CALIBRATION 0x42
+#define FORCE_CALIBRATION_ON 0x01
+#define FORCE_CALIBRATION_OFF 0x00
+
+#define CPU_FREQ 0x50 /* 10 / (reg + 1) MHz */
+#define CPU_FREQ_10MHZ 0x00
+#define CPU_FREQ_5MHZ 0x01
+#define CPU_FREQ_1MHZ 0x09
+
+#define EEPROM_ADDR 0x51
+
+#define CALIBRATION_ADJUST 0x52
+#define CALIBRATION_ADJUST_DEFAULT 0x00
+
+#define THRESHOLD_SLEEP_IN 0x53
+
+#define EVR_XY 0x56
+#define EVR_XY_DEFAULT 0x10
+
+#define PRM_SWOFF_TIME 0x57
+#define PRM_SWOFF_TIME_DEFAULT 0x04
+
+#define PROGRAM_VERSION 0x5f
+
+#define ADC_CTRL 0x60
+#define ADC_DIV_MASK 0x1f /* The minimum value is 4 */
+#define ADC_DIV_DEFAULT 0x08
+
+#define ADC_WAIT 0x61
+#define ADC_WAIT_DEFAULT 0x0a
+
+#define SWCONT 0x62
+#define SWCONT_DEFAULT 0x0f
+
+#define EVR_X 0x63
+#define EVR_X_DEFAULT 0x86
+
+#define EVR_Y 0x64
+#define EVR_Y_DEFAULT 0x64
+
+#define TEST1 0x65
+#define DUALTOUCH_STABILIZE_ON 0x01
+#define DUALTOUCH_STABILIZE_OFF 0x00
+#define DUALTOUCH_REG_ON 0x20
+#define DUALTOUCH_REG_OFF 0x00
+
+#define CALIBRATION_REG1 0x68
+#define CALIBRATION_REG1_DEFAULT 0xd9
+
+#define CALIBRATION_REG2 0x69
+#define CALIBRATION_REG2_DEFAULT 0x36
+
+#define CALIBRATION_REG3 0x6a
+#define CALIBRATION_REG3_DEFAULT 0x32
+
+#define EX_ADDR_H 0x70
+#define EX_ADDR_L 0x71
+#define EX_WDAT 0x72
+#define EX_RDAT 0x73
+#define EX_CHK_SUM1 0x74
+#define EX_CHK_SUM2 0x75
+#define EX_CHK_SUM3 0x76
+
+#endif /* _BU21023_TS_H */
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Pramod Gurav @ 2014-07-31 11:54 UTC (permalink / raw)
To: Yoichi Yuasa; +Cc: Dmitry Torokhov, linux-input
In-Reply-To: <20140731195434.d141b39f3920686485c64191@linux-mips.org>
Hi Yoichi,
On Thursday 31 July 2014 04:24 PM, Yoichi Yuasa wrote:
> Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
> ---
> drivers/input/touchscreen/Kconfig | 11 +
> drivers/input/touchscreen/Makefile | 1 +
> drivers/input/touchscreen/rohm_bu21023.c | 791 ++++++++++++++++++++++++++++++
> drivers/input/touchscreen/rohm_bu21023.h | 255 ++++++++++
> 4 files changed, 1058 insertions(+)
[snip]
> +
> +/*
> + * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24
> + * @adap: Handle to I2C bus
> + * @msgs: combined messages to execute
> + * @num: Number of messages to be executed.
> + *
> + * Returns negative errno, else the number of messages executed.
> + *
> + * Note
> + * In BU21023/24 burst read, stop condition is needed after "address write".
> + * Therefore, transmission is performed in 2 steps.
> + */
> +static inline int rohm_i2c_burst_read(struct i2c_adapter *adap,
> + struct i2c_msg *msgs, int num)
> +{
> + int ret, i;
> +
> + if (!adap->algo->master_xfer) {
> + dev_dbg(&adap->dev, "I2C level transfers not supported\n");
Should it be dev_err?
> + return -EOPNOTSUPP;
> + }
> +
> + i2c_lock_adapter(adap);
> +
> + for (i = 0; i < num; i++) {
> + ret = __i2c_transfer(adap, &msgs[i], 1);
.
[snip]
.
> +
> + return 0;
> +}
> +
> +static int rohm_bu21023_i2c_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct rohm_ts_data *ts;
> + struct device *dev = &client->dev;
> + struct input_dev *input_dev;
> + int ret;
> +
> + ts = kzalloc(sizeof(struct rohm_ts_data), GFP_KERNEL);
Can you please move to managed resources? devm_kzalloc in this case?
> + if (!ts)
> + return -ENOMEM;
> +
> + INIT_WORK(&ts->work, rohm_ts_work_func);
> +
> + ts->client = client;
> + i2c_set_clientdata(client, ts);
> +
> + ret = rohm_ts_device_init(client);
> + if (ret) {
> + dev_err(dev, "Failed to device initialization\n");
> + goto err_ts_free_exit;
> + }
> +
> + input_dev = input_allocate_device();
Same here as well. You can use devm_input_allocate_device here. These
helps in error handling and clean unbinding of driver.
> + if (!input_dev) {
> + ret = -ENOMEM;
> + dev_err(dev, "Failed to allocate input device\n");
> + goto err_ts_free_exit;
> + }
> +
> + input_dev->name = BU21023_NAME;
> + input_dev->id.bustype = BUS_I2C;
> + input_dev->dev.parent = &client->dev;
> +
> + ts->input_dev = input_dev;
> +
> + set_bit(EV_SYN, input_dev->evbit);
> + set_bit(EV_KEY, input_dev->evbit);
> + set_bit(EV_ABS, input_dev->evbit);
> +
> + input_set_abs_params(input_dev, ABS_MT_POSITION_X,
> + ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0);
> + input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
> + ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0);
> +
> + ret = input_register_device(input_dev);
> + if (ret) {
> + dev_err(dev, "Unable to register input device\n");
> + goto err_input_free_device_exit;
> + }
> +
> + ts->workqueue = create_singlethread_workqueue("rohm_ts_wq");
> + if (!ts->workqueue) {
> + dev_err(dev, "Cannot create workqueue\n");
> + ret = -ENOMEM;
> + goto err_input_unregister_device_exit;
> + }
> +
> + if (client->irq) {
> + ret = request_irq(client->irq, rohm_ts_irq_handler,
> + IRQF_TRIGGER_FALLING, client->name, ts);
Use devm_request_irq.
> +
> + /* If the request IRQ failed, use polling mode */
> + if (!ret)
> + ts->use_irq = 1;
> + }
> +
> + hrtimer_init(&ts->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> + ts->hrtimer.function = rohm_ts_timer_func;
> + if (!ts->use_irq)
> + hrtimer_start(&ts->hrtimer, INACTIVE_POLLING_INTERVAL_KTIME,
> + HRTIMER_MODE_REL);
> +
> + dev_info(dev, "%s mode\n", ts->use_irq ? "interrupt" : "polling");
> +
> + return 0;
> +
> +err_input_unregister_device_exit:
> + input_unregister_device(input_dev);
> +
> +err_input_free_device_exit:
> + input_free_device(input_dev);
> +
> +err_ts_free_exit:
> + kfree(ts);
> +
> + return ret;
You can get rid of these lables with managed resources as they will be
release automatically when device is unbinded.
> +}
> +
> +static int rohm_bu21023_i2c_remove(struct i2c_client *client)
> +{
> + struct rohm_ts_data *ts = i2c_get_clientdata(client);
> +
> + if (ts->use_irq)
> + free_irq(client->irq, ts);
Use of Managed resources will get rid of this as well.
> + else
> + hrtimer_cancel(&ts->hrtimer);
> +
> + if (ts->workqueue)
> + destroy_workqueue(ts->workqueue);
> +
> + input_unregister_device(ts->input_dev);
This too.
> +
> + i2c_smbus_write_byte_data(client, SYSTEM,
> + ANALOG_POWER_ON | CPU_POWER_OFF);
> +
> + i2c_smbus_write_byte_data(client, SYSTEM,
> + ANALOG_POWER_OFF | CPU_POWER_OFF);
> +
> + kfree(ts);
This too.
> +
> + return 0;
> +}
> +
> +static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
> + {BU21023_NAME, 0},
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
> +
> +static struct i2c_driver rohm_bu21023_i2c_driver = {
> + .driver = {
> + .name = BU21023_NAME,
> + },
> + .probe = rohm_bu21023_i2c_probe,
> + .remove = rohm_bu21023_i2c_remove,
> + .id_table = rohm_bu21023_i2c_id,
> +};
> +
> +module_i2c_driver(rohm_bu21023_i2c_driver);
> +
> +MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver");
> +MODULE_LICENSE("GPL");
Make it GPL v2.
MODULE_AUTHOR missing.
> diff --git a/drivers/input/touchscreen/rohm_bu21023.h b/drivers/input/touchscreen/rohm_bu21023.h
> new file mode 100644
> index 0000000..2db32848
> --- /dev/null
> +++ b/drivers/input/touchscreen/rohm_bu21023.h
[snip]
>
^ permalink raw reply
* Re: [PATCH v3 4/7] Input - wacom: Check for bluetooth protocol while setting OLEDs
From: Ping Cheng @ 2014-07-31 15:56 UTC (permalink / raw)
To: Przemo Firszt
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Jason Gerecke,
linux-kernel@vger.kernel.org, linux-input
In-Reply-To: <1406674412.24026.1.camel@fedora-lan>
On Tue, Jul 29, 2014 at 3:53 PM, Przemo Firszt <przemo@firszt.eu> wrote:
> Dnia 2014-07-29, wto o godzinie 14:43 -0400, Benjamin Tissoires pisze:
>> Bluetooth Intuos 4 use 1-bit definition while the USB ones use a 4-bits
>> definition. This changes the size of the raw image we receive, and thus
>> the kernel will only accept 1-bit images for Bluetooth and 4-bits for
>> USB.
>>
>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> ---
>> drivers/hid/wacom_sys.c | 29 +++++++++++++++++++++--------
>> 1 file changed, 21 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
>> index f5c9c56..a12cd9c 100644
>> --- a/drivers/hid/wacom_sys.c
>> +++ b/drivers/hid/wacom_sys.c
>> @@ -20,6 +20,7 @@
>> #define WAC_CMD_LED_CONTROL 0x20
>> #define WAC_CMD_ICON_START 0x21
>> #define WAC_CMD_ICON_XFER 0x23
>> +#define WAC_CMD_ICON_BT_XFER 0x26
>> #define WAC_CMD_RETRIES 10
>>
>> static int wacom_get_report(struct hid_device *hdev, u8 type, u8 id,
>> @@ -526,12 +527,14 @@ static int wacom_led_control(struct wacom *wacom)
>> return retval;
>> }
>>
>> -static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
>> +static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id,
>> + const unsigned len, const void *img)
>> {
>> unsigned char *buf;
>> int i, retval;
>> + const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */
>>
>> - buf = kzalloc(259, GFP_KERNEL);
>> + buf = kzalloc(chunk_len + 3 , GFP_KERNEL);
>> if (!buf)
>> return -ENOMEM;
>>
>> @@ -543,15 +546,15 @@ static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *im
>> if (retval < 0)
>> goto out;
>>
>> - buf[0] = WAC_CMD_ICON_XFER;
>> + buf[0] = xfer_id;
>> buf[1] = button_id & 0x07;
>> for (i = 0; i < 4; i++) {
>> buf[2] = i;
>> - memcpy(buf + 3, img + i * 256, 256);
>> + memcpy(buf + 3, img + i * chunk_len, chunk_len);
>>
>> retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT,
>> - WAC_CMD_ICON_XFER,
>> - buf, 259, WAC_CMD_RETRIES);
>> + xfer_id, buf, chunk_len + 3,
>> + WAC_CMD_RETRIES);
>> if (retval < 0)
>> break;
>> }
>> @@ -652,13 +655,23 @@ static ssize_t wacom_button_image_store(struct device *dev, int button_id,
>> struct hid_device *hdev = container_of(dev, struct hid_device, dev);
>> struct wacom *wacom = hid_get_drvdata(hdev);
>> int err;
>> + unsigned len;
>> + u8 xfer_id;
>>
>> - if (count != 1024)
>> + if (hdev->bus == BUS_BLUETOOTH) {
>> + len = 256;
>> + xfer_id = WAC_CMD_ICON_BT_XFER;
>> + } else {
>> + len = 1024;
>> + xfer_id = WAC_CMD_ICON_XFER;
>> + }
>> +
>> + if (count != len)
>> return -EINVAL;
>>
>> mutex_lock(&wacom->lock);
>>
>> - err = wacom_led_putimage(wacom, button_id, buf);
>> + err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf);
>>
>> mutex_unlock(&wacom->lock);
>
> Signed-off-by: Przemo Firszt <przemo@firszt.eu>
Reviewed-by: Ping Cheng <pingc@wacom.com>
> I'll test the whole series tomorrow.
I'd like to see Przemo's Tested-by tag here as well. Przemo, are you
done with your testing?
Thank you Przemo and Benjamin for your effort in making this
transition smooth and successful. We, at Wacom, are very grateful to
be part of this great community.
Cheers,
Ping
^ permalink raw reply
* Re: [PATCH] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Dmitry Torokhov @ 2014-07-31 17:16 UTC (permalink / raw)
To: Yoichi Yuasa; +Cc: linux-input
In-Reply-To: <20140731195434.d141b39f3920686485c64191@linux-mips.org>
Hi Yuichi,
On Thu, Jul 31, 2014 at 07:54:34PM +0900, Yoichi Yuasa wrote:
> Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
I few high-level comments:
- please get rid of polling - it is not useful in production mode;
- switch to threaded interrupts so that you do not need to manage
workqueue/work/timers;
- new drivers should use MT-B protocol with proper contact tracking. If device
does not do good job at tracking contacts you can use input's core matching
algorithm (input_mt_assign_slots).
- please provide ST emulation as well (input_mt_report_pointer_emulation).
- the way you requesting firmware in probe path means you need to build
firmware image into kernel or be careful how you pack it to avoid timeouts on
boot. Since the device properties are not changing you might want to postpone
that until somebody tries to open the device.
- please add error handling for IO operations.
- managed resources simplify the code.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: PATCH hid: Implement mode switching on Logitech gaming wheels accordingly to the documentation
From: simon @ 2014-07-31 17:29 UTC (permalink / raw)
To: "Michal Malý"
Cc: Jiri Kosina, linux-input, linux-kernel@vger.kernel.org, edwin,
elias.vds@gmail.com, simon@mungewell.org, Roland Bosa
In-Reply-To: <3335238.KGDcEM6DjH@sigyn>
> +#define LG4FF_MSW_MIN 0
> +#define LG4FF_MSW_NATIVE 0 /* Switch device to its native mode (if
> applicable) */
> +#define LG4FF_MSW_DONTSWITCH 1 /* Leave device in its current mode */
> +#define LG4FF_MSW_DFP 2 /* Switch device so that it emulates Driving
> Force Pro (only G25, G27, DFGT) */
> +#define LG4FF_MSW_G25 3 /* Switch device so that it emulates G25 (only
> G27) */
> +#define LG4FF_MSW_MAX 3
Just to let everyone know I am looking at this patch, and have emailed
Michal some questions on whether it covers all options for control.
Cheers,
Simon.
^ permalink raw reply
* Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
From: Dmitry Torokhov @ 2014-07-31 17:53 UTC (permalink / raw)
To: Christopher Heiny
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Linus Walleij, Benjamin Tissoires,
David Herrmann, Jiri Kosina
In-Reply-To: <1394675637-23853-5-git-send-email-cheiny@synaptics.com>
Hi Christopher,
On Wed, Mar 12, 2014 at 06:53:56PM -0700, Christopher Heiny wrote:
> Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function
implementation. By that I mean that it does not declare itself as struct
rmi_function_handler and does not rely on RMI core to bind itself to the device
if device supports it.
By the way, isn't rmi_extract_u32() is the same as le32_to_cpup()?
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH] Input: imx_keypad - Remove ifdef
From: Fabio Estevam @ 2014-07-31 18:42 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: linux-input, Fabio Estevam
From: Fabio Estevam <fabio.estevam@freescale.com>
We can annonate the suspend/resume functions with '__maybe_unused' and get rid
of the ifdef, which makes the code smaller and simpler
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
drivers/input/keyboard/imx_keypad.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 8280cb1..20a99c3 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -531,8 +531,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -552,7 +551,7 @@ static int imx_kbd_suspend(struct device *dev)
return 0;
}
-static int imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -575,7 +574,6 @@ err_clk:
return ret;
}
-#endif
static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
--
1.9.1
^ permalink raw reply related
* [PATCH v5] input: drv260x: Add TI drv260x haptics driver
From: Dan Murphy @ 2014-07-31 19:14 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, devicetree, mark.rutland, madcatxster, simon,
elias.vds, dmitry.torokhov, Dan Murphy
Add the TI drv260x haptics/vibrator driver.
This device uses the input force feedback
to produce a wave form to driver an
ERM or LRA actuator device.
The initial driver supports the devices
real time playback mode. But the device
has additional wave patterns in ROM.
This functionality will be added in
future patchsets.
Product data sheet is located here:
http://www.ti.com/product/drv2605
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
v5 - Move register defines to c file and rm header file, error check
init in probe, fixed identation, remove empty labels in probe
and just return on fail and removed the remove callback and function.
Did not factor out the suspend into a stop function. - https://patchwork.kernel.org/patch/4649631/
v4 - Convert regulator to devm, added error checking where required,
updated bindings doc, moved dt parsing to separate call and made platform
data the first data point, moved vibrator enable and mode programming from
play entry to worker thread, added user check and input mutex in suspend/resume
calls, moved platform data to individual file and into include platform-data directory,
removed file names from file headers - https://patchwork.kernel.org/patch/4642221/
v3 - Updated binding doc, changed to memless device, updated input alloc to
devm, removed mutex locking, add sanity checks for mode and library - https://patchwork.kernel.org/patch/4635421/
v2 - Fixed binding doc and patch headline - https://patchwork.kernel.org/patch/4619641/
.../devicetree/bindings/input/ti,drv260x.txt | 50 ++
drivers/input/misc/Kconfig | 9 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/drv260x.c | 697 ++++++++++++++++++++
include/dt-bindings/input/ti-drv260x.h | 35 +
include/linux/platform_data/drv260x-pdata.h | 29 +
6 files changed, 821 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/ti,drv260x.txt
create mode 100644 drivers/input/misc/drv260x.c
create mode 100644 include/dt-bindings/input/ti-drv260x.h
create mode 100644 include/linux/platform_data/drv260x-pdata.h
diff --git a/Documentation/devicetree/bindings/input/ti,drv260x.txt b/Documentation/devicetree/bindings/input/ti,drv260x.txt
new file mode 100644
index 0000000..8e6970d
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,drv260x.txt
@@ -0,0 +1,50 @@
+Texas Instruments - drv260x Haptics driver family
+
+The drv260x family serial control bus communicates through I2C protocols
+
+Required properties:
+ - compatible - One of:
+ "ti,drv2604" - DRV2604
+ "ti,drv2605" - DRV2605
+ "ti,drv2605l" - DRV2605L
+ - reg - I2C slave address
+ - supply- Required supply regulators are:
+ "vbat" - battery voltage
+ - mode - Power up mode of the chip (defined in include/dt-bindings/input/ti-drv260x.h)
+ DRV260X_LRA_MODE - Linear Resonance Actuator mode (Piezoelectric)
+ DRV260X_LRA_NO_CAL_MODE - This is a LRA Mode but there is no calibration
+ sequence during init. And the device is configured for real
+ time playback mode (RTP mode).
+ DRV260X_ERM_MODE - Eccentric Rotating Mass mode (Rotary vibrator)
+ - library-sel - These are ROM based waveforms pre-programmed into the IC.
+ This should be set to set the library to use at power up.
+ (defined in include/dt-bindings/input/ti-drv260x.h)
+ DRV260X_LIB_A - Pre-programmed Library
+ DRV260X_LIB_B - Pre-programmed Library
+ DRV260X_LIB_C - Pre-programmed Library
+ DRV260X_LIB_D - Pre-programmed Library
+ DRV260X_LIB_E - Pre-programmed Library
+ DRV260X_LIB_F - Pre-programmed Library
+
+Optional properties:
+ - enable-gpio - gpio pin to enable/disable the device.
+ - vib_rated_voltage - The rated voltage of the actuator in millivolts.
+ If this is not set then the value will be defaulted to
+ 3.2 v.
+ - vib_overdrive_voltage - The overdrive voltage of the actuator in millivolts.
+ If this is not set then the value will be defaulted to
+ 3.2 v.
+Example:
+
+drv2605l: drv2605l@5a {
+ compatible = "ti,drv2605l";
+ reg = <0x5a>;
+ enable-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+ mode = <DRV260X_LRA_MODE>;
+ library-sel = <DRV260X_LIB_SEL_DEFAULT>;
+ vib-rated-voltage = <3200>;
+ vib-overdriver-voltage = <3200>;
+};
+
+For more product information please see the link below:
+http://www.ti.com/product/drv2605
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 2ff4425..99f6762 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -676,4 +676,13 @@ config INPUT_SOC_BUTTON_ARRAY
To compile this driver as a module, choose M here: the
module will be called soc_button_array.
+config INPUT_DRV260X_HAPTICS
+ tristate "TI DRV260X haptics support"
+ depends on INPUT && I2C
+ help
+ Say Y to enable support for the TI DRV260X haptics driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called drv260x-haptics.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 4955ad3..d8ef3c7 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -64,3 +64,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
new file mode 100644
index 0000000..6ccdeff
--- /dev/null
+++ b/drivers/input/misc/drv260x.c
@@ -0,0 +1,697 @@
+/*
+ * DRV260X haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2014 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#include <dt-bindings/input/ti-drv260x.h>
+#include <linux/platform_data/drv260x-pdata.h>
+
+#define DRV260X_STATUS 0x0
+#define DRV260X_MODE 0x1
+#define DRV260X_RT_PB_IN 0x2
+#define DRV260X_LIB_SEL 0x3
+#define DRV260X_WV_SEQ_1 0x4
+#define DRV260X_WV_SEQ_2 0x5
+#define DRV260X_WV_SEQ_3 0x6
+#define DRV260X_WV_SEQ_4 0x7
+#define DRV260X_WV_SEQ_5 0x8
+#define DRV260X_WV_SEQ_6 0x9
+#define DRV260X_WV_SEQ_7 0xa
+#define DRV260X_WV_SEQ_8 0xb
+#define DRV260X_GO 0xc
+#define DRV260X_OVERDRIVE_OFF 0xd
+#define DRV260X_SUSTAIN_P_OFF 0xe
+#define DRV260X_SUSTAIN_N_OFF 0xf
+#define DRV260X_BRAKE_OFF 0x10
+#define DRV260X_A_TO_V_CTRL 0x11
+#define DRV260X_A_TO_V_MIN_INPUT 0x12
+#define DRV260X_A_TO_V_MAX_INPUT 0x13
+#define DRV260X_A_TO_V_MIN_OUT 0x14
+#define DRV260X_A_TO_V_MAX_OUT 0x15
+#define DRV260X_RATED_VOLT 0x16
+#define DRV260X_OD_CLAMP_VOLT 0x17
+#define DRV260X_CAL_COMP 0x18
+#define DRV260X_CAL_BACK_EMF 0x19
+#define DRV260X_FEEDBACK_CTRL 0x1a
+#define DRV260X_CTRL1 0x1b
+#define DRV260X_CTRL2 0x1c
+#define DRV260X_CTRL3 0x1d
+#define DRV260X_CTRL4 0x1e
+#define DRV260X_CTRL5 0x1f
+#define DRV260X_LRA_LOOP_PERIOD 0x20
+#define DRV260X_VBAT_MON 0x21
+#define DRV260X_LRA_RES_PERIOD 0x22
+#define DRV260X_MAX_REG 0x23
+
+#define DRV260X_ALLOWED_R_BYTES 25
+#define DRV260X_ALLOWED_W_BYTES 2
+#define DRV260X_MAX_RW_RETRIES 5
+#define DRV260X_I2C_RETRY_DELAY 10
+
+#define DRV260X_GO_BIT 0x01
+
+/* Library Selection */
+#define DRV260X_LIB_SEL_MASK 0x07
+#define DRV260X_LIB_SEL_RAM 0x0
+#define DRV260X_LIB_SEL_OD 0x1
+#define DRV260X_LIB_SEL_40_60 0x2
+#define DRV260X_LIB_SEL_60_80 0x3
+#define DRV260X_LIB_SEL_100_140 0x4
+#define DRV260X_LIB_SEL_140_PLUS 0x5
+
+#define DRV260X_LIB_SEL_HIZ_MASK 0x10
+#define DRV260X_LIB_SEL_HIZ_EN 0x01
+#define DRV260X_LIB_SEL_HIZ_DIS 0
+
+/* Mode register */
+#define DRV260X_STANDBY (1 << 6)
+#define DRV260X_STANDBY_MASK 0x40
+#define DRV260X_INTERNAL_TRIGGER 0x00
+#define DRV260X_EXT_TRIGGER_EDGE 0x01
+#define DRV260X_EXT_TRIGGER_LEVEL 0x02
+#define DRV260X_PWM_ANALOG_IN 0x03
+#define DRV260X_AUDIOHAPTIC 0x04
+#define DRV260X_RT_PLAYBACK 0x05
+#define DRV260X_DIAGNOSTICS 0x06
+#define DRV260X_AUTO_CAL 0x07
+
+/* Audio to Haptics Control */
+#define DRV260X_AUDIO_HAPTICS_PEAK_10MS (0 << 2)
+#define DRV260X_AUDIO_HAPTICS_PEAK_20MS (1 << 2)
+#define DRV260X_AUDIO_HAPTICS_PEAK_30MS (2 << 2)
+#define DRV260X_AUDIO_HAPTICS_PEAK_40MS (3 << 2)
+
+#define DRV260X_AUDIO_HAPTICS_FILTER_100HZ 0x00
+#define DRV260X_AUDIO_HAPTICS_FILTER_125HZ 0x01
+#define DRV260X_AUDIO_HAPTICS_FILTER_150HZ 0x02
+#define DRV260X_AUDIO_HAPTICS_FILTER_200HZ 0x03
+
+/* Min/Max Input/Output Voltages */
+#define DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT 0x19
+#define DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT 0x64
+#define DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT 0x19
+#define DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT 0xFF
+
+/* Feedback register */
+#define DRV260X_FB_REG_ERM_MODE 0x7f
+#define DRV260X_FB_REG_LRA_MODE (1 << 7)
+
+#define DRV260X_BRAKE_FACTOR_MASK 0x1f
+#define DRV260X_BRAKE_FACTOR_2X (1 << 0)
+#define DRV260X_BRAKE_FACTOR_3X (2 << 4)
+#define DRV260X_BRAKE_FACTOR_4X (3 << 4)
+#define DRV260X_BRAKE_FACTOR_6X (4 << 4)
+#define DRV260X_BRAKE_FACTOR_8X (5 << 4)
+#define DRV260X_BRAKE_FACTOR_16 (6 << 4)
+#define DRV260X_BRAKE_FACTOR_DIS (7 << 4)
+
+#define DRV260X_LOOP_GAIN_LOW 0xf3
+#define DRV260X_LOOP_GAIN_MED (1 << 2)
+#define DRV260X_LOOP_GAIN_HIGH (2 << 2)
+#define DRV260X_LOOP_GAIN_VERY_HIGH (3 << 2)
+
+#define DRV260X_BEMF_GAIN_0 0xfc
+#define DRV260X_BEMF_GAIN_1 (1 << 0)
+#define DRV260X_BEMF_GAIN_2 (2 << 0)
+#define DRV260X_BEMF_GAIN_3 (3 << 0)
+
+/* Control 1 register */
+#define DRV260X_AC_CPLE_EN (1 << 5)
+#define DRV260X_STARTUP_BOOST (1 << 7)
+
+/* Control 2 register */
+
+#define DRV260X_IDISS_TIME_45 0
+#define DRV260X_IDISS_TIME_75 (1 << 0)
+#define DRV260X_IDISS_TIME_150 (1 << 1)
+#define DRV260X_IDISS_TIME_225 0x03
+
+#define DRV260X_BLANK_TIME_45 (0 << 2)
+#define DRV260X_BLANK_TIME_75 (1 << 2)
+#define DRV260X_BLANK_TIME_150 (2 << 2)
+#define DRV260X_BLANK_TIME_225 (3 << 2)
+
+#define DRV260X_SAMP_TIME_150 (0 << 4)
+#define DRV260X_SAMP_TIME_200 (1 << 4)
+#define DRV260X_SAMP_TIME_250 (2 << 4)
+#define DRV260X_SAMP_TIME_300 (3 << 4)
+
+#define DRV260X_BRAKE_STABILIZER (1 << 6)
+#define DRV260X_UNIDIR_IN (0 << 7)
+#define DRV260X_BIDIR_IN (1 << 7)
+
+/* Control 3 Register */
+#define DRV260X_LRA_OPEN_LOOP (1 << 0)
+#define DRV260X_ANANLOG_IN (1 << 1)
+#define DRV260X_LRA_DRV_MODE (1 << 2)
+#define DRV260X_RTP_UNSIGNED_DATA (1 << 3)
+#define DRV260X_SUPPLY_COMP_DIS (1 << 4)
+#define DRV260X_ERM_OPEN_LOOP (1 << 5)
+#define DRV260X_NG_THRESH_0 (0 << 6)
+#define DRV260X_NG_THRESH_2 (1 << 6)
+#define DRV260X_NG_THRESH_4 (2 << 6)
+#define DRV260X_NG_THRESH_8 (3 << 6)
+
+/* Control 4 Register */
+#define DRV260X_AUTOCAL_TIME_150MS (0 << 4)
+#define DRV260X_AUTOCAL_TIME_250MS (1 << 4)
+#define DRV260X_AUTOCAL_TIME_500MS (2 << 4)
+#define DRV260X_AUTOCAL_TIME_1000MS (3 << 4)
+
+/**
+ * struct drv260x_data -
+ * @input_dev - Pointer to the input device
+ * @client - Pointer to the I2C client
+ * @regmap - Register map of the device
+ * @work - Work item used to off load the enable/disable of the vibration
+ * @enable_gpio - Pointer to the gpio used for enable/disabling
+ * @regulator - Pointer to the regulator for the IC
+ * @magnitude - Magnitude of the vibration event
+ * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA)
+ * @library - The vibration library to be used
+ * @rated_voltage - The rated_voltage of the actuator
+ * @overdriver_voltage - The over drive voltage of the actuator
+**/
+struct drv260x_data {
+ struct input_dev *input_dev;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct work_struct work;
+ struct gpio_desc *enable_gpio;
+ struct regulator *regulator;
+ u32 magnitude;
+ u32 mode;
+ u32 library;
+ int rated_voltage;
+ int overdrive_voltage;
+};
+
+static struct reg_default drv260x_reg_defs[] = {
+ { DRV260X_STATUS, 0xe0 },
+ { DRV260X_MODE, 0x40 },
+ { DRV260X_RT_PB_IN, 0x00},
+ { DRV260X_LIB_SEL, 0x00},
+ { DRV260X_WV_SEQ_1, 0x01},
+ { DRV260X_WV_SEQ_2, 0x00},
+ { DRV260X_WV_SEQ_3, 0x00},
+ { DRV260X_WV_SEQ_4, 0x00},
+ { DRV260X_WV_SEQ_5, 0x00},
+ { DRV260X_WV_SEQ_6, 0x00},
+ { DRV260X_WV_SEQ_7, 0x00},
+ { DRV260X_WV_SEQ_8, 0x00},
+ { DRV260X_GO, 0x00},
+ { DRV260X_OVERDRIVE_OFF, 0x00},
+ { DRV260X_SUSTAIN_P_OFF, 0x00},
+ { DRV260X_SUSTAIN_N_OFF, 0x00},
+ { DRV260X_BRAKE_OFF , 0x00},
+ { DRV260X_A_TO_V_CTRL , 0x05},
+ { DRV260X_A_TO_V_MIN_INPUT, 0x19},
+ { DRV260X_A_TO_V_MAX_INPUT, 0xff},
+ { DRV260X_A_TO_V_MIN_OUT, 0x19},
+ { DRV260X_A_TO_V_MAX_OUT, 0xff},
+ { DRV260X_RATED_VOLT, 0x3e},
+ { DRV260X_OD_CLAMP_VOLT, 0x8c},
+ { DRV260X_CAL_COMP, 0x0c},
+ { DRV260X_CAL_BACK_EMF, 0x6c},
+ { DRV260X_FEEDBACK_CTRL, 0x36},
+ { DRV260X_CTRL1, 0x93},
+ { DRV260X_CTRL2, 0xfa},
+ { DRV260X_CTRL3, 0xa0},
+ { DRV260X_CTRL4, 0x20},
+ { DRV260X_CTRL5, 0x80},
+ { DRV260X_LRA_LOOP_PERIOD, 0x33},
+ { DRV260X_VBAT_MON, 0x00},
+ { DRV260X_LRA_RES_PERIOD, 0x00},
+};
+
+/**
+ * Rated and Overdriver Voltages:
+ * Calculated using the formula r = v * 255 / 5.6
+ * where r is what will be written to the register
+ * and v is the rated or overdriver voltage of the actuator
+ **/
+#define DRV260X_DEF_RATED_VOLT 0x90
+#define DRV260X_DEF_OD_CLAMP_VOLT 0x90
+
+static int drv260x_calculate_voltage(int voltage)
+{
+ return (voltage * 255 / 5600);
+}
+
+static void drv260x_worker(struct work_struct *work)
+{
+ struct drv260x_data *haptics = container_of(work, struct drv260x_data, work);
+ int ret;
+
+ gpiod_set_value(haptics->enable_gpio, 1);
+ /* Data sheet says to wait 250us before trying to communicate */
+ udelay(250);
+
+ ret = regmap_write(haptics->regmap, DRV260X_MODE, DRV260X_RT_PLAYBACK);
+ if (ret != 0) {
+ dev_err(&haptics->client->dev,
+ "Failed to write set mode: %d\n", ret);
+ return;
+ }
+
+ ret = regmap_write(haptics->regmap, DRV260X_RT_PB_IN, haptics->magnitude);
+ if (ret != 0) {
+ dev_err(&haptics->client->dev,
+ "Failed to set magnitude: %d\n", ret);
+ }
+}
+
+static int drv260x_haptics_play(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct drv260x_data *haptics = input_get_drvdata(input);
+
+ haptics->mode = DRV260X_LRA_NO_CAL_MODE;
+ haptics->magnitude = 0;
+
+ if (effect->u.rumble.strong_magnitude ||
+ effect->u.rumble.weak_magnitude) {
+ if (effect->u.rumble.strong_magnitude > 0)
+ haptics->magnitude = effect->u.rumble.strong_magnitude;
+ else if (effect->u.rumble.weak_magnitude > 0)
+ haptics->magnitude = effect->u.rumble.weak_magnitude;
+ }
+
+ schedule_work(&haptics->work);
+
+ return 0;
+}
+
+static void drv260x_close(struct input_dev *input)
+{
+ struct drv260x_data *haptics = input_get_drvdata(input);
+ int ret;
+
+ cancel_work_sync(&haptics->work);
+
+ ret = regmap_write(haptics->regmap, DRV260X_MODE, DRV260X_STANDBY);
+ if (ret != 0) {
+ dev_err(&haptics->client->dev,
+ "Failed to write standby mode: %d\n", ret);
+ }
+
+ gpiod_set_value(haptics->enable_gpio, 0);
+}
+
+static const struct reg_default drv260x_lra_cal_regs[] = {
+ { DRV260X_MODE, DRV260X_AUTO_CAL },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2},
+ { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
+};
+
+static const struct reg_default drv260x_lra_init_regs[] = {
+ { DRV260X_MODE, DRV260X_RT_PLAYBACK},
+ { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS | DRV260X_AUDIO_HAPTICS_FILTER_125HZ},
+ { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT },
+ { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT },
+ { DRV260X_A_TO_V_MIN_OUT, DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT },
+ { DRV260X_A_TO_V_MAX_OUT, DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT },
+ { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_2X | DRV260X_LOOP_GAIN_MED | DRV260X_BEMF_GAIN_3 },
+ { DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
+ { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ANANLOG_IN },
+ { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
+};
+
+static const struct reg_default drv260x_erm_cal_regs[] = {
+ { DRV260X_MODE, DRV260X_AUTO_CAL },
+ { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT },
+ { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT },
+ { DRV260X_A_TO_V_MIN_OUT, DRV260X_AUDIO_HAPTICS_MIN_OUT_VOLT },
+ { DRV260X_A_TO_V_MAX_OUT, DRV260X_AUDIO_HAPTICS_MAX_OUT_VOLT },
+ { DRV260X_FEEDBACK_CTRL, DRV260X_BRAKE_FACTOR_3X | DRV260X_LOOP_GAIN_MED | DRV260X_BEMF_GAIN_2 },
+ { DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
+ { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 | DRV260X_BLANK_TIME_75 | DRV260X_SAMP_TIME_250 | DRV260X_IDISS_TIME_75 },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ERM_OPEN_LOOP },
+ { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
+};
+
+static int drv260x_init(struct drv260x_data *haptics)
+{
+ int ret;
+ unsigned int cal_buf;
+
+ ret = regmap_write(haptics->regmap,
+ DRV260X_RATED_VOLT, haptics->rated_voltage);
+ if (ret != 0)
+ goto write_failure;
+
+ ret = regmap_write(haptics->regmap,
+ DRV260X_OD_CLAMP_VOLT, haptics->overdrive_voltage);
+ if (ret != 0)
+ goto write_failure;
+
+ switch(haptics->mode) {
+ case DRV260X_LRA_MODE:
+ ret = regmap_register_patch(haptics->regmap,
+ drv260x_lra_cal_regs,
+ ARRAY_SIZE(drv260x_lra_cal_regs));
+ if (ret != 0)
+ goto write_failure;
+ break;
+ case DRV260X_ERM_MODE:
+ ret = regmap_register_patch(haptics->regmap,
+ drv260x_erm_cal_regs,
+ ARRAY_SIZE(drv260x_erm_cal_regs));
+ if (ret != 0)
+ goto write_failure;
+
+ ret = regmap_update_bits(haptics->regmap, DRV260X_LIB_SEL,
+ DRV260X_LIB_SEL_MASK,
+ haptics->library);
+ if (ret != 0)
+ goto write_failure;
+ break;
+ default:
+ ret = regmap_register_patch(haptics->regmap,
+ drv260x_lra_init_regs,
+ ARRAY_SIZE(drv260x_lra_init_regs));
+ if (ret != 0)
+ goto write_failure;
+
+ ret = regmap_update_bits(haptics->regmap, DRV260X_LIB_SEL,
+ DRV260X_LIB_SEL_MASK,
+ haptics->library);
+ if (ret != 0)
+ goto write_failure;
+
+ goto skip_go_bit;
+ break;
+ }
+
+ if (ret != 0) {
+ dev_err(&haptics->client->dev,
+ "Failed to write init registers: %d\n",
+ ret);
+ goto write_failure;
+ }
+
+ ret = regmap_write(haptics->regmap, DRV260X_GO, DRV260X_GO_BIT);
+ if (ret != 0)
+ goto write_failure;
+
+ do {
+ ret = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
+ if (ret != 0)
+ goto write_failure;
+ } while (cal_buf == DRV260X_GO_BIT || ret != 0);
+
+ return ret;
+
+write_failure:
+ dev_err(&haptics->client->dev,
+ "Failed to write init registers: %d\n",
+ ret);
+skip_go_bit:
+ return ret;
+}
+
+static const struct regmap_config drv260x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = DRV260X_MAX_REG,
+ .reg_defaults = drv260x_reg_defs,
+ .num_reg_defaults = ARRAY_SIZE(drv260x_reg_defs),
+ .cache_type = REGCACHE_NONE,
+};
+
+#ifdef CONFIG_OF
+static int drv260x_parse_dt(struct device_node *dev_node,
+ struct drv260x_data *haptics,
+ struct device *dev)
+{
+ int ret;
+ int voltage;
+
+ ret = of_property_read_u32(dev_node, "mode", &haptics->mode);
+ if (ret < 0) {
+ dev_err(dev, "%s: No entry for mode\n", __func__);
+
+ return ret;
+ }
+ ret = of_property_read_u32(dev_node, "library-sel",
+ &haptics->library);
+ if (ret < 0) {
+ dev_err(dev, "%s: No entry for library selection\n",
+ __func__);
+
+ return ret;
+ }
+ ret = of_property_read_u32(dev_node, "vib-rated-voltage",
+ &voltage);
+ if (!ret)
+ haptics->rated_voltage = drv260x_calculate_voltage(voltage);
+
+
+ ret = of_property_read_u32(dev_node, "vib-overdrive-voltage",
+ &voltage);
+ if (!ret)
+ haptics->overdrive_voltage = drv260x_calculate_voltage(voltage);
+
+ return ret;
+
+}
+#else
+static inline int drv260x_parse_dt(struct device *dev)
+{
+ dev_err(dev, "no platform data defined\n");
+
+ return -EINVAL;
+}
+#endif
+static int drv260x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct drv260x_data *haptics;
+ struct device_node *np = client->dev.of_node;
+ struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev);
+ int ret;
+
+ haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+ if (!haptics)
+ return -ENOMEM;
+
+ haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
+ haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
+
+ if (pdata) {
+ haptics->mode = pdata->mode;
+ haptics->library = pdata->library_selection;
+ if (pdata->vib_overdrive_voltage)
+ haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage);
+ if (pdata->vib_rated_voltage)
+ haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage);
+ } else if (np) {
+ ret = drv260x_parse_dt(np, haptics, &client->dev);
+ if (ret)
+ return ret;
+ } else {
+ dev_err(&client->dev, "Platform data not set\n");
+ return -ENODEV;
+ }
+
+
+ if (haptics->mode < DRV260X_LRA_MODE ||
+ haptics->mode > DRV260X_ERM_MODE) {
+ dev_err(&client->dev,
+ "Vibrator mode is invalid: %i\n",
+ haptics->mode);
+ return -EINVAL;
+ }
+
+ if (haptics->library < DRV260X_LIB_SEL_DEFAULT ||
+ haptics->library > DRV260X_LIB_F) {
+ dev_err(&client->dev,
+ "Library value is invalid: %i\n", haptics->library);
+ return -EINVAL;
+ }
+
+ haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+ if (IS_ERR(haptics->regulator)) {
+ ret = PTR_ERR(haptics->regulator);
+ dev_err(&client->dev,
+ "unable to get regulator, error: %d\n", ret);
+ return ret;
+ }
+
+ haptics->enable_gpio = devm_gpiod_get(&client->dev, "enable");
+ if (IS_ERR(haptics->enable_gpio)) {
+ ret = PTR_ERR(haptics->enable_gpio);
+ if (ret != -ENOENT && ret != -ENOSYS)
+ return ret;
+ haptics->enable_gpio = NULL;
+ } else {
+ gpiod_direction_output(haptics->enable_gpio, 1);
+ }
+
+ haptics->input_dev = devm_input_allocate_device(&client->dev);
+ if (haptics->input_dev == NULL) {
+ dev_err(&client->dev, "Failed to allocate input device\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ haptics->input_dev->name = "drv260x:haptics";
+ haptics->input_dev->dev.parent = client->dev.parent;
+ haptics->input_dev->close = drv260x_close;
+ input_set_drvdata(haptics->input_dev, haptics);
+ input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+ ret = input_ff_create_memless(haptics->input_dev, NULL,
+ drv260x_haptics_play);
+ if (ret < 0) {
+ dev_err(&client->dev, "input_ff_create() failed: %d\n",
+ ret);
+ return ret;
+ }
+
+ INIT_WORK(&haptics->work, drv260x_worker);
+
+ haptics->client = client;
+ i2c_set_clientdata(client, haptics);
+
+ haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
+ if (IS_ERR(haptics->regmap)) {
+ ret = PTR_ERR(haptics->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = drv260x_init(haptics);
+ if (ret < 0) {
+ dev_err(&client->dev, "Device init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = input_register_device(haptics->input_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "couldn't register input device: %d\n",
+ ret);
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int drv260x_suspend(struct device *dev)
+{
+ struct drv260x_data *haptics = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ if (haptics->input_dev->users) {
+ ret = regmap_update_bits(haptics->regmap,
+ DRV260X_MODE,
+ DRV260X_STANDBY_MASK,
+ DRV260X_STANDBY);
+ if (ret) {
+ dev_err(dev, "Failed to set standby mode\n");
+ goto out;
+ }
+
+ gpiod_set_value(haptics->enable_gpio, 0);
+
+ ret = regulator_disable(haptics->regulator);
+ if (ret)
+ dev_err(dev, "Failed to disable regulator\n");
+ }
+out:
+ mutex_unlock(&haptics->input_dev->mutex);
+ return ret;
+}
+
+static int drv260x_resume(struct device *dev)
+{
+ struct drv260x_data *haptics = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ if (haptics->input_dev->users) {
+ ret = regulator_enable(haptics->regulator);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator\n");
+ goto out;
+ }
+ ret = regmap_update_bits(haptics->regmap,
+ DRV260X_MODE,
+ DRV260X_STANDBY_MASK, 0);
+ if (ret) {
+ dev_err(dev, "Failed to unset standby mode\n");
+ goto out;
+ }
+
+ gpiod_set_value(haptics->enable_gpio, 1);
+ }
+
+out:
+ mutex_unlock(&haptics->input_dev->mutex);
+ return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
+
+static const struct i2c_device_id drv260x_id[] = {
+ { "drv2605l", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, drv260x_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id drv260x_of_match[] = {
+ { .compatible = "ti,drv2604", },
+ { .compatible = "ti,drv2604l", },
+ { .compatible = "ti,drv2605", },
+ { .compatible = "ti,drv2605l", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, drv260x_of_match);
+#endif
+
+static struct i2c_driver drv260x_driver = {
+ .probe = drv260x_probe,
+ .driver = {
+ .name = "drv260x-haptics",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(drv260x_of_match),
+ .pm = &drv260x_pm_ops,
+ },
+ .id_table = drv260x_id,
+};
+module_i2c_driver(drv260x_driver);
+
+MODULE_ALIAS("platform:drv260x-haptics");
+MODULE_DESCRIPTION("TI DRV260x haptics driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
diff --git a/include/dt-bindings/input/ti-drv260x.h b/include/dt-bindings/input/ti-drv260x.h
new file mode 100644
index 0000000..be7f245
--- /dev/null
+++ b/include/dt-bindings/input/ti-drv260x.h
@@ -0,0 +1,35 @@
+/*
+ * DRV260X haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2014 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_TI_DRV260X_H
+#define _DT_BINDINGS_TI_DRV260X_H
+
+/* Calibration Types */
+#define DRV260X_LRA_MODE 0x00
+#define DRV260X_LRA_NO_CAL_MODE 0x01
+#define DRV260X_ERM_MODE 0x02
+
+/* Library Selection */
+#define DRV260X_LIB_SEL_DEFAULT 0x00
+#define DRV260X_LIB_A 0x01
+#define DRV260X_LIB_B 0x02
+#define DRV260X_LIB_C 0x03
+#define DRV260X_LIB_D 0x04
+#define DRV260X_LIB_E 0x05
+#define DRV260X_LIB_F 0x06
+
+#endif
diff --git a/include/linux/platform_data/drv260x-pdata.h b/include/linux/platform_data/drv260x-pdata.h
new file mode 100644
index 0000000..4091a9b
--- /dev/null
+++ b/include/linux/platform_data/drv260x-pdata.h
@@ -0,0 +1,29 @@
+/*
+ * Platform data for DRV260X haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2014 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _LINUX_DRV260X_PDATA_H
+#define _LINUX_DRV260X_PDATA_H
+
+struct drv260x_platform_data {
+ int enable_gpio;
+ u32 library_selection;
+ u32 mode;
+ u32 vib_rated_voltage;
+ u32 vib_overdrive_voltage;
+};
+
+#endif
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v3 7/7] HID: remove hid-wacom Bluetooth driver
From: Przemo Firszt @ 2014-07-31 19:18 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Jason Gerecke,
linux-kernel, linux-input
In-Reply-To: <1406659385-3256-8-git-send-email-benjamin.tissoires@redhat.com>
Hi Benjamin,
Look like you pressed "y" when git send-email asked for charset:
Content-Type: text/plain; charset=y
It kills git am:
> fedora-lan:/home/przemo/sf/wacom-kernel
> $ git am ../linux-next/\[PATCH_v3_*
> Applying: Input - wacom: prepare the driver to include BT devices
> Applying: Input - wacom: handle Graphire BT tablets in wacom.ko
> Applying: Input - wacom: handle Intuos 4 BT in wacom.ko
> Applying: Input - wacom: Check for bluetooth protocol while setting OLEDs
> Applying: Input - wacom: Remove passing id for wacom_set_report
> Applying: Input - wacom: add copyright note and bump version to 2.0
> fatal: cannot convert from y to UTF-8
The rest of patches is OK, I'm testing them now.
Regards,
Przemo
Dnia 2014-07-29, wto o godzinie 14:43 -0400, Benjamin Tissoires pisze:
> Bluetooth Wacom tablets are now handled by the regular wacom.ko driver.
> Remove the now useless hid-wacom driver.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> ---
> drivers/hid/Kconfig | 10 +-
> drivers/hid/Makefile | 3 +-
> drivers/hid/hid-wacom.c | 971 ------------------------------------------------
> 3 files changed, 2 insertions(+), 982 deletions(-)
> delete mode 100644 drivers/hid/hid-wacom.c
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index b18bae6..354122b 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -762,21 +762,13 @@ config THRUSTMASTER_FF
> Rumble Force or Force Feedback Wheel.
>
> config HID_WACOM
> - tristate "Wacom Bluetooth devices support"
> - depends on HID
> - depends on LEDS_CLASS
> - select POWER_SUPPLY
> - ---help---
> - Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
> -
> -config HID_USB_WACOM
> tristate "Wacom Intuos/Graphire tablet support (USB)"
> depends on HID
> select POWER_SUPPLY
> select NEW_LEDS
> select LEDS_CLASS
> help
> - Say Y here if you want to use the USB version of the Wacom Intuos
> + Say Y here if you want to use the USB or BT version of the Wacom Intuos
> or Graphire tablet.
>
> To compile this driver as a module, choose M here: the
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 19ba7c3..2d7e149 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -116,10 +116,9 @@ obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
> obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
> obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
> obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
> -obj-$(CONFIG_HID_WACOM) += hid-wacom.o
>
> wacom-objs := wacom_wac.o wacom_sys.o
> -obj-$(CONFIG_HID_USB_WACOM) += wacom.o
> +obj-$(CONFIG_HID_WACOM) += wacom.o
> obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
> obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
> obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
> diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
> deleted file mode 100644
> index db2d07d..0000000
> --- a/drivers/hid/hid-wacom.c
> +++ /dev/null
> @@ -1,971 +0,0 @@
> -/*
> - * Bluetooth Wacom Tablet support
> - *
> - * Copyright (c) 1999 Andreas Gal
> - * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
> - * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
> - * Copyright (c) 2006-2007 Jiri Kosina
> - * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
> - * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
> - * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
> - * Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu>
> - */
> -
> -/*
> - * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/device.h>
> -#include <linux/hid.h>
> -#include <linux/module.h>
> -#include <linux/leds.h>
> -#include <linux/slab.h>
> -#include <linux/power_supply.h>
> -
> -#include "hid-ids.h"
> -
> -#define PAD_DEVICE_ID 0x0F
> -
> -#define WAC_CMD_LED_CONTROL 0x20
> -#define WAC_CMD_ICON_START_STOP 0x21
> -#define WAC_CMD_ICON_TRANSFER 0x26
> -
> -struct wacom_data {
> - __u16 tool;
> - __u16 butstate;
> - __u8 whlstate;
> - __u8 features;
> - __u32 id;
> - __u32 serial;
> - unsigned char high_speed;
> - __u8 battery_capacity;
> - __u8 power_raw;
> - __u8 ps_connected;
> - __u8 bat_charging;
> - struct power_supply battery;
> - struct power_supply ac;
> - __u8 led_selector;
> - struct led_classdev *leds[4];
> -};
> -
> -/*percent of battery capacity for Graphire
> - 8th value means AC online and show 100% capacity */
> -static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
> -/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
> -static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
> -
> -static enum power_supply_property wacom_battery_props[] = {
> - POWER_SUPPLY_PROP_PRESENT,
> - POWER_SUPPLY_PROP_CAPACITY,
> - POWER_SUPPLY_PROP_SCOPE,
> - POWER_SUPPLY_PROP_STATUS,
> -};
> -
> -static enum power_supply_property wacom_ac_props[] = {
> - POWER_SUPPLY_PROP_PRESENT,
> - POWER_SUPPLY_PROP_ONLINE,
> - POWER_SUPPLY_PROP_SCOPE,
> -};
> -
> -static void wacom_scramble(__u8 *image)
> -{
> - __u16 mask;
> - __u16 s1;
> - __u16 s2;
> - __u16 r1 ;
> - __u16 r2 ;
> - __u16 r;
> - __u8 buf[256];
> - int i, w, x, y, z;
> -
> - for (x = 0; x < 32; x++) {
> - for (y = 0; y < 8; y++)
> - buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
> - }
> -
> - /* Change 76543210 into GECA6420 as required by Intuos4 WL
> - * HGFEDCBA HFDB7531
> - */
> - for (x = 0; x < 4; x++) {
> - for (y = 0; y < 4; y++) {
> - for (z = 0; z < 8; z++) {
> - mask = 0x0001;
> - r1 = 0;
> - r2 = 0;
> - i = (x << 6) + (y << 4) + z;
> - s1 = buf[i];
> - s2 = buf[i+8];
> - for (w = 0; w < 8; w++) {
> - r1 |= (s1 & mask);
> - r2 |= (s2 & mask);
> - s1 <<= 1;
> - s2 <<= 1;
> - mask <<= 2;
> - }
> - r = r1 | (r2 << 1);
> - i = (x << 6) + (y << 4) + (z << 1);
> - image[i] = 0xFF & r;
> - image[i+1] = (0xFF00 & r) >> 8;
> - }
> - }
> - }
> -}
> -
> -static void wacom_set_image(struct hid_device *hdev, const char *image,
> - __u8 icon_no)
> -{
> - __u8 rep_data[68];
> - __u8 p[256];
> - int ret, i, j;
> -
> - for (i = 0; i < 256; i++)
> - p[i] = image[i];
> -
> - rep_data[0] = WAC_CMD_ICON_START_STOP;
> - rep_data[1] = 0;
> - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> - if (ret < 0)
> - goto err;
> -
> - rep_data[0] = WAC_CMD_ICON_TRANSFER;
> - rep_data[1] = icon_no & 0x07;
> -
> - wacom_scramble(p);
> -
> - for (i = 0; i < 4; i++) {
> - for (j = 0; j < 64; j++)
> - rep_data[j + 3] = p[(i << 6) + j];
> -
> - rep_data[2] = i;
> - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
> - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> - }
> -
> - rep_data[0] = WAC_CMD_ICON_START_STOP;
> - rep_data[1] = 0;
> -
> - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> -
> -err:
> - return;
> -}
> -
> -static void wacom_leds_set_brightness(struct led_classdev *led_dev,
> - enum led_brightness value)
> -{
> - struct device *dev = led_dev->dev->parent;
> - struct hid_device *hdev;
> - struct wacom_data *wdata;
> - unsigned char *buf;
> - __u8 led = 0;
> - int i;
> -
> - hdev = container_of(dev, struct hid_device, dev);
> - wdata = hid_get_drvdata(hdev);
> - for (i = 0; i < 4; ++i) {
> - if (wdata->leds[i] == led_dev)
> - wdata->led_selector = i;
> - }
> -
> - led = wdata->led_selector | 0x04;
> - buf = kzalloc(9, GFP_KERNEL);
> - if (buf) {
> - buf[0] = WAC_CMD_LED_CONTROL;
> - buf[1] = led;
> - buf[2] = value >> 2;
> - buf[3] = value;
> - /* use fixed brightness for OLEDs */
> - buf[4] = 0x08;
> - hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
> - HID_REQ_SET_REPORT);
> - kfree(buf);
> - }
> -
> - return;
> -}
> -
> -static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
> -{
> - struct wacom_data *wdata;
> - struct device *dev = led_dev->dev->parent;
> - int value = 0;
> - int i;
> -
> - wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
> -
> - for (i = 0; i < 4; ++i) {
> - if (wdata->leds[i] == led_dev) {
> - value = wdata->leds[i]->brightness;
> - break;
> - }
> - }
> -
> - return value;
> -}
> -
> -
> -static int wacom_initialize_leds(struct hid_device *hdev)
> -{
> - struct wacom_data *wdata = hid_get_drvdata(hdev);
> - struct led_classdev *led;
> - struct device *dev = &hdev->dev;
> - size_t namesz = strlen(dev_name(dev)) + 12;
> - char *name;
> - int i, ret;
> -
> - wdata->led_selector = 0;
> -
> - for (i = 0; i < 4; i++) {
> - led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
> - if (!led) {
> - hid_warn(hdev,
> - "can't allocate memory for LED selector\n");
> - ret = -ENOMEM;
> - goto err;
> - }
> -
> - name = (void *)&led[1];
> - snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
> - led->name = name;
> - led->brightness = 0;
> - led->max_brightness = 127;
> - led->brightness_get = wacom_leds_get_brightness;
> - led->brightness_set = wacom_leds_set_brightness;
> -
> - wdata->leds[i] = led;
> -
> - ret = led_classdev_register(dev, wdata->leds[i]);
> -
> - if (ret) {
> - wdata->leds[i] = NULL;
> - kfree(led);
> - hid_warn(hdev, "can't register LED\n");
> - goto err;
> - }
> - }
> -
> -err:
> - return ret;
> -}
> -
> -static void wacom_destroy_leds(struct hid_device *hdev)
> -{
> - struct wacom_data *wdata = hid_get_drvdata(hdev);
> - struct led_classdev *led;
> - int i;
> -
> - for (i = 0; i < 4; ++i) {
> - if (wdata->leds[i]) {
> - led = wdata->leds[i];
> - wdata->leds[i] = NULL;
> - led_classdev_unregister(led);
> - kfree(led);
> - }
> - }
> -
> -}
> -
> -static int wacom_battery_get_property(struct power_supply *psy,
> - enum power_supply_property psp,
> - union power_supply_propval *val)
> -{
> - struct wacom_data *wdata = container_of(psy,
> - struct wacom_data, battery);
> - int ret = 0;
> -
> - switch (psp) {
> - case POWER_SUPPLY_PROP_PRESENT:
> - val->intval = 1;
> - break;
> - case POWER_SUPPLY_PROP_SCOPE:
> - val->intval = POWER_SUPPLY_SCOPE_DEVICE;
> - break;
> - case POWER_SUPPLY_PROP_CAPACITY:
> - val->intval = wdata->battery_capacity;
> - break;
> - case POWER_SUPPLY_PROP_STATUS:
> - if (wdata->bat_charging)
> - val->intval = POWER_SUPPLY_STATUS_CHARGING;
> - else
> - if (wdata->battery_capacity == 100 && wdata->ps_connected)
> - val->intval = POWER_SUPPLY_STATUS_FULL;
> - else
> - val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
> - break;
> - default:
> - ret = -EINVAL;
> - break;
> - }
> - return ret;
> -}
> -
> -static int wacom_ac_get_property(struct power_supply *psy,
> - enum power_supply_property psp,
> - union power_supply_propval *val)
> -{
> - struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
> - int ret = 0;
> -
> - switch (psp) {
> - case POWER_SUPPLY_PROP_PRESENT:
> - /* fall through */
> - case POWER_SUPPLY_PROP_ONLINE:
> - val->intval = wdata->ps_connected;
> - break;
> - case POWER_SUPPLY_PROP_SCOPE:
> - val->intval = POWER_SUPPLY_SCOPE_DEVICE;
> - break;
> - default:
> - ret = -EINVAL;
> - break;
> - }
> - return ret;
> -}
> -
> -static void wacom_set_features(struct hid_device *hdev, u8 speed)
> -{
> - struct wacom_data *wdata = hid_get_drvdata(hdev);
> - int limit, ret;
> - __u8 rep_data[2];
> -
> - switch (hdev->product) {
> - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> - rep_data[0] = 0x03 ; rep_data[1] = 0x00;
> - limit = 3;
> - do {
> - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> - } while (ret < 0 && limit-- > 0);
> -
> - if (ret >= 0) {
> - if (speed == 0)
> - rep_data[0] = 0x05;
> - else
> - rep_data[0] = 0x06;
> -
> - rep_data[1] = 0x00;
> - limit = 3;
> - do {
> - ret = hid_hw_raw_request(hdev, rep_data[0],
> - rep_data, 2, HID_FEATURE_REPORT,
> - HID_REQ_SET_REPORT);
> - } while (ret < 0 && limit-- > 0);
> -
> - if (ret >= 0) {
> - wdata->high_speed = speed;
> - return;
> - }
> - }
> -
> - /*
> - * Note that if the raw queries fail, it's not a hard failure
> - * and it is safe to continue
> - */
> - hid_warn(hdev, "failed to poke device, command %d, err %d\n",
> - rep_data[0], ret);
> - break;
> - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> - if (speed == 1)
> - wdata->features &= ~0x20;
> - else
> - wdata->features |= 0x20;
> -
> - rep_data[0] = 0x03;
> - rep_data[1] = wdata->features;
> -
> - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> - if (ret >= 0)
> - wdata->high_speed = speed;
> - break;
> - }
> -
> - return;
> -}
> -
> -static ssize_t wacom_show_speed(struct device *dev,
> - struct device_attribute
> - *attr, char *buf)
> -{
> - struct wacom_data *wdata = dev_get_drvdata(dev);
> -
> - return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
> -}
> -
> -static ssize_t wacom_store_speed(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf, size_t count)
> -{
> - struct hid_device *hdev = container_of(dev, struct hid_device, dev);
> - int new_speed;
> -
> - if (sscanf(buf, "%1d", &new_speed ) != 1)
> - return -EINVAL;
> -
> - if (new_speed == 0 || new_speed == 1) {
> - wacom_set_features(hdev, new_speed);
> - return strnlen(buf, PAGE_SIZE);
> - } else
> - return -EINVAL;
> -}
> -
> -static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
> - wacom_show_speed, wacom_store_speed);
> -
> -#define WACOM_STORE(OLED_ID) \
> -static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \
> - struct device_attribute *attr, \
> - const char *buf, size_t count) \
> -{ \
> - struct hid_device *hdev = container_of(dev, struct hid_device, \
> - dev); \
> - \
> - if (count != 256) \
> - return -EINVAL; \
> - \
> - wacom_set_image(hdev, buf, OLED_ID); \
> - \
> - return count; \
> -} \
> - \
> -static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \
> - wacom_oled##OLED_ID##_store)
> -
> -WACOM_STORE(0);
> -WACOM_STORE(1);
> -WACOM_STORE(2);
> -WACOM_STORE(3);
> -WACOM_STORE(4);
> -WACOM_STORE(5);
> -WACOM_STORE(6);
> -WACOM_STORE(7);
> -
> -static int wacom_gr_parse_report(struct hid_device *hdev,
> - struct wacom_data *wdata,
> - struct input_dev *input, unsigned char *data)
> -{
> - int tool, x, y, rw;
> -
> - tool = 0;
> - /* Get X & Y positions */
> - x = le16_to_cpu(*(__le16 *) &data[2]);
> - y = le16_to_cpu(*(__le16 *) &data[4]);
> -
> - /* Get current tool identifier */
> - if (data[1] & 0x90) { /* If pen is in the in/active area */
> - switch ((data[1] >> 5) & 3) {
> - case 0: /* Pen */
> - tool = BTN_TOOL_PEN;
> - break;
> -
> - case 1: /* Rubber */
> - tool = BTN_TOOL_RUBBER;
> - break;
> -
> - case 2: /* Mouse with wheel */
> - case 3: /* Mouse without wheel */
> - tool = BTN_TOOL_MOUSE;
> - break;
> - }
> -
> - /* Reset tool if out of active tablet area */
> - if (!(data[1] & 0x10))
> - tool = 0;
> - }
> -
> - /* If tool changed, notify input subsystem */
> - if (wdata->tool != tool) {
> - if (wdata->tool) {
> - /* Completely reset old tool state */
> - if (wdata->tool == BTN_TOOL_MOUSE) {
> - input_report_key(input, BTN_LEFT, 0);
> - input_report_key(input, BTN_RIGHT, 0);
> - input_report_key(input, BTN_MIDDLE, 0);
> - input_report_abs(input, ABS_DISTANCE,
> - input_abs_get_max(input, ABS_DISTANCE));
> - } else {
> - input_report_key(input, BTN_TOUCH, 0);
> - input_report_key(input, BTN_STYLUS, 0);
> - input_report_key(input, BTN_STYLUS2, 0);
> - input_report_abs(input, ABS_PRESSURE, 0);
> - }
> - input_report_key(input, wdata->tool, 0);
> - input_sync(input);
> - }
> - wdata->tool = tool;
> - if (tool)
> - input_report_key(input, tool, 1);
> - }
> -
> - if (tool) {
> - input_report_abs(input, ABS_X, x);
> - input_report_abs(input, ABS_Y, y);
> -
> - switch ((data[1] >> 5) & 3) {
> - case 2: /* Mouse with wheel */
> - input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
> - rw = (data[6] & 0x01) ? -1 :
> - (data[6] & 0x02) ? 1 : 0;
> - input_report_rel(input, REL_WHEEL, rw);
> - /* fall through */
> -
> - case 3: /* Mouse without wheel */
> - input_report_key(input, BTN_LEFT, data[1] & 0x01);
> - input_report_key(input, BTN_RIGHT, data[1] & 0x02);
> - /* Compute distance between mouse and tablet */
> - rw = 44 - (data[6] >> 2);
> - if (rw < 0)
> - rw = 0;
> - else if (rw > 31)
> - rw = 31;
> - input_report_abs(input, ABS_DISTANCE, rw);
> - break;
> -
> - default:
> - input_report_abs(input, ABS_PRESSURE,
> - data[6] | (((__u16) (data[1] & 0x08)) << 5));
> - input_report_key(input, BTN_TOUCH, data[1] & 0x01);
> - input_report_key(input, BTN_STYLUS, data[1] & 0x02);
> - input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
> - break;
> - }
> -
> - input_sync(input);
> - }
> -
> - /* Report the state of the two buttons at the top of the tablet
> - * as two extra fingerpad keys (buttons 4 & 5). */
> - rw = data[7] & 0x03;
> - if (rw != wdata->butstate) {
> - wdata->butstate = rw;
> - input_report_key(input, BTN_0, rw & 0x02);
> - input_report_key(input, BTN_1, rw & 0x01);
> - input_report_key(input, BTN_TOOL_FINGER, 0xf0);
> - input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
> - input_sync(input);
> - }
> -
> - /* Store current battery capacity and power supply state*/
> - rw = (data[7] >> 2 & 0x07);
> - if (rw != wdata->power_raw) {
> - wdata->power_raw = rw;
> - wdata->battery_capacity = batcap_gr[rw];
> - if (rw == 7)
> - wdata->ps_connected = 1;
> - else
> - wdata->ps_connected = 0;
> - }
> - return 1;
> -}
> -
> -static void wacom_i4_parse_button_report(struct wacom_data *wdata,
> - struct input_dev *input, unsigned char *data)
> -{
> - __u16 new_butstate;
> - __u8 new_whlstate;
> - __u8 sync = 0;
> -
> - new_whlstate = data[1];
> - if (new_whlstate != wdata->whlstate) {
> - wdata->whlstate = new_whlstate;
> - if (new_whlstate & 0x80) {
> - input_report_key(input, BTN_TOUCH, 1);
> - input_report_abs(input, ABS_WHEEL, (new_whlstate & 0x7f));
> - input_report_key(input, BTN_TOOL_FINGER, 1);
> - } else {
> - input_report_key(input, BTN_TOUCH, 0);
> - input_report_abs(input, ABS_WHEEL, 0);
> - input_report_key(input, BTN_TOOL_FINGER, 0);
> - }
> - sync = 1;
> - }
> -
> - new_butstate = (data[3] << 1) | (data[2] & 0x01);
> - if (new_butstate != wdata->butstate) {
> - wdata->butstate = new_butstate;
> - input_report_key(input, BTN_0, new_butstate & 0x001);
> - input_report_key(input, BTN_1, new_butstate & 0x002);
> - input_report_key(input, BTN_2, new_butstate & 0x004);
> - input_report_key(input, BTN_3, new_butstate & 0x008);
> - input_report_key(input, BTN_4, new_butstate & 0x010);
> - input_report_key(input, BTN_5, new_butstate & 0x020);
> - input_report_key(input, BTN_6, new_butstate & 0x040);
> - input_report_key(input, BTN_7, new_butstate & 0x080);
> - input_report_key(input, BTN_8, new_butstate & 0x100);
> - input_report_key(input, BTN_TOOL_FINGER, 1);
> - sync = 1;
> - }
> -
> - if (sync) {
> - input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
> - input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
> - input_sync(input);
> - }
> -}
> -
> -static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
> - struct input_dev *input, unsigned char *data)
> -{
> - __u16 x, y, pressure;
> - __u8 distance;
> - __u8 tilt_x, tilt_y;
> -
> - switch (data[1]) {
> - case 0x80: /* Out of proximity report */
> - input_report_key(input, BTN_TOUCH, 0);
> - input_report_abs(input, ABS_PRESSURE, 0);
> - input_report_key(input, BTN_STYLUS, 0);
> - input_report_key(input, BTN_STYLUS2, 0);
> - input_report_key(input, wdata->tool, 0);
> - input_report_abs(input, ABS_MISC, 0);
> - input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
> - wdata->tool = 0;
> - input_sync(input);
> - break;
> - case 0xC2: /* Tool report */
> - wdata->id = ((data[2] << 4) | (data[3] >> 4) |
> - ((data[7] & 0x0f) << 20) |
> - ((data[8] & 0xf0) << 12));
> - wdata->serial = ((data[3] & 0x0f) << 28) +
> - (data[4] << 20) + (data[5] << 12) +
> - (data[6] << 4) + (data[7] >> 4);
> -
> - switch (wdata->id) {
> - case 0x100802:
> - wdata->tool = BTN_TOOL_PEN;
> - break;
> - case 0x10080A:
> - wdata->tool = BTN_TOOL_RUBBER;
> - break;
> - }
> - break;
> - default: /* Position/pressure report */
> - x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
> - y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
> - pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
> - | (data[1] & 0x01);
> - distance = (data[9] >> 2) & 0x3f;
> - tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
> - tilt_y = data[8] & 0x7f;
> -
> - input_report_key(input, BTN_TOUCH, pressure > 1);
> -
> - input_report_key(input, BTN_STYLUS, data[1] & 0x02);
> - input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
> - input_report_key(input, wdata->tool, 1);
> - input_report_abs(input, ABS_X, x);
> - input_report_abs(input, ABS_Y, y);
> - input_report_abs(input, ABS_PRESSURE, pressure);
> - input_report_abs(input, ABS_DISTANCE, distance);
> - input_report_abs(input, ABS_TILT_X, tilt_x);
> - input_report_abs(input, ABS_TILT_Y, tilt_y);
> - input_report_abs(input, ABS_MISC, wdata->id);
> - input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
> - input_report_key(input, wdata->tool, 1);
> - input_sync(input);
> - break;
> - }
> -
> - return;
> -}
> -
> -static void wacom_i4_parse_report(struct hid_device *hdev,
> - struct wacom_data *wdata,
> - struct input_dev *input, unsigned char *data)
> -{
> - switch (data[0]) {
> - case 0x00: /* Empty report */
> - break;
> - case 0x02: /* Pen report */
> - wacom_i4_parse_pen_report(wdata, input, data);
> - break;
> - case 0x03: /* Features Report */
> - wdata->features = data[2];
> - break;
> - case 0x0C: /* Button report */
> - wacom_i4_parse_button_report(wdata, input, data);
> - break;
> - default:
> - hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
> - break;
> - }
> -}
> -
> -static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
> - u8 *raw_data, int size)
> -{
> - struct wacom_data *wdata = hid_get_drvdata(hdev);
> - struct hid_input *hidinput;
> - struct input_dev *input;
> - unsigned char *data = (unsigned char *) raw_data;
> - int i;
> - __u8 power_raw;
> -
> - if (!(hdev->claimed & HID_CLAIMED_INPUT))
> - return 0;
> -
> - hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
> - input = hidinput->input;
> -
> - switch (hdev->product) {
> - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> - if (data[0] == 0x03) {
> - return wacom_gr_parse_report(hdev, wdata, input, data);
> - } else {
> - hid_err(hdev, "Unknown report: %d,%d size:%d\n",
> - data[0], data[1], size);
> - return 0;
> - }
> - break;
> - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> - i = 1;
> -
> - switch (data[0]) {
> - case 0x04:
> - wacom_i4_parse_report(hdev, wdata, input, data + i);
> - i += 10;
> - /* fall through */
> - case 0x03:
> - wacom_i4_parse_report(hdev, wdata, input, data + i);
> - i += 10;
> - wacom_i4_parse_report(hdev, wdata, input, data + i);
> - power_raw = data[i+10];
> - if (power_raw != wdata->power_raw) {
> - wdata->power_raw = power_raw;
> - wdata->battery_capacity = batcap_i4[power_raw & 0x07];
> - wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
> - wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
> - }
> -
> - break;
> - default:
> - hid_err(hdev, "Unknown report: %d,%d size:%d\n",
> - data[0], data[1], size);
> - return 0;
> - }
> - }
> - return 1;
> -}
> -
> -static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
> - struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
> - int *max)
> -{
> - struct input_dev *input = hi->input;
> -
> - __set_bit(INPUT_PROP_POINTER, input->propbit);
> -
> - /* Basics */
> - input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
> -
> - __set_bit(REL_WHEEL, input->relbit);
> -
> - __set_bit(BTN_TOOL_PEN, input->keybit);
> - __set_bit(BTN_TOUCH, input->keybit);
> - __set_bit(BTN_STYLUS, input->keybit);
> - __set_bit(BTN_STYLUS2, input->keybit);
> - __set_bit(BTN_LEFT, input->keybit);
> - __set_bit(BTN_RIGHT, input->keybit);
> - __set_bit(BTN_MIDDLE, input->keybit);
> -
> - /* Pad */
> - input_set_capability(input, EV_MSC, MSC_SERIAL);
> -
> - __set_bit(BTN_0, input->keybit);
> - __set_bit(BTN_1, input->keybit);
> - __set_bit(BTN_TOOL_FINGER, input->keybit);
> -
> - /* Distance, rubber and mouse */
> - __set_bit(BTN_TOOL_RUBBER, input->keybit);
> - __set_bit(BTN_TOOL_MOUSE, input->keybit);
> -
> - switch (hdev->product) {
> - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> - input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
> - input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
> - input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
> - input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
> - break;
> - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> - __set_bit(ABS_WHEEL, input->absbit);
> - __set_bit(ABS_MISC, input->absbit);
> - __set_bit(BTN_2, input->keybit);
> - __set_bit(BTN_3, input->keybit);
> - __set_bit(BTN_4, input->keybit);
> - __set_bit(BTN_5, input->keybit);
> - __set_bit(BTN_6, input->keybit);
> - __set_bit(BTN_7, input->keybit);
> - __set_bit(BTN_8, input->keybit);
> - input_set_abs_params(input, ABS_WHEEL, 0, 71, 0, 0);
> - input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
> - input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
> - input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
> - input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
> - input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
> - input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
> - break;
> - }
> -
> - return 0;
> -}
> -
> -static int wacom_probe(struct hid_device *hdev,
> - const struct hid_device_id *id)
> -{
> - struct wacom_data *wdata;
> - int ret;
> -
> - wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
> - if (wdata == NULL) {
> - hid_err(hdev, "can't alloc wacom descriptor\n");
> - return -ENOMEM;
> - }
> -
> - hid_set_drvdata(hdev, wdata);
> -
> - /* Parse the HID report now */
> - ret = hid_parse(hdev);
> - if (ret) {
> - hid_err(hdev, "parse failed\n");
> - goto err_free;
> - }
> -
> - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> - if (ret) {
> - hid_err(hdev, "hw start failed\n");
> - goto err_free;
> - }
> -
> - ret = device_create_file(&hdev->dev, &dev_attr_speed);
> - if (ret)
> - hid_warn(hdev,
> - "can't create sysfs speed attribute err: %d\n", ret);
> -
> -#define OLED_INIT(OLED_ID) \
> - do { \
> - ret = device_create_file(&hdev->dev, \
> - &dev_attr_oled##OLED_ID##_img); \
> - if (ret) \
> - hid_warn(hdev, \
> - "can't create sysfs oled attribute, err: %d\n", ret);\
> - } while (0)
> -
> -OLED_INIT(0);
> -OLED_INIT(1);
> -OLED_INIT(2);
> -OLED_INIT(3);
> -OLED_INIT(4);
> -OLED_INIT(5);
> -OLED_INIT(6);
> -OLED_INIT(7);
> -
> - wdata->features = 0;
> - wacom_set_features(hdev, 1);
> -
> - if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
> - sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
> - ret = wacom_initialize_leds(hdev);
> - if (ret)
> - hid_warn(hdev,
> - "can't create led attribute, err: %d\n", ret);
> - }
> -
> - wdata->battery.properties = wacom_battery_props;
> - wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
> - wdata->battery.get_property = wacom_battery_get_property;
> - wdata->battery.name = "wacom_battery";
> - wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
> - wdata->battery.use_for_apm = 0;
> -
> -
> - ret = power_supply_register(&hdev->dev, &wdata->battery);
> - if (ret) {
> - hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
> - ret);
> - goto err_battery;
> - }
> -
> - power_supply_powers(&wdata->battery, &hdev->dev);
> -
> - wdata->ac.properties = wacom_ac_props;
> - wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
> - wdata->ac.get_property = wacom_ac_get_property;
> - wdata->ac.name = "wacom_ac";
> - wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
> - wdata->ac.use_for_apm = 0;
> -
> - ret = power_supply_register(&hdev->dev, &wdata->ac);
> - if (ret) {
> - hid_err(hdev,
> - "can't create ac battery attribute, err: %d\n", ret);
> - goto err_ac;
> - }
> -
> - power_supply_powers(&wdata->ac, &hdev->dev);
> - return 0;
> -
> -err_ac:
> - power_supply_unregister(&wdata->battery);
> -err_battery:
> - wacom_destroy_leds(hdev);
> - device_remove_file(&hdev->dev, &dev_attr_oled0_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled1_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled2_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled3_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled4_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled5_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled6_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled7_img);
> - device_remove_file(&hdev->dev, &dev_attr_speed);
> - hid_hw_stop(hdev);
> -err_free:
> - kfree(wdata);
> - return ret;
> -}
> -
> -static void wacom_remove(struct hid_device *hdev)
> -{
> - struct wacom_data *wdata = hid_get_drvdata(hdev);
> -
> - wacom_destroy_leds(hdev);
> - device_remove_file(&hdev->dev, &dev_attr_oled0_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled1_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled2_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled3_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled4_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled5_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled6_img);
> - device_remove_file(&hdev->dev, &dev_attr_oled7_img);
> - device_remove_file(&hdev->dev, &dev_attr_speed);
> - hid_hw_stop(hdev);
> -
> - power_supply_unregister(&wdata->battery);
> - power_supply_unregister(&wdata->ac);
> - kfree(hid_get_drvdata(hdev));
> -}
> -
> -static const struct hid_device_id wacom_devices[] = {
> -
> - { }
> -};
> -MODULE_DEVICE_TABLE(hid, wacom_devices);
> -
> -static struct hid_driver wacom_driver = {
> - .name = "hid-wacom",
> - .id_table = wacom_devices,
> - .probe = wacom_probe,
> - .remove = wacom_remove,
> - .raw_event = wacom_raw_event,
> - .input_mapped = wacom_input_mapped,
> -};
> -module_hid_driver(wacom_driver);
> -
> -MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
> -MODULE_LICENSE("GPL");
--
Kind regards,
Przemo Firszt
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 7/7] HID: remove hid-wacom Bluetooth driver
From: Benjamin Tissoires @ 2014-07-31 19:32 UTC (permalink / raw)
To: Przemo Firszt
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Jason Gerecke,
linux-kernel, linux-input
In-Reply-To: <1406834337.9693.2.camel@fedora-lan>
On Jul 31 2014 or thereabouts, Przemo Firszt wrote:
> Hi Benjamin,
> Look like you pressed "y" when git send-email asked for charset:
hehe, yep, sorry. I should have read the message before hitting 'y' :)
>
> Content-Type: text/plain; charset=y
>
> It kills git am:
>
> > fedora-lan:/home/przemo/sf/wacom-kernel
> > $ git am ../linux-next/\[PATCH_v3_*
> > Applying: Input - wacom: prepare the driver to include BT devices
> > Applying: Input - wacom: handle Graphire BT tablets in wacom.ko
> > Applying: Input - wacom: handle Intuos 4 BT in wacom.ko
> > Applying: Input - wacom: Check for bluetooth protocol while setting OLEDs
> > Applying: Input - wacom: Remove passing id for wacom_set_report
> > Applying: Input - wacom: add copyright note and bump version to 2.0
> > fatal: cannot convert from y to UTF-8
Replacing "charset=y" by "charset=UTF-8" should allow you to apply the
patch.
>
> The rest of patches is OK, I'm testing them now.
Cool, thanks.
Cheers,
Benjamin
>
> Dnia 2014-07-29, wto o godzinie 14:43 -0400, Benjamin Tissoires pisze:
> > Bluetooth Wacom tablets are now handled by the regular wacom.ko driver.
> > Remove the now useless hid-wacom driver.
> >
> > Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> > ---
> > drivers/hid/Kconfig | 10 +-
> > drivers/hid/Makefile | 3 +-
> > drivers/hid/hid-wacom.c | 971 ------------------------------------------------
> > 3 files changed, 2 insertions(+), 982 deletions(-)
> > delete mode 100644 drivers/hid/hid-wacom.c
> >
> > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> > index b18bae6..354122b 100644
> > --- a/drivers/hid/Kconfig
> > +++ b/drivers/hid/Kconfig
> > @@ -762,21 +762,13 @@ config THRUSTMASTER_FF
> > Rumble Force or Force Feedback Wheel.
> >
> > config HID_WACOM
> > - tristate "Wacom Bluetooth devices support"
> > - depends on HID
> > - depends on LEDS_CLASS
> > - select POWER_SUPPLY
> > - ---help---
> > - Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
> > -
> > -config HID_USB_WACOM
> > tristate "Wacom Intuos/Graphire tablet support (USB)"
> > depends on HID
> > select POWER_SUPPLY
> > select NEW_LEDS
> > select LEDS_CLASS
> > help
> > - Say Y here if you want to use the USB version of the Wacom Intuos
> > + Say Y here if you want to use the USB or BT version of the Wacom Intuos
> > or Graphire tablet.
> >
> > To compile this driver as a module, choose M here: the
> > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> > index 19ba7c3..2d7e149 100644
> > --- a/drivers/hid/Makefile
> > +++ b/drivers/hid/Makefile
> > @@ -116,10 +116,9 @@ obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
> > obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
> > obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
> > obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
> > -obj-$(CONFIG_HID_WACOM) += hid-wacom.o
> >
> > wacom-objs := wacom_wac.o wacom_sys.o
> > -obj-$(CONFIG_HID_USB_WACOM) += wacom.o
> > +obj-$(CONFIG_HID_WACOM) += wacom.o
> > obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
> > obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
> > obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
> > diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
> > deleted file mode 100644
> > index db2d07d..0000000
> > --- a/drivers/hid/hid-wacom.c
> > +++ /dev/null
> > @@ -1,971 +0,0 @@
> > -/*
> > - * Bluetooth Wacom Tablet support
> > - *
> > - * Copyright (c) 1999 Andreas Gal
> > - * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
> > - * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
> > - * Copyright (c) 2006-2007 Jiri Kosina
> > - * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
> > - * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
> > - * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
> > - * Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu>
> > - */
> > -
> > -/*
> > - * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/device.h>
> > -#include <linux/hid.h>
> > -#include <linux/module.h>
> > -#include <linux/leds.h>
> > -#include <linux/slab.h>
> > -#include <linux/power_supply.h>
> > -
> > -#include "hid-ids.h"
> > -
> > -#define PAD_DEVICE_ID 0x0F
> > -
> > -#define WAC_CMD_LED_CONTROL 0x20
> > -#define WAC_CMD_ICON_START_STOP 0x21
> > -#define WAC_CMD_ICON_TRANSFER 0x26
> > -
> > -struct wacom_data {
> > - __u16 tool;
> > - __u16 butstate;
> > - __u8 whlstate;
> > - __u8 features;
> > - __u32 id;
> > - __u32 serial;
> > - unsigned char high_speed;
> > - __u8 battery_capacity;
> > - __u8 power_raw;
> > - __u8 ps_connected;
> > - __u8 bat_charging;
> > - struct power_supply battery;
> > - struct power_supply ac;
> > - __u8 led_selector;
> > - struct led_classdev *leds[4];
> > -};
> > -
> > -/*percent of battery capacity for Graphire
> > - 8th value means AC online and show 100% capacity */
> > -static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
> > -/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
> > -static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
> > -
> > -static enum power_supply_property wacom_battery_props[] = {
> > - POWER_SUPPLY_PROP_PRESENT,
> > - POWER_SUPPLY_PROP_CAPACITY,
> > - POWER_SUPPLY_PROP_SCOPE,
> > - POWER_SUPPLY_PROP_STATUS,
> > -};
> > -
> > -static enum power_supply_property wacom_ac_props[] = {
> > - POWER_SUPPLY_PROP_PRESENT,
> > - POWER_SUPPLY_PROP_ONLINE,
> > - POWER_SUPPLY_PROP_SCOPE,
> > -};
> > -
> > -static void wacom_scramble(__u8 *image)
> > -{
> > - __u16 mask;
> > - __u16 s1;
> > - __u16 s2;
> > - __u16 r1 ;
> > - __u16 r2 ;
> > - __u16 r;
> > - __u8 buf[256];
> > - int i, w, x, y, z;
> > -
> > - for (x = 0; x < 32; x++) {
> > - for (y = 0; y < 8; y++)
> > - buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
> > - }
> > -
> > - /* Change 76543210 into GECA6420 as required by Intuos4 WL
> > - * HGFEDCBA HFDB7531
> > - */
> > - for (x = 0; x < 4; x++) {
> > - for (y = 0; y < 4; y++) {
> > - for (z = 0; z < 8; z++) {
> > - mask = 0x0001;
> > - r1 = 0;
> > - r2 = 0;
> > - i = (x << 6) + (y << 4) + z;
> > - s1 = buf[i];
> > - s2 = buf[i+8];
> > - for (w = 0; w < 8; w++) {
> > - r1 |= (s1 & mask);
> > - r2 |= (s2 & mask);
> > - s1 <<= 1;
> > - s2 <<= 1;
> > - mask <<= 2;
> > - }
> > - r = r1 | (r2 << 1);
> > - i = (x << 6) + (y << 4) + (z << 1);
> > - image[i] = 0xFF & r;
> > - image[i+1] = (0xFF00 & r) >> 8;
> > - }
> > - }
> > - }
> > -}
> > -
> > -static void wacom_set_image(struct hid_device *hdev, const char *image,
> > - __u8 icon_no)
> > -{
> > - __u8 rep_data[68];
> > - __u8 p[256];
> > - int ret, i, j;
> > -
> > - for (i = 0; i < 256; i++)
> > - p[i] = image[i];
> > -
> > - rep_data[0] = WAC_CMD_ICON_START_STOP;
> > - rep_data[1] = 0;
> > - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> > - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> > - if (ret < 0)
> > - goto err;
> > -
> > - rep_data[0] = WAC_CMD_ICON_TRANSFER;
> > - rep_data[1] = icon_no & 0x07;
> > -
> > - wacom_scramble(p);
> > -
> > - for (i = 0; i < 4; i++) {
> > - for (j = 0; j < 64; j++)
> > - rep_data[j + 3] = p[(i << 6) + j];
> > -
> > - rep_data[2] = i;
> > - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
> > - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> > - }
> > -
> > - rep_data[0] = WAC_CMD_ICON_START_STOP;
> > - rep_data[1] = 0;
> > -
> > - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> > - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> > -
> > -err:
> > - return;
> > -}
> > -
> > -static void wacom_leds_set_brightness(struct led_classdev *led_dev,
> > - enum led_brightness value)
> > -{
> > - struct device *dev = led_dev->dev->parent;
> > - struct hid_device *hdev;
> > - struct wacom_data *wdata;
> > - unsigned char *buf;
> > - __u8 led = 0;
> > - int i;
> > -
> > - hdev = container_of(dev, struct hid_device, dev);
> > - wdata = hid_get_drvdata(hdev);
> > - for (i = 0; i < 4; ++i) {
> > - if (wdata->leds[i] == led_dev)
> > - wdata->led_selector = i;
> > - }
> > -
> > - led = wdata->led_selector | 0x04;
> > - buf = kzalloc(9, GFP_KERNEL);
> > - if (buf) {
> > - buf[0] = WAC_CMD_LED_CONTROL;
> > - buf[1] = led;
> > - buf[2] = value >> 2;
> > - buf[3] = value;
> > - /* use fixed brightness for OLEDs */
> > - buf[4] = 0x08;
> > - hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
> > - HID_REQ_SET_REPORT);
> > - kfree(buf);
> > - }
> > -
> > - return;
> > -}
> > -
> > -static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
> > -{
> > - struct wacom_data *wdata;
> > - struct device *dev = led_dev->dev->parent;
> > - int value = 0;
> > - int i;
> > -
> > - wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
> > -
> > - for (i = 0; i < 4; ++i) {
> > - if (wdata->leds[i] == led_dev) {
> > - value = wdata->leds[i]->brightness;
> > - break;
> > - }
> > - }
> > -
> > - return value;
> > -}
> > -
> > -
> > -static int wacom_initialize_leds(struct hid_device *hdev)
> > -{
> > - struct wacom_data *wdata = hid_get_drvdata(hdev);
> > - struct led_classdev *led;
> > - struct device *dev = &hdev->dev;
> > - size_t namesz = strlen(dev_name(dev)) + 12;
> > - char *name;
> > - int i, ret;
> > -
> > - wdata->led_selector = 0;
> > -
> > - for (i = 0; i < 4; i++) {
> > - led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
> > - if (!led) {
> > - hid_warn(hdev,
> > - "can't allocate memory for LED selector\n");
> > - ret = -ENOMEM;
> > - goto err;
> > - }
> > -
> > - name = (void *)&led[1];
> > - snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
> > - led->name = name;
> > - led->brightness = 0;
> > - led->max_brightness = 127;
> > - led->brightness_get = wacom_leds_get_brightness;
> > - led->brightness_set = wacom_leds_set_brightness;
> > -
> > - wdata->leds[i] = led;
> > -
> > - ret = led_classdev_register(dev, wdata->leds[i]);
> > -
> > - if (ret) {
> > - wdata->leds[i] = NULL;
> > - kfree(led);
> > - hid_warn(hdev, "can't register LED\n");
> > - goto err;
> > - }
> > - }
> > -
> > -err:
> > - return ret;
> > -}
> > -
> > -static void wacom_destroy_leds(struct hid_device *hdev)
> > -{
> > - struct wacom_data *wdata = hid_get_drvdata(hdev);
> > - struct led_classdev *led;
> > - int i;
> > -
> > - for (i = 0; i < 4; ++i) {
> > - if (wdata->leds[i]) {
> > - led = wdata->leds[i];
> > - wdata->leds[i] = NULL;
> > - led_classdev_unregister(led);
> > - kfree(led);
> > - }
> > - }
> > -
> > -}
> > -
> > -static int wacom_battery_get_property(struct power_supply *psy,
> > - enum power_supply_property psp,
> > - union power_supply_propval *val)
> > -{
> > - struct wacom_data *wdata = container_of(psy,
> > - struct wacom_data, battery);
> > - int ret = 0;
> > -
> > - switch (psp) {
> > - case POWER_SUPPLY_PROP_PRESENT:
> > - val->intval = 1;
> > - break;
> > - case POWER_SUPPLY_PROP_SCOPE:
> > - val->intval = POWER_SUPPLY_SCOPE_DEVICE;
> > - break;
> > - case POWER_SUPPLY_PROP_CAPACITY:
> > - val->intval = wdata->battery_capacity;
> > - break;
> > - case POWER_SUPPLY_PROP_STATUS:
> > - if (wdata->bat_charging)
> > - val->intval = POWER_SUPPLY_STATUS_CHARGING;
> > - else
> > - if (wdata->battery_capacity == 100 && wdata->ps_connected)
> > - val->intval = POWER_SUPPLY_STATUS_FULL;
> > - else
> > - val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
> > - break;
> > - default:
> > - ret = -EINVAL;
> > - break;
> > - }
> > - return ret;
> > -}
> > -
> > -static int wacom_ac_get_property(struct power_supply *psy,
> > - enum power_supply_property psp,
> > - union power_supply_propval *val)
> > -{
> > - struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
> > - int ret = 0;
> > -
> > - switch (psp) {
> > - case POWER_SUPPLY_PROP_PRESENT:
> > - /* fall through */
> > - case POWER_SUPPLY_PROP_ONLINE:
> > - val->intval = wdata->ps_connected;
> > - break;
> > - case POWER_SUPPLY_PROP_SCOPE:
> > - val->intval = POWER_SUPPLY_SCOPE_DEVICE;
> > - break;
> > - default:
> > - ret = -EINVAL;
> > - break;
> > - }
> > - return ret;
> > -}
> > -
> > -static void wacom_set_features(struct hid_device *hdev, u8 speed)
> > -{
> > - struct wacom_data *wdata = hid_get_drvdata(hdev);
> > - int limit, ret;
> > - __u8 rep_data[2];
> > -
> > - switch (hdev->product) {
> > - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> > - rep_data[0] = 0x03 ; rep_data[1] = 0x00;
> > - limit = 3;
> > - do {
> > - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> > - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> > - } while (ret < 0 && limit-- > 0);
> > -
> > - if (ret >= 0) {
> > - if (speed == 0)
> > - rep_data[0] = 0x05;
> > - else
> > - rep_data[0] = 0x06;
> > -
> > - rep_data[1] = 0x00;
> > - limit = 3;
> > - do {
> > - ret = hid_hw_raw_request(hdev, rep_data[0],
> > - rep_data, 2, HID_FEATURE_REPORT,
> > - HID_REQ_SET_REPORT);
> > - } while (ret < 0 && limit-- > 0);
> > -
> > - if (ret >= 0) {
> > - wdata->high_speed = speed;
> > - return;
> > - }
> > - }
> > -
> > - /*
> > - * Note that if the raw queries fail, it's not a hard failure
> > - * and it is safe to continue
> > - */
> > - hid_warn(hdev, "failed to poke device, command %d, err %d\n",
> > - rep_data[0], ret);
> > - break;
> > - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> > - if (speed == 1)
> > - wdata->features &= ~0x20;
> > - else
> > - wdata->features |= 0x20;
> > -
> > - rep_data[0] = 0x03;
> > - rep_data[1] = wdata->features;
> > -
> > - ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
> > - HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
> > - if (ret >= 0)
> > - wdata->high_speed = speed;
> > - break;
> > - }
> > -
> > - return;
> > -}
> > -
> > -static ssize_t wacom_show_speed(struct device *dev,
> > - struct device_attribute
> > - *attr, char *buf)
> > -{
> > - struct wacom_data *wdata = dev_get_drvdata(dev);
> > -
> > - return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
> > -}
> > -
> > -static ssize_t wacom_store_speed(struct device *dev,
> > - struct device_attribute *attr,
> > - const char *buf, size_t count)
> > -{
> > - struct hid_device *hdev = container_of(dev, struct hid_device, dev);
> > - int new_speed;
> > -
> > - if (sscanf(buf, "%1d", &new_speed ) != 1)
> > - return -EINVAL;
> > -
> > - if (new_speed == 0 || new_speed == 1) {
> > - wacom_set_features(hdev, new_speed);
> > - return strnlen(buf, PAGE_SIZE);
> > - } else
> > - return -EINVAL;
> > -}
> > -
> > -static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
> > - wacom_show_speed, wacom_store_speed);
> > -
> > -#define WACOM_STORE(OLED_ID) \
> > -static ssize_t wacom_oled##OLED_ID##_store(struct device *dev, \
> > - struct device_attribute *attr, \
> > - const char *buf, size_t count) \
> > -{ \
> > - struct hid_device *hdev = container_of(dev, struct hid_device, \
> > - dev); \
> > - \
> > - if (count != 256) \
> > - return -EINVAL; \
> > - \
> > - wacom_set_image(hdev, buf, OLED_ID); \
> > - \
> > - return count; \
> > -} \
> > - \
> > -static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL, \
> > - wacom_oled##OLED_ID##_store)
> > -
> > -WACOM_STORE(0);
> > -WACOM_STORE(1);
> > -WACOM_STORE(2);
> > -WACOM_STORE(3);
> > -WACOM_STORE(4);
> > -WACOM_STORE(5);
> > -WACOM_STORE(6);
> > -WACOM_STORE(7);
> > -
> > -static int wacom_gr_parse_report(struct hid_device *hdev,
> > - struct wacom_data *wdata,
> > - struct input_dev *input, unsigned char *data)
> > -{
> > - int tool, x, y, rw;
> > -
> > - tool = 0;
> > - /* Get X & Y positions */
> > - x = le16_to_cpu(*(__le16 *) &data[2]);
> > - y = le16_to_cpu(*(__le16 *) &data[4]);
> > -
> > - /* Get current tool identifier */
> > - if (data[1] & 0x90) { /* If pen is in the in/active area */
> > - switch ((data[1] >> 5) & 3) {
> > - case 0: /* Pen */
> > - tool = BTN_TOOL_PEN;
> > - break;
> > -
> > - case 1: /* Rubber */
> > - tool = BTN_TOOL_RUBBER;
> > - break;
> > -
> > - case 2: /* Mouse with wheel */
> > - case 3: /* Mouse without wheel */
> > - tool = BTN_TOOL_MOUSE;
> > - break;
> > - }
> > -
> > - /* Reset tool if out of active tablet area */
> > - if (!(data[1] & 0x10))
> > - tool = 0;
> > - }
> > -
> > - /* If tool changed, notify input subsystem */
> > - if (wdata->tool != tool) {
> > - if (wdata->tool) {
> > - /* Completely reset old tool state */
> > - if (wdata->tool == BTN_TOOL_MOUSE) {
> > - input_report_key(input, BTN_LEFT, 0);
> > - input_report_key(input, BTN_RIGHT, 0);
> > - input_report_key(input, BTN_MIDDLE, 0);
> > - input_report_abs(input, ABS_DISTANCE,
> > - input_abs_get_max(input, ABS_DISTANCE));
> > - } else {
> > - input_report_key(input, BTN_TOUCH, 0);
> > - input_report_key(input, BTN_STYLUS, 0);
> > - input_report_key(input, BTN_STYLUS2, 0);
> > - input_report_abs(input, ABS_PRESSURE, 0);
> > - }
> > - input_report_key(input, wdata->tool, 0);
> > - input_sync(input);
> > - }
> > - wdata->tool = tool;
> > - if (tool)
> > - input_report_key(input, tool, 1);
> > - }
> > -
> > - if (tool) {
> > - input_report_abs(input, ABS_X, x);
> > - input_report_abs(input, ABS_Y, y);
> > -
> > - switch ((data[1] >> 5) & 3) {
> > - case 2: /* Mouse with wheel */
> > - input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
> > - rw = (data[6] & 0x01) ? -1 :
> > - (data[6] & 0x02) ? 1 : 0;
> > - input_report_rel(input, REL_WHEEL, rw);
> > - /* fall through */
> > -
> > - case 3: /* Mouse without wheel */
> > - input_report_key(input, BTN_LEFT, data[1] & 0x01);
> > - input_report_key(input, BTN_RIGHT, data[1] & 0x02);
> > - /* Compute distance between mouse and tablet */
> > - rw = 44 - (data[6] >> 2);
> > - if (rw < 0)
> > - rw = 0;
> > - else if (rw > 31)
> > - rw = 31;
> > - input_report_abs(input, ABS_DISTANCE, rw);
> > - break;
> > -
> > - default:
> > - input_report_abs(input, ABS_PRESSURE,
> > - data[6] | (((__u16) (data[1] & 0x08)) << 5));
> > - input_report_key(input, BTN_TOUCH, data[1] & 0x01);
> > - input_report_key(input, BTN_STYLUS, data[1] & 0x02);
> > - input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
> > - break;
> > - }
> > -
> > - input_sync(input);
> > - }
> > -
> > - /* Report the state of the two buttons at the top of the tablet
> > - * as two extra fingerpad keys (buttons 4 & 5). */
> > - rw = data[7] & 0x03;
> > - if (rw != wdata->butstate) {
> > - wdata->butstate = rw;
> > - input_report_key(input, BTN_0, rw & 0x02);
> > - input_report_key(input, BTN_1, rw & 0x01);
> > - input_report_key(input, BTN_TOOL_FINGER, 0xf0);
> > - input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
> > - input_sync(input);
> > - }
> > -
> > - /* Store current battery capacity and power supply state*/
> > - rw = (data[7] >> 2 & 0x07);
> > - if (rw != wdata->power_raw) {
> > - wdata->power_raw = rw;
> > - wdata->battery_capacity = batcap_gr[rw];
> > - if (rw == 7)
> > - wdata->ps_connected = 1;
> > - else
> > - wdata->ps_connected = 0;
> > - }
> > - return 1;
> > -}
> > -
> > -static void wacom_i4_parse_button_report(struct wacom_data *wdata,
> > - struct input_dev *input, unsigned char *data)
> > -{
> > - __u16 new_butstate;
> > - __u8 new_whlstate;
> > - __u8 sync = 0;
> > -
> > - new_whlstate = data[1];
> > - if (new_whlstate != wdata->whlstate) {
> > - wdata->whlstate = new_whlstate;
> > - if (new_whlstate & 0x80) {
> > - input_report_key(input, BTN_TOUCH, 1);
> > - input_report_abs(input, ABS_WHEEL, (new_whlstate & 0x7f));
> > - input_report_key(input, BTN_TOOL_FINGER, 1);
> > - } else {
> > - input_report_key(input, BTN_TOUCH, 0);
> > - input_report_abs(input, ABS_WHEEL, 0);
> > - input_report_key(input, BTN_TOOL_FINGER, 0);
> > - }
> > - sync = 1;
> > - }
> > -
> > - new_butstate = (data[3] << 1) | (data[2] & 0x01);
> > - if (new_butstate != wdata->butstate) {
> > - wdata->butstate = new_butstate;
> > - input_report_key(input, BTN_0, new_butstate & 0x001);
> > - input_report_key(input, BTN_1, new_butstate & 0x002);
> > - input_report_key(input, BTN_2, new_butstate & 0x004);
> > - input_report_key(input, BTN_3, new_butstate & 0x008);
> > - input_report_key(input, BTN_4, new_butstate & 0x010);
> > - input_report_key(input, BTN_5, new_butstate & 0x020);
> > - input_report_key(input, BTN_6, new_butstate & 0x040);
> > - input_report_key(input, BTN_7, new_butstate & 0x080);
> > - input_report_key(input, BTN_8, new_butstate & 0x100);
> > - input_report_key(input, BTN_TOOL_FINGER, 1);
> > - sync = 1;
> > - }
> > -
> > - if (sync) {
> > - input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
> > - input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
> > - input_sync(input);
> > - }
> > -}
> > -
> > -static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
> > - struct input_dev *input, unsigned char *data)
> > -{
> > - __u16 x, y, pressure;
> > - __u8 distance;
> > - __u8 tilt_x, tilt_y;
> > -
> > - switch (data[1]) {
> > - case 0x80: /* Out of proximity report */
> > - input_report_key(input, BTN_TOUCH, 0);
> > - input_report_abs(input, ABS_PRESSURE, 0);
> > - input_report_key(input, BTN_STYLUS, 0);
> > - input_report_key(input, BTN_STYLUS2, 0);
> > - input_report_key(input, wdata->tool, 0);
> > - input_report_abs(input, ABS_MISC, 0);
> > - input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
> > - wdata->tool = 0;
> > - input_sync(input);
> > - break;
> > - case 0xC2: /* Tool report */
> > - wdata->id = ((data[2] << 4) | (data[3] >> 4) |
> > - ((data[7] & 0x0f) << 20) |
> > - ((data[8] & 0xf0) << 12));
> > - wdata->serial = ((data[3] & 0x0f) << 28) +
> > - (data[4] << 20) + (data[5] << 12) +
> > - (data[6] << 4) + (data[7] >> 4);
> > -
> > - switch (wdata->id) {
> > - case 0x100802:
> > - wdata->tool = BTN_TOOL_PEN;
> > - break;
> > - case 0x10080A:
> > - wdata->tool = BTN_TOOL_RUBBER;
> > - break;
> > - }
> > - break;
> > - default: /* Position/pressure report */
> > - x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
> > - y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
> > - pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
> > - | (data[1] & 0x01);
> > - distance = (data[9] >> 2) & 0x3f;
> > - tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
> > - tilt_y = data[8] & 0x7f;
> > -
> > - input_report_key(input, BTN_TOUCH, pressure > 1);
> > -
> > - input_report_key(input, BTN_STYLUS, data[1] & 0x02);
> > - input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
> > - input_report_key(input, wdata->tool, 1);
> > - input_report_abs(input, ABS_X, x);
> > - input_report_abs(input, ABS_Y, y);
> > - input_report_abs(input, ABS_PRESSURE, pressure);
> > - input_report_abs(input, ABS_DISTANCE, distance);
> > - input_report_abs(input, ABS_TILT_X, tilt_x);
> > - input_report_abs(input, ABS_TILT_Y, tilt_y);
> > - input_report_abs(input, ABS_MISC, wdata->id);
> > - input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
> > - input_report_key(input, wdata->tool, 1);
> > - input_sync(input);
> > - break;
> > - }
> > -
> > - return;
> > -}
> > -
> > -static void wacom_i4_parse_report(struct hid_device *hdev,
> > - struct wacom_data *wdata,
> > - struct input_dev *input, unsigned char *data)
> > -{
> > - switch (data[0]) {
> > - case 0x00: /* Empty report */
> > - break;
> > - case 0x02: /* Pen report */
> > - wacom_i4_parse_pen_report(wdata, input, data);
> > - break;
> > - case 0x03: /* Features Report */
> > - wdata->features = data[2];
> > - break;
> > - case 0x0C: /* Button report */
> > - wacom_i4_parse_button_report(wdata, input, data);
> > - break;
> > - default:
> > - hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
> > - break;
> > - }
> > -}
> > -
> > -static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
> > - u8 *raw_data, int size)
> > -{
> > - struct wacom_data *wdata = hid_get_drvdata(hdev);
> > - struct hid_input *hidinput;
> > - struct input_dev *input;
> > - unsigned char *data = (unsigned char *) raw_data;
> > - int i;
> > - __u8 power_raw;
> > -
> > - if (!(hdev->claimed & HID_CLAIMED_INPUT))
> > - return 0;
> > -
> > - hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
> > - input = hidinput->input;
> > -
> > - switch (hdev->product) {
> > - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> > - if (data[0] == 0x03) {
> > - return wacom_gr_parse_report(hdev, wdata, input, data);
> > - } else {
> > - hid_err(hdev, "Unknown report: %d,%d size:%d\n",
> > - data[0], data[1], size);
> > - return 0;
> > - }
> > - break;
> > - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> > - i = 1;
> > -
> > - switch (data[0]) {
> > - case 0x04:
> > - wacom_i4_parse_report(hdev, wdata, input, data + i);
> > - i += 10;
> > - /* fall through */
> > - case 0x03:
> > - wacom_i4_parse_report(hdev, wdata, input, data + i);
> > - i += 10;
> > - wacom_i4_parse_report(hdev, wdata, input, data + i);
> > - power_raw = data[i+10];
> > - if (power_raw != wdata->power_raw) {
> > - wdata->power_raw = power_raw;
> > - wdata->battery_capacity = batcap_i4[power_raw & 0x07];
> > - wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
> > - wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
> > - }
> > -
> > - break;
> > - default:
> > - hid_err(hdev, "Unknown report: %d,%d size:%d\n",
> > - data[0], data[1], size);
> > - return 0;
> > - }
> > - }
> > - return 1;
> > -}
> > -
> > -static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
> > - struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
> > - int *max)
> > -{
> > - struct input_dev *input = hi->input;
> > -
> > - __set_bit(INPUT_PROP_POINTER, input->propbit);
> > -
> > - /* Basics */
> > - input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
> > -
> > - __set_bit(REL_WHEEL, input->relbit);
> > -
> > - __set_bit(BTN_TOOL_PEN, input->keybit);
> > - __set_bit(BTN_TOUCH, input->keybit);
> > - __set_bit(BTN_STYLUS, input->keybit);
> > - __set_bit(BTN_STYLUS2, input->keybit);
> > - __set_bit(BTN_LEFT, input->keybit);
> > - __set_bit(BTN_RIGHT, input->keybit);
> > - __set_bit(BTN_MIDDLE, input->keybit);
> > -
> > - /* Pad */
> > - input_set_capability(input, EV_MSC, MSC_SERIAL);
> > -
> > - __set_bit(BTN_0, input->keybit);
> > - __set_bit(BTN_1, input->keybit);
> > - __set_bit(BTN_TOOL_FINGER, input->keybit);
> > -
> > - /* Distance, rubber and mouse */
> > - __set_bit(BTN_TOOL_RUBBER, input->keybit);
> > - __set_bit(BTN_TOOL_MOUSE, input->keybit);
> > -
> > - switch (hdev->product) {
> > - case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
> > - input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
> > - input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
> > - input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
> > - input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
> > - break;
> > - case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
> > - __set_bit(ABS_WHEEL, input->absbit);
> > - __set_bit(ABS_MISC, input->absbit);
> > - __set_bit(BTN_2, input->keybit);
> > - __set_bit(BTN_3, input->keybit);
> > - __set_bit(BTN_4, input->keybit);
> > - __set_bit(BTN_5, input->keybit);
> > - __set_bit(BTN_6, input->keybit);
> > - __set_bit(BTN_7, input->keybit);
> > - __set_bit(BTN_8, input->keybit);
> > - input_set_abs_params(input, ABS_WHEEL, 0, 71, 0, 0);
> > - input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
> > - input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
> > - input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
> > - input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
> > - input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
> > - input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
> > - break;
> > - }
> > -
> > - return 0;
> > -}
> > -
> > -static int wacom_probe(struct hid_device *hdev,
> > - const struct hid_device_id *id)
> > -{
> > - struct wacom_data *wdata;
> > - int ret;
> > -
> > - wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
> > - if (wdata == NULL) {
> > - hid_err(hdev, "can't alloc wacom descriptor\n");
> > - return -ENOMEM;
> > - }
> > -
> > - hid_set_drvdata(hdev, wdata);
> > -
> > - /* Parse the HID report now */
> > - ret = hid_parse(hdev);
> > - if (ret) {
> > - hid_err(hdev, "parse failed\n");
> > - goto err_free;
> > - }
> > -
> > - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> > - if (ret) {
> > - hid_err(hdev, "hw start failed\n");
> > - goto err_free;
> > - }
> > -
> > - ret = device_create_file(&hdev->dev, &dev_attr_speed);
> > - if (ret)
> > - hid_warn(hdev,
> > - "can't create sysfs speed attribute err: %d\n", ret);
> > -
> > -#define OLED_INIT(OLED_ID) \
> > - do { \
> > - ret = device_create_file(&hdev->dev, \
> > - &dev_attr_oled##OLED_ID##_img); \
> > - if (ret) \
> > - hid_warn(hdev, \
> > - "can't create sysfs oled attribute, err: %d\n", ret);\
> > - } while (0)
> > -
> > -OLED_INIT(0);
> > -OLED_INIT(1);
> > -OLED_INIT(2);
> > -OLED_INIT(3);
> > -OLED_INIT(4);
> > -OLED_INIT(5);
> > -OLED_INIT(6);
> > -OLED_INIT(7);
> > -
> > - wdata->features = 0;
> > - wacom_set_features(hdev, 1);
> > -
> > - if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
> > - sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
> > - ret = wacom_initialize_leds(hdev);
> > - if (ret)
> > - hid_warn(hdev,
> > - "can't create led attribute, err: %d\n", ret);
> > - }
> > -
> > - wdata->battery.properties = wacom_battery_props;
> > - wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
> > - wdata->battery.get_property = wacom_battery_get_property;
> > - wdata->battery.name = "wacom_battery";
> > - wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
> > - wdata->battery.use_for_apm = 0;
> > -
> > -
> > - ret = power_supply_register(&hdev->dev, &wdata->battery);
> > - if (ret) {
> > - hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
> > - ret);
> > - goto err_battery;
> > - }
> > -
> > - power_supply_powers(&wdata->battery, &hdev->dev);
> > -
> > - wdata->ac.properties = wacom_ac_props;
> > - wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
> > - wdata->ac.get_property = wacom_ac_get_property;
> > - wdata->ac.name = "wacom_ac";
> > - wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
> > - wdata->ac.use_for_apm = 0;
> > -
> > - ret = power_supply_register(&hdev->dev, &wdata->ac);
> > - if (ret) {
> > - hid_err(hdev,
> > - "can't create ac battery attribute, err: %d\n", ret);
> > - goto err_ac;
> > - }
> > -
> > - power_supply_powers(&wdata->ac, &hdev->dev);
> > - return 0;
> > -
> > -err_ac:
> > - power_supply_unregister(&wdata->battery);
> > -err_battery:
> > - wacom_destroy_leds(hdev);
> > - device_remove_file(&hdev->dev, &dev_attr_oled0_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled1_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled2_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled3_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled4_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled5_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled6_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled7_img);
> > - device_remove_file(&hdev->dev, &dev_attr_speed);
> > - hid_hw_stop(hdev);
> > -err_free:
> > - kfree(wdata);
> > - return ret;
> > -}
> > -
> > -static void wacom_remove(struct hid_device *hdev)
> > -{
> > - struct wacom_data *wdata = hid_get_drvdata(hdev);
> > -
> > - wacom_destroy_leds(hdev);
> > - device_remove_file(&hdev->dev, &dev_attr_oled0_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled1_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled2_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled3_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled4_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled5_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled6_img);
> > - device_remove_file(&hdev->dev, &dev_attr_oled7_img);
> > - device_remove_file(&hdev->dev, &dev_attr_speed);
> > - hid_hw_stop(hdev);
> > -
> > - power_supply_unregister(&wdata->battery);
> > - power_supply_unregister(&wdata->ac);
> > - kfree(hid_get_drvdata(hdev));
> > -}
> > -
> > -static const struct hid_device_id wacom_devices[] = {
> > -
> > - { }
> > -};
> > -MODULE_DEVICE_TABLE(hid, wacom_devices);
> > -
> > -static struct hid_driver wacom_driver = {
> > - .name = "hid-wacom",
> > - .id_table = wacom_devices,
> > - .probe = wacom_probe,
> > - .remove = wacom_remove,
> > - .raw_event = wacom_raw_event,
> > - .input_mapped = wacom_input_mapped,
> > -};
> > -module_hid_driver(wacom_driver);
> > -
> > -MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
> > -MODULE_LICENSE("GPL");
>
> --
> Kind regards,
> Przemo Firszt
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] drivers: Let several drivers depends on HAS_IOMEM for 'devm_ioremap_resource'
From: Chris Metcalf @ 2014-07-31 20:09 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Chen Gang, Lars-Peter Clausen, Guenter Roeck, Richard Weinberger,
Greg Kroah-Hartman, dmitry.torokhov, linux-iio,
Benjamin Herrenschmidt, teg, Thierry Reding, Lennox Wu,
Marek Vasut, Liqin Chen, msalter, linux-pwm, devel,
linux-watchdog, linux-input, linux-kernel@vger.kernel.org,
knaack.h, Martin Schwidefsky, Mischa.Jonker, jic23,
Geert Uytterhoeven
In-Reply-To: <5190668.jExaFa8pKn@wuerfel>
On 7/17/2014 5:05 PM, Arnd Bergmann wrote:
> On Thursday 17 July 2014 16:41:14 Chris Metcalf wrote:
>> On 7/17/2014 7:28 AM, Chen Gang wrote:
>>> According to current source code, tile still has chance to choose
>>> NO_IOMEM, for me, welcome the tile's maintainer's ideas or suggestions.
>> I'm not really sure. It's true that on tile, if you don't enable PCI
>> support there's no other I/O memory (or I/O port) space you can use.
>> We pretty much always enable PCI support in our kernel, though. I'm
>> kind of surprised that other architectures don't also have the model
>> that IOMEM requires PCI, but perhaps most architectures just don't
>> encode that in the Kconfig file?
> Only s390 as far as I know. Most architectures have integrated
> peripherals that use MMIO without PCI.
Yes, and tilegx has these too (quite a few of them). The memory-mapped
devices are accessed by specifying a shim x,y coordinate in the high bits
of the physical address, in conjunction with an MMIO type in the TLB entry.
Various tilegx drivers set up these kinds of mappings in the page table.
The issue with ioremap() is that it takes a generic resource_size_t
"physical address", and we don't have any general-purpose layer that maps
particular PAs to shim coordinates, other than for TRIO (our PCI peripheral).
Right now we just check the PCI root complexes that we have configured in
the kernel, and if the pseudo physical address requested is in a range that
we're associating with one of the root complexes, we will use the appropriate
mapping against the appropriate TRIO shim to set up its x,y coordinate in
the page table.
So it makes some kind of sense to condition HAS_IOMEM on PCI, even though
naively it seems like it shouldn't be strictly related.
--
Chris Metcalf, Tilera Corp.
http://www.tilera.com
^ permalink raw reply
* Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
From: Christopher Heiny @ 2014-07-31 21:00 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Linus Walleij, Benjamin Tissoires,
David Herrmann, Jiri Kosina
In-Reply-To: <20140731175323.GB5631@core.coreip.homeip.net>
On 07/31/2014 10:53 AM, Dmitry Torokhov wrote:
> Hi Christopher,
>
> On Wed, Mar 12, 2014 at 06:53:56PM -0700, Christopher Heiny wrote:
>> Add support for updating firmware on RMI4 devices with V5 bootloader.
>
> I am wondering why F34 is not following the staindard RMI function
> implementation. By that I mean that it does not declare itself as struct
> rmi_function_handler and does not rely on RMI core to bind itself to the device
> if device supports it.
Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function
standard and exposed most of the basic F34 operations via sysfs.
However, we got feedback (both on LKML and offline) (a) recommending to
use request_firmware, and (b) improve reflash times while (c) reducing
impact on boot time, and (d) "get rid of all that sysfs crap"
(paraphrased, but close to it).
So after looking at how some other drivers use request_firmware, we came
up with the current approach. Switching to request_firmware definitely
sped up the reflash times! Including a check to see if firmware update
is required before setting up the RMI4 sensor/function structures also
significantly reduced boot times.
> By the way, isn't rmi_extract_u32() is the same as le32_to_cpup()?
Hmmm. Looks like that one escaped the sweep of roll-your-own endian
fixes. I'll update it.
Chris
^ permalink raw reply
* Re: [PATCH v3 4/7] Input - wacom: Check for bluetooth protocol while setting OLEDs
From: Przemo Firszt @ 2014-07-31 21:14 UTC (permalink / raw)
To: Ping Cheng
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Jason Gerecke,
linux-kernel@vger.kernel.org, linux-input
In-Reply-To: <CAF8JNhK1R3mzfJA2OZwZv3-KwqpFBkOjDmzM1JkZW_Wix+Ww8g@mail.gmail.com>
Dnia 2014-07-31, czw o godzinie 08:56 -0700, Ping Cheng pisze:
[..]
Hi Ping,
> I'd like to see Przemo's Tested-by tag here as well. Przemo, are you
> done with your testing?
Whole series:
Tested-by: Przemo Firszt <przemo@firszt.eu>
Tested on two Intuos4 Wireless (usb + bt) tablets. Everything works as
expected.
If someone wants to test icons scrambling in the userspace I added
option to i4oled (switch -B):
https://github.com/PrzemoF/i4oled/tree/v1.3
> Thank you Przemo and Benjamin for your effort in making this
> transition smooth and successful. We, at Wacom, are very grateful to
> be part of this great community.
Thanks! All credit goes to Benjamin :-)
--
Kind regards,
Przemo Firszt
^ permalink raw reply
* Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
From: Dmitry Torokhov @ 2014-07-31 21:19 UTC (permalink / raw)
To: Christopher Heiny
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Linus Walleij, Benjamin Tissoires,
David Herrmann, Jiri Kosina
In-Reply-To: <53DAAE5E.7030708@synaptics.com>
On Thu, Jul 31, 2014 at 02:00:14PM -0700, Christopher Heiny wrote:
> On 07/31/2014 10:53 AM, Dmitry Torokhov wrote:
> >Hi Christopher,
> >
> >On Wed, Mar 12, 2014 at 06:53:56PM -0700, Christopher Heiny wrote:
> >>Add support for updating firmware on RMI4 devices with V5 bootloader.
> >
> >I am wondering why F34 is not following the staindard RMI function
> >implementation. By that I mean that it does not declare itself as struct
> >rmi_function_handler and does not rely on RMI core to bind itself to the device
> >if device supports it.
>
> Hi Dmitry,
>
> We originally had an F34 implementation that followed the RMI4
> function standard and exposed most of the basic F34 operations via
> sysfs. However, we got feedback (both on LKML and offline) (a)
> recommending to use request_firmware, and (b) improve reflash times
> while (c) reducing impact on boot time, and (d) "get rid of all that
> sysfs crap" (paraphrased, but close to it).
>
> So after looking at how some other drivers use request_firmware, we
> came up with the current approach. Switching to request_firmware
> definitely sped up the reflash times! Including a check to see if
> firmware update is required before setting up the RMI4
> sensor/function structures also significantly reduced boot times.
I am not suggesting you stop using request-firmware or introduce
bazillion of new sysfs attributes. I just wondered why you have manual
"binding" of F34 functionality instead of standrad RMI4 function
binding, liek you do for F01, F11 and so forth.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
From: Christopher Heiny @ 2014-07-31 21:43 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Linus Walleij, Benjamin Tissoires,
David Herrmann, Jiri Kosina
In-Reply-To: <20140731211921.GA36491@core.coreip.homeip.net>
On 07/31/2014 02:19 PM, Dmitry Torokhov wrote:
> On Thu, Jul 31, 2014 at 02:00:14PM -0700, Christopher Heiny wrote:
>> >On 07/31/2014 10:53 AM, Dmitry Torokhov wrote:
>>> > >Hi Christopher,
>>> > >
>>> > >On Wed, Mar 12, 2014 at 06:53:56PM -0700, Christopher Heiny wrote:
>>>> > >>Add support for updating firmware on RMI4 devices with V5 bootloader.
>>> > >
>>> > >I am wondering why F34 is not following the staindard RMI function
>>> > >implementation. By that I mean that it does not declare itself as struct
>>> > >rmi_function_handler and does not rely on RMI core to bind itself to the device
>>> > >if device supports it.
>> >
>> >Hi Dmitry,
>> >
>> >We originally had an F34 implementation that followed the RMI4
>> >function standard and exposed most of the basic F34 operations via
>> >sysfs. However, we got feedback (both on LKML and offline) (a)
>> >recommending to use request_firmware, and (b) improve reflash times
>> >while (c) reducing impact on boot time, and (d) "get rid of all that
>> >sysfs crap" (paraphrased, but close to it).
>> >
>> >So after looking at how some other drivers use request_firmware, we
>> >came up with the current approach. Switching to request_firmware
>> >definitely sped up the reflash times! Including a check to see if
>> >firmware update is required before setting up the RMI4
>> >sensor/function structures also significantly reduced boot times.
>
> I am not suggesting you stop using request-firmware or introduce
> bazillion of new sysfs attributes. I just wondered why you have manual
> "binding" of F34 functionality instead of standrad RMI4 function
> binding, liek you do for F01, F11 and so forth.
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the
boot/probe process. This eliminates the need to set up the whole sensor
+ functions structure, tear it down in order to reflash, and then build
it all back up again. It is felt that the time savings is significant,
especially on highly featured products.
Chris
^ permalink raw reply
* Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
From: Dmitry Torokhov @ 2014-07-31 21:58 UTC (permalink / raw)
To: Christopher Heiny
Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
Daniel Rosenberg, Linus Walleij, Benjamin Tissoires,
David Herrmann, Jiri Kosina
In-Reply-To: <53DAB893.2070308@synaptics.com>
On Thu, Jul 31, 2014 at 02:43:47PM -0700, Christopher Heiny wrote:
> On 07/31/2014 02:19 PM, Dmitry Torokhov wrote:
> >On Thu, Jul 31, 2014 at 02:00:14PM -0700, Christopher Heiny wrote:
> >>>On 07/31/2014 10:53 AM, Dmitry Torokhov wrote:
> >>>> >Hi Christopher,
> >>>> >
> >>>> >On Wed, Mar 12, 2014 at 06:53:56PM -0700, Christopher Heiny wrote:
> >>>>> >>Add support for updating firmware on RMI4 devices with V5 bootloader.
> >>>> >
> >>>> >I am wondering why F34 is not following the staindard RMI function
> >>>> >implementation. By that I mean that it does not declare itself as struct
> >>>> >rmi_function_handler and does not rely on RMI core to bind itself to the device
> >>>> >if device supports it.
> >>>
> >>>Hi Dmitry,
> >>>
> >>>We originally had an F34 implementation that followed the RMI4
> >>>function standard and exposed most of the basic F34 operations via
> >>>sysfs. However, we got feedback (both on LKML and offline) (a)
> >>>recommending to use request_firmware, and (b) improve reflash times
> >>>while (c) reducing impact on boot time, and (d) "get rid of all that
> >>>sysfs crap" (paraphrased, but close to it).
> >>>
> >>>So after looking at how some other drivers use request_firmware, we
> >>>came up with the current approach. Switching to request_firmware
> >>>definitely sped up the reflash times! Including a check to see if
> >>>firmware update is required before setting up the RMI4
> >>>sensor/function structures also significantly reduced boot times.
> >
> >I am not suggesting you stop using request-firmware or introduce
> >bazillion of new sysfs attributes. I just wondered why you have manual
> >"binding" of F34 functionality instead of standrad RMI4 function
> >binding, liek you do for F01, F11 and so forth.
>
> Sorry! My answer wasn't very clear on that part, was it?
>
> The manual binding gets the reflash (if required) done very early in
> the boot/probe process. This eliminates the need to set up the
> whole sensor + functions structure, tear it down in order to
> reflash, and then build it all back up again. It is felt that the
> time savings is significant, especially on highly featured products.
I am sorry but I have hard time accepting this argument. How often do
you reflash devices during normal operation and how long does it take to
initialize the device compared to getting entire userspace up and
running to be able to actually supply or serve flash data (even without
using usermode helper to flash you need filesystem with the firmware to
be mounted)?
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Yoichi Yuasa @ 2014-08-01 5:31 UTC (permalink / raw)
To: Pramod Gurav; +Cc: yuasa, Dmitry Torokhov, linux-input
In-Reply-To: <53DA2E82.1040704@smartplayin.com>
Hi Pramod,
Thank you for your comments.
On Thu, 31 Jul 2014 17:24:42 +0530
Pramod Gurav <pramod.gurav@smartplayin.com> wrote:
> Hi Yoichi,
>
> On Thursday 31 July 2014 04:24 PM, Yoichi Yuasa wrote:
> > Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
> > ---
> > drivers/input/touchscreen/Kconfig | 11 +
> > drivers/input/touchscreen/Makefile | 1 +
> > drivers/input/touchscreen/rohm_bu21023.c | 791 ++++++++++++++++++++++++++++++
> > drivers/input/touchscreen/rohm_bu21023.h | 255 ++++++++++
> > 4 files changed, 1058 insertions(+)
>
[snip]
> > +static inline int rohm_i2c_burst_read(struct i2c_adapter *adap,
> > + struct i2c_msg *msgs, int num)
> > +{
> > + int ret, i;
> > +
> > + if (!adap->algo->master_xfer) {
> > + dev_dbg(&adap->dev, "I2C level transfers not supported\n");
> Should it be dev_err?
Yes it is.
> > +static int rohm_bu21023_i2c_probe(struct i2c_client *client,
> > + const struct i2c_device_id *id)
> > +{
> > + struct rohm_ts_data *ts;
> > + struct device *dev = &client->dev;
> > + struct input_dev *input_dev;
> > + int ret;
> > +
> > + ts = kzalloc(sizeof(struct rohm_ts_data), GFP_KERNEL);
> Can you please move to managed resources? devm_kzalloc in this case?
I'll move these to managed resources.
> > +
> > +MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver");
> > +MODULE_LICENSE("GPL");
> Make it GPL v2.
> MODULE_AUTHOR missing.
I'll try to contact the original author.
Thanks,
Yoichi
^ permalink raw reply
* Re: [PATCH] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Yoichi Yuasa @ 2014-08-01 10:32 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: yuasa, linux-input
In-Reply-To: <20140731171655.GA5631@core.coreip.homeip.net>
Hi Dmitry,
On Thu, 31 Jul 2014 10:16:55 -0700
Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote:
> Hi Yuichi,
>
> On Thu, Jul 31, 2014 at 07:54:34PM +0900, Yoichi Yuasa wrote:
> > Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
>
> I few high-level comments:
>
> - please get rid of polling - it is not useful in production mode;
> - switch to threaded interrupts so that you do not need to manage
> workqueue/work/timers;
> - new drivers should use MT-B protocol with proper contact tracking. If device
> does not do good job at tracking contacts you can use input's core matching
> algorithm (input_mt_assign_slots).
> - please provide ST emulation as well (input_mt_report_pointer_emulation).
> - the way you requesting firmware in probe path means you need to build
> firmware image into kernel or be careful how you pack it to avoid timeouts on
> boot. Since the device properties are not changing you might want to postpone
> that until somebody tries to open the device.
> - please add error handling for IO operations.
> - managed resources simplify the code.
Thank you for your comments.
I'll try to update.
Thanks,
Yoichi
^ permalink raw reply
* GPIO-muxed inputs
From: Alexander Stein @ 2014-08-01 11:49 UTC (permalink / raw)
To: linux-input
Hi,
I have a custom board which has 2 DIP switches connected to some GPIOs. I think I could use gpio_tilt_polled to generate proper input events. But the twist here is, that those switches uses the same GPIOs but are muxed by an additional GPIO. I'm wondering how this can be solved. An idea would be to add i2c-mux like "bus" where each input device is connected to. I think this way you can block "users" of the muxing GPIO before they can switch that.
Is this a proper way to go? How should (optional feature) should be integrated? Any other ideas?
Best regards,
Alexander
^ permalink raw reply
* [PATCH] HID: hyperv: register as a wakeup source
From: Dexuan Cui @ 2014-08-01 14:26 UTC (permalink / raw)
To: gregkh, jkosina, linux-input, linux-kernel, driverdev-devel, olaf,
apw, jasowang
Cc: kys, haiyangz
With this patch, we can move the mouse to wake up the VM after the VM executes
"echo freeze > /sys/power/state".
This addresses part of https://bugzilla.redhat.com/show_bug.cgi?id=1086100
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Dexuan Cui <decui@microsoft.com>
---
drivers/hid/hid-hyperv.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index f52dbcb..31fad64 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -308,6 +308,9 @@ static void mousevsc_on_receive(struct hv_device *device,
memcpy(input_dev->input_buf, input_report->buffer, len);
hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
input_dev->input_buf, len, 1);
+
+ pm_wakeup_event(&input_dev->device->device, 0);
+
break;
default:
pr_err("unsupported hid msg type - type %d len %d",
@@ -549,6 +552,8 @@ static int mousevsc_probe(struct hv_device *device,
goto probe_err2;
}
+ device_init_wakeup(&device->device, true);
+
input_dev->connected = true;
input_dev->init_complete = true;
@@ -571,6 +576,7 @@ static int mousevsc_remove(struct hv_device *dev)
{
struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+ device_init_wakeup(&dev->device, false);
vmbus_close(dev->channel);
hid_hw_stop(input_dev->hid_device);
hid_destroy_device(input_dev->hid_device);
--
1.9.1
^ permalink raw reply related
* [PATCH] Input: hyperv-keyboard: register as a wakeup source
From: Dexuan Cui @ 2014-08-01 14:28 UTC (permalink / raw)
To: gregkh, dmitry.torokhov, linux-input, linux-kernel,
driverdev-devel, olaf, apw, jasowang
Cc: haiyangz
With this patch, we can press a key to wake up the VM after the VM executes
"echo freeze > /sys/power/state".
This addresses part of https://bugzilla.redhat.com/show_bug.cgi?id=1086100
Cc: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Dexuan Cui <decui@microsoft.com>
---
drivers/input/serio/hyperv-keyboard.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index 6132619..e74e5d6 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -170,6 +170,15 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
}
spin_unlock_irqrestore(&kbd_dev->lock, flags);
+
+ /*
+ * Only trigger a wakeup on key down, otherwise
+ * "echo freeze > /sys/power/state" can't really enter the
+ * state because the Enter-UP can trigger a wakeup at once.
+ */
+ if (!(info & IS_BREAK))
+ pm_wakeup_event(&hv_dev->device, 0);
+
break;
default:
@@ -376,6 +385,9 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
goto err_close_vmbus;
serio_register_port(kbd_dev->hv_serio);
+
+ device_init_wakeup(&hv_dev->device, true);
+
return 0;
err_close_vmbus:
@@ -390,6 +402,7 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
{
struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
+ device_init_wakeup(&hv_dev->device, false);
serio_unregister_port(kbd_dev->hv_serio);
vmbus_close(hv_dev->channel);
kfree(kbd_dev);
--
1.9.1
^ permalink raw reply related
* RE: [PATCH] Input: hyperv-keyboard: register as a wakeup source
From: KY Srinivasan @ 2014-08-01 17:29 UTC (permalink / raw)
To: Dexuan Cui, gregkh@linuxfoundation.org, dmitry.torokhov@gmail.com,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
driverdev-devel@linuxdriverproject.org, olaf@aepfle.de,
apw@canonical.com, jasowang@redhat.com
Cc: Haiyang Zhang
In-Reply-To: <1406903304-7256-1-git-send-email-decui@microsoft.com>
> -----Original Message-----
> From: Dexuan Cui [mailto:decui@microsoft.com]
> Sent: Friday, August 1, 2014 7:28 AM
> To: gregkh@linuxfoundation.org; dmitry.torokhov@gmail.com; linux-
> input@vger.kernel.org; linux-kernel@vger.kernel.org; driverdev-
> devel@linuxdriverproject.org; olaf@aepfle.de; apw@canonical.com;
> jasowang@redhat.com
> Cc: KY Srinivasan; Haiyang Zhang
> Subject: [PATCH] Input: hyperv-keyboard: register as a wakeup source
>
> With this patch, we can press a key to wake up the VM after the VM
> executes "echo freeze > /sys/power/state".
>
> This addresses part of https://bugzilla.redhat.com/show_bug.cgi?id=1086100
>
> Cc: K. Y. Srinivasan <kys@microsoft.com>
Thanks Dexuan.
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Dexuan Cui <decui@microsoft.com>
> ---
> drivers/input/serio/hyperv-keyboard.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/drivers/input/serio/hyperv-keyboard.c
> b/drivers/input/serio/hyperv-keyboard.c
> index 6132619..e74e5d6 100644
> --- a/drivers/input/serio/hyperv-keyboard.c
> +++ b/drivers/input/serio/hyperv-keyboard.c
> @@ -170,6 +170,15 @@ static void hv_kbd_on_receive(struct hv_device
> *hv_dev,
> serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
> }
> spin_unlock_irqrestore(&kbd_dev->lock, flags);
> +
> + /*
> + * Only trigger a wakeup on key down, otherwise
> + * "echo freeze > /sys/power/state" can't really enter the
> + * state because the Enter-UP can trigger a wakeup at once.
> + */
> + if (!(info & IS_BREAK))
> + pm_wakeup_event(&hv_dev->device, 0);
> +
> break;
>
> default:
> @@ -376,6 +385,9 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
> goto err_close_vmbus;
>
> serio_register_port(kbd_dev->hv_serio);
> +
> + device_init_wakeup(&hv_dev->device, true);
> +
> return 0;
>
> err_close_vmbus:
> @@ -390,6 +402,7 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
> {
> struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
>
> + device_init_wakeup(&hv_dev->device, false);
> serio_unregister_port(kbd_dev->hv_serio);
> vmbus_close(hv_dev->channel);
> kfree(kbd_dev);
> --
> 1.9.1
^ permalink raw reply
* RE: [PATCH] HID: hyperv: register as a wakeup source
From: KY Srinivasan @ 2014-08-01 17:29 UTC (permalink / raw)
To: Dexuan Cui, gregkh@linuxfoundation.org, jkosina@suse.cz,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
driverdev-devel@linuxdriverproject.org, olaf@aepfle.de,
apw@canonical.com, jasowang@redhat.com
Cc: Haiyang Zhang
In-Reply-To: <1406903201-7210-1-git-send-email-decui@microsoft.com>
> -----Original Message-----
> From: Dexuan Cui [mailto:decui@microsoft.com]
> Sent: Friday, August 1, 2014 7:27 AM
> To: gregkh@linuxfoundation.org; jkosina@suse.cz; linux-
> input@vger.kernel.org; linux-kernel@vger.kernel.org; driverdev-
> devel@linuxdriverproject.org; olaf@aepfle.de; apw@canonical.com;
> jasowang@redhat.com
> Cc: KY Srinivasan; Haiyang Zhang
> Subject: [PATCH] HID: hyperv: register as a wakeup source
>
> With this patch, we can move the mouse to wake up the VM after the VM
> executes "echo freeze > /sys/power/state".
>
> This addresses part of https://bugzilla.redhat.com/show_bug.cgi?id=1086100
>
> Cc: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> ---
> drivers/hid/hid-hyperv.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index
> f52dbcb..31fad64 100644
> --- a/drivers/hid/hid-hyperv.c
> +++ b/drivers/hid/hid-hyperv.c
> @@ -308,6 +308,9 @@ static void mousevsc_on_receive(struct hv_device
> *device,
> memcpy(input_dev->input_buf, input_report->buffer, len);
> hid_input_report(input_dev->hid_device,
> HID_INPUT_REPORT,
> input_dev->input_buf, len, 1);
> +
> + pm_wakeup_event(&input_dev->device->device, 0);
> +
> break;
> default:
> pr_err("unsupported hid msg type - type %d len %d", @@ -
> 549,6 +552,8 @@ static int mousevsc_probe(struct hv_device *device,
> goto probe_err2;
> }
>
> + device_init_wakeup(&device->device, true);
> +
> input_dev->connected = true;
> input_dev->init_complete = true;
>
> @@ -571,6 +576,7 @@ static int mousevsc_remove(struct hv_device *dev) {
> struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
>
> + device_init_wakeup(&dev->device, false);
> vmbus_close(dev->channel);
> hid_hw_stop(input_dev->hid_device);
> hid_destroy_device(input_dev->hid_device);
> --
> 1.9.1
^ permalink raw reply
* Re: [PATCH 2/7] i2c: i2c-cros-ec-tunnel: Set retries to 3
From: Wolfram Sang @ 2014-08-01 17:59 UTC (permalink / raw)
To: Javier Martinez Canillas
Cc: Lee Jones, Dmitry Torokhov, Doug Anderson, Simon Glass,
Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
Olof Johansson, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1406549967-21291-3-git-send-email-javier.martinez-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1584 bytes --]
On Mon, Jul 28, 2014 at 02:19:22PM +0200, Javier Martinez Canillas wrote:
> From: Derek Basehore <dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>
> Since the i2c bus can get wedged on the EC sometimes, set the number of retries
> to 3. Since we un-wedge the bus immediately after the wedge happens, this is the
> correct fix since only one transfer will fail.
>
> Signed-off-by: Derek Basehore <dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Reviewed-by: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
> drivers/i2c/busses/i2c-cros-ec-tunnel.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
> index 05e033c..a4411da 100644
> --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
> +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
> @@ -16,6 +16,8 @@
> #include <linux/platform_device.h>
> #include <linux/slab.h>
>
> +#define I2C_MAX_RETRIES 3
I think a define for this is overkill, yet I don't really mind.
Acked-by: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
I assume this goes via MFD, let me know if I should take it.
> +
> /**
> * struct ec_i2c_device - Driver data for I2C tunnel
> *
> @@ -290,6 +292,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
> bus->adap.algo_data = bus;
> bus->adap.dev.parent = &pdev->dev;
> bus->adap.dev.of_node = np;
> + bus->adap.retries = I2C_MAX_RETRIES;
>
> err = i2c_add_adapter(&bus->adap);
> if (err) {
> --
> 2.0.0.rc2
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 2/7] i2c: i2c-cros-ec-tunnel: Set retries to 3
From: Javier Martinez Canillas @ 2014-08-01 18:05 UTC (permalink / raw)
To: Wolfram Sang
Cc: Lee Jones, Dmitry Torokhov, Doug Anderson, Simon Glass,
Bill Richardson, Andrew Bresticker, Derek Basehore, Todd Broch,
Olof Johansson, linux-i2c, linux-input, linux-samsung-soc
In-Reply-To: <20140801175912.GF3277@katana>
Hello Wolfram,
On 08/01/2014 07:59 PM, Wolfram Sang wrote:
>>
>> +#define I2C_MAX_RETRIES 3
>
> I think a define for this is overkill, yet I don't really mind.
>
> Acked-by: Wolfram Sang <wsa@the-dreams.de>
>
Thanks a lot.
> I assume this goes via MFD, let me know if I should take it.
>
Yes, if possible I prefer if all the series are picked by Lee Jones to avoid any
dependencies.
Best regards,
Javier
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox