]>
Commit | Line | Data |
---|---|---|
92d57a73 TS |
1 | /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | */ | |
12 | ||
13 | #include <linux/module.h> | |
92d57a73 TS |
14 | #include <linux/kernel.h> |
15 | #include <linux/errno.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/input.h> | |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/platform_device.h> | |
1e63bd9c | 20 | #include <linux/regmap.h> |
92d57a73 | 21 | #include <linux/log2.h> |
57918dfa | 22 | #include <linux/of.h> |
02b0b79c | 23 | #include <linux/of_device.h> |
92d57a73 TS |
24 | |
25 | #define PON_CNTL_1 0x1C | |
26 | #define PON_CNTL_PULL_UP BIT(7) | |
27 | #define PON_CNTL_TRIG_DELAY_MASK (0x7) | |
02b0b79c SB |
28 | #define PON_CNTL_1_PULL_UP_EN 0xe0 |
29 | #define PON_CNTL_1_USB_PWR_EN 0x10 | |
30 | #define PON_CNTL_1_WD_EN_RESET 0x08 | |
31 | ||
32 | #define PM8058_SLEEP_CTRL 0x02b | |
33 | #define PM8921_SLEEP_CTRL 0x10a | |
34 | ||
35 | #define SLEEP_CTRL_SMPL_EN_RESET 0x04 | |
36 | ||
37 | /* Regulator master enable addresses */ | |
38 | #define REG_PM8058_VREG_EN_MSM 0x018 | |
39 | #define REG_PM8058_VREG_EN_GRP_5_4 0x1c8 | |
40 | ||
41 | /* Regulator control registers for shutdown/reset */ | |
42 | #define PM8058_S0_CTRL 0x004 | |
43 | #define PM8058_S1_CTRL 0x005 | |
44 | #define PM8058_S3_CTRL 0x111 | |
45 | #define PM8058_L21_CTRL 0x120 | |
46 | #define PM8058_L22_CTRL 0x121 | |
47 | ||
48 | #define PM8058_REGULATOR_ENABLE_MASK 0x80 | |
49 | #define PM8058_REGULATOR_ENABLE 0x80 | |
50 | #define PM8058_REGULATOR_DISABLE 0x00 | |
51 | #define PM8058_REGULATOR_PULL_DOWN_MASK 0x40 | |
52 | #define PM8058_REGULATOR_PULL_DOWN_EN 0x40 | |
53 | ||
54 | /* Buck CTRL register */ | |
55 | #define PM8058_SMPS_LEGACY_VREF_SEL 0x20 | |
56 | #define PM8058_SMPS_LEGACY_VPROG_MASK 0x1f | |
57 | #define PM8058_SMPS_ADVANCED_BAND_MASK 0xC0 | |
58 | #define PM8058_SMPS_ADVANCED_BAND_SHIFT 6 | |
59 | #define PM8058_SMPS_ADVANCED_VPROG_MASK 0x3f | |
60 | ||
61 | /* Buck TEST2 registers for shutdown/reset */ | |
62 | #define PM8058_S0_TEST2 0x084 | |
63 | #define PM8058_S1_TEST2 0x085 | |
64 | #define PM8058_S3_TEST2 0x11a | |
65 | ||
66 | #define PM8058_REGULATOR_BANK_WRITE 0x80 | |
67 | #define PM8058_REGULATOR_BANK_MASK 0x70 | |
68 | #define PM8058_REGULATOR_BANK_SHIFT 4 | |
69 | #define PM8058_REGULATOR_BANK_SEL(n) ((n) << PM8058_REGULATOR_BANK_SHIFT) | |
70 | ||
71 | /* Buck TEST2 register bank 1 */ | |
72 | #define PM8058_SMPS_LEGACY_VLOW_SEL 0x01 | |
73 | ||
74 | /* Buck TEST2 register bank 7 */ | |
75 | #define PM8058_SMPS_ADVANCED_MODE_MASK 0x02 | |
76 | #define PM8058_SMPS_ADVANCED_MODE 0x02 | |
77 | #define PM8058_SMPS_LEGACY_MODE 0x00 | |
92d57a73 TS |
78 | |
79 | /** | |
80 | * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information | |
81 | * @key_press_irq: key press irq number | |
02b0b79c SB |
82 | * @regmap: device regmap |
83 | * @shutdown_fn: shutdown configuration function | |
92d57a73 TS |
84 | */ |
85 | struct pmic8xxx_pwrkey { | |
92d57a73 | 86 | int key_press_irq; |
02b0b79c SB |
87 | struct regmap *regmap; |
88 | int (*shutdown_fn)(struct pmic8xxx_pwrkey *, bool); | |
92d57a73 TS |
89 | }; |
90 | ||
b27f8fee | 91 | static irqreturn_t pwrkey_press_irq(int irq, void *_pwr) |
92d57a73 | 92 | { |
b27f8fee | 93 | struct input_dev *pwr = _pwr; |
92d57a73 | 94 | |
b27f8fee SB |
95 | input_report_key(pwr, KEY_POWER, 1); |
96 | input_sync(pwr); | |
92d57a73 TS |
97 | |
98 | return IRQ_HANDLED; | |
99 | } | |
100 | ||
b27f8fee | 101 | static irqreturn_t pwrkey_release_irq(int irq, void *_pwr) |
92d57a73 | 102 | { |
b27f8fee | 103 | struct input_dev *pwr = _pwr; |
92d57a73 | 104 | |
b27f8fee SB |
105 | input_report_key(pwr, KEY_POWER, 0); |
106 | input_sync(pwr); | |
92d57a73 TS |
107 | |
108 | return IRQ_HANDLED; | |
109 | } | |
110 | ||
97a652a8 | 111 | static int __maybe_unused pmic8xxx_pwrkey_suspend(struct device *dev) |
92d57a73 TS |
112 | { |
113 | struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); | |
114 | ||
115 | if (device_may_wakeup(dev)) | |
116 | enable_irq_wake(pwrkey->key_press_irq); | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
97a652a8 | 121 | static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev) |
92d57a73 TS |
122 | { |
123 | struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); | |
124 | ||
125 | if (device_may_wakeup(dev)) | |
126 | disable_irq_wake(pwrkey->key_press_irq); | |
127 | ||
128 | return 0; | |
129 | } | |
92d57a73 TS |
130 | |
131 | static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, | |
132 | pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); | |
133 | ||
02b0b79c SB |
134 | static void pmic8xxx_pwrkey_shutdown(struct platform_device *pdev) |
135 | { | |
136 | struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); | |
137 | int error; | |
138 | u8 mask, val; | |
139 | bool reset = system_state == SYSTEM_RESTART; | |
140 | ||
141 | if (pwrkey->shutdown_fn) { | |
142 | error = pwrkey->shutdown_fn(pwrkey, reset); | |
143 | if (error) | |
144 | return; | |
145 | } | |
146 | ||
147 | /* | |
148 | * Select action to perform (reset or shutdown) when PS_HOLD goes low. | |
149 | * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that | |
150 | * USB charging is enabled. | |
151 | */ | |
152 | mask = PON_CNTL_1_PULL_UP_EN | PON_CNTL_1_USB_PWR_EN; | |
153 | mask |= PON_CNTL_1_WD_EN_RESET; | |
154 | val = mask; | |
155 | if (!reset) | |
156 | val &= ~PON_CNTL_1_WD_EN_RESET; | |
157 | ||
158 | regmap_update_bits(pwrkey->regmap, PON_CNTL_1, mask, val); | |
159 | } | |
160 | ||
161 | /* | |
162 | * Set an SMPS regulator to be disabled in its CTRL register, but enabled | |
163 | * in the master enable register. Also set it's pull down enable bit. | |
164 | * Take care to make sure that the output voltage doesn't change if switching | |
165 | * from advanced mode to legacy mode. | |
166 | */ | |
167 | static int pm8058_disable_smps_locally_set_pull_down(struct regmap *regmap, | |
168 | u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr, | |
169 | u8 master_enable_bit) | |
170 | { | |
171 | int error; | |
172 | u8 vref_sel, vlow_sel, band, vprog, bank; | |
173 | unsigned int reg; | |
174 | ||
175 | bank = PM8058_REGULATOR_BANK_SEL(7); | |
176 | error = regmap_write(regmap, test2_addr, bank); | |
177 | if (error) | |
178 | return error; | |
179 | ||
180 | error = regmap_read(regmap, test2_addr, ®); | |
181 | if (error) | |
182 | return error; | |
183 | ||
184 | reg &= PM8058_SMPS_ADVANCED_MODE_MASK; | |
185 | /* Check if in advanced mode. */ | |
186 | if (reg == PM8058_SMPS_ADVANCED_MODE) { | |
187 | /* Determine current output voltage. */ | |
188 | error = regmap_read(regmap, ctrl_addr, ®); | |
189 | if (error) | |
190 | return error; | |
191 | ||
192 | band = reg & PM8058_SMPS_ADVANCED_BAND_MASK; | |
193 | band >>= PM8058_SMPS_ADVANCED_BAND_SHIFT; | |
194 | switch (band) { | |
195 | case 3: | |
196 | vref_sel = 0; | |
197 | vlow_sel = 0; | |
198 | break; | |
199 | case 2: | |
200 | vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; | |
201 | vlow_sel = 0; | |
202 | break; | |
203 | case 1: | |
204 | vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; | |
205 | vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL; | |
206 | break; | |
207 | default: | |
208 | pr_err("%s: regulator already disabled\n", __func__); | |
209 | return -EPERM; | |
210 | } | |
211 | vprog = reg & PM8058_SMPS_ADVANCED_VPROG_MASK; | |
212 | /* Round up if fine step is in use. */ | |
213 | vprog = (vprog + 1) >> 1; | |
214 | if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK) | |
215 | vprog = PM8058_SMPS_LEGACY_VPROG_MASK; | |
216 | ||
217 | /* Set VLOW_SEL bit. */ | |
218 | bank = PM8058_REGULATOR_BANK_SEL(1); | |
219 | error = regmap_write(regmap, test2_addr, bank); | |
220 | if (error) | |
221 | return error; | |
222 | ||
223 | error = regmap_update_bits(regmap, test2_addr, | |
224 | PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK | |
225 | | PM8058_SMPS_LEGACY_VLOW_SEL, | |
226 | PM8058_REGULATOR_BANK_WRITE | | |
227 | PM8058_REGULATOR_BANK_SEL(1) | vlow_sel); | |
228 | if (error) | |
229 | return error; | |
230 | ||
231 | /* Switch to legacy mode */ | |
232 | bank = PM8058_REGULATOR_BANK_SEL(7); | |
233 | error = regmap_write(regmap, test2_addr, bank); | |
234 | if (error) | |
235 | return error; | |
236 | ||
237 | error = regmap_update_bits(regmap, test2_addr, | |
238 | PM8058_REGULATOR_BANK_WRITE | | |
239 | PM8058_REGULATOR_BANK_MASK | | |
240 | PM8058_SMPS_ADVANCED_MODE_MASK, | |
241 | PM8058_REGULATOR_BANK_WRITE | | |
242 | PM8058_REGULATOR_BANK_SEL(7) | | |
243 | PM8058_SMPS_LEGACY_MODE); | |
244 | if (error) | |
245 | return error; | |
246 | ||
247 | /* Enable locally, enable pull down, keep voltage the same. */ | |
248 | error = regmap_update_bits(regmap, ctrl_addr, | |
249 | PM8058_REGULATOR_ENABLE_MASK | | |
250 | PM8058_REGULATOR_PULL_DOWN_MASK | | |
251 | PM8058_SMPS_LEGACY_VREF_SEL | | |
252 | PM8058_SMPS_LEGACY_VPROG_MASK, | |
253 | PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN | |
254 | | vref_sel | vprog); | |
255 | if (error) | |
256 | return error; | |
257 | } | |
258 | ||
259 | /* Enable in master control register. */ | |
260 | error = regmap_update_bits(regmap, master_enable_addr, | |
261 | master_enable_bit, master_enable_bit); | |
262 | if (error) | |
263 | return error; | |
264 | ||
265 | /* Disable locally and enable pull down. */ | |
266 | return regmap_update_bits(regmap, ctrl_addr, | |
267 | PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, | |
268 | PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); | |
269 | } | |
270 | ||
271 | static int pm8058_disable_ldo_locally_set_pull_down(struct regmap *regmap, | |
272 | u16 ctrl_addr, u16 master_enable_addr, u8 master_enable_bit) | |
273 | { | |
274 | int error; | |
275 | ||
276 | /* Enable LDO in master control register. */ | |
277 | error = regmap_update_bits(regmap, master_enable_addr, | |
278 | master_enable_bit, master_enable_bit); | |
279 | if (error) | |
280 | return error; | |
281 | ||
282 | /* Disable LDO in CTRL register and set pull down */ | |
283 | return regmap_update_bits(regmap, ctrl_addr, | |
284 | PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, | |
285 | PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); | |
286 | } | |
287 | ||
288 | static int pm8058_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) | |
289 | { | |
290 | int error; | |
291 | struct regmap *regmap = pwrkey->regmap; | |
292 | u8 mask, val; | |
293 | ||
294 | /* When shutting down, enable active pulldowns on important rails. */ | |
295 | if (!reset) { | |
296 | /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */ | |
297 | pm8058_disable_smps_locally_set_pull_down(regmap, | |
298 | PM8058_S0_CTRL, PM8058_S0_TEST2, | |
299 | REG_PM8058_VREG_EN_MSM, BIT(7)); | |
300 | pm8058_disable_smps_locally_set_pull_down(regmap, | |
301 | PM8058_S1_CTRL, PM8058_S1_TEST2, | |
302 | REG_PM8058_VREG_EN_MSM, BIT(6)); | |
303 | pm8058_disable_smps_locally_set_pull_down(regmap, | |
304 | PM8058_S3_CTRL, PM8058_S3_TEST2, | |
305 | REG_PM8058_VREG_EN_GRP_5_4, BIT(7) | BIT(4)); | |
306 | /* Disable LDO 21 locally and set pulldown enable bit. */ | |
307 | pm8058_disable_ldo_locally_set_pull_down(regmap, | |
308 | PM8058_L21_CTRL, REG_PM8058_VREG_EN_GRP_5_4, | |
309 | BIT(1)); | |
310 | } | |
311 | ||
312 | /* | |
313 | * Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its | |
314 | * pull-down state intact. This ensures a safe shutdown. | |
315 | */ | |
316 | error = regmap_update_bits(regmap, PM8058_L22_CTRL, 0xbf, 0x93); | |
317 | if (error) | |
318 | return error; | |
319 | ||
320 | /* Enable SMPL if resetting is desired */ | |
321 | mask = SLEEP_CTRL_SMPL_EN_RESET; | |
322 | val = 0; | |
323 | if (reset) | |
324 | val = mask; | |
325 | return regmap_update_bits(regmap, PM8058_SLEEP_CTRL, mask, val); | |
326 | } | |
327 | ||
328 | static int pm8921_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) | |
329 | { | |
330 | struct regmap *regmap = pwrkey->regmap; | |
331 | u8 mask = SLEEP_CTRL_SMPL_EN_RESET; | |
332 | u8 val = 0; | |
333 | ||
334 | /* Enable SMPL if resetting is desired */ | |
335 | if (reset) | |
336 | val = mask; | |
337 | return regmap_update_bits(regmap, PM8921_SLEEP_CTRL, mask, val); | |
338 | } | |
339 | ||
5298cc4c | 340 | static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) |
92d57a73 TS |
341 | { |
342 | struct input_dev *pwr; | |
343 | int key_release_irq = platform_get_irq(pdev, 0); | |
344 | int key_press_irq = platform_get_irq(pdev, 1); | |
345 | int err; | |
346 | unsigned int delay; | |
1e63bd9c SB |
347 | unsigned int pon_cntl; |
348 | struct regmap *regmap; | |
92d57a73 | 349 | struct pmic8xxx_pwrkey *pwrkey; |
57918dfa SB |
350 | u32 kpd_delay; |
351 | bool pull_up; | |
92d57a73 | 352 | |
57918dfa | 353 | if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay)) |
70a26071 | 354 | kpd_delay = 15625; |
92d57a73 | 355 | |
70a26071 | 356 | if (kpd_delay > 62500 || kpd_delay == 0) { |
92d57a73 TS |
357 | dev_err(&pdev->dev, "invalid power key trigger delay\n"); |
358 | return -EINVAL; | |
359 | } | |
360 | ||
70a26071 SB |
361 | pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up"); |
362 | ||
1e63bd9c SB |
363 | regmap = dev_get_regmap(pdev->dev.parent, NULL); |
364 | if (!regmap) { | |
365 | dev_err(&pdev->dev, "failed to locate regmap for the device\n"); | |
366 | return -ENODEV; | |
367 | } | |
368 | ||
eb735d3b | 369 | pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL); |
92d57a73 TS |
370 | if (!pwrkey) |
371 | return -ENOMEM; | |
372 | ||
02b0b79c SB |
373 | pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev); |
374 | pwrkey->regmap = regmap; | |
eb735d3b DT |
375 | pwrkey->key_press_irq = key_press_irq; |
376 | ||
377 | pwr = devm_input_allocate_device(&pdev->dev); | |
92d57a73 TS |
378 | if (!pwr) { |
379 | dev_dbg(&pdev->dev, "Can't allocate power button\n"); | |
eb735d3b | 380 | return -ENOMEM; |
92d57a73 TS |
381 | } |
382 | ||
383 | input_set_capability(pwr, EV_KEY, KEY_POWER); | |
384 | ||
385 | pwr->name = "pmic8xxx_pwrkey"; | |
386 | pwr->phys = "pmic8xxx_pwrkey/input0"; | |
92d57a73 | 387 | |
57918dfa | 388 | delay = (kpd_delay << 10) / USEC_PER_SEC; |
92d57a73 TS |
389 | delay = 1 + ilog2(delay); |
390 | ||
1e63bd9c | 391 | err = regmap_read(regmap, PON_CNTL_1, &pon_cntl); |
92d57a73 TS |
392 | if (err < 0) { |
393 | dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err); | |
eb735d3b | 394 | return err; |
92d57a73 TS |
395 | } |
396 | ||
397 | pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK; | |
398 | pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK); | |
57918dfa | 399 | if (pull_up) |
92d57a73 TS |
400 | pon_cntl |= PON_CNTL_PULL_UP; |
401 | else | |
402 | pon_cntl &= ~PON_CNTL_PULL_UP; | |
403 | ||
1e63bd9c | 404 | err = regmap_write(regmap, PON_CNTL_1, pon_cntl); |
92d57a73 TS |
405 | if (err < 0) { |
406 | dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err); | |
eb735d3b | 407 | return err; |
92d57a73 TS |
408 | } |
409 | ||
eb735d3b DT |
410 | err = devm_request_irq(&pdev->dev, key_press_irq, pwrkey_press_irq, |
411 | IRQF_TRIGGER_RISING, | |
412 | "pmic8xxx_pwrkey_press", pwr); | |
92d57a73 | 413 | if (err) { |
eb735d3b DT |
414 | dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", |
415 | key_press_irq, err); | |
416 | return err; | |
92d57a73 TS |
417 | } |
418 | ||
eb735d3b DT |
419 | err = devm_request_irq(&pdev->dev, key_release_irq, pwrkey_release_irq, |
420 | IRQF_TRIGGER_RISING, | |
421 | "pmic8xxx_pwrkey_release", pwr); | |
422 | if (err) { | |
423 | dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", | |
424 | key_release_irq, err); | |
425 | return err; | |
92d57a73 TS |
426 | } |
427 | ||
eb735d3b DT |
428 | err = input_register_device(pwr); |
429 | if (err) { | |
430 | dev_err(&pdev->dev, "Can't register power key: %d\n", err); | |
431 | return err; | |
92d57a73 TS |
432 | } |
433 | ||
eb735d3b | 434 | platform_set_drvdata(pdev, pwrkey); |
57918dfa | 435 | device_init_wakeup(&pdev->dev, 1); |
92d57a73 TS |
436 | |
437 | return 0; | |
92d57a73 TS |
438 | } |
439 | ||
e2619cf7 | 440 | static int pmic8xxx_pwrkey_remove(struct platform_device *pdev) |
92d57a73 | 441 | { |
92d57a73 TS |
442 | device_init_wakeup(&pdev->dev, 0); |
443 | ||
92d57a73 TS |
444 | return 0; |
445 | } | |
446 | ||
57918dfa | 447 | static const struct of_device_id pm8xxx_pwr_key_id_table[] = { |
02b0b79c SB |
448 | { .compatible = "qcom,pm8058-pwrkey", .data = &pm8058_pwrkey_shutdown }, |
449 | { .compatible = "qcom,pm8921-pwrkey", .data = &pm8921_pwrkey_shutdown }, | |
57918dfa SB |
450 | { } |
451 | }; | |
452 | MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); | |
453 | ||
92d57a73 TS |
454 | static struct platform_driver pmic8xxx_pwrkey_driver = { |
455 | .probe = pmic8xxx_pwrkey_probe, | |
1cb0aa88 | 456 | .remove = pmic8xxx_pwrkey_remove, |
02b0b79c | 457 | .shutdown = pmic8xxx_pwrkey_shutdown, |
92d57a73 | 458 | .driver = { |
57918dfa | 459 | .name = "pm8xxx-pwrkey", |
92d57a73 | 460 | .pm = &pm8xxx_pwr_key_pm_ops, |
57918dfa | 461 | .of_match_table = pm8xxx_pwr_key_id_table, |
92d57a73 TS |
462 | }, |
463 | }; | |
840a746b | 464 | module_platform_driver(pmic8xxx_pwrkey_driver); |
92d57a73 TS |
465 | |
466 | MODULE_ALIAS("platform:pmic8xxx_pwrkey"); | |
467 | MODULE_DESCRIPTION("PMIC8XXX Power Key driver"); | |
468 | MODULE_LICENSE("GPL v2"); | |
469 | MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>"); |