16cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg/* drivers/input/misc/gpio_event.c
26cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg *
36cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * Copyright (C) 2007 Google, Inc.
46cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg *
56cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * This software is licensed under the terms of the GNU General Public
66cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * License version 2, as published by the Free Software Foundation, and
76cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * may be copied, distributed, and modified under those terms.
86cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg *
96cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * This program is distributed in the hope that it will be useful,
106cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * but WITHOUT ANY WARRANTY; without even the implied warranty of
116cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
126cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg * GNU General Public License for more details.
136cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg *
146cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg */
156cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
166cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/module.h>
176cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/input.h>
186cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/gpio_event.h>
196cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/hrtimer.h>
206cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/platform_device.h>
216cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg#include <linux/slab.h>
226cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
236cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstruct gpio_event {
246cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event_input_devs *input_devs;
256cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	const struct gpio_event_platform_data *info;
266cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	void *state[0];
276cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg};
286cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
296cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic int gpio_input_event(
306cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct input_dev *dev, unsigned int type, unsigned int code, int value)
316cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
326cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int i;
336cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int devnr;
346cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int ret = 0;
356cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int tmp_ret;
366cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event_info **ii;
376cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event *ip = input_get_drvdata(dev);
386cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
396cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (devnr = 0; devnr < ip->input_devs->count; devnr++)
406cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		if (ip->input_devs->dev[devnr] == dev)
416cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			break;
426cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (devnr == ip->input_devs->count) {
436cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		pr_err("gpio_input_event: unknown device %p\n", dev);
446cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		return -EIO;
456cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
466cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
476cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
486cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		if ((*ii)->event) {
496cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			tmp_ret = (*ii)->event(ip->input_devs, *ii,
506cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg						&ip->state[i],
516cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg						devnr, type, code, value);
526cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			if (tmp_ret)
536cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				ret = tmp_ret;
546cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		}
556cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
566cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return ret;
576cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
586cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
596cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic int gpio_event_call_all_func(struct gpio_event *ip, int func)
606cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
616cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int i;
626cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int ret;
636cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event_info **ii;
646cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
656cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
666cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ii = ip->info->info;
676cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		for (i = 0; i < ip->info->info_count; i++, ii++) {
686cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			if ((*ii)->func == NULL) {
696cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				ret = -ENODEV;
706cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				pr_err("gpio_event_probe: Incomplete pdata, "
716cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg					"no function\n");
726cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				goto err_no_func;
736cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			}
746cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
756cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				continue;
766cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
776cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg					  func);
786cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			if (ret) {
796cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				pr_err("gpio_event_probe: function failed\n");
806cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				goto err_func_failed;
816cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			}
826cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		}
836cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		return 0;
846cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
856cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
866cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ret = 0;
876cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	i = ip->info->info_count;
886cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ii = ip->info->info + i;
896cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	while (i > 0) {
906cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		i--;
916cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ii--;
926cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
936cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			continue;
946cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		(*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
956cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_func_failed:
966cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_no_func:
976cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		;
986cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
996cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return ret;
1006cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
1016cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
102f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Crossstatic void __maybe_unused gpio_event_suspend(struct gpio_event *ip)
1036cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
1046cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
105f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross	if (ip->info->power)
106f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross		ip->info->power(ip->info, 0);
1076cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
1086cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
109f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Crossstatic void __maybe_unused gpio_event_resume(struct gpio_event *ip)
1106cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
111f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross	if (ip->info->power)
112f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross		ip->info->power(ip->info, 1);
1136cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
1146cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
1156cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1166cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic int gpio_event_probe(struct platform_device *pdev)
1176cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
1186cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int err;
1196cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event *ip;
1206cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event_platform_data *event_info;
1216cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int dev_count = 1;
1226cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int i;
1236cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int registered = 0;
1246cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1256cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	event_info = pdev->dev.platform_data;
1266cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (event_info == NULL) {
1276cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		pr_err("gpio_event_probe: No pdata\n");
1286cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		return -ENODEV;
1296cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1306cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if ((!event_info->name && !event_info->names[0]) ||
1316cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	    !event_info->info || !event_info->info_count) {
1326cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		pr_err("gpio_event_probe: Incomplete pdata\n");
1336cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		return -ENODEV;
1346cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1356cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (!event_info->name)
1366cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		while (event_info->names[dev_count])
1376cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			dev_count++;
1386cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ip = kzalloc(sizeof(*ip) +
1396cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		     sizeof(ip->state[0]) * event_info->info_count +
1406cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		     sizeof(*ip->input_devs) +
1416cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		     sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
1426cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (ip == NULL) {
1436cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		err = -ENOMEM;
1446cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		pr_err("gpio_event_probe: Failed to allocate private data\n");
1456cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		goto err_kp_alloc_failed;
1466cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1476cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ip->input_devs = (void*)&ip->state[event_info->info_count];
1486cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	platform_set_drvdata(pdev, ip);
1496cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1506cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = 0; i < dev_count; i++) {
1516cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		struct input_dev *input_dev = input_allocate_device();
1526cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		if (input_dev == NULL) {
1536cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			err = -ENOMEM;
1546cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			pr_err("gpio_event_probe: "
1556cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				"Failed to allocate input device\n");
1566cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			goto err_input_dev_alloc_failed;
1576cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		}
1586cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_set_drvdata(input_dev, ip);
1596cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_dev->name = event_info->name ?
1606cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg					event_info->name : event_info->names[i];
1616cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_dev->event = gpio_input_event;
1626cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ip->input_devs->dev[i] = input_dev;
1636cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1646cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ip->input_devs->count = dev_count;
1656cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	ip->info = event_info;
166f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross	if (event_info->power)
1676cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ip->info->power(ip->info, 1);
1686cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1696cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
1706cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	if (err)
1716cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		goto err_call_all_func_failed;
1726cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1736cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = 0; i < dev_count; i++) {
1746cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		err = input_register_device(ip->input_devs->dev[i]);
1756cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		if (err) {
1766cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			pr_err("gpio_event_probe: Unable to register %s "
1776cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg				"input device\n", ip->input_devs->dev[i]->name);
1786cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg			goto err_input_register_device_failed;
1796cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		}
1806cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		registered++;
1816cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1826cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1836cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return 0;
1846cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
1856cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_input_register_device_failed:
1866cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
1876cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_call_all_func_failed:
188f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross	if (event_info->power)
1896cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ip->info->power(ip->info, 0);
1906cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = 0; i < registered; i++)
1916cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_unregister_device(ip->input_devs->dev[i]);
1926cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = dev_count - 1; i >= registered; i--) {
1936cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_free_device(ip->input_devs->dev[i]);
1946cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_input_dev_alloc_failed:
1956cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		;
1966cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	}
1976cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	kfree(ip);
1986cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågerr_kp_alloc_failed:
1996cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return err;
2006cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
2016cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2026cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic int gpio_event_remove(struct platform_device *pdev)
2036cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
2046cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	struct gpio_event *ip = platform_get_drvdata(pdev);
2056cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	int i;
2066cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2076cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
208f811f7f66c3ca0047fbbfae747cb09433bd64824Colin Cross	if (ip->info->power)
2096cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		ip->info->power(ip->info, 0);
2106cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	for (i = 0; i < ip->input_devs->count; i++)
2116cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		input_unregister_device(ip->input_devs->dev[i]);
2126cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	kfree(ip);
2136cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return 0;
2146cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
2156cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2166cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic struct platform_driver gpio_event_driver = {
2176cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	.probe		= gpio_event_probe,
2186cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	.remove		= gpio_event_remove,
2196cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	.driver		= {
2206cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg		.name	= GPIO_EVENT_DEV_NAME,
2216cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	},
2226cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg};
2236cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2246cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic int __devinit gpio_event_init(void)
2256cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
2266cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	return platform_driver_register(&gpio_event_driver);
2276cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
2286cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2296cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågstatic void __exit gpio_event_exit(void)
2306cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg{
2316cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg	platform_driver_unregister(&gpio_event_driver);
2326cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg}
2336cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2346cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågmodule_init(gpio_event_init);
2356cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevågmodule_exit(gpio_event_exit);
2366cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
2376cf80c7fbf27523037b2306322c60cc97a23814cArve HjønnevågMODULE_DESCRIPTION("GPIO Event Driver");
2386cf80c7fbf27523037b2306322c60cc97a23814cArve HjønnevågMODULE_LICENSE("GPL");
2396cf80c7fbf27523037b2306322c60cc97a23814cArve Hjønnevåg
240