rk30 phone loauqt: add touch screen synaptics s3202 standar drivers

This commit is contained in:
hhb 2012-05-27 15:52:01 +08:00
parent 76ca4c2356
commit 7b8ca11798
20 changed files with 20877 additions and 0 deletions

View File

@ -0,0 +1,198 @@
#
# RMI4 configuration
#
config RMI4_BUS
bool "Synaptics RMI4 bus support"
depends on TOUCHSCREEN_SYNAPTICS_RMI4_I2C_RK
help
Say Y here if you want to support the Synaptics RMI4 bus.
If unsure, say Y.
This feature is not currently available as
a loadable module.
config RMI4_DEBUG
bool "Synaptics RMI4 debugging"
depends on RMI4_BUS
help
Say Y here to enable debug feature in the RMI4 driver.
Note that the RMI4 driver debug features can generate a lot of
output (potentially clogging up your dmesg output) and generally
slow down driver operation. It's recommended to enable them only
if you are actively developing/debugging RMI4 features.
If unsure, say N.
config RMI4_I2C
bool "RMI4 I2C Support"
depends on RMI4_BUS && I2C
help
Say Y here if you want to support RMI4 devices connected to an I2C
bus.
If unsure, say Y.
This feature is not currently available as a loadable module.
config RMI4_I2C_SCL_RATE
int "RMI4 I2C SCL RATE Support"
depends on RMI4_I2C
config RMI4_SPI
bool "RMI4 SPI Support"
depends on RMI4_BUS && SPI
help
Say Y here if you want to support RMI4 devices connected to an SPI
bus.
If unsure, say Y.
This feature is not currently available as a loadable module.
config RMI4_GENERIC
bool "RMI4 Generic driver"
depends on RMI4_BUS
help
Say Y here if you want to support generic RMI4 devices.
This is pretty much required if you want to do anything useful with
your RMI device.
This feature is not currently available as a loadable module.
config RMI4_F1A
tristate "RMI4 Function 1A (capacitive button sensor)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 1A.
Function 1A provides self testing for touchscreens and touchpads.
To compile this driver as a module, choose M here: the
module will be called rmi-f1a.
config RMI4_F09
tristate "RMI4 Function 09 (self testing)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 09.
Function 09 provides self testing for touchscreens and touchpads.
To compile this driver as a module, choose M here: the
module will be called rmi-f09.
config RMI4_F11
tristate "RMI4 Function 11 (2D pointing)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 11.
Function 11 provides 2D multifinger pointing for touchscreens and
touchpads. For sensors that support relative pointing, F11 also
provides mouse input.
To compile this driver as a module, choose M here: the
module will be called rmi-f11.
config RMI4_F11_PEN
bool "RMI4 F11 Pen Support"
depends on RMI4_F11
help
Say Y here to add support for pen input to RMI4 function 11.
If this feature is enabled, when pen inputs are detected they
will be reported to the input stream as MT_TOOL_PEN. Otherwise,
pens will be treated the same as fingers.
Not all UI implementations deal gracefully with pen discrimination.
If your system is not recognizing pen touches and you know your
sensor supports pen input, you probably want to turn this feature
off.
config RMI4_VIRTUAL_BUTTON
tristate "RMI4 Vitual Button"
depends on RMI4_F11
help
Say Y here if you want to add support for RMI4 virtual button to F11.
The virtual button feature implement the virtual button device in
certain RMI4 touch sensors.
This works only if your sensor supports F11 gestures.
config RMI4_F17
tristate "RMI4 Function 17 (pointing sticks)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 17.
Function 19 provides support for capacitive and resistive
pointing sticks.
To compile this driver as a module, choose M here: the
module will be called rmi-f17.
config RMI4_F19
tristate "RMI4 Function 19 (0D pointing)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 19.
Function 19 provides support for capacitive buttons for sensors
that implement capacitive buttons.
To compile this driver as a module, choose M here: the
module will be called rmi-f19.
config RMI4_F21
tristate "RMI4 Function 21 (2D Force)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 21.
Function 21 provides 2D Force Sensing for ForcePad products.
To compile this driver as a module, choose M here: the
module will be called rmi-f21.
config RMI4_F34
tristate "RMI4 Function 34 (device reflash)"
depends on RMI4_BUS && RMI4_GENERIC
help
Say Y here if you want to add support for RMI4 function 34.
Function 34 provides firmware upgrade capability for your sensor.
To compile this driver as a module, choose M here: the
module will be called rmi-f34.
config RMI4_REFLASH_WHEN_BOOT
tristate "RMI4 Function 34 (device reflash when system boot)"
depends on RMI4_BUS && RMI4_GENERIC
config RMI4_F54
tristate "RMI4 Function 54 (analog diagnostics)"
depends on RMI4_BUS && RMI4_GENERIC
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.
To compile this driver as a module, choose M here: the
module will be called rmi-f54.
config RMI4_DEV
tristate "Synaptics direct RMI device support (rmidev)"
depends on GPIO_SYSFS && (RMI4_I2C || RMI4_SPI)
help
Say Y here to add support for rmidev.
The rmidev feature implements a character device providing access
to RMI4 sensor register maps.
To compile this driver as a module, choose M here: the
module will be called rmi-dev.

View File

@ -0,0 +1,34 @@
obj-$(CONFIG_RMI4_BUS) += rmi_bus.o
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
obj-$(CONFIG_RMI4_GENERIC) += rmi_driver.o rmi_f01.o
obj-$(CONFIG_RMI4_F09) += rmi_f09.o
obj-$(CONFIG_RMI4_F1A) += rmi_f1a.o
obj-$(CONFIG_RMI4_F11) += rmi_f11.o
obj-$(CONFIG_RMI4_F17) += rmi_f17.o
obj-$(CONFIG_RMI4_F19) += rmi_f19.o
obj-$(CONFIG_RMI4_F21) += rmi_f21.o
obj-$(CONFIG_RMI4_F34) += rmi_f34.o
obj-$(CONFIG_RMI4_F54) += rmi_f54.o
obj-$(CONFIG_RMI4_DEV) += rmi_dev.o
obj-y += rmi_reflash.o
ifeq ($(KERNELRELEASE),)
# KERNELDIR ?= /home/<AndroidKernelDirectory>
PWD := $(shell pwd)
.PHONY: build clean
build:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
else
$(info Building with KERNELRELEASE = ${KERNELRELEASE})
obj-m += rmi_dev.o
endif

View File

@ -0,0 +1,482 @@
/*
* Copyright (c) 2011 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/rmi.h>
#include <linux/types.h>
#ifdef CONFIG_RMI4_DEBUG
#include <linux/debugfs.h>
#endif
#include "rmi_driver.h"
DEFINE_MUTEX(rmi_bus_mutex);
static struct rmi_function_list {
struct list_head list;
struct rmi_function_handler *fh;
} rmi_supported_functions;
static struct rmi_character_driver_list {
struct list_head list;
struct rmi_char_driver *cd;
} rmi_character_drivers;
static atomic_t physical_device_count;
#ifdef CONFIG_RMI4_DEBUG
static struct dentry *rmi_debugfs_root;
#endif
static int rmi_bus_match(struct device *dev, struct device_driver *driver)
{
struct rmi_driver *rmi_driver;
struct rmi_device *rmi_dev;
struct rmi_device_platform_data *pdata;
rmi_driver = to_rmi_driver(driver);
rmi_dev = to_rmi_device(dev);
pdata = to_rmi_platform_data(rmi_dev);
dev_dbg(dev, "%s: Matching %s.\n", __func__, pdata->sensor_name);
if (!strcmp(pdata->driver_name, rmi_driver->driver.name)) {
rmi_dev->driver = rmi_driver;
dev_dbg(dev, "%s: Match %s to %s succeeded.\n", __func__,
pdata->driver_name, rmi_driver->driver.name);
return 1;
}
dev_vdbg(dev, "%s: Match %s to %s failed.\n", __func__,
pdata->driver_name, rmi_driver->driver.name);
return 0;
}
#ifdef CONFIG_PM
static int rmi_bus_suspend(struct device *dev)
{
#ifdef GENERIC_SUBSYS_PM_OPS
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm && pm->suspend)
return pm->suspend(dev);
#endif
return 0;
}
static int rmi_bus_resume(struct device *dev)
{
#ifdef GENERIC_SUBSYS_PM_OPS
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pm && pm->resume)
return pm->resume(dev);
else if (dev->driver && dev->driver->resume)
return dev->driver->resume(dev);
#else
if (dev->driver && dev->driver->resume)
return dev->driver->resume(dev);
#endif
return 0;
}
#endif
static int rmi_bus_probe(struct device *dev)
{
struct rmi_driver *driver;
struct rmi_device *rmi_dev = to_rmi_device(dev);
driver = rmi_dev->driver;
if (driver && driver->probe)
return driver->probe(rmi_dev);
return 0;
}
static int rmi_bus_remove(struct device *dev)
{
struct rmi_driver *driver;
struct rmi_device *rmi_dev = to_rmi_device(dev);
driver = rmi_dev->driver;
if (driver && driver->remove)
return driver->remove(rmi_dev);
return 0;
}
static void rmi_bus_shutdown(struct device *dev)
{
struct rmi_driver *driver;
struct rmi_device *rmi_dev = to_rmi_device(dev);
driver = rmi_dev->driver;
if (driver && driver->shutdown)
driver->shutdown(rmi_dev);
}
static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops,
rmi_bus_suspend, rmi_bus_resume);
struct bus_type rmi_bus_type = {
.name = "rmi",
.match = rmi_bus_match,
.probe = rmi_bus_probe,
.remove = rmi_bus_remove,
.shutdown = rmi_bus_shutdown,
.pm = &rmi_bus_pm_ops
};
static void release_rmidev_device(struct device *dev) {
device_unregister(dev);
}
int rmi_register_phys_device(struct rmi_phys_device *phys)
{
struct rmi_device_platform_data *pdata = phys->dev->platform_data;
struct rmi_device *rmi_dev;
if (!pdata) {
dev_err(phys->dev, "no platform data!\n");
return -EINVAL;
}
rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
if (!rmi_dev)
return -ENOMEM;
rmi_dev->phys = phys;
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->number = atomic_inc_return(&physical_device_count) - 1;
rmi_dev->dev.release = release_rmidev_device;
dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
dev_dbg(phys->dev, "%s: Registered %s as %s.\n", __func__,
pdata->sensor_name, dev_name(&rmi_dev->dev));
#ifdef CONFIG_RMI4_DEBUG
if (rmi_debugfs_root) {
rmi_dev->debugfs_root = debugfs_create_dir(
dev_name(&rmi_dev->dev), rmi_debugfs_root);
if (!rmi_dev->debugfs_root)
dev_err(&rmi_dev->dev, "Failed to create debugfs root.\n");
}
#endif
phys->rmi_dev = rmi_dev;
return device_register(&rmi_dev->dev);
}
EXPORT_SYMBOL(rmi_register_phys_device);
void rmi_unregister_phys_device(struct rmi_phys_device *phys)
{
struct rmi_device *rmi_dev = phys->rmi_dev;
#ifdef CONFIG_RMI4_DEBUG
if (rmi_dev->debugfs_root)
debugfs_remove(rmi_dev->debugfs_root);
#endif
kfree(rmi_dev);
}
EXPORT_SYMBOL(rmi_unregister_phys_device);
int rmi_register_driver(struct rmi_driver *driver)
{
driver->driver.bus = &rmi_bus_type;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL(rmi_register_driver);
static int __rmi_driver_remove(struct device *dev, void *data)
{
struct rmi_driver *driver = data;
struct rmi_device *rmi_dev = to_rmi_device(dev);
if (rmi_dev->driver == driver)
rmi_dev->driver = NULL;
return 0;
}
void rmi_unregister_driver(struct rmi_driver *driver)
{
bus_for_each_dev(&rmi_bus_type, NULL, driver, __rmi_driver_remove);
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL(rmi_unregister_driver);
static int __rmi_bus_fh_add(struct device *dev, void *data)
{
struct rmi_driver *driver;
struct rmi_device *rmi_dev = to_rmi_device(dev);
driver = rmi_dev->driver;
if (driver && driver->fh_add)
driver->fh_add(rmi_dev, data);
return 0;
}
int rmi_register_function_driver(struct rmi_function_handler *fh)
{
struct rmi_function_list *entry;
struct rmi_function_handler *fh_dup;
fh_dup = rmi_get_function_handler(fh->func);
if (fh_dup) {
pr_err("%s: function f%.2x already registered!\n", __func__,
fh->func);
return -EINVAL;
}
entry = kzalloc(sizeof(struct rmi_function_list), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->fh = fh;
INIT_LIST_HEAD(&entry->list);
list_add_tail(&entry->list, &rmi_supported_functions.list);
/* notify devices of the new function handler */
bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_add);
return 0;
}
EXPORT_SYMBOL(rmi_register_function_driver);
static int __rmi_bus_fh_remove(struct device *dev, void *data)
{
struct rmi_driver *driver;
struct rmi_device *rmi_dev = to_rmi_device(dev);
driver = rmi_dev->driver;
if (driver && driver->fh_remove)
driver->fh_remove(rmi_dev, data);
return 0;
}
void rmi_unregister_function_driver(struct rmi_function_handler *fh)
{
struct rmi_function_list *entry, *n;
/* notify devices of the removal of the function handler */
bus_for_each_dev(&rmi_bus_type, NULL, fh, __rmi_bus_fh_remove);
if (list_empty(&rmi_supported_functions.list))
return;
list_for_each_entry_safe(entry, n, &rmi_supported_functions.list,
list) {
if (entry->fh->func == fh->func) {
list_del(&entry->list);
kfree(entry);
}
}
}
EXPORT_SYMBOL(rmi_unregister_function_driver);
struct rmi_function_handler *rmi_get_function_handler(int id)
{
struct rmi_function_list *entry;
if (list_empty(&rmi_supported_functions.list))
return NULL;
list_for_each_entry(entry, &rmi_supported_functions.list, list)
if (entry->fh->func == id)
return entry->fh;
return NULL;
}
EXPORT_SYMBOL(rmi_get_function_handler);
static void rmi_release_character_device(struct device *dev)
{
dev_dbg(dev, "%s: Called.\n", __func__);
return;
}
static int rmi_register_character_device(struct device *dev, void *data)
{
struct rmi_device *rmi_dev;
struct rmi_char_driver *char_driver = data;
struct rmi_char_device *char_dev;
int retval;
dev_dbg(dev, "Attaching character device.\n");
rmi_dev = to_rmi_device(dev);
if (char_driver->match && !char_driver->match(rmi_dev))
return 0;
if (!char_driver->init) {
dev_err(dev, "ERROR: No init() function in %s.\n", __func__);
return -EINVAL;
}
char_dev = kzalloc(sizeof(struct rmi_char_device), GFP_KERNEL);
if (!char_dev)
return -ENOMEM;
char_dev->rmi_dev = rmi_dev;
char_dev->driver = char_driver;
char_dev->dev.parent = dev;
char_dev->dev.release = rmi_release_character_device;
char_dev->dev.driver = &char_driver->driver;
retval = device_register(&char_dev->dev);
if (!retval) {
dev_err(dev, "Failed to register character device.\n");
goto error_exit;
}
retval = char_driver->init(char_dev);
if (retval) {
dev_err(dev, "Failed to initialize character device.\n");
goto error_exit;
}
mutex_lock(&rmi_bus_mutex);
list_add_tail(&char_dev->list, &char_driver->devices);
mutex_unlock(&rmi_bus_mutex);
dev_info(&char_dev->dev, "Registered a device.\n");
return retval;
error_exit:
kfree(char_dev);
return retval;
}
int rmi_register_character_driver(struct rmi_char_driver *char_driver)
{
struct rmi_character_driver_list *entry;
int retval;
pr_debug("%s: Registering character driver %s.\n", __func__,
char_driver->driver.name);
char_driver->driver.bus = &rmi_bus_type;
INIT_LIST_HEAD(&char_driver->devices);
retval = driver_register(&char_driver->driver);
if (retval) {
pr_err("%s: Failed to register %s, code: %d.\n", __func__,
char_driver->driver.name, retval);
return retval;
}
entry = kzalloc(sizeof(struct rmi_character_driver_list), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->cd = char_driver;
mutex_lock(&rmi_bus_mutex);
list_add_tail(&entry->list, &rmi_character_drivers.list);
mutex_unlock(&rmi_bus_mutex);
/* notify devices of the removal of the function handler */
bus_for_each_dev(&rmi_bus_type, NULL, char_driver,
rmi_register_character_device);
return 0;
}
EXPORT_SYMBOL(rmi_register_character_driver);
int rmi_unregister_character_driver(struct rmi_char_driver *char_driver)
{
struct rmi_character_driver_list *entry, *n;
struct rmi_char_device *char_dev, *m;
pr_debug("%s: Unregistering character driver %s.\n", __func__,
char_driver->driver.name);
mutex_lock(&rmi_bus_mutex);
list_for_each_entry_safe(char_dev, m, &char_driver->devices,
list) {
list_del(&char_dev->list);
char_dev->driver->remove(char_dev);
}
list_for_each_entry_safe(entry, n, &rmi_character_drivers.list,
list) {
if (entry->cd == char_driver) {
list_del(&entry->list);
kfree(entry);
}
}
mutex_unlock(&rmi_bus_mutex);
driver_unregister(&char_driver->driver);
return 0;
}
EXPORT_SYMBOL(rmi_unregister_character_driver);
static int __init rmi_bus_init(void)
{
int error;
mutex_init(&rmi_bus_mutex);
INIT_LIST_HEAD(&rmi_supported_functions.list);
INIT_LIST_HEAD(&rmi_character_drivers.list);
#ifdef CONFIG_RMI4_DEBUG
rmi_debugfs_root = debugfs_create_dir(rmi_bus_type.name, NULL);
if (!rmi_debugfs_root)
pr_err("%s: Failed to create debugfs root.\n", __func__);
else if (IS_ERR(rmi_debugfs_root)) {
pr_err("%s: Kernel may not contain debugfs support, code=%ld\n",
__func__, PTR_ERR(rmi_debugfs_root));
rmi_debugfs_root = NULL;
}
#endif
error = bus_register(&rmi_bus_type);
if (error < 0) {
pr_err("%s: error registering the RMI bus: %d\n", __func__,
error);
return error;
}
pr_debug("%s: successfully registered RMI bus.\n", __func__);
return 0;
}
static void __exit rmi_bus_exit(void)
{
/* We should only ever get here if all drivers are unloaded, so
* all we have to do at this point is unregister ourselves.
*/
#ifdef CONFIG_RMI4_DEBUG
if (rmi_debugfs_root)
debugfs_remove(rmi_debugfs_root);
#endif
bus_unregister(&rmi_bus_type);
}
module_init(rmi_bus_init);
module_exit(rmi_bus_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
MODULE_DESCRIPTION("RMI bus");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

View File

@ -0,0 +1,448 @@
/*
* Copyright (c) 2011 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/syscalls.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#define CHAR_DEVICE_NAME "rmi"
#define DEVICE_CLASS_NAME "rmidev"
#define RMI_CHAR_DEV_TMPBUF_SZ 128
#define RMI_REG_ADDR_PAGE_SELECT 0xFF
#define REG_ADDR_LIMIT 0xFFFF
struct rmidev_data {
/* mutex for file operation*/
struct mutex file_mutex;
/* main char dev structure */
struct cdev main_dev;
/* pointer to the corresponding RMI4 device. We use this to do */
/* read, write, etc. */
struct rmi_device *rmi_dev;
/* reference count */
int ref_count;
struct class *device_class;
};
/*store dynamically allocated major number of char device*/
static int rmidev_major_num;
static struct class *rmidev_device_class;
/* file operations for RMI char device */
/*
* rmidev_llseek: - use to setup register address
*
* @filp: file structure for seek
* @off: offset
* if whence == SEEK_SET,
* high 16 bits: page address
* low 16 bits: register address
*
* if whence == SEEK_CUR,
* offset from current position
*
* if whence == SEEK_END,
* offset from END(0xFFFF)
*
* @whence: SEEK_SET , SEEK_CUR or SEEK_END
*/
static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
{
loff_t newpos;
struct rmidev_data *data = filp->private_data;
if (IS_ERR(data)) {
pr_err("%s: pointer of char device is invalid", __func__);
return -EBADF;
}
mutex_lock(&(data->file_mutex));
switch (whence) {
case SEEK_SET:
newpos = off;
break;
case SEEK_CUR:
newpos = filp->f_pos + off;
break;
case SEEK_END:
newpos = REG_ADDR_LIMIT + off;
break;
default: /* can't happen */
newpos = -EINVAL;
goto clean_up;
}
if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
dev_err(&data->rmi_dev->dev, "newpos 0x%04x is invalid.\n",
(unsigned int)newpos);
newpos = -EINVAL;
goto clean_up;
}
filp->f_pos = newpos;
clean_up:
mutex_unlock(&(data->file_mutex));
return newpos;
}
/*
* rmidev_read: - use to read data from RMI stream
*
* @filp: file structure for read
* @buf: user-level buffer pointer
*
* @count: number of byte read
* @f_pos: offset (starting register address)
*
* @return number of bytes read into user buffer (buf) if succeeds
* negative number if error occurs.
*/
static ssize_t rmidev_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
struct rmidev_data *data = filp->private_data;
ssize_t retval = 0;
unsigned char tmpbuf[count+1];
/* limit offset to REG_ADDR_LIMIT-1 */
if (count > (REG_ADDR_LIMIT - *f_pos))
count = REG_ADDR_LIMIT - *f_pos;
if (count == 0)
return 0;
if (IS_ERR(data)) {
pr_err("%s: pointer of char device is invalid", __func__);
return -EBADF;
}
mutex_lock(&(data->file_mutex));
retval = rmi_read_block(data->rmi_dev, *f_pos, tmpbuf, count);
if (retval < 0)
goto clean_up;
if (copy_to_user(buf, tmpbuf, count))
retval = -EFAULT;
else
*f_pos += retval;
clean_up:
mutex_unlock(&(data->file_mutex));
return retval;
}
/*
* rmidev_write: - use to write data into RMI stream
*
* @filep : file structure for write
* @buf: user-level buffer pointer contains data to be written
* @count: number of byte be be written
* @f_pos: offset (starting register address)
*
* @return number of bytes written from user buffer (buf) if succeeds
* negative number if error occurs.
*/
static ssize_t rmidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
struct rmidev_data *data = filp->private_data;
ssize_t retval = 0;
unsigned char tmpbuf[count+1];
/* limit offset to REG_ADDR_LIMIT-1 */
if (count > (REG_ADDR_LIMIT - *f_pos))
count = REG_ADDR_LIMIT - *f_pos;
if (count == 0)
return 0;
if (IS_ERR(data)) {
pr_err("%s: pointer of char device is invalid", __func__);
return -EBADF;
}
if (copy_from_user(tmpbuf, buf, count))
return -EFAULT;
mutex_lock(&(data->file_mutex));
retval = rmi_write_block(data->rmi_dev, *f_pos, tmpbuf, count);
if (retval >= 0)
*f_pos += count;
mutex_unlock(&(data->file_mutex));
return retval;
}
/*
* rmidev_open: - get a new handle for from RMI stream
* @inp : inode struture
* @filp: file structure for read/write
*
* @return 0 if succeeds
*/
static int rmidev_open(struct inode *inp, struct file *filp)
{
struct rmidev_data *data = container_of(inp->i_cdev,
struct rmidev_data, main_dev);
int retval = 0;
filp->private_data = data;
if (!data->rmi_dev)
return -EACCES;
mutex_lock(&(data->file_mutex));
if (data->ref_count < 1)
data->ref_count++;
else
retval = -EACCES;
mutex_unlock(&(data->file_mutex));
return retval;
}
/*
* rmidev_release: - release an existing handle
* @inp: inode structure
* @filp: file structure for read/write
*
* @return 0 if succeeds
*/
static int rmidev_release(struct inode *inp, struct file *filp)
{
struct rmidev_data *data = container_of(inp->i_cdev,
struct rmidev_data, main_dev);
if (!data->rmi_dev)
return -EACCES;
mutex_lock(&(data->file_mutex));
data->ref_count--;
if (data->ref_count < 0)
data->ref_count = 0;
mutex_unlock(&(data->file_mutex));
return 0;
}
static const struct file_operations rmidev_fops = {
.owner = THIS_MODULE,
.llseek = rmidev_llseek,
.read = rmidev_read,
.write = rmidev_write,
.open = rmidev_open,
.release = rmidev_release,
};
/*
* rmidev_device_cleanup - release memory or unregister driver
* @rmidev_data: instance data for a particular device.
*
*/
static void rmidev_device_cleanup(struct rmidev_data *data)
{
dev_t devno;
/* Get rid of our char dev entries */
if (data) {
devno = data->main_dev.dev;
if (data->device_class)
device_destroy(data->device_class, devno);
cdev_del(&data->main_dev);
kfree(data);
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, 1);
pr_debug("%s: rmidev device is removed\n", __func__);
}
}
/*
* rmi_char_devnode - return device permission
*
* @dev: char device structure
* @mode: file permission
*
*/
static char *rmi_char_devnode(struct device *dev, mode_t *mode)
{
if (!mode)
return NULL;
/**mode = 0666*/
*mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
}
static int rmidev_init_device(struct rmi_char_device *cd)
{
struct rmi_device *rmi_dev = cd->rmi_dev;
struct rmidev_data *data;
dev_t dev_no;
int retval;
struct device *device_ptr;
if (rmidev_major_num) {
dev_no = MKDEV(rmidev_major_num, cd->rmi_dev->number);
retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
} else {
retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
/* let kernel allocate a major for us */
rmidev_major_num = MAJOR(dev_no);
dev_info(&rmi_dev->dev, "Major number of rmidev: %d\n",
rmidev_major_num);
}
if (retval < 0) {
dev_err(&rmi_dev->dev,
"Failed to get minor dev number %d, code %d.\n",
cd->rmi_dev->number, retval);
return retval;
} else
dev_info(&rmi_dev->dev, "Allocated rmidev %d %d.\n",
MAJOR(dev_no), MINOR(dev_no));
data = kzalloc(sizeof(struct rmidev_data), GFP_KERNEL);
if (!data) {
dev_err(&rmi_dev->dev, "Failed to allocate rmidev_data.\n");
/* unregister the char device region */
__unregister_chrdev(rmidev_major_num, MINOR(dev_no), 1,
CHAR_DEVICE_NAME);
return -ENOMEM;
}
mutex_init(&data->file_mutex);
data->rmi_dev = cd->rmi_dev;
cd->data = data;
cdev_init(&data->main_dev, &rmidev_fops);
retval = cdev_add(&data->main_dev, dev_no, 1);
if (retval) {
dev_err(&cd->rmi_dev->dev, "Error %d adding rmi_char_dev.\n",
retval);
rmidev_device_cleanup(data);
return retval;
}
dev_set_name(&cd->dev, "rmidev%d", MINOR(dev_no));
data->device_class = rmidev_device_class;
device_ptr = device_create(
data->device_class,
NULL, dev_no, NULL,
CHAR_DEVICE_NAME"%d",
MINOR(dev_no));
if (IS_ERR(device_ptr)) {
dev_err(&cd->rmi_dev->dev, "Failed to create rmi device.\n");
rmidev_device_cleanup(data);
return -ENODEV;
}
return 0;
}
static void rmidev_remove_device(struct rmi_char_device *cd)
{
struct rmidev_data *data;
dev_dbg(&cd->dev, "%s: removing an rmidev device.\n", __func__);
if (!cd)
return;
data = cd->data;
if (data)
rmidev_device_cleanup(data);
}
static struct rmi_char_driver rmidev_driver = {
.driver = {
.name = "rmidev",
.owner = THIS_MODULE,
},
.init = rmidev_init_device,
.remove = rmidev_remove_device,
};
static int __init rmidev_init(void)
{
int error = 0;
pr_debug("%s: rmi_dev initialization.\n", __func__);
/* create device node */
rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
if (IS_ERR(rmidev_device_class)) {
pr_err("%s: ERROR - Failed to create /dev/%s.\n", __func__,
CHAR_DEVICE_NAME);
return -ENODEV;
}
/* setup permission */
rmidev_device_class->devnode = rmi_char_devnode;
error = rmi_register_character_driver(&rmidev_driver);
if (error)
class_destroy(rmidev_device_class);
return error;
}
static void __exit rmidev_exit(void)
{
pr_debug("%s: exiting.\n", __func__);
rmi_unregister_character_driver(&rmidev_driver);
class_destroy(rmidev_device_class);
}
module_init(rmidev_init);
module_exit(rmidev_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_DESCRIPTION("RMI4 Char Device");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,405 @@
/*
* Copyright (c) 2011 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _RMI_DRIVER_H
#define _RMI_DRIVER_H
#define RMI_DRIVER_VERSION "1.3"
#define RMI_PRODUCT_ID_LENGTH 10
#define RMI_PRODUCT_INFO_LENGTH 2
#define RMI_DATE_CODE_LENGTH 3
#include <linux/ctype.h>
/* Sysfs related macros */
/* You must define FUNCTION_DATA and FNUM to use these functions. */
#define RMI4_SYSFS_DEBUG defined(CONFIG_RMI4_DEBUG) || defined(CONFIG_ANDROID))
#if defined(FNUM) && defined(FUNCTION_DATA)
#define tricat(x,y,z) tricat_(x,y,z)
#define tricat_(x,y,z) x##y##z
#define show_union_struct_prototype(propname)\
static ssize_t tricat(rmi_fn_,FNUM,_##propname##_show)(\
struct device *dev,\
struct device_attribute *attr,\
char *buf);\
\
DEVICE_ATTR(propname, RMI_RO_ATTR,\
tricat(rmi_fn_,FNUM,_##propname##_show),\
rmi_store_error);
#define store_union_struct_prototype(propname)\
static ssize_t tricat(rmi_fn_,FNUM,_##propname##_store)(\
struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count);\
\
DEVICE_ATTR(propname, RMI_WO_ATTR,\
rmi_show_error,\
tricat(rmi_fn_, FNUM, _##propname##_store));
#define show_store_union_struct_prototype(propname)\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\
struct device *dev,\
struct device_attribute *attr,\
char *buf);\
\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\
struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count);\
\
DEVICE_ATTR(propname, RMI_RW_ATTR,\
tricat(rmi_fn_, FNUM, _##propname##_show),\
tricat(rmi_fn_, FNUM, _##propname##_store));
#define simple_show_union_struct(regtype, propname, fmt)\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\
struct device_attribute *attr, char *buf) {\
struct rmi_function_container *fc;\
struct FUNCTION_DATA *data;\
\
fc = to_rmi_function_container(dev);\
data = fc->data;\
\
return snprintf(buf, PAGE_SIZE, fmt,\
data->regtype.propname);\
}
#define show_union_struct(regtype, reg_group, propname, fmt)\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(\
struct device *dev,\
struct device_attribute *attr,\
char *buf) {\
struct rmi_function_container *fc;\
struct FUNCTION_DATA *data;\
int result;\
\
fc = to_rmi_function_container(dev);\
data = fc->data;\
\
mutex_lock(&data->regtype##_mutex);\
/* Read current regtype values */\
result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8 *)data->regtype.reg_group,\
sizeof(data->regtype.reg_group->regs));\
mutex_unlock(&data->regtype##_mutex);\
if (result < 0) {\
dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\
__func__, data->regtype.reg_group->address);\
return result;\
}\
return snprintf(buf, PAGE_SIZE, fmt,\
data->regtype.reg_group->propname);\
}\
#define show_store_union_struct(regtype, reg_group, propname, fmt)\
show_union_struct(regtype, reg_group, propname, fmt)\
\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(\
struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count) {\
int result;\
unsigned long val;\
unsigned long old_val;\
struct rmi_function_container *fc;\
struct FUNCTION_DATA *data;\
\
fc = to_rmi_function_container(dev);\
data = fc->data;\
\
/* need to convert the string data to an actual value */\
result = strict_strtoul(buf, 10, &val);\
\
/* if an error occured, return it */\
if (result)\
return result;\
/* Check value maybe */\
\
/* Read current regtype values */\
mutex_lock(&data->regtype##_mutex);\
result =\
rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8 *)data->regtype.reg_group,\
sizeof(data->regtype.reg_group->regs));\
\
if (result < 0) {\
mutex_unlock(&data->regtype##_mutex);\
dev_dbg(dev, "%s : Could not read regtype at 0x%x\\n",\
__func__,\
data->regtype.reg_group->address);\
return result;\
}\
/* if the current regtype registers are already set as we want them,\
* do nothing to them */\
if (data->regtype.reg_group->propname == val) {\
mutex_unlock(&data->regtype##_mutex);\
return count;\
}\
/* Write the regtype back to the regtype register */\
old_val = data->regtype.reg_group->propname;\
data->regtype.reg_group->propname = val;\
result =\
rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8 *)data->regtype.reg_group,\
sizeof(data->regtype.reg_group->regs));\
if (result < 0) {\
dev_dbg(dev, "%s : Could not write regtype to 0x%x\\n",\
__func__,\
data->regtype.reg_group->address);\
/* revert change to local value if value not written */\
data->regtype.reg_group->propname = old_val;\
mutex_unlock(&data->regtype##_mutex);\
return result;\
}\
mutex_unlock(&data->regtype##_mutex);\
return count;\
}
#define show_repeated_union_struct(regtype, reg_group, propname, fmt)\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_show)(struct device *dev,\
struct device_attribute *attr,\
char *buf) {\
struct rmi_function_container *fc;\
struct FUNCTION_DATA *data;\
int reg_length;\
int result, size = 0;\
char *temp;\
int i;\
\
fc = to_rmi_function_container(dev);\
data = fc->data;\
mutex_lock(&data->regtype##_mutex);\
\
/* Read current regtype values */\
reg_length = data->regtype.reg_group->length;\
result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8*) data->regtype.reg_group->regs,\
reg_length * sizeof(u8));\
mutex_unlock(&data->regtype##_mutex);\
if (result < 0) {\
dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\
"Data may be outdated.", __func__,\
data->regtype.reg_group->address);\
}\
temp = buf;\
for (i = 0; i < reg_length; i++) {\
result = snprintf(temp, PAGE_SIZE - size, fmt " ",\
data->regtype.reg_group->regs[i].propname);\
if (result < 0) {\
dev_err(dev, "%s : Could not write output.", __func__);\
return result;\
}\
size += result;\
temp += result;\
}\
result = snprintf(temp, PAGE_SIZE - size, "\n");\
if (result < 0) {\
dev_err(dev, "%s : Could not write output.", __func__);\
return result;\
}\
return size + result;\
}
#define show_store_repeated_union_struct(regtype, reg_group, propname, fmt)\
show_repeated_union_struct(regtype, reg_group, propname, fmt)\
\
static ssize_t tricat(rmi_fn_, FNUM, _##propname##_store)(struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count) {\
struct rmi_function_container *fc;\
struct FUNCTION_DATA *data;\
int reg_length;\
int result;\
const char *temp;\
int i;\
unsigned int newval;\
\
fc = to_rmi_function_container(dev);\
data = fc->data;\
mutex_lock(&data->regtype##_mutex);\
\
/* Read current regtype values */\
\
reg_length = data->regtype.reg_group->length;\
result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8*) data->regtype.reg_group->regs,\
reg_length * sizeof(u8));\
\
if (result < 0) {\
dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\
"Data may be outdated.", __func__,\
data->regtype.reg_group->address);\
}\
/* parse input */\
\
temp = buf;\
for (i = 0; i < reg_length; i++) {\
if(sscanf(temp, fmt, &newval) == 1) {\
data->regtype.reg_group->regs[i].propname = newval;\
} else {\
/* If we don't read a value for each position, abort, restore
* previous values locally by rereading */\
result = rmi_read_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8*) data->regtype.reg_group->regs,\
reg_length * sizeof(u8));\
\
if (result < 0) {\
dev_dbg(dev, "%s : Could not read regtype at 0x%x\n"\
"Local data may be innacurrate.", __func__,\
data->regtype.reg_group->address);\
}\
return -EINVAL;\
}\
/* move to next number */\
while (*temp != 0) {\
temp++;\
if (isspace(*(temp - 1)) && !isspace(*temp))\
break;\
}\
}\
result = rmi_write_block(fc->rmi_dev, data->regtype.reg_group->address,\
(u8*) data->regtype.reg_group->regs,\
reg_length * sizeof(u8));\
mutex_unlock(&data->regtype##_mutex);\
if (result < 0) {\
dev_dbg(dev, "%s : Could not write new values"\
" to 0x%x\n", __func__, data->regtype.reg_group->address);\
return result;\
}\
return count;\
}
/* Create templates for given types */
#define simple_show_union_struct_unsigned(regtype, propname)\
simple_show_union_struct(regtype, propname, "%u\n")
#define show_union_struct_unsigned(regtype, reg_group, propname)\
show_union_struct(regtype, reg_group, propname, "%u\n")
#define show_store_union_struct_unsigned(regtype, reg_group, propname)\
show_store_union_struct(regtype, reg_group, propname, "%u\n")
#define show_repeated_union_struct_unsigned(regtype, reg_group, propname)\
show_repeated_union_struct(regtype, reg_group, propname, "%u")
#define show_store_repeated_union_struct_unsigned(regtype, reg_group, propname)\
show_store_repeated_union_struct(regtype, reg_group, propname, "%u")
/* Remove access to raw format string versions */
/*#undef simple_show_union_struct
#undef show_union_struct_unsigned
#undef show_store_union_struct
#undef show_repeated_union_struct
#undef show_store_repeated_union_struct*/
#endif
#define GROUP(_attrs) { \
.attrs = _attrs, \
}
#define attrify(nm) &dev_attr_##nm.attr
union f01_device_status {
struct {
u8 status_code:4;
u8 reserved:2;
u8 flash_prog:1;
u8 unconfigured:1;
};
u8 reg;
};
struct rmi_driver_data {
struct rmi_function_container rmi_functions;
struct rmi_function_container *f01_container;
bool f01_bootloader_mode;
int num_of_irq_regs;
int irq_count;
u8 *current_irq_mask;
u8 *irq_mask_store;
bool irq_stored;
struct mutex irq_mutex;
struct mutex pdt_mutex;
unsigned char pdt_props;
unsigned char bsr;
bool enabled;
#ifdef CONFIG_PM
bool suspended;
struct mutex suspend_mutex;
void *pm_data;
int (*pre_suspend) (const void *pm_data);
int (*post_resume) (const void *pm_data);
#endif
#ifdef CONFIG_RMI4_DEBUG
#ifdef CONFIG_RMI4_SPI
struct dentry *debugfs_delay;
#endif
struct dentry *debugfs_phys;
struct dentry *debugfs_reg_ctl;
struct dentry *debugfs_reg;
u16 reg_debug_addr;
u8 reg_debug_size;
#endif
void *data;
};
struct pdt_entry {
u8 query_base_addr:8;
u8 command_base_addr:8;
u8 control_base_addr:8;
u8 data_base_addr:8;
u8 interrupt_source_count:3;
u8 bits3and4:2;
u8 function_version:2;
u8 bit7:1;
u8 function_number:8;
};
int rmi_driver_f01_init(struct rmi_device *rmi_dev);
static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
struct rmi_function_descriptor *fd,
u16 page_start)
{
fd->query_base_addr = pdt->query_base_addr + page_start;
fd->command_base_addr = pdt->command_base_addr + page_start;
fd->control_base_addr = pdt->control_base_addr + page_start;
fd->data_base_addr = pdt->data_base_addr + page_start;
fd->function_number = pdt->function_number;
fd->interrupt_source_count = pdt->interrupt_source_count;
fd->function_version = pdt->function_version;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,771 @@
/*
* Copyright (c) 2011 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/input.h>
#include <linux/slab.h>
#include "rmi_driver.h"
#define QUERY_BASE_INDEX 1
/* data specific to fn $09 that needs to be kept around */
struct f09_query {
u8 limit_register_count;
union {
struct {
u8 result_register_count:3;
u8 reserved:3;
u8 internal_limits:1;
u8 host_test_enable:1;
};
u8 f09_bist_query1;
};
};
struct f09_control {
union {
struct {
u8 test1_limit_low:8;
u8 test1_limit_high:8;
u8 test1_limit_diff:8;
};
u8 f09_control_test1[3];
};
union {
struct {
u8 test2_limit_low:8;
u8 test2_limit_high:8;
u8 test2_limit_diff:8;
};
u8 f09_control_test2[3];
};
};
struct f09_data {
u8 test_number_control;
u8 overall_bist_result;
u8 test_result1;
u8 test_result2;
u8 transmitter_number;
union {
struct {
u8 receiver_number:6;
u8 limit_failure_code:2;
};
u8 f09_bist_data2;
};
};
struct f09_cmd {
union {
struct {
u8 run_bist:1;
};
u8 f09_bist_cmd0;
};
};
struct rmi_fn_09_data {
struct f09_query query;
struct f09_data data;
struct f09_cmd cmd;
struct f09_control control;
signed char status;
};
static ssize_t rmi_f09_status_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_f09_limit_register_count_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_host_test_enable_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_host_test_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_f09_internal_limits_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_result_register_count_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_overall_bist_result_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_test_number_control_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_test_number_control_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_f09_run_bist_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_run_bist_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_f09_test_result1_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_test_result2_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_control_test1_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_control_test1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_f09_control_test2_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_f09_control_test2_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static int rmi_f09_alloc_memory(struct rmi_function_container *fc);
static void rmi_f09_free_memory(struct rmi_function_container *fc);
static int rmi_f09_initialize(struct rmi_function_container *fc);
static int rmi_f09_config(struct rmi_function_container *fc);
static int rmi_f09_reset(struct rmi_function_container *fc);
static int rmi_f09_create_sysfs(struct rmi_function_container *fc);
static struct device_attribute attrs[] = {
__ATTR(status, RMI_RW_ATTR,
rmi_f09_status_show, rmi_f09_status_store),
__ATTR(limitRegisterCount, RMI_RO_ATTR,
rmi_f09_limit_register_count_show, rmi_store_error),
__ATTR(hostTestEnable, RMI_RW_ATTR,
rmi_f09_host_test_enable_show, rmi_f09_host_test_enable_store),
__ATTR(internalLimits, RMI_RO_ATTR,
rmi_f09_internal_limits_show, rmi_store_error),
__ATTR(resultRegisterCount, RMI_RO_ATTR,
rmi_f09_result_register_count_show, rmi_store_error),
__ATTR(overall_bist_result, RMI_RO_ATTR,
rmi_f09_overall_bist_result_show, rmi_store_error),
__ATTR(test_number_control, RMI_RW_ATTR,
rmi_f09_test_number_control_show,
rmi_f09_test_number_control_store),
__ATTR(test_result1, RMI_RO_ATTR,
rmi_f09_test_result1_show, rmi_store_error),
__ATTR(test_result2, RMI_RO_ATTR,
rmi_f09_test_result2_show, rmi_store_error),
__ATTR(run_bist, RMI_RW_ATTR,
rmi_f09_run_bist_show, rmi_f09_run_bist_store),
__ATTR(f09_control_test1, RMI_RW_ATTR,
rmi_f09_control_test1_show, rmi_f09_control_test1_store),
__ATTR(f09_control_test2, RMI_RW_ATTR,
rmi_f09_control_test2_show, rmi_f09_control_test2_store),
};
static int rmi_f09_init(struct rmi_function_container *fc)
{
int rc;
dev_info(&fc->dev, "Intializing F09 values.");
rc = rmi_f09_alloc_memory(fc);
if (rc < 0)
goto error_exit;
rc = rmi_f09_initialize(fc);
if (rc < 0)
goto error_exit;
rc = rmi_f09_create_sysfs(fc);
if (rc < 0)
goto error_exit;
return 0;
error_exit:
rmi_f09_free_memory(fc);
return rc;
}
static int rmi_f09_alloc_memory(struct rmi_function_container *fc)
{
struct rmi_fn_09_data *f09;
f09 = kzalloc(sizeof(struct rmi_fn_09_data), GFP_KERNEL);
if (!f09) {
dev_err(&fc->dev, "Failed to allocate rmi_fn_09_data.\n");
return -ENOMEM;
}
fc->data = f09;
return 0;
}
static void rmi_f09_free_memory(struct rmi_function_container *fc)
{
kfree(fc->data);
fc->data = NULL;
}
static int rmi_f09_initialize(struct rmi_function_container *fc)
{
struct rmi_device *rmi_dev = fc->rmi_dev;
struct rmi_device_platform_data *pdata;
struct rmi_fn_09_data *f09 = fc->data;
u8 query_base_addr;
int rc;
pdata = to_rmi_platform_data(rmi_dev);
query_base_addr = fc->fd.query_base_addr;
/* initial all default values for f09 query here */
rc = rmi_read_block(rmi_dev, query_base_addr,
(u8 *)&f09->query, sizeof(f09->query));
if (rc < 0) {
dev_err(&fc->dev, "Failed to read query register."
" from 0x%04x\n", query_base_addr);
return rc;
}
return 0;
}
static int rmi_f09_create_sysfs(struct rmi_function_container *fc)
{
int attr_count = 0;
int rc;
dev_dbg(&fc->dev, "Creating sysfs files.");
/* Set up sysfs device attributes. */
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
if (sysfs_create_file
(&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
dev_err(&fc->dev, "Failed to create sysfs file for %s.",
attrs[attr_count].attr.name);
rc = -ENODEV;
goto err_remove_sysfs;
}
}
return 0;
err_remove_sysfs:
for (attr_count--; attr_count >= 0; attr_count--)
sysfs_remove_file(&fc->dev.kobj,
&attrs[attr_count].attr);
return rc;
}
static int rmi_f09_config(struct rmi_function_container *fc)
{
/*we do nothing here. instead reset should notify the user.*/
return 0;
}
static int rmi_f09_reset(struct rmi_function_container *fc)
{
struct rmi_fn_09_data *instance_data = fc->data;
instance_data->status = -ECONNRESET;
return 0;
}
static void rmi_f09_remove(struct rmi_function_container *fc)
{
int attr_count;
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
sysfs_remove_file(&fc->dev.kobj,
&attrs[attr_count].attr);
rmi_f09_free_memory(fc);
}
static int rmi_f09_attention(struct rmi_function_container *fc, u8 *irq_bits)
{
struct rmi_device *rmi_dev = fc->rmi_dev;
struct rmi_fn_09_data *data = fc->data;
int error;
error = rmi_read_block(rmi_dev, fc->fd.command_base_addr,
(u8 *)&data->cmd, sizeof(data->cmd));
if (error < 0) {
dev_err(&fc->dev, "Failed to read command register.\n");
return error;
}
/* If the command register is cleared, meaning the value is 0 */
if (data->status == ECONNRESET) {
dev_warn(&rmi_dev->dev, "RESET occured: %#04x.\n",
data->status);
} else if (data->cmd.run_bist) {
dev_warn(&rmi_dev->dev,
"Command register not cleared: %#04x.\n",
data->cmd.run_bist);
}
return 0;
}
static struct rmi_function_handler function_handler = {
.func = 0x09,
.init = rmi_f09_init,
.attention = rmi_f09_attention,
.config = rmi_f09_config,
.reset = rmi_f09_reset,
.remove = rmi_f09_remove
};
static int __init rmi_f09_module_init(void)
{
int error;
error = rmi_register_function_driver(&function_handler);
if (error < 0) {
pr_err("%s: register failed!\n", __func__);
return error;
}
return 0;
}
static void rmi_f09_module_exit(void)
{
rmi_unregister_function_driver(&function_handler);
}
static ssize_t rmi_f09_status_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%d\n", instance_data->status);
}
static ssize_t rmi_f09_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
/* any write to status resets 1 */
instance_data->status = 0;
return 0;
}
static ssize_t rmi_f09_limit_register_count_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.limit_register_count);
}
static ssize_t rmi_f09_host_test_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.host_test_enable);
}
static ssize_t rmi_f09_host_test_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
unsigned int new_value;
int result;
fc = to_rmi_function_container(dev);
data = fc->data;
if (sscanf(buf, "%u", &new_value) != 1) {
dev_err(dev,
"%s: Error - hostTestEnable has an invalid length.\n",
__func__);
return -EINVAL;
}
if (new_value < 0 || new_value > 1) {
dev_err(dev, "%s: Invalid hostTestEnable bit %s.",
__func__, buf);
return -EINVAL;
}
data->query.host_test_enable = new_value;
result = rmi_write(fc->rmi_dev, fc->fd.query_base_addr,
data->query.host_test_enable);
if (result < 0) {
dev_err(dev, "%s: Could not write hostTestEnable to 0x%x\n",
__func__, fc->fd.query_base_addr);
return result;
}
return count;
}
static ssize_t rmi_f09_internal_limits_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.internal_limits);
}
static ssize_t rmi_f09_result_register_count_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->query.result_register_count);
}
static ssize_t rmi_f09_overall_bist_result_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->data.overall_bist_result);
}
static ssize_t rmi_f09_test_result1_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->data.test_result1);
}
static ssize_t rmi_f09_test_result2_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->data.test_result2);
}
static ssize_t rmi_f09_run_bist_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->cmd.run_bist);
}
static ssize_t rmi_f09_run_bist_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
unsigned int new_value;
int result;
fc = to_rmi_function_container(dev);
data = fc->data;
if (sscanf(buf, "%u", &new_value) != 1) {
dev_err(dev,
"%s: Error - run_bist_store has an "
"invalid len.\n",
__func__);
return -EINVAL;
}
if (new_value < 0 || new_value > 1) {
dev_err(dev, "%s: Invalid run_bist bit %s.", __func__, buf);
return -EINVAL;
}
data->cmd.run_bist = new_value;
result = rmi_write(fc->rmi_dev, fc->fd.command_base_addr,
data->cmd.run_bist);
if (result < 0) {
dev_err(dev, "%s : Could not write run_bist_store to 0x%x\n",
__func__, fc->fd.command_base_addr);
return result;
}
return count;
}
static ssize_t rmi_f09_control_test1_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u %u %u\n",
data->control.test1_limit_low,
data->control.test1_limit_high,
data->control.test1_limit_diff);
}
static ssize_t rmi_f09_control_test1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
unsigned int new_low, new_high, new_diff;
int result;
fc = to_rmi_function_container(dev);
data = fc->data;
if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) {
dev_err(dev,
"%s: Error - f09_control_test1_store has an "
"invalid len.\n",
__func__);
return -EINVAL;
}
if (new_low < 0 || new_low > 1 || new_high < 0 || new_high
|| new_diff < 0 || new_diff) {
dev_err(dev, "%s: Invalid f09_control_test1_diff bit %s.",
__func__, buf);
return -EINVAL;
}
data->control.test1_limit_low = new_low;
data->control.test1_limit_high = new_high;
data->control.test1_limit_diff = new_diff;
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test1_limit_low);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test1_limit_low to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test1_limit_high);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test1_limit_high to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test1_limit_diff);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test1_limit_diff to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
return count;
}
static ssize_t rmi_f09_control_test2_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u %u %u\n",
data->control.test2_limit_low,
data->control.test2_limit_high,
data->control.test2_limit_diff);
}
static ssize_t rmi_f09_control_test2_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
unsigned int new_low, new_high, new_diff;
int result;
fc = to_rmi_function_container(dev);
data = fc->data;
if (sscanf(buf, "%u %u %u", &new_low, &new_high, &new_diff) != 3) {
dev_err(dev,
"%s: Error - f09_control_test1_store has an "
"invalid len.\n",
__func__);
return -EINVAL;
}
if (new_low < 0 || new_low > 1 || new_high < 0 || new_high > 1 ||
new_diff < 0 || new_diff > 1) {
dev_err(dev, "%s: Invalid f09_control_test2_diff bit %s.",
__func__, buf);
return -EINVAL;
}
data->control.test2_limit_low = new_low;
data->control.test2_limit_high = new_high;
data->control.test2_limit_diff = new_diff;
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test2_limit_low);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test2_limit_low to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test2_limit_high);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test2_limit_high to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->control.test2_limit_diff);
if (result < 0) {
dev_err(dev, "%s : Could not write f09_control_test2_limit_diff to 0x%x\n",
__func__, fc->fd.control_base_addr);
return result;
}
return count;
}
static ssize_t rmi_f09_test_number_control_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
fc = to_rmi_function_container(dev);
data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
data->data.test_number_control);
}
static ssize_t rmi_f09_test_number_control_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_09_data *data;
unsigned int new_value;
int result;
fc = to_rmi_function_container(dev);
data = fc->data;
if (sscanf(buf, "%u", &new_value) != 1) {
dev_err(dev,
"%s: Error - test_number_control_store has an "
"invalid len.\n",
__func__);
return -EINVAL;
}
if (new_value < 0 || new_value > 1) {
dev_err(dev, "%s: Invalid test_number_control bit %s.",
__func__, buf);
return -EINVAL;
}
data->data.test_number_control = new_value;
result = rmi_write(fc->rmi_dev, fc->fd.control_base_addr,
data->data.test_number_control);
if (result < 0) {
dev_err(dev, "%s : Could not write "
"test_number_control_store to 0x%x\n",
__func__, fc->fd.data_base_addr);
return result;
}
return count;
}
module_init(rmi_f09_module_init);
module_exit(rmi_f09_module_exit);
MODULE_AUTHOR("Allie Xiong <axiong@Synaptics.com>");
MODULE_DESCRIPTION("RMI F09 module");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,731 @@
/*
* Copyright (c) 2012 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/input.h>
#include <linux/slab.h>
#include "rmi_driver.h"
#define QUERY_BASE_INDEX 1
#define MAX_NAME_LENGTH 256
union f17_device_query {
struct {
u8 number_of_sticks:3;
};
u8 regs[1];
};
#define F17_MANUFACTURER_SYNAPTICS 0
#define F17_MANUFACTURER_NMB 1
#define F17_MANUFACTURER_ALPS 2
struct f17_stick_query {
union {
struct {
u8 manufacturer:4;
u8 resistive:1;
u8 ballistics:1;
u8 reserved1:2;
u8 has_relative:1;
u8 has_absolute:1;
u8 has_gestures:1;
u8 has_dribble:1;
u8 reserved2:4;
};
u8 regs[2];
} general;
union {
struct {
u8 has_single_tap:1;
u8 has_tap_and_hold:1;
u8 has_double_tap:1;
u8 has_early_tap:1;
u8 has_press:1;
};
u8 regs[1];
} gestures;
};
union f17_device_controls {
struct {
u8 reporting_mode:3;
u8 dribble:1;
};
u8 regs[1];
};
struct f17_stick_controls {
union {
struct {
u8 z_force_threshold;
u8 radial_force_threshold;
};
u8 regs[3];
} general;
union {
struct {
u8 motion_sensitivity:4;
u8 antijitter:1;
};
u8 regs[1];
} relative;
union {
struct {
u8 single_tap:1;
u8 tap_and_hold:1;
u8 double_tap:1;
u8 early_tap:1;
u8 press:1;
};
u8 regs[1];
} enable;
u8 maximum_tap_time;
u8 minimum_press_time;
u8 maximum_radial_force;
};
union f17_device_commands {
struct {
u8 rezero:1;
};
u8 regs[1];
};
struct f17_stick_data {
union {
struct {
u8 x_force_high;
u8 y_force_high;
u8 y_force_low:4;
u8 x_force_low:4;
u8 z_force;
};
u8 regs[4];
} abs;
union {
struct {
s8 x_delta;
s8 y_delta;
};
u8 regs[2];
} rel;
union {
struct {
u8 single_tap:1;
u8 tap_and_hold:1;
u8 double_tap:1;
u8 early_tap:1;
u8 press:1;
};
u8 regs[1];
} gestures;
};
/* data specific to f17 that needs to be kept around */
struct rmi_f17_stick_data {
struct f17_stick_query query;
struct f17_stick_controls controls;
struct f17_stick_data data;
u16 abs_data_address;
u16 rel_data_address;
u16 gesture_data_address;
u16 control_address;
int index;
char input_name[MAX_NAME_LENGTH];
char input_phys[MAX_NAME_LENGTH];
struct input_dev *input;
char mouse_name[MAX_NAME_LENGTH];
char mouse_phys[MAX_NAME_LENGTH];
struct input_dev *mouse;
};
struct rmi_f17_device_data {
u16 control_address;
union f17_device_query query;
union f17_device_commands commands;
union f17_device_controls controls;
struct rmi_f17_stick_data *sticks;
};
static ssize_t f17_rezero_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t f17_rezero_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static int f17_alloc_memory(struct rmi_function_container *fc);
static void f17_free_memory(struct rmi_function_container *fc);
static int f17_initialize(struct rmi_function_container *fc);
static int f17_register_devices(struct rmi_function_container *fc);
static int f17_create_sysfs(struct rmi_function_container *fc);
static int f17_config(struct rmi_function_container *fc);
static int f17_reset(struct rmi_function_container *fc);
static struct device_attribute attrs[] = {
__ATTR(rezero, RMI_RW_ATTR,
f17_rezero_show, f17_rezero_store),
};
int f17_read_control_parameters(struct rmi_device *rmi_dev,
struct rmi_f17_device_data *f17)
{
int retval = 0;
// TODO: read this or delete the function
return retval;
}
static int f17_init(struct rmi_function_container *fc)
{
int retval;
retval = f17_alloc_memory(fc);
if (retval < 0)
goto err_free_data;
retval = f17_initialize(fc);
if (retval < 0)
goto err_free_data;
retval = f17_register_devices(fc);
if (retval < 0)
goto err_free_data;
retval = f17_create_sysfs(fc);
if (retval < 0)
goto err_free_data;
return 0;
err_free_data:
f17_free_memory(fc);
return retval;
}
static int f17_alloc_memory(struct rmi_function_container *fc)
{
struct rmi_f17_device_data *f17;
int retval;
int i;
f17 = kzalloc(sizeof(struct rmi_f17_device_data), GFP_KERNEL);
if (!f17) {
dev_err(&fc->dev, "Failed to allocate function data.\n");
return -ENOMEM;
}
fc->data = f17;
retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr,
f17->query.regs, sizeof(f17->query.regs));
if (retval < 0) {
dev_err(&fc->dev, "Failed to read query register.\n");
goto error_exit;
}
dev_info(&fc->dev, "Found F17 with %d sticks.\n",
f17->query.number_of_sticks + 1);
f17->sticks = kcalloc(f17->query.number_of_sticks + 1,
sizeof(struct rmi_f17_stick_data), GFP_KERNEL);
if (!f17->sticks) {
dev_err(&fc->dev, "Failed to allocate per stick data.\n");
return -ENOMEM;
}
for (i = 0; i < f17->query.number_of_sticks + 1; i++) {
// TODO: allocate any per stick stuff (or remove this loop)
}
return 0;
error_exit:
kfree(f17);
fc->data = NULL;
return retval;
}
static void f17_free_memory(struct rmi_function_container *fc)
{
struct rmi_f17_device_data *f17 = fc->data;
int i;
if (f17) {
if (f17->sticks) {
for (i = 0; i < f17->query.number_of_sticks + 1; i++) {
// TODO: Free stick stuff
}
}
kfree(f17->sticks);
f17->sticks = NULL;
}
kfree(f17);
fc->data = NULL;
}
static int f17_init_stick(struct rmi_device *rmi_dev,
struct rmi_f17_stick_data *stick,
u16 *next_query_reg, u16 *next_data_reg,
u16 *next_control_reg) {
int retval = 0;
retval = rmi_read_block(rmi_dev, *next_query_reg,
stick->query.general.regs,
sizeof(stick->query.general.regs));
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to read stick general query.\n");
return retval;
}
*next_query_reg += sizeof(stick->query.general.regs);
dev_info(&rmi_dev->dev, "Stick %d found\n", stick->index);
dev_info(&rmi_dev->dev, " Manufacturer: %d.\n", stick->query.general.manufacturer);
dev_info(&rmi_dev->dev, " Resistive: %d.\n", stick->query.general.resistive);
dev_info(&rmi_dev->dev, " Ballistics: %d.\n", stick->query.general.ballistics);
dev_info(&rmi_dev->dev, " Manufacturer: %d.\n", stick->query.general.ballistics);
dev_info(&rmi_dev->dev, " Has relative: %d.\n", stick->query.general.has_relative);
dev_info(&rmi_dev->dev, " Has absolute: %d.\n", stick->query.general.has_absolute);
dev_info(&rmi_dev->dev, " Had dribble: %d.\n", stick->query.general.has_dribble);
dev_info(&rmi_dev->dev, " Has gestures: %d.\n", stick->query.general.has_gestures);
if (stick->query.general.has_gestures) {
retval = rmi_read_block(rmi_dev, *next_query_reg,
stick->query.gestures.regs,
sizeof(stick->query.gestures.regs));
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to read stick gestures query.\n");
return retval;
}
*next_query_reg += sizeof(stick->query.gestures.regs);
dev_info(&rmi_dev->dev, " single tap: %d.\n", stick->query.gestures.has_single_tap);
dev_info(&rmi_dev->dev, " tap & hold: %d.\n", stick->query.gestures.has_tap_and_hold);
dev_info(&rmi_dev->dev, " double tap: %d.\n", stick->query.gestures.has_double_tap);
dev_info(&rmi_dev->dev, " early tap: %d.\n", stick->query.gestures.has_early_tap);
dev_info(&rmi_dev->dev, " press: %d.\n", stick->query.gestures.has_press);
}
if (stick->query.general.has_absolute) {
stick->abs_data_address = *next_data_reg;
*next_data_reg += sizeof(stick->data.abs.regs);
}
if (stick->query.general.has_relative) {
stick->rel_data_address = *next_data_reg;
*next_data_reg += sizeof(stick->data.rel.regs);
}
if (stick->query.general.has_gestures) {
stick->gesture_data_address = *next_data_reg;
*next_data_reg += sizeof(stick->data.gestures.regs);
}
return retval;
}
static int f17_initialize(struct rmi_function_container *fc)
{
struct rmi_device *rmi_dev = fc->rmi_dev;
struct rmi_f17_device_data *f17 = fc->data;
int i;
int retval;
u16 next_query_reg = fc->fd.query_base_addr;
u16 next_data_reg = fc->fd.data_base_addr;
u16 next_control_reg = fc->fd.control_base_addr;
dev_info(&fc->dev, "Intializing F17 values.");
retval = rmi_read_block(fc->rmi_dev, fc->fd.query_base_addr,
f17->query.regs, sizeof(f17->query.regs));
if (retval < 0) {
dev_err(&fc->dev, "Failed to read query register.\n");
return retval;
}
dev_info(&fc->dev, "Found F17 with %d sticks.\n",
f17->query.number_of_sticks + 1);
next_query_reg += sizeof(f17->query.regs);
retval = rmi_read_block(rmi_dev, fc->fd.command_base_addr,
f17->commands.regs, sizeof(f17->commands.regs));
if (retval < 0) {
dev_err(&fc->dev, "Failed to read command register.\n");
return retval;
}
f17->control_address = fc->fd.control_base_addr;
retval = f17_read_control_parameters(rmi_dev, f17);
if (retval < 0) {
dev_err(&fc->dev, "Failed to initialize F17 control params.\n");
return retval;
}
for (i = 0; i < f17->query.number_of_sticks + 1; i++) {
f17->sticks[i].index = i;
retval = f17_init_stick(rmi_dev, &f17->sticks[i],
&next_query_reg, &next_data_reg,
&next_control_reg);
if (!retval) {
dev_err(&fc->dev, "Failed to init stick %d.\n", i);
return retval;
}
}
return retval;
}
static int f17_register_stick(struct rmi_function_container *fc,
struct rmi_f17_stick_data *stick) {
struct rmi_device *rmi_dev = fc->rmi_dev;
int retval = 0;
if (stick->query.general.has_absolute) {
struct input_dev *input_dev;
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&rmi_dev->dev, "Failed to allocate stick device %d.\n",
stick->index);
return -ENOMEM;
}
snprintf(stick->input_name, sizeof(stick->input_name),
"RMI F%02x Stick %d", 0x17, stick->index);
snprintf(stick->input_phys, sizeof(stick->input_phys),
"sensor00fn%02x/stick%d", 0x17, stick->index);
input_dev->name = stick->input_name;
input_dev->phys = stick->input_phys;
input_dev->dev.parent = &fc->dev;
input_set_drvdata(input_dev, stick);
retval = input_register_device(input_dev);
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to register stick device %d.\n",
stick->index);
goto error_free_device;
}
stick->input = input_dev;
}
if (stick->query.general.has_relative) {
struct input_dev *input_dev_mouse;
/*create input device for mouse events */
input_dev_mouse = input_allocate_device();
if (!input_dev_mouse) {
retval = -ENOMEM;
goto error_free_device;
}
snprintf(stick->mouse_name, sizeof(stick->mouse_name),
"RMI F%02x Mouse %d", 0x17, stick->index);
snprintf(stick->mouse_phys, sizeof(stick->mouse_name),
"sensor00fn%02x/mouse%d", 0x17, stick->index);
input_dev_mouse->name = stick->mouse_name;
input_dev_mouse->phys = stick->mouse_phys;
input_dev_mouse->dev.parent = &fc->dev;
input_dev_mouse->id.vendor = 0x18d1;
input_dev_mouse->id.product = 0x0210;
input_dev_mouse->id.version = 0x0100;
set_bit(EV_REL, input_dev_mouse->evbit);
set_bit(REL_X, input_dev_mouse->relbit);
set_bit(REL_Y, input_dev_mouse->relbit);
set_bit(BTN_MOUSE, input_dev_mouse->evbit);
/* Register device's buttons and keys */
set_bit(EV_KEY, input_dev_mouse->evbit);
set_bit(BTN_LEFT, input_dev_mouse->keybit);
set_bit(BTN_MIDDLE, input_dev_mouse->keybit);
set_bit(BTN_RIGHT, input_dev_mouse->keybit);
retval = input_register_device(input_dev_mouse);
if (retval < 0)
goto error_free_device;
stick->mouse = input_dev_mouse;
}
return 0;
error_free_device:
if (stick->input) {
input_free_device(stick->input);
stick->input = NULL;
}
if (stick->mouse) {
input_free_device(stick->mouse);
stick->mouse = NULL;
}
return retval;
}
static int f17_register_devices(struct rmi_function_container *fc)
{
struct rmi_f17_device_data *f17 = fc->data;
int i;
int retval = 0;
for (i = 0; i < f17->query.number_of_sticks + 1 && !retval; i++) {
retval = f17_register_stick(fc, &f17->sticks[i]);
}
return retval;
}
static int f17_create_sysfs(struct rmi_function_container *fc)
{
int attr_count = 0;
int rc;
dev_dbg(&fc->dev, "Creating sysfs files.\n");
/* Set up sysfs device attributes. */
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
if (sysfs_create_file
(&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
dev_err(&fc->dev,
"Failed to create sysfs file for %s.",
attrs[attr_count].attr.name);
rc = -ENODEV;
goto err_remove_sysfs;
}
}
return 0;
err_remove_sysfs:
for (attr_count--; attr_count >= 0; attr_count--)
sysfs_remove_file(&fc->dev.kobj, &attrs[attr_count].attr);
return rc;
}
static int f17_config(struct rmi_function_container *fc)
{
struct rmi_f17_device_data *f17 = fc->data;
int retval;
int i;
retval = rmi_write_block(fc->rmi_dev, f17->control_address,
f17->controls.regs, sizeof(f17->controls.regs));
if (retval < 0) {
dev_err(&fc->dev, "Could not write stick controls to 0x%04x\n",
f17->control_address);
return retval;
}
#if 0
if (f17->query.has_relative) {
retval = rmi_write_block(fc->rmi_dev,
f17->relative_control_address,
f17->controls.relative.regs,
sizeof(f17->controls.relative.regs));
if (retval < 0) {
dev_err(&fc->dev, "Could not write stick controls to 0x%04x\n",
f17->control_address);
return retval;
}
}
#endif
for (i = 0; i < f17->query.number_of_sticks + 1; i++) {
// TODO: Configure each styk
}
return retval;
}
static int f17_reset(struct rmi_function_container *fc)
{
/* we do nothing here */
return 0;
}
static void f17_remove(struct rmi_function_container *fc)
{
struct rmi_f17_device_data *f17 = fc->data;
int i = 0;
for (i = 0; i < ARRAY_SIZE(attrs); i++)
sysfs_remove_file(&fc->dev.kobj, &attrs[i].attr);
for (i = 0; i < f17->query.number_of_sticks + 1; i++) {
input_unregister_device(f17->sticks[i].input);
}
f17_free_memory(fc);
}
static int f17_process_stick(struct rmi_device *rmi_dev,
struct rmi_f17_stick_data *stick) {
int retval = 0;
if (stick->query.general.has_absolute) {
retval = rmi_read_block(rmi_dev, stick->abs_data_address,
stick->data.abs.regs, sizeof(stick->data.abs.regs));
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to read abs data for stick %d.\n",
stick->index);
goto error_exit;
}
}
if (stick->query.general.has_relative) {
retval = rmi_read_block(rmi_dev, stick->rel_data_address,
stick->data.rel.regs, sizeof(stick->data.rel.regs));
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to read rel data for stick %d.\n",
stick->index);
goto error_exit;
}
dev_info(&rmi_dev->dev, "Reporting dX: %d, dy: %d\n", stick->data.rel.x_delta, stick->data.rel.y_delta);
input_report_rel(stick->mouse, REL_X, stick->data.rel.x_delta);
input_report_rel(stick->mouse, REL_Y, stick->data.rel.y_delta);
}
if (stick->query.general.has_gestures) {
retval = rmi_read_block(rmi_dev, stick->gesture_data_address,
stick->data.gestures.regs, sizeof(stick->data.gestures.regs));
if (retval < 0) {
dev_err(&rmi_dev->dev, "Failed to read gesture data for stick %d.\n",
stick->index);
goto error_exit;
}
}
retval = 0;
error_exit:
if (stick->input)
input_sync(stick->input);
if (stick->mouse)
input_sync(stick->mouse);
return retval;
}
static int f17_attention(struct rmi_function_container *fc, u8 *irq_bits)
{
struct rmi_device *rmi_dev = fc->rmi_dev;
struct rmi_f17_device_data *f17 = fc->data;
int i;
int retval = 0;
for (i = 0; i < f17->query.number_of_sticks + 1 && !retval; i++) {
retval = f17_process_stick(rmi_dev, &f17->sticks[i]);
}
return retval;
}
static struct rmi_function_handler function_handler = {
.func = 0x17,
.init = f17_init,
.config = f17_config,
.reset = f17_reset,
.attention = f17_attention,
.remove = f17_remove
};
static int __init f17_module_init(void)
{
int error;
error = rmi_register_function_driver(&function_handler);
if (error < 0) {
pr_err("%s: register failed!\n", __func__);
return error;
}
return 0;
}
static void f17_module_exit(void)
{
rmi_unregister_function_driver(&function_handler);
}
static ssize_t f17_rezero_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_f17_device_data *f17;
fc = to_rmi_function_container(dev);
f17 = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
f17->commands.rezero);
}
static ssize_t f17_rezero_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct rmi_function_container *fc;
struct rmi_f17_device_data *data;
unsigned int new_value;
int len;
fc = to_rmi_function_container(dev);
data = fc->data;
len = sscanf(buf, "%u", &new_value);
if (new_value != 0 && new_value != 1) {
dev_err(dev,
"%s: Error - rezero is not a valid value 0x%x.\n",
__func__, new_value);
return -EINVAL;
}
data->commands.rezero = new_value;
len = rmi_write(fc->rmi_dev, fc->fd.command_base_addr,
data->commands.rezero);
if (len < 0) {
dev_err(dev, "%s : Could not write rezero to 0x%x\n",
__func__, fc->fd.command_base_addr);
return -EINVAL;
}
return count;
}
module_init(f17_module_init);
module_exit(f17_module_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_DESCRIPTION("RMI F17 module");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,751 @@
/*
* Copyright (c) 2012 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define FUNCTION_DATA rmi_fn_21_data
#define FNUM 21
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include "rmi_driver.h"
union f21_2df_query {
struct {
/* Query 0 */
u8 max_force_sensor_count:3;
u8 f21_2df_query0_b3__6:4;
u8 has_high_resolution:1;
};
struct {
u8 regs[1];
u16 address;
};
};
union f21_2df_control_0__3 {
struct {
/* Control 0 */
u8 reporting_mode:2;
u8 no_rezero:1;
u8 f21_2df_control0_b5__7:4;
/* Control 1 */
u8 force_click_threshold;
/* Control 2 */
u8 int_en_force_0:1;
u8 int_en_force_1:1;
u8 int_en_force_2:1;
u8 int_en_force_3:1;
u8 int_en_force_4:1;
u8 int_en_force_5:1;
u8 int_en_force_6:1;
u8 f21_ap_control2_b4__6:3;
u8 int_en_click:1;
/* Control 3 */
u8 force_interrupt_threshold;
};
struct {
u8 regs[4];
u16 address;
};
};
struct f21_2df_control_4n {
/*Control 4.* */
u8 one_newton_calibration:7;
u8 use_cfg_cal:1;
};
struct f21_2df_control_4{
struct f21_2df_control_4n *regs;
u16 address;
u8 length;
};
struct f21_2df_control_5n {
/*Control 5.* */
u8 x_location;
};
struct f21_2df_control_5{
struct f21_2df_control_5n *regs;
u16 address;
u8 length;
};
struct f21_2df_control_6n {
/*Control 6.* */
u8 y_location;
};
struct f21_2df_control_6{
struct f21_2df_control_6n *regs;
u16 address;
u8 length;
};
struct f21_2df_control_7n {
/*Control 7.* */
u8 transmitter_force_sensor;
};
struct f21_2df_control_7{
struct f21_2df_control_7n *regs;
u16 address;
u8 length;
};
struct f21_2df_control_8n {
/*Control 8.* */
u8 receiver_force_sensor;
};
struct f21_2df_control_8{
struct f21_2df_control_8n *regs;
u16 address;
u8 length;
};
#define RMI_F21_NUM_CTRL_REGS 8
struct f21_2df_control {
/* Control 0-3 */
union f21_2df_control_0__3 *reg_0__3;
/* Control 4 */
struct f21_2df_control_4 *reg_4;
/* Control 5 */
struct f21_2df_control_5 *reg_5;
/* Control 6 */
struct f21_2df_control_6 *reg_6;
/* Control 7 */
struct f21_2df_control_7 *reg_7;
/* Control 8 */
struct f21_2df_control_8 *reg_8;
};
union f21_2df_data_2 {
struct {
/* Data 2 */
u8 force_click:1;
u8 f21_2df_control0_b2__7:7;
};
struct {
u8 regs[1];
u16 address;
};
};
struct f21_2df_data {
/* Data 0 */
struct {
u8 *force_hi_lo;
u16 address;
} reg_0__1;
/* Data 2 */
union f21_2df_data_2 *reg_2;
};
#define F21_REZERO_CMD 0x01
/* data specific to fn $21 that needs to be kept around */
struct rmi_fn_21_data {
union f21_2df_query query;
struct f21_2df_control control;
struct f21_2df_data data;
struct mutex control_mutex;
struct mutex data_mutex;
};
static int rmi_f21_alloc_memory(struct rmi_function_container *fc);
static void rmi_f21_free_memory(struct rmi_function_container *fc);
static int rmi_f21_initialize(struct rmi_function_container *fc);
static int rmi_f21_config(struct rmi_function_container *fc);
static int rmi_f21_create_sysfs(struct rmi_function_container *fc);
/* Sysfs files */
/* Query sysfs files */
show_union_struct_prototype(max_force_sensor_count)
show_union_struct_prototype(has_high_resolution)
static struct attribute *attrs[] = {
attrify(max_force_sensor_count),
attrify(has_high_resolution),
NULL
};
static struct attribute_group attrs_query = GROUP(attrs);
/* Control sysfs files */
show_store_union_struct_prototype(reporting_mode)
show_store_union_struct_prototype(no_rezero)
show_store_union_struct_prototype(force_click_threshold)
show_store_union_struct_prototype(int_en_force_0)
show_store_union_struct_prototype(int_en_force_1)
show_store_union_struct_prototype(int_en_force_2)
show_store_union_struct_prototype(int_en_force_3)
show_store_union_struct_prototype(int_en_force_4)
show_store_union_struct_prototype(int_en_force_5)
show_store_union_struct_prototype(int_en_force_6)
show_store_union_struct_prototype(int_en_click)
show_store_union_struct_prototype(force_interrupt_threshold)
show_store_union_struct_prototype(use_cfg_cal)
show_store_union_struct_prototype(one_newton_calibration)
show_store_union_struct_prototype(x_location)
show_store_union_struct_prototype(y_location)
show_store_union_struct_prototype(transmitter_force_sensor)
show_store_union_struct_prototype(receiver_force_sensor)
static struct attribute *attrs2[] = {
attrify(reporting_mode),
attrify(no_rezero),
attrify(force_click_threshold),
attrify(int_en_click),
attrify(force_interrupt_threshold),
attrify(use_cfg_cal),
attrify(one_newton_calibration),
attrify(x_location),
attrify(y_location),
attrify(transmitter_force_sensor),
attrify(receiver_force_sensor),
NULL
};
static struct attribute_group attrs_control = GROUP(attrs2);
/* Data sysfs files */
show_union_struct_prototype(force)
show_union_struct_prototype(force_click)
static struct attribute *attrs3[] = {
attrify(force),
attrify(force_click),
NULL
};
static struct attribute_group attrs_data = GROUP(attrs3);
/* Command sysfs files */
static ssize_t rmi_fn_21_rezero_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(rezero, RMI_WO_ATTR,
rmi_show_error,
rmi_fn_21_rezero_store);
static struct attribute *attrs4[] = {
attrify(rezero),
NULL
};
static struct attribute_group attrs_command = GROUP(attrs4);
static int rmi_f21_init(struct rmi_function_container *fc)
{
int retval = 0;
dev_info(&fc->dev, "Intializing F21.");
retval = rmi_f21_alloc_memory(fc);
if (retval < 0)
goto error_exit;
retval = rmi_f21_initialize(fc);
if (retval < 0)
goto error_exit;
retval = rmi_f21_create_sysfs(fc);
if (retval < 0)
goto error_exit;
return retval;
error_exit:
rmi_f21_free_memory(fc);
return retval;
}
static int rmi_f21_alloc_memory(struct rmi_function_container *fc)
{
struct rmi_fn_21_data *f21;
f21 = kzalloc(sizeof(struct rmi_fn_21_data), GFP_KERNEL);
if (!f21) {
dev_err(&fc->dev, "Failed to allocate rmi_fn_21_data.\n");
return -ENOMEM;
}
fc->data = f21;
return 0;
}
static void rmi_f21_free_memory(struct rmi_function_container *fc)
{
struct rmi_fn_21_data *f21 = fc->data;
u8 int_num = f21->query.max_force_sensor_count;
sysfs_remove_group(&fc->dev.kobj, &attrs_query);
sysfs_remove_group(&fc->dev.kobj, &attrs_control);
switch(int_num) {
case 7:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_6));
case 6:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_5));
case 5:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_4));
case 4:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_3));
case 3:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_2));
case 2:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_1));
case 1:
sysfs_remove_file(&fc->dev.kobj, attrify(int_en_force_0));
default:
break;
}
sysfs_remove_group(&fc->dev.kobj, &attrs_data);
sysfs_remove_group(&fc->dev.kobj, &attrs_command);
if (f21) {
kfree(f21->control.reg_0__3);
kfree(f21->control.reg_4->regs);
kfree(f21->control.reg_4);
kfree(f21->control.reg_5->regs);
kfree(f21->control.reg_5);
kfree(f21->control.reg_6->regs);
kfree(f21->control.reg_6);
kfree(f21->control.reg_7->regs);
kfree(f21->control.reg_7);
kfree(f21->control.reg_8->regs);
kfree(f21->control.reg_8);
kfree(f21);
fc->data = NULL;
}
}
static int rmi_f21_initialize(struct rmi_function_container *fc)
{
struct rmi_fn_21_data *instance_data = fc->data;
int retval = 0;
u16 next_loc;
/* Read F21 Query Data */
instance_data->query.address = fc->fd.query_base_addr;
retval = rmi_read_block(fc->rmi_dev, instance_data->query.address,
(u8 *)&instance_data->query, sizeof(instance_data->query.regs));
if (retval < 0) {
dev_err(&fc->dev, "Could not read query registers from 0x%04x\n", instance_data->query.address);
return retval;
}
/* Initialize Control Data */
next_loc = fc->fd.control_base_addr;
instance_data->control.reg_0__3 =
kzalloc(sizeof(union f21_2df_control_0__3), GFP_KERNEL);
if (!instance_data->control.reg_0__3) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_0__3->address = next_loc;
next_loc += sizeof(instance_data->control.reg_0__3->regs);
instance_data->control.reg_4 =
kzalloc(sizeof(struct f21_2df_control_4), GFP_KERNEL);
if (!instance_data->control.reg_4) {
dev_err(&fc->dev, "Failed to allocate control register.");
return -ENOMEM;
}
instance_data->control.reg_4->length = instance_data->query.max_force_sensor_count;
instance_data->control.reg_4->regs =
kzalloc(sizeof(struct f21_2df_control_4n)
* instance_data->control.reg_4->length, GFP_KERNEL);
if (!instance_data->control.reg_4->regs) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_4->address = next_loc;
next_loc += instance_data->control.reg_4->length;
instance_data->control.reg_5 =
kzalloc(sizeof(struct f21_2df_control_5), GFP_KERNEL);
if (!instance_data->control.reg_5) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_5->length = instance_data->query.max_force_sensor_count;
instance_data->control.reg_5->regs =
kzalloc(sizeof(struct f21_2df_control_5n)
* instance_data->control.reg_5->length, GFP_KERNEL);
if (!instance_data->control.reg_5->regs) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_5->address = next_loc;
next_loc += instance_data->control.reg_5->length;
instance_data->control.reg_6 =
kzalloc(sizeof(struct f21_2df_control_6), GFP_KERNEL);
if (!instance_data->control.reg_6) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_6->length = instance_data->query.max_force_sensor_count;
instance_data->control.reg_6->regs =
kzalloc(sizeof(struct f21_2df_control_6n)
* instance_data->control.reg_6->length, GFP_KERNEL);
if (!instance_data->control.reg_6->regs) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_6->address = next_loc;
next_loc += instance_data->control.reg_6->length;
instance_data->control.reg_7 =
kzalloc(sizeof(struct f21_2df_control_7), GFP_KERNEL);
if (!instance_data->control.reg_7) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_7->length = instance_data->query.max_force_sensor_count;
instance_data->control.reg_7->regs =
kzalloc(sizeof(struct f21_2df_control_7n)
* instance_data->control.reg_7->length, GFP_KERNEL);
if (!instance_data->control.reg_7->regs) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_7->address = next_loc;
next_loc += instance_data->control.reg_7->length;
instance_data->control.reg_8 =
kzalloc(sizeof(struct f21_2df_control_8), GFP_KERNEL);
if (!instance_data->control.reg_8) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_8->length = instance_data->query.max_force_sensor_count;
instance_data->control.reg_8->regs =
kzalloc(sizeof(struct f21_2df_control_8n)
* instance_data->control.reg_8->length, GFP_KERNEL);
if (!instance_data->control.reg_8->regs) {
dev_err(&fc->dev, "Failed to allocate control registers.");
return -ENOMEM;
}
instance_data->control.reg_8->address = next_loc;
/* initialize data registers */
next_loc = fc->fd.data_base_addr;
instance_data->data.reg_0__1.force_hi_lo = kzalloc(
2 * instance_data->query.max_force_sensor_count * sizeof(u8),
GFP_KERNEL);
if (!instance_data->data.reg_0__1.force_hi_lo) {
dev_err(&fc->dev, "Failed to allocate data registers.");
return -ENOMEM;
}
instance_data->data.reg_0__1.address = next_loc;
next_loc += 2 * instance_data->query.max_force_sensor_count;
instance_data->data.reg_2 =
kzalloc(sizeof(union f21_2df_data_2), GFP_KERNEL);
if (!instance_data->data.reg_2) {
dev_err(&fc->dev, "Failed to allocate data registers.");
return -ENOMEM;
}
instance_data->control.reg_0__3->address = next_loc;
mutex_init(&instance_data->control_mutex);
return 0;
}
static int rmi_f21_create_sysfs(struct rmi_function_container *fc)
{
struct rmi_fn_21_data *instance_data = fc->data;
u8 int_num = instance_data->query.max_force_sensor_count;
if (int_num > 7)
int_num = 7;
dev_dbg(&fc->dev, "Creating sysfs files.");
/* Set up sysfs device attributes. */
if (sysfs_create_group(&fc->dev.kobj, &attrs_query) < 0 ) {
dev_err(&fc->dev, "Failed to create query sysfs files.");
return -ENODEV;
}
if (sysfs_create_group(&fc->dev.kobj, &attrs_control) < 0 ) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
switch(int_num) {
case 7:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_6)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 6:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_5)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 5:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_4)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 4:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_3)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 3:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_2)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 2:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_1)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
case 1:
if (sysfs_create_file(&fc->dev.kobj, attrify(int_en_force_0)) < 0) {
dev_err(&fc->dev, "Failed to create control sysfs files.");
return -ENODEV;
}
default:
break;
}
if (sysfs_create_group(&fc->dev.kobj, &attrs_data) < 0 ) {
dev_err(&fc->dev, "Failed to create data sysfs files.");
return -ENODEV;
}
if (sysfs_create_group(&fc->dev.kobj, &attrs_command) < 0 ) {
dev_err(&fc->dev, "Failed to create command sysfs files.");
return -ENODEV;
}
return 0;
}
static int rmi_f21_config(struct rmi_function_container *fc)
{
struct rmi_fn_21_data *data = fc->data;
/* repeated register functions */
/* Write Control Register values back to device */
rmi_write_block(fc->rmi_dev, data->control.reg_0__3->address,
(u8 *)data->control.reg_0__3,
sizeof(data->control.reg_0__3->regs));
rmi_write_block(fc->rmi_dev, data->control.reg_4->address,
(u8*) data->control.reg_4->regs,
data->query.max_force_sensor_count * sizeof(u8));
rmi_write_block(fc->rmi_dev, data->control.reg_5->address,
(u8*) data->control.reg_5->regs,
data->query.max_force_sensor_count * sizeof(u8));
rmi_write_block(fc->rmi_dev, data->control.reg_6->address,
(u8*) data->control.reg_6->regs,
data->query.max_force_sensor_count * sizeof(u8));
rmi_write_block(fc->rmi_dev, data->control.reg_7->address,
(u8*) data->control.reg_7->regs,
data->query.max_force_sensor_count * sizeof(u8));
rmi_write_block(fc->rmi_dev, data->control.reg_8->address,
(u8*) data->control.reg_8->regs,
data->query.max_force_sensor_count * sizeof(u8));
return 0;
}
static void rmi_f21_remove(struct rmi_function_container *fc)
{
dev_info(&fc->dev, "Removing F21.");
rmi_f21_free_memory(fc);
}
/* sysfs functions */
/* Query */
simple_show_union_struct_unsigned(query, max_force_sensor_count)
simple_show_union_struct_unsigned(query, has_high_resolution)
/* Control */
show_store_union_struct_unsigned(control, reg_0__3, reporting_mode)
show_store_union_struct_unsigned(control, reg_0__3, no_rezero)
show_store_union_struct_unsigned(control, reg_0__3, force_click_threshold)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_0)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_1)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_2)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_3)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_4)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_5)
show_store_union_struct_unsigned(control, reg_0__3, int_en_force_6)
show_store_union_struct_unsigned(control, reg_0__3, int_en_click)
show_store_union_struct_unsigned(control, reg_0__3, force_interrupt_threshold)
/* repeated register functions */
show_store_repeated_union_struct_unsigned(control, reg_4, use_cfg_cal)
show_store_repeated_union_struct_unsigned(control, reg_4, one_newton_calibration)
show_store_repeated_union_struct_unsigned(control, reg_5, x_location)
show_store_repeated_union_struct_unsigned(control, reg_6, y_location)
show_store_repeated_union_struct_unsigned(control, reg_7, transmitter_force_sensor)
show_store_repeated_union_struct_unsigned(control, reg_8, receiver_force_sensor)
/* Data */
static ssize_t rmi_fn_21_force_show(struct device *dev,
struct device_attribute *attr,
char *buf) {
struct rmi_function_container *fc;
struct FUNCTION_DATA *data;
int reg_length;
int result, size = 0;
char *temp;
int i;
fc = to_rmi_function_container(dev);
data = fc->data;
/* Read current regtype values */
reg_length = data->query.max_force_sensor_count;
result = rmi_read_block(fc->rmi_dev, data->data.reg_0__1.address,
data->data.reg_0__1.force_hi_lo,
2 *reg_length * sizeof(u8));
if (result < 0) {
dev_err(dev, "%s : Could not read regtype at 0x%x\nData may be outdated.", __func__,
data->data.reg_0__1.address);
}
temp = buf;
for (i = 0; i < reg_length; i++) {
result = snprintf(temp, PAGE_SIZE - size, "%d ",
data->data.reg_0__1.force_hi_lo[i] * (2 << 3)
+ data->data.reg_0__1.force_hi_lo[i + reg_length]);
if (result < 0) {
dev_err(dev, "%s : Could not write output.", __func__);
return result;
}
size += result;
temp += result;
}
result = snprintf(temp, PAGE_SIZE - size, "\n");
if (result < 0) {
dev_err(dev, "%s : Could not write output.", __func__);
return result;
}
return size + result;
}
show_union_struct_unsigned(data, reg_2, force_click)
/* Command */
static ssize_t rmi_fn_21_rezero_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) {
unsigned long val;
int error, result;
struct rmi_function_container *fc;
struct rmi_fn_21_data *instance_data;
struct rmi_driver *driver;
u8 command;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
driver = fc->rmi_dev->driver;
/* need to convert the string data to an actual value */
error = strict_strtoul(buf, 10, &val);
if (error)
return error;
/* Do nothing if not set to 1. This prevents accidental commands. */
if (val != 1)
return count;
command = (unsigned char)F21_REZERO_CMD;
/* Write the command to the command register */
result = rmi_write_block(fc->rmi_dev, fc->fd.command_base_addr,
&command, 1);
if (result < 0) {
dev_err(dev, "%s : Could not write command to 0x%x\n",
__func__, fc->fd.command_base_addr);
return result;
}
return count;
}
static struct rmi_function_handler function_handler = {
.func = 0x21,
.init = rmi_f21_init,
.config = rmi_f21_config,
.reset = NULL,
.attention = NULL,
.remove = rmi_f21_remove
};
static int __init rmi_f21_module_init(void)
{
int error;
error = rmi_register_function_driver(&function_handler);
if (error < 0) {
pr_err("%s: register failed!\n", __func__);
return error;
}
return 0;
}
static void rmi_f21_module_exit(void)
{
rmi_unregister_function_driver(&function_handler);
}
module_init(rmi_f21_module_init);
module_exit(rmi_f21_module_exit);
MODULE_AUTHOR("Daniel Rosenberg <daniel.rosenberg@synaptics.com>");
MODULE_DESCRIPTION("RMI F21 module");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

View File

@ -0,0 +1,962 @@
/*
* Copyright (c) 2011 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/version.h>
#include "rmi_driver.h"
/* define fn $34 commands */
#define WRITE_FW_BLOCK 0x2
#define ERASE_ALL 0x3
#define READ_CONFIG_BLOCK 0x5
#define WRITE_CONFIG_BLOCK 0x6
#define ERASE_CONFIG 0x7
#define ENABLE_FLASH_PROG 0xf
#define STATUS_IN_PROGRESS 0xff
#define STATUS_IDLE 0x80
#define PDT_START_SCAN_LOCATION 0x00e9
#define PDT_END_SCAN_LOCATION 0x0005
#define BLK_SZ_OFF 3
#define IMG_BLK_CNT_OFF 5
#define CFG_BLK_CNT_OFF 7
#define BLK_NUM_OFF 2
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32)
#define KERNEL_VERSION_ABOVE_2_6_32 1
#endif
/* data specific to fn $34 that needs to be kept around */
struct rmi_fn_34_data {
unsigned char status;
unsigned char cmd;
unsigned short bootloaderid;
unsigned short blocksize;
unsigned short imageblockcount;
unsigned short configblockcount;
unsigned short blocknum;
bool inflashprogmode;
struct mutex attn_mutex;
};
static ssize_t rmi_fn_34_status_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_34_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_fn_34_cmd_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_34_cmd_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
#ifdef KERNEL_VERSION_ABOVE_2_6_32
static ssize_t rmi_fn_34_data_read(struct file *data_file, struct kobject *kobj,
struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
static ssize_t rmi_fn_34_data_write(struct file *data_file,
struct kobject *kobj,
struct bin_attribute *attributes, char *buf,
loff_t pos, size_t count);
#else
static ssize_t rmi_fn_34_data_read(struct kobject *kobj,
struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
static ssize_t rmi_fn_34_data_write(struct kobject *kobj,
struct bin_attribute *attributes, char *buf,
loff_t pos, size_t count);
#endif
static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t rmi_fn_34_blocknum_show(struct device *dev,
struct device_attribute *attr,
char *buf);
static ssize_t rmi_fn_34_blocknum_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
static int rmi_f34_alloc_memory(struct rmi_function_container *fc);
static void rmi_f34_free_memory(struct rmi_function_container *fc);
static int rmi_f34_initialize(struct rmi_function_container *fc);
static int rmi_f34_config(struct rmi_function_container *fc);
static int rmi_f34_reset(struct rmi_function_container *fc);
static int rmi_f34_create_sysfs(struct rmi_function_container *fc);
static struct device_attribute attrs[] = {
__ATTR(status, RMI_RW_ATTR,
rmi_fn_34_status_show, rmi_fn_34_status_store),
/* Also, sysfs will need to have a file set up to distinguish
* between commands - like Config write/read, Image write/verify. */
__ATTR(cmd, RMI_RW_ATTR,
rmi_fn_34_cmd_show, rmi_fn_34_cmd_store),
__ATTR(bootloaderid, RMI_RW_ATTR,
rmi_fn_34_bootloaderid_show, rmi_fn_34_bootloaderid_store),
__ATTR(blocksize, RMI_RO_ATTR,
rmi_fn_34_blocksize_show, rmi_store_error),
__ATTR(imageblockcount, RMI_RO_ATTR,
rmi_fn_34_imageblockcount_show, rmi_store_error),
__ATTR(configblockcount, RMI_RO_ATTR,
rmi_fn_34_configblockcount_show, rmi_store_error),
__ATTR(blocknum, RMI_RW_ATTR,
rmi_fn_34_blocknum_show, rmi_fn_34_blocknum_store),
__ATTR(rescanPDT, RMI_WO_ATTR,
rmi_show_error, rmi_fn_34_rescanPDT_store)
};
struct bin_attribute dev_attr_data = {
.attr = {
.name = "data",
.mode = 0666},
.size = 0,
.read = rmi_fn_34_data_read,
.write = rmi_fn_34_data_write,
};
static int rmi_f34_init(struct rmi_function_container *fc)
{
int retval;
dev_info(&fc->dev, "Intializing f34 values.");
/* init instance data, fill in values and create any sysfs files */
retval = rmi_f34_alloc_memory(fc);
if (retval < 0)
goto exit_free_data;
retval = rmi_f34_initialize(fc);
if (retval < 0)
goto exit_free_data;
retval = rmi_f34_create_sysfs(fc);
if (retval < 0)
goto exit_free_data;
return 0;
exit_free_data:
rmi_f34_free_memory(fc);
return retval;
}
static int rmi_f34_alloc_memory(struct rmi_function_container *fc)
{
struct rmi_fn_34_data *f34;
f34 = kzalloc(sizeof(struct rmi_fn_34_data), GFP_KERNEL);
if (!f34) {
dev_err(&fc->dev, "Failed to allocate rmi_fn_34_data.\n");
return -ENOMEM;
}
fc->data = f34;
return 0;
}
static void rmi_f34_free_memory(struct rmi_function_container *fc)
{
kfree(fc->data);
fc->data = NULL;
}
static int rmi_f34_initialize(struct rmi_function_container *fc)
{
struct rmi_device *rmi_dev = fc->rmi_dev;
struct rmi_device_platform_data *pdata;
int retval = 0;
struct rmi_fn_34_data *f34 = fc->data;
u16 query_base_addr;
u16 control_base_addr;
unsigned char buf[2];
pdata = to_rmi_platform_data(rmi_dev);
dev_dbg(&fc->dev, "Initializing F34 values for %s.\n",
pdata->sensor_name);
mutex_init(&f34->attn_mutex);
/* get the Bootloader ID and Block Size. */
query_base_addr = fc->fd.query_base_addr;
control_base_addr = fc->fd.control_base_addr;
retval = rmi_read_block(fc->rmi_dev, query_base_addr, buf,
ARRAY_SIZE(buf));
if (retval < 0) {
dev_err(&fc->dev, "Could not read bootloaderid from 0x%04x.\n",
query_base_addr);
return retval;
}
batohs(&f34->bootloaderid, buf);
retval = rmi_read_block(fc->rmi_dev, query_base_addr + BLK_SZ_OFF, buf,
ARRAY_SIZE(buf));
if (retval < 0) {
dev_err(&fc->dev, "Could not read block size from 0x%04x, "
"error=%d.\n", query_base_addr + BLK_SZ_OFF, retval);
return retval;
}
batohs(&f34->blocksize, buf);
/* Get firmware image block count and store it in the instance data */
retval = rmi_read_block(fc->rmi_dev, query_base_addr + IMG_BLK_CNT_OFF,
buf, ARRAY_SIZE(buf));
if (retval < 0) {
dev_err(&fc->dev, "Couldn't read image block count from 0x%x, "
"error=%d.\n", query_base_addr + IMG_BLK_CNT_OFF,
retval);
return retval;
}
batohs(&f34->imageblockcount, buf);
/* Get config block count and store it in the instance data */
retval = rmi_read_block(fc->rmi_dev, query_base_addr + 7, buf,
ARRAY_SIZE(buf));
if (retval < 0) {
dev_err(&fc->dev, "Couldn't read config block count from 0x%x, "
"error=%d.\n", query_base_addr + CFG_BLK_CNT_OFF,
retval);
return retval;
}
batohs(&f34->configblockcount, buf);
return 0;
}
static int rmi_f34_create_sysfs(struct rmi_function_container *fc)
{
int attr_count = 0;
int rc;
dev_dbg(&fc->dev, "Creating sysfs files.");
/* We need a sysfs file for the image/config block to write or read.
* Set up sysfs bin file for binary data block. Since the image is
* already in our format there is no need to convert the data for
* endianess. */
rc = sysfs_create_bin_file(&fc->dev.kobj,
&dev_attr_data);
if (rc < 0) {
dev_err(&fc->dev, "Failed to create sysfs file for F34 data "
"(error = %d).\n", rc);
return -ENODEV;
}
/* Set up sysfs device attributes. */
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
if (sysfs_create_file
(&fc->dev.kobj, &attrs[attr_count].attr) < 0) {
dev_err(&fc->dev, "Failed to create sysfs file for %s.",
attrs[attr_count].attr.name);
rc = -ENODEV;
goto err_remove_sysfs;
}
}
return 0;
err_remove_sysfs:
sysfs_remove_bin_file(&fc->dev.kobj, &dev_attr_data);
for (attr_count--; attr_count >= 0; attr_count--)
sysfs_remove_file(&fc->dev.kobj,
&attrs[attr_count].attr);
return rc;
}
static int rmi_f34_config(struct rmi_function_container *fc)
{
/* for this function we should do nothing here */
return 0;
}
static int rmi_f34_reset(struct rmi_function_container *fc)
{
struct rmi_fn_34_data *instance_data = fc->data;
instance_data->status = ECONNRESET;
return 0;
}
static void rmi_f34_remove(struct rmi_function_container *fc)
{
int attr_count;
sysfs_remove_bin_file(&fc->dev.kobj,
&dev_attr_data);
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
sysfs_remove_file(&fc->dev.kobj,
&attrs[attr_count].attr);
rmi_f34_free_memory(fc);
}
static int f34_read_status(struct rmi_function_container *fc)
{
struct rmi_fn_34_data *instance_data = fc->data;
u16 data_base_addr = fc->fd.data_base_addr;
u8 status;
int retval;
if (instance_data->status == ECONNRESET)
return instance_data->status;
/* Read the Fn $34 status from F34_Flash_Data3 to see the previous
* commands status. F34_Flash_Data3 will be the address after the
* 2 block number registers plus blocksize Data registers.
* inform user space - through a sysfs param. */
retval = rmi_read(fc->rmi_dev,
data_base_addr + instance_data->blocksize +
BLK_NUM_OFF, &status);
if (retval < 0) {
dev_err(&fc->dev, "Could not read status from 0x%x\n",
data_base_addr + instance_data->blocksize + BLK_NUM_OFF);
status = 0xff; /* failure */
}
/* set a sysfs value that the user mode can read - only
* upper 4 bits are the status. successful is $80, anything
* else is failure */
instance_data->status = status & 0xf0;
/* put mode into Flash Prog Mode when we successfully do
* an Enable Flash Prog cmd. */
if ((instance_data->status == STATUS_IDLE) &&
(instance_data->cmd == ENABLE_FLASH_PROG))
instance_data->inflashprogmode = true;
return retval;
}
int rmi_f34_attention(struct rmi_function_container *fc, u8 *irq_bits)
{
int retval;
struct rmi_fn_34_data *data = fc->data;
mutex_lock(&data->attn_mutex);
retval = f34_read_status(fc);
mutex_unlock(&data->attn_mutex);
return retval;
}
static struct rmi_function_handler function_handler = {
.func = 0x34,
.init = rmi_f34_init,
.config = rmi_f34_config,
.reset = rmi_f34_reset,
.attention = rmi_f34_attention,
.remove = rmi_f34_remove
};
static ssize_t rmi_fn_34_bootloaderid_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->bootloaderid);
}
static ssize_t rmi_fn_34_bootloaderid_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
int error;
unsigned long val;
unsigned char data[2];
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
u16 data_base_addr;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
/* need to convert the string data to an actual value */
error = strict_strtoul(buf, 10, &val);
if (error)
return error;
instance_data->bootloaderid = val;
/* Write the Bootloader ID key data back to the first two Block
* Data registers (F34_Flash_Data2.0 and F34_Flash_Data2.1). */
hstoba(data, (unsigned short)val);
data_base_addr = fc->fd.data_base_addr;
error = rmi_write_block(fc->rmi_dev,
data_base_addr + BLK_NUM_OFF,
data,
ARRAY_SIZE(data));
if (error < 0) {
dev_err(dev, "%s : Could not write bootloader id to 0x%x\n",
__func__, data_base_addr + BLK_NUM_OFF);
return error;
}
return count;
}
static ssize_t rmi_fn_34_blocksize_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocksize);
}
static ssize_t rmi_fn_34_imageblockcount_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
instance_data->imageblockcount);
}
static ssize_t rmi_fn_34_configblockcount_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n",
instance_data->configblockcount);
}
static ssize_t rmi_fn_34_status_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
int retval;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
mutex_lock(&instance_data->attn_mutex);
retval = f34_read_status(fc);
mutex_unlock(&instance_data->attn_mutex);
if (retval < 0)
return retval;
return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->status);
}
static ssize_t rmi_fn_34_status_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
instance_data->status = 0;
return 0;
}
static ssize_t rmi_fn_34_cmd_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->cmd);
}
static ssize_t rmi_fn_34_cmd_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
unsigned long val;
u16 data_base_addr;
int error;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
data_base_addr = fc->fd.data_base_addr;
/* need to convert the string data to an actual value */
error = strict_strtoul(buf, 10, &val);
if (error)
return error;
/* make sure we are in Flash Prog mode for all cmds except the
* Enable Flash Programming cmd - otherwise we are in error */
if ((val != ENABLE_FLASH_PROG) && !instance_data->inflashprogmode) {
dev_err(dev, "%s: CANNOT SEND CMD %d TO SENSOR - "
"NOT IN FLASH PROG MODE\n"
, __func__, data_base_addr);
return -EINVAL;
}
instance_data->cmd = val;
/* Validate command value and (if necessary) write it to the command
* register.
*/
switch (instance_data->cmd) {
case ENABLE_FLASH_PROG:
case ERASE_ALL:
case ERASE_CONFIG:
case WRITE_FW_BLOCK:
case READ_CONFIG_BLOCK:
case WRITE_CONFIG_BLOCK:
/* Reset the status to indicate we are in progress on a cmd. */
/* The status will change when the ATTN interrupt happens
and the status of the cmd that was issued is read from
the F34_Flash_Data3 register - result should be 0x80 for
success - any other value indicates an error */
/* Issue the command to the device. */
error = rmi_write(fc->rmi_dev,
data_base_addr + instance_data->blocksize +
BLK_NUM_OFF, instance_data->cmd);
if (error < 0) {
dev_err(dev, "%s: Could not write command 0x%02x "
"to 0x%04x\n", __func__, instance_data->cmd,
data_base_addr + instance_data->blocksize +
BLK_NUM_OFF);
return error;
}
if (instance_data->cmd == ENABLE_FLASH_PROG)
instance_data->inflashprogmode = true;
/* set status to indicate we are in progress */
instance_data->status = STATUS_IN_PROGRESS;
break;
default:
dev_dbg(dev, "%s: RMI4 function $34 - "
"unknown command 0x%02lx.\n", __func__, val);
count = -EINVAL;
break;
}
return count;
}
static ssize_t rmi_fn_34_blocknum_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
return snprintf(buf, PAGE_SIZE, "%u\n", instance_data->blocknum);
}
static ssize_t rmi_fn_34_blocknum_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
int error;
unsigned long val;
unsigned char data[2];
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
u16 data_base_addr;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
data_base_addr = fc->fd.data_base_addr;
/* need to convert the string data to an actual value */
error = strict_strtoul(buf, 10, &val);
if (error)
return error;
instance_data->blocknum = val;
/* Write the Block Number data back to the first two Block
* Data registers (F34_Flash_Data_0 and F34_Flash_Data_1). */
hstoba(data, (unsigned short)val);
error = rmi_write_block(fc->rmi_dev,
data_base_addr,
data,
ARRAY_SIZE(data));
if (error < 0) {
dev_err(dev, "%s : Could not write block number %u to 0x%x\n",
__func__, instance_data->blocknum, data_base_addr);
return error;
}
return count;
}
static ssize_t rmi_fn_34_rescanPDT_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
struct rmi_device *rmi_dev;
struct rmi_driver_data *driver_data;
struct pdt_entry pdt_entry;
bool fn01found = false;
bool fn34found = false;
unsigned int rescan;
int irq_count = 0;
int retval = 0;
int i;
/* Rescan of the PDT is needed since issuing the Flash Enable cmd
* the device registers for Fn$01 and Fn$34 moving around because
* of the change from Bootloader mode to Flash Programming mode
* may change to a different PDT with only Fn$01 and Fn$34 that
* could have addresses for query, control, data, command registers
* that differ from the PDT scan done at device initialization. */
fc = to_rmi_function_container(dev);
instance_data = fc->data;
rmi_dev = fc->rmi_dev;
driver_data = rmi_get_driverdata(rmi_dev);
/* Make sure we are only in Flash Programming mode - DON'T
* ALLOW THIS IN UI MODE. */
if (instance_data->cmd != ENABLE_FLASH_PROG) {
dev_err(dev, "%s: NOT IN FLASH PROG MODE - CAN'T RESCAN PDT.\n"
, __func__);
return -EINVAL;
}
/* The only good value to write to this is 1, we allow 0, but with
* no effect (this is consistent with the way the command bit works. */
if (sscanf(buf, "%u", &rescan) != 1)
return -EINVAL;
if (rescan < 0 || rescan > 1)
return -EINVAL;
/* 0 has no effect, so we skip it entirely. */
if (rescan) {
/* rescan the PDT - filling in Fn01 and Fn34 addresses -
* this is only temporary - the device will need to be reset
* to return the PDT to the normal values. */
/* mini-parse the PDT - we only have to get Fn$01 and Fn$34 and
since we are Flash Programming mode we only have page 0. */
for (i = PDT_START_SCAN_LOCATION; i >= PDT_END_SCAN_LOCATION;
i -= sizeof(pdt_entry)) {
retval = rmi_read_block(rmi_dev, i, (u8 *)&pdt_entry,
sizeof(pdt_entry));
if (retval != sizeof(pdt_entry)) {
dev_err(dev, "%s: err frm rmi_read_block pdt "
"entry data from PDT, "
"error = %d.", __func__, retval);
return retval;
}
if ((pdt_entry.function_number == 0x00) ||
(pdt_entry.function_number == 0xff))
break;
dev_dbg(dev, "%s: Found F%.2X\n",
__func__, pdt_entry.function_number);
/* f01 found - just fill in the new addresses in
* the existing fc. */
if (pdt_entry.function_number == 0x01) {
struct rmi_function_container *f01_fc =
driver_data->f01_container;
fn01found = true;
f01_fc->fd.query_base_addr =
pdt_entry.query_base_addr;
f01_fc->fd.command_base_addr =
pdt_entry.command_base_addr;
f01_fc->fd.control_base_addr =
pdt_entry.control_base_addr;
f01_fc->fd.data_base_addr =
pdt_entry.data_base_addr;
f01_fc->fd.function_number =
pdt_entry.function_number;
f01_fc->fd.interrupt_source_count =
pdt_entry.interrupt_source_count;
f01_fc->num_of_irqs =
pdt_entry.interrupt_source_count;
f01_fc->irq_pos = irq_count;
irq_count += f01_fc->num_of_irqs;
if (fn34found)
break;
}
/* f34 found - just fill in the new addresses in
* the existing fc. */
if (pdt_entry.function_number == 0x34) {
fn34found = true;
fc->fd.query_base_addr =
pdt_entry.query_base_addr;
fc->fd.command_base_addr =
pdt_entry.command_base_addr;
fc->fd.control_base_addr =
pdt_entry.control_base_addr;
fc->fd.data_base_addr =
pdt_entry.data_base_addr;
fc->fd.function_number =
pdt_entry.function_number;
fc->fd.interrupt_source_count =
pdt_entry.interrupt_source_count;
fc->num_of_irqs =
pdt_entry.interrupt_source_count;
fc->irq_pos = irq_count;
irq_count += fc->num_of_irqs;
if (fn01found)
break;
}
}
if (!fn01found || !fn34found) {
dev_err(dev, "%s: failed to find fn$01 or fn$34 trying "
"to do rescan PDT.\n"
, __func__);
return -EINVAL;
}
}
return count;
}
#ifdef KERNEL_VERSION_ABOVE_2_6_32
static ssize_t rmi_fn_34_data_read(struct file *data_file,
struct kobject *kobj,
struct bin_attribute *attributes,
char *buf,
loff_t pos,
size_t count)
#else
static ssize_t rmi_fn_34_data_read(struct kobject *kobj,
struct bin_attribute *attributes,
char *buf,
loff_t pos,
size_t count)
#endif
{
struct device *dev = container_of(kobj, struct device, kobj);
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
u16 data_base_addr;
int error;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
data_base_addr = fc->fd.data_base_addr;
if (count != instance_data->blocksize) {
dev_err(dev,
"%s : Incorrect F34 block size %d. "
"Expected size %d.\n",
__func__, count, instance_data->blocksize);
return -EINVAL;
}
/* Read the data from flash into buf. The app layer will be blocked
* at reading from the sysfs file. When we return the count (or
* error if we fail) the app will resume. */
error = rmi_read_block(fc->rmi_dev, data_base_addr + BLK_NUM_OFF,
(unsigned char *)buf, count);
if (error < 0) {
dev_err(dev, "%s : Could not read data from 0x%04x\n",
__func__, data_base_addr + BLK_NUM_OFF);
return error;
}
return count;
}
#ifdef KERNEL_VERSION_ABOVE_2_6_32
static ssize_t rmi_fn_34_data_write(struct file *data_file,
struct kobject *kobj,
struct bin_attribute *attributes,
char *buf,
loff_t pos,
size_t count)
#else
static ssize_t rmi_fn_34_data_write(struct kobject *kobj,
struct bin_attribute *attributes,
char *buf,
loff_t pos,
size_t count)
#endif
{
struct device *dev = container_of(kobj, struct device, kobj);
struct rmi_function_container *fc;
struct rmi_fn_34_data *instance_data;
u16 data_base_addr;
int error;
fc = to_rmi_function_container(dev);
instance_data = fc->data;
data_base_addr = fc->fd.data_base_addr;
/* Write the data from buf to flash. The app layer will be
* blocked at writing to the sysfs file. When we return the
* count (or error if we fail) the app will resume. */
if (count != instance_data->blocksize) {
dev_err(dev,
"%s : Incorrect F34 block size %d. "
"Expected size %d.\n",
__func__, count, instance_data->blocksize);
return -EINVAL;
}
/* Write the data block - only if the count is non-zero */
if (count) {
error = rmi_write_block(fc->rmi_dev,
data_base_addr + BLK_NUM_OFF,
(unsigned char *)buf,
count);
if (error < 0) {
dev_err(dev, "%s : Could not write block data "
"to 0x%x\n", __func__,
data_base_addr + BLK_NUM_OFF);
return error;
}
}
return count;
}
static int __init rmi_f34_module_init(void)
{
int error;
error = rmi_register_function_driver(&function_handler);
if (error < 0) {
pr_err("%s : register failed !\n", __func__);
return error;
}
return 0;
}
static void rmi_f34_module_exit(void)
{
rmi_unregister_function_driver(&function_handler);
}
module_init(rmi_f34_module_init);
module_exit(rmi_f34_module_exit);
MODULE_AUTHOR("William Manson <wmanson@synaptics.com");
MODULE_DESCRIPTION("RMI F34 module");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,453 @@
/*
* Copyright (c) 2011 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define COMMS_DEBUG 0
#define IRQ_DEBUG 0
#if COMMS_DEBUG || IRQ_DEBUG
#define DEBUG
#endif
#include <linux/kernel.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#define RMI_PAGE_SELECT_REGISTER 0xff
#define RMI_I2C_PAGE(addr) (((addr) >> 8) & 0xff)
#ifndef CONFIG_RMI4_I2C_SCL_RATE
#define CONFIG_RMI4_I2C_SCL_RATE 100000 // 100kHz
#endif
static char *phys_proto_name = "i2c";
struct rmi_i2c_data {
struct mutex page_mutex;
int page;
int enabled;
int irq;
int irq_flags;
struct rmi_phys_device *phys;
};
static irqreturn_t rmi_i2c_irq_thread(int irq, void *p)
{
struct rmi_phys_device *phys = p;
struct rmi_device *rmi_dev = phys->rmi_dev;
struct rmi_driver *driver = rmi_dev->driver;
struct rmi_device_platform_data *pdata = phys->dev->platform_data;
#if IRQ_DEBUG
dev_dbg(phys->dev, "ATTN gpio, value: %d.\n",
gpio_get_value(pdata->attn_gpio));
#endif
if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) {
phys->info.attn_count++;
if (driver && driver->irq_handler && rmi_dev)
driver->irq_handler(rmi_dev, irq);
}
return IRQ_HANDLED;
}
/*
* rmi_set_page - Set RMI page
* @phys: The pointer to the rmi_phys_device struct
* @page: The new page address.
*
* RMI devices have 16-bit addressing, but some of the physical
* implementations (like SMBus) only have 8-bit addressing. So RMI implements
* a page address at 0xff of every page so we can reliable page addresses
* every 256 registers.
*
* The page_mutex lock must be held when this function is entered.
*
* Returns zero on success, non-zero on failure.
*/
static int rmi_set_page(struct rmi_phys_device *phys, unsigned int page)
{
struct i2c_client *client = to_i2c_client(phys->dev);
struct rmi_i2c_data *data = phys->data;
char txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page};
int retval;
#if COMMS_DEBUG
dev_dbg(&client->dev, "RMI4 I2C writes 3 bytes: %02x %02x\n",
txbuf[0], txbuf[1]);
#endif
phys->info.tx_count++;
phys->info.tx_bytes += sizeof(txbuf);
retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE);
if (retval != sizeof(txbuf)) {
phys->info.tx_errs++;
dev_err(&client->dev,
"%s: set page failed: %d.", __func__, retval);
return (retval < 0) ? retval : -EIO;
}
data->page = page;
return 0;
}
int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len)
{
struct i2c_client *client = to_i2c_client(phys->dev);
struct rmi_i2c_data *data = phys->data;
u8 txbuf[len + 1];
int retval;
#if COMMS_DEBUG
int i;
#endif
txbuf[0] = addr & 0xff;
memcpy(txbuf + 1, buf, len);
mutex_lock(&data->page_mutex);
if (RMI_I2C_PAGE(addr) != data->page) {
retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
if (retval < 0)
goto exit;
}
#if COMMS_DEBUG
dev_dbg(&client->dev, "RMI4 I2C writes %d bytes: ", sizeof(txbuf));
for (i = 0; i < sizeof(txbuf); i++)
dev_dbg(&client->dev, "%02x ", txbuf[i]);
dev_dbg(&client->dev, "\n");
#endif
phys->info.tx_count++;
phys->info.tx_bytes += sizeof(txbuf);
retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE);
if (retval < 0)
phys->info.tx_errs++;
else
retval--; /* don't count the address byte */
exit:
mutex_unlock(&data->page_mutex);
return retval;
}
static int rmi_i2c_write(struct rmi_phys_device *phys, u16 addr, u8 data)
{
int retval = rmi_i2c_write_block(phys, addr, &data, 1);
return (retval < 0) ? retval : 0;
}
int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len)
{
struct i2c_client *client = to_i2c_client(phys->dev);
struct rmi_i2c_data *data = phys->data;
u8 txbuf[1] = {addr & 0xff};
int retval;
#if COMMS_DEBUG
int i;
#endif
mutex_lock(&data->page_mutex);
if (RMI_I2C_PAGE(addr) != data->page) {
retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
if (retval < 0)
goto exit;
}
#if COMMS_DEBUG
dev_dbg(&client->dev, "RMI4 I2C writes 1 bytes: %02x\n", txbuf[0]);
#endif
phys->info.tx_count++;
phys->info.tx_bytes += sizeof(txbuf);
retval = i2c_master_normal_send(client, txbuf, sizeof(txbuf), CONFIG_RMI4_I2C_SCL_RATE);
if (retval != sizeof(txbuf)) {
phys->info.tx_errs++;
retval = (retval < 0) ? retval : -EIO;
goto exit;
}
retval = i2c_master_normal_recv(client, buf, len, CONFIG_RMI4_I2C_SCL_RATE);
phys->info.rx_count++;
phys->info.rx_bytes += len;
if (retval < 0)
phys->info.rx_errs++;
#if COMMS_DEBUG
else {
dev_dbg(&client->dev, "RMI4 I2C received %d bytes: ", len);
for (i = 0; i < len; i++)
dev_dbg(&client->dev, "%02x ", buf[i]);
dev_dbg(&client->dev, "\n");
}
#endif
exit:
mutex_unlock(&data->page_mutex);
return retval;
}
static int rmi_i2c_read(struct rmi_phys_device *phys, u16 addr, u8 *buf)
{
int retval = rmi_i2c_read_block(phys, addr, buf, 1);
return (retval < 0) ? retval : 0;
}
static int acquire_attn_irq(struct rmi_i2c_data *data)
{
return request_threaded_irq(data->irq, NULL, rmi_i2c_irq_thread,
data->irq_flags, dev_name(data->phys->dev), data->phys);
}
static int enable_device(struct rmi_phys_device *phys)
{
int retval = 0;
struct rmi_i2c_data *data = phys->data;
if (data->enabled)
return 0;
retval = acquire_attn_irq(data);
if (retval)
goto error_exit;
data->enabled = true;
dev_dbg(phys->dev, "Physical device enabled.\n");
return 0;
error_exit:
dev_err(phys->dev, "Failed to enable physical device. Code=%d.\n",
retval);
return retval;
}
static void disable_device(struct rmi_phys_device *phys)
{
struct rmi_i2c_data *data = phys->data;
if (!data->enabled)
return;
disable_irq(data->irq);
free_irq(data->irq, data->phys);
dev_dbg(phys->dev, "Physical device disabled.\n");
data->enabled = false;
}
void CompleteReflash(struct rmi_phys_device *phys);
static int __devinit rmi_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rmi_phys_device *rmi_phys;
struct rmi_i2c_data *data;
struct rmi_device_platform_data *pdata = client->dev.platform_data;
int error;
if (!pdata) {
dev_err(&client->dev, "no platform data\n");
return -EINVAL;
}
pr_info("%s: Probing %s at %#02x (IRQ %d).\n", __func__,
pdata->sensor_name ? pdata->sensor_name : "-no name-",
client->addr, pdata->attn_gpio);
error = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
if (!error) {
dev_err(&client->dev, "i2c_check_functionality error %d.\n",
error);
return error;
}
rmi_phys = kzalloc(sizeof(struct rmi_phys_device), GFP_KERNEL);
if (!rmi_phys)
return -ENOMEM;
data = kzalloc(sizeof(struct rmi_i2c_data), GFP_KERNEL);
if (!data) {
error = -ENOMEM;
goto err_phys;
}
data->enabled = true; /* We plan to come up enabled. */
data->irq = gpio_to_irq(pdata->attn_gpio);
if (pdata->level_triggered) {
data->irq_flags = IRQF_ONESHOT |
((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ?
IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW);
} else {
data->irq_flags =
(pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
}
data->phys = rmi_phys;
rmi_phys->data = data;
rmi_phys->dev = &client->dev;
rmi_phys->write = rmi_i2c_write;
rmi_phys->write_block = rmi_i2c_write_block;
rmi_phys->read = rmi_i2c_read;
rmi_phys->read_block = rmi_i2c_read_block;
rmi_phys->enable_device = enable_device;
rmi_phys->disable_device = disable_device;
rmi_phys->info.proto = phys_proto_name;
mutex_init(&data->page_mutex);
/* Setting the page to zero will (a) make sure the PSR is in a
* known state, and (b) make sure we can talk to the device.
*/
error = rmi_set_page(rmi_phys, 0);
if (error) {
dev_err(&client->dev, "Failed to set page select to 0.\n");
goto err_data;
}
if (pdata->gpio_config) {
error = pdata->gpio_config(pdata->gpio_data, true);
if (error < 0) {
dev_err(&client->dev, "failed to setup irq %d\n",
pdata->attn_gpio);
goto err_data;
}
}
error = rmi_register_phys_device(rmi_phys);
if (error) {
dev_err(&client->dev,
"failed to register physical driver at 0x%.2X.\n",
client->addr);
goto err_gpio;
}
i2c_set_clientdata(client, rmi_phys);
if (pdata->attn_gpio > 0) {
error = acquire_attn_irq(data);
if (error < 0) {
dev_err(&client->dev,
"request_threaded_irq failed %d\n",
pdata->attn_gpio);
goto err_unregister;
}
}
#if defined(CONFIG_RMI4_DEV)
error = gpio_export(pdata->attn_gpio, false);
if (error) {
dev_warn(&client->dev, "%s: WARNING: Failed to "
"export ATTN gpio!\n", __func__);
error = 0;
} else {
error = gpio_export_link(&(rmi_phys->rmi_dev->dev), "attn",
pdata->attn_gpio);
if (error) {
dev_warn(&(rmi_phys->rmi_dev->dev),
"%s: WARNING: Failed to symlink ATTN gpio!\n",
__func__);
error = 0;
} else {
dev_info(&(rmi_phys->rmi_dev->dev),
"%s: Exported GPIO %d.", __func__,
pdata->attn_gpio);
}
}
#endif /* CONFIG_RMI4_DEV */
dev_info(&client->dev, "registered rmi i2c driver at 0x%.2X.\n",
client->addr);
//reflash the new firmware revision hhb@rock-chips.com
#ifdef CONFIG_RMI4_REFLASH_WHEN_BOOT
CompleteReflash(rmi_phys);
#endif
return 0;
err_unregister:
rmi_unregister_phys_device(rmi_phys);
err_gpio:
if (pdata->gpio_config)
pdata->gpio_config(pdata->gpio_data, false);
err_data:
kfree(data);
err_phys:
kfree(rmi_phys);
return error;
}
static int __devexit rmi_i2c_remove(struct i2c_client *client)
{
struct rmi_phys_device *phys = i2c_get_clientdata(client);
struct rmi_device_platform_data *pd = client->dev.platform_data;
disable_device(phys);
rmi_unregister_phys_device(phys);
kfree(phys->data);
kfree(phys);
if (pd->gpio_config)
pd->gpio_config(&pd->gpio_data, false);
return 0;
}
static const struct i2c_device_id rmi_id[] = {
{ "rmi", 0 },
{ "rmi_i2c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
static struct i2c_driver rmi_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "rmi_i2c"
},
.id_table = rmi_id,
.probe = rmi_i2c_probe,
.remove = __devexit_p(rmi_i2c_remove),
};
static int __init rmi_i2c_init(void)
{
return i2c_add_driver(&rmi_i2c_driver);
}
static void __exit rmi_i2c_exit(void)
{
i2c_del_driver(&rmi_i2c_driver);
}
module_init(rmi_i2c_init);
module_exit(rmi_i2c_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_DESCRIPTION("RMI I2C driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

View File

@ -0,0 +1,670 @@
/*
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2011 Synaptics, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
// SynaFirmwareImage.h contains the data for both the entire image and the config block
//#include "SynaFirmwareImage.h"
//#include "config.h"
#include <linux/string.h>
//#include <linux/printk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/rmi.h>
#include "rmi_reflash.h"
//need
#define ASSERT 1
#define TOUCH_CONTROLLER "s3202"
#define FW_REVISION "DS4 R3.0"
void eraseConfigBlock(void);
void SynaInitialize(void);
void SynaReadConfigInfo(void);
void SynaReadFirmwareInfo(void);
int TouchControllerTypeCheck(void);
void SynaEnableFlashing(void);
int fimrwareRevisionCheck(void);
void SynaBootloaderLock(void);
void SynaProgramConfiguration(void);
void SynaProgramFirmware(void);
void SynaFinalizeReflash(void);
void SynaWaitForATTN(void);
void convertConfigBlockData(void);
int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len);
int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len);
/* Variables for F34 functionality */
unsigned short SynaF34DataBase;
unsigned short SynaF34QueryBase;
unsigned short SynaF01DataBase;
unsigned short SynaF01CommandBase;
unsigned short SynaF01QueryBase;
unsigned short SynaF34Reflash_BlockNum;
unsigned short SynaF34Reflash_BlockData;
unsigned short SynaF34ReflashQuery_BootID;
unsigned short SynaF34ReflashQuery_FlashPropertyQuery;
unsigned short SynaF34ReflashQuery_FirmwareBlockSize;
unsigned short SynaF34ReflashQuery_FirmwareBlockCount;
unsigned short SynaF34ReflashQuery_ConfigBlockSize;
unsigned short SynaF34ReflashQuery_ConfigBlockCount;
unsigned short SynaFirmwareBlockSize;
unsigned short SynaFirmwareBlockCount;
unsigned long SynaImageSize;
unsigned short SynaConfigBlockSize;
unsigned short SynaConfigBlockCount;
unsigned long SynaConfigImageSize;
unsigned short SynaBootloadID;
unsigned short SynaF34_FlashControl;
unsigned char *SynafirmwareImgData;
unsigned char *SynaconfigImgData;
unsigned char *SynalockImgData;
unsigned int SynafirmwareImgVersion;
unsigned char *ConfigBlock;
unsigned char *ConfigBlockData;
struct rmi_phys_device *rmi_phys;
int readRMI(u16 addr, u8 *buf, int len) {
rmi_i2c_read_block(rmi_phys, addr, buf, len);
return 0;
}
int writeRMI(u16 addr, u8 *buf, int len) {
rmi_i2c_write_block(rmi_phys, addr, buf, len);
return 0;
}
int waitATTN(u8 n, u16 delay) {
#if 1
unsigned char uStatus;
do{
readRMI((SynaF01DataBase + 1), &uStatus, 1);
}while((uStatus & 0x01) == 0);
#else
msleep(1);
#endif
return 0;
}
/* End: Variables for F34 functionality */
/* CompleteReflash reflashes the entire user image, including the configuration block and firmware
*/
void CompleteReflash(struct rmi_phys_device *phys)
{
rmi_phys = phys;
SynaInitialize();
//if (TouchControllerTypeCheck())
{
if (fimrwareRevisionCheck())
{
printk("rmi find the current firmware revision is old, reflash now...");
SynaReadConfigInfo();
SynaReadFirmwareInfo();
SynaF34_FlashControl = SynaF34DataBase + SynaFirmwareBlockSize + 2;
SynaEnableFlashing();
SynaBootloaderLock();
SynaProgramFirmware();
SynaProgramConfiguration();
SynaFinalizeReflash();
}
}
}
/* SynaSetup scans the Page Description Table (PDT) and sets up the necessary variables
* for the reflash process. This function is a "slim" version of the PDT scan function in
* in PDT.c, since only F34 and F01 are needed for reflash.
*/
void SynaSetup(void)
{
unsigned char address;
unsigned char buffer[6] = {0};
for (address = 0xe9; address > 0xc0; address = address - 6)
{
readRMI(address, buffer, 6);
switch (buffer[5])
{
case 0x34:
SynaF34DataBase = buffer[3];
SynaF34QueryBase = buffer[0];
break;
case 0x01:
SynaF01DataBase = buffer[3];
SynaF01CommandBase = buffer[1];
SynaF01QueryBase = buffer[0];
break;
}
}
SynaF34Reflash_BlockNum = SynaF34DataBase;
SynaF34Reflash_BlockData = SynaF34DataBase + 2;
SynaF34ReflashQuery_BootID = SynaF34QueryBase;
SynaF34ReflashQuery_FlashPropertyQuery = SynaF34QueryBase + 2;
SynaF34ReflashQuery_FirmwareBlockSize = SynaF34QueryBase + 3;
SynaF34ReflashQuery_FirmwareBlockCount = SynaF34QueryBase +5;
SynaF34ReflashQuery_ConfigBlockSize = SynaF34QueryBase + 3;
SynaF34ReflashQuery_ConfigBlockCount = SynaF34QueryBase + 7;
SynafirmwareImgData = (unsigned char *)((&SynaFirmware[0])+0x100);
SynaconfigImgData = (unsigned char *)(SynafirmwareImgData+SynaImageSize);
SynafirmwareImgVersion = (unsigned int)(SynaFirmware[7]);
ConfigBlockData = SynaconfigImgData;
switch (SynafirmwareImgVersion)
{
case 2:
SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xD0);
break;
case 3:
case 4:
SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xC0);
break;
case 5:
SynalockImgData = (unsigned char *)((&SynaFirmware[0]) + 0xB0);
default: break;
}
}
/* SynaInitialize sets up the reflahs process
*/
void SynaInitialize(void)
{
unsigned char uData[2];
unsigned char uStatus = 0;
//printk("\nInitializing Reflash Process...");
uData[0] = 0;
writeRMI(0xff, uData, 1); // switch to page0 //hhb
do {
readRMI(0, &uStatus, 1);
if (uStatus & 0x80)
{
break;
}
} while (uStatus & 0x40);
SynaSetup();
SynafirmwareImgData = 0;
SynaconfigImgData = 0;
readRMI(SynaF34ReflashQuery_FirmwareBlockSize, &uData[0], 2);
SynaFirmwareBlockSize = uData[0] | (uData[1] << 8);
}
/* SynaReadFirmwareInfo reads the F34 query registers and retrieves the block size and count
* of the firmware section of the image to be reflashed
*/
void SynaReadFirmwareInfo(void)
{
unsigned char uData[2];
printk("Read Firmware Info\n");
readRMI(SynaF34ReflashQuery_FirmwareBlockSize, &uData[0], 2);
SynaFirmwareBlockSize = uData[0] | (uData[1] << 8);
readRMI(SynaF34ReflashQuery_FirmwareBlockCount, &uData[0], 2);
SynaFirmwareBlockCount = uData[0] | (uData[1] << 8);
SynaImageSize = SynaFirmwareBlockCount * SynaFirmwareBlockSize;
printk("SynaFirmwareBlockSize:%d,SynaFirmwareBlockCount:%d \n", SynaFirmwareBlockSize, SynaFirmwareBlockCount);
}
/* SynaReadConfigInfo reads the F34 query registers and retrieves the block size and count
* of the configuration section of the image to be reflashed
*/
void SynaReadConfigInfo(void)
{
unsigned char uData[2];
printk("Read Config Info\n");
readRMI(SynaF34ReflashQuery_ConfigBlockSize, &uData[0], 2);
SynaConfigBlockSize = uData[0] | (uData[1] << 8);
readRMI(SynaF34ReflashQuery_ConfigBlockCount, &uData[0], 2);
SynaConfigBlockCount = uData[0] | (uData[1] << 8);
SynaConfigImageSize = SynaConfigBlockCount * SynaConfigBlockSize;
printk("SynaConfigBlockSize:%d,SynaConfigBlockCount:%d \n", SynaConfigBlockSize, SynaConfigBlockCount);
}
/* SynaReadBootloadID reads the F34 query registers and retrieves the bootloader ID of the firmware
*/
void SynaReadBootloadID(void)
{
unsigned char uData[2];
readRMI(SynaF34ReflashQuery_BootID, &uData[0], 2);
SynaBootloadID = uData[0] + uData[1] * 0x100;
}
/* SynaWriteBootloadID writes the bootloader ID to the F34 data register to unlock the reflash process
*/
void SynaWriteBootloadID(void)
{
unsigned char uData[2];
uData[0] = SynaBootloadID % 0x100;
uData[1] = SynaBootloadID / 0x100;
writeRMI(SynaF34Reflash_BlockData, &uData[0], 2);
}
/* SynaEnableFlashing kicks off the reflash process
*/
void SynaEnableFlashing(void)
{
unsigned char uData = 0;
unsigned char uStatus = 0;
printk("Enable Reflash...\n");
// Reflash is enabled by first reading the bootloader ID from the firmware and write it back
SynaReadBootloadID();
SynaWriteBootloadID();
// Make sure Reflash is not already enabled
do {
readRMI(SynaF34_FlashControl, &uData, 1);
} while (((uData & 0x0f) != 0x00));
// Clear ATTN
readRMI (SynaF01DataBase, &uStatus, 1);
if ((uStatus & 0x40) == 0)
{
// Write the "Enable Flash Programming command to F34 Control register
// Wait for ATTN and then clear the ATTN.
readRMI(SynaF34_FlashControl, &uData, 1);
uData &= 0xf0;
uData |= 0x0f;
writeRMI(SynaF34_FlashControl, &uData, 1);
SynaWaitForATTN();
readRMI((SynaF01DataBase + 1), &uStatus, 1);
// Scan the PDT again to ensure all register offsets are correct
SynaSetup();
// Read the "Program Enabled" bit of the F34 Control register, and proceed only if the
// bit is set.
readRMI(SynaF34_FlashControl, &uData, 1);
while (uData != 0x80)
{
// In practice, if uData!=0x80 happens for multiple counts, it indicates reflash
// is failed to be enabled, and program should quit
;
}
}
}
/* SynaWaitForATTN waits for ATTN to be asserted within a certain time threshold.
*/
void SynaWaitForATTN(void)
{
unsigned int error;
error = waitATTN(ASSERT, 300);
}
/* SynaWaitATTN waits for ATTN to be asserted within a certain time threshold.
* The function also checks for the F34 "Program Enabled" bit and clear ATTN accordingly.
*/
void SynaWaitATTN(void)
{
unsigned char uData = 0;
unsigned char uStatus = 0;
waitATTN(ASSERT, 300);
do {
readRMI(SynaF34_FlashControl, &uData, 1);
readRMI((SynaF01DataBase + 1), &uStatus, 1);
} while (uData != 0x80);
}
/* SynaProgramConfiguration writes the configuration section of the image block by block
*/
void SynaProgramConfiguration(void)
{
unsigned char uData[2];
unsigned char *puData = ConfigBlockData;
unsigned short blockNum;
// eraseConfigBlock();
for (blockNum = 0; blockNum < SynaConfigBlockCount; blockNum++)
{
uData[0] = blockNum & 0xff;
uData[1] = (blockNum & 0xff00) >> 8;
//Block by blcok, write the block number and data to the corresponding F34 data registers
writeRMI(SynaF34Reflash_BlockNum, &uData[0], 2);
writeRMI(SynaF34Reflash_BlockData, puData, SynaConfigBlockSize);
puData += SynaConfigBlockSize;
// Issue the "Write Configuration Block" command
readRMI(SynaF34_FlashControl, &uData[0], 1);
uData[0] &= 0xf0;
uData[0] |= 0x06;
writeRMI(SynaF34_FlashControl, &uData[0], 1);
SynaWaitATTN();
printk(".");
}
printk("\n");
readRMI(SynaF01DataBase, uData, 1);
printk("+++++++SynaProgramConfiguration++uData:%x+++++++%s:%d\n", uData[0], __func__, __LINE__);
}
/* SynaFinalizeReflash finalizes the reflash process
*/
void SynaFinalizeReflash(void)
{
unsigned char uData = 0;
unsigned char uStatus = 0;
printk("Finalizing Reflash...\n");
// Issue the "Reset" command to F01 command register to reset the chip
// This command will also test the new firmware image and check if its is valid
uData = 1;
writeRMI(SynaF01CommandBase, &uData, 1);
msleep(100);
//SynaWaitForATTN();
readRMI(SynaF01DataBase, &uData, 1);
printk("+++++++++uData:%x+++++++%s:%d\n", uData, __func__, __LINE__);
// Sanity check that the reflash process is still enabled
do {
readRMI(SynaF34_FlashControl, &uStatus, 1);
} while ((uStatus & 0x0f) != 0x00);
printk("+++++++++uStatus:%x+++++++%s:%d\n", uStatus, __func__, __LINE__);
readRMI((SynaF01DataBase + 1), &uStatus, 1);
SynaSetup();
uData = 0;
// Check if the "Program Enabled" bit in F01 data register is cleared
// Reflash is completed, and the image passes testing when the bit is cleared
do {
readRMI(SynaF01DataBase, &uData, 1);
} while ((uData & 0x40) != 0);
// Rescan PDT the update any changed register offsets
SynaSetup();
printk("\nReflash Completed. Please reboot.");
}
/* SynaFlashFirmwareWrite writes the firmware section of the image block by block
*/
void SynaFlashFirmwareWrite(void)
{
unsigned char *puFirmwareData = (unsigned char *)(SynaFirmware+0x100); //SynafirmwareImgData; //hhb
unsigned char uData[2];
unsigned short blockNum;
for (blockNum = 0; blockNum < SynaFirmwareBlockCount; ++blockNum)
{
//Block by blcok, write the block number and data to the corresponding F34 data registers
uData[0] = blockNum & 0xff;
uData[1] = (blockNum & 0xff00) >> 8;
writeRMI(SynaF34Reflash_BlockNum, &uData[0], 2);
writeRMI(SynaF34Reflash_BlockData, puFirmwareData, SynaFirmwareBlockSize);
puFirmwareData += SynaFirmwareBlockSize;
// Issue the "Write Firmware Block" command
readRMI(SynaF34_FlashControl, &uData[0], 1);
uData[0] &= 0xf0;
uData[0] |= 0x02;
writeRMI(SynaF34_FlashControl, &uData[0], 1);
if(blockNum % 128 == 0)
printk(".");
SynaWaitATTN();
}
}
/* SynaProgramFirmware prepares the firmware writing process
*/
void SynaProgramFirmware(void)
{
unsigned char uData;
printk("Program Firmware Section...\n");
SynaReadBootloadID();
SynaWriteBootloadID();
readRMI(SynaF34_FlashControl, &uData, 1);
uData &= 0xf0;
uData |= 0x03;
writeRMI(SynaF34_FlashControl, &uData, 1);
msleep(5000);
SynaWaitATTN();
SynaFlashFirmwareWrite();
readRMI(SynaF01DataBase, &uData, 1);
printk("+++++++SynaProgramFirmware++uData:%x+++++++%s:%d\n", uData, __func__, __LINE__);
}
/* SynaBootloaderLock locks down the bootloader
*/
void SynaBootloaderLock(void)
{
unsigned short lockBlockCount;
unsigned char *puFirmwareData = SynalockImgData;
unsigned char uData[2];
unsigned short uBlockNum;
// Check if device is in unlocked state
readRMI((SynaF34QueryBase+ 2), &uData[0], 1);
//Device is unlocked
if (uData[0] & 0x02)
{
printk("Device unlocked. Lock it first...\n");
// Different bootloader version has different block count for the lockdown data
// Need to check the bootloader version from the image file being reflashed
switch (SynafirmwareImgVersion)
{
case 2:
lockBlockCount = 3;
break;
case 3:
case 4:
lockBlockCount = 4;
break;
case 5:
lockBlockCount = 5;
break;
default:
lockBlockCount = 0;
break;
}
// Write the lockdown info block by block
// This reference code of lockdown process does not check for bootloader version
// currently programmed on the ASIC against the bootloader version of the image to
// be reflashed. Such case should not happen in practice. Reflashing cross different
// bootloader versions is not supported.
for (uBlockNum = 0; uBlockNum < lockBlockCount; ++uBlockNum)
{
uData[0] = uBlockNum & 0xff;
uData[1] = (uBlockNum & 0xff00) >> 8;
/* Write Block Number */
readRMI(SynaF34Reflash_BlockNum, &uData[0], 2);
/* Write Data Block */
writeRMI(SynaF34Reflash_BlockData, puFirmwareData, SynaFirmwareBlockSize);
/* Move to next data block */
puFirmwareData += SynaFirmwareBlockSize;
/* Issue Write Lockdown Block command */
readRMI(SynaF34_FlashControl, &uData[0], 1);
uData[0] &= 0xf0;
uData[0] |= 0x04;
writeRMI(SynaF34_FlashControl, &uData[0], 1);
/* Wait ATTN until device is done writing the block and is ready for the next. */
SynaWaitATTN();
}
printk("Device locking done.\n");
// Enable reflash again to finish the lockdown process.
// Since this lockdown process is part of the reflash process, we are enabling
// reflash instead, rather than resetting the device to finish the unlock procedure.
SynaEnableFlashing();
}
else printk("Device already locked.\n");
}
/* ConfigBlockReflash reflashes the config block only
*/
void ConfigBlockReflash(void)
{
unsigned char uData[2];
convertConfigBlockData();
SynaInitialize();
SynaReadConfigInfo();
SynaReadFirmwareInfo();
SynaF34_FlashControl = SynaF34DataBase + SynaFirmwareBlockSize + 2;
SynaEnableFlashing();
SynaBootloaderLock();
// Check if device is in unlocked state
readRMI((SynaF34QueryBase + 2), &uData[0], 1);
//Device is unlocked
if (uData[0] & 0x02)
{
SynaFinalizeReflash();
return;
// Do not reflash config block if not locked.
}
eraseConfigBlock();
SynaconfigImgData = (unsigned char *)ConfigBlock;
SynaProgramConfiguration();
SynaFinalizeReflash();
}
/* eraseConfigBlock erases the config block
*/
void eraseConfigBlock(void)
{
unsigned char uData;
// Erase of config block is done by first entering into bootloader mode
SynaReadBootloadID();
SynaWriteBootloadID();
// Command 7 to erase config block
readRMI(SynaF34_FlashControl, &uData, 1);
uData &= 0xf0;
uData |= 0x07;
writeRMI(SynaF34_FlashControl, &uData, 1);
SynaWaitATTN();
}
// This function is intended to convert the config data struct output by DS4 (read config.h) into an array that
// the reflash code uses (read SynaFirmwareImage.h)
// DS4 will output the array format in the next release and this function will not be necessary
void convertConfigBlockData(void)
{
#if 0
int i = 0;
char value[32]; //hhb
for (i = 0; value[i]!=NULL; i++)
{
ConfigBlock[i] = value[i].Value;
}
#endif
}
// This function is to check the touch controller type of the touch controller matches with the firmware image
int TouchControllerTypeCheck(void)
{
unsigned char uData[4];
char buffer[4];
char controllerType[20];
int ID;
//int revision;
readRMI((SynaF01QueryBase + 43), &uData[0], 1);
if ((uData[0] & 0x0f) > 0)
{
readRMI((SynaF01QueryBase + 44), &uData[0], 1);
if (uData[0] & 0x01)
{
readRMI((SynaF01QueryBase + 17), &uData[0], 2);
ID = (int)(uData[1] & (uData[0] << 8));
sprintf(buffer, "%d", ID);
if (strstr(controllerType, TOUCH_CONTROLLER) != 0)
return true;
else
return false;
}
else
return false;
}
else
return false;
}
int fimrwareRevisionCheck(void)
{
unsigned char uData[10];
readRMI((SynaF01QueryBase + 11), uData, 10);
return strcmp(uData, FW_REVISION);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,909 @@
/*
* Copyright (c) 2011 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <linux/rmi.h>
#define COMMS_DEBUG 0
#define FF_DEBUG 0
#define RMI_PROTOCOL_VERSION_ADDRESS 0xa0fd
#define SPI_V2_UNIFIED_READ 0xc0
#define SPI_V2_WRITE 0x40
#define SPI_V2_PREPARE_SPLIT_READ 0xc8
#define SPI_V2_EXECUTE_SPLIT_READ 0xca
#define RMI_SPI_BLOCK_DELAY_US 65
#define RMI_SPI_BYTE_DELAY_US 65
#define RMI_SPI_WRITE_DELAY_US 0
#define RMI_V1_READ_FLAG 0x80
#define RMI_PAGE_SELECT_REGISTER 0x00FF
#define RMI_SPI_PAGE(addr) (((addr) >> 8) & 0x80)
#define DEFAULT_POLL_INTERVAL_MS 13
static char *spi_v1_proto_name = "spi";
static char *spi_v2_proto_name = "spiv2";
struct rmi_spi_data {
struct mutex page_mutex;
int page;
int (*set_page) (struct rmi_phys_device *phys, u8 page);
bool split_read_pending;
int enabled;
int irq;
int irq_flags;
struct rmi_phys_device *phys;
struct completion irq_comp;
/* Following are used when polling. */
struct hrtimer poll_timer;
struct work_struct poll_work;
int poll_interval;
};
static irqreturn_t rmi_spi_hard_irq(int irq, void *p)
{
struct rmi_phys_device *phys = p;
struct rmi_spi_data *data = phys->data;
struct rmi_device_platform_data *pdata = phys->dev->platform_data;
if (data->split_read_pending &&
gpio_get_value(pdata->attn_gpio) ==
pdata->attn_polarity) {
phys->info.attn_count++;
complete(&data->irq_comp);
return IRQ_HANDLED;
}
return IRQ_WAKE_THREAD;
}
static irqreturn_t rmi_spi_irq_thread(int irq, void *p)
{
struct rmi_phys_device *phys = p;
struct rmi_device *rmi_dev = phys->rmi_dev;
struct rmi_driver *driver = rmi_dev->driver;
struct rmi_device_platform_data *pdata = phys->dev->platform_data;
if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) {
phys->info.attn_count++;
if (driver && driver->irq_handler)
driver->irq_handler(rmi_dev, irq);
}
return IRQ_HANDLED;
}
static void spi_poll_work(struct work_struct *work)
{
struct rmi_spi_data *data =
container_of(work, struct rmi_spi_data, poll_work);
struct rmi_device *rmi_dev = data->phys->rmi_dev;
struct rmi_driver *driver = rmi_dev->driver;
if (driver && driver->irq_handler)
driver->irq_handler(rmi_dev, 0);
}
/* This is the timer function for polling - it simply has to schedule work
* and restart the timer. */
static enum hrtimer_restart spi_poll_timer(struct hrtimer *timer)
{
struct rmi_spi_data *data =
container_of(timer, struct rmi_spi_data, poll_timer);
if (!work_pending(&data->poll_work))
schedule_work(&data->poll_work);
hrtimer_start(&data->poll_timer, ktime_set(0, data->poll_interval),
HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
static int rmi_spi_xfer(struct rmi_phys_device *phys,
const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx)
{
struct spi_device *client = to_spi_device(phys->dev);
struct rmi_spi_data *v2_data = phys->data;
struct rmi_device_platform_data *pdata = phys->dev->platform_data;
int status;
struct spi_message message;
struct spi_transfer *xfers;
int total_bytes = n_tx + n_rx;
u8 local_buf[total_bytes];
int xfer_count = 0;
int xfer_index = 0;
int block_delay = n_rx > 0 ? pdata->spi_data.block_delay_us : 0;
int byte_delay = n_rx > 1 ? pdata->spi_data.read_delay_us : 0;
int write_delay = n_tx > 1 ? pdata->spi_data.write_delay_us : 0;
#if FF_DEBUG
bool bad_data = true;
#endif
#if COMMS_DEBUG || FF_DEBUG
int i;
#endif
if (v2_data->split_read_pending) {
block_delay =
n_rx > 0 ? pdata->spi_data.split_read_block_delay_us : 0;
byte_delay =
n_rx > 1 ? pdata->spi_data.split_read_byte_delay_us : 0;
write_delay = 0;
}
if (n_tx) {
phys->info.tx_count++;
phys->info.tx_bytes += n_tx;
if (write_delay)
xfer_count += n_tx;
else
xfer_count += 1;
}
if (n_rx) {
phys->info.rx_count++;
phys->info.rx_bytes += n_rx;
if (byte_delay)
xfer_count += n_rx;
else
xfer_count += 1;
}
xfers = kcalloc(xfer_count,
sizeof(struct spi_transfer), GFP_KERNEL);
if (!xfers)
return -ENOMEM;
spi_message_init(&message);
if (n_tx) {
if (write_delay) {
for (xfer_index = 0; xfer_index < n_tx;
xfer_index++) {
memset(&xfers[xfer_index], 0,
sizeof(struct spi_transfer));
xfers[xfer_index].len = 1;
xfers[xfer_index].delay_usecs = write_delay;
xfers[xfer_index].tx_buf = txbuf + xfer_index;
spi_message_add_tail(&xfers[xfer_index],
&message);
}
} else {
memset(&xfers[0], 0, sizeof(struct spi_transfer));
xfers[0].len = n_tx;
spi_message_add_tail(&xfers[0], &message);
memcpy(local_buf, txbuf, n_tx);
xfers[0].tx_buf = local_buf;
xfer_index++;
}
if (block_delay)
xfers[xfer_index-1].delay_usecs = block_delay;
}
if (n_rx) {
if (byte_delay) {
int buffer_offset = n_tx;
for (; xfer_index < xfer_count; xfer_index++) {
memset(&xfers[xfer_index], 0,
sizeof(struct spi_transfer));
xfers[xfer_index].len = 1;
xfers[xfer_index].delay_usecs = byte_delay;
xfers[xfer_index].rx_buf =
local_buf + buffer_offset;
buffer_offset++;
spi_message_add_tail(&xfers[xfer_index],
&message);
}
} else {
memset(&xfers[xfer_index], 0,
sizeof(struct spi_transfer));
xfers[xfer_index].len = n_rx;
xfers[xfer_index].rx_buf = local_buf + n_tx;
spi_message_add_tail(&xfers[xfer_index], &message);
xfer_index++;
}
}
#if COMMS_DEBUG
if (n_tx) {
dev_dbg(&client->dev, "SPI sends %d bytes: ", n_tx);
for (i = 0; i < n_tx; i++)
pr_info("%02X ", txbuf[i]);
pr_info("\n");
}
#endif
/* do the i/o */
if (pdata->spi_data.cs_assert) {
status = pdata->spi_data.cs_assert(
pdata->spi_data.cs_assert_data, true);
if (status) {
dev_err(phys->dev, "Failed to assert CS, code %d.\n",
status);
/* nonzero means error */
status = -1;
goto error_exit;
} else
status = 0;
}
if (pdata->spi_data.pre_delay_us)
udelay(pdata->spi_data.pre_delay_us);
status = spi_sync(client, &message);
if (pdata->spi_data.post_delay_us)
udelay(pdata->spi_data.post_delay_us);
if (pdata->spi_data.cs_assert) {
status = pdata->spi_data.cs_assert(
pdata->spi_data.cs_assert_data, false);
if (status) {
dev_err(phys->dev, "Failed to deassert CS. code %d.\n",
status);
/* nonzero means error */
status = -1;
goto error_exit;
} else
status = 0;
}
if (status == 0) {
memcpy(rxbuf, local_buf + n_tx, n_rx);
status = message.status;
} else {
if (n_tx) phys->info.tx_errs++;
if (n_rx) phys->info.rx_errs++;
dev_err(phys->dev, "spi_sync failed with error code %d.",
status);
goto error_exit;
}
#if COMMS_DEBUG
if (n_rx) {
dev_dbg(&client->dev, "SPI received %d bytes: ", n_rx);
for (i = 0; i < n_rx; i++)
pr_info("%02X ", rxbuf[i]);
pr_info("\n");
}
#endif
#if FF_DEBUG
if (n_rx) {
for (i = 0; i < n_rx; i++) {
if (rxbuf[i] != 0xFF) {
bad_data = false;
break;
}
}
if (bad_data) {
phys->info.rx_errs++;
dev_err(phys->dev, "BAD READ %lu out of %lu.\n",
phys->info.rx_errs, phys->info.rx_count);
}
}
#endif
error_exit:
kfree(xfers);
return status;
}
static int rmi_spi_v2_write_block(struct rmi_phys_device *phys, u16 addr,
u8 *buf, int len)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[len + 4];
int error;
txbuf[0] = SPI_V2_WRITE;
txbuf[1] = (addr >> 8) & 0x00FF;
txbuf[2] = addr & 0x00FF;
txbuf[3] = len;
memcpy(&txbuf[4], buf, len);
mutex_lock(&data->page_mutex);
if (RMI_SPI_PAGE(addr) != data->page) {
error = data->set_page(phys, RMI_SPI_PAGE(addr));
if (error < 0)
goto exit;
}
error = rmi_spi_xfer(phys, buf, len + 4, NULL, 0);
if (error < 0)
goto exit;
error = len;
exit:
mutex_unlock(&data->page_mutex);
return error;
}
static int rmi_spi_v2_write(struct rmi_phys_device *phys, u16 addr, u8 data)
{
int error = rmi_spi_v2_write_block(phys, addr, &data, 1);
return (error == 1) ? 0 : error;
}
static int rmi_spi_v1_write_block(struct rmi_phys_device *phys, u16 addr,
u8 *buf, int len)
{
struct rmi_spi_data *data = phys->data;
unsigned char txbuf[len + 2];
int error;
txbuf[0] = (addr >> 8) & ~RMI_V1_READ_FLAG;
txbuf[1] = addr;
memcpy(txbuf+2, buf, len);
mutex_lock(&data->page_mutex);
if (RMI_SPI_PAGE(addr) != data->page) {
error = data->set_page(phys, RMI_SPI_PAGE(addr));
if (error < 0)
goto exit;
}
error = rmi_spi_xfer(phys, txbuf, len + 2, NULL, 0);
if (error < 0)
goto exit;
error = len;
exit:
mutex_unlock(&data->page_mutex);
return error;
}
static int rmi_spi_v1_write(struct rmi_phys_device *phys, u16 addr, u8 data)
{
int error = rmi_spi_v1_write_block(phys, addr, &data, 1);
return (error == 1) ? 0 : error;
}
static int rmi_spi_v2_split_read_block(struct rmi_phys_device *phys, u16 addr,
u8 *buf, int len)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[4];
u8 rxbuf[len + 1]; /* one extra byte for read length */
int error;
txbuf[0] = SPI_V2_PREPARE_SPLIT_READ;
txbuf[1] = (addr >> 8) & 0x00FF;
txbuf[2] = addr & 0x00ff;
txbuf[3] = len;
mutex_lock(&data->page_mutex);
if (RMI_SPI_PAGE(addr) != data->page) {
error = data->set_page(phys, RMI_SPI_PAGE(addr));
if (error < 0)
goto exit;
}
data->split_read_pending = true;
error = rmi_spi_xfer(phys, txbuf, 4, NULL, 0);
if (error < 0) {
data->split_read_pending = false;
goto exit;
}
wait_for_completion(&data->irq_comp);
txbuf[0] = SPI_V2_EXECUTE_SPLIT_READ;
txbuf[1] = 0;
error = rmi_spi_xfer(phys, txbuf, 2, rxbuf, len + 1);
data->split_read_pending = false;
if (error < 0)
goto exit;
/* first byte is length */
if (rxbuf[0] != len) {
error = -EIO;
goto exit;
}
memcpy(buf, rxbuf + 1, len);
error = len;
exit:
mutex_unlock(&data->page_mutex);
return error;
}
static int rmi_spi_v2_read_block(struct rmi_phys_device *phys, u16 addr,
u8 *buf, int len)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[4];
int error;
txbuf[0] = SPI_V2_UNIFIED_READ;
txbuf[1] = (addr >> 8) & 0x00FF;
txbuf[2] = addr & 0x00ff;
txbuf[3] = len;
mutex_lock(&data->page_mutex);
if (RMI_SPI_PAGE(addr) != data->page) {
error = data->set_page(phys, RMI_SPI_PAGE(addr));
if (error < 0)
goto exit;
}
error = rmi_spi_xfer(phys, txbuf, 4, buf, len);
if (error < 0)
goto exit;
error = len;
exit:
mutex_unlock(&data->page_mutex);
return error;
}
static int rmi_spi_v2_read(struct rmi_phys_device *phys, u16 addr, u8 *buf)
{
int error = rmi_spi_v2_read_block(phys, addr, buf, 1);
return (error == 1) ? 0 : error;
}
static int rmi_spi_v1_read_block(struct rmi_phys_device *phys, u16 addr,
u8 *buf, int len)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[2];
int error;
txbuf[0] = (addr >> 8) | RMI_V1_READ_FLAG;
txbuf[1] = addr;
mutex_lock(&data->page_mutex);
if (RMI_SPI_PAGE(addr) != data->page) {
error = data->set_page(phys, RMI_SPI_PAGE(addr));
if (error < 0)
goto exit;
}
error = rmi_spi_xfer(phys, txbuf, 2, buf, len);
if (error < 0)
goto exit;
error = len;
exit:
mutex_unlock(&data->page_mutex);
return error;
}
static int rmi_spi_v1_read(struct rmi_phys_device *phys, u16 addr, u8 *buf)
{
int error = rmi_spi_v1_read_block(phys, addr, buf, 1);
return (error == 1) ? 0 : error;
}
#define RMI_SPI_PAGE_SELECT_WRITE_LENGTH 1
static int rmi_spi_v1_set_page(struct rmi_phys_device *phys, u8 page)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[] = {RMI_PAGE_SELECT_REGISTER >> 8,
RMI_PAGE_SELECT_REGISTER & 0xFF, page};
int error;
error = rmi_spi_xfer(phys, txbuf, sizeof(txbuf), NULL, 0);
if (error < 0) {
dev_err(phys->dev, "Failed to set page select, code: %d.\n",
error);
return error;
}
data->page = page;
return RMI_SPI_PAGE_SELECT_WRITE_LENGTH;
}
static int rmi_spi_v2_set_page(struct rmi_phys_device *phys, u8 page)
{
struct rmi_spi_data *data = phys->data;
u8 txbuf[] = {SPI_V2_WRITE, RMI_PAGE_SELECT_REGISTER >> 8,
RMI_PAGE_SELECT_REGISTER & 0xFF,
RMI_SPI_PAGE_SELECT_WRITE_LENGTH, page};
int error;
error = rmi_spi_xfer(phys, txbuf, sizeof(txbuf), NULL, 0);
if (error < 0) {
dev_err(phys->dev, "Failed to set page select, code: %d.\n",
error);
return error;
}
data->page = page;
return RMI_SPI_PAGE_SELECT_WRITE_LENGTH;
}
static int acquire_attn_irq(struct rmi_spi_data *data)
{
int retval;
struct rmi_phys_device *rmi_phys = data->phys;
retval = request_threaded_irq(data->irq, rmi_spi_hard_irq,
rmi_spi_irq_thread, data->irq_flags,
dev_name(rmi_phys->dev), rmi_phys);
if (retval < 0) {
dev_err(&(rmi_phys->rmi_dev->dev), "request_threaded_irq "
"failed, code: %d.\n", retval);
}
return retval;
}
static int setup_attn(struct rmi_spi_data *data)
{
int retval;
struct rmi_phys_device *rmi_phys = data->phys;
struct rmi_device_platform_data *pdata = rmi_phys->dev->platform_data;
retval = acquire_attn_irq(data);
if (retval < 0)
return retval;
#if defined(CONFIG_RMI4_DEV)
retval = gpio_export(pdata->attn_gpio, false);
if (retval) {
dev_warn(&(rmi_phys->rmi_dev->dev),
"WARNING: Failed to export ATTN gpio!\n");
retval = 0;
} else {
retval = gpio_export_link(&(rmi_phys->rmi_dev->dev), "attn",
pdata->attn_gpio);
if (retval) {
dev_warn(&(rmi_phys->rmi_dev->dev), "WARNING: "
"Failed to symlink ATTN gpio!\n");
retval = 0;
} else {
dev_info(&(rmi_phys->rmi_dev->dev),
"%s: Exported GPIO %d.", __func__,
pdata->attn_gpio);
}
}
#endif /* CONFIG_RMI4_DEV */
return retval;
}
static int setup_polling(struct rmi_spi_data *data)
{
INIT_WORK(&data->poll_work, spi_poll_work);
hrtimer_init(&data->poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
data->poll_timer.function = spi_poll_timer;
hrtimer_start(&data->poll_timer, ktime_set(1, 0), HRTIMER_MODE_REL);
return 0;
}
static int enable_device(struct rmi_phys_device *phys)
{
int retval = 0;
struct rmi_spi_data *data = phys->data;
if (data->enabled) {
dev_dbg(phys->dev, "Physical device already enabled.\n");
return 0;
}
retval = acquire_attn_irq(data);
if (retval)
goto error_exit;
data->enabled = true;
dev_dbg(phys->dev, "Physical device enabled.\n");
return 0;
error_exit:
dev_err(phys->dev, "Failed to enable physical device. Code=%d.\n",
retval);
return retval;
}
static void disable_device(struct rmi_phys_device *phys)
{
struct rmi_spi_data *data = phys->data;
if (!data->enabled) {
dev_warn(phys->dev, "Physical device already disabled.\n");
return;
}
disable_irq(data->irq);
free_irq(data->irq, data->phys);
dev_dbg(phys->dev, "Physical device disabled.\n");
data->enabled = false;
}
#define DUMMY_READ_SLEEP_US 10
static int rmi_spi_check_device(struct rmi_phys_device *rmi_phys)
{
u8 buf[6];
int error;
int i;
/* Some SPI subsystems return 0 for the very first read you do. So
* we use this dummy read to get that out of the way.
*/
error = rmi_spi_v1_read_block(rmi_phys, PDT_START_SCAN_LOCATION,
buf, sizeof(buf));
if (error < 0) {
dev_err(rmi_phys->dev, "dummy read failed with %d.\n", error);
return error;
}
udelay(DUMMY_READ_SLEEP_US);
/* Force page select to 0.
*/
error = rmi_spi_v1_set_page(rmi_phys, 0x00);
if (error < 0)
return error;
/* Now read the first PDT entry. We know where this is, and if the
* RMI4 device is out there, these 6 bytes will be something other
* than all 0x00 or 0xFF. We need to check for 0x00 and 0xFF,
* because many (maybe all) SPI implementations will return all 0x00
* or all 0xFF on read if the device is not connected.
*/
error = rmi_spi_v1_read_block(rmi_phys, PDT_START_SCAN_LOCATION,
buf, sizeof(buf));
if (error < 0) {
dev_err(rmi_phys->dev, "probe read failed with %d.\n", error);
return error;
}
for (i = 0; i < sizeof(buf); i++) {
if (buf[i] != 0x00 && buf[i] != 0xFF)
return error;
}
dev_err(rmi_phys->dev, "probe read returned invalid block.\n");
return -ENODEV;
}
static int __devinit rmi_spi_probe(struct spi_device *spi)
{
struct rmi_phys_device *rmi_phys;
struct rmi_spi_data *data;
struct rmi_device_platform_data *pdata = spi->dev.platform_data;
u8 buf[2];
int retval;
if (!pdata) {
dev_err(&spi->dev, "no platform data\n");
return -EINVAL;
}
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
return -EINVAL;
spi->bits_per_word = 8;
spi->mode = SPI_MODE_3;
retval = spi_setup(spi);
if (retval < 0) {
dev_err(&spi->dev, "spi_setup failed!\n");
return retval;
}
rmi_phys = kzalloc(sizeof(struct rmi_phys_device), GFP_KERNEL);
if (!rmi_phys)
return -ENOMEM;
data = kzalloc(sizeof(struct rmi_spi_data), GFP_KERNEL);
if (!data) {
retval = -ENOMEM;
goto err_phys;
}
data->enabled = true; /* We plan to come up enabled. */
data->irq = gpio_to_irq(pdata->attn_gpio);
if (pdata->level_triggered) {
data->irq_flags = IRQF_ONESHOT |
((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ?
IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW);
} else {
data->irq_flags =
(pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
}
data->phys = rmi_phys;
rmi_phys->data = data;
rmi_phys->dev = &spi->dev;
rmi_phys->write = rmi_spi_v1_write;
rmi_phys->write_block = rmi_spi_v1_write_block;
rmi_phys->read = rmi_spi_v1_read;
rmi_phys->read_block = rmi_spi_v1_read_block;
rmi_phys->enable_device = enable_device;
rmi_phys->disable_device = disable_device;
data->set_page = rmi_spi_v1_set_page;
rmi_phys->info.proto = spi_v1_proto_name;
mutex_init(&data->page_mutex);
dev_set_drvdata(&spi->dev, rmi_phys);
pdata->spi_data.block_delay_us = pdata->spi_data.block_delay_us ?
pdata->spi_data.block_delay_us : RMI_SPI_BLOCK_DELAY_US;
pdata->spi_data.read_delay_us = pdata->spi_data.read_delay_us ?
pdata->spi_data.read_delay_us : RMI_SPI_BYTE_DELAY_US;
pdata->spi_data.write_delay_us = pdata->spi_data.write_delay_us ?
pdata->spi_data.write_delay_us : RMI_SPI_BYTE_DELAY_US;
pdata->spi_data.split_read_block_delay_us =
pdata->spi_data.split_read_block_delay_us ?
pdata->spi_data.split_read_block_delay_us :
RMI_SPI_BLOCK_DELAY_US;
pdata->spi_data.split_read_byte_delay_us =
pdata->spi_data.split_read_byte_delay_us ?
pdata->spi_data.split_read_byte_delay_us :
RMI_SPI_BYTE_DELAY_US;
if (pdata->gpio_config) {
retval = pdata->gpio_config(pdata->gpio_data, true);
if (retval < 0) {
dev_err(&spi->dev, "Failed to setup GPIOs, code: %d.\n",
retval);
goto err_data;
}
}
retval = rmi_spi_check_device(rmi_phys);
if (retval < 0)
goto err_gpio;
/* check if this is an SPI v2 device */
retval = rmi_spi_v1_read_block(rmi_phys, RMI_PROTOCOL_VERSION_ADDRESS,
buf, 2);
if (retval < 0) {
dev_err(&spi->dev, "failed to get SPI version number!\n");
goto err_gpio;
}
dev_dbg(&spi->dev, "SPI version is %d", buf[0]);
if (buf[0] == 1) {
/* SPIv2 */
rmi_phys->write = rmi_spi_v2_write;
rmi_phys->write_block = rmi_spi_v2_write_block;
rmi_phys->read = rmi_spi_v2_read;
data->set_page = rmi_spi_v2_set_page;
rmi_phys->info.proto = spi_v2_proto_name;
if (pdata->attn_gpio > 0) {
init_completion(&data->irq_comp);
rmi_phys->read_block = rmi_spi_v2_split_read_block;
} else {
dev_warn(&spi->dev, "WARNING: SPI V2 detected, but no "
"attention GPIO was specified. This is unlikely"
" to work well.\n");
rmi_phys->read_block = rmi_spi_v2_read_block;
}
} else if (buf[0] != 0) {
dev_err(&spi->dev, "Unrecognized SPI version %d.\n", buf[0]);
retval = -ENODEV;
goto err_gpio;
}
retval = rmi_register_phys_device(rmi_phys);
if (retval) {
dev_err(&spi->dev, "failed to register physical driver\n");
goto err_gpio;
}
if (pdata->attn_gpio > 0) {
retval = setup_attn(data);
if (retval < 0)
goto err_unregister;
} else {
retval = setup_polling(data);
if (retval < 0)
goto err_unregister;
}
dev_info(&spi->dev, "registered RMI SPI driver\n");
return 0;
err_unregister:
rmi_unregister_phys_device(rmi_phys);
err_gpio:
if (pdata->gpio_config)
pdata->gpio_config(pdata->gpio_data, false);
err_data:
kfree(data);
err_phys:
kfree(rmi_phys);
return retval;
}
static int __devexit rmi_spi_remove(struct spi_device *spi)
{
struct rmi_phys_device *phys = dev_get_drvdata(&spi->dev);
struct rmi_device_platform_data *pd = spi->dev.platform_data;
disable_device(phys);
rmi_unregister_phys_device(phys);
kfree(phys->data);
kfree(phys);
if (pd->gpio_config)
pd->gpio_config(pdata->gpio_data, false);
return 0;
}
static const struct spi_device_id rmi_id[] = {
{ "rmi", 0 },
{ "rmi_spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, rmi_id);
static struct spi_driver rmi_spi_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "rmi_spi",
},
.id_table = rmi_id,
.probe = rmi_spi_probe,
.remove = __devexit_p(rmi_spi_remove),
};
static int __init rmi_spi_init(void)
{
return spi_register_driver(&rmi_spi_driver);
}
static void __exit rmi_spi_exit(void)
{
spi_unregister_driver(&rmi_spi_driver);
}
module_init(rmi_spi_init);
module_exit(rmi_spi_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_DESCRIPTION("RMI SPI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

609
include/linux/rmi.h Executable file
View File

@ -0,0 +1,609 @@
/*
* Copyright (c) 2011 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _RMI_H
#define _RMI_H
#include <linux/kernel.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/stat.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#ifdef CONFIG_RMI_DEBUG
#include <linux/debugfs.h>
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
/* Permissions for sysfs attributes. Since the permissions policy will change
* on a global basis in the future, rather than edit all sysfs attrs everywhere
* in the driver (and risk screwing that up in the process), we use this handy
* set of #defines. That way when we change the policy for sysfs permissions,
* we only need to change them here.
*/
#define RMI_RO_ATTR S_IRUGO
#define RMI_RW_ATTR (S_IRUGO | S_IWUGO)
#define RMI_WO_ATTR S_IWUGO
#define PDT_START_SCAN_LOCATION 0x00e9
enum rmi_attn_polarity {
RMI_ATTN_ACTIVE_LOW = 0,
RMI_ATTN_ACTIVE_HIGH = 1
};
/**
* struct rmi_f11_axis_alignment - target axis alignment
* @swap_axes: set to TRUE if desired to swap x- and y-axis
* @flip_x: set to TRUE if desired to flip direction on x-axis
* @flip_y: set to TRUE if desired to flip direction on y-axis
*/
struct rmi_f11_2d_axis_alignment {
bool swap_axes;
bool flip_x;
bool flip_y;
int clip_X_low;
int clip_Y_low;
int clip_X_high;
int clip_Y_high;
int offset_X;
int offset_Y;
int rel_report_enabled;
};
/**
* struct rmi_f01_power - override default power management settings.
*
*/
enum rmi_f01_nosleep {
RMI_F01_NOSLEEP_DEFAULT = 0,
RMI_F01_NOSLEEP_OFF = 1,
RMI_F01_NOSLEEP_ON = 2
};
struct rmi_f01_power_management {
enum rmi_f01_nosleep nosleep;
u8 wakeup_threshold;
u8 doze_holdoff;
u8 doze_interval;
};
struct rmi_f19_button_map {
unsigned char nbuttons;
unsigned char *map;
};
struct rmi_f1a_button_map {
unsigned char nbuttons;
unsigned char *map;
};
struct virtualbutton_map {
u16 x;
u16 y;
u16 width;
u16 height;
u16 code;
};
struct rmi_f11_virtualbutton_map {
u8 buttons;
struct virtualbutton_map *map;
};
struct rmi_device_platform_data_spi {
int block_delay_us;
int split_read_block_delay_us;
int read_delay_us;
int write_delay_us;
int split_read_byte_delay_us;
int pre_delay_us;
int post_delay_us;
void *cs_assert_data;
int (*cs_assert) (const void *cs_assert_data, const bool assert);
};
struct rmi_device_platform_data {
char *driver_name;
char *sensor_name; /* Used for diagnostics. */
int attn_gpio;
enum rmi_attn_polarity attn_polarity;
bool level_triggered;
void *gpio_data;
int (*gpio_config)(void *gpio_data, bool configure);
int reset_delay_ms;
struct rmi_device_platform_data_spi spi_data;
/* function handler pdata */
struct rmi_f01_power_management power_management;
struct rmi_f11_2d_axis_alignment axis_align;
struct rmi_f19_button_map *button_map;
struct rmi_f1a_button_map *f1a_button_map;
struct rmi_f11_virtualbutton_map *virtualbutton_map;
int (*init_hw)(void);
#ifdef CONFIG_PM
void *pm_data;
int (*pre_suspend) (const void *pm_data);
int (*post_resume) (const void *pm_data);
#endif
};
/**
* struct rmi_function_descriptor - RMI function base addresses
* @query_base_addr: The RMI Query base address
* @command_base_addr: The RMI Command base address
* @control_base_addr: The RMI Control base address
* @data_base_addr: The RMI Data base address
* @interrupt_source_count: The number of irqs this RMI function needs
* @function_number: The RMI function number
*
* This struct is used when iterating the Page Description Table. The addresses
* are 16-bit values to include the current page address.
*
*/
struct rmi_function_descriptor {
u16 query_base_addr;
u16 command_base_addr;
u16 control_base_addr;
u16 data_base_addr;
u8 interrupt_source_count;
u8 function_number;
u8 function_version;
};
struct rmi_function_container;
struct rmi_device;
/**
* struct rmi_function_handler - an RMI function handler
* @func: The RMI function number
* @init: Callback for RMI function init
* @attention: Callback for RMI function attention
* @suspend: Callback for function suspend, returns 0 for success.
* @resume: Callback for RMI function resume, returns 0 for success.
* @remove: Callback for RMI function removal
*
* This struct describes the interface of an RMI function. These are
* registered to the bus using the rmi_register_function_driver() call.
*
*/
struct rmi_function_handler {
int func;
int (*init)(struct rmi_function_container *fc);
int (*config)(struct rmi_function_container *fc);
int (*reset)(struct rmi_function_container *fc);
int (*attention)(struct rmi_function_container *fc, u8 *irq_bits);
#ifdef CONFIG_PM
int (*suspend)(struct rmi_function_container *fc);
int (*resume)(struct rmi_function_container *fc);
#ifdef CONFIG_HAS_EARLYSUSPEND
int (*early_suspend)(struct rmi_function_container *fc);
int (*late_resume)(struct rmi_function_container *fc);
#endif
#endif
void (*remove)(struct rmi_function_container *fc);
};
/**
* struct rmi_function_container - an element in a function handler list
* @list: The list
* @fd: The function descriptor of the RMI function
* @rmi_dev: Pointer to the RMI device associated with this function container
* @fh: The callbacks connected to this function
* @num_of_irqs: The number of irqs needed by this function
* @irq_pos: The position in the irq bitfield this function holds
* @data: Private data pointer
*
*/
struct rmi_function_container {
struct list_head list;
struct rmi_function_descriptor fd;
struct rmi_device *rmi_dev;
struct rmi_function_handler *fh;
struct device dev;
#ifdef CONFIG_RMI4_DEBUG
struct dentry *debugfs_root;
#endif
int num_of_irqs;
int irq_pos;
u8 *irq_mask;
void *data;
};
#define to_rmi_function_container(d) \
container_of(d, struct rmi_function_container, dev);
/**
* struct rmi_driver - represents an RMI driver
* @driver: Device driver model driver
* @probe: Callback for device probe
* @remove: Callback for device removal
* @shutdown: Callback for device shutdown
* @irq_handler: Callback for handling irqs
* @fh_add: Callback for function handler add
* @fh_remove: Callback for function handler remove
* @get_func_irq_mask: Callback for calculating interrupt mask
* @store_irq_mask: Callback for storing and replacing interrupt mask
* @restore_irq_mask: Callback for restoring previously stored interrupt mask
* @data: Private data pointer
*
* The RMI driver implements a driver on the RMI bus.
*
*/
struct rmi_driver {
struct device_driver driver;
int (*probe)(struct rmi_device *rmi_dev);
int (*remove)(struct rmi_device *rmi_dev);
void (*shutdown)(struct rmi_device *rmi_dev);
int (*irq_handler)(struct rmi_device *rmi_dev, int irq);
int (*reset_handler)(struct rmi_device *rmi_dev);
void (*fh_add)(struct rmi_device *rmi_dev,
struct rmi_function_handler *fh);
void (*fh_remove)(struct rmi_device *rmi_dev,
struct rmi_function_handler *fh);
u8* (*get_func_irq_mask)(struct rmi_device *rmi_dev,
struct rmi_function_container *fc);
int (*store_irq_mask)(struct rmi_device *rmi_dev, u8* new_interupts);
int (*restore_irq_mask)(struct rmi_device *rmi_dev);
void *data;
};
#define to_rmi_driver(d) \
container_of(d, struct rmi_driver, driver);
/** struct rmi_phys_info - diagnostic information about the RMI physical
* device, used in the phys sysfs file.
* @proto String indicating the protocol being used.
* @tx_count Number of transmit operations.
* @tx_bytes Number of bytes transmitted.
* @tx_errs Number of errors encountered during transmit operations.
* @rx_count Number of receive operations.
* @rx_bytes Number of bytes received.
* @rx_errs Number of errors encountered during receive operations.
* @att_count Number of times ATTN assertions have been handled.
*/
struct rmi_phys_info {
char *proto;
long tx_count;
long tx_bytes;
long tx_errs;
long rx_count;
long rx_bytes;
long rx_errs;
long attn_count;
};
/**
* struct rmi_phys_device - represent an RMI physical device
* @dev: Pointer to the communication device, e.g. i2c or spi
* @rmi_dev: Pointer to the RMI device
* @write: Callback for write
* @write_block: Callback for writing a block of data
* @read: Callback for read
* @read_block: Callback for reading a block of data
* @data: Private data pointer
*
* The RMI physical device implements the glue between different communication
* buses such as I2C and SPI.
*
*/
struct rmi_phys_device {
struct device *dev;
struct rmi_device *rmi_dev;
int (*write)(struct rmi_phys_device *phys, u16 addr, u8 data);
int (*write_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len);
int (*read)(struct rmi_phys_device *phys, u16 addr, u8 *buf);
int (*read_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf,
int len);
int (*enable_device) (struct rmi_phys_device *phys);
void (*disable_device) (struct rmi_phys_device *phys);
void *data;
struct rmi_phys_info info;
};
/**
* struct rmi_device - represents an RMI device
* @dev: The device created for the RMI bus
* @number: Unique number for the device on the bus.
* @driver: Pointer to associated driver
* @phys: Pointer to the physical interface
* @early_suspend_handler: Pointers to early_suspend and late_resume, if
* configured.
*
* This structs represent an RMI device.
*
*/
struct rmi_device {
struct device dev;
int number;
struct rmi_driver *driver;
struct rmi_phys_device *phys;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend_handler;
#endif
#ifdef CONFIG_RMI4_DEBUG
struct dentry *debugfs_root;
#endif
};
#define to_rmi_device(d) container_of(d, struct rmi_device, dev);
#define to_rmi_platform_data(d) ((d)->phys->dev->platform_data);
static inline void rmi_set_driverdata(struct rmi_device *d, void *data)
{
dev_set_drvdata(&d->dev, data);
}
static inline void *rmi_get_driverdata(struct rmi_device *d)
{
return dev_get_drvdata(&d->dev);
}
/**
* rmi_read - RMI read byte
* @d: Pointer to an RMI device
* @addr: The address to read from
* @buf: The read buffer
*
* Reads a byte of data using the underlaying physical protocol in to buf. It
* returns zero or a negative error code.
*/
static inline int rmi_read(struct rmi_device *d, u16 addr, u8 *buf)
{
return d->phys->read(d->phys, addr, buf);
}
/**
* rmi_read_block - RMI read block
* @d: Pointer to an RMI device
* @addr: The start address to read from
* @buf: The read buffer
* @len: Length of the read buffer
*
* Reads a block of byte data using the underlaying physical protocol in to buf.
* It returns the amount of bytes read or a negative error code.
*/
static inline int rmi_read_block(struct rmi_device *d, u16 addr, u8 *buf,
int len)
{
return d->phys->read_block(d->phys, addr, buf, len);
}
/**
* rmi_write - RMI write byte
* @d: Pointer to an RMI device
* @addr: The address to write to
* @data: The data to write
*
* Writes a byte from buf using the underlaying physical protocol. It
* returns zero or a negative error code.
*/
static inline int rmi_write(struct rmi_device *d, u16 addr, u8 data)
{
return d->phys->write(d->phys, addr, data);
}
/**
* rmi_write_block - RMI write block
* @d: Pointer to an RMI device
* @addr: The start address to write to
* @buf: The write buffer
* @len: Length of the write buffer
*
* Writes a block of byte data from buf using the underlaying physical protocol.
* It returns the amount of bytes written or a negative error code.
*/
static inline int rmi_write_block(struct rmi_device *d, u16 addr, u8 *buf,
int len)
{
return d->phys->write_block(d->phys, addr, buf, len);
}
/**
* rmi_register_driver - register rmi driver
* @driver: the driver to register
*
* This function registers an RMI driver to the RMI bus.
*/
int rmi_register_driver(struct rmi_driver *driver);
/**
* rmi_unregister_driver - unregister rmi driver
* @driver: the driver to unregister
*
* This function unregisters an RMI driver to the RMI bus.
*/
void rmi_unregister_driver(struct rmi_driver *driver);
/**
* rmi_register_phys_device - register a physical device connection
* @phys: the physical driver to register
*
* This function registers a physical driver to the RMI bus. These drivers
* provide a communication layer for the drivers connected to the bus, e.g.
* I2C, SPI and so on.
*/
int rmi_register_phys_device(struct rmi_phys_device *phys);
/**
* rmi_unregister_phys_device - unregister a physical device connection
* @phys: the physical driver to unregister
*
* This function unregisters a physical driver from the RMI bus.
*/
void rmi_unregister_phys_device(struct rmi_phys_device *phys);
/**
* rmi_register_function_driver - register an RMI function driver
* @fh: the function handler to register
*
* This function registers support for a new RMI function to the bus. All
* drivers on the bus will be notified of the presence of the new function
* driver.
*/
int rmi_register_function_driver(struct rmi_function_handler *fh);
/**
* rmi_unregister_function_driver - unregister an RMI function driver
* @fh: the function handler to unregister
*
* This function unregisters a RMI function from the RMI bus. All drivers on
* the bus will be notified of the removal of a function driver.
*/
void rmi_unregister_function_driver(struct rmi_function_handler *fh);
/**
* rmi_get_function_handler - get a pointer to specified RMI function
* @id: the RMI function id
*
* This function gets the specified RMI function handler from the list of
* supported functions.
*/
struct rmi_function_handler *rmi_get_function_handler(int id);
struct rmi_char_device;
/**
* rmi_char_driver - a general driver that doesn't handle specific functions,
* operating outside the bus::sensor::functions
* @match: returns 1 if the driver wants to talk to the specified rmi_dev.
*
* All of the above are optional except driver and init which are required.
*
*/
struct rmi_char_driver {
struct device_driver driver;
int (*match)(struct rmi_device *rmi_dev);
int (*init)(struct rmi_char_device *cd);
int (*attention)(struct rmi_char_device *cd, u8 *irq_bits);
#ifdef CONFIG_PM
int (*suspend)(struct rmi_char_device *cd);
int (*resume)(struct rmi_char_device *cd);
#ifdef CONFIG_HAS_EARLYSUSPEND
int (*early_suspend)(struct rmi_char_device *cd);
int (*late_resume)(struct rmi_char_device *cd);
#endif
#endif
void (*remove)(struct rmi_char_device *cd);
struct list_head devices;
};
struct rmi_char_device {
struct list_head list;
struct rmi_device *rmi_dev;
struct rmi_char_driver *driver;
struct device dev;
#ifdef CONFIG_RMI4_DEBUG
struct dentry *debugfs_root;
#endif
void *data;
};
#define to_rmi_char_device(d) \
container_of(d, struct rmi_char_device, dev)
int rmi_register_character_driver(struct rmi_char_driver *char_driver);
int rmi_unregister_character_driver(struct rmi_char_driver *char_driver);
/* Helper fn to convert a byte array representing a short in the RMI
* endian-ness to a short in the native processor's specific endianness.
* We don't use ntohs/htons here because, well, we're not dealing with
* a pair of shorts. And casting dest to short* wouldn't work, because
* that would imply knowing the byte order of short in the first place.
*/
static inline void batohs(unsigned short *dest, unsigned char *src)
{
*dest = src[1] * 0x100 + src[0];
}
/* Helper function to convert a short (in host processor endianess) to
* a byte array in the RMI endianess for shorts. See above comment for
* why we dont us htons or something like that.
*/
static inline void hstoba(unsigned char *dest, unsigned short src)
{
dest[0] = src % 0x100;
dest[1] = src / 0x100;
}
/* Utility routine to handle writes to read-only attributes. Hopefully
* this will never happen, but if the user does something stupid, we don't
* want to accept it quietly (which is what can happen if you just put NULL
* for the attribute's store function).
*/
static inline ssize_t rmi_store_error(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
dev_warn(dev,
"RMI4 WARNING: Attempt to write %d characters to read-only "
"attribute %s.", count, attr->attr.name);
return -EPERM;
}
/* Utility routine to handle reads of write-only attributes. Hopefully
* this will never happen, but if the user does something stupid, we don't
* want to accept it quietly (which is what can happen if you just put NULL
* for the attribute's show function).
*/
static inline ssize_t rmi_show_error(struct device *dev,
struct device_attribute *attr,
char *buf)
{
dev_warn(dev,
"RMI4 WARNING: Attempt to read from write-only attribute %s.",
attr->attr.name);
return -EPERM;
}
/* utility function for bit access of u8*'s */
void u8_set_bit(u8 *target, int pos);
void u8_clear_bit(u8 *target, int pos);
bool u8_is_set(u8 *target, int pos);
bool u8_is_any_set(u8 *target, int size);
void u8_or(u8 *dest, u8* target1, u8* target2, int size);
void u8_and(u8 *dest, u8* target1, u8* target2, int size);
#endif