diff mbox

[10/15] Input: synaptics-rmi4 - add devicetree support

Message ID 1390521623-6491-11-git-send-email-courtney.cavin@sonymobile.com (mailing list archive)
State New, archived
Headers show

Commit Message

Courtney Cavin Jan. 24, 2014, midnight UTC
Cc: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Courtney Cavin <courtney.cavin@sonymobile.com>
---
 Documentation/devicetree/bindings/input/rmi4.txt   | 107 +++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/input/rmi4/rmi_bus.c                       |  12 +-
 drivers/input/rmi4/rmi_bus.h                       |   3 +-
 drivers/input/rmi4/rmi_driver.c                    |  44 +++++--
 drivers/input/rmi4/rmi_f01.c                       | 107 +++++++++++++++--
 drivers/input/rmi4/rmi_f11.c                       | 133 ++++++++++++++++++++-
 drivers/input/rmi4/rmi_i2c.c                       |  19 +--
 8 files changed, 388 insertions(+), 38 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/rmi4.txt

Comments

Christopher Heiny Feb. 4, 2014, 11:10 p.m. UTC | #1
On 01/23/2014 04:00 PM, Courtney Cavin wrote:

This is pretty interesting, and looks potentially useful.  I'm not very 
familiar with OF/DT structures, though.  What happens if there are two 
different RMI4 devices in the system, each of which has its own platform 
settings?

> Cc: Christopher Heiny <cheiny@synaptics.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Courtney Cavin <courtney.cavin@sonymobile.com>
> ---
>   Documentation/devicetree/bindings/input/rmi4.txt   | 107 +++++++++++++++++
>   .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>   drivers/input/rmi4/rmi_bus.c                       |  12 +-
>   drivers/input/rmi4/rmi_bus.h                       |   3 +-
>   drivers/input/rmi4/rmi_driver.c                    |  44 +++++--
>   drivers/input/rmi4/rmi_f01.c                       | 107 +++++++++++++++--
>   drivers/input/rmi4/rmi_f11.c                       | 133 ++++++++++++++++++++-
>   drivers/input/rmi4/rmi_i2c.c                       |  19 +--
>   8 files changed, 388 insertions(+), 38 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/input/rmi4.txt
>
> diff --git a/Documentation/devicetree/bindings/input/rmi4.txt b/Documentation/devicetree/bindings/input/rmi4.txt
> new file mode 100644
> index 0000000..fff9db7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/rmi4.txt
> @@ -0,0 +1,107 @@
> +Synaptics RMI4-based input device binding
> +
> +PROPERTIES
> +
> +compatible:
> +	Usage: required
> +	Type: string, must be "syn,rmi_i2c"
> +
> +interrupts:
> +	Usage: required
> +	Type: <prop-encoded-array>
> +	Desc: See devicetree/bindings/interrupt-controller/interrupts.txt;
> +		Trigger sense required in mask
> +
> +syn,reset-delay:
> +	Usage: optional (default: 100)
> +	Type: u32, milliseconds
> +	Desc: Delay after issuing a reset
> +
> +syn,power-no-sleep:
> +	Usage: optional, mutually exclusive with syn,power-sleep
> +		(default: chip-specific)
> +	Type: boolean
> +	Desc: Disable sleep mode
> +
> +syn,power-sleep:
> +	Usage: optional, mutually exclusive with syn,power-no-sleep
> +		(default: chip-specific)
> +	Type: boolean
> +	Desc: Enable sleep mode
> +
> +syn,power-wakeup-thresh:
> +	Usage: optional (default: chip-specific)
> +	Type: u32, chip-specific unit [0-255]
> +	Desc: Capacitance threshold at which device should wake
> +
> +syn,power-doze-holdoff:
> +	Usage: optional (default: chip-specific)
> +	Type: u32, milliseconds [0-25500]
> +	Desc: Idle delay before entering sleep mode
> +
> +syn,power-doze-interval:
> +	Usage: optional (default: chip-specific)
> +	Type: u32, milliseconds [0-2550]
> +	Desc: Interval between checks for idle
> +
> +syn,2d-rezero-wait:
> +	Usage: optional (default: no re-zeroing)
> +	Type: u32, milliseconds [0-65535]
> +	Desc: Delay after resume to re-zero sensor
> +
> +syn,2d-axis-swap:
> +	Usage: optional (default: false)
> +	Type: boolean
> +	Desc: Swap X and Y axis
> +
> +syn,2d-flip-x:
> +	Usage: optional (default: false)
> +	Type: boolean
> +	Desc: Invert X axis
> +
> +syn,2d-flip-y:
> +	Usage: optional (default: false)
> +	Type: boolean
> +	Desc: Invert Y axis
> +
> +syn,2d-clip-range:
> +	Usage: optional (default: clip disabled)
> +	Type: u32 array (<top left bottom right>) [0-65535]
> +	Usage: Clip values outside this range
> +
> +syn,2d-offset:
> +	Usage: optional (default: offset disabled)
> +	Type: u32 array (<X-offset Y-offset>) [0-65535]
> +	Usage: Add offset values to reported events
> +
> +syn,2d-delta-thresh:
> +	Usage: optional (default: chip-specific)
> +	Type: u32 array (<X-delta Y-delta>) [0-255]
> +	Usage: Minimum delta before event is reported
> +
> +syn,2d-sensor-type:
> +	Usage: optional (default: chip-specific)
> +	Type: string, "indirect" or "direct"
> +	Usage: Set screen type for event reporting
> +
> +syn,2d-type-a:
> +	Usage: optional (default: false)
> +	Type: boolean
> +	Usage: Sensor supports only Multifinger Type A protocol
> +
> +EXAMPLE
> +
> +i2c@0 {
> +	compatible = "...";
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	synaptics_rmi4@2c {
> +		compatible = "syn,rmi_i2c";
> +		reg = <0x2c>;
> +
> +		interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
> +
> +		syn,2d-clip-range = <0 0 1919 1079>;
> +	};
> +};
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index edbb8d8..3388986 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -72,6 +72,7 @@ snps 	Synopsys, Inc.
>   st	STMicroelectronics
>   ste	ST-Ericsson
>   stericsson	ST-Ericsson
> +syn	Synaptics, Inc.
>   ti	Texas Instruments
>   toshiba	Toshiba Corporation
>   toumaz	Toumaz
> diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
> index a51e6b4..57de579 100644
> --- a/drivers/input/rmi4/rmi_bus.c
> +++ b/drivers/input/rmi4/rmi_bus.c
> @@ -52,14 +52,11 @@ bool rmi_is_physical_device(struct device *dev)
>   int rmi_register_transport_device(struct rmi_transport_dev *xport)
>   {
>   	static atomic_t transport_device_count = ATOMIC_INIT(0);
> -	struct rmi_device_platform_data *pdata = xport->dev->platform_data;
>   	struct rmi_device *rmi_dev;
>   	int error;
>
> -	if (!pdata) {
> -		dev_err(xport->dev, "no platform data!\n");
> -		return -EINVAL;
> -	}
> +	if (unlikely(!rmi_bus_type.p))
> +		return -EPROBE_DEFER;
>
>   	rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
>   	if (!rmi_dev)
> @@ -70,8 +67,10 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport)
>
>   	dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
>
> +	rmi_dev->dev.parent = xport->dev;
>   	rmi_dev->dev.bus = &rmi_bus_type;
>   	rmi_dev->dev.type = &rmi_device_type;
> +	rmi_dev->dev.of_node = xport->dev->of_node;
>
>   	xport->rmi_dev = rmi_dev;
>
> @@ -206,6 +205,9 @@ int __rmi_register_function_handler(struct rmi_function_handler *handler,
>   	struct device_driver *driver = &handler->driver;
>   	int error;
>
> +	if (WARN_ON(unlikely(!rmi_bus_type.p)))
> +		return -EAGAIN;
> +
>   	driver->bus = &rmi_bus_type;
>   	driver->owner = owner;
>   	driver->mod_name = mod_name;
> diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
> index a21e4c4..51f9372 100644
> --- a/drivers/input/rmi4/rmi_bus.h
> +++ b/drivers/input/rmi4/rmi_bus.h
> @@ -212,7 +212,8 @@ struct rmi_device {
>   };
>
>   #define to_rmi_device(d) container_of(d, struct rmi_device, dev)
> -#define to_rmi_platform_data(d) ((d)->xport->dev->platform_data)
> +#define to_rmi_xport_device(d) ((d)->xport->dev)
> +#define to_rmi_platform_data(d) (dev_get_platdata(to_rmi_xport_device(d)))
>
>   bool rmi_is_physical_device(struct device *dev);
>
> diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
> index 9ec7b93..92415ce 100644
> --- a/drivers/input/rmi4/rmi_driver.c
> +++ b/drivers/input/rmi4/rmi_driver.c
> @@ -26,6 +26,8 @@
>   #include <linux/rmi.h>
>   #include <linux/slab.h>
>   #include <linux/uaccess.h>
> +#include <linux/of_irq.h>
> +#include <linux/of.h>
>   #include <uapi/linux/input.h>
>   #include "rmi_bus.h"
>   #include "rmi_driver.h"
> @@ -498,7 +500,7 @@ static int create_function(struct rmi_device *rmi_dev,
>    * We have to do this before actually building the PDT because the reflash
>    * updates (if any) might cause various registers to move around.
>    */
> -static int rmi_initial_reset(struct rmi_device *rmi_dev)
> +static int rmi_initial_reset(struct rmi_device *rmi_dev, u32 reset_delay)
>   {
>   	struct pdt_entry pdt_entry;
>   	int page;
> @@ -507,8 +509,6 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev)
>   	bool has_f01 = false;
>   	int i;
>   	int retval;
> -	const struct rmi_device_platform_data *pdata =
> -			to_rmi_platform_data(rmi_dev);
>
>   	dev_dbg(dev, "Initial reset.\n");
>
> @@ -538,7 +538,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev)
>   						retval);
>   					return retval;
>   				}
> -				mdelay(pdata->reset_delay_ms);
> +				mdelay(reset_delay);
>   				done = true;
>   				has_f01 = true;
>   				break;
> @@ -648,6 +648,8 @@ static int rmi_driver_probe(struct device *dev)
>   	struct rmi_device_platform_data *pdata;
>   	int retval = 0;
>   	struct rmi_device *rmi_dev;
> +	unsigned int irq;
> +	u32 reset_delay;
>
>   	dev_dbg(dev, "%s: Starting probe.\n", __func__);
>
> @@ -661,6 +663,28 @@ static int rmi_driver_probe(struct device *dev)
>   	rmi_dev->driver = rmi_driver;
>
>   	pdata = to_rmi_platform_data(rmi_dev);
> +	if (pdata == NULL) {
> +#ifdef CONFIG_OF
> +		const char *p;
> +
> +		p = "syn,reset-delay";
> +		retval = of_property_read_u32(dev->of_node, p, &reset_delay);
> +		if (retval && retval != -EINVAL) {
> +			dev_err(dev, "Invalid '%s' property\n", p);
> +			return -EINVAL;
> +		}
> +		if (retval == -EINVAL)
> +			reset_delay = 0;
> +
> +		irq = irq_of_parse_and_map(dev->of_node, 0);
> +#else
> +		dev_err(dev, "No pdata\n");
> +		return -EINVAL;
> +#endif
> +	} else {
> +		reset_delay = pdata->reset_delay_ms;
> +		irq = pdata->irq;
> +	}
>
>   	data = devm_kzalloc(dev, sizeof(struct rmi_driver_data), GFP_KERNEL);
>   	if (!data) {
> @@ -688,9 +712,9 @@ static int rmi_driver_probe(struct device *dev)
>   	 * and leave the customer's device unusable.  So we warn them, and
>   	 * continue processing.
>   	 */
> -	if (!pdata->reset_delay_ms)
> -		pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
> -	retval = rmi_initial_reset(rmi_dev);
> +	if (!reset_delay)
> +		reset_delay = DEFAULT_RESET_DELAY_MS;
> +	retval = rmi_initial_reset(rmi_dev, reset_delay);
>   	if (retval)
>   		dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
>
> @@ -762,10 +786,10 @@ static int rmi_driver_probe(struct device *dev)
>   		goto err_free_data;
>   	}
>
> -	data->irq = pdata->irq;
> -	if (data->irq < 0) {
> +	data->irq = irq;
> +	if (data->irq < 0 || data->irq == NO_IRQ) {
>   		dev_err(dev, "Failed to get attn IRQ.\n");
> -		retval = data->irq;
> +		retval = -EINVAL;
>   		goto err_free_data;
>
>   	}
> diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
> index 4cb9fcb..22b57f2 100644
> --- a/drivers/input/rmi4/rmi_f01.c
> +++ b/drivers/input/rmi4/rmi_f01.c
> @@ -12,6 +12,7 @@
>   #include <linux/rmi.h>
>   #include <linux/slab.h>
>   #include <linux/uaccess.h>
> +#include <linux/of.h>
>   #include "rmi_driver.h"
>
>   #define RMI_PRODUCT_ID_LENGTH    10
> @@ -169,15 +170,104 @@ static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
>   	return 0;
>   }
>
> +#ifdef CONFIG_OF
> +static int rmi_f01_of_parse(struct device *dev,
> +		struct rmi_f01_power_management *cdata)
> +{
> +	bool sleep, nosleep;
> +	const char *p;
> +	u32 val;
> +	int rc;
> +
> +	if (dev->of_node == NULL)
> +		return -EINVAL;
> +
> +	memset(cdata, 0, sizeof(*cdata));
> +
> +	sleep = of_property_read_bool(dev->of_node, "syn,power-sleep");
> +	nosleep = of_property_read_bool(dev->of_node, "syn,power-nosleep");
> +	if (sleep && nosleep) {
> +		dev_err(dev, "'syn,power-sleep' and 'syn,power-nosleep' are mutually exclusive\n");
> +		return -EINVAL;
> +	}
> +	if (sleep)
> +		cdata->nosleep = RMI_F01_NOSLEEP_OFF;
> +	else if (nosleep)
> +		cdata->nosleep = RMI_F01_NOSLEEP_ON;
> +
> +	p = "syn,power-wakeup-thresh";
> +	rc = of_property_read_u32(dev->of_node, p, &val);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if (val & ~0xff) {
> +			dev_err(dev, "'%s' out of range [0-255]\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->wakeup_threshold = val;
> +	}
> +
> +	p = "syn,power-doze-holdoff";
> +	rc = of_property_read_u32(dev->of_node, p, &val);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if (val > 25500) {
> +			dev_err(dev, "'%s' out of range [0-25500]ms\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->doze_holdoff = (val + 50) / 100;
> +	}
> +
> +	p = "syn,power-doze-interval";
> +	rc = of_property_read_u32(dev->of_node, p, &val);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if (val > 2550) {
> +			dev_err(dev, "'%s' out of range [0-2550]ms\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->doze_interval = (val + 5) / 10;
> +	}
> +
> +	return 0;
> +}
> +#else
> +static int rmi_f01_of_parse(struct device *dev,
> +		struct rmi_f01_power_management *cdata)
> +{
> +	return -EINVAL;
> +}
> +#endif
> +
>   static int rmi_f01_initialize(struct rmi_function *fn)
>   {
>   	u8 temp;
>   	int error;
>   	u16 ctrl_base_addr;
> +	struct rmi_f01_power_management cdata;
>   	struct rmi_device *rmi_dev = fn->rmi_dev;
> +	struct device *dev = to_rmi_xport_device(rmi_dev);
>   	struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
>   	struct f01_data *data = fn->data;
> -	struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
> +	struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
> +
> +	if (pdata != NULL) {
> +		cdata = pdata->power_management;
> +	} else {
> +		error = rmi_f01_of_parse(dev, &cdata);
> +		if (error) {
> +			dev_err(dev, "Unable to parse DT data\n");
> +			return error;
> +		}
> +	}
>
>   	/*
>   	 * Set the configured bit and (optionally) other important stuff
> @@ -191,7 +281,7 @@ static int rmi_f01_initialize(struct rmi_function *fn)
>   		dev_err(&fn->dev, "Failed to read F01 control.\n");
>   		return error;
>   	}
> -	switch (pdata->power_management.nosleep) {
> +	switch (cdata.nosleep) {
>   	case RMI_F01_NOSLEEP_DEFAULT:
>   		break;
>   	case RMI_F01_NOSLEEP_OFF:
> @@ -262,9 +352,9 @@ static int rmi_f01_initialize(struct rmi_function *fn)
>   		data->doze_interval_addr = ctrl_base_addr;
>   		ctrl_base_addr++;
>
> -		if (pdata->power_management.doze_interval) {
> +		if (cdata.doze_interval) {
>   			data->device_control.doze_interval =
> -				pdata->power_management.doze_interval;
> +				cdata.doze_interval;
>   			error = rmi_write(rmi_dev, data->doze_interval_addr,
>   					data->device_control.doze_interval);
>   			if (error < 0) {
> @@ -283,9 +373,9 @@ static int rmi_f01_initialize(struct rmi_function *fn)
>   		data->wakeup_threshold_addr = ctrl_base_addr;
>   		ctrl_base_addr++;
>
> -		if (pdata->power_management.wakeup_threshold) {
> +		if (cdata.wakeup_threshold) {
>   			data->device_control.wakeup_threshold =
> -				pdata->power_management.wakeup_threshold;
> +				cdata.wakeup_threshold;
>   			error = rmi_write(rmi_dev, data->wakeup_threshold_addr,
>   					data->device_control.wakeup_threshold);
>   			if (error < 0) {
> @@ -306,9 +396,8 @@ static int rmi_f01_initialize(struct rmi_function *fn)
>   		data->doze_holdoff_addr = ctrl_base_addr;
>   		ctrl_base_addr++;
>
> -		if (pdata->power_management.doze_holdoff) {
> -			data->device_control.doze_holdoff =
> -				pdata->power_management.doze_holdoff;
> +		if (cdata.doze_holdoff) {
> +			data->device_control.doze_holdoff = cdata.doze_holdoff;
>   			error = rmi_write(rmi_dev, data->doze_holdoff_addr,
>   					data->device_control.doze_holdoff);
>   			if (error < 0) {
> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
> index b114f25..837b6e7 100644
> --- a/drivers/input/rmi4/rmi_f11.c
> +++ b/drivers/input/rmi4/rmi_f11.c
> @@ -13,6 +13,7 @@
>   #include <linux/input.h>
>   #include <linux/input/mt.h>
>   #include <linux/kconfig.h>
> +#include <linux/of.h>
>   #include <linux/rmi.h>
>   #include <linux/slab.h>
>   #include "rmi_driver.h"
> @@ -794,9 +795,120 @@ static void f11_set_abs_params(struct rmi_function *fn)
>   				     0, MT_TOOL_FINGER, 0, 0);
>   }
>
> +#ifdef CONFIG_OF
> +static int rmi_f11_of_parse(struct device *dev,
> +		struct rmi_f11_sensor_data *cdata)
> +{
> +	const char *type;
> +	const char *p;
> +	u32 a[4];
> +	int rc;
> +
> +	if (dev->of_node == NULL)
> +		return -EINVAL;
> +
> +	memset(cdata, 0, sizeof(*cdata));
> +
> +	p = "syn,2d-rezero-wait";
> +	rc = of_property_read_u32(dev->of_node, p, &a[0]);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if (a[0] & ~0xffff) {
> +			dev_err(dev, "'%s' value out of range [0-65535]\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->rezero_wait = a[0];
> +	}
> +
> +	cdata->type_a = of_property_read_bool(dev->of_node, "syn,2d-type-a");
> +	cdata->axis_align.swap_axes = of_property_read_bool(dev->of_node,
> +			"syn,2d-axis-swap");
> +	cdata->axis_align.flip_x = of_property_read_bool(dev->of_node,
> +			"syn,2d-flip-x");
> +	cdata->axis_align.flip_y = of_property_read_bool(dev->of_node,
> +			"syn,2d-flip-y");
> +
> +	p = "syn-2d-clip-range";
> +	rc = of_property_read_u32_array(dev->of_node, p, a, 4);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if ((a[0] | a[1] | a[2] | a[3]) & ~0xffff) {
> +			dev_err(dev, "'%s' values out of range [0-65535]\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->axis_align.clip_x_low = a[0];
> +		cdata->axis_align.clip_y_low = a[1];
> +		cdata->axis_align.clip_x_high = a[2];
> +		cdata->axis_align.clip_y_high = a[3];
> +	}
> +
> +	p = "syn-2d-offset";
> +	rc = of_property_read_u32_array(dev->of_node, p, a, 2);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if ((a[0] | a[1]) & ~0xffff) {
> +			dev_err(dev, "'%s' values out of range [0-65535]\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->axis_align.offset_x = a[0];
> +		cdata->axis_align.offset_y = a[1];
> +	}
> +
> +	p = "syn,2d-delta-thresh";
> +	rc = of_property_read_u32_array(dev->of_node, p, a, 2);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if ((a[0] | a[1]) & ~0xff) {
> +			dev_err(dev, "'%s' values out of range [0-255]\n", p);
> +			return -EINVAL;
> +		}
> +		cdata->axis_align.delta_x_threshold = a[0];
> +		cdata->axis_align.delta_y_threshold = a[1];
> +	}
> +
> +	p = "syn,2d-sensor-type";
> +	rc = of_property_read_string(dev->of_node, p, &type);
> +	if (rc && rc != -EINVAL) {
> +		dev_err(dev, "Invalid '%s' property\n", p);
> +		return rc;
> +	}
> +	if (rc != -EINVAL) {
> +		if (!strcmp(type, "direct")) {
> +			cdata->sensor_type = RMI_F11_SENSOR_DIRECT;
> +		} else if (!strcmp(type, "indirect")) {
> +			cdata->sensor_type = RMI_F11_SENSOR_INDIRECT;
> +		} else {
> +			dev_err(dev, "'%s' must be one of: \"indirect\", \"direct\"\n", p);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +#else
> +static int rmi_f11_of_parse(struct device *dev,
> +		struct rmi_f11_sensor_data *cdata)
> +{
> +	return -EINVAL;
> +}
> +#endif
> +
>   static int rmi_f11_initialize(struct rmi_function *fn)
>   {
>   	struct rmi_device *rmi_dev = fn->rmi_dev;
> +	struct device *dev = to_rmi_xport_device(rmi_dev);
>   	struct f11_data *f11;
>   	struct f11_2d_ctrl *ctrl;
>   	u8 query_offset;
> @@ -804,12 +916,23 @@ static int rmi_f11_initialize(struct rmi_function *fn)
>   	u16 control_base_addr;
>   	u16 max_x_pos, max_y_pos, temp;
>   	int rc;
> -	struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
> +	struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
> +	struct rmi_f11_sensor_data cdata;
>   	struct f11_2d_sensor *sensor;
>   	u8 buf;
>
>   	dev_dbg(&fn->dev, "Initializing F11 values.\n");
>
> +	if (pdata != NULL) {
> +		cdata = pdata->f11_sensor_data;
> +	} else {
> +		rc = rmi_f11_of_parse(dev, &cdata);
> +		if (rc) {
> +			dev_err(dev, "Unable to parse DT data\n");
> +			return rc;
> +		}
> +	}
> +
>   	/*
>   	** init instance data, fill in values and create any sysfs files
>   	*/
> @@ -818,7 +941,7 @@ static int rmi_f11_initialize(struct rmi_function *fn)
>   		return -ENOMEM;
>
>   	fn->data = f11;
> -	f11->rezero_wait_ms = pdata->f11_sensor_data.rezero_wait;
> +	f11->rezero_wait_ms = cdata.rezero_wait;
>
>   	query_base_addr = fn->fd.query_base_addr;
>   	control_base_addr = fn->fd.control_base_addr;
> @@ -851,9 +974,9 @@ static int rmi_f11_initialize(struct rmi_function *fn)
>   		return rc;
>   	}
>
> -	sensor->axis_align = pdata->f11_sensor_data.axis_align;
> -	sensor->type_a = pdata->f11_sensor_data.type_a;
> -	sensor->sensor_type = pdata->f11_sensor_data.sensor_type;
> +	sensor->axis_align = cdata.axis_align;
> +	sensor->type_a = cdata.type_a;
> +	sensor->sensor_type = cdata.sensor_type;
>
>   	rc = rmi_read_block(rmi_dev,
>   		control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET,
> diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
> index aebf974..377d4cc 100644
> --- a/drivers/input/rmi4/rmi_i2c.c
> +++ b/drivers/input/rmi4/rmi_i2c.c
> @@ -186,16 +186,9 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
>   static int rmi_i2c_probe(struct i2c_client *client,
>   			 const struct i2c_device_id *id)
>   {
> -	const struct rmi_device_platform_data *pdata =
> -				dev_get_platdata(&client->dev);
>   	struct rmi_i2c_xport *rmi_i2c;
>   	int retval;
>
> -	if (!pdata) {
> -		dev_err(&client->dev, "no platform data\n");
> -		return -EINVAL;
> -	}
> -
>   	dev_dbg(&client->dev, "Probing %#02x.\n", client->addr);
>
>   	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> @@ -258,10 +251,20 @@ static const struct i2c_device_id rmi_id[] = {
>   };
>   MODULE_DEVICE_TABLE(i2c, rmi_id);
>
> +#ifdef CONFIG_OF
> +static struct of_device_id rmi_match_table[] = {
> +	{ .compatible = "syn,rmi_i2c", },
> +	{ },
> +};
> +#else
> +#define rmi_match_table NULL
> +#endif
> +
>   static struct i2c_driver rmi_i2c_driver = {
>   	.driver = {
>   		.owner	= THIS_MODULE,
> -		.name	= "rmi_i2c"
> +		.name	= "rmi_i2c",
> +		.of_match_table = rmi_match_table,
>   	},
>   	.id_table	= rmi_id,
>   	.probe		= rmi_i2c_probe,
>
Courtney Cavin Feb. 5, 2014, 2:37 a.m. UTC | #2
On Wed, Feb 05, 2014 at 12:10:16AM +0100, Christopher Heiny wrote:
> On 01/23/2014 04:00 PM, Courtney Cavin wrote:
>
> This is pretty interesting, and looks potentially useful.  I'm not very
> familiar with OF/DT structures, though.  What happens if there are two
> different RMI4 devices in the system, each of which has its own platform
> settings?
>

OF support will be required for most newer platforms as well as for
multi-platform support.

In order to support multiple devices, you just need a DT node for each
device.  The following is an example of two devices on the same I2C bus,
with the devices called "sensor_A" and "sensor_B" at the addresses 0x2c
and 0x2e respectively.

i2c@0 {
        ... /* I2C adapter settings */

        sensor_A@2c {
                compatible = "syn,rmi_i2c";
                reg = <0x2c>;
                interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
                ... /* sensor A settings */
        };


        sensor_B@2e {
                compatible = "syn,rmi_i2c";
                reg = <0x2e>;
                interrupts = <62 IRQ_TYPE_EDGE_RISING>;
                ... /* sensor B settings */
        }
};

> > Cc: Christopher Heiny <cheiny@synaptics.com>
> > Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > Signed-off-by: Courtney Cavin <courtney.cavin@sonymobile.com>
> > ---
> >   Documentation/devicetree/bindings/input/rmi4.txt   | 107 +++++++++++++++++
> >   .../devicetree/bindings/vendor-prefixes.txt        |   1 +
> >   drivers/input/rmi4/rmi_bus.c                       |  12 +-
> >   drivers/input/rmi4/rmi_bus.h                       |   3 +-
> >   drivers/input/rmi4/rmi_driver.c                    |  44 +++++--
> >   drivers/input/rmi4/rmi_f01.c                       | 107 +++++++++++++++--
> >   drivers/input/rmi4/rmi_f11.c                       | 133 ++++++++++++++++++++-
> >   drivers/input/rmi4/rmi_i2c.c                       |  19 +--
> >   8 files changed, 388 insertions(+), 38 deletions(-)
> >   create mode 100644 Documentation/devicetree/bindings/input/rmi4.txt
> >
> > diff --git a/Documentation/devicetree/bindings/input/rmi4.txt b/Documentation/devicetree/bindings/input/rmi4.txt
> > new file mode 100644
> > index 0000000..fff9db7
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/rmi4.txt
> > @@ -0,0 +1,107 @@
> > +Synaptics RMI4-based input device binding
> > +
> > +PROPERTIES
> > +
> > +compatible:
> > +     Usage: required
> > +     Type: string, must be "syn,rmi_i2c"
> > +
> > +interrupts:
> > +     Usage: required
> > +     Type: <prop-encoded-array>
> > +     Desc: See devicetree/bindings/interrupt-controller/interrupts.txt;
> > +             Trigger sense required in mask
> > +
> > +syn,reset-delay:
> > +     Usage: optional (default: 100)
> > +     Type: u32, milliseconds
> > +     Desc: Delay after issuing a reset
> > +
> > +syn,power-no-sleep:
> > +     Usage: optional, mutually exclusive with syn,power-sleep
> > +             (default: chip-specific)
> > +     Type: boolean
> > +     Desc: Disable sleep mode
> > +
> > +syn,power-sleep:
> > +     Usage: optional, mutually exclusive with syn,power-no-sleep
> > +             (default: chip-specific)
> > +     Type: boolean
> > +     Desc: Enable sleep mode
> > +
> > +syn,power-wakeup-thresh:
> > +     Usage: optional (default: chip-specific)
> > +     Type: u32, chip-specific unit [0-255]
> > +     Desc: Capacitance threshold at which device should wake
> > +
> > +syn,power-doze-holdoff:
> > +     Usage: optional (default: chip-specific)
> > +     Type: u32, milliseconds [0-25500]
> > +     Desc: Idle delay before entering sleep mode
> > +
> > +syn,power-doze-interval:
> > +     Usage: optional (default: chip-specific)
> > +     Type: u32, milliseconds [0-2550]
> > +     Desc: Interval between checks for idle
> > +
> > +syn,2d-rezero-wait:
> > +     Usage: optional (default: no re-zeroing)
> > +     Type: u32, milliseconds [0-65535]
> > +     Desc: Delay after resume to re-zero sensor
> > +
> > +syn,2d-axis-swap:
> > +     Usage: optional (default: false)
> > +     Type: boolean
> > +     Desc: Swap X and Y axis
> > +
> > +syn,2d-flip-x:
> > +     Usage: optional (default: false)
> > +     Type: boolean
> > +     Desc: Invert X axis
> > +
> > +syn,2d-flip-y:
> > +     Usage: optional (default: false)
> > +     Type: boolean
> > +     Desc: Invert Y axis
> > +
> > +syn,2d-clip-range:
> > +     Usage: optional (default: clip disabled)
> > +     Type: u32 array (<top left bottom right>) [0-65535]
> > +     Usage: Clip values outside this range
> > +
> > +syn,2d-offset:
> > +     Usage: optional (default: offset disabled)
> > +     Type: u32 array (<X-offset Y-offset>) [0-65535]
> > +     Usage: Add offset values to reported events
> > +
> > +syn,2d-delta-thresh:
> > +     Usage: optional (default: chip-specific)
> > +     Type: u32 array (<X-delta Y-delta>) [0-255]
> > +     Usage: Minimum delta before event is reported
> > +
> > +syn,2d-sensor-type:
> > +     Usage: optional (default: chip-specific)
> > +     Type: string, "indirect" or "direct"
> > +     Usage: Set screen type for event reporting
> > +
> > +syn,2d-type-a:
> > +     Usage: optional (default: false)
> > +     Type: boolean
> > +     Usage: Sensor supports only Multifinger Type A protocol
> > +
> > +EXAMPLE
> > +
> > +i2c@0 {
> > +     compatible = "...";
> > +     #address-cells = <1>;
> > +     #size-cells = <0>;
> > +
> > +     synaptics_rmi4@2c {
> > +             compatible = "syn,rmi_i2c";
> > +             reg = <0x2c>;
> > +
> > +             interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
> > +
> > +             syn,2d-clip-range = <0 0 1919 1079>;
> > +     };
> > +};
> > diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> > index edbb8d8..3388986 100644
> > --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> > +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> > @@ -72,6 +72,7 @@ snps        Synopsys, Inc.
> >   st  STMicroelectronics
> >   ste ST-Ericsson
> >   stericsson  ST-Ericsson
> > +syn  Synaptics, Inc.
> >   ti  Texas Instruments
> >   toshiba     Toshiba Corporation
> >   toumaz      Toumaz
> > diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
> > index a51e6b4..57de579 100644
> > --- a/drivers/input/rmi4/rmi_bus.c
> > +++ b/drivers/input/rmi4/rmi_bus.c
> > @@ -52,14 +52,11 @@ bool rmi_is_physical_device(struct device *dev)
> >   int rmi_register_transport_device(struct rmi_transport_dev *xport)
> >   {
> >       static atomic_t transport_device_count = ATOMIC_INIT(0);
> > -     struct rmi_device_platform_data *pdata = xport->dev->platform_data;
> >       struct rmi_device *rmi_dev;
> >       int error;
> >
> > -     if (!pdata) {
> > -             dev_err(xport->dev, "no platform data!\n");
> > -             return -EINVAL;
> > -     }
> > +     if (unlikely(!rmi_bus_type.p))
> > +             return -EPROBE_DEFER;
> >
> >       rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
> >       if (!rmi_dev)
> > @@ -70,8 +67,10 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport)
> >
> >       dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
> >
> > +     rmi_dev->dev.parent = xport->dev;
> >       rmi_dev->dev.bus = &rmi_bus_type;
> >       rmi_dev->dev.type = &rmi_device_type;
> > +     rmi_dev->dev.of_node = xport->dev->of_node;
> >
> >       xport->rmi_dev = rmi_dev;
> >
> > @@ -206,6 +205,9 @@ int __rmi_register_function_handler(struct rmi_function_handler *handler,
> >       struct device_driver *driver = &handler->driver;
> >       int error;
> >
> > +     if (WARN_ON(unlikely(!rmi_bus_type.p)))
> > +             return -EAGAIN;
> > +
> >       driver->bus = &rmi_bus_type;
> >       driver->owner = owner;
> >       driver->mod_name = mod_name;
> > diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
> > index a21e4c4..51f9372 100644
> > --- a/drivers/input/rmi4/rmi_bus.h
> > +++ b/drivers/input/rmi4/rmi_bus.h
> > @@ -212,7 +212,8 @@ struct rmi_device {
> >   };
> >
> >   #define to_rmi_device(d) container_of(d, struct rmi_device, dev)
> > -#define to_rmi_platform_data(d) ((d)->xport->dev->platform_data)
> > +#define to_rmi_xport_device(d) ((d)->xport->dev)
> > +#define to_rmi_platform_data(d) (dev_get_platdata(to_rmi_xport_device(d)))
> >
> >   bool rmi_is_physical_device(struct device *dev);
> >
> > diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
> > index 9ec7b93..92415ce 100644
> > --- a/drivers/input/rmi4/rmi_driver.c
> > +++ b/drivers/input/rmi4/rmi_driver.c
> > @@ -26,6 +26,8 @@
> >   #include <linux/rmi.h>
> >   #include <linux/slab.h>
> >   #include <linux/uaccess.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of.h>
> >   #include <uapi/linux/input.h>
> >   #include "rmi_bus.h"
> >   #include "rmi_driver.h"
> > @@ -498,7 +500,7 @@ static int create_function(struct rmi_device *rmi_dev,
> >    * We have to do this before actually building the PDT because the reflash
> >    * updates (if any) might cause various registers to move around.
> >    */
> > -static int rmi_initial_reset(struct rmi_device *rmi_dev)
> > +static int rmi_initial_reset(struct rmi_device *rmi_dev, u32 reset_delay)
> >   {
> >       struct pdt_entry pdt_entry;
> >       int page;
> > @@ -507,8 +509,6 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev)
> >       bool has_f01 = false;
> >       int i;
> >       int retval;
> > -     const struct rmi_device_platform_data *pdata =
> > -                     to_rmi_platform_data(rmi_dev);
> >
> >       dev_dbg(dev, "Initial reset.\n");
> >
> > @@ -538,7 +538,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev)
> >                                               retval);
> >                                       return retval;
> >                               }
> > -                             mdelay(pdata->reset_delay_ms);
> > +                             mdelay(reset_delay);
> >                               done = true;
> >                               has_f01 = true;
> >                               break;
> > @@ -648,6 +648,8 @@ static int rmi_driver_probe(struct device *dev)
> >       struct rmi_device_platform_data *pdata;
> >       int retval = 0;
> >       struct rmi_device *rmi_dev;
> > +     unsigned int irq;
> > +     u32 reset_delay;
> >
> >       dev_dbg(dev, "%s: Starting probe.\n", __func__);
> >
> > @@ -661,6 +663,28 @@ static int rmi_driver_probe(struct device *dev)
> >       rmi_dev->driver = rmi_driver;
> >
> >       pdata = to_rmi_platform_data(rmi_dev);
> > +     if (pdata == NULL) {
> > +#ifdef CONFIG_OF
> > +             const char *p;
> > +
> > +             p = "syn,reset-delay";
> > +             retval = of_property_read_u32(dev->of_node, p, &reset_delay);
> > +             if (retval && retval != -EINVAL) {
> > +                     dev_err(dev, "Invalid '%s' property\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             if (retval == -EINVAL)
> > +                     reset_delay = 0;
> > +
> > +             irq = irq_of_parse_and_map(dev->of_node, 0);
> > +#else
> > +             dev_err(dev, "No pdata\n");
> > +             return -EINVAL;
> > +#endif
> > +     } else {
> > +             reset_delay = pdata->reset_delay_ms;
> > +             irq = pdata->irq;
> > +     }
> >
> >       data = devm_kzalloc(dev, sizeof(struct rmi_driver_data), GFP_KERNEL);
> >       if (!data) {
> > @@ -688,9 +712,9 @@ static int rmi_driver_probe(struct device *dev)
> >        * and leave the customer's device unusable.  So we warn them, and
> >        * continue processing.
> >        */
> > -     if (!pdata->reset_delay_ms)
> > -             pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
> > -     retval = rmi_initial_reset(rmi_dev);
> > +     if (!reset_delay)
> > +             reset_delay = DEFAULT_RESET_DELAY_MS;
> > +     retval = rmi_initial_reset(rmi_dev, reset_delay);
> >       if (retval)
> >               dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
> >
> > @@ -762,10 +786,10 @@ static int rmi_driver_probe(struct device *dev)
> >               goto err_free_data;
> >       }
> >
> > -     data->irq = pdata->irq;
> > -     if (data->irq < 0) {
> > +     data->irq = irq;
> > +     if (data->irq < 0 || data->irq == NO_IRQ) {
> >               dev_err(dev, "Failed to get attn IRQ.\n");
> > -             retval = data->irq;
> > +             retval = -EINVAL;
> >               goto err_free_data;
> >
> >       }
> > diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
> > index 4cb9fcb..22b57f2 100644
> > --- a/drivers/input/rmi4/rmi_f01.c
> > +++ b/drivers/input/rmi4/rmi_f01.c
> > @@ -12,6 +12,7 @@
> >   #include <linux/rmi.h>
> >   #include <linux/slab.h>
> >   #include <linux/uaccess.h>
> > +#include <linux/of.h>
> >   #include "rmi_driver.h"
> >
> >   #define RMI_PRODUCT_ID_LENGTH    10
> > @@ -169,15 +170,104 @@ static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
> >       return 0;
> >   }
> >
> > +#ifdef CONFIG_OF
> > +static int rmi_f01_of_parse(struct device *dev,
> > +             struct rmi_f01_power_management *cdata)
> > +{
> > +     bool sleep, nosleep;
> > +     const char *p;
> > +     u32 val;
> > +     int rc;
> > +
> > +     if (dev->of_node == NULL)
> > +             return -EINVAL;
> > +
> > +     memset(cdata, 0, sizeof(*cdata));
> > +
> > +     sleep = of_property_read_bool(dev->of_node, "syn,power-sleep");
> > +     nosleep = of_property_read_bool(dev->of_node, "syn,power-nosleep");
> > +     if (sleep && nosleep) {
> > +             dev_err(dev, "'syn,power-sleep' and 'syn,power-nosleep' are mutually exclusive\n");
> > +             return -EINVAL;
> > +     }
> > +     if (sleep)
> > +             cdata->nosleep = RMI_F01_NOSLEEP_OFF;
> > +     else if (nosleep)
> > +             cdata->nosleep = RMI_F01_NOSLEEP_ON;
> > +
> > +     p = "syn,power-wakeup-thresh";
> > +     rc = of_property_read_u32(dev->of_node, p, &val);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if (val & ~0xff) {
> > +                     dev_err(dev, "'%s' out of range [0-255]\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->wakeup_threshold = val;
> > +     }
> > +
> > +     p = "syn,power-doze-holdoff";
> > +     rc = of_property_read_u32(dev->of_node, p, &val);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if (val > 25500) {
> > +                     dev_err(dev, "'%s' out of range [0-25500]ms\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->doze_holdoff = (val + 50) / 100;
> > +     }
> > +
> > +     p = "syn,power-doze-interval";
> > +     rc = of_property_read_u32(dev->of_node, p, &val);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if (val > 2550) {
> > +                     dev_err(dev, "'%s' out of range [0-2550]ms\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->doze_interval = (val + 5) / 10;
> > +     }
> > +
> > +     return 0;
> > +}
> > +#else
> > +static int rmi_f01_of_parse(struct device *dev,
> > +             struct rmi_f01_power_management *cdata)
> > +{
> > +     return -EINVAL;
> > +}
> > +#endif
> > +
> >   static int rmi_f01_initialize(struct rmi_function *fn)
> >   {
> >       u8 temp;
> >       int error;
> >       u16 ctrl_base_addr;
> > +     struct rmi_f01_power_management cdata;
> >       struct rmi_device *rmi_dev = fn->rmi_dev;
> > +     struct device *dev = to_rmi_xport_device(rmi_dev);
> >       struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
> >       struct f01_data *data = fn->data;
> > -     struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
> > +     struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
> > +
> > +     if (pdata != NULL) {
> > +             cdata = pdata->power_management;
> > +     } else {
> > +             error = rmi_f01_of_parse(dev, &cdata);
> > +             if (error) {
> > +                     dev_err(dev, "Unable to parse DT data\n");
> > +                     return error;
> > +             }
> > +     }
> >
> >       /*
> >        * Set the configured bit and (optionally) other important stuff
> > @@ -191,7 +281,7 @@ static int rmi_f01_initialize(struct rmi_function *fn)
> >               dev_err(&fn->dev, "Failed to read F01 control.\n");
> >               return error;
> >       }
> > -     switch (pdata->power_management.nosleep) {
> > +     switch (cdata.nosleep) {
> >       case RMI_F01_NOSLEEP_DEFAULT:
> >               break;
> >       case RMI_F01_NOSLEEP_OFF:
> > @@ -262,9 +352,9 @@ static int rmi_f01_initialize(struct rmi_function *fn)
> >               data->doze_interval_addr = ctrl_base_addr;
> >               ctrl_base_addr++;
> >
> > -             if (pdata->power_management.doze_interval) {
> > +             if (cdata.doze_interval) {
> >                       data->device_control.doze_interval =
> > -                             pdata->power_management.doze_interval;
> > +                             cdata.doze_interval;
> >                       error = rmi_write(rmi_dev, data->doze_interval_addr,
> >                                       data->device_control.doze_interval);
> >                       if (error < 0) {
> > @@ -283,9 +373,9 @@ static int rmi_f01_initialize(struct rmi_function *fn)
> >               data->wakeup_threshold_addr = ctrl_base_addr;
> >               ctrl_base_addr++;
> >
> > -             if (pdata->power_management.wakeup_threshold) {
> > +             if (cdata.wakeup_threshold) {
> >                       data->device_control.wakeup_threshold =
> > -                             pdata->power_management.wakeup_threshold;
> > +                             cdata.wakeup_threshold;
> >                       error = rmi_write(rmi_dev, data->wakeup_threshold_addr,
> >                                       data->device_control.wakeup_threshold);
> >                       if (error < 0) {
> > @@ -306,9 +396,8 @@ static int rmi_f01_initialize(struct rmi_function *fn)
> >               data->doze_holdoff_addr = ctrl_base_addr;
> >               ctrl_base_addr++;
> >
> > -             if (pdata->power_management.doze_holdoff) {
> > -                     data->device_control.doze_holdoff =
> > -                             pdata->power_management.doze_holdoff;
> > +             if (cdata.doze_holdoff) {
> > +                     data->device_control.doze_holdoff = cdata.doze_holdoff;
> >                       error = rmi_write(rmi_dev, data->doze_holdoff_addr,
> >                                       data->device_control.doze_holdoff);
> >                       if (error < 0) {
> > diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
> > index b114f25..837b6e7 100644
> > --- a/drivers/input/rmi4/rmi_f11.c
> > +++ b/drivers/input/rmi4/rmi_f11.c
> > @@ -13,6 +13,7 @@
> >   #include <linux/input.h>
> >   #include <linux/input/mt.h>
> >   #include <linux/kconfig.h>
> > +#include <linux/of.h>
> >   #include <linux/rmi.h>
> >   #include <linux/slab.h>
> >   #include "rmi_driver.h"
> > @@ -794,9 +795,120 @@ static void f11_set_abs_params(struct rmi_function *fn)
> >                                    0, MT_TOOL_FINGER, 0, 0);
> >   }
> >
> > +#ifdef CONFIG_OF
> > +static int rmi_f11_of_parse(struct device *dev,
> > +             struct rmi_f11_sensor_data *cdata)
> > +{
> > +     const char *type;
> > +     const char *p;
> > +     u32 a[4];
> > +     int rc;
> > +
> > +     if (dev->of_node == NULL)
> > +             return -EINVAL;
> > +
> > +     memset(cdata, 0, sizeof(*cdata));
> > +
> > +     p = "syn,2d-rezero-wait";
> > +     rc = of_property_read_u32(dev->of_node, p, &a[0]);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if (a[0] & ~0xffff) {
> > +                     dev_err(dev, "'%s' value out of range [0-65535]\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->rezero_wait = a[0];
> > +     }
> > +
> > +     cdata->type_a = of_property_read_bool(dev->of_node, "syn,2d-type-a");
> > +     cdata->axis_align.swap_axes = of_property_read_bool(dev->of_node,
> > +                     "syn,2d-axis-swap");
> > +     cdata->axis_align.flip_x = of_property_read_bool(dev->of_node,
> > +                     "syn,2d-flip-x");
> > +     cdata->axis_align.flip_y = of_property_read_bool(dev->of_node,
> > +                     "syn,2d-flip-y");
> > +
> > +     p = "syn-2d-clip-range";
> > +     rc = of_property_read_u32_array(dev->of_node, p, a, 4);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if ((a[0] | a[1] | a[2] | a[3]) & ~0xffff) {
> > +                     dev_err(dev, "'%s' values out of range [0-65535]\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->axis_align.clip_x_low = a[0];
> > +             cdata->axis_align.clip_y_low = a[1];
> > +             cdata->axis_align.clip_x_high = a[2];
> > +             cdata->axis_align.clip_y_high = a[3];
> > +     }
> > +
> > +     p = "syn-2d-offset";
> > +     rc = of_property_read_u32_array(dev->of_node, p, a, 2);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if ((a[0] | a[1]) & ~0xffff) {
> > +                     dev_err(dev, "'%s' values out of range [0-65535]\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->axis_align.offset_x = a[0];
> > +             cdata->axis_align.offset_y = a[1];
> > +     }
> > +
> > +     p = "syn,2d-delta-thresh";
> > +     rc = of_property_read_u32_array(dev->of_node, p, a, 2);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if ((a[0] | a[1]) & ~0xff) {
> > +                     dev_err(dev, "'%s' values out of range [0-255]\n", p);
> > +                     return -EINVAL;
> > +             }
> > +             cdata->axis_align.delta_x_threshold = a[0];
> > +             cdata->axis_align.delta_y_threshold = a[1];
> > +     }
> > +
> > +     p = "syn,2d-sensor-type";
> > +     rc = of_property_read_string(dev->of_node, p, &type);
> > +     if (rc && rc != -EINVAL) {
> > +             dev_err(dev, "Invalid '%s' property\n", p);
> > +             return rc;
> > +     }
> > +     if (rc != -EINVAL) {
> > +             if (!strcmp(type, "direct")) {
> > +                     cdata->sensor_type = RMI_F11_SENSOR_DIRECT;
> > +             } else if (!strcmp(type, "indirect")) {
> > +                     cdata->sensor_type = RMI_F11_SENSOR_INDIRECT;
> > +             } else {
> > +                     dev_err(dev, "'%s' must be one of: \"indirect\", \"direct\"\n", p);
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +#else
> > +static int rmi_f11_of_parse(struct device *dev,
> > +             struct rmi_f11_sensor_data *cdata)
> > +{
> > +     return -EINVAL;
> > +}
> > +#endif
> > +
> >   static int rmi_f11_initialize(struct rmi_function *fn)
> >   {
> >       struct rmi_device *rmi_dev = fn->rmi_dev;
> > +     struct device *dev = to_rmi_xport_device(rmi_dev);
> >       struct f11_data *f11;
> >       struct f11_2d_ctrl *ctrl;
> >       u8 query_offset;
> > @@ -804,12 +916,23 @@ static int rmi_f11_initialize(struct rmi_function *fn)
> >       u16 control_base_addr;
> >       u16 max_x_pos, max_y_pos, temp;
> >       int rc;
> > -     struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
> > +     struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
> > +     struct rmi_f11_sensor_data cdata;
> >       struct f11_2d_sensor *sensor;
> >       u8 buf;
> >
> >       dev_dbg(&fn->dev, "Initializing F11 values.\n");
> >
> > +     if (pdata != NULL) {
> > +             cdata = pdata->f11_sensor_data;
> > +     } else {
> > +             rc = rmi_f11_of_parse(dev, &cdata);
> > +             if (rc) {
> > +                     dev_err(dev, "Unable to parse DT data\n");
> > +                     return rc;
> > +             }
> > +     }
> > +
> >       /*
> >       ** init instance data, fill in values and create any sysfs files
> >       */
> > @@ -818,7 +941,7 @@ static int rmi_f11_initialize(struct rmi_function *fn)
> >               return -ENOMEM;
> >
> >       fn->data = f11;
> > -     f11->rezero_wait_ms = pdata->f11_sensor_data.rezero_wait;
> > +     f11->rezero_wait_ms = cdata.rezero_wait;
> >
> >       query_base_addr = fn->fd.query_base_addr;
> >       control_base_addr = fn->fd.control_base_addr;
> > @@ -851,9 +974,9 @@ static int rmi_f11_initialize(struct rmi_function *fn)
> >               return rc;
> >       }
> >
> > -     sensor->axis_align = pdata->f11_sensor_data.axis_align;
> > -     sensor->type_a = pdata->f11_sensor_data.type_a;
> > -     sensor->sensor_type = pdata->f11_sensor_data.sensor_type;
> > +     sensor->axis_align = cdata.axis_align;
> > +     sensor->type_a = cdata.type_a;
> > +     sensor->sensor_type = cdata.sensor_type;
> >
> >       rc = rmi_read_block(rmi_dev,
> >               control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET,
> > diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
> > index aebf974..377d4cc 100644
> > --- a/drivers/input/rmi4/rmi_i2c.c
> > +++ b/drivers/input/rmi4/rmi_i2c.c
> > @@ -186,16 +186,9 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
> >   static int rmi_i2c_probe(struct i2c_client *client,
> >                        const struct i2c_device_id *id)
> >   {
> > -     const struct rmi_device_platform_data *pdata =
> > -                             dev_get_platdata(&client->dev);
> >       struct rmi_i2c_xport *rmi_i2c;
> >       int retval;
> >
> > -     if (!pdata) {
> > -             dev_err(&client->dev, "no platform data\n");
> > -             return -EINVAL;
> > -     }
> > -
> >       dev_dbg(&client->dev, "Probing %#02x.\n", client->addr);
> >
> >       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> > @@ -258,10 +251,20 @@ static const struct i2c_device_id rmi_id[] = {
> >   };
> >   MODULE_DEVICE_TABLE(i2c, rmi_id);
> >
> > +#ifdef CONFIG_OF
> > +static struct of_device_id rmi_match_table[] = {
> > +     { .compatible = "syn,rmi_i2c", },
> > +     { },
> > +};
> > +#else
> > +#define rmi_match_table NULL
> > +#endif
> > +
> >   static struct i2c_driver rmi_i2c_driver = {
> >       .driver = {
> >               .owner  = THIS_MODULE,
> > -             .name   = "rmi_i2c"
> > +             .name   = "rmi_i2c",
> > +             .of_match_table = rmi_match_table,
> >       },
> >       .id_table       = rmi_id,
> >       .probe          = rmi_i2c_probe,
> >
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/input/rmi4.txt b/Documentation/devicetree/bindings/input/rmi4.txt
new file mode 100644
index 0000000..fff9db7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/rmi4.txt
@@ -0,0 +1,107 @@ 
+Synaptics RMI4-based input device binding
+
+PROPERTIES
+
+compatible:
+	Usage: required
+	Type: string, must be "syn,rmi_i2c"
+
+interrupts:
+	Usage: required
+	Type: <prop-encoded-array>
+	Desc: See devicetree/bindings/interrupt-controller/interrupts.txt;
+		Trigger sense required in mask
+
+syn,reset-delay:
+	Usage: optional (default: 100)
+	Type: u32, milliseconds
+	Desc: Delay after issuing a reset
+
+syn,power-no-sleep:
+	Usage: optional, mutually exclusive with syn,power-sleep
+		(default: chip-specific)
+	Type: boolean
+	Desc: Disable sleep mode
+
+syn,power-sleep:
+	Usage: optional, mutually exclusive with syn,power-no-sleep
+		(default: chip-specific)
+	Type: boolean
+	Desc: Enable sleep mode
+
+syn,power-wakeup-thresh:
+	Usage: optional (default: chip-specific)
+	Type: u32, chip-specific unit [0-255]
+	Desc: Capacitance threshold at which device should wake
+
+syn,power-doze-holdoff:
+	Usage: optional (default: chip-specific)
+	Type: u32, milliseconds [0-25500]
+	Desc: Idle delay before entering sleep mode
+
+syn,power-doze-interval:
+	Usage: optional (default: chip-specific)
+	Type: u32, milliseconds [0-2550]
+	Desc: Interval between checks for idle
+
+syn,2d-rezero-wait:
+	Usage: optional (default: no re-zeroing)
+	Type: u32, milliseconds [0-65535]
+	Desc: Delay after resume to re-zero sensor
+
+syn,2d-axis-swap:
+	Usage: optional (default: false)
+	Type: boolean
+	Desc: Swap X and Y axis
+
+syn,2d-flip-x:
+	Usage: optional (default: false)
+	Type: boolean
+	Desc: Invert X axis
+
+syn,2d-flip-y:
+	Usage: optional (default: false)
+	Type: boolean
+	Desc: Invert Y axis
+
+syn,2d-clip-range:
+	Usage: optional (default: clip disabled)
+	Type: u32 array (<top left bottom right>) [0-65535]
+	Usage: Clip values outside this range
+
+syn,2d-offset:
+	Usage: optional (default: offset disabled)
+	Type: u32 array (<X-offset Y-offset>) [0-65535]
+	Usage: Add offset values to reported events
+
+syn,2d-delta-thresh:
+	Usage: optional (default: chip-specific)
+	Type: u32 array (<X-delta Y-delta>) [0-255]
+	Usage: Minimum delta before event is reported
+
+syn,2d-sensor-type:
+	Usage: optional (default: chip-specific)
+	Type: string, "indirect" or "direct"
+	Usage: Set screen type for event reporting
+
+syn,2d-type-a:
+	Usage: optional (default: false)
+	Type: boolean
+	Usage: Sensor supports only Multifinger Type A protocol
+
+EXAMPLE
+
+i2c@0 {
+	compatible = "...";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	synaptics_rmi4@2c {
+		compatible = "syn,rmi_i2c";
+		reg = <0x2c>;
+
+		interrupts = <61 IRQ_TYPE_EDGE_FALLING>;
+
+		syn,2d-clip-range = <0 0 1919 1079>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index edbb8d8..3388986 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -72,6 +72,7 @@  snps 	Synopsys, Inc.
 st	STMicroelectronics
 ste	ST-Ericsson
 stericsson	ST-Ericsson
+syn	Synaptics, Inc.
 ti	Texas Instruments
 toshiba	Toshiba Corporation
 toumaz	Toumaz
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index a51e6b4..57de579 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -52,14 +52,11 @@  bool rmi_is_physical_device(struct device *dev)
 int rmi_register_transport_device(struct rmi_transport_dev *xport)
 {
 	static atomic_t transport_device_count = ATOMIC_INIT(0);
-	struct rmi_device_platform_data *pdata = xport->dev->platform_data;
 	struct rmi_device *rmi_dev;
 	int error;
 
-	if (!pdata) {
-		dev_err(xport->dev, "no platform data!\n");
-		return -EINVAL;
-	}
+	if (unlikely(!rmi_bus_type.p))
+		return -EPROBE_DEFER;
 
 	rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
 	if (!rmi_dev)
@@ -70,8 +67,10 @@  int rmi_register_transport_device(struct rmi_transport_dev *xport)
 
 	dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
 
+	rmi_dev->dev.parent = xport->dev;
 	rmi_dev->dev.bus = &rmi_bus_type;
 	rmi_dev->dev.type = &rmi_device_type;
+	rmi_dev->dev.of_node = xport->dev->of_node;
 
 	xport->rmi_dev = rmi_dev;
 
@@ -206,6 +205,9 @@  int __rmi_register_function_handler(struct rmi_function_handler *handler,
 	struct device_driver *driver = &handler->driver;
 	int error;
 
+	if (WARN_ON(unlikely(!rmi_bus_type.p)))
+		return -EAGAIN;
+
 	driver->bus = &rmi_bus_type;
 	driver->owner = owner;
 	driver->mod_name = mod_name;
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index a21e4c4..51f9372 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -212,7 +212,8 @@  struct rmi_device {
 };
 
 #define to_rmi_device(d) container_of(d, struct rmi_device, dev)
-#define to_rmi_platform_data(d) ((d)->xport->dev->platform_data)
+#define to_rmi_xport_device(d) ((d)->xport->dev)
+#define to_rmi_platform_data(d) (dev_get_platdata(to_rmi_xport_device(d)))
 
 bool rmi_is_physical_device(struct device *dev);
 
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 9ec7b93..92415ce 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -26,6 +26,8 @@ 
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
 #include <uapi/linux/input.h>
 #include "rmi_bus.h"
 #include "rmi_driver.h"
@@ -498,7 +500,7 @@  static int create_function(struct rmi_device *rmi_dev,
  * We have to do this before actually building the PDT because the reflash
  * updates (if any) might cause various registers to move around.
  */
-static int rmi_initial_reset(struct rmi_device *rmi_dev)
+static int rmi_initial_reset(struct rmi_device *rmi_dev, u32 reset_delay)
 {
 	struct pdt_entry pdt_entry;
 	int page;
@@ -507,8 +509,6 @@  static int rmi_initial_reset(struct rmi_device *rmi_dev)
 	bool has_f01 = false;
 	int i;
 	int retval;
-	const struct rmi_device_platform_data *pdata =
-			to_rmi_platform_data(rmi_dev);
 
 	dev_dbg(dev, "Initial reset.\n");
 
@@ -538,7 +538,7 @@  static int rmi_initial_reset(struct rmi_device *rmi_dev)
 						retval);
 					return retval;
 				}
-				mdelay(pdata->reset_delay_ms);
+				mdelay(reset_delay);
 				done = true;
 				has_f01 = true;
 				break;
@@ -648,6 +648,8 @@  static int rmi_driver_probe(struct device *dev)
 	struct rmi_device_platform_data *pdata;
 	int retval = 0;
 	struct rmi_device *rmi_dev;
+	unsigned int irq;
+	u32 reset_delay;
 
 	dev_dbg(dev, "%s: Starting probe.\n", __func__);
 
@@ -661,6 +663,28 @@  static int rmi_driver_probe(struct device *dev)
 	rmi_dev->driver = rmi_driver;
 
 	pdata = to_rmi_platform_data(rmi_dev);
+	if (pdata == NULL) {
+#ifdef CONFIG_OF
+		const char *p;
+
+		p = "syn,reset-delay";
+		retval = of_property_read_u32(dev->of_node, p, &reset_delay);
+		if (retval && retval != -EINVAL) {
+			dev_err(dev, "Invalid '%s' property\n", p);
+			return -EINVAL;
+		}
+		if (retval == -EINVAL)
+			reset_delay = 0;
+
+		irq = irq_of_parse_and_map(dev->of_node, 0);
+#else
+		dev_err(dev, "No pdata\n");
+		return -EINVAL;
+#endif
+	} else {
+		reset_delay = pdata->reset_delay_ms;
+		irq = pdata->irq;
+	}
 
 	data = devm_kzalloc(dev, sizeof(struct rmi_driver_data), GFP_KERNEL);
 	if (!data) {
@@ -688,9 +712,9 @@  static int rmi_driver_probe(struct device *dev)
 	 * and leave the customer's device unusable.  So we warn them, and
 	 * continue processing.
 	 */
-	if (!pdata->reset_delay_ms)
-		pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
-	retval = rmi_initial_reset(rmi_dev);
+	if (!reset_delay)
+		reset_delay = DEFAULT_RESET_DELAY_MS;
+	retval = rmi_initial_reset(rmi_dev, reset_delay);
 	if (retval)
 		dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
 
@@ -762,10 +786,10 @@  static int rmi_driver_probe(struct device *dev)
 		goto err_free_data;
 	}
 
-	data->irq = pdata->irq;
-	if (data->irq < 0) {
+	data->irq = irq;
+	if (data->irq < 0 || data->irq == NO_IRQ) {
 		dev_err(dev, "Failed to get attn IRQ.\n");
-		retval = data->irq;
+		retval = -EINVAL;
 		goto err_free_data;
 
 	}
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index 4cb9fcb..22b57f2 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -12,6 +12,7 @@ 
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/of.h>
 #include "rmi_driver.h"
 
 #define RMI_PRODUCT_ID_LENGTH    10
@@ -169,15 +170,104 @@  static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static int rmi_f01_of_parse(struct device *dev,
+		struct rmi_f01_power_management *cdata)
+{
+	bool sleep, nosleep;
+	const char *p;
+	u32 val;
+	int rc;
+
+	if (dev->of_node == NULL)
+		return -EINVAL;
+
+	memset(cdata, 0, sizeof(*cdata));
+
+	sleep = of_property_read_bool(dev->of_node, "syn,power-sleep");
+	nosleep = of_property_read_bool(dev->of_node, "syn,power-nosleep");
+	if (sleep && nosleep) {
+		dev_err(dev, "'syn,power-sleep' and 'syn,power-nosleep' are mutually exclusive\n");
+		return -EINVAL;
+	}
+	if (sleep)
+		cdata->nosleep = RMI_F01_NOSLEEP_OFF;
+	else if (nosleep)
+		cdata->nosleep = RMI_F01_NOSLEEP_ON;
+
+	p = "syn,power-wakeup-thresh";
+	rc = of_property_read_u32(dev->of_node, p, &val);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if (val & ~0xff) {
+			dev_err(dev, "'%s' out of range [0-255]\n", p);
+			return -EINVAL;
+		}
+		cdata->wakeup_threshold = val;
+	}
+
+	p = "syn,power-doze-holdoff";
+	rc = of_property_read_u32(dev->of_node, p, &val);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if (val > 25500) {
+			dev_err(dev, "'%s' out of range [0-25500]ms\n", p);
+			return -EINVAL;
+		}
+		cdata->doze_holdoff = (val + 50) / 100;
+	}
+
+	p = "syn,power-doze-interval";
+	rc = of_property_read_u32(dev->of_node, p, &val);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if (val > 2550) {
+			dev_err(dev, "'%s' out of range [0-2550]ms\n", p);
+			return -EINVAL;
+		}
+		cdata->doze_interval = (val + 5) / 10;
+	}
+
+	return 0;
+}
+#else
+static int rmi_f01_of_parse(struct device *dev,
+		struct rmi_f01_power_management *cdata)
+{
+	return -EINVAL;
+}
+#endif
+
 static int rmi_f01_initialize(struct rmi_function *fn)
 {
 	u8 temp;
 	int error;
 	u16 ctrl_base_addr;
+	struct rmi_f01_power_management cdata;
 	struct rmi_device *rmi_dev = fn->rmi_dev;
+	struct device *dev = to_rmi_xport_device(rmi_dev);
 	struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
 	struct f01_data *data = fn->data;
-	struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
+	struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
+
+	if (pdata != NULL) {
+		cdata = pdata->power_management;
+	} else {
+		error = rmi_f01_of_parse(dev, &cdata);
+		if (error) {
+			dev_err(dev, "Unable to parse DT data\n");
+			return error;
+		}
+	}
 
 	/*
 	 * Set the configured bit and (optionally) other important stuff
@@ -191,7 +281,7 @@  static int rmi_f01_initialize(struct rmi_function *fn)
 		dev_err(&fn->dev, "Failed to read F01 control.\n");
 		return error;
 	}
-	switch (pdata->power_management.nosleep) {
+	switch (cdata.nosleep) {
 	case RMI_F01_NOSLEEP_DEFAULT:
 		break;
 	case RMI_F01_NOSLEEP_OFF:
@@ -262,9 +352,9 @@  static int rmi_f01_initialize(struct rmi_function *fn)
 		data->doze_interval_addr = ctrl_base_addr;
 		ctrl_base_addr++;
 
-		if (pdata->power_management.doze_interval) {
+		if (cdata.doze_interval) {
 			data->device_control.doze_interval =
-				pdata->power_management.doze_interval;
+				cdata.doze_interval;
 			error = rmi_write(rmi_dev, data->doze_interval_addr,
 					data->device_control.doze_interval);
 			if (error < 0) {
@@ -283,9 +373,9 @@  static int rmi_f01_initialize(struct rmi_function *fn)
 		data->wakeup_threshold_addr = ctrl_base_addr;
 		ctrl_base_addr++;
 
-		if (pdata->power_management.wakeup_threshold) {
+		if (cdata.wakeup_threshold) {
 			data->device_control.wakeup_threshold =
-				pdata->power_management.wakeup_threshold;
+				cdata.wakeup_threshold;
 			error = rmi_write(rmi_dev, data->wakeup_threshold_addr,
 					data->device_control.wakeup_threshold);
 			if (error < 0) {
@@ -306,9 +396,8 @@  static int rmi_f01_initialize(struct rmi_function *fn)
 		data->doze_holdoff_addr = ctrl_base_addr;
 		ctrl_base_addr++;
 
-		if (pdata->power_management.doze_holdoff) {
-			data->device_control.doze_holdoff =
-				pdata->power_management.doze_holdoff;
+		if (cdata.doze_holdoff) {
+			data->device_control.doze_holdoff = cdata.doze_holdoff;
 			error = rmi_write(rmi_dev, data->doze_holdoff_addr,
 					data->device_control.doze_holdoff);
 			if (error < 0) {
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index b114f25..837b6e7 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -13,6 +13,7 @@ 
 #include <linux/input.h>
 #include <linux/input/mt.h>
 #include <linux/kconfig.h>
+#include <linux/of.h>
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include "rmi_driver.h"
@@ -794,9 +795,120 @@  static void f11_set_abs_params(struct rmi_function *fn)
 				     0, MT_TOOL_FINGER, 0, 0);
 }
 
+#ifdef CONFIG_OF
+static int rmi_f11_of_parse(struct device *dev,
+		struct rmi_f11_sensor_data *cdata)
+{
+	const char *type;
+	const char *p;
+	u32 a[4];
+	int rc;
+
+	if (dev->of_node == NULL)
+		return -EINVAL;
+
+	memset(cdata, 0, sizeof(*cdata));
+
+	p = "syn,2d-rezero-wait";
+	rc = of_property_read_u32(dev->of_node, p, &a[0]);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if (a[0] & ~0xffff) {
+			dev_err(dev, "'%s' value out of range [0-65535]\n", p);
+			return -EINVAL;
+		}
+		cdata->rezero_wait = a[0];
+	}
+
+	cdata->type_a = of_property_read_bool(dev->of_node, "syn,2d-type-a");
+	cdata->axis_align.swap_axes = of_property_read_bool(dev->of_node,
+			"syn,2d-axis-swap");
+	cdata->axis_align.flip_x = of_property_read_bool(dev->of_node,
+			"syn,2d-flip-x");
+	cdata->axis_align.flip_y = of_property_read_bool(dev->of_node,
+			"syn,2d-flip-y");
+
+	p = "syn-2d-clip-range";
+	rc = of_property_read_u32_array(dev->of_node, p, a, 4);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if ((a[0] | a[1] | a[2] | a[3]) & ~0xffff) {
+			dev_err(dev, "'%s' values out of range [0-65535]\n", p);
+			return -EINVAL;
+		}
+		cdata->axis_align.clip_x_low = a[0];
+		cdata->axis_align.clip_y_low = a[1];
+		cdata->axis_align.clip_x_high = a[2];
+		cdata->axis_align.clip_y_high = a[3];
+	}
+
+	p = "syn-2d-offset";
+	rc = of_property_read_u32_array(dev->of_node, p, a, 2);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if ((a[0] | a[1]) & ~0xffff) {
+			dev_err(dev, "'%s' values out of range [0-65535]\n", p);
+			return -EINVAL;
+		}
+		cdata->axis_align.offset_x = a[0];
+		cdata->axis_align.offset_y = a[1];
+	}
+
+	p = "syn,2d-delta-thresh";
+	rc = of_property_read_u32_array(dev->of_node, p, a, 2);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if ((a[0] | a[1]) & ~0xff) {
+			dev_err(dev, "'%s' values out of range [0-255]\n", p);
+			return -EINVAL;
+		}
+		cdata->axis_align.delta_x_threshold = a[0];
+		cdata->axis_align.delta_y_threshold = a[1];
+	}
+
+	p = "syn,2d-sensor-type";
+	rc = of_property_read_string(dev->of_node, p, &type);
+	if (rc && rc != -EINVAL) {
+		dev_err(dev, "Invalid '%s' property\n", p);
+		return rc;
+	}
+	if (rc != -EINVAL) {
+		if (!strcmp(type, "direct")) {
+			cdata->sensor_type = RMI_F11_SENSOR_DIRECT;
+		} else if (!strcmp(type, "indirect")) {
+			cdata->sensor_type = RMI_F11_SENSOR_INDIRECT;
+		} else {
+			dev_err(dev, "'%s' must be one of: \"indirect\", \"direct\"\n", p);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+#else
+static int rmi_f11_of_parse(struct device *dev,
+		struct rmi_f11_sensor_data *cdata)
+{
+	return -EINVAL;
+}
+#endif
+
 static int rmi_f11_initialize(struct rmi_function *fn)
 {
 	struct rmi_device *rmi_dev = fn->rmi_dev;
+	struct device *dev = to_rmi_xport_device(rmi_dev);
 	struct f11_data *f11;
 	struct f11_2d_ctrl *ctrl;
 	u8 query_offset;
@@ -804,12 +916,23 @@  static int rmi_f11_initialize(struct rmi_function *fn)
 	u16 control_base_addr;
 	u16 max_x_pos, max_y_pos, temp;
 	int rc;
-	struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
+	struct rmi_device_platform_data *pdata = dev_get_platdata(dev);
+	struct rmi_f11_sensor_data cdata;
 	struct f11_2d_sensor *sensor;
 	u8 buf;
 
 	dev_dbg(&fn->dev, "Initializing F11 values.\n");
 
+	if (pdata != NULL) {
+		cdata = pdata->f11_sensor_data;
+	} else {
+		rc = rmi_f11_of_parse(dev, &cdata);
+		if (rc) {
+			dev_err(dev, "Unable to parse DT data\n");
+			return rc;
+		}
+	}
+
 	/*
 	** init instance data, fill in values and create any sysfs files
 	*/
@@ -818,7 +941,7 @@  static int rmi_f11_initialize(struct rmi_function *fn)
 		return -ENOMEM;
 
 	fn->data = f11;
-	f11->rezero_wait_ms = pdata->f11_sensor_data.rezero_wait;
+	f11->rezero_wait_ms = cdata.rezero_wait;
 
 	query_base_addr = fn->fd.query_base_addr;
 	control_base_addr = fn->fd.control_base_addr;
@@ -851,9 +974,9 @@  static int rmi_f11_initialize(struct rmi_function *fn)
 		return rc;
 	}
 
-	sensor->axis_align = pdata->f11_sensor_data.axis_align;
-	sensor->type_a = pdata->f11_sensor_data.type_a;
-	sensor->sensor_type = pdata->f11_sensor_data.sensor_type;
+	sensor->axis_align = cdata.axis_align;
+	sensor->type_a = cdata.type_a;
+	sensor->sensor_type = cdata.sensor_type;
 
 	rc = rmi_read_block(rmi_dev,
 		control_base_addr + F11_CTRL_SENSOR_MAX_X_POS_OFFSET,
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index aebf974..377d4cc 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -186,16 +186,9 @@  static const struct rmi_transport_ops rmi_i2c_ops = {
 static int rmi_i2c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	const struct rmi_device_platform_data *pdata =
-				dev_get_platdata(&client->dev);
 	struct rmi_i2c_xport *rmi_i2c;
 	int retval;
 
-	if (!pdata) {
-		dev_err(&client->dev, "no platform data\n");
-		return -EINVAL;
-	}
-
 	dev_dbg(&client->dev, "Probing %#02x.\n", client->addr);
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
@@ -258,10 +251,20 @@  static const struct i2c_device_id rmi_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rmi_id);
 
+#ifdef CONFIG_OF
+static struct of_device_id rmi_match_table[] = {
+	{ .compatible = "syn,rmi_i2c", },
+	{ },
+};
+#else
+#define rmi_match_table NULL
+#endif
+
 static struct i2c_driver rmi_i2c_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "rmi_i2c"
+		.name	= "rmi_i2c",
+		.of_match_table = rmi_match_table,
 	},
 	.id_table	= rmi_id,
 	.probe		= rmi_i2c_probe,