diff options
Diffstat (limited to 'drivers/input/keyboard/omap4-keypad.c')
| -rw-r--r-- | drivers/input/keyboard/omap4-keypad.c | 127 | 
1 files changed, 87 insertions, 40 deletions
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index aed5f6999ce..c05f98c4141 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -27,6 +27,7 @@  #include <linux/platform_device.h>  #include <linux/errno.h>  #include <linux/io.h> +#include <linux/of.h>  #include <linux/input.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> @@ -84,8 +85,9 @@ struct omap4_keypad {  	u32 reg_offset;  	u32 irqreg_offset;  	unsigned int row_shift; +	bool no_autorepeat;  	unsigned char key_state[8]; -	unsigned short keymap[]; +	unsigned short *keymap;  };  static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) @@ -208,25 +210,51 @@ static void omap4_keypad_close(struct input_dev *input)  	pm_runtime_put_sync(input->dev.parent);  } +#ifdef CONFIG_OF +static int __devinit omap4_keypad_parse_dt(struct device *dev, +					   struct omap4_keypad *keypad_data) +{ +	struct device_node *np = dev->of_node; + +	if (!np) { +		dev_err(dev, "missing DT data"); +		return -EINVAL; +	} + +	of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); +	of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); +	if (!keypad_data->rows || !keypad_data->cols) { +		dev_err(dev, "number of keypad rows/columns not specified\n"); +		return -EINVAL; +	} + +	if (of_get_property(np, "linux,input-no-autorepeat", NULL)) +		keypad_data->no_autorepeat = true; + +	return 0; +} +#else +static inline int omap4_keypad_parse_dt(struct device *dev, +					struct omap4_keypad *keypad_data) +{ +	return -ENOSYS; +} +#endif +  static int __devinit omap4_keypad_probe(struct platform_device *pdev)  { -	const struct omap4_keypad_platform_data *pdata; +	const struct omap4_keypad_platform_data *pdata = +				dev_get_platdata(&pdev->dev); +	const struct matrix_keymap_data *keymap_data = +				pdata ? pdata->keymap_data : NULL;  	struct omap4_keypad *keypad_data;  	struct input_dev *input_dev;  	struct resource *res; -	resource_size_t size; -	unsigned int row_shift, max_keys; +	unsigned int max_keys;  	int rev;  	int irq;  	int error; -	/* platform data */ -	pdata = pdev->dev.platform_data; -	if (!pdata) { -		dev_err(&pdev->dev, "no platform data defined\n"); -		return -EINVAL; -	} -  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) {  		dev_err(&pdev->dev, "no base address specified\n"); @@ -239,25 +267,24 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	if (!pdata->keymap_data) { -		dev_err(&pdev->dev, "no keymap data defined\n"); -		return -EINVAL; -	} - -	row_shift = get_count_order(pdata->cols); -	max_keys = pdata->rows << row_shift; - -	keypad_data = kzalloc(sizeof(struct omap4_keypad) + -				max_keys * sizeof(keypad_data->keymap[0]), -			      GFP_KERNEL); +	keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);  	if (!keypad_data) {  		dev_err(&pdev->dev, "keypad_data memory allocation failed\n");  		return -ENOMEM;  	} -	size = resource_size(res); +	keypad_data->irq = irq; + +	if (pdata) { +		keypad_data->rows = pdata->rows; +		keypad_data->cols = pdata->cols; +	} else { +		error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); +		if (error) +			return error; +	} -	res = request_mem_region(res->start, size, pdev->name); +	res = request_mem_region(res->start, resource_size(res), pdev->name);  	if (!res) {  		dev_err(&pdev->dev, "can't request mem region\n");  		error = -EBUSY; @@ -271,15 +298,11 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)  		goto err_release_mem;  	} -	keypad_data->irq = irq; -	keypad_data->row_shift = row_shift; -	keypad_data->rows = pdata->rows; -	keypad_data->cols = pdata->cols;  	/* -	* Enable clocks for the keypad module so that we can read -	* revision register. -	*/ +	 * Enable clocks for the keypad module so that we can read +	 * revision register. +	 */  	pm_runtime_enable(&pdev->dev);  	error = pm_runtime_get_sync(&pdev->dev);  	if (error) { @@ -322,19 +345,30 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)  	input_dev->open = omap4_keypad_open;  	input_dev->close = omap4_keypad_close; -	error = matrix_keypad_build_keymap(pdata->keymap_data, NULL, -					   pdata->rows, pdata->cols, +	input_set_capability(input_dev, EV_MSC, MSC_SCAN); +	if (!keypad_data->no_autorepeat) +		__set_bit(EV_REP, input_dev->evbit); + +	input_set_drvdata(input_dev, keypad_data); + +	keypad_data->row_shift = get_count_order(keypad_data->cols); +	max_keys = keypad_data->rows << keypad_data->row_shift; +	keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]), +				      GFP_KERNEL); +	if (!keypad_data->keymap) { +		dev_err(&pdev->dev, "Not enough memory for keymap\n"); +		error = -ENOMEM; +		goto err_free_input; +	} + +	error = matrix_keypad_build_keymap(keymap_data, NULL, +					   keypad_data->rows, keypad_data->cols,  					   keypad_data->keymap, input_dev);  	if (error) {  		dev_err(&pdev->dev, "failed to build keymap\n"); -		goto err_free_input; +		goto err_free_keymap;  	} -	__set_bit(EV_REP, input_dev->evbit); -	input_set_capability(input_dev, EV_MSC, MSC_SCAN); - -	input_set_drvdata(input_dev, keypad_data); -  	error = request_irq(keypad_data->irq, omap4_keypad_interrupt,  			     IRQF_TRIGGER_RISING,  			     "omap4-keypad", keypad_data); @@ -357,6 +391,8 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)  err_pm_disable:  	pm_runtime_disable(&pdev->dev);  	free_irq(keypad_data->irq, keypad_data); +err_free_keymap: +	kfree(keypad_data->keymap);  err_free_input:  	input_free_device(input_dev);  err_pm_put_sync: @@ -364,7 +400,7 @@ err_pm_put_sync:  err_unmap:  	iounmap(keypad_data->base);  err_release_mem: -	release_mem_region(res->start, size); +	release_mem_region(res->start, resource_size(res));  err_free_keypad:  	kfree(keypad_data);  	return error; @@ -386,18 +422,29 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev)  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	release_mem_region(res->start, resource_size(res)); +	kfree(keypad_data->keymap);  	kfree(keypad_data); +  	platform_set_drvdata(pdev, NULL);  	return 0;  } +#ifdef CONFIG_OF +static const struct of_device_id omap_keypad_dt_match[] = { +	{ .compatible = "ti,omap4-keypad" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); +#endif +  static struct platform_driver omap4_keypad_driver = {  	.probe		= omap4_keypad_probe,  	.remove		= __devexit_p(omap4_keypad_remove),  	.driver		= {  		.name	= "omap4-keypad",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(omap_keypad_dt_match),  	},  };  module_platform_driver(omap4_keypad_driver);  |