/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This driver provides the core support for a single RMI4-based device.
*
* The RMI4 specification can be found here (URL split for line length):
*
* http://www.synaptics.com/sites/default/files/
* 511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
*
* 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/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>
#include <uapi/linux/input.h>
#include <linux/rmi.h>
#include "rmi_bus.h"
#include "rmi_driver.h"
#define HAS_NONSTANDARD_PDT_MASK 0x40
#define RMI4_MAX_PAGE 0xff
#define RMI4_PAGE_SIZE 0x100
#define RMI4_PAGE_MASK 0xFF00
#define RMI_DEVICE_RESET_CMD 0x01
#define DEFAULT_RESET_DELAY_MS 100
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,
&data->function_list, node) {
list_del(&fn->node);
rmi_unregister_function(fn);
}
}
static int reset_one_function(struct rmi_function *fn)
{
struct rmi_function_handler *fh;
int retval = 0;
if (!fn || !fn->dev.driver)
return 0;
fh = to_rmi_function_handler(fn->dev.driver);
if (fh->reset) {
retval = fh->reset(fn);
if (retval < 0)
dev_err(&fn->dev, "Reset failed with code %d.\n",
retval);
}
return retval;
}
static int configure_one_function(struct rmi_function *fn)
{
struct rmi_function_handler *fh;
int retval = 0;
if (!fn || !fn->dev.driver)
return 0;
fh = to_rmi_function_handler(fn->dev.driver);
if (fh->config) {
retval = fh->config(fn);
if (retval < 0)
dev_err(&fn->dev, "Config failed with code %d.\n",
retval);
}
return retval;
}
static int rmi_driver_process_reset_requests(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct rmi_function *entry;
int retval;
list_for_each_entry(entry, &data->function_list, node) {
retval