Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add a driver for GPIO controllable vibrators

Provide a simple driver for GPIO controllable vibrators.
It will be used by the Fairphone 2.

Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Luca Weiss and committed by
Dmitry Torokhov
13bda2d0 9a952206

+257
+37
Documentation/devicetree/bindings/input/gpio-vibrator.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/bindings/input/gpio-vibrator.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: GPIO vibrator 8 + 9 + maintainers: 10 + - Luca Weiss <luca@z3ntu.xyz> 11 + 12 + description: |+ 13 + Registers a GPIO device as vibrator, where the on/off capability is controlled by a GPIO. 14 + 15 + properties: 16 + compatible: 17 + const: gpio-vibrator 18 + 19 + enable-gpios: 20 + maxItems: 1 21 + 22 + vcc-supply: 23 + description: Regulator that provides power 24 + 25 + required: 26 + - compatible 27 + - enable-gpios 28 + 29 + examples: 30 + - | 31 + #include <dt-bindings/gpio/gpio.h> 32 + 33 + vibrator { 34 + compatible = "gpio-vibrator"; 35 + enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>; 36 + vcc-supply = <&pm8941_l18>; 37 + };
+12
drivers/input/misc/Kconfig
··· 290 290 To compile this driver as a module, choose M here: the module 291 291 will be called gpio_decoder. 292 292 293 + config INPUT_GPIO_VIBRA 294 + tristate "GPIO vibrator support" 295 + depends on GPIOLIB || COMPILE_TEST 296 + select INPUT_FF_MEMLESS 297 + help 298 + Say Y here to get support for GPIO based vibrator devices. 299 + 300 + If unsure, say N. 301 + 302 + To compile this driver as a module, choose M here: the module will be 303 + called gpio-vibra. 304 + 293 305 config INPUT_IXP4XX_BEEPER 294 306 tristate "IXP4XX Beeper support" 295 307 depends on ARCH_IXP4XX
+1
drivers/input/misc/Makefile
··· 36 36 obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o 37 37 obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o 38 38 obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o 39 + obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o 39 40 obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o 40 41 obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o 41 42 obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
+207
drivers/input/misc/gpio-vibra.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * GPIO vibrator driver 4 + * 5 + * Copyright (C) 2019 Luca Weiss <luca@z3ntu.xyz> 6 + * 7 + * Based on PWM vibrator driver: 8 + * Copyright (C) 2017 Collabora Ltd. 9 + * 10 + * Based on previous work from: 11 + * Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com> 12 + * 13 + * Based on PWM beeper driver: 14 + * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 15 + */ 16 + 17 + #include <linux/gpio/consumer.h> 18 + #include <linux/input.h> 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/of_device.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/property.h> 24 + #include <linux/regulator/consumer.h> 25 + #include <linux/slab.h> 26 + 27 + struct gpio_vibrator { 28 + struct input_dev *input; 29 + struct gpio_desc *gpio; 30 + struct regulator *vcc; 31 + 32 + struct work_struct play_work; 33 + bool running; 34 + bool vcc_on; 35 + }; 36 + 37 + static int gpio_vibrator_start(struct gpio_vibrator *vibrator) 38 + { 39 + struct device *pdev = vibrator->input->dev.parent; 40 + int err; 41 + 42 + if (!vibrator->vcc_on) { 43 + err = regulator_enable(vibrator->vcc); 44 + if (err) { 45 + dev_err(pdev, "failed to enable regulator: %d\n", err); 46 + return err; 47 + } 48 + vibrator->vcc_on = true; 49 + } 50 + 51 + gpiod_set_value_cansleep(vibrator->gpio, 1); 52 + 53 + return 0; 54 + } 55 + 56 + static void gpio_vibrator_stop(struct gpio_vibrator *vibrator) 57 + { 58 + gpiod_set_value_cansleep(vibrator->gpio, 0); 59 + 60 + if (vibrator->vcc_on) { 61 + regulator_disable(vibrator->vcc); 62 + vibrator->vcc_on = false; 63 + } 64 + } 65 + 66 + static void gpio_vibrator_play_work(struct work_struct *work) 67 + { 68 + struct gpio_vibrator *vibrator = 69 + container_of(work, struct gpio_vibrator, play_work); 70 + 71 + if (vibrator->running) 72 + gpio_vibrator_start(vibrator); 73 + else 74 + gpio_vibrator_stop(vibrator); 75 + } 76 + 77 + static int gpio_vibrator_play_effect(struct input_dev *dev, void *data, 78 + struct ff_effect *effect) 79 + { 80 + struct gpio_vibrator *vibrator = input_get_drvdata(dev); 81 + int level; 82 + 83 + level = effect->u.rumble.strong_magnitude; 84 + if (!level) 85 + level = effect->u.rumble.weak_magnitude; 86 + 87 + vibrator->running = level; 88 + schedule_work(&vibrator->play_work); 89 + 90 + return 0; 91 + } 92 + 93 + static void gpio_vibrator_close(struct input_dev *input) 94 + { 95 + struct gpio_vibrator *vibrator = input_get_drvdata(input); 96 + 97 + cancel_work_sync(&vibrator->play_work); 98 + gpio_vibrator_stop(vibrator); 99 + vibrator->running = false; 100 + } 101 + 102 + static int gpio_vibrator_probe(struct platform_device *pdev) 103 + { 104 + struct gpio_vibrator *vibrator; 105 + int err; 106 + 107 + vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL); 108 + if (!vibrator) 109 + return -ENOMEM; 110 + 111 + vibrator->input = devm_input_allocate_device(&pdev->dev); 112 + if (!vibrator->input) 113 + return -ENOMEM; 114 + 115 + vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc"); 116 + err = PTR_ERR_OR_ZERO(vibrator->vcc); 117 + if (err) { 118 + if (err != -EPROBE_DEFER) 119 + dev_err(&pdev->dev, "Failed to request regulator: %d\n", 120 + err); 121 + return err; 122 + } 123 + 124 + vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); 125 + err = PTR_ERR_OR_ZERO(vibrator->gpio); 126 + if (err) { 127 + if (err != -EPROBE_DEFER) 128 + dev_err(&pdev->dev, "Failed to request main gpio: %d\n", 129 + err); 130 + return err; 131 + } 132 + 133 + INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work); 134 + 135 + vibrator->input->name = "gpio-vibrator"; 136 + vibrator->input->id.bustype = BUS_HOST; 137 + vibrator->input->close = gpio_vibrator_close; 138 + 139 + input_set_drvdata(vibrator->input, vibrator); 140 + input_set_capability(vibrator->input, EV_FF, FF_RUMBLE); 141 + 142 + err = input_ff_create_memless(vibrator->input, NULL, 143 + gpio_vibrator_play_effect); 144 + if (err) { 145 + dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err); 146 + return err; 147 + } 148 + 149 + err = input_register_device(vibrator->input); 150 + if (err) { 151 + dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err); 152 + return err; 153 + } 154 + 155 + platform_set_drvdata(pdev, vibrator); 156 + 157 + return 0; 158 + } 159 + 160 + static int __maybe_unused gpio_vibrator_suspend(struct device *dev) 161 + { 162 + struct platform_device *pdev = to_platform_device(dev); 163 + struct gpio_vibrator *vibrator = platform_get_drvdata(pdev); 164 + 165 + cancel_work_sync(&vibrator->play_work); 166 + if (vibrator->running) 167 + gpio_vibrator_stop(vibrator); 168 + 169 + return 0; 170 + } 171 + 172 + static int __maybe_unused gpio_vibrator_resume(struct device *dev) 173 + { 174 + struct platform_device *pdev = to_platform_device(dev); 175 + struct gpio_vibrator *vibrator = platform_get_drvdata(pdev); 176 + 177 + if (vibrator->running) 178 + gpio_vibrator_start(vibrator); 179 + 180 + return 0; 181 + } 182 + 183 + static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops, 184 + gpio_vibrator_suspend, gpio_vibrator_resume); 185 + 186 + #ifdef CONFIG_OF 187 + static const struct of_device_id gpio_vibra_dt_match_table[] = { 188 + { .compatible = "gpio-vibrator" }, 189 + {} 190 + }; 191 + MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table); 192 + #endif 193 + 194 + static struct platform_driver gpio_vibrator_driver = { 195 + .probe = gpio_vibrator_probe, 196 + .driver = { 197 + .name = "gpio-vibrator", 198 + .pm = &gpio_vibrator_pm_ops, 199 + .of_match_table = of_match_ptr(gpio_vibra_dt_match_table), 200 + }, 201 + }; 202 + module_platform_driver(gpio_vibrator_driver); 203 + 204 + MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xy>"); 205 + MODULE_DESCRIPTION("GPIO vibrator driver"); 206 + MODULE_LICENSE("GPL"); 207 + MODULE_ALIAS("platform:gpio-vibrator");