diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 11:35:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 11:35:35 -0400 |
commit | d042380886fb2fc6c4b0fcfe1214ba473769a8e9 (patch) | |
tree | 61e29ff167e0f83f67930ee9911062415030e1ef /drivers/input | |
parent | 3477d168ba61c5b0ca42d3d4642f3463609a5417 (diff) | |
parent | b8d336ed90f541097a2ce583be430bb3e895dfbd (diff) |
Merge tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core framework:
- Add the MFD bindings doc to MAINTAINERS
New drivers:
- X-Powers AC100 Audio CODEC and RTC
- TI LP873x PMIC
- Rockchip RK808 PMIC
- Samsung Exynos Low Power Audio
New device support:
- Add support for STMPE1600 variant to stmpe
- Add support for PM8018 PMIC to pm8921-core
- Add support for AXP806 PMIC in axp20x
- Add support for AXP209 GPIO in axp20x
New functionality:
- Add support for Reset to all STMPE variants
- Add support for MKBP event support to cros_ec
- Add support for USB to intel_soc_pmic_bxtwc
- Add support for IRQs and Power Button to tps65217
Fix-ups:
- Clean-up defunct author emails (da9063, max14577)
- Kconfig fixups (wm8350-i2c, as37220
- Constify (altera-a10sr, sm501)
- Supply PCI IDs (intel-lpss-pci)
- Improve clocking (qcom_rpm)
- Fix IRQ probing (ucb1x00-core)
- Ensure fault log is cleared (da9052)
- Remove NO_IRQ check (ucb1x00-core)
- Supply I2C properties (intel-lpss-acpi, intel-lpss-pci)
- Non standard declaration (tps65217, max8997-irq)
- Remove unused code (lp873x, db8500-prcmu, ab8500-debugfs,
cros_ec_spi)
- Make non-modular (altera-a10sr, intel_msic, smsc-ece1099,
sun6i-prcm, twl-core)
- OF bindings (ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x,
lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona)
Bugfixes:
- Release OF pointer (qcom_rpm)
- Avoid double shifting in suspend/resume (88pm80x)
- Fix 'defined but not used' error (exynos-lpass)
- Fix 'sleeping whilst attomic' (atmel-hlcdc)"
* tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits)
mfd: arizona: Handle probe deferral for reset GPIO
mfd: arizona: Remove arizona_of_get_named_gpio helper function
mfd: arizona: Add DT options for max_channels_clocked and PDM speaker config
mfd: twl6040: Register child device for twl6040-pdmclk
mfd: cros_ec_spi: Remove unused variable 'request'
mfd: omap-usb-host: Return value is not 'const int'
mfd: ab8500-debugfs: Remove 'weak' function suspend_test_wake_cause_interrupt_is_mine()
mfd: ab8500-debugfs: Remove ab8500_dump_all_banks_to_mem()
mfd: db8500-prcmu: Remove unused *prcmu_set_ddr_opp() calls
mfd: ab8500-debugfs: Prevent initialised field from being over-written
mfd: max8997-irq: 'inline' should be at the beginning of the declaration
mfd: rk808: Fix RK818_IRQ_DISCHG_ILIM initializer
mfd: tps65217: Fix nonstandard declaration
mfd: lp873x: Remove unused mutex lock from struct lp873x
mfd: atmel-hlcdc: Do not sleep in atomic context
mfd: exynos-lpass: Mark PM functions as __maybe_unused
mfd: intel-lpss: Add default I2C device properties for Apollo Lake
mfd: twl-core: Make it explicitly non-modular
mfd: sun6i-prcm: Make it explicitly non-modular
mfd: smsc-ece1099: Make it explicitly non-modular
...
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/keyboard/cros_ec_keyb.c | 135 |
1 files changed, 31 insertions, 104 deletions
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 4b0878f35471..25943e9bc8bf 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/input.h> | 27 | #include <linux/input.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/notifier.h> | ||
30 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | #include <linux/input/matrix_keypad.h> | 33 | #include <linux/input/matrix_keypad.h> |
@@ -44,6 +45,7 @@ | |||
44 | * @dev: Device pointer | 45 | * @dev: Device pointer |
45 | * @idev: Input device | 46 | * @idev: Input device |
46 | * @ec: Top level ChromeOS device to use to talk to EC | 47 | * @ec: Top level ChromeOS device to use to talk to EC |
48 | * @notifier: interrupt event notifier for transport devices | ||
47 | */ | 49 | */ |
48 | struct cros_ec_keyb { | 50 | struct cros_ec_keyb { |
49 | unsigned int rows; | 51 | unsigned int rows; |
@@ -57,6 +59,7 @@ struct cros_ec_keyb { | |||
57 | struct device *dev; | 59 | struct device *dev; |
58 | struct input_dev *idev; | 60 | struct input_dev *idev; |
59 | struct cros_ec_device *ec; | 61 | struct cros_ec_device *ec; |
62 | struct notifier_block notifier; | ||
60 | }; | 63 | }; |
61 | 64 | ||
62 | 65 | ||
@@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, | |||
146 | input_sync(ckdev->idev); | 149 | input_sync(ckdev->idev); |
147 | } | 150 | } |
148 | 151 | ||
149 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) | 152 | static int cros_ec_keyb_open(struct input_dev *dev) |
150 | { | ||
151 | int ret = 0; | ||
152 | struct cros_ec_command *msg; | ||
153 | |||
154 | msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL); | ||
155 | if (!msg) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | msg->version = 0; | ||
159 | msg->command = EC_CMD_MKBP_STATE; | ||
160 | msg->insize = ckdev->cols; | ||
161 | msg->outsize = 0; | ||
162 | |||
163 | ret = cros_ec_cmd_xfer(ckdev->ec, msg); | ||
164 | if (ret < 0) { | ||
165 | dev_err(ckdev->dev, "Error transferring EC message %d\n", ret); | ||
166 | goto exit; | ||
167 | } | ||
168 | |||
169 | memcpy(kb_state, msg->data, ckdev->cols); | ||
170 | exit: | ||
171 | kfree(msg); | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | static irqreturn_t cros_ec_keyb_irq(int irq, void *data) | ||
176 | { | 153 | { |
177 | struct cros_ec_keyb *ckdev = data; | 154 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); |
178 | struct cros_ec_device *ec = ckdev->ec; | ||
179 | int ret; | ||
180 | uint8_t kb_state[ckdev->cols]; | ||
181 | |||
182 | if (device_may_wakeup(ec->dev)) | ||
183 | pm_wakeup_event(ec->dev, 0); | ||
184 | |||
185 | ret = cros_ec_keyb_get_state(ckdev, kb_state); | ||
186 | if (ret >= 0) | ||
187 | cros_ec_keyb_process(ckdev, kb_state, ret); | ||
188 | else | ||
189 | dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret); | ||
190 | 155 | ||
191 | return IRQ_HANDLED; | 156 | return blocking_notifier_chain_register(&ckdev->ec->event_notifier, |
157 | &ckdev->notifier); | ||
192 | } | 158 | } |
193 | 159 | ||
194 | static int cros_ec_keyb_open(struct input_dev *dev) | 160 | static void cros_ec_keyb_close(struct input_dev *dev) |
195 | { | 161 | { |
196 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | 162 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); |
197 | struct cros_ec_device *ec = ckdev->ec; | ||
198 | 163 | ||
199 | return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq, | 164 | blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, |
200 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 165 | &ckdev->notifier); |
201 | "cros_ec_keyb", ckdev); | ||
202 | } | 166 | } |
203 | 167 | ||
204 | static void cros_ec_keyb_close(struct input_dev *dev) | 168 | static int cros_ec_keyb_work(struct notifier_block *nb, |
169 | unsigned long queued_during_suspend, void *_notify) | ||
205 | { | 170 | { |
206 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | 171 | struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, |
207 | struct cros_ec_device *ec = ckdev->ec; | 172 | notifier); |
208 | 173 | ||
209 | free_irq(ec->irq, ckdev); | 174 | if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX) |
175 | return NOTIFY_DONE; | ||
176 | /* | ||
177 | * If EC is not the wake source, discard key state changes during | ||
178 | * suspend. | ||
179 | */ | ||
180 | if (queued_during_suspend) | ||
181 | return NOTIFY_OK; | ||
182 | if (ckdev->ec->event_size != ckdev->cols) { | ||
183 | dev_err(ckdev->dev, | ||
184 | "Discarded incomplete key matrix event.\n"); | ||
185 | return NOTIFY_OK; | ||
186 | } | ||
187 | cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix, | ||
188 | ckdev->ec->event_size); | ||
189 | return NOTIFY_OK; | ||
210 | } | 190 | } |
211 | 191 | ||
212 | /* | 192 | /* |
@@ -265,12 +245,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
265 | if (!idev) | 245 | if (!idev) |
266 | return -ENOMEM; | 246 | return -ENOMEM; |
267 | 247 | ||
268 | if (!ec->irq) { | ||
269 | dev_err(dev, "no EC IRQ specified\n"); | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | |||
273 | ckdev->ec = ec; | 248 | ckdev->ec = ec; |
249 | ckdev->notifier.notifier_call = cros_ec_keyb_work; | ||
274 | ckdev->dev = dev; | 250 | ckdev->dev = dev; |
275 | dev_set_drvdata(dev, ckdev); | 251 | dev_set_drvdata(dev, ckdev); |
276 | 252 | ||
@@ -311,54 +287,6 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
311 | return 0; | 287 | return 0; |
312 | } | 288 | } |
313 | 289 | ||
314 | #ifdef CONFIG_PM_SLEEP | ||
315 | /* Clear any keys in the buffer */ | ||
316 | static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev) | ||
317 | { | ||
318 | uint8_t old_state[ckdev->cols]; | ||
319 | uint8_t new_state[ckdev->cols]; | ||
320 | unsigned long duration; | ||
321 | int i, ret; | ||
322 | |||
323 | /* | ||
324 | * Keep reading until we see that the scan state does not change. | ||
325 | * That indicates that we are done. | ||
326 | * | ||
327 | * Assume that the EC keyscan buffer is at most 32 deep. | ||
328 | */ | ||
329 | duration = jiffies; | ||
330 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
331 | for (i = 1; !ret && i < 32; i++) { | ||
332 | memcpy(old_state, new_state, sizeof(old_state)); | ||
333 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
334 | if (0 == memcmp(old_state, new_state, sizeof(old_state))) | ||
335 | break; | ||
336 | } | ||
337 | duration = jiffies - duration; | ||
338 | dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i, | ||
339 | jiffies_to_usecs(duration)); | ||
340 | } | ||
341 | |||
342 | static int cros_ec_keyb_resume(struct device *dev) | ||
343 | { | ||
344 | struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); | ||
345 | |||
346 | /* | ||
347 | * When the EC is not a wake source, then it could not have caused the | ||
348 | * resume, so we clear the EC's key scan buffer. If the EC was a | ||
349 | * wake source (e.g. the lid is open and the user might press a key to | ||
350 | * wake) then the key scan buffer should be preserved. | ||
351 | */ | ||
352 | if (!ckdev->ec->was_wake_device) | ||
353 | cros_ec_keyb_clear_keyboard(ckdev); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | #endif | ||
359 | |||
360 | static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); | ||
361 | |||
362 | #ifdef CONFIG_OF | 290 | #ifdef CONFIG_OF |
363 | static const struct of_device_id cros_ec_keyb_of_match[] = { | 291 | static const struct of_device_id cros_ec_keyb_of_match[] = { |
364 | { .compatible = "google,cros-ec-keyb" }, | 292 | { .compatible = "google,cros-ec-keyb" }, |
@@ -372,7 +300,6 @@ static struct platform_driver cros_ec_keyb_driver = { | |||
372 | .driver = { | 300 | .driver = { |
373 | .name = "cros-ec-keyb", | 301 | .name = "cros-ec-keyb", |
374 | .of_match_table = of_match_ptr(cros_ec_keyb_of_match), | 302 | .of_match_table = of_match_ptr(cros_ec_keyb_of_match), |
375 | .pm = &cros_ec_keyb_pm_ops, | ||
376 | }, | 303 | }, |
377 | }; | 304 | }; |
378 | 305 | ||