Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input subsystem updates from Dmitry Torokhov: - updated support for Synaptics RMI4 devices, including support for SMBus controllers, firmware update support, sensor tuning, and PS/2 guest support - ALPS driver now supports tracksticks on SS5 controllers - i8042 now uses chassis info to skip selftest on Asus laptops as list of individual models became too unwieldy - miscellaneous fixes to other drivers * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (67 commits) Input: imx6ul_tsc - generalize the averaging property Input: drv260x - use generic device properties Input: drv260x - use temporary for &client->dev Input: drv260x - fix input device's parent assignment Input: synaptics-rmi4 - add support for F34 V7 bootloader Input: drv260x - fix initializing overdrive voltage Input: ALPS - fix protcol -> protocol Input: i8042 - comment #else/#endif of CONFIG_PNP Input: lpc32xx-keys - fix invalid error handling of a requested irq Input: synaptics-rmi4 - fix debug for sensor clip Input: synaptics-rmi4 - store the attn data in the driver Input: synaptics-rmi4 - allow to add attention data Input: synaptics-rmi4 - f03 - grab data passed by transport device Input: synaptics-rmi4 - add support for F03 Input: imx6ul_tsc - convert int to u32 Input: imx6ul_tsc - add mask when set REG_ADC_CFG Input: synaptics-rmi4 - have only one struct platform data Input: synaptics-rmi4 - remove EXPORT_SYMBOL_GPL for internal functions Input: synaptics-rmi4 - remove mutex calls while updating the firmware Input: drv2667 - fix misuse of regmap_update_bits ...
This commit is contained in:
@@ -27,6 +27,27 @@ config RMI4_SPI
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config RMI4_SMB
|
||||
tristate "RMI4 SMB Support"
|
||||
depends on RMI4_CORE && I2C
|
||||
help
|
||||
Say Y here if you want to support RMI4 devices connected to an SMB
|
||||
bus.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called rmi_smbus.
|
||||
|
||||
config RMI4_F03
|
||||
bool "RMI4 Function 03 (PS2 Guest)"
|
||||
depends on RMI4_CORE && SERIO
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 03.
|
||||
|
||||
Function 03 provides PS2 guest support for RMI4 devices. This
|
||||
includes support for TrackPoints on TouchPads.
|
||||
|
||||
config RMI4_2D_SENSOR
|
||||
bool
|
||||
depends on RMI4_CORE
|
||||
@@ -62,13 +83,34 @@ config RMI4_F30
|
||||
Function 30 provides GPIO and LED support for RMI4 devices. This
|
||||
includes support for buttons on TouchPads and ClickPads.
|
||||
|
||||
config RMI4_F34
|
||||
bool "RMI4 Function 34 (Device reflash)"
|
||||
depends on RMI4_CORE
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 34.
|
||||
|
||||
Function 34 provides support for upgrading the firmware on the RMI4
|
||||
device via the firmware loader interface. This is triggered using a
|
||||
sysfs attribute.
|
||||
|
||||
config RMI4_F54
|
||||
bool "RMI4 Function 54 (Analog diagnostics)"
|
||||
depends on RMI4_CORE
|
||||
depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select RMI4_F55
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 54
|
||||
|
||||
Function 54 provides access to various diagnostic features in certain
|
||||
RMI4 touch sensors.
|
||||
|
||||
config RMI4_F55
|
||||
bool "RMI4 Function 55 (Sensor tuning)"
|
||||
depends on RMI4_CORE
|
||||
help
|
||||
Say Y here if you want to add support for RMI4 function 55
|
||||
|
||||
Function 55 provides access to the RMI4 touch sensor tuning
|
||||
mechanism.
|
||||
|
@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
|
||||
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
|
||||
|
||||
# Function drivers
|
||||
rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
|
||||
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
|
||||
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
|
||||
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
|
||||
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
|
||||
rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
|
||||
rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
|
||||
|
||||
# Transports
|
||||
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
|
||||
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
|
||||
obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
|
||||
|
@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
|
||||
sensor->dmax = DMAX * res_x;
|
||||
}
|
||||
|
||||
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOOL_TYPE,
|
||||
0, MT_TOOL_MAX, 0, 0);
|
||||
|
||||
if (sensor->sensor_type == rmi_sensor_touchpad)
|
||||
input_flags = INPUT_MT_POINTER;
|
||||
|
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
|
||||
u8 report_rel;
|
||||
u8 x_mm;
|
||||
u8 y_mm;
|
||||
enum rmi_reg_state dribble;
|
||||
enum rmi_reg_state palm_detect;
|
||||
};
|
||||
|
||||
int rmi_2d_sensor_of_probe(struct device *dev,
|
||||
|
@@ -230,6 +230,9 @@ err_put_device:
|
||||
|
||||
void rmi_unregister_function(struct rmi_function *fn)
|
||||
{
|
||||
rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
|
||||
fn->fd.function_number);
|
||||
|
||||
device_del(&fn->dev);
|
||||
of_node_put(fn->dev.of_node);
|
||||
put_device(&fn->dev);
|
||||
@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = {
|
||||
|
||||
static struct rmi_function_handler *fn_handlers[] = {
|
||||
&rmi_f01_handler,
|
||||
#ifdef CONFIG_RMI4_F03
|
||||
&rmi_f03_handler,
|
||||
#endif
|
||||
#ifdef CONFIG_RMI4_F11
|
||||
&rmi_f11_handler,
|
||||
#endif
|
||||
@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = {
|
||||
#ifdef CONFIG_RMI4_F30
|
||||
&rmi_f30_handler,
|
||||
#endif
|
||||
#ifdef CONFIG_RMI4_F34
|
||||
&rmi_f34_handler,
|
||||
#endif
|
||||
#ifdef CONFIG_RMI4_F54
|
||||
&rmi_f54_handler,
|
||||
#endif
|
||||
#ifdef CONFIG_RMI4_F55
|
||||
&rmi_f55_handler,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void __rmi_unregister_function_handlers(int start_idx)
|
||||
|
@@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d)
|
||||
|
||||
bool rmi_is_physical_device(struct device *dev);
|
||||
|
||||
/**
|
||||
* rmi_reset - reset a RMI4 device
|
||||
* @d: Pointer to an RMI device
|
||||
*
|
||||
* Calls for a reset of each function implemented by a specific device.
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
static inline int rmi_reset(struct rmi_device *d)
|
||||
{
|
||||
return d->driver->reset_handler(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* rmi_read - read a single byte
|
||||
* @d: Pointer to an RMI device
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
@@ -33,12 +34,22 @@
|
||||
#define RMI_DEVICE_RESET_CMD 0x01
|
||||
#define DEFAULT_RESET_DELAY_MS 100
|
||||
|
||||
static void rmi_free_function_list(struct rmi_device *rmi_dev)
|
||||
void rmi_free_function_list(struct rmi_device *rmi_dev)
|
||||
{
|
||||
struct rmi_function *fn, *tmp;
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
|
||||
|
||||
devm_kfree(&rmi_dev->dev, data->irq_memory);
|
||||
data->irq_memory = NULL;
|
||||
data->irq_status = NULL;
|
||||
data->fn_irq_bits = NULL;
|
||||
data->current_irq_mask = NULL;
|
||||
data->new_irq_mask = NULL;
|
||||
|
||||
data->f01_container = NULL;
|
||||
data->f34_container = NULL;
|
||||
|
||||
/* Doing it in the reverse order so F01 will be removed last */
|
||||
list_for_each_entry_safe_reverse(fn, tmp,
|
||||
@@ -133,7 +144,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
|
||||
}
|
||||
}
|
||||
|
||||
int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (!rmi_dev->xport->attn_data) {
|
||||
if (!data->attn_data.data) {
|
||||
error = rmi_read_block(rmi_dev,
|
||||
data->f01_container->fd.data_base_addr + 1,
|
||||
data->irq_status, data->num_of_irq_regs);
|
||||
@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
|
||||
|
||||
void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
|
||||
void *data, size_t size)
|
||||
{
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi4_attn_data attn_data;
|
||||
void *fifo_data;
|
||||
|
||||
if (!drvdata->enabled)
|
||||
return;
|
||||
|
||||
fifo_data = kmemdup(data, size, GFP_ATOMIC);
|
||||
if (!fifo_data)
|
||||
return;
|
||||
|
||||
attn_data.irq_status = irq_status;
|
||||
attn_data.size = size;
|
||||
attn_data.data = fifo_data;
|
||||
|
||||
kfifo_put(&drvdata->attn_fifo, attn_data);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_set_attn_data);
|
||||
|
||||
static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct rmi_device *rmi_dev = dev_id;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi4_attn_data attn_data = {0};
|
||||
int ret, count;
|
||||
|
||||
count = kfifo_get(&drvdata->attn_fifo, &attn_data);
|
||||
if (count) {
|
||||
*(drvdata->irq_status) = attn_data.irq_status;
|
||||
drvdata->attn_data = attn_data;
|
||||
}
|
||||
|
||||
ret = rmi_process_interrupt_requests(rmi_dev);
|
||||
if (ret)
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
|
||||
"Failed to process interrupt request: %d\n", ret);
|
||||
|
||||
if (count)
|
||||
kfree(attn_data.data);
|
||||
|
||||
if (!kfifo_is_empty(&drvdata->attn_fifo))
|
||||
return rmi_irq_fn(irq, dev_id);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rmi_irq_init(struct rmi_device *rmi_dev)
|
||||
{
|
||||
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int irq_flags = irq_get_trigger_type(pdata->irq);
|
||||
int ret;
|
||||
|
||||
if (!irq_flags)
|
||||
irq_flags = IRQF_TRIGGER_LOW;
|
||||
|
||||
ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
|
||||
rmi_irq_fn, irq_flags | IRQF_ONESHOT,
|
||||
dev_name(rmi_dev->xport->dev),
|
||||
rmi_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
|
||||
pdata->irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int suspend_one_function(struct rmi_function *fn)
|
||||
{
|
||||
@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_sensor(struct rmi_device *rmi_dev)
|
||||
int rmi_enable_sensor(struct rmi_device *rmi_dev)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
|
||||
u16 pdt_address)
|
||||
static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
|
||||
struct pdt_entry *entry, u16 pdt_address)
|
||||
{
|
||||
u8 buf[RMI_PDT_ENTRY_SIZE];
|
||||
int error;
|
||||
@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
|
||||
|
||||
static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
|
||||
struct rmi_function_descriptor *fd)
|
||||
@@ -422,6 +506,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
|
||||
|
||||
static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
|
||||
int page,
|
||||
int *empty_pages,
|
||||
void *ctx,
|
||||
int (*callback)(struct rmi_device *rmi_dev,
|
||||
void *ctx,
|
||||
@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
|
||||
return retval;
|
||||
}
|
||||
|
||||
return (data->f01_bootloader_mode || addr == pdt_start) ?
|
||||
/*
|
||||
* Count number of empty PDT pages. If a gap of two pages
|
||||
* or more is found, stop scanning.
|
||||
*/
|
||||
if (addr == pdt_start)
|
||||
++*empty_pages;
|
||||
else
|
||||
*empty_pages = 0;
|
||||
|
||||
return (data->bootloader_mode || *empty_pages >= 2) ?
|
||||
RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
|
||||
}
|
||||
|
||||
static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
int (*callback)(struct rmi_device *rmi_dev,
|
||||
void *ctx,
|
||||
const struct pdt_entry *entry))
|
||||
int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
int (*callback)(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *entry))
|
||||
{
|
||||
int page;
|
||||
int empty_pages = 0;
|
||||
int retval = RMI_SCAN_DONE;
|
||||
|
||||
for (page = 0; page <= RMI4_MAX_PAGE; page++) {
|
||||
retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
|
||||
retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages,
|
||||
ctx, callback);
|
||||
if (retval != RMI_SCAN_CONTINUE)
|
||||
break;
|
||||
}
|
||||
@@ -600,7 +695,6 @@ free_struct_buff:
|
||||
kfree(struct_buf);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_read_register_desc);
|
||||
|
||||
const struct rmi_register_desc_item *rmi_get_register_desc_item(
|
||||
struct rmi_register_descriptor *rdesc, u16 reg)
|
||||
@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
|
||||
|
||||
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
|
||||
{
|
||||
@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
|
||||
}
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
|
||||
|
||||
/* Compute the register offset relative to the base address */
|
||||
int rmi_register_desc_calc_reg_offset(
|
||||
@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset(
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
|
||||
|
||||
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
|
||||
u8 subpacket)
|
||||
@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
|
||||
subpacket) == subpacket;
|
||||
}
|
||||
|
||||
/* Indicates that flash programming is enabled (bootloader mode). */
|
||||
#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
|
||||
|
||||
/*
|
||||
* Given the PDT entry for F01, read the device status register to determine
|
||||
* if we're stuck in bootloader mode or not.
|
||||
*
|
||||
*/
|
||||
static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
|
||||
const struct pdt_entry *pdt)
|
||||
{
|
||||
int error;
|
||||
u8 device_status;
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int ret;
|
||||
u8 status;
|
||||
|
||||
error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
|
||||
&device_status);
|
||||
if (error) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read device status: %d.\n", error);
|
||||
return error;
|
||||
if (pdt->function_number == 0x34 && pdt->function_version > 1) {
|
||||
ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
|
||||
if (ret) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read F34 status: %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status & BIT(7))
|
||||
data->bootloader_mode = true;
|
||||
} else if (pdt->function_number == 0x01) {
|
||||
ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
|
||||
if (ret) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed to read F01 status: %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status & BIT(6))
|
||||
data->bootloader_mode = true;
|
||||
}
|
||||
|
||||
return RMI_F01_STATUS_BOOTLOADER(device_status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_count_irqs(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *pdt)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int *irq_count = ctx;
|
||||
int ret;
|
||||
|
||||
*irq_count += pdt->interrupt_source_count;
|
||||
if (pdt->function_number == 0x01) {
|
||||
data->f01_bootloader_mode =
|
||||
rmi_check_bootloader_mode(rmi_dev, pdt);
|
||||
if (data->f01_bootloader_mode)
|
||||
dev_warn(&rmi_dev->dev,
|
||||
"WARNING: RMI4 device is in bootloader mode!\n");
|
||||
}
|
||||
|
||||
ret = rmi_check_bootloader_mode(rmi_dev, pdt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return RMI_SCAN_CONTINUE;
|
||||
}
|
||||
|
||||
static int rmi_initial_reset(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *pdt)
|
||||
int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
|
||||
const struct pdt_entry *pdt)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
|
||||
return RMI_SCAN_DONE;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n");
|
||||
error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
|
||||
if (error) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
|
||||
if (pdt->function_number == 0x01)
|
||||
data->f01_container = fn;
|
||||
else if (pdt->function_number == 0x34)
|
||||
data->f34_container = fn;
|
||||
|
||||
list_add_tail(&fn->node, &data->function_list);
|
||||
|
||||
@@ -786,23 +884,95 @@ err_put_fn:
|
||||
return error;
|
||||
}
|
||||
|
||||
int rmi_driver_suspend(struct rmi_device *rmi_dev)
|
||||
void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
|
||||
{
|
||||
int retval = 0;
|
||||
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
int irq = pdata->irq;
|
||||
int irq_flags;
|
||||
int retval;
|
||||
|
||||
mutex_lock(&data->enabled_mutex);
|
||||
|
||||
if (data->enabled)
|
||||
goto out;
|
||||
|
||||
enable_irq(irq);
|
||||
data->enabled = true;
|
||||
if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
|
||||
retval = disable_irq_wake(irq);
|
||||
if (!retval)
|
||||
dev_warn(&rmi_dev->dev,
|
||||
"Failed to disable irq for wake: %d\n",
|
||||
retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call rmi_process_interrupt_requests() after enabling irq,
|
||||
* otherwise we may lose interrupt on edge-triggered systems.
|
||||
*/
|
||||
irq_flags = irq_get_trigger_type(pdata->irq);
|
||||
if (irq_flags & IRQ_TYPE_EDGE_BOTH)
|
||||
rmi_process_interrupt_requests(rmi_dev);
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->enabled_mutex);
|
||||
}
|
||||
|
||||
void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
|
||||
{
|
||||
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi4_attn_data attn_data = {0};
|
||||
int irq = pdata->irq;
|
||||
int retval, count;
|
||||
|
||||
mutex_lock(&data->enabled_mutex);
|
||||
|
||||
if (!data->enabled)
|
||||
goto out;
|
||||
|
||||
data->enabled = false;
|
||||
disable_irq(irq);
|
||||
if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
|
||||
retval = enable_irq_wake(irq);
|
||||
if (!retval)
|
||||
dev_warn(&rmi_dev->dev,
|
||||
"Failed to enable irq for wake: %d\n",
|
||||
retval);
|
||||
}
|
||||
|
||||
/* make sure the fifo is clean */
|
||||
while (!kfifo_is_empty(&data->attn_fifo)) {
|
||||
count = kfifo_get(&data->attn_fifo, &attn_data);
|
||||
if (count)
|
||||
kfree(attn_data.data);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->enabled_mutex);
|
||||
}
|
||||
|
||||
int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = rmi_suspend_functions(rmi_dev);
|
||||
if (retval)
|
||||
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
|
||||
retval);
|
||||
|
||||
rmi_disable_irq(rmi_dev, enable_wake);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_driver_suspend);
|
||||
|
||||
int rmi_driver_resume(struct rmi_device *rmi_dev)
|
||||
int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
|
||||
{
|
||||
int retval;
|
||||
|
||||
rmi_enable_irq(rmi_dev, clear_wake);
|
||||
|
||||
retval = rmi_resume_functions(rmi_dev);
|
||||
if (retval)
|
||||
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
|
||||
@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev)
|
||||
{
|
||||
struct rmi_device *rmi_dev = to_rmi_device(dev);
|
||||
|
||||
rmi_disable_irq(rmi_dev, false);
|
||||
|
||||
rmi_f34_remove_sysfs(rmi_dev);
|
||||
rmi_free_function_list(rmi_dev);
|
||||
|
||||
return 0;
|
||||
@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
int rmi_probe_interrupts(struct rmi_driver_data *data)
|
||||
{
|
||||
struct rmi_device *rmi_dev = data->rmi_dev;
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
int irq_count;
|
||||
size_t size;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* We need to count the IRQs and allocate their storage before scanning
|
||||
* the PDT and creating the function entries, because adding a new
|
||||
* function can trigger events that result in the IRQ related storage
|
||||
* being accessed.
|
||||
*/
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
|
||||
irq_count = 0;
|
||||
data->bootloader_mode = false;
|
||||
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "IRQ counting failed with code %d.\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data->bootloader_mode)
|
||||
dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
|
||||
|
||||
data->irq_count = irq_count;
|
||||
data->num_of_irq_regs = (data->irq_count + 7) / 8;
|
||||
|
||||
size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
|
||||
data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
|
||||
if (!data->irq_memory) {
|
||||
dev_err(dev, "Failed to allocate memory for irq masks.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
data->irq_status = data->irq_memory + size * 0;
|
||||
data->fn_irq_bits = data->irq_memory + size * 1;
|
||||
data->current_irq_mask = data->irq_memory + size * 2;
|
||||
data->new_irq_mask = data->irq_memory + size * 3;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rmi_init_functions(struct rmi_driver_data *data)
|
||||
{
|
||||
struct rmi_device *rmi_dev = data->rmi_dev;
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
int irq_count;
|
||||
int retval;
|
||||
|
||||
irq_count = 0;
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "Function creation failed with code %d.\n",
|
||||
retval);
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
|
||||
if (!data->f01_container) {
|
||||
dev_err(dev, "Missing F01 container!\n");
|
||||
retval = -EINVAL;
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
|
||||
retval = rmi_read_block(rmi_dev,
|
||||
data->f01_container->fd.control_base_addr + 1,
|
||||
data->current_irq_mask, data->num_of_irq_regs);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Failed to read current IRQ mask.\n",
|
||||
__func__);
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_functions:
|
||||
rmi_free_function_list(rmi_dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rmi_driver_probe(struct device *dev)
|
||||
{
|
||||
struct rmi_driver *rmi_driver;
|
||||
struct rmi_driver_data *data;
|
||||
struct rmi_device_platform_data *pdata;
|
||||
struct rmi_device *rmi_dev;
|
||||
size_t size;
|
||||
void *irq_memory;
|
||||
int irq_count;
|
||||
int retval;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
|
||||
@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev)
|
||||
PDT_PROPERTIES_LOCATION, retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to count the IRQs and allocate their storage before scanning
|
||||
* the PDT and creating the function entries, because adding a new
|
||||
* function can trigger events that result in the IRQ related storage
|
||||
* being accessed.
|
||||
*/
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
|
||||
irq_count = 0;
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "IRQ counting failed with code %d.\n", retval);
|
||||
goto err;
|
||||
}
|
||||
data->irq_count = irq_count;
|
||||
data->num_of_irq_regs = (data->irq_count + 7) / 8;
|
||||
|
||||
mutex_init(&data->irq_mutex);
|
||||
mutex_init(&data->enabled_mutex);
|
||||
|
||||
size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
|
||||
irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
|
||||
if (!irq_memory) {
|
||||
dev_err(dev, "Failed to allocate memory for irq masks.\n");
|
||||
retval = rmi_probe_interrupts(data);
|
||||
if (retval)
|
||||
goto err;
|
||||
}
|
||||
|
||||
data->irq_status = irq_memory + size * 0;
|
||||
data->fn_irq_bits = irq_memory + size * 1;
|
||||
data->current_irq_mask = irq_memory + size * 2;
|
||||
data->new_irq_mask = irq_memory + size * 3;
|
||||
|
||||
if (rmi_dev->xport->input) {
|
||||
/*
|
||||
@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev)
|
||||
dev_err(dev, "%s: Failed to allocate input device.\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_destroy_functions;
|
||||
goto err;
|
||||
}
|
||||
rmi_driver_set_input_params(rmi_dev, data->input);
|
||||
data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"%s/input0", dev_name(dev));
|
||||
}
|
||||
|
||||
irq_count = 0;
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "Function creation failed with code %d.\n",
|
||||
retval);
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
retval = rmi_init_functions(data);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
if (!data->f01_container) {
|
||||
dev_err(dev, "Missing F01 container!\n");
|
||||
retval = -EINVAL;
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
|
||||
retval = rmi_read_block(rmi_dev,
|
||||
data->f01_container->fd.control_base_addr + 1,
|
||||
data->current_irq_mask, data->num_of_irq_regs);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Failed to read current IRQ mask.\n",
|
||||
__func__);
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
retval = rmi_f34_create_sysfs(rmi_dev);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
if (data->input) {
|
||||
rmi_driver_set_input_name(rmi_dev, data->input);
|
||||
@@ -1003,9 +1217,13 @@ static int rmi_driver_probe(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
retval = rmi_irq_init(rmi_dev);
|
||||
if (retval < 0)
|
||||
goto err_destroy_functions;
|
||||
|
||||
if (data->f01_container->dev.driver)
|
||||
/* Driver already bound, so enable ATTN now. */
|
||||
return enable_sensor(rmi_dev);
|
||||
return rmi_enable_sensor(rmi_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@@ -51,9 +51,6 @@ struct pdt_entry {
|
||||
u8 function_number;
|
||||
};
|
||||
|
||||
int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
|
||||
u16 pdt_address);
|
||||
|
||||
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
|
||||
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
|
||||
|
||||
@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
|
||||
bool rmi_is_physical_driver(struct device_driver *);
|
||||
int rmi_register_physical_driver(void);
|
||||
void rmi_unregister_physical_driver(void);
|
||||
void rmi_free_function_list(struct rmi_device *rmi_dev);
|
||||
int rmi_enable_sensor(struct rmi_device *rmi_dev);
|
||||
int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
int (*callback)(struct rmi_device *rmi_dev, void *ctx,
|
||||
const struct pdt_entry *entry));
|
||||
int rmi_probe_interrupts(struct rmi_driver_data *data);
|
||||
void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
|
||||
void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
|
||||
int rmi_init_functions(struct rmi_driver_data *data);
|
||||
int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
|
||||
const struct pdt_entry *pdt);
|
||||
|
||||
char *rmi_f01_get_product_ID(struct rmi_function *fn);
|
||||
|
||||
#ifdef CONFIG_RMI4_F34
|
||||
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
|
||||
void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
|
||||
#else
|
||||
static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_RMI_F34 */
|
||||
|
||||
extern struct rmi_function_handler rmi_f01_handler;
|
||||
extern struct rmi_function_handler rmi_f03_handler;
|
||||
extern struct rmi_function_handler rmi_f11_handler;
|
||||
extern struct rmi_function_handler rmi_f12_handler;
|
||||
extern struct rmi_function_handler rmi_f30_handler;
|
||||
extern struct rmi_function_handler rmi_f34_handler;
|
||||
extern struct rmi_function_handler rmi_f54_handler;
|
||||
extern struct rmi_function_handler rmi_f55_handler;
|
||||
#endif
|
||||
|
@@ -62,6 +62,8 @@ struct f01_basic_properties {
|
||||
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
|
||||
/* The device has lost its configuration for some reason. */
|
||||
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
|
||||
/* The device is in bootloader mode */
|
||||
#define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40)
|
||||
|
||||
/* Control register bits */
|
||||
|
||||
@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
|
||||
}
|
||||
|
||||
switch (pdata->power_management.nosleep) {
|
||||
case RMI_F01_NOSLEEP_DEFAULT:
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
break;
|
||||
case RMI_F01_NOSLEEP_OFF:
|
||||
case RMI_REG_STATE_OFF:
|
||||
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
|
||||
break;
|
||||
case RMI_F01_NOSLEEP_ON:
|
||||
case RMI_REG_STATE_ON:
|
||||
f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
|
||||
break;
|
||||
}
|
||||
@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (RMI_F01_STATUS_BOOTLOADER(device_status))
|
||||
dev_warn(&fn->dev,
|
||||
"Device in bootloader mode, please update firmware\n");
|
||||
|
||||
if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
|
||||
dev_warn(&fn->dev, "Device reset detected.\n");
|
||||
error = rmi_dev->driver->reset_handler(rmi_dev);
|
||||
|
250
drivers/input/rmi4/rmi_f03.c
Normal file
250
drivers/input/rmi4/rmi_f03.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Red Hat
|
||||
* Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/notifier.h>
|
||||
#include "rmi_driver.h"
|
||||
|
||||
#define RMI_F03_RX_DATA_OFB 0x01
|
||||
#define RMI_F03_OB_SIZE 2
|
||||
|
||||
#define RMI_F03_OB_OFFSET 2
|
||||
#define RMI_F03_OB_DATA_OFFSET 1
|
||||
#define RMI_F03_OB_FLAG_TIMEOUT BIT(6)
|
||||
#define RMI_F03_OB_FLAG_PARITY BIT(7)
|
||||
|
||||
#define RMI_F03_DEVICE_COUNT 0x07
|
||||
#define RMI_F03_BYTES_PER_DEVICE 0x07
|
||||
#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
|
||||
#define RMI_F03_QUEUE_LENGTH 0x0F
|
||||
|
||||
struct f03_data {
|
||||
struct rmi_function *fn;
|
||||
|
||||
struct serio *serio;
|
||||
|
||||
u8 device_count;
|
||||
u8 rx_queue_length;
|
||||
};
|
||||
|
||||
static int rmi_f03_pt_write(struct serio *id, unsigned char val)
|
||||
{
|
||||
struct f03_data *f03 = id->port_data;
|
||||
int error;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
|
||||
"%s: Wrote %.2hhx to PS/2 passthrough address",
|
||||
__func__, val);
|
||||
|
||||
error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
|
||||
if (error) {
|
||||
dev_err(&f03->fn->dev,
|
||||
"%s: Failed to write to F03 TX register (%d).\n",
|
||||
__func__, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f03_initialize(struct f03_data *f03)
|
||||
{
|
||||
struct rmi_function *fn = f03->fn;
|
||||
struct device *dev = &fn->dev;
|
||||
int error;
|
||||
u8 bytes_per_device;
|
||||
u8 query1;
|
||||
u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
|
||||
size_t query2_len;
|
||||
|
||||
error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to read query register (%d).\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
|
||||
bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
|
||||
RMI_F03_BYTES_PER_DEVICE;
|
||||
|
||||
query2_len = f03->device_count * bytes_per_device;
|
||||
|
||||
/*
|
||||
* The first generation of image sensors don't have a second part to
|
||||
* their f03 query, as such we have to set some of these values manually
|
||||
*/
|
||||
if (query2_len < 1) {
|
||||
f03->device_count = 1;
|
||||
f03->rx_queue_length = 7;
|
||||
} else {
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
|
||||
query2, query2_len);
|
||||
if (error) {
|
||||
dev_err(dev,
|
||||
"Failed to read second set of query registers (%d).\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f03_register_pt(struct f03_data *f03)
|
||||
{
|
||||
struct serio *serio;
|
||||
|
||||
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!serio)
|
||||
return -ENOMEM;
|
||||
|
||||
serio->id.type = SERIO_8042;
|
||||
serio->write = rmi_f03_pt_write;
|
||||
serio->port_data = f03;
|
||||
|
||||
strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
|
||||
sizeof(serio->name));
|
||||
strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
|
||||
sizeof(serio->phys));
|
||||
serio->dev.parent = &f03->fn->dev;
|
||||
|
||||
f03->serio = serio;
|
||||
|
||||
serio_register_port(serio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f03_probe(struct rmi_function *fn)
|
||||
{
|
||||
struct device *dev = &fn->dev;
|
||||
struct f03_data *f03;
|
||||
int error;
|
||||
|
||||
f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
|
||||
if (!f03)
|
||||
return -ENOMEM;
|
||||
|
||||
f03->fn = fn;
|
||||
|
||||
error = rmi_f03_initialize(f03);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
if (f03->device_count != 1)
|
||||
dev_warn(dev, "found %d devices on PS/2 passthrough",
|
||||
f03->device_count);
|
||||
|
||||
dev_set_drvdata(dev, f03);
|
||||
|
||||
error = rmi_f03_register_pt(f03);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f03_config(struct rmi_function *fn)
|
||||
{
|
||||
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
{
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
|
||||
u16 data_addr = fn->fd.data_base_addr;
|
||||
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
|
||||
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
|
||||
u8 ob_status;
|
||||
u8 ob_data;
|
||||
unsigned int serio_flags;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
if (!rmi_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (drvdata->attn_data.data) {
|
||||
/* First grab the data passed by the transport device */
|
||||
if (drvdata->attn_data.size < ob_len) {
|
||||
dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(obs, drvdata->attn_data.data, ob_len);
|
||||
|
||||
drvdata->attn_data.data += ob_len;
|
||||
drvdata->attn_data.size -= ob_len;
|
||||
} else {
|
||||
/* Grab all of the data registers, and check them for data */
|
||||
error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
|
||||
&obs, ob_len);
|
||||
if (error) {
|
||||
dev_err(&fn->dev,
|
||||
"%s: Failed to read F03 output buffers: %d\n",
|
||||
__func__, error);
|
||||
serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
|
||||
ob_status = obs[i];
|
||||
ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
|
||||
serio_flags = 0;
|
||||
|
||||
if (!(ob_status & RMI_F03_RX_DATA_OFB))
|
||||
continue;
|
||||
|
||||
if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
|
||||
serio_flags |= SERIO_TIMEOUT;
|
||||
if (ob_status & RMI_F03_OB_FLAG_PARITY)
|
||||
serio_flags |= SERIO_PARITY;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
|
||||
"%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
|
||||
__func__, ob_data,
|
||||
serio_flags & SERIO_TIMEOUT ? 'Y' : 'N',
|
||||
serio_flags & SERIO_PARITY ? 'Y' : 'N');
|
||||
|
||||
serio_interrupt(f03->serio, ob_data, serio_flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_f03_remove(struct rmi_function *fn)
|
||||
{
|
||||
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
serio_unregister_port(f03->serio);
|
||||
}
|
||||
|
||||
struct rmi_function_handler rmi_f03_handler = {
|
||||
.driver = {
|
||||
.name = "rmi4_f03",
|
||||
},
|
||||
.func = 0x03,
|
||||
.probe = rmi_f03_probe,
|
||||
.config = rmi_f03_config,
|
||||
.attention = rmi_f03_attention,
|
||||
.remove = rmi_f03_remove,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
|
||||
MODULE_DESCRIPTION("RMI F03 module");
|
||||
MODULE_LICENSE("GPL");
|
@@ -571,31 +571,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
|
||||
|
||||
static void rmi_f11_finger_handler(struct f11_data *f11,
|
||||
struct rmi_2d_sensor *sensor,
|
||||
unsigned long *irq_bits, int num_irq_regs)
|
||||
unsigned long *irq_bits, int num_irq_regs,
|
||||
int size)
|
||||
{
|
||||
const u8 *f_state = f11->data.f_state;
|
||||
u8 finger_state;
|
||||
u8 i;
|
||||
int abs_fingers;
|
||||
int rel_fingers;
|
||||
int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
|
||||
|
||||
int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
|
||||
num_irq_regs * 8);
|
||||
int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
|
||||
num_irq_regs * 8);
|
||||
|
||||
for (i = 0; i < sensor->nbr_fingers; i++) {
|
||||
/* Possible of having 4 fingers per f_statet register */
|
||||
finger_state = rmi_f11_parse_finger_state(f_state, i);
|
||||
if (finger_state == F11_RESERVED) {
|
||||
pr_err("Invalid finger state[%d]: 0x%02x", i,
|
||||
finger_state);
|
||||
continue;
|
||||
}
|
||||
if (abs_bits) {
|
||||
if (abs_size > size)
|
||||
abs_fingers = size / RMI_F11_ABS_BYTES;
|
||||
else
|
||||
abs_fingers = sensor->nbr_fingers;
|
||||
|
||||
for (i = 0; i < abs_fingers; i++) {
|
||||
/* Possible of having 4 fingers per f_state register */
|
||||
finger_state = rmi_f11_parse_finger_state(f_state, i);
|
||||
if (finger_state == F11_RESERVED) {
|
||||
pr_err("Invalid finger state[%d]: 0x%02x", i,
|
||||
finger_state);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abs_bits)
|
||||
rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
|
||||
finger_state, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (rel_bits)
|
||||
if (rel_bits) {
|
||||
if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
|
||||
rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
|
||||
else
|
||||
rel_fingers = sensor->nbr_fingers;
|
||||
|
||||
for (i = 0; i < rel_fingers; i++)
|
||||
rmi_f11_rel_pos_report(f11, i);
|
||||
}
|
||||
|
||||
@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
|
||||
sensor->nbr_fingers,
|
||||
sensor->dmax);
|
||||
|
||||
for (i = 0; i < sensor->nbr_fingers; i++) {
|
||||
for (i = 0; i < abs_fingers; i++) {
|
||||
finger_state = rmi_f11_parse_finger_state(f_state, i);
|
||||
if (finger_state == F11_RESERVED)
|
||||
/* no need to send twice the error */
|
||||
@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
|
||||
rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else if (pdata->sensor_pdata) {
|
||||
f11->sensor_pdata = *pdata->sensor_pdata;
|
||||
} else {
|
||||
f11->sensor_pdata = pdata->sensor_pdata;
|
||||
}
|
||||
|
||||
f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
|
||||
@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
|
||||
sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
|
||||
sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
|
||||
sensor->dmax = f11->sensor_pdata.dmax;
|
||||
sensor->dribble = f11->sensor_pdata.dribble;
|
||||
sensor->palm_detect = f11->sensor_pdata.palm_detect;
|
||||
|
||||
if (f11->sens_query.has_physical_props) {
|
||||
sensor->x_mm = f11->sens_query.x_sensor_size_mm;
|
||||
@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
|
||||
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
|
||||
sensor->axis_align.delta_y_threshold;
|
||||
|
||||
if (f11->sens_query.has_dribble)
|
||||
ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
|
||||
if (f11->sens_query.has_dribble) {
|
||||
switch (sensor->dribble) {
|
||||
case RMI_REG_STATE_OFF:
|
||||
ctrl->ctrl0_11[0] &= ~BIT(6);
|
||||
break;
|
||||
case RMI_REG_STATE_ON:
|
||||
ctrl->ctrl0_11[0] |= BIT(6);
|
||||
break;
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (f11->sens_query.has_palm_det)
|
||||
ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
|
||||
if (f11->sens_query.has_palm_det) {
|
||||
switch (sensor->palm_detect) {
|
||||
case RMI_REG_STATE_OFF:
|
||||
ctrl->ctrl0_11[11] &= ~BIT(0);
|
||||
break;
|
||||
case RMI_REG_STATE_ON:
|
||||
ctrl->ctrl0_11[11] |= BIT(0);
|
||||
break;
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = f11_write_control_regs(fn, &f11->sens_query,
|
||||
&f11->dev_controls, fn->fd.query_base_addr);
|
||||
@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
struct f11_data *f11 = dev_get_drvdata(&fn->dev);
|
||||
u16 data_base_addr = fn->fd.data_base_addr;
|
||||
int error;
|
||||
int valid_bytes = f11->sensor.pkt_size;
|
||||
|
||||
if (rmi_dev->xport->attn_data) {
|
||||
memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
|
||||
f11->sensor.attn_size);
|
||||
rmi_dev->xport->attn_data += f11->sensor.attn_size;
|
||||
rmi_dev->xport->attn_size -= f11->sensor.attn_size;
|
||||
if (drvdata->attn_data.data) {
|
||||
/*
|
||||
* The valid data in the attention report is less then
|
||||
* expected. Only process the complete fingers.
|
||||
*/
|
||||
if (f11->sensor.attn_size > drvdata->attn_data.size)
|
||||
valid_bytes = drvdata->attn_data.size;
|
||||
else
|
||||
valid_bytes = f11->sensor.attn_size;
|
||||
memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
|
||||
valid_bytes);
|
||||
drvdata->attn_data.data += f11->sensor.attn_size;
|
||||
drvdata->attn_data.size -= f11->sensor.attn_size;
|
||||
} else {
|
||||
error = rmi_read_block(rmi_dev,
|
||||
data_base_addr, f11->sensor.data_pkt,
|
||||
@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
}
|
||||
|
||||
rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
|
||||
drvdata->num_of_irq_regs);
|
||||
drvdata->num_of_irq_regs, valid_bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
|
||||
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
|
||||
};
|
||||
|
||||
#define F12_DATA1_BYTES_PER_OBJ 8
|
||||
|
||||
struct f12_data {
|
||||
struct rmi_2d_sensor sensor;
|
||||
struct rmi_2d_sensor_platform_data sensor_pdata;
|
||||
bool has_dribble;
|
||||
|
||||
u16 data_addr;
|
||||
|
||||
@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
u8 buf[15];
|
||||
int pitch_x = 0;
|
||||
int pitch_y = 0;
|
||||
int clip_x_low = 0;
|
||||
int clip_x_high = 0;
|
||||
int clip_y_low = 0;
|
||||
int clip_y_high = 0;
|
||||
int rx_receivers = 0;
|
||||
int tx_receivers = 0;
|
||||
int sensor_flags = 0;
|
||||
@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
|
||||
__func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
|
||||
__func__,
|
||||
sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high,
|
||||
sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high);
|
||||
|
||||
if (rmi_register_desc_has_subpacket(item, 3)) {
|
||||
rx_receivers = buf[offset];
|
||||
@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
|
||||
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
|
||||
{
|
||||
int i;
|
||||
struct rmi_2d_sensor *sensor = &f12->sensor;
|
||||
int objects = f12->data1->num_subpackets;
|
||||
|
||||
for (i = 0; i < f12->data1->num_subpackets; i++) {
|
||||
if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
|
||||
objects = size / F12_DATA1_BYTES_PER_OBJ;
|
||||
|
||||
for (i = 0; i < objects; i++) {
|
||||
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
|
||||
|
||||
obj->type = RMI_2D_OBJECT_NONE;
|
||||
@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
|
||||
|
||||
rmi_2d_sensor_abs_process(sensor, obj, i);
|
||||
|
||||
data1 += 8;
|
||||
data1 += F12_DATA1_BYTES_PER_OBJ;
|
||||
}
|
||||
|
||||
if (sensor->kernel_tracking)
|
||||
@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
|
||||
sensor->nbr_fingers,
|
||||
sensor->dmax);
|
||||
|
||||
for (i = 0; i < sensor->nbr_fingers; i++)
|
||||
for (i = 0; i < objects; i++)
|
||||
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
|
||||
}
|
||||
|
||||
@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
|
||||
{
|
||||
int retval;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
struct rmi_2d_sensor *sensor = &f12->sensor;
|
||||
int valid_bytes = sensor->pkt_size;
|
||||
|
||||
if (rmi_dev->xport->attn_data) {
|
||||
memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
|
||||
sensor->attn_size);
|
||||
rmi_dev->xport->attn_data += sensor->attn_size;
|
||||
rmi_dev->xport->attn_size -= sensor->attn_size;
|
||||
if (drvdata->attn_data.data) {
|
||||
if (sensor->attn_size > drvdata->attn_data.size)
|
||||
valid_bytes = drvdata->attn_data.size;
|
||||
else
|
||||
valid_bytes = sensor->attn_size;
|
||||
memcpy(sensor->data_pkt, drvdata->attn_data.data,
|
||||
valid_bytes);
|
||||
drvdata->attn_data.data += sensor->attn_size;
|
||||
drvdata->attn_data.size -= sensor->attn_size;
|
||||
} else {
|
||||
retval = rmi_read_block(rmi_dev, f12->data_addr,
|
||||
sensor->data_pkt, sensor->pkt_size);
|
||||
@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
|
||||
|
||||
if (f12->data1)
|
||||
rmi_f12_process_objects(f12,
|
||||
&sensor->data_pkt[f12->data1_offset]);
|
||||
&sensor->data_pkt[f12->data1_offset], valid_bytes);
|
||||
|
||||
input_mt_sync_frame(sensor->input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f12_write_control_regs(struct rmi_function *fn)
|
||||
{
|
||||
int ret;
|
||||
const struct rmi_register_desc_item *item;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
int control_size;
|
||||
char buf[3];
|
||||
u16 control_offset = 0;
|
||||
u8 subpacket_offset = 0;
|
||||
|
||||
if (f12->has_dribble
|
||||
&& (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
|
||||
item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
|
||||
if (item) {
|
||||
control_offset = rmi_register_desc_calc_reg_offset(
|
||||
&f12->control_reg_desc, 20);
|
||||
|
||||
/*
|
||||
* The byte containing the EnableDribble bit will be
|
||||
* in either byte 0 or byte 2 of control 20. Depending
|
||||
* on the existence of subpacket 0. If control 20 is
|
||||
* larger then 3 bytes, just read the first 3.
|
||||
*/
|
||||
control_size = min(item->reg_size, 3UL);
|
||||
|
||||
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
|
||||
+ control_offset, buf, control_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rmi_register_desc_has_subpacket(item, 0))
|
||||
subpacket_offset += 1;
|
||||
|
||||
switch (f12->sensor.dribble) {
|
||||
case RMI_REG_STATE_OFF:
|
||||
buf[subpacket_offset] &= ~BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_ON:
|
||||
buf[subpacket_offset] |= BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = rmi_write_block(rmi_dev,
|
||||
fn->fd.control_base_addr + control_offset,
|
||||
buf, control_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int rmi_f12_config(struct rmi_function *fn)
|
||||
{
|
||||
struct rmi_driver *drv = fn->rmi_dev->driver;
|
||||
int ret;
|
||||
|
||||
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
|
||||
|
||||
ret = rmi_f12_write_control_regs(fn);
|
||||
if (ret)
|
||||
dev_warn(&fn->dev,
|
||||
"Failed to write F12 control registers: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
const struct rmi_register_desc_item *item;
|
||||
struct rmi_2d_sensor *sensor;
|
||||
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_transport_dev *xport = rmi_dev->xport;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
u16 data_offset = 0;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
|
||||
@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
}
|
||||
++query_addr;
|
||||
|
||||
if (!(buf & 0x1)) {
|
||||
if (!(buf & BIT(0))) {
|
||||
dev_err(&fn->dev,
|
||||
"Behavior of F12 without register descriptors is undefined.\n");
|
||||
return -ENODEV;
|
||||
@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
if (!f12)
|
||||
return -ENOMEM;
|
||||
|
||||
f12->has_dribble = !!(buf & BIT(3));
|
||||
|
||||
if (fn->dev.of_node) {
|
||||
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (pdata->sensor_pdata) {
|
||||
f12->sensor_pdata = *pdata->sensor_pdata;
|
||||
} else {
|
||||
f12->sensor_pdata = pdata->sensor_pdata;
|
||||
}
|
||||
|
||||
ret = rmi_read_register_desc(rmi_dev, query_addr,
|
||||
@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
|
||||
sensor->x_mm = f12->sensor_pdata.x_mm;
|
||||
sensor->y_mm = f12->sensor_pdata.y_mm;
|
||||
sensor->dribble = f12->sensor_pdata.dribble;
|
||||
|
||||
if (sensor->sensor_type == rmi_sensor_default)
|
||||
sensor->sensor_type =
|
||||
@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
* HID attention reports.
|
||||
*/
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
|
||||
@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
|
||||
@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
|
||||
if (item && !xport->attn_data) {
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data6 = item;
|
||||
f12->data6_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
|
||||
if (item && !xport->attn_data) {
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data9 = item;
|
||||
f12->data9_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
|
||||
if (item && !xport->attn_data)
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
|
||||
if (item && !xport->attn_data) {
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data15 = item;
|
||||
f12->data15_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
|
@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
{
|
||||
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
int retval;
|
||||
int gpiled = 0;
|
||||
int value = 0;
|
||||
@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
return 0;
|
||||
|
||||
/* Read the gpi led data. */
|
||||
if (rmi_dev->xport->attn_data) {
|
||||
memcpy(f30->data_regs, rmi_dev->xport->attn_data,
|
||||
if (drvdata->attn_data.data) {
|
||||
if (drvdata->attn_data.size < f30->register_count) {
|
||||
dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy(f30->data_regs, drvdata->attn_data.data,
|
||||
f30->register_count);
|
||||
rmi_dev->xport->attn_data += f30->register_count;
|
||||
rmi_dev->xport->attn_size -= f30->register_count;
|
||||
drvdata->attn_data.data += f30->register_count;
|
||||
drvdata->attn_data.size -= f30->register_count;
|
||||
} else {
|
||||
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
|
||||
f30->data_regs, f30->register_count);
|
||||
@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
|
||||
rmi_get_platform_data(fn->rmi_dev);
|
||||
int error;
|
||||
|
||||
if (pdata->f30_data && pdata->f30_data->disable) {
|
||||
if (pdata->f30_data.disable) {
|
||||
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
|
||||
} else {
|
||||
/* Write Control Register values back to device */
|
||||
@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
|
||||
f30->gpioled_key_map = (u16 *)map_memory;
|
||||
|
||||
pdata = rmi_get_platform_data(rmi_dev);
|
||||
if (pdata && f30->has_gpio) {
|
||||
if (f30->has_gpio) {
|
||||
button = BTN_LEFT;
|
||||
for (i = 0; i < f30->gpioled_count; i++) {
|
||||
if (rmi_f30_is_valid_button(i, f30->ctrl)) {
|
||||
@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
|
||||
* f30->has_mech_mouse_btns, but I am
|
||||
* not sure, so use only the pdata info
|
||||
*/
|
||||
if (pdata->f30_data &&
|
||||
pdata->f30_data->buttonpad)
|
||||
if (pdata->f30_data.buttonpad)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
|
||||
const struct rmi_device_platform_data *pdata =
|
||||
rmi_get_platform_data(fn->rmi_dev);
|
||||
|
||||
if (pdata->f30_data && pdata->f30_data->disable)
|
||||
if (pdata->f30_data.disable)
|
||||
return 0;
|
||||
|
||||
rc = rmi_f30_initialize(fn);
|
||||
|
516
drivers/input/rmi4/rmi_f34.c
Normal file
516
drivers/input/rmi4/rmi_f34.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2016, Synaptics Incorporated
|
||||
* Copyright (C) 2016 Zodiac Inflight Innovations
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "rmi_driver.h"
|
||||
#include "rmi_f34.h"
|
||||
|
||||
static int rmi_f34_write_bootloader_id(struct f34_data *f34)
|
||||
{
|
||||
struct rmi_function *fn = f34->fn;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
u8 bootloader_id[F34_BOOTLOADER_ID_LEN];
|
||||
int ret;
|
||||
|
||||
ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
|
||||
bootloader_id, sizeof(bootloader_id));
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n",
|
||||
__func__, bootloader_id[0], bootloader_id[1]);
|
||||
|
||||
ret = rmi_write_block(rmi_dev,
|
||||
fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET,
|
||||
bootloader_id, sizeof(bootloader_id));
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f34_command(struct f34_data *f34, u8 command,
|
||||
unsigned int timeout, bool write_bl_id)
|
||||
{
|
||||
struct rmi_function *fn = f34->fn;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
int ret;
|
||||
|
||||
if (write_bl_id) {
|
||||
ret = rmi_f34_write_bootloader_id(f34);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_completion(&f34->v5.cmd_done);
|
||||
|
||||
ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
|
||||
if (ret) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"%s: Failed to read cmd register: %d (command %#02x)\n",
|
||||
__func__, ret, command);
|
||||
return ret;
|
||||
}
|
||||
|
||||
f34->v5.status |= command & 0x0f;
|
||||
|
||||
ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status);
|
||||
if (ret < 0) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"Failed to write F34 command %#02x: %d\n",
|
||||
command, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!wait_for_completion_timeout(&f34->v5.cmd_done,
|
||||
msecs_to_jiffies(timeout))) {
|
||||
|
||||
ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
|
||||
if (ret) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"%s: cmd %#02x timed out: %d\n",
|
||||
__func__, command, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (f34->v5.status & 0x7f) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"%s: cmd %#02x timed out, status: %#02x\n",
|
||||
__func__, command, f34->v5.status);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
|
||||
{
|
||||
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
|
||||
int ret;
|
||||
|
||||
if (f34->bl_version != 5)
|
||||
return 0;
|
||||
|
||||
ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n",
|
||||
__func__, f34->v5.status, ret);
|
||||
|
||||
if (!ret && !(f34->v5.status & 0x7f))
|
||||
complete(&f34->v5.cmd_done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
|
||||
int block_count, u8 command)
|
||||
{
|
||||
struct rmi_function *fn = f34->fn;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET;
|
||||
u8 start_address[] = { 0, 0 };
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr,
|
||||
start_address, sizeof(start_address));
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < block_count; i++) {
|
||||
ret = rmi_write_block(rmi_dev, address,
|
||||
data, f34->v5.block_size);
|
||||
if (ret) {
|
||||
dev_err(&fn->dev,
|
||||
"failed to write block #%d: %d\n", i, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false);
|
||||
if (ret) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to write command for block #%d: %d\n",
|
||||
i, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n",
|
||||
i + 1, block_count);
|
||||
|
||||
data += f34->v5.block_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f34_write_firmware(struct f34_data *f34, const void *data)
|
||||
{
|
||||
return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks,
|
||||
F34_WRITE_FW_BLOCK);
|
||||
}
|
||||
|
||||
static int rmi_f34_write_config(struct f34_data *f34, const void *data)
|
||||
{
|
||||
return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks,
|
||||
F34_WRITE_CONFIG_BLOCK);
|
||||
}
|
||||
|
||||
int rmi_f34_enable_flash(struct f34_data *f34)
|
||||
{
|
||||
return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
|
||||
F34_ENABLE_WAIT_MS, true);
|
||||
}
|
||||
|
||||
static int rmi_f34_flash_firmware(struct f34_data *f34,
|
||||
const struct rmi_f34_firmware *syn_fw)
|
||||
{
|
||||
struct rmi_function *fn = f34->fn;
|
||||
int ret;
|
||||
|
||||
if (syn_fw->image_size) {
|
||||
dev_info(&fn->dev, "Erasing firmware...\n");
|
||||
ret = rmi_f34_command(f34, F34_ERASE_ALL,
|
||||
F34_ERASE_WAIT_MS, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
|
||||
syn_fw->image_size);
|
||||
ret = rmi_f34_write_firmware(f34, syn_fw->data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (syn_fw->config_size) {
|
||||
/*
|
||||
* We only need to erase config if we haven't updated
|
||||
* firmware.
|
||||
*/
|
||||
if (!syn_fw->image_size) {
|
||||
dev_info(&fn->dev, "Erasing config...\n");
|
||||
ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
|
||||
F34_ERASE_WAIT_MS, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&fn->dev, "Writing config (%d bytes)...\n",
|
||||
syn_fw->config_size);
|
||||
ret = rmi_f34_write_config(f34,
|
||||
&syn_fw->data[syn_fw->image_size]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
|
||||
{
|
||||
const struct rmi_f34_firmware *syn_fw;
|
||||
int ret;
|
||||
|
||||
syn_fw = (const struct rmi_f34_firmware *)fw->data;
|
||||
BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
|
||||
F34_FW_IMAGE_OFFSET);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
|
||||
"FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
|
||||
(int)fw->size,
|
||||
le32_to_cpu(syn_fw->checksum),
|
||||
le32_to_cpu(syn_fw->image_size),
|
||||
le32_to_cpu(syn_fw->config_size));
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
|
||||
"FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
|
||||
syn_fw->bootloader_version,
|
||||
(int)sizeof(syn_fw->product_id), syn_fw->product_id,
|
||||
syn_fw->product_info[0], syn_fw->product_info[1]);
|
||||
|
||||
if (syn_fw->image_size &&
|
||||
syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"Bad firmware image: fw size %d, expected %d\n",
|
||||
syn_fw->image_size,
|
||||
f34->v5.fw_blocks * f34->v5.block_size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (syn_fw->config_size &&
|
||||
syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
|
||||
dev_err(&f34->fn->dev,
|
||||
"Bad firmware image: config size %d, expected %d\n",
|
||||
syn_fw->config_size,
|
||||
f34->v5.config_blocks * f34->v5.block_size);
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (syn_fw->image_size && !syn_fw->config_size) {
|
||||
dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
|
||||
ret = -EILSEQ;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_info(&f34->fn->dev, "Firmware image OK\n");
|
||||
mutex_lock(&f34->v5.flash_mutex);
|
||||
|
||||
ret = rmi_f34_flash_firmware(f34, syn_fw);
|
||||
|
||||
mutex_unlock(&f34->v5.flash_mutex);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
struct rmi_device *rmi_dev = data->rmi_dev;
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
struct f34_data *f34;
|
||||
int ret;
|
||||
|
||||
if (!data->f34_container) {
|
||||
dev_warn(dev, "%s: No F34 present!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f34 = dev_get_drvdata(&data->f34_container->dev);
|
||||
|
||||
if (f34->bl_version == 7) {
|
||||
if (data->pdt_props & HAS_BSR) {
|
||||
dev_err(dev, "%s: LTS not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (f34->bl_version != 5) {
|
||||
dev_warn(dev, "F34 V%d not supported!\n",
|
||||
data->f34_container->fd.function_version);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Enter flash mode */
|
||||
if (f34->bl_version == 7)
|
||||
ret = rmi_f34v7_start_reflash(f34, fw);
|
||||
else
|
||||
ret = rmi_f34_enable_flash(f34);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rmi_disable_irq(rmi_dev, false);
|
||||
|
||||
/* Tear down functions and re-probe */
|
||||
rmi_free_function_list(rmi_dev);
|
||||
|
||||
ret = rmi_probe_interrupts(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rmi_init_functions(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!data->bootloader_mode || !data->f34_container) {
|
||||
dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rmi_enable_irq(rmi_dev, false);
|
||||
|
||||
f34 = dev_get_drvdata(&data->f34_container->dev);
|
||||
|
||||
/* Perform firmware update */
|
||||
if (f34->bl_version == 7)
|
||||
ret = rmi_f34v7_do_reflash(f34, fw);
|
||||
else
|
||||
ret = rmi_f34_update_firmware(f34, fw);
|
||||
|
||||
dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
|
||||
|
||||
rmi_disable_irq(rmi_dev, false);
|
||||
|
||||
/* Re-probe */
|
||||
rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n");
|
||||
rmi_free_function_list(rmi_dev);
|
||||
|
||||
ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "RMI reset failed!\n");
|
||||
|
||||
ret = rmi_probe_interrupts(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rmi_init_functions(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rmi_enable_irq(rmi_dev, false);
|
||||
|
||||
if (data->f01_container->dev.driver)
|
||||
/* Driver already bound, so enable ATTN now. */
|
||||
return rmi_enable_sensor(rmi_dev);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_firmware_update(struct rmi_driver_data *data,
|
||||
const struct firmware *fw);
|
||||
|
||||
static ssize_t rmi_driver_update_fw_store(struct device *dev,
|
||||
struct device_attribute *dattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||
char fw_name[NAME_MAX];
|
||||
const struct firmware *fw;
|
||||
size_t copy_count = count;
|
||||
int ret;
|
||||
|
||||
if (count == 0 || count >= NAME_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (buf[count - 1] == '\0' || buf[count - 1] == '\n')
|
||||
copy_count -= 1;
|
||||
|
||||
strncpy(fw_name, buf, copy_count);
|
||||
fw_name[copy_count] = '\0';
|
||||
|
||||
ret = request_firmware(&fw, fw_name, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(dev, "Flashing %s\n", fw_name);
|
||||
|
||||
ret = rmi_firmware_update(data, fw);
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
|
||||
|
||||
static struct attribute *rmi_firmware_attrs[] = {
|
||||
&dev_attr_update_fw.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group rmi_firmware_attr_group = {
|
||||
.attrs = rmi_firmware_attrs,
|
||||
};
|
||||
|
||||
static int rmi_f34_probe(struct rmi_function *fn)
|
||||
{
|
||||
struct f34_data *f34;
|
||||
unsigned char f34_queries[9];
|
||||
bool has_config_id;
|
||||
u8 version = fn->fd.function_version;
|
||||
int ret;
|
||||
|
||||
f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
|
||||
if (!f34)
|
||||
return -ENOMEM;
|
||||
|
||||
f34->fn = fn;
|
||||
dev_set_drvdata(&fn->dev, f34);
|
||||
|
||||
/* v5 code only supported version 0, try V7 probe */
|
||||
if (version > 0)
|
||||
return rmi_f34v7_probe(f34);
|
||||
else if (version != 0)
|
||||
return -ENODEV;
|
||||
|
||||
f34->bl_version = 5;
|
||||
|
||||
ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
|
||||
f34_queries, sizeof(f34_queries));
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "%s: Failed to query properties\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
|
||||
"%c%c", f34_queries[0], f34_queries[1]);
|
||||
|
||||
mutex_init(&f34->v5.flash_mutex);
|
||||
init_completion(&f34->v5.cmd_done);
|
||||
|
||||
f34->v5.block_size = get_unaligned_le16(&f34_queries[3]);
|
||||
f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]);
|
||||
f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]);
|
||||
f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET +
|
||||
f34->v5.block_size;
|
||||
has_config_id = f34_queries[2] & (1 << 2);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n",
|
||||
f34->bootloader_id);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n",
|
||||
f34->v5.block_size);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n",
|
||||
f34->v5.fw_blocks);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n",
|
||||
f34->v5.config_blocks);
|
||||
|
||||
if (has_config_id) {
|
||||
ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
|
||||
f34_queries, sizeof(f34_queries));
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "Failed to read F34 config ID\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
snprintf(f34->configuration_id, sizeof(f34->configuration_id),
|
||||
"%02x%02x%02x%02x",
|
||||
f34_queries[0], f34_queries[1],
|
||||
f34_queries[2], f34_queries[3]);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
|
||||
f34->configuration_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
|
||||
{
|
||||
return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
|
||||
}
|
||||
|
||||
void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
|
||||
{
|
||||
sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
|
||||
}
|
||||
|
||||
struct rmi_function_handler rmi_f34_handler = {
|
||||
.driver = {
|
||||
.name = "rmi4_f34",
|
||||
},
|
||||
.func = 0x34,
|
||||
.probe = rmi_f34_probe,
|
||||
.attention = rmi_f34_attention,
|
||||
};
|
314
drivers/input/rmi4/rmi_f34.h
Normal file
314
drivers/input/rmi4/rmi_f34.h
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2016, Synaptics Incorporated
|
||||
* Copyright (C) 2016 Zodiac Inflight Innovations
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _RMI_F34_H
|
||||
#define _RMI_F34_H
|
||||
|
||||
/* F34 image file offsets. */
|
||||
#define F34_FW_IMAGE_OFFSET 0x100
|
||||
|
||||
/* F34 register offsets. */
|
||||
#define F34_BLOCK_DATA_OFFSET 2
|
||||
|
||||
/* F34 commands */
|
||||
#define F34_WRITE_FW_BLOCK 0x2
|
||||
#define F34_ERASE_ALL 0x3
|
||||
#define F34_READ_CONFIG_BLOCK 0x5
|
||||
#define F34_WRITE_CONFIG_BLOCK 0x6
|
||||
#define F34_ERASE_CONFIG 0x7
|
||||
#define F34_ENABLE_FLASH_PROG 0xf
|
||||
|
||||
#define F34_STATUS_IN_PROGRESS 0xff
|
||||
#define F34_STATUS_IDLE 0x80
|
||||
|
||||
#define F34_IDLE_WAIT_MS 500
|
||||
#define F34_ENABLE_WAIT_MS 300
|
||||
#define F34_ERASE_WAIT_MS 5000
|
||||
|
||||
#define F34_BOOTLOADER_ID_LEN 2
|
||||
|
||||
/* F34 V7 defines */
|
||||
#define V7_FLASH_STATUS_OFFSET 0
|
||||
#define V7_PARTITION_ID_OFFSET 1
|
||||
#define V7_BLOCK_NUMBER_OFFSET 2
|
||||
#define V7_TRANSFER_LENGTH_OFFSET 3
|
||||
#define V7_COMMAND_OFFSET 4
|
||||
#define V7_PAYLOAD_OFFSET 5
|
||||
#define V7_BOOTLOADER_ID_OFFSET 1
|
||||
|
||||
#define IMAGE_HEADER_VERSION_10 0x10
|
||||
|
||||
#define CONFIG_ID_SIZE 32
|
||||
#define PRODUCT_ID_SIZE 10
|
||||
|
||||
#define ENABLE_WAIT_MS (1 * 1000)
|
||||
#define WRITE_WAIT_MS (3 * 1000)
|
||||
|
||||
#define MIN_SLEEP_TIME_US 50
|
||||
#define MAX_SLEEP_TIME_US 100
|
||||
|
||||
#define HAS_BSR BIT(5)
|
||||
#define HAS_CONFIG_ID BIT(3)
|
||||
#define HAS_GUEST_CODE BIT(6)
|
||||
#define HAS_DISP_CFG BIT(5)
|
||||
|
||||
/* F34 V7 commands */
|
||||
#define CMD_V7_IDLE 0
|
||||
#define CMD_V7_ENTER_BL 1
|
||||
#define CMD_V7_READ 2
|
||||
#define CMD_V7_WRITE 3
|
||||
#define CMD_V7_ERASE 4
|
||||
#define CMD_V7_ERASE_AP 5
|
||||
#define CMD_V7_SENSOR_ID 6
|
||||
|
||||
#define v7_CMD_IDLE 0
|
||||
#define v7_CMD_WRITE_FW 1
|
||||
#define v7_CMD_WRITE_CONFIG 2
|
||||
#define v7_CMD_WRITE_LOCKDOWN 3
|
||||
#define v7_CMD_WRITE_GUEST_CODE 4
|
||||
#define v7_CMD_READ_CONFIG 5
|
||||
#define v7_CMD_ERASE_ALL 6
|
||||
#define v7_CMD_ERASE_UI_FIRMWARE 7
|
||||
#define v7_CMD_ERASE_UI_CONFIG 8
|
||||
#define v7_CMD_ERASE_BL_CONFIG 9
|
||||
#define v7_CMD_ERASE_DISP_CONFIG 10
|
||||
#define v7_CMD_ERASE_FLASH_CONFIG 11
|
||||
#define v7_CMD_ERASE_GUEST_CODE 12
|
||||
#define v7_CMD_ENABLE_FLASH_PROG 13
|
||||
|
||||
#define v7_UI_CONFIG_AREA 0
|
||||
#define v7_PM_CONFIG_AREA 1
|
||||
#define v7_BL_CONFIG_AREA 2
|
||||
#define v7_DP_CONFIG_AREA 3
|
||||
#define v7_FLASH_CONFIG_AREA 4
|
||||
|
||||
/* F34 V7 partition IDs */
|
||||
#define BOOTLOADER_PARTITION 1
|
||||
#define DEVICE_CONFIG_PARTITION 2
|
||||
#define FLASH_CONFIG_PARTITION 3
|
||||
#define MANUFACTURING_BLOCK_PARTITION 4
|
||||
#define GUEST_SERIALIZATION_PARTITION 5
|
||||
#define GLOBAL_PARAMETERS_PARTITION 6
|
||||
#define CORE_CODE_PARTITION 7
|
||||
#define CORE_CONFIG_PARTITION 8
|
||||
#define GUEST_CODE_PARTITION 9
|
||||
#define DISPLAY_CONFIG_PARTITION 10
|
||||
|
||||
/* F34 V7 container IDs */
|
||||
#define TOP_LEVEL_CONTAINER 0
|
||||
#define UI_CONTAINER 1
|
||||
#define UI_CONFIG_CONTAINER 2
|
||||
#define BL_CONTAINER 3
|
||||
#define BL_IMAGE_CONTAINER 4
|
||||
#define BL_CONFIG_CONTAINER 5
|
||||
#define BL_LOCKDOWN_INFO_CONTAINER 6
|
||||
#define PERMANENT_CONFIG_CONTAINER 7
|
||||
#define GUEST_CODE_CONTAINER 8
|
||||
#define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9
|
||||
#define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10
|
||||
#define RMI_SELF_DISCOVERY_CONTAINER 11
|
||||
#define RMI_PAGE_CONTENT_CONTAINER 12
|
||||
#define GENERAL_INFORMATION_CONTAINER 13
|
||||
#define DEVICE_CONFIG_CONTAINER 14
|
||||
#define FLASH_CONFIG_CONTAINER 15
|
||||
#define GUEST_SERIALIZATION_CONTAINER 16
|
||||
#define GLOBAL_PARAMETERS_CONTAINER 17
|
||||
#define CORE_CODE_CONTAINER 18
|
||||
#define CORE_CONFIG_CONTAINER 19
|
||||
#define DISPLAY_CONFIG_CONTAINER 20
|
||||
|
||||
struct f34v7_query_1_7 {
|
||||
u8 bl_minor_revision; /* query 1 */
|
||||
u8 bl_major_revision;
|
||||
__le32 bl_fw_id; /* query 2 */
|
||||
u8 minimum_write_size; /* query 3 */
|
||||
__le16 block_size;
|
||||
__le16 flash_page_size;
|
||||
__le16 adjustable_partition_area_size; /* query 4 */
|
||||
__le16 flash_config_length; /* query 5 */
|
||||
__le16 payload_length; /* query 6 */
|
||||
u8 partition_support[4]; /* query 7 */
|
||||
} __packed;
|
||||
|
||||
struct f34v7_data_1_5 {
|
||||
u8 partition_id;
|
||||
__le16 block_offset;
|
||||
__le16 transfer_length;
|
||||
u8 command;
|
||||
u8 payload[2];
|
||||
} __packed;
|
||||
|
||||
struct block_data {
|
||||
const void *data;
|
||||
int size;
|
||||
};
|
||||
|
||||
struct partition_table {
|
||||
u8 partition_id;
|
||||
u8 byte_1_reserved;
|
||||
__le16 partition_length;
|
||||
__le16 start_physical_address;
|
||||
__le16 partition_properties;
|
||||
} __packed;
|
||||
|
||||
struct physical_address {
|
||||
u16 ui_firmware;
|
||||
u16 ui_config;
|
||||
u16 dp_config;
|
||||
u16 guest_code;
|
||||
};
|
||||
|
||||
struct container_descriptor {
|
||||
__le32 content_checksum;
|
||||
__le16 container_id;
|
||||
u8 minor_version;
|
||||
u8 major_version;
|
||||
u8 reserved_08;
|
||||
u8 reserved_09;
|
||||
u8 reserved_0a;
|
||||
u8 reserved_0b;
|
||||
u8 container_option_flags[4];
|
||||
__le32 content_options_length;
|
||||
__le32 content_options_address;
|
||||
__le32 content_length;
|
||||
__le32 content_address;
|
||||
} __packed;
|
||||
|
||||
struct block_count {
|
||||
u16 ui_firmware;
|
||||
u16 ui_config;
|
||||
u16 dp_config;
|
||||
u16 fl_config;
|
||||
u16 pm_config;
|
||||
u16 bl_config;
|
||||
u16 lockdown;
|
||||
u16 guest_code;
|
||||
};
|
||||
|
||||
struct image_header_10 {
|
||||
__le32 checksum;
|
||||
u8 reserved_04;
|
||||
u8 reserved_05;
|
||||
u8 minor_header_version;
|
||||
u8 major_header_version;
|
||||
u8 reserved_08;
|
||||
u8 reserved_09;
|
||||
u8 reserved_0a;
|
||||
u8 reserved_0b;
|
||||
__le32 top_level_container_start_addr;
|
||||
};
|
||||
|
||||
struct image_metadata {
|
||||
bool contains_firmware_id;
|
||||
bool contains_bootloader;
|
||||
bool contains_display_cfg;
|
||||
bool contains_guest_code;
|
||||
bool contains_flash_config;
|
||||
unsigned int firmware_id;
|
||||
unsigned int checksum;
|
||||
unsigned int bootloader_size;
|
||||
unsigned int display_cfg_offset;
|
||||
unsigned char bl_version;
|
||||
unsigned char product_id[PRODUCT_ID_SIZE + 1];
|
||||
unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
|
||||
struct block_data bootloader;
|
||||
struct block_data ui_firmware;
|
||||
struct block_data ui_config;
|
||||
struct block_data dp_config;
|
||||
struct block_data fl_config;
|
||||
struct block_data bl_config;
|
||||
struct block_data guest_code;
|
||||
struct block_data lockdown;
|
||||
struct block_count blkcount;
|
||||
struct physical_address phyaddr;
|
||||
};
|
||||
|
||||
struct register_offset {
|
||||
u8 properties;
|
||||
u8 properties_2;
|
||||
u8 block_size;
|
||||
u8 block_count;
|
||||
u8 gc_block_count;
|
||||
u8 flash_status;
|
||||
u8 partition_id;
|
||||
u8 block_number;
|
||||
u8 transfer_length;
|
||||
u8 flash_cmd;
|
||||
u8 payload;
|
||||
};
|
||||
|
||||
struct rmi_f34_firmware {
|
||||
__le32 checksum;
|
||||
u8 pad1[3];
|
||||
u8 bootloader_version;
|
||||
__le32 image_size;
|
||||
__le32 config_size;
|
||||
u8 product_id[10];
|
||||
u8 product_info[2];
|
||||
u8 pad2[228];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
struct f34v5_data {
|
||||
u16 block_size;
|
||||
u16 fw_blocks;
|
||||
u16 config_blocks;
|
||||
u16 ctrl_address;
|
||||
u8 status;
|
||||
|
||||
struct completion cmd_done;
|
||||
struct mutex flash_mutex;
|
||||
};
|
||||
|
||||
struct f34v7_data {
|
||||
bool has_display_cfg;
|
||||
bool has_guest_code;
|
||||
bool force_update;
|
||||
bool in_bl_mode;
|
||||
u8 *read_config_buf;
|
||||
size_t read_config_buf_size;
|
||||
u8 command;
|
||||
u8 flash_status;
|
||||
u16 block_size;
|
||||
u16 config_block_count;
|
||||
u16 config_size;
|
||||
u16 config_area;
|
||||
u16 flash_config_length;
|
||||
u16 payload_length;
|
||||
u8 partitions;
|
||||
u16 partition_table_bytes;
|
||||
bool new_partition_table;
|
||||
|
||||
struct register_offset off;
|
||||
struct block_count blkcount;
|
||||
struct physical_address phyaddr;
|
||||
struct image_metadata img;
|
||||
|
||||
const void *config_data;
|
||||
const void *image;
|
||||
};
|
||||
|
||||
struct f34_data {
|
||||
struct rmi_function *fn;
|
||||
|
||||
u8 bl_version;
|
||||
unsigned char bootloader_id[5];
|
||||
unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
|
||||
|
||||
union {
|
||||
struct f34v5_data v5;
|
||||
struct f34v7_data v7;
|
||||
};
|
||||
};
|
||||
|
||||
int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
|
||||
int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
|
||||
int rmi_f34v7_probe(struct f34_data *f34);
|
||||
|
||||
#endif /* _RMI_F34_H */
|
1372
drivers/input/rmi4/rmi_f34v7.c
Normal file
1372
drivers/input/rmi4/rmi_f34v7.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
|
||||
|
||||
error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
|
||||
if (error < 0)
|
||||
return error;
|
||||
goto unlock;
|
||||
|
||||
init_completion(&f54->cmd_done);
|
||||
|
||||
@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
|
||||
|
||||
queue_delayed_work(f54->workqueue, &f54->work, 0);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&f54->data_mutex);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static size_t rmi_f54_get_report_size(struct f54_data *f54)
|
||||
{
|
||||
u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes;
|
||||
u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes;
|
||||
struct rmi_device *rmi_dev = f54->fn->rmi_dev;
|
||||
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
|
||||
u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
|
||||
u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
|
||||
size_t size;
|
||||
|
||||
switch (rmi_f54_get_reptype(f54, f54->input)) {
|
||||
@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
|
||||
|
||||
static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
|
||||
{
|
||||
struct rmi_device *rmi_dev = f54->fn->rmi_dev;
|
||||
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
|
||||
u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
|
||||
u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
|
||||
struct v4l2_pix_format *f = &f54->format;
|
||||
enum rmi_f54_report_type reptype;
|
||||
int ret;
|
||||
@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
|
||||
|
||||
f54->input = i;
|
||||
|
||||
f->width = f54->num_rx_electrodes;
|
||||
f->height = f54->num_tx_electrodes;
|
||||
f->width = rx;
|
||||
f->height = tx;
|
||||
f->field = V4L2_FIELD_NONE;
|
||||
f->colorspace = V4L2_COLORSPACE_RAW;
|
||||
f->bytesperline = f->width * sizeof(u16);
|
||||
|
131
drivers/input/rmi4/rmi_f55.c
Normal file
131
drivers/input/rmi4/rmi_f55.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 Synaptics Incorporated
|
||||
* Copyright (C) 2016 Zodiac Inflight Innovations
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include "rmi_driver.h"
|
||||
|
||||
#define F55_NAME "rmi4_f55"
|
||||
|
||||
/* F55 data offsets */
|
||||
#define F55_NUM_RX_OFFSET 0
|
||||
#define F55_NUM_TX_OFFSET 1
|
||||
#define F55_PHYS_CHAR_OFFSET 2
|
||||
|
||||
/* Only read required query registers */
|
||||
#define F55_QUERY_LEN 3
|
||||
|
||||
/* F55 capabilities */
|
||||
#define F55_CAP_SENSOR_ASSIGN BIT(0)
|
||||
|
||||
struct f55_data {
|
||||
struct rmi_function *fn;
|
||||
|
||||
u8 qry[F55_QUERY_LEN];
|
||||
u8 num_rx_electrodes;
|
||||
u8 cfg_num_rx_electrodes;
|
||||
u8 num_tx_electrodes;
|
||||
u8 cfg_num_tx_electrodes;
|
||||
};
|
||||
|
||||
static int rmi_f55_detect(struct rmi_function *fn)
|
||||
{
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f55_data *f55;
|
||||
int error;
|
||||
|
||||
f55 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
|
||||
&f55->qry, sizeof(f55->qry));
|
||||
if (error) {
|
||||
dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
|
||||
__func__);
|
||||
return error;
|
||||
}
|
||||
|
||||
f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
|
||||
f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
|
||||
|
||||
f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
|
||||
f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
|
||||
|
||||
drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
|
||||
drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
|
||||
|
||||
if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
|
||||
int i, total;
|
||||
u8 buf[256];
|
||||
|
||||
/*
|
||||
* Calculate the number of enabled receive and transmit
|
||||
* electrodes by reading F55:Ctrl1 (sensor receiver assignment)
|
||||
* and F55:Ctrl2 (sensor transmitter assignment). The number of
|
||||
* enabled electrodes is the sum of all field entries with a
|
||||
* value other than 0xff.
|
||||
*/
|
||||
error = rmi_read_block(fn->rmi_dev,
|
||||
fn->fd.control_base_addr + 1,
|
||||
buf, f55->num_rx_electrodes);
|
||||
if (!error) {
|
||||
total = 0;
|
||||
for (i = 0; i < f55->num_rx_electrodes; i++) {
|
||||
if (buf[i] != 0xff)
|
||||
total++;
|
||||
}
|
||||
f55->cfg_num_rx_electrodes = total;
|
||||
drv_data->num_rx_electrodes = total;
|
||||
}
|
||||
|
||||
error = rmi_read_block(fn->rmi_dev,
|
||||
fn->fd.control_base_addr + 2,
|
||||
buf, f55->num_tx_electrodes);
|
||||
if (!error) {
|
||||
total = 0;
|
||||
for (i = 0; i < f55->num_tx_electrodes; i++) {
|
||||
if (buf[i] != 0xff)
|
||||
total++;
|
||||
}
|
||||
f55->cfg_num_tx_electrodes = total;
|
||||
drv_data->num_tx_electrodes = total;
|
||||
}
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
|
||||
f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
|
||||
f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f55_probe(struct rmi_function *fn)
|
||||
{
|
||||
struct f55_data *f55;
|
||||
|
||||
f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
|
||||
if (!f55)
|
||||
return -ENOMEM;
|
||||
|
||||
f55->fn = fn;
|
||||
dev_set_drvdata(&fn->dev, f55);
|
||||
|
||||
return rmi_f55_detect(fn);
|
||||
}
|
||||
|
||||
struct rmi_function_handler rmi_f55_handler = {
|
||||
.driver = {
|
||||
.name = F55_NAME,
|
||||
},
|
||||
.func = 0x55,
|
||||
.probe = rmi_f55_probe,
|
||||
};
|
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
|
||||
struct mutex page_mutex;
|
||||
int page;
|
||||
|
||||
int irq;
|
||||
|
||||
u8 *tx_buf;
|
||||
size_t tx_buf_size;
|
||||
|
||||
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
|
||||
.read_block = rmi_i2c_read_block,
|
||||
};
|
||||
|
||||
static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = dev_id;
|
||||
struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
|
||||
int ret;
|
||||
|
||||
ret = rmi_process_interrupt_requests(rmi_dev);
|
||||
if (ret)
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
|
||||
"Failed to process interrupt request: %d\n", ret);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rmi_i2c_init_irq(struct i2c_client *client)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
|
||||
int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
|
||||
int ret;
|
||||
|
||||
if (!irq_flags)
|
||||
irq_flags = IRQF_TRIGGER_LOW;
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
|
||||
rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
|
||||
rmi_i2c);
|
||||
if (ret < 0) {
|
||||
dev_warn(&client->dev, "Failed to register interrupt %d\n",
|
||||
rmi_i2c->irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id rmi_i2c_of_match[] = {
|
||||
{ .compatible = "syna,rmi4-i2c" },
|
||||
@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
if (!client->dev.of_node && client_pdata)
|
||||
*pdata = *client_pdata;
|
||||
|
||||
if (client->irq > 0)
|
||||
rmi_i2c->irq = client->irq;
|
||||
pdata->irq = client->irq;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
|
||||
dev_name(&client->dev));
|
||||
@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_i2c_init_irq(client);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
|
||||
client->addr);
|
||||
return 0;
|
||||
@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
|
||||
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
|
||||
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
disable_irq(rmi_i2c->irq);
|
||||
if (device_may_wakeup(&client->dev)) {
|
||||
ret = enable_irq_wake(rmi_i2c->irq);
|
||||
if (!ret)
|
||||
dev_warn(dev, "Failed to enable irq for wake: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
|
||||
@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
|
||||
|
||||
msleep(rmi_i2c->startup_delay);
|
||||
|
||||
enable_irq(rmi_i2c->irq);
|
||||
if (device_may_wakeup(&client->dev)) {
|
||||
ret = disable_irq_wake(rmi_i2c->irq);
|
||||
if (!ret)
|
||||
dev_warn(dev, "Failed to disable irq for wake: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
|
||||
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
|
||||
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
|
||||
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
disable_irq(rmi_i2c->irq);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
|
||||
@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
|
||||
|
||||
msleep(rmi_i2c->startup_delay);
|
||||
|
||||
enable_irq(rmi_i2c->irq);
|
||||
|
||||
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
|
||||
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
|
447
drivers/input/rmi4/rmi_smbus.c
Normal file
447
drivers/input/rmi4/rmi_smbus.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2016 Red Hat, Inc
|
||||
* Copyright (c) 2011, 2012 Synaptics Incorporated
|
||||
* Copyright (c) 2011 Unixphere
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include "rmi_driver.h"
|
||||
|
||||
#define SMB_PROTOCOL_VERSION_ADDRESS 0xfd
|
||||
#define SMB_MAX_COUNT 32
|
||||
#define RMI_SMB2_MAP_SIZE 8 /* 8 entry of 4 bytes each */
|
||||
#define RMI_SMB2_MAP_FLAGS_WE 0x01
|
||||
|
||||
struct mapping_table_entry {
|
||||
__le16 rmiaddr;
|
||||
u8 readcount;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct rmi_smb_xport {
|
||||
struct rmi_transport_dev xport;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct mutex page_mutex;
|
||||
int page;
|
||||
u8 table_index;
|
||||
struct mutex mappingtable_mutex;
|
||||
struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
|
||||
};
|
||||
|
||||
static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
|
||||
{
|
||||
struct i2c_client *client = rmi_smb->client;
|
||||
int retval;
|
||||
|
||||
/* Check if for SMBus new version device by reading version byte. */
|
||||
retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
|
||||
if (retval < 0) {
|
||||
dev_err(&client->dev, "failed to get SMBus version number!\n");
|
||||
return retval;
|
||||
}
|
||||
return retval + 1;
|
||||
}
|
||||
|
||||
/* SMB block write - wrapper over ic2_smb_write_block */
|
||||
static int smb_block_write(struct rmi_transport_dev *xport,
|
||||
u8 commandcode, const void *buf, size_t len)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
struct i2c_client *client = rmi_smb->client;
|
||||
int retval;
|
||||
|
||||
retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
|
||||
"wrote %zd bytes at %#04x: %d (%*ph)\n",
|
||||
len, commandcode, retval, (int)len, buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* The function to get command code for smbus operations and keeps
|
||||
* records to the driver mapping table
|
||||
*/
|
||||
static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
|
||||
u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
int i;
|
||||
int retval;
|
||||
struct mapping_table_entry mapping_data[1];
|
||||
|
||||
mutex_lock(&rmi_smb->mappingtable_mutex);
|
||||
for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
|
||||
if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
|
||||
if (isread) {
|
||||
if (rmi_smb->mapping_table[i].readcount
|
||||
== bytecount) {
|
||||
*commandcode = i;
|
||||
retval = 0;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
if (rmi_smb->mapping_table[i].flags &
|
||||
RMI_SMB2_MAP_FLAGS_WE) {
|
||||
*commandcode = i;
|
||||
retval = 0;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i = rmi_smb->table_index;
|
||||
rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
|
||||
|
||||
/* constructs mapping table data entry. 4 bytes each entry */
|
||||
memset(mapping_data, 0, sizeof(mapping_data));
|
||||
|
||||
mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
|
||||
mapping_data[0].readcount = bytecount;
|
||||
mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
|
||||
|
||||
retval = smb_block_write(xport, i + 0x80, mapping_data,
|
||||
sizeof(mapping_data));
|
||||
|
||||
if (retval < 0) {
|
||||
/*
|
||||
* if not written to device mapping table
|
||||
* clear the driver mapping table records
|
||||
*/
|
||||
rmi_smb->mapping_table[i].rmiaddr = 0x0000;
|
||||
rmi_smb->mapping_table[i].readcount = 0;
|
||||
rmi_smb->mapping_table[i].flags = 0;
|
||||
goto exit;
|
||||
}
|
||||
/* save to the driver level mapping table */
|
||||
rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
|
||||
rmi_smb->mapping_table[i].readcount = bytecount;
|
||||
rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
|
||||
*commandcode = i;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&rmi_smb->mappingtable_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
|
||||
const void *databuff, size_t len)
|
||||
{
|
||||
int retval = 0;
|
||||
u8 commandcode;
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
int cur_len = (int)len;
|
||||
|
||||
mutex_lock(&rmi_smb->page_mutex);
|
||||
|
||||
while (cur_len > 0) {
|
||||
/*
|
||||
* break into 32 bytes chunks to write get command code
|
||||
*/
|
||||
int block_len = min_t(int, len, SMB_MAX_COUNT);
|
||||
|
||||
retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
|
||||
false, &commandcode);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
retval = smb_block_write(xport, commandcode,
|
||||
databuff, block_len);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
/* prepare to write next block of bytes */
|
||||
cur_len -= SMB_MAX_COUNT;
|
||||
databuff += SMB_MAX_COUNT;
|
||||
rmiaddr += SMB_MAX_COUNT;
|
||||
}
|
||||
exit:
|
||||
mutex_unlock(&rmi_smb->page_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* SMB block read - wrapper over ic2_smb_read_block */
|
||||
static int smb_block_read(struct rmi_transport_dev *xport,
|
||||
u8 commandcode, void *buf, size_t len)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
struct i2c_client *client = rmi_smb->client;
|
||||
int retval;
|
||||
|
||||
retval = i2c_smbus_read_block_data(client, commandcode, buf);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
|
||||
void *databuff, size_t len)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
int retval;
|
||||
u8 commandcode;
|
||||
int cur_len = (int)len;
|
||||
|
||||
mutex_lock(&rmi_smb->page_mutex);
|
||||
memset(databuff, 0, len);
|
||||
|
||||
while (cur_len > 0) {
|
||||
/* break into 32 bytes chunks to write get command code */
|
||||
int block_len = min_t(int, cur_len, SMB_MAX_COUNT);
|
||||
|
||||
retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
|
||||
true, &commandcode);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
retval = smb_block_read(xport, commandcode,
|
||||
databuff, block_len);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
/* prepare to read next block of bytes */
|
||||
cur_len -= SMB_MAX_COUNT;
|
||||
databuff += SMB_MAX_COUNT;
|
||||
rmiaddr += SMB_MAX_COUNT;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&rmi_smb->page_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
|
||||
{
|
||||
/* the mapping table has been flushed, discard the current one */
|
||||
mutex_lock(&rmi_smb->mappingtable_mutex);
|
||||
memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
|
||||
mutex_unlock(&rmi_smb->mappingtable_mutex);
|
||||
}
|
||||
|
||||
static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* we need to get the smbus version to activate the touchpad */
|
||||
retval = rmi_smb_get_version(rmi_smb);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb =
|
||||
container_of(xport, struct rmi_smb_xport, xport);
|
||||
|
||||
rmi_smb_clear_state(rmi_smb);
|
||||
|
||||
/*
|
||||
* we do not call the actual reset command, it has to be handled in
|
||||
* PS/2 or there will be races between PS/2 and SMBus.
|
||||
* PS/2 should ensure that a psmouse_reset is called before
|
||||
* intializing the device and after it has been removed to be in a known
|
||||
* state.
|
||||
*/
|
||||
return rmi_smb_enable_smbus_mode(rmi_smb);
|
||||
}
|
||||
|
||||
static const struct rmi_transport_ops rmi_smb_ops = {
|
||||
.write_block = rmi_smb_write_block,
|
||||
.read_block = rmi_smb_read_block,
|
||||
.reset = rmi_smb_reset,
|
||||
};
|
||||
|
||||
static int rmi_smb_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct rmi_smb_xport *rmi_smb;
|
||||
int retval;
|
||||
int smbus_version;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_HOST_NOTIFY)) {
|
||||
dev_err(&client->dev,
|
||||
"adapter does not support required functionality.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (client->irq <= 0) {
|
||||
dev_err(&client->dev, "no IRQ provided, giving up.\n");
|
||||
return client->irq ? client->irq : -ENODEV;
|
||||
}
|
||||
|
||||
rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
|
||||
GFP_KERNEL);
|
||||
if (!rmi_smb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "no platform data, aborting\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
|
||||
dev_name(&client->dev));
|
||||
|
||||
rmi_smb->client = client;
|
||||
mutex_init(&rmi_smb->page_mutex);
|
||||
mutex_init(&rmi_smb->mappingtable_mutex);
|
||||
|
||||
rmi_smb->xport.dev = &client->dev;
|
||||
rmi_smb->xport.pdata = *pdata;
|
||||
rmi_smb->xport.pdata.irq = client->irq;
|
||||
rmi_smb->xport.proto_name = "smb2";
|
||||
rmi_smb->xport.ops = &rmi_smb_ops;
|
||||
|
||||
retval = rmi_smb_get_version(rmi_smb);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
smbus_version = retval;
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
|
||||
smbus_version);
|
||||
|
||||
if (smbus_version != 2) {
|
||||
dev_err(&client->dev, "Unrecognized SMB version %d.\n",
|
||||
smbus_version);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, rmi_smb);
|
||||
|
||||
retval = rmi_register_transport_device(&rmi_smb->xport);
|
||||
if (retval) {
|
||||
dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
|
||||
client->addr);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
return retval;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
|
||||
client->addr);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int rmi_smb_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
|
||||
|
||||
rmi_unregister_transport_device(&rmi_smb->xport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rmi_smb_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to suspend device: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to suspend device: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused rmi_smb_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
|
||||
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
|
||||
struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
|
||||
int ret;
|
||||
|
||||
rmi_smb_reset(&rmi_smb->xport, 0);
|
||||
|
||||
rmi_reset(rmi_dev);
|
||||
|
||||
ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rmi_smb_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
|
||||
SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rmi_id[] = {
|
||||
{ "rmi4_smbus", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rmi_id);
|
||||
|
||||
static struct i2c_driver rmi_smb_driver = {
|
||||
.driver = {
|
||||
.name = "rmi4_smbus",
|
||||
.pm = &rmi_smb_pm,
|
||||
},
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_smb_probe,
|
||||
.remove = rmi_smb_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(rmi_smb_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
|
||||
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
|
||||
MODULE_DESCRIPTION("RMI4 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -12,7 +12,6 @@
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include "rmi_driver.h"
|
||||
|
||||
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
|
||||
struct mutex page_mutex;
|
||||
int page;
|
||||
|
||||
int irq;
|
||||
|
||||
u8 *rx_buf;
|
||||
u8 *tx_buf;
|
||||
int xfer_buf_size;
|
||||
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
|
||||
.read_block = rmi_spi_read_block,
|
||||
};
|
||||
|
||||
static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = dev_id;
|
||||
struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
|
||||
int ret;
|
||||
|
||||
ret = rmi_process_interrupt_requests(rmi_dev);
|
||||
if (ret)
|
||||
rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
|
||||
"Failed to process interrupt request: %d\n", ret);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rmi_spi_init_irq(struct spi_device *spi)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
|
||||
int ret;
|
||||
|
||||
if (!irq_flags)
|
||||
irq_flags = IRQF_TRIGGER_LOW;
|
||||
|
||||
ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
|
||||
rmi_spi_irq, irq_flags | IRQF_ONESHOT,
|
||||
dev_name(&spi->dev), rmi_spi);
|
||||
if (ret < 0) {
|
||||
dev_warn(&spi->dev, "Failed to register interrupt %d\n",
|
||||
rmi_spi->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int rmi_spi_of_probe(struct spi_device *spi,
|
||||
struct rmi_device_platform_data *pdata)
|
||||
@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (spi->irq > 0)
|
||||
rmi_spi->irq = spi->irq;
|
||||
pdata->irq = spi->irq;
|
||||
|
||||
rmi_spi->spi = spi;
|
||||
mutex_init(&rmi_spi->page_mutex);
|
||||
@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_spi_init_irq(spi);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
dev_info(&spi->dev, "registered RMI SPI driver\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
|
||||
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
disable_irq(rmi_spi->irq);
|
||||
if (device_may_wakeup(&spi->dev)) {
|
||||
ret = enable_irq_wake(rmi_spi->irq);
|
||||
if (!ret)
|
||||
dev_warn(dev, "Failed to enable irq for wake: %d\n",
|
||||
ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
enable_irq(rmi_spi->irq);
|
||||
if (device_may_wakeup(&spi->dev)) {
|
||||
ret = disable_irq_wake(rmi_spi->irq);
|
||||
if (!ret)
|
||||
dev_warn(dev, "Failed to disable irq for wake: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
|
||||
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
|
||||
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
disable_irq(rmi_spi->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
enable_irq(rmi_spi->irq);
|
||||
|
||||
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
|
||||
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to resume device: %d\n", ret);
|
||||
|
||||
|
Reference in New Issue
Block a user