diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-27 22:14:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-27 22:14:35 -0400 |
commit | ed2608faa0f701b1dbc65277a9e5c7ff7118bfd4 (patch) | |
tree | 542950c65a22d6a149322849b6f45657e12d6a2e /drivers/input/misc/pwm-beeper.c | |
parent | 06d2e7812ecd1b585c5e9e7bda8ee90acebaef8c (diff) | |
parent | f49cf3b8b4c841457244c461c66186a719e13bcc (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull more input subsystem updates from Dmitry Torokhov:
"Just a few more driver fixes; new drivers will be coming in the next
merge window"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
Input: pwm-beeper - fix - scheduling while atomic
Input: xpad - xbox one elite controller support
Input: xpad - add more third-party controllers
Input: xpad - prevent spurious input from wired Xbox 360 controllers
Input: xpad - move pending clear to the correct location
Input: uinput - handle compat ioctl for UI_SET_PHYS
Diffstat (limited to 'drivers/input/misc/pwm-beeper.c')
-rw-r--r-- | drivers/input/misc/pwm-beeper.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 8d7133268745..5f9655d49a65 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c | |||
@@ -20,21 +20,40 @@ | |||
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/pwm.h> | 21 | #include <linux/pwm.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/workqueue.h> | ||
23 | 24 | ||
24 | struct pwm_beeper { | 25 | struct pwm_beeper { |
25 | struct input_dev *input; | 26 | struct input_dev *input; |
26 | struct pwm_device *pwm; | 27 | struct pwm_device *pwm; |
28 | struct work_struct work; | ||
27 | unsigned long period; | 29 | unsigned long period; |
28 | }; | 30 | }; |
29 | 31 | ||
30 | #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x)) | 32 | #define HZ_TO_NANOSECONDS(x) (1000000000UL/(x)) |
31 | 33 | ||
34 | static void __pwm_beeper_set(struct pwm_beeper *beeper) | ||
35 | { | ||
36 | unsigned long period = beeper->period; | ||
37 | |||
38 | if (period) { | ||
39 | pwm_config(beeper->pwm, period / 2, period); | ||
40 | pwm_enable(beeper->pwm); | ||
41 | } else | ||
42 | pwm_disable(beeper->pwm); | ||
43 | } | ||
44 | |||
45 | static void pwm_beeper_work(struct work_struct *work) | ||
46 | { | ||
47 | struct pwm_beeper *beeper = | ||
48 | container_of(work, struct pwm_beeper, work); | ||
49 | |||
50 | __pwm_beeper_set(beeper); | ||
51 | } | ||
52 | |||
32 | static int pwm_beeper_event(struct input_dev *input, | 53 | static int pwm_beeper_event(struct input_dev *input, |
33 | unsigned int type, unsigned int code, int value) | 54 | unsigned int type, unsigned int code, int value) |
34 | { | 55 | { |
35 | int ret = 0; | ||
36 | struct pwm_beeper *beeper = input_get_drvdata(input); | 56 | struct pwm_beeper *beeper = input_get_drvdata(input); |
37 | unsigned long period; | ||
38 | 57 | ||
39 | if (type != EV_SND || value < 0) | 58 | if (type != EV_SND || value < 0) |
40 | return -EINVAL; | 59 | return -EINVAL; |
@@ -49,22 +68,31 @@ static int pwm_beeper_event(struct input_dev *input, | |||
49 | return -EINVAL; | 68 | return -EINVAL; |
50 | } | 69 | } |
51 | 70 | ||
52 | if (value == 0) { | 71 | if (value == 0) |
53 | pwm_disable(beeper->pwm); | 72 | beeper->period = 0; |
54 | } else { | 73 | else |
55 | period = HZ_TO_NANOSECONDS(value); | 74 | beeper->period = HZ_TO_NANOSECONDS(value); |
56 | ret = pwm_config(beeper->pwm, period / 2, period); | 75 | |
57 | if (ret) | 76 | schedule_work(&beeper->work); |
58 | return ret; | ||
59 | ret = pwm_enable(beeper->pwm); | ||
60 | if (ret) | ||
61 | return ret; | ||
62 | beeper->period = period; | ||
63 | } | ||
64 | 77 | ||
65 | return 0; | 78 | return 0; |
66 | } | 79 | } |
67 | 80 | ||
81 | static void pwm_beeper_stop(struct pwm_beeper *beeper) | ||
82 | { | ||
83 | cancel_work_sync(&beeper->work); | ||
84 | |||
85 | if (beeper->period) | ||
86 | pwm_disable(beeper->pwm); | ||
87 | } | ||
88 | |||
89 | static void pwm_beeper_close(struct input_dev *input) | ||
90 | { | ||
91 | struct pwm_beeper *beeper = input_get_drvdata(input); | ||
92 | |||
93 | pwm_beeper_stop(beeper); | ||
94 | } | ||
95 | |||
68 | static int pwm_beeper_probe(struct platform_device *pdev) | 96 | static int pwm_beeper_probe(struct platform_device *pdev) |
69 | { | 97 | { |
70 | unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev); | 98 | unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev); |
@@ -93,6 +121,8 @@ static int pwm_beeper_probe(struct platform_device *pdev) | |||
93 | */ | 121 | */ |
94 | pwm_apply_args(beeper->pwm); | 122 | pwm_apply_args(beeper->pwm); |
95 | 123 | ||
124 | INIT_WORK(&beeper->work, pwm_beeper_work); | ||
125 | |||
96 | beeper->input = input_allocate_device(); | 126 | beeper->input = input_allocate_device(); |
97 | if (!beeper->input) { | 127 | if (!beeper->input) { |
98 | dev_err(&pdev->dev, "Failed to allocate input device\n"); | 128 | dev_err(&pdev->dev, "Failed to allocate input device\n"); |
@@ -112,6 +142,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) | |||
112 | beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL); | 142 | beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL); |
113 | 143 | ||
114 | beeper->input->event = pwm_beeper_event; | 144 | beeper->input->event = pwm_beeper_event; |
145 | beeper->input->close = pwm_beeper_close; | ||
115 | 146 | ||
116 | input_set_drvdata(beeper->input, beeper); | 147 | input_set_drvdata(beeper->input, beeper); |
117 | 148 | ||
@@ -141,7 +172,6 @@ static int pwm_beeper_remove(struct platform_device *pdev) | |||
141 | 172 | ||
142 | input_unregister_device(beeper->input); | 173 | input_unregister_device(beeper->input); |
143 | 174 | ||
144 | pwm_disable(beeper->pwm); | ||
145 | pwm_free(beeper->pwm); | 175 | pwm_free(beeper->pwm); |
146 | 176 | ||
147 | kfree(beeper); | 177 | kfree(beeper); |
@@ -153,8 +183,7 @@ static int __maybe_unused pwm_beeper_suspend(struct device *dev) | |||
153 | { | 183 | { |
154 | struct pwm_beeper *beeper = dev_get_drvdata(dev); | 184 | struct pwm_beeper *beeper = dev_get_drvdata(dev); |
155 | 185 | ||
156 | if (beeper->period) | 186 | pwm_beeper_stop(beeper); |
157 | pwm_disable(beeper->pwm); | ||
158 | 187 | ||
159 | return 0; | 188 | return 0; |
160 | } | 189 | } |
@@ -163,10 +192,8 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev) | |||
163 | { | 192 | { |
164 | struct pwm_beeper *beeper = dev_get_drvdata(dev); | 193 | struct pwm_beeper *beeper = dev_get_drvdata(dev); |
165 | 194 | ||
166 | if (beeper->period) { | 195 | if (beeper->period) |
167 | pwm_config(beeper->pwm, beeper->period / 2, beeper->period); | 196 | __pwm_beeper_set(beeper); |
168 | pwm_enable(beeper->pwm); | ||
169 | } | ||
170 | 197 | ||
171 | return 0; | 198 | return 0; |
172 | } | 199 | } |