aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/joystick/rpisense-js.c
blob: 6a416769065d2198344792eb02d8e38da1d03fd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Raspberry Pi Sense HAT joystick driver
 * http://raspberrypi.org
 *
 * Copyright (C) 2015 Raspberry Pi
 *
 * Author: Serge Schneider
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 */

#include <linux/module.h>

#include <linux/mfd/rpisense/joystick.h>
#include <linux/mfd/rpisense/core.h>

static struct rpisense *rpisense;
static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};

static void keys_work_fn(struct work_struct *work)
{
	int i;
	static s32 prev_keys;
	struct rpisense_js *rpisense_js = &rpisense->joystick;
	s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
	s32 changes = keys ^ prev_keys;

	prev_keys = keys;
	for (i = 0; i < 5; i++) {
		if (changes & 1) {
			input_report_key(rpisense_js->keys_dev,
					 keymap[i], keys & 1);
		}
		changes >>= 1;
		keys >>= 1;
	}
	input_sync(rpisense_js->keys_dev);
}

static irqreturn_t keys_irq_handler(int irq, void *pdev)
{
	struct rpisense_js *rpisense_js = &rpisense->joystick;

	schedule_work(&rpisense_js->keys_work_s);
	return IRQ_HANDLED;
}

static int rpisense_js_probe(struct platform_device *pdev)
{
	int ret;
	int i;
	struct rpisense_js *rpisense_js;

	rpisense = rpisense_get_dev();
	rpisense_js = &rpisense->joystick;

	INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);

	rpisense_js->keys_dev = input_allocate_device();
	if (!rpisense_js->keys_dev) {
		dev_err(&pdev->dev, "Could not allocate input device.\n");
		return -ENOMEM;
	}

	rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
	for (i = 0; i < ARRAY_SIZE(keymap); i++) {
		set_bit(keymap[i],
			rpisense_js->keys_dev->keybit);
	}

	rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
	rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
	rpisense_js->keys_dev->id.bustype = BUS_I2C;
	rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	rpisense_js->keys_dev->keycode = keymap;
	rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
	rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);

	ret = input_register_device(rpisense_js->keys_dev);
	if (ret) {
		dev_err(&pdev->dev, "Could not register input device.\n");
		goto err_keys_alloc;
	}

	ret = gpiod_direction_input(rpisense_js->keys_desc);
	if (ret) {
		dev_err(&pdev->dev, "Could not set keys-int direction.\n");
		goto err_keys_reg;
	}

	rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
	if (rpisense_js->keys_irq < 0) {
		dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
		ret = rpisense_js->keys_irq;
		goto err_keys_reg;
	}

	ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
			       keys_irq_handler, IRQF_TRIGGER_RISING,
			       "keys", &pdev->dev);
	if (ret) {
		dev_err(&pdev->dev, "IRQ request failed.\n");
		goto err_keys_reg;
	}
	return 0;
err_keys_reg:
	input_unregister_device(rpisense_js->keys_dev);
err_keys_alloc:
	input_free_device(rpisense_js->keys_dev);
	return ret;
}

static int rpisense_js_remove(struct platform_device *pdev)
{
	struct rpisense_js *rpisense_js = &rpisense->joystick;

	input_unregister_device(rpisense_js->keys_dev);
	input_free_device(rpisense_js->keys_dev);
	return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id rpisense_js_id[] = {
	{ .compatible = "rpi,rpi-sense-js" },
	{ },
};
MODULE_DEVICE_TABLE(of, rpisense_js_id);
#endif

static struct platform_device_id rpisense_js_device_id[] = {
	{ .name = "rpi-sense-js" },
	{ },
};
MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);

static struct platform_driver rpisense_js_driver = {
	.probe = rpisense_js_probe,
	.remove = rpisense_js_remove,
	.driver = {
		.name = "rpi-sense-js",
		.owner = THIS_MODULE,
	},
};

module_platform_driver(rpisense_js_driver);

MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
MODULE_LICENSE("GPL");