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

Input: Add pwm beeper driver

This patch adds a simple driver which allows to use pwm based beepers (for
example piezo elements) as a pcspkr-like device.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Lars-Peter Clausen and committed by
Dmitry Torokhov
e22739d0 7beae702

+211
+11
drivers/input/misc/Kconfig
··· 327 327 To compile this driver as a module, choose M here: the 328 328 module will be called pcf8574_keypad. 329 329 330 + config INPUT_PWM_BEEPER 331 + tristate "PWM beeper support" 332 + depends on HAVE_PWM 333 + help 334 + Say Y here to get support for PWM based beeper devices. 335 + 336 + If unsure, say N. 337 + 338 + To compile this driver as a module, choose M here: the module will be 339 + called pwm-beeper. 340 + 330 341 config INPUT_GPIO_ROTARY_ENCODER 331 342 tristate "Rotary encoders connected to GPIO pins" 332 343 depends on GPIOLIB && GENERIC_GPIO
+1
drivers/input/misc/Makefile
··· 29 29 obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o 30 30 obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o 31 31 obj-$(CONFIG_INPUT_POWERMATE) += powermate.o 32 + obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o 32 33 obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o 33 34 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o 34 35 obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+199
drivers/input/misc/pwm-beeper.c
··· 1 + /* 2 + * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 3 + * PWM beeper driver 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms of the GNU General Public License as published by the 7 + * Free Software Foundation; either version 2 of the License, or (at your 8 + * option) any later version. 9 + * 10 + * You should have received a copy of the GNU General Public License along 11 + * with this program; if not, write to the Free Software Foundation, Inc., 12 + * 675 Mass Ave, Cambridge, MA 02139, USA. 13 + * 14 + */ 15 + 16 + #include <linux/input.h> 17 + #include <linux/module.h> 18 + #include <linux/kernel.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/pwm.h> 21 + #include <linux/slab.h> 22 + 23 + struct pwm_beeper { 24 + struct input_dev *input; 25 + struct pwm_device *pwm; 26 + unsigned long period; 27 + }; 28 + 29 + #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x)) 30 + 31 + static int pwm_beeper_event(struct input_dev *input, 32 + unsigned int type, unsigned int code, int value) 33 + { 34 + int ret = 0; 35 + struct pwm_beeper *beeper = input_get_drvdata(input); 36 + unsigned long period; 37 + 38 + if (type != EV_SND || value < 0) 39 + return -EINVAL; 40 + 41 + switch (code) { 42 + case SND_BELL: 43 + value = value ? 1000 : 0; 44 + break; 45 + case SND_TONE: 46 + break; 47 + default: 48 + return -EINVAL; 49 + } 50 + 51 + if (value == 0) { 52 + pwm_config(beeper->pwm, 0, 0); 53 + pwm_disable(beeper->pwm); 54 + } else { 55 + period = HZ_TO_NANOSECONDS(value); 56 + ret = pwm_config(beeper->pwm, period / 2, period); 57 + if (ret) 58 + return ret; 59 + ret = pwm_enable(beeper->pwm); 60 + if (ret) 61 + return ret; 62 + beeper->period = period; 63 + } 64 + 65 + return 0; 66 + } 67 + 68 + static int __devinit pwm_beeper_probe(struct platform_device *pdev) 69 + { 70 + unsigned long pwm_id = (unsigned long)pdev->dev.platform_data; 71 + struct pwm_beeper *beeper; 72 + int error; 73 + 74 + beeper = kzalloc(sizeof(*beeper), GFP_KERNEL); 75 + if (!beeper) 76 + return -ENOMEM; 77 + 78 + beeper->pwm = pwm_request(pwm_id, "pwm beeper"); 79 + 80 + if (IS_ERR(beeper->pwm)) { 81 + error = PTR_ERR(beeper->pwm); 82 + dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error); 83 + goto err_free; 84 + } 85 + 86 + beeper->input = input_allocate_device(); 87 + if (!beeper->input) { 88 + dev_err(&pdev->dev, "Failed to allocate input device\n"); 89 + error = -ENOMEM; 90 + goto err_pwm_free; 91 + } 92 + beeper->input->dev.parent = &pdev->dev; 93 + 94 + beeper->input->name = "pwm-beeper"; 95 + beeper->input->phys = "pwm/input0"; 96 + beeper->input->id.bustype = BUS_HOST; 97 + beeper->input->id.vendor = 0x001f; 98 + beeper->input->id.product = 0x0001; 99 + beeper->input->id.version = 0x0100; 100 + 101 + beeper->input->evbit[0] = BIT(EV_SND); 102 + beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL); 103 + 104 + beeper->input->event = pwm_beeper_event; 105 + 106 + input_set_drvdata(beeper->input, beeper); 107 + 108 + error = input_register_device(beeper->input); 109 + if (error) { 110 + dev_err(&pdev->dev, "Failed to register input device: %d\n", error); 111 + goto err_input_free; 112 + } 113 + 114 + platform_set_drvdata(pdev, beeper); 115 + 116 + return 0; 117 + 118 + err_input_free: 119 + input_free_device(beeper->input); 120 + err_pwm_free: 121 + pwm_free(beeper->pwm); 122 + err_free: 123 + kfree(beeper); 124 + 125 + return error; 126 + } 127 + 128 + static int __devexit pwm_beeper_remove(struct platform_device *pdev) 129 + { 130 + struct pwm_beeper *beeper = platform_get_drvdata(pdev); 131 + 132 + platform_set_drvdata(pdev, NULL); 133 + input_unregister_device(beeper->input); 134 + 135 + pwm_disable(beeper->pwm); 136 + pwm_free(beeper->pwm); 137 + 138 + kfree(beeper); 139 + 140 + return 0; 141 + } 142 + 143 + #ifdef CONFIG_PM 144 + static int pwm_beeper_suspend(struct device *dev) 145 + { 146 + struct pwm_beeper *beeper = dev_get_drvdata(dev); 147 + 148 + if (beeper->period) 149 + pwm_disable(beeper->pwm); 150 + 151 + return 0; 152 + } 153 + 154 + static int pwm_beeper_resume(struct device *dev) 155 + { 156 + struct pwm_beeper *beeper = dev_get_drvdata(dev); 157 + 158 + if (beeper->period) { 159 + pwm_config(beeper->pwm, beeper->period / 2, beeper->period); 160 + pwm_enable(beeper->pwm); 161 + } 162 + 163 + return 0; 164 + } 165 + 166 + static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops, 167 + pwm_beeper_suspend, pwm_beeper_resume); 168 + 169 + #define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops) 170 + #else 171 + #define PWM_BEEPER_PM_OPS NULL 172 + #endif 173 + 174 + static struct platform_driver pwm_beeper_driver = { 175 + .probe = pwm_beeper_probe, 176 + .remove = __devexit_p(pwm_beeper_remove), 177 + .driver = { 178 + .name = "pwm-beeper", 179 + .owner = THIS_MODULE, 180 + .pm = PWM_BEEPER_PM_OPS, 181 + }, 182 + }; 183 + 184 + static int __init pwm_beeper_init(void) 185 + { 186 + return platform_driver_register(&pwm_beeper_driver); 187 + } 188 + module_init(pwm_beeper_init); 189 + 190 + static void __exit pwm_beeper_exit(void) 191 + { 192 + platform_driver_unregister(&pwm_beeper_driver); 193 + } 194 + module_exit(pwm_beeper_exit); 195 + 196 + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 197 + MODULE_DESCRIPTION("PWM beeper driver"); 198 + MODULE_LICENSE("GPL"); 199 + MODULE_ALIAS("platform:pwm-beeper");