663 lines
20 KiB
C
663 lines
20 KiB
C
/**
|
|
* Synaptics Register Mapped Interface (RMI4) - RMI Sensor Module.
|
|
* Copyright (C) 2007 - 2011, Synaptics Incorporated
|
|
*
|
|
*/
|
|
/*
|
|
* This file is licensed under the GPL2 license.
|
|
*
|
|
*############################################################################
|
|
* GPL
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published
|
|
* by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
*############################################################################
|
|
*/
|
|
|
|
static const char sensorname[] = "sensor";
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/list.h>
|
|
#include <linux/device.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/input.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
|
|
|
|
#include "rmi_drvr.h"
|
|
#include "rmi_bus.h"
|
|
#include "rmi_function.h"
|
|
#include "rmi_sensor.h"
|
|
|
|
long polltime = 25000000; /* Shared with rmi_function.c. */
|
|
EXPORT_SYMBOL(polltime);
|
|
module_param(polltime, long, 0644);
|
|
MODULE_PARM_DESC(polltime, "How long to wait between polls (in nano seconds).");
|
|
|
|
|
|
#define PDT_START_SCAN_LOCATION 0x00E9
|
|
#define PDT_END_SCAN_LOCATION 0x0005
|
|
#define PDT_ENTRY_SIZE 0x0006
|
|
|
|
static DEFINE_MUTEX(rfi_mutex);
|
|
|
|
struct rmi_functions *rmi_find_function(int functionNum);
|
|
|
|
int rmi_read(struct rmi_sensor_driver *sensor, unsigned short address,
|
|
char *dest)
|
|
{
|
|
struct rmi_phys_driver *rpd = sensor->rpd;
|
|
if (!rpd)
|
|
return -ENODEV;
|
|
return rpd->read(rpd, address, dest);
|
|
}
|
|
EXPORT_SYMBOL(rmi_read);
|
|
|
|
int rmi_write(struct rmi_sensor_driver *sensor, unsigned short address,
|
|
unsigned char data)
|
|
{
|
|
struct rmi_phys_driver *rpd = sensor->rpd;
|
|
if (!rpd)
|
|
return -ENODEV;
|
|
return rpd->write(rpd, address, data);
|
|
}
|
|
EXPORT_SYMBOL(rmi_write);
|
|
|
|
int rmi_read_multiple(struct rmi_sensor_driver *sensor,
|
|
unsigned short address, char *dest, int length)
|
|
{
|
|
struct rmi_phys_driver *rpd = sensor->rpd;
|
|
if (!rpd)
|
|
return -ENODEV;
|
|
return rpd->read_multiple(rpd, address, dest, length);
|
|
}
|
|
EXPORT_SYMBOL(rmi_read_multiple);
|
|
|
|
int rmi_write_multiple(struct rmi_sensor_driver *sensor,
|
|
unsigned short address, unsigned char *data, int length)
|
|
{
|
|
struct rmi_phys_driver *rpd = sensor->rpd;
|
|
if (!rpd)
|
|
return -ENODEV;
|
|
return rpd->write_multiple(rpd, address, data, length);
|
|
}
|
|
EXPORT_SYMBOL(rmi_write_multiple);
|
|
|
|
/* Utility routine to set bits in a register. */
|
|
int rmi_set_bits(struct rmi_sensor_driver *sensor, unsigned short address,
|
|
unsigned char bits)
|
|
{
|
|
unsigned char reg_contents;
|
|
int retval;
|
|
|
|
retval = rmi_read(sensor, address, ®_contents);
|
|
if (retval)
|
|
return retval;
|
|
reg_contents = reg_contents | bits;
|
|
retval = rmi_write(sensor, address, reg_contents);
|
|
if (retval == 1)
|
|
return 0;
|
|
else if (retval == 0)
|
|
return -EINVAL; /* TODO: What should this be? */
|
|
else
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL(rmi_set_bits);
|
|
|
|
/* Utility routine to clear bits in a register. */
|
|
int rmi_clear_bits(struct rmi_sensor_driver *sensor,
|
|
unsigned short address, unsigned char bits)
|
|
{
|
|
unsigned char reg_contents;
|
|
int retval;
|
|
|
|
retval = rmi_read(sensor, address, ®_contents);
|
|
if (retval)
|
|
return retval;
|
|
reg_contents = reg_contents & ~bits;
|
|
retval = rmi_write(sensor, address, reg_contents);
|
|
if (retval == 1)
|
|
return 0;
|
|
else if (retval == 0)
|
|
return -EINVAL; /* TODO: What should this be? */
|
|
else
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL(rmi_clear_bits);
|
|
|
|
/* Utility routine to set the value of a bit field in a register. */
|
|
int rmi_set_bit_field(struct rmi_sensor_driver *sensor,
|
|
unsigned short address, unsigned char field_mask, unsigned char bits)
|
|
{
|
|
unsigned char reg_contents;
|
|
int retval;
|
|
|
|
retval = rmi_read(sensor, address, ®_contents);
|
|
if (retval)
|
|
return retval;
|
|
reg_contents = (reg_contents & ~field_mask) | bits;
|
|
retval = rmi_write(sensor, address, reg_contents);
|
|
if (retval == 1)
|
|
return 0;
|
|
else if (retval == 0)
|
|
return -EINVAL; /* TODO: What should this be? */
|
|
else
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL(rmi_set_bit_field);
|
|
|
|
bool rmi_polling_required(struct rmi_sensor_driver *sensor)
|
|
{
|
|
return sensor->polling_required;
|
|
}
|
|
EXPORT_SYMBOL(rmi_polling_required);
|
|
|
|
/** Functions can call this in order to dispatch IRQs. */
|
|
void dispatchIRQs(struct rmi_sensor_driver *sensor, unsigned int irqStatus)
|
|
{
|
|
struct rmi_function_info *functionInfo;
|
|
|
|
list_for_each_entry(functionInfo, &sensor->functions, link) {
|
|
if ((functionInfo->interruptMask & irqStatus)) {
|
|
if (functionInfo->function_device->
|
|
rmi_funcs->inthandler) {
|
|
/* Call the functions interrupt handler function. */
|
|
functionInfo->function_device->rmi_funcs->
|
|
inthandler(functionInfo,
|
|
(functionInfo->interruptMask & irqStatus));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is the function we pass to the RMI4 subsystem so we can be notified
|
|
* when attention is required. It may be called in interrupt context.
|
|
*/
|
|
static void attention(struct rmi_phys_driver *physdrvr, int instance)
|
|
{
|
|
/* All we have to do is schedule work. */
|
|
|
|
/* TODO: It's possible that workIsReady is not really needed anymore.
|
|
* Investigate this to see if the race condition between setting up
|
|
* the work and enabling the interrupt still exists.
|
|
*/
|
|
if (physdrvr->sensor->workIsReady) {
|
|
schedule_work(&(physdrvr->sensor->work));
|
|
} else {
|
|
/* Got an interrupt but we're not ready so enable the irq
|
|
* so it doesn't get hung up
|
|
*/
|
|
printk(KERN_DEBUG "%s: Work not initialized yet -"
|
|
"enabling irqs.\n", __func__);
|
|
enable_irq(physdrvr->irq);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This notifies any interested functions that there
|
|
* is an Attention interrupt. The interested functions should take
|
|
* appropriate
|
|
* actions (such as reading the interrupt status register and dispatching any
|
|
* appropriate RMI4 interrupts).
|
|
*/
|
|
void attn_notify(struct rmi_sensor_driver *sensor)
|
|
{
|
|
struct rmi_function_info *functionInfo;
|
|
|
|
/* check each function that has data sources and if the interrupt for
|
|
* that triggered then call that RMI4 functions report() function to
|
|
* gather data and report it to the input subsystem
|
|
*/
|
|
list_for_each_entry(functionInfo, &sensor->functions, link) {
|
|
if (functionInfo->function_device &&
|
|
functionInfo->function_device->rmi_funcs->attention)
|
|
functionInfo->function_device->
|
|
rmi_funcs->attention(functionInfo);
|
|
}
|
|
}
|
|
|
|
/* This is the worker function - for now it simply has to call attn_notify.
|
|
* This work should be scheduled whenever an ATTN interrupt is asserted by
|
|
* the touch sensor.
|
|
* We then call attn_notify to dispatch notification of the ATTN interrupt
|
|
* to all
|
|
* interested functions. After all the attention handling functions
|
|
* have returned, it is presumed safe to re-enable the Attention interrupt.
|
|
*/
|
|
static void sensor_work_func(struct work_struct *work)
|
|
{
|
|
struct rmi_sensor_driver *sensor = container_of(work,
|
|
struct rmi_sensor_driver, work);
|
|
|
|
attn_notify(sensor);
|
|
|
|
/* we only need to enable the irq if doing interrupts */
|
|
if (!rmi_polling_required(sensor))
|
|
enable_irq(sensor->rpd->irq);
|
|
}
|
|
|
|
/* This is the timer function for polling - it simply has to schedule work
|
|
* and restart the timer. */
|
|
static enum hrtimer_restart sensor_poll_timer_func(struct hrtimer *timer)
|
|
{
|
|
struct rmi_sensor_driver *sensor = container_of(timer,
|
|
struct rmi_sensor_driver, timer);
|
|
|
|
schedule_work(&sensor->work);
|
|
hrtimer_start(&sensor->timer, ktime_set(0, polltime),
|
|
HRTIMER_MODE_REL);
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
|
|
/* This is the probe function passed to the RMI4 subsystem that gives us a
|
|
* chance to recognize an RMI4 device. In this case, we're looking for
|
|
* Synaptics devices that have data sources - such as touch screens, buttons,
|
|
* etc.
|
|
*
|
|
* TODO: Well, it used to do this. I'm not sure it's required any more.
|
|
*/
|
|
static int probe(struct rmi_sensor_driver *sensor)
|
|
{
|
|
struct rmi_phys_driver *rpd;
|
|
|
|
rpd = sensor->rpd;
|
|
|
|
if (!rpd) {
|
|
printk(KERN_ERR "%s: Invalid rmi physical driver - null ptr:"
|
|
"%p\n", __func__, rpd);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void config(struct rmi_sensor_driver *sensor)
|
|
{
|
|
/* For each data source we had detected print info and set up interrupts
|
|
or polling. */
|
|
struct rmi_function_info *functionInfo;
|
|
struct rmi_phys_driver *rpd;
|
|
|
|
rpd = sensor->rpd; /* get ptr to rmi_physical_driver from app */
|
|
|
|
list_for_each_entry(functionInfo, &sensor->functions, link) {
|
|
/* Get and print some info about the data sources... */
|
|
struct rmi_functions *fn;
|
|
bool found = false;
|
|
/* check if function number matches - if so call that
|
|
config function */
|
|
fn = rmi_find_function(functionInfo->functionNum);
|
|
if (fn) {
|
|
found = true;
|
|
|
|
if (fn->config) {
|
|
fn->config(functionInfo);
|
|
} else {
|
|
/* the developer did not add in the
|
|
pointer to the config function into
|
|
rmi4_supported_data_src_functions */
|
|
printk(KERN_ERR
|
|
"%s: no config function for "
|
|
"function 0x%x\n",
|
|
__func__, functionInfo->functionNum);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
/* if no support found for this RMI4 function
|
|
it means the developer did not add the
|
|
appropriate function pointer list into the
|
|
rmi4_supported_data_src_functions array and/or
|
|
did not bump up the number of supported RMI4
|
|
functions in rmi.h as required */
|
|
printk(KERN_ERR "%s: could not find support "
|
|
"for function 0x%x\n",
|
|
__func__, functionInfo->functionNum);
|
|
}
|
|
}
|
|
|
|
/* This will handle interrupts on the ATTN line (interrupt driven)
|
|
* or will be called every poll interval (when we're not interrupt
|
|
* driven).
|
|
*/
|
|
INIT_WORK(&sensor->work, sensor_work_func);
|
|
sensor->workIsReady = true;
|
|
|
|
if (rmi_polling_required(sensor)) {
|
|
/* We're polling driven, so set up the polling timer
|
|
and timer function. */
|
|
hrtimer_init(&sensor->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
sensor->timer.function = sensor_poll_timer_func;
|
|
hrtimer_start(&sensor->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
|
|
}
|
|
}
|
|
|
|
/** Just a stub for now.
|
|
*/
|
|
static int rmi_sensor_suspend(struct device *dev, pm_message_t state)
|
|
{
|
|
printk(KERN_INFO "%s: sensor suspend called.", __func__);
|
|
return 0;
|
|
}
|
|
|
|
/** Just a stub for now.
|
|
*/
|
|
static int rmi_sensor_resume(struct device *dev)
|
|
{
|
|
printk(KERN_INFO "%s: sensor resume called.", __func__);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* This method is called, whenever a new sensor device is added for the rmi
|
|
* bus.
|
|
*
|
|
* It will scan the devices PDT to determine the supported functions
|
|
* and create a new function device for each of these. It will read
|
|
* the query, control, command and data regsiters for the function
|
|
* to be used for each newly created function device.
|
|
*
|
|
* The sensor device is then bound to every function it supports.
|
|
*
|
|
*/
|
|
int rmi_sensor_register_functions(struct rmi_sensor_driver *sensor)
|
|
{
|
|
struct rmi_function_device *function;
|
|
unsigned int interruptRegisterCount;
|
|
struct rmi_phys_driver *rpd;
|
|
int i;
|
|
unsigned char interruptCount;
|
|
struct rmi_function_info *functionInfo;
|
|
struct rmi_function_descriptor rmi_fd;
|
|
struct rmi_functions *fn;
|
|
int retval;
|
|
|
|
pr_debug("%s: Registering sensor functions\n", __func__);
|
|
|
|
retval = 0;
|
|
|
|
/* Scan device for functions that may be supported */
|
|
{
|
|
pr_debug("%s: Scanning sensor for Functions:\n", __func__);
|
|
|
|
interruptCount = 0;
|
|
rpd = sensor->rpd;
|
|
|
|
/* Read the Page Descriptor Table to determine what functions
|
|
* are present */
|
|
|
|
printk(KERN_DEBUG "%s: Scanning page descriptors.", __func__);
|
|
for (i = PDT_START_SCAN_LOCATION;
|
|
i >= PDT_END_SCAN_LOCATION;
|
|
i -= PDT_ENTRY_SIZE) {
|
|
printk(KERN_DEBUG "%s: Reading page descriptor 0x%02x", __func__, i);
|
|
retval = rpd->read_multiple(rpd, i, (char *)&rmi_fd,
|
|
sizeof(rmi_fd));
|
|
if (!retval) {
|
|
functionInfo = NULL;
|
|
|
|
if (rmi_fd.functionNum != 0x00 && rmi_fd.functionNum != 0xff) {
|
|
printk(KERN_DEBUG "%s: F%02x - queries %02x commands %02x control %02x data %02x ints %02x", __func__, rmi_fd.functionNum, rmi_fd.queryBaseAddr, rmi_fd.commandBaseAddr, rmi_fd.controlBaseAddr, rmi_fd.dataBaseAddr, rmi_fd.interruptSrcCnt);
|
|
|
|
if ((rmi_fd.functionNum & 0xff) == 0x01)
|
|
printk(KERN_DEBUG "%s: Fn $01 Found - RMI Device Control", __func__);
|
|
|
|
/* determine if the function is supported and if so
|
|
* then bind this function device to the sensor */
|
|
if (rmi_fd.interruptSrcCnt) {
|
|
functionInfo = kzalloc(sizeof(*functionInfo), GFP_KERNEL);
|
|
if (!functionInfo) {
|
|
printk(KERN_ERR "%s: could not allocate memory for function 0x%x.",
|
|
__func__, rmi_fd.functionNum);
|
|
retval = -ENOMEM;
|
|
goto exit_fail;
|
|
}
|
|
functionInfo->sensor = sensor;
|
|
functionInfo->functionNum = (rmi_fd.functionNum & 0xff);
|
|
INIT_LIST_HEAD(&functionInfo->link);
|
|
/* Get the ptr to the detect function based on
|
|
* the function number */
|
|
printk(KERN_DEBUG "%s: Checking for RMI function F%02x.", __func__, rmi_fd.functionNum);
|
|
fn = rmi_find_function(rmi_fd.functionNum);
|
|
if (fn) {
|
|
retval = fn->detect(functionInfo, &rmi_fd,
|
|
interruptCount);
|
|
if (retval)
|
|
printk(KERN_ERR "%s: Function detect for F%02x failed with %d.",
|
|
__func__, rmi_fd.functionNum, retval);
|
|
|
|
/* Create a function device and function driver for this Fn */
|
|
function = kzalloc(sizeof(*function), GFP_KERNEL);
|
|
if (!function) {
|
|
printk(KERN_ERR "%s: Error allocating memory for rmi_function_device.", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
function->dev.parent = &sensor->sensor_device->dev;
|
|
function->dev.bus = sensor->sensor_device->dev.bus;
|
|
function->rmi_funcs = fn;
|
|
function->sensor = sensor;
|
|
function->rfi = functionInfo;
|
|
functionInfo->function_device = function;
|
|
|
|
/* Check if we have an interrupt mask of 0 and a non-NULL interrupt
|
|
handler function and print a debug message since we should never
|
|
have this.
|
|
*/
|
|
if (functionInfo->interruptMask == 0 && fn->inthandler != NULL) {
|
|
printk(KERN_DEBUG "%s: Can't have a zero interrupt mask for function F%02x (which requires an interrupt handler).\n",
|
|
__func__, rmi_fd.functionNum);
|
|
}
|
|
|
|
|
|
/* Check if we have a non-zero interrupt mask and a NULL interrupt
|
|
handler function and print a debug message since we should never
|
|
have this.
|
|
*/
|
|
if (functionInfo->interruptMask != 0 && fn->inthandler == NULL) {
|
|
printk(KERN_DEBUG "%s: Can't have a non-zero interrupt mask %d for function F%02x with a NULL inthandler fn.\n",
|
|
__func__, functionInfo->interruptMask, rmi_fd.functionNum);
|
|
}
|
|
|
|
/* Register the rmi function device */
|
|
retval = rmi_function_register_device(function, rmi_fd.functionNum);
|
|
if (retval) {
|
|
printk(KERN_ERR "%s: Failed rmi_function_register_device.\n",
|
|
__func__);
|
|
return retval;
|
|
}
|
|
} else {
|
|
printk(KERN_ERR "%s: could not find support for function 0x%02X.\n",
|
|
__func__, rmi_fd.functionNum);
|
|
}
|
|
} else {
|
|
printk(KERN_DEBUG "%s: Found function F%02x - Ignored.\n", __func__, rmi_fd.functionNum & 0xff);
|
|
}
|
|
|
|
/* bump interrupt count for next iteration */
|
|
/* NOTE: The value 7 is reserved - for now, only bump up one for an interrupt count of 7 */
|
|
if ((rmi_fd.interruptSrcCnt & 0x7) == 0x7) {
|
|
interruptCount += 1;
|
|
} else {
|
|
interruptCount +=
|
|
(rmi_fd.interruptSrcCnt & 0x7);
|
|
}
|
|
|
|
/* link this function info to the RMI module infos list
|
|
of functions */
|
|
if (functionInfo == NULL) {
|
|
printk(KERN_DEBUG "%s: WTF? functionInfo is null here.", __func__);
|
|
} else {
|
|
printk(KERN_DEBUG "%s: Adding function F%02x with %d sources.\n",
|
|
__func__, functionInfo->functionNum, functionInfo->numSources);
|
|
|
|
mutex_lock(&rfi_mutex);
|
|
list_add_tail(&functionInfo->link,
|
|
&sensor->functions);
|
|
mutex_unlock(&rfi_mutex);
|
|
}
|
|
|
|
} else {
|
|
/* A zero or 0xff in the function number
|
|
signals the end of the PDT */
|
|
printk(KERN_DEBUG "%s: Found End of PDT\n",
|
|
__func__);
|
|
break;
|
|
}
|
|
} else {
|
|
/* failed to read next PDT entry - end PDT
|
|
scan - this may result in an incomplete set
|
|
of recognized functions - should probably
|
|
return an error but the driver may still be
|
|
viable for diagnostics and debugging so let's
|
|
let it continue. */
|
|
printk(KERN_ERR "%s: Read Error %d when reading next PDT entry - "
|
|
"ending PDT scan.\n",
|
|
__func__, retval);
|
|
break;
|
|
}
|
|
}
|
|
printk(KERN_DEBUG "%s: Done scanning.", __func__);
|
|
|
|
/* calculate the interrupt register count - used in the
|
|
ISR to read the correct number of interrupt registers */
|
|
interruptRegisterCount = (interruptCount + 7) / 8;
|
|
sensor->interruptRegisterCount = interruptRegisterCount; /* TODO: Is this needed by the sensor anymore? */
|
|
}
|
|
|
|
return 0;
|
|
|
|
exit_fail:
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL(rmi_sensor_register_functions);
|
|
|
|
int rmi_sensor_register_device(struct rmi_sensor_device *dev, int index)
|
|
{
|
|
int status;
|
|
|
|
printk(KERN_INFO "%s: Registering sensor device.\n", __func__);
|
|
|
|
/* make name - sensor00, sensor01, etc. */
|
|
dev_set_name(&dev->dev, "sensor%02d", index);
|
|
status = device_register(&dev->dev);
|
|
|
|
return status;
|
|
}
|
|
EXPORT_SYMBOL(rmi_sensor_register_device);
|
|
|
|
static void rmi_sensor_unregister_device(struct rmi_sensor_device *rmisensordev)
|
|
{
|
|
printk(KERN_INFO "%s: Unregistering sensor device.\n", __func__);
|
|
|
|
device_unregister(&rmisensordev->dev);
|
|
}
|
|
EXPORT_SYMBOL(rmi_sensor_unregister_device);
|
|
|
|
int rmi_sensor_register_driver(struct rmi_sensor_driver *driver)
|
|
{
|
|
static int index;
|
|
int ret;
|
|
char *drvrname;
|
|
|
|
driver->workIsReady = false;
|
|
|
|
printk(KERN_INFO "%s: Registering sensor driver.\n", __func__);
|
|
driver->dispatchIRQs = dispatchIRQs;
|
|
driver->attention = attention;
|
|
driver->config = config;
|
|
driver->probe = probe;
|
|
|
|
/* assign the bus type for this driver to be rmi bus */
|
|
driver->drv.bus = &rmi_bus_type;
|
|
driver->drv.suspend = rmi_sensor_suspend;
|
|
driver->drv.resume = rmi_sensor_resume;
|
|
/* Create a function device and function driver for this Fn */
|
|
drvrname = kzalloc(sizeof(sensorname) + 4, GFP_KERNEL);
|
|
if (!drvrname) {
|
|
printk(KERN_ERR "%s: Error allocating memeory for rmi_sensor_driver name.\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
sprintf(drvrname, "sensor%02d", index++);
|
|
|
|
driver->drv.name = drvrname;
|
|
driver->module = driver->drv.owner;
|
|
|
|
/* register the sensor driver */
|
|
ret = driver_register(&driver->drv);
|
|
if (ret) {
|
|
printk(KERN_ERR "%s: Failed driver_register %d\n",
|
|
__func__, ret);
|
|
goto exit_fail;
|
|
}
|
|
|
|
/* register the functions on the sensor */
|
|
ret = rmi_sensor_register_functions(driver);
|
|
if (ret) {
|
|
printk(KERN_ERR "%s: Failed rmi_sensor_register_functions %d\n",
|
|
__func__, ret);
|
|
}
|
|
|
|
/* configure the sensor - enable interrupts for each function, init work, set polling timer or adjust report rate, etc. */
|
|
config(driver);
|
|
|
|
printk(KERN_DEBUG "%s: sensor driver registration completed.", __func__);
|
|
|
|
exit_fail:
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(rmi_sensor_register_driver);
|
|
|
|
static void rmi_sensor_unregister_driver(struct rmi_sensor_driver *driver)
|
|
{
|
|
printk(KERN_DEBUG "%s: Unregistering sensor driver.\n", __func__);
|
|
|
|
/* Stop the polling timer if doing polling */
|
|
if (rmi_polling_required(driver))
|
|
hrtimer_cancel(&driver->timer);
|
|
|
|
flush_scheduled_work(); /* Make sure all scheduled work is stopped */
|
|
|
|
driver_unregister(&driver->drv);
|
|
}
|
|
EXPORT_SYMBOL(rmi_sensor_unregister_driver);
|
|
|
|
|
|
static int __init rmi_sensor_init(void)
|
|
{
|
|
printk(KERN_DEBUG "%s: RMI Sensor Init\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static void __exit rmi_sensor_exit(void)
|
|
{
|
|
printk(KERN_DEBUG "%s: RMI Sensor Driver Exit\n", __func__);
|
|
flush_scheduled_work(); /* Make sure all scheduled work is stopped */
|
|
}
|
|
|
|
|
|
module_init(rmi_sensor_init);
|
|
module_exit(rmi_sensor_exit);
|
|
|
|
MODULE_AUTHOR("Synaptics, Inc.");
|
|
MODULE_DESCRIPTION("RMI4 Sensor Driver");
|
|
MODULE_LICENSE("GPL");
|