gpio-ir-recv.c 6.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/slab.h>
19
#include <linux/of.h>
20
#include <linux/of_gpio.h>
21 22 23
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <media/rc-core.h>
24
#include <linux/platform_data/media/gpio-ir-recv.h>
25 26 27 28 29 30

#define GPIO_IR_DRIVER_NAME	"gpio-rc-recv"
#define GPIO_IR_DEVICE_NAME	"gpio_ir_recv"

struct gpio_rc_dev {
	struct rc_dev *rcdev;
31
	int gpio_nr;
32 33 34
	bool active_low;
};

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#ifdef CONFIG_OF
/*
 * Translate OpenFirmware node properties into platform_data
 */
static int gpio_ir_recv_get_devtree_pdata(struct device *dev,
				  struct gpio_ir_recv_platform_data *pdata)
{
	struct device_node *np = dev->of_node;
	enum of_gpio_flags flags;
	int gpio;

	gpio = of_get_gpio_flags(np, 0, &flags);
	if (gpio < 0) {
		if (gpio != -EPROBE_DEFER)
			dev_err(dev, "Failed to get gpio flags (%d)\n", gpio);
		return gpio;
	}

	pdata->gpio_nr = gpio;
	pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW);
	/* probe() takes care of map_name == NULL or allowed_protos == 0 */
	pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL);
	pdata->allowed_protos = 0;

	return 0;
}

62
static const struct of_device_id gpio_ir_recv_of_match[] = {
63 64 65 66 67 68 69 70 71 72 73
	{ .compatible = "gpio-ir-receiver", },
	{ },
};
MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);

#else /* !CONFIG_OF */

#define gpio_ir_recv_get_devtree_pdata(dev, pdata)	(-ENOSYS)

#endif

74 75 76
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
	struct gpio_rc_dev *gpio_dev = dev_id;
77
	int gval;
78 79
	int rc = 0;

80
	gval = gpio_get_value(gpio_dev->gpio_nr);
81 82 83 84 85 86 87

	if (gval < 0)
		goto err_get_value;

	if (gpio_dev->active_low)
		gval = !gval;

88
	rc = ir_raw_event_store_edge(gpio_dev->rcdev, gval == 1);
89 90 91 92 93 94 95
	if (rc < 0)
		goto err_get_value;

err_get_value:
	return IRQ_HANDLED;
}

96
static int gpio_ir_recv_probe(struct platform_device *pdev)
97
{
98
	struct device *dev = &pdev->dev;
99 100
	struct gpio_rc_dev *gpio_dev;
	struct rc_dev *rcdev;
101
	const struct gpio_ir_recv_platform_data *pdata = dev->platform_data;
102 103
	int rc;

104 105
	if (pdev->dev.of_node) {
		struct gpio_ir_recv_platform_data *dtpdata =
106
			devm_kzalloc(dev, sizeof(*dtpdata), GFP_KERNEL);
107 108
		if (!dtpdata)
			return -ENOMEM;
109
		rc = gpio_ir_recv_get_devtree_pdata(dev, dtpdata);
110 111 112 113 114
		if (rc)
			return rc;
		pdata = dtpdata;
	}

115 116 117 118 119 120
	if (!pdata)
		return -EINVAL;

	if (pdata->gpio_nr < 0)
		return -EINVAL;

121
	gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL);
122 123 124
	if (!gpio_dev)
		return -ENOMEM;

125
	rcdev = rc_allocate_device(RC_DRIVER_IR_RAW);
126 127
	if (!rcdev)
		return -ENOMEM;
128

129
	rcdev->priv = gpio_dev;
130
	rcdev->device_name = GPIO_IR_DEVICE_NAME;
131
	rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
132
	rcdev->input_id.bustype = BUS_HOST;
133 134 135
	rcdev->input_id.vendor = 0x0001;
	rcdev->input_id.product = 0x0001;
	rcdev->input_id.version = 0x0100;
136
	rcdev->dev.parent = dev;
137
	rcdev->driver_name = GPIO_IR_DRIVER_NAME;
138
	rcdev->min_timeout = 1;
139 140
	rcdev->timeout = IR_DEFAULT_TIMEOUT;
	rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
141
	if (pdata->allowed_protos)
142
		rcdev->allowed_protocols = pdata->allowed_protos;
143
	else
144
		rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
145
	rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
146 147 148 149 150 151 152 153 154 155 156 157 158 159

	gpio_dev->rcdev = rcdev;
	gpio_dev->gpio_nr = pdata->gpio_nr;
	gpio_dev->active_low = pdata->active_low;

	rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
	if (rc < 0)
		goto err_gpio_request;
	rc  = gpio_direction_input(pdata->gpio_nr);
	if (rc < 0)
		goto err_gpio_direction_input;

	rc = rc_register_device(rcdev);
	if (rc < 0) {
160
		dev_err(dev, "failed to register rc device (%d)\n", rc);
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
		goto err_register_rc_device;
	}

	platform_set_drvdata(pdev, gpio_dev);

	rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),
				gpio_ir_recv_irq,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
					"gpio-ir-recv-irq", gpio_dev);
	if (rc < 0)
		goto err_request_irq;

	return 0;

err_request_irq:
	rc_unregister_device(rcdev);
177
	rcdev = NULL;
178 179 180 181 182 183 184 185
err_register_rc_device:
err_gpio_direction_input:
	gpio_free(pdata->gpio_nr);
err_gpio_request:
	rc_free_device(rcdev);
	return rc;
}

186
static int gpio_ir_recv_remove(struct platform_device *pdev)
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
{
	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);

	free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
	rc_unregister_device(gpio_dev->rcdev);
	gpio_free(gpio_dev->gpio_nr);
	return 0;
}

#ifdef CONFIG_PM
static int gpio_ir_recv_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);

	if (device_may_wakeup(dev))
		enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
	else
		disable_irq(gpio_to_irq(gpio_dev->gpio_nr));

	return 0;
}

static int gpio_ir_recv_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);

	if (device_may_wakeup(dev))
		disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));
	else
		enable_irq(gpio_to_irq(gpio_dev->gpio_nr));

	return 0;
}

static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
	.suspend        = gpio_ir_recv_suspend,
	.resume         = gpio_ir_recv_resume,
};
#endif

static struct platform_driver gpio_ir_recv_driver = {
	.probe  = gpio_ir_recv_probe,
231
	.remove = gpio_ir_recv_remove,
232 233
	.driver = {
		.name   = GPIO_IR_DRIVER_NAME,
234
		.of_match_table = of_match_ptr(gpio_ir_recv_of_match),
235 236 237 238 239
#ifdef CONFIG_PM
		.pm	= &gpio_ir_recv_pm_ops,
#endif
	},
};
240
module_platform_driver(gpio_ir_recv_driver);
241 242 243

MODULE_DESCRIPTION("GPIO IR Receiver driver");
MODULE_LICENSE("GPL v2");