Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Support for the S1 button on Routerboard 532
4 *
5 * Copyright (C) 2009 Phil Sutter <n0-1@freewrt.org>
6 */
7
8#include <linux/input.h>
9#include <linux/module.h>
10#include <linux/platform_device.h>
11#include <linux/gpio/consumer.h>
12
13#include <asm/mach-rc32434/gpio.h>
14#include <asm/mach-rc32434/rb.h>
15
16#define DRV_NAME "rb532-button"
17
18#define RB532_BTN_RATE 100 /* msec */
19#define RB532_BTN_KSYM BTN_0
20
21/**
22 * struct rb532_button - RB532 button information
23 * @gpio: GPIO connected to the button
24 */
25struct rb532_button {
26 struct gpio_desc *gpio;
27};
28
29/* The S1 button state is provided by GPIO pin 1. But as this
30 * pin is also used for uart input as alternate function, the
31 * operational modes must be switched first:
32 * 1) disable uart using set_latch_u5()
33 * 2) turn off alternate function implicitly through
34 * gpio_direction_input()
35 * 3) read the GPIO's current value
36 * 4) undo step 2 by enabling alternate function (in this
37 * mode the GPIO direction is fixed, so no change needed)
38 * 5) turn on uart again
39 * The GPIO value occurs to be inverted, so pin high means
40 * button is not pressed.
41 */
42static bool rb532_button_pressed(struct rb532_button *button)
43{
44 int val;
45
46 set_latch_u5(0, LO_FOFF);
47 gpiod_direction_input(button->gpio);
48
49 val = gpiod_get_value(button->gpio);
50
51 rb532_gpio_set_func(GPIO_BTN_S1);
52 set_latch_u5(LO_FOFF, 0);
53
54 return val;
55}
56
57static void rb532_button_poll(struct input_dev *input)
58{
59 struct rb532_button *button = input_get_drvdata(input);
60
61 input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed(button));
62 input_sync(input);
63}
64
65static int rb532_button_probe(struct platform_device *pdev)
66{
67 struct rb532_button *button;
68 struct input_dev *input;
69 int error;
70
71 button = devm_kzalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
72 if (!button)
73 return -ENOMEM;
74
75 button->gpio = devm_gpiod_get(&pdev->dev, "button", GPIOD_IN);
76 if (IS_ERR(button->gpio))
77 return dev_err_probe(&pdev->dev, PTR_ERR(button->gpio),
78 "error getting button GPIO\n");
79
80 input = devm_input_allocate_device(&pdev->dev);
81 if (!input)
82 return -ENOMEM;
83 input_set_drvdata(input, button);
84
85 input->name = "rb532 button";
86 input->phys = "rb532/button0";
87 input->id.bustype = BUS_HOST;
88
89 input_set_capability(input, EV_KEY, RB532_BTN_KSYM);
90
91 error = input_setup_polling(input, rb532_button_poll);
92 if (error)
93 return error;
94
95 input_set_poll_interval(input, RB532_BTN_RATE);
96
97 error = input_register_device(input);
98 if (error)
99 return error;
100
101 platform_set_drvdata(pdev, button);
102
103 return 0;
104}
105
106static struct platform_driver rb532_button_driver = {
107 .probe = rb532_button_probe,
108 .driver = {
109 .name = DRV_NAME,
110 },
111};
112module_platform_driver(rb532_button_driver);
113
114MODULE_AUTHOR("Phil Sutter <n0-1@freewrt.org>");
115MODULE_LICENSE("GPL");
116MODULE_DESCRIPTION("Support for S1 button on Routerboard 532");
117MODULE_ALIAS("platform:" DRV_NAME);